За несколько лет работы в SAP, как пользователя, я составил большое количество различных скриптов для облегчения работы в SAP, т.к. SAP «из коробки» довольно неудобен для быстрой и эффективной работы. Особенно раздражает то, что за один раз невозможно вставить в таблицу больше строк, чем отображается на экране. Приходится вставлять частями, прокручивая таблицу. На невысоком широкоформатном мониторе так вообще ужасно неудобно. Я как-то давно, еще до составления скриптов, свой монитор ставил вертикально и поворачивал изображение, чтобы отображалось больше строк.
Решил поделиться своими наработками с общественностью.
Добиться разработки нужных для работы вещей в компании практически (и фактически) нереально. Компания крупная, бюрократия, куча согласований, жалко денег на программистов SAP, множество посредников-отделов и т.д. Поэтому я потихоньку самостоятельно автоматизировал свою (и не только свою) работу с помощью VBScript. Запуск «левых» exe на компьютерах компании запрещен всякими политиками, настройками и сторонними программами, а вот VBScript спокойно запускается.
Основной методикой составления скриптов была запись действий в макрос средствами самого SAP с дальнейшим разбором записанного, изучением справки, поиском информации в интернете и т.д. и т.п.
В интернете множество примеров работы с SAP с помощью VBScript, который запускается двойным кликом по vbs-файлу, но они практически все рассчитаны на работу с первым окном SAP. В начале таких примеров обычно есть код session.findById(«wnd[0]»).maximize, разворачивающий окно SAP. Работать с такими скриптами, «заточенными» под первое окно – неудобно по следующим причинам:
- Окно SAP Logon должно быть закрыто или свернуто в трей. Иначе скрипт будет пытаться работать в нем.
- В первом окне может выполняться другая транзакция, или будут находиться результаты работы транзакции, или будет открыта транзакция для ввода параметров. В общем, если в первом окне будет открыто что-то, кроме меню – запуск транзакции через скрипт не сработает.
- В первом окне может быть открыто подключение к другому серверу.
Себе в помощь дополнительно написал скрипт, который выгружает в XML-файл дерево GUI-элементов первого окна SAP. Получается так:

Dim currentNode Set xmlParser = CreateObject("Msxml2.DOMDocument") ' Создание объявления XML xmlParser.appendChild(xmlParser.createProcessingInstruction("xml", "version='1.0' encoding='windows-1251'")) Set SapGuiAuto = GetObject("SAPGUI") Set application = SapGuiAuto.GetScriptingEngine Set connection = application.Children(0) Set session = connection.Children(0) WScript.ConnectObject session, "on" WScript.ConnectObject application, "on" ' Максимизируем окно SAP session.findById("wnd[0]").maximize enumeration "wnd[0]" 'enumeration "wnd[0]/usr" MsgBox "Готово!", vbSystemModal Or vbInformation Sub enumeration(SAPRootElementId) Set SAPRootElement = session.findById(SAPRootElementId) 'Создание корневого элемента Set XMLRootNode = xmlParser.appendChild(xmlParser.createElement(SAPRootElement.Type)) enumChildrens SAPRootElement, XMLRootNode xmlParser.save("C:\SAP_tree.xml") End Sub Sub enumChildrens(SAPRootElement, XMLRootNode) For i = 0 To SAPRootElement.Children.Count - 1 Set SAPChildElement = SAPRootElement.Children.ElementAt(i) ' Создаем узел Set XMLSubNode = XMLRootNode.appendChild(xmlParser.createElement(SAPChildElement.Type)) ' Атрибут Name Set attrName = xmlParser.createAttribute("Name") attrName.Value = SAPChildElement.Name XMLSubNode.setAttributeNode(attrName) ' Атрибут Text If (Len(SAPChildElement.Text) > 0) Then Set attrText = xmlParser.createAttribute("Text") attrText.Value = SAPChildElement.Text XMLSubNode.setAttributeNode(attrText) End If ' Атрибут Id Set attrId = xmlParser.createAttribute("Id") attrId.Value = SAPChildElement.Id XMLSubNode.setAttributeNode(attrId) ' Если текущий объект - контейнер, то перебираем дочерние элементы If (SAPChildElement.ContainerType) Then enumChildrens SAPChildElement, XMLSubNode Next End Sub
Комментируя одну из строк:
- enumeration «wnd[0]»
- enumeration «wnd[0]/usr»
получаем результаты обхода элементов либо всего окна SAP, либо только UserArea (без меню, тулбара, строки статуса).
Несколько нюансов:
- Если какой-то элемент не видим на экране, то он не существует, и не найдется ни по имени, ни по ID. Чтобы до него добраться, нужно развернуть и сделать видимыми все вышестоящие элементы. Например:
- В транзакции ME51N невозможно указать «Примечание заголовка» если заголовок свернут. Надо предварительно развернуть заголовок.
- В транзакции ME21N, чтобы добраться до поля «Наш знак» – нужно не только развернуть заголовок, но и переключиться на вкладку «Связь».
- При обновлении экрана практически все GUI-объекты создаются заново, и их нужно заново искать по имени или ID. При обращении к объектам, созданным в скрипте до обновления экрана – произойдет ошибка.
- Все команды VBScript, взаимодействующие с GUI-элементами SAP, выполняются в синхронном режиме, т.е. выполнение кода VBScript не идет дальше, пока SAP не отработает команду. Это очень удобно, не нужно вставлять везде паузы и/или циклы, проверяя изменения на экране или ожидая появления какого-либо окна с сообщением.
- Во время работы скрипта и его взаимодействия с одним окном (режимом) SAP — можно спокойно работать как в других режимах SAP, так и в самой Windows или других приложениях.
Мои скрипты запускаются прямо из SAP. Для этого в SAP в избранном создается объект типа «Web-адрес или файл» с указанием полного пути к файлу скрипта.

Для работы скриптов я использую файлы WSF (Windows Script File), которые состоят из двух частей:
- Общий файл под громким названием SDK.vbs, содержащий код, используемый в каждом скрипте, плюс несколько функций и процедур, которые используются не во всех скриптах.
- Собственно, сам VBScript, который выполняет мои задачи. VBScript выполняет команды именно в том окне SAP, из которого запущен.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> … Код скрипта … </script> </job>
Т.е. WSF может состоять из нескольких скриптов (на различных языках программирования), как раскиданных по отдельным файлам, так и прописанных в самом WSF. При запуске WSF сначала выполняется код из файла SDK.vbs, а потом уже код самого скрипта. Т.к. WSF запускается прямо из SAP – то он гарантированно будет выполняться именно в том же окне, из которого запущен. Активная сессия определяется командой Set session = application.ActiveSession().
SDK.vbs состоит из кода подключения к SAP и определения активной сессии, и нескольких вспомогательных процедур и функций.
Далее в скрипте для удобства работы определяются несколько объектов и переменных:
- Wnd0 и UserArea – используются практически везде,
- Menubar, Statusbar и UserName – в некоторых скриптах.
Дополнительные процедуры и функции:
- Запуск транзакции.
- Эмуляция нажатия кнопок Enter, F3, F5, F8.
- Диалог открытия csv- или txt-файла с возможностью создания файла для записи. Файл для записи создается в той же папке и имеет такое же имя, но перед расширением добавляется «out». Файлы для чтения не должны быть в кодировке UTF-8 с BOM, т.к. при чтении первой строки дополнительно считываются три байта в начале файла (#EFBBBF), которые вызывают ошибку при вставке прочитанной строки в какое-либо поле SAP.
- Заполнение одной строки в таблице (для транзакции ME51N).
- Работа с буфером обмена.
' Создаем объект WScript.Shell Set WshShell = WScript.CreateObject("WScript.Shell") ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Подключение к SAP ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Создаем объект Set SapGuiAuto = GetObject("SAPGUI") ' Создаем объект типа GuiApplication (COM-интерфейс) Set application = SapGuiAuto.GetScriptingEngine() ' Создаем объект типа GuiSession - это сессия, которой соответствует активное окно SAP ' Т.е. при запуске WSF сам скрипт будет выполняться в том же окне SAP, из которого запущен Set session = application.ActiveSession() WScript.ConnectObject session, "on" WScript.ConnectObject application, "on" ' Создаем объект типа GuiMainWindow Set Wnd0 = session.findById("wnd[0]") ' Создаем объект типа GuiMenubar Set Menubar = Wnd0.findById("mbar") ' Создаем объект типа GuiUserArea Set UserArea = Wnd0.findById("usr") ' Создаем объект типа GuiStatusbar Set Statusbar = Wnd0.findById("sbar") ' Определяем логин пользователя UserName = session.Info.User ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Вспомогательные процедуры и функции ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Запуск транзакции Sub startTransaction(transaction_name) session.StartTransaction transaction_name End Sub ' Нажатие кнопки "Enter" Sub pressEnter() Wnd0.sendVKey 0 End Sub ' Нажатие кнопки F2 Sub pressF2() Wnd0.sendVKey 2 End Sub ' Нажатие кнопки F3 Sub pressF3() Wnd0.sendVKey 3 End Sub ' Нажатие кнопки F5 Sub pressF5() Wnd0.sendVKey 5 End Sub ' Нажатие кнопки F8 Sub pressF8() Wnd0.sendVKey 8 End Sub ' Диалог выбора файла, создание потоков чтения из файла и записи в файл Function selectFile(createOuputFile) Set objDialog = CreateObject("UserAccounts.CommonDialog") ' Заполняем свойства и открываем диалог With objDialog .InitialDir = WshShell.SpecialFolders("Desktop") ' Начальная папка - рабочий стол .Filter = "Текстовые файлы (*.csv;*.txt)|*.csv;*.txt" result = .ShowOpen End With ' Если файл не выбран - выходим If (result = 0) Then WScript.Quit inputFile = objDialog.FileName ' Полный путь к выбранному файлу Set fso = CreateObject("Scripting.FileSystemObject") Set inputStream = fso.OpenTextFile(inputFile) ' Создавать выходной файл? If (createOuputFile) Then outputFile = Left(inputFile, Len(inputFile) - 3) & "out" & Right(inputFile, 4) Set outputStream = fso.CreateTextFile(outputFile, True) ' Возвращаем массив из потока чтения из файла и потока записи в файл selectFile = Array(inputStream, outputStream) Else ' Возвращаем поток чтения из файла Set selectFile = inputStream End If End Function ' Заполняем одну строку в таблице (для ME51N) Sub fill_row(row, material, kolvo, zavod, zatreboval) Set grid = session.findById(UserArea.findByName("GRIDCONTROL", "GuiCustomControl").Id & "/shellcont/shell") grid.modifyCell row, "KNTTP", "K" ' Тип контировки grid.modifyCell row, "MATNR", material ' Материал grid.modifyCell row, "MENGE", kolvo ' Количество grid.modifyCell row, "NAME1", zavod ' Завод grid.modifyCell row, "LGOBE", "0001" ' Склад grid.modifyCell row, "AFNAM", zatreboval ' Затребовал End Sub ' Set, get and clear ClipBoard text in VBScript ' CLEAR - QuickClip("") ' SET - QuickClip("Hello World!") ' GET - Result = QuickClip(Null) Function QuickClip(input) '@description: A quick way to set and get your clipboard. '@author: Jeremy England (SimplyCoded) If IsNull(input) Then QuickClip = CreateObject("HTMLFile").parentWindow.clipboardData.getData("Text") If IsNull(QuickClip) Then QuickClip = "" Else CreateObject("WScript.Shell").Run "mshta.exe javascript:eval(""document.parentWindow.clipboardData.setData('text','" & Replace(Replace(input, "'", "\\u0027"), """", "\\u0022") & "');window.close()"")", 0, True End If End Function
Далее приведу примеры скриптов с комментариями и небольшим описанием.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Запускаем транзакцию startTransaction("IQ09") ' Кнопка "Многократный выбор" серийников UserArea.findById("btn%_SERNR_%_APP_%-VALU_PUSH").Press() ' Кнопка "Загрузка из буфера" session.findById("wnd[1]/tbar[0]/btn[24]").Press() ' Кнопка "Скопировать" (F8) pressF8() ' Кнопка "Выполнить" (F8) pressF8() </script> </job>
Т.е. непосредственно перед запуском скрипта необходимо скопировать в буфер обмена столбец из серийных номеров, например, из Excel или текстового файла.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Определяем первый и последний дни текущего месяца curr_date = Date() curr_month = Month(curr_date) curr_year = Year(curr_date) curr_day = Day(curr_date) date_begin = DateSerial(curr_year, curr_month, 1) date_end = DateSerial(curr_year, curr_month + 1, 0) ' Запускаем транзакцию startTransaction("MB51") ' Заполняем/очищаем поля ввода UserArea.findById("ctxtMATNR-LOW").Text = "100000" ' Материал UserArea.findById("ctxtWERKS-LOW").Text = "9999" ' Завод UserArea.findById("ctxtLGORT-LOW").Text = "0001" ' Склад UserArea.findById("ctxtBWART-LOW").Text = "101" ' Вид движения UserArea.findById("ctxtBUDAT-LOW").Text = date_begin ' Дата проводки - начало интервала UserArea.findById("ctxtBUDAT-HIGH").Text = date_end ' Дата проводки - конец интервала UserArea.findById("ctxtLIFNR-LOW").Text = "" UserArea.findById("ctxtBUKRS-LOW").Text = "" UserArea.findById("ctxtEBELN-LOW").Text = "" ' Заказ на поставку UserArea.findById("txtMAT_KDPO-LOW").Text = "" ' Поз. заказа клиента UserArea.findById("txtZEILE-LOW").Text = "" ' Поз. док. материала UserArea.findById("txtMBLNR-LOW").Text = "" ' Документ материала UserArea.findById("txtMJAHR-LOW").Text = "" ' ГодДокумМатериала pressF8() ' Кнопка "Подробный список" Wnd0.findById("tbar[1]/btn[48]").Press() ' Меню "Параметры настройки -> Вариант просмотра -> Выбрать..." Menubar.findById("menu[3]/menu[2]/menu[1]").Select() ' Выбираем форматы "X СпецифДляПользов" session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cmbG51_USPEC_LBOX").Key = "X" ' Клик по 3-му формату сверху session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").currentCellRow = 3 session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").clickCurrentCell() </script> </job>
В начале скрипта определяются первый и последний дни текущего месяца. Дополнительно очищаются некоторые поля ввода, которые могут быть заполнены после предыдущего запуска транзакции. Для таблицы используется предварительно созданный формат (специфический для пользователя), который должен быть третьим в списке. Порядковый номер формата легко исправить в коде.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Определяем первый и последний дни прошлого месяца curr_date = Date() curr_month = Month(curr_date) curr_year = Year(curr_date) curr_day = Day(curr_date) curr_month = curr_month - 1 date_begin = DateSerial(curr_year, curr_month, 1) date_end = DateSerial(curr_year, curr_month + 1, 0) ' Запускаем транзакцию startTransaction("VL06O") ' Кнопка "Список поставок - исх. п" UserArea.findById("btnBUTTON6").Press() ' Кнопка "Вызвать вариант..." Wnd0.findById("tbar[1]/btn[17]").Press() ' Вводим имя формата session.findById("wnd[1]/usr/txtV-LOW").Text = "MY_FORMAT" ' Кнопка "Выполнить" (F8) pressF8() ' Вводим интервал UserArea.findById("ctxtIT_WTIST-LOW").Text = date_begin UserArea.findById("ctxtIT_WTIST-HIGH").Text = date_end ' Кнопка "Выполнить" (F8) pressF8() ' Кнопка "Выбрать формат..." Wnd0.findById("tbar[1]/btn[33]").Press() ' Выбираем форматы "X СпецифДляПользов" session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cmbG51_USPEC_LBOX").Key = "X" ' Клик по 3-му формату session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").currentCellRow = 3 session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").clickCurrentCell() </script> </job>
В начале скрипта определяются первый и последний дни прошлого месяца. Остальные параметры запуска транзакции хранятся в предварительно созданном формате MY_FORMAT_2. Для таблицы так же используется предварительно созданный формат (специфический для пользователя), который должен быть третьим в списке.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> zavod = InputBox("Введите код завода") If (zavod = "") Then WScript.Quit ' Диалог выбора файла streams = selectFile(True) Set inputStream = streams(0) Set outputStream = streams(1) ' Запускаем транзакцию startTransaction("MM43") ' Читаем строки из файла, пока не достигнем конца Do While (Not inputStream.AtEndOfLine) ' Вводим завод UserArea.findById("ctxtRMMW1-VZWRK").Text = zavod ' Считываем материал из файла material = inputStream.ReadLine() ' Вставляем материал UserArea.findById("ctxtRMMW1-MATNR").Text = material ' Кнопка "Enter" pressEnter() ' Вкладка "Логистика: ЦентрРасп" UserArea.findById("tabsTABSPR1/tabpSP05").Select() ' Кнопка "Бухучет" UserArea.findById("tabsTABSPR1/tabpSP05/ssubTABFRA1:SAPLMGMW:2004/subSUB9:SAPLMGD2:2480/btnMBEW_PUSH").Press() ' Извлекаем цену price = UserArea.findById("subSUB3:SAPLMGD2:2802/txtMBEW-VERPR").Text ' Убираем точку в цене price = Replace(price, ".", "") ' Кнопка "Назад" (F3) pressF3() ' Кнопка "Назад" (F3) pressF3() ' Записываем в файл материал и цену outputStream.WriteLine(material & vbTab & price) Loop ' Кнопка "Назад" (F3) pressF3() inputStream.Close() outputStream.Close() MsgBox "Готово!", vbSystemModal Or vbInformation </script> </job>
Материалы, по которым надо получить среднескользящие цены – находятся в текстовом файле и расположены в столбец. Скрипт запускает транзакцию MM43, потом переключается по вкладкам, нажимает кнопку, чтобы добраться до нужного поля. Полученную цену записывает в новый файл вместе с материалом (через табуляцию).
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Определяем первый день текущего месяца curr_date = Date() curr_month = Month(curr_date) curr_year = Year(curr_date) date_begin = DateSerial(curr_year, curr_month, 1) ' Запускаем транзакцию startTransaction("VT16") ' Кнопка "Enter" pressEnter() ' Интервал "ТекущКонецПогрз" UserArea.findById("ctxtK_DALEN-LOW").Text = date_begin UserArea.findById("ctxtK_DALEN-HIGH").Text = "31.12.9999" ' Вид транспортировки UserArea.findById("ctxtK_SHTYP-LOW").Text = "0001" ' Заполняем пункты отгрузки UserArea.findById("btn%_A_VSTEL_%_APP_%-VALU_PUSH").Press() Set table = session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE") table.findById("ctxtRSCSEL_255-SLOW_I[1,0]").Text = "1111" table.findById("ctxtRSCSEL_255-SLOW_I[1,1]").Text = "2222" table.findById("ctxtRSCSEL_255-SLOW_I[1,2]").Text = "3333" session.findById("wnd[1]/tbar[0]/btn[8]").Press() ' Кнопка "Выполнить" (F8) pressF8() ' Пункт меню "Параметры настройки -> Варианты просмотра -> Выбрать..." Menubar.findById("menu[3]/menu[0]/menu[1]").Select() ' Выбираем первый формат в списке session.findById("wnd[1]/usr/lbl[1,3]").setFocus() ' Кнопка "Enter" pressEnter() </script> </job>
Транспортировки выбираются из интервала – с первого дня текущего месяца по 31.12.9999. Дата первого дня текущего месяца определяется в начале скрипта. Указываются пункты отгрузки. Для сформированного отчета выбирается первый формат в списке.
Следующие три скрипта предназначены для проводки отгруженных поставок датой, равной дате окончания погрузки.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Запускаем транзакцию startTransaction("VL06O") ' Кнопка "С��исок поставок - исх. п" UserArea.findById("btnBUTTON6").Press() ' Кнопка "Вызвать вариант..." Wnd0.findById("tbar[1]/btn[17]").Press() ' Вводим имя формата session.findById("wnd[1]/usr/txtV-LOW").Text = "MY_FORMAT_2" ' Очищаем поле "Создал" session.findById("wnd[1]/usr/txtENAME-LOW").Text = "" ' Кнопка "Выполнить" pressF8() ' Кнопка "Выполнить" pressF8() </script> </job>
Для таблицы используется предварительно созданный формат.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Запускаем транзакцию startTransaction("VT16") ' Закрываем ненужное окошко session.findById("wnd[1]/tbar[0]/btn[0]").Press() ' Кнопка "Многократный выбор" исходящих поставок UserArea.findById("btn%_S_VBELN_%_APP_%-VALU_PUSH").Press() ' Кнопка "Загрузка из буфера" session.findById("wnd[1]/tbar[0]/btn[24]").Press() ' Кнопка "Скопировать" (F8) pressF8() ' Кнопка "Выполнить" (F8) pressF8() ' Пункт меню "Параметры настройки -> Варианты просмотра -> Выбрать..." Menubar.findById("menu[3]/menu[0]/menu[1]").Select() ' Выбираем первый формат в списке session.findById("wnd[1]/usr/lbl[1,3]").setFocus() ' Кнопка "Enter" pressEnter() </script> </job>
Аналогично, столбец из номеров поставок необходимо предварительно скопировать в буфер обмена.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Запуск транзакции startTransaction("VL06O") ' Кнопка "Для ОМ" UserArea.findById("btnBUTTON4").Press() ' Удаление начальной и конечной дат "Дата ПлановДвижМтр" UserArea.findById("ctxtIT_WADAT-LOW").Text = "" UserArea.findById("ctxtIT_WADAT-HIGH").Text = "" ' Кнопка "Многократный выбор" транспортировок UserArea.findById("btn%_IT_TKNUM_%_APP_%-VALU_PUSH").Press() ' Кнопка "Загрузка из буфера" session.findById("wnd[1]/tbar[0]/btn[24]").Press() ' Кнопка "Выполнить" (F8) pressF8() ' Кнопка "Выполнить" (F8) pressF8() ' Если нет кнопки "Ракурс позиции" - то и поставок нет If (Wnd0.findById("tbar[1]/btn[18]").Text = "Ракурс позиции") Then ' Выделяем все UserArea.findById("cntlGRID1/shellcont/shell").selectAll ' Меню "Последующие функции -> Выполнить проводку отпуска материала" Menubar.findById("menu[4]/menu[7]").Select() ' В появившемся окне стираем два первых символа (день месяца) в поле ввода даты фактического движения материала WshShell.SendKeys "{HOME}{DELETE}{DELETE}" Else MsgBox "Поставок нет!", vbSystemModal Or vbExclamation ' Кнопка "Назад" (F3) pressF3() ' Кнопка "Назад" (F3) pressF3() End If </script> </job>
Столбец с номерами транспортировок необходимо предварительно скопировать в буфер обмена из результатов работы транзакции VT16 (предыдущий скрипт). После окончания работы транзакции:
- Если поставок в отчете нет – выводится соответствующее сообщение, далее скрипт завершает работу.
- Если поставки в отчете есть – выбирается пункт меню «Выполнить проводку отпуска материала», в появившемся окошке с датой проводки стираются два первых символа (т.е. день). Далее скрипт завершает работу, а пользователю необходимо ввести нужный день и нажать Enter.
Наличие/отсутствие поставок в отчете определяется по наличию/отсутствию меню. Предварительно включается обработка ошибок скриптом.
Пока писал статью, решил объединить первые два скрипта для проводки отгруженных поставок в один.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> '############################################################## ' Запускаем первую транзакцию startTransaction("VL06O") ' Кнопка "Список поставок - исх. п" UserArea.findById("btnBUTTON6").Press() ' Кнопка "Вызвать вариант..." Wnd0.findById("tbar[1]/btn[17]").Press() ' Вводим имя формата session.findById("wnd[1]/usr/txtV-LOW").Text = "MY_FORMAT_3" ' Очищаем поле "Создал" session.findById("wnd[1]/usr/txtENAME-LOW").Text = "" ' Кнопка "Выполнить" pressF8() ' Кнопка "Выполнить" pressF8() Set grid = UserArea.findById("cntlGRID1/shellcont/shell") ' GuiGridView rowCount = grid.RowCount ' Всего заполненных строк visibleRowCount = grid.VisibleRowCount ' Количество видимых строк ' Прокручиваем таблицу до конца, чтобы скопировались все поставки firstVisibleRow = visibleRowCount Do While (firstVisibleRow < rowCount) grid.firstVisibleRow = firstVisibleRow firstVisibleRow = firstVisibleRow + visibleRowCount Loop ' Выделяем столбец с поставками grid.SelectColumn("VBELN") ' Копируем в буфер выделенный столбец с помощью контекстного меню grid.ContextMenu() grid.SelectContextMenuItemByText "Скопировать текст" ' Выходим в меню SAP pressF3() pressF3() pressF3() '############################################################## ' Запускаем вторую транзакцию startTransaction("VT16") ' Закрываем ненужное окошко session.findById("wnd[1]/tbar[0]/btn[0]").Press() ' Кнопка "Многократный выбор" исходящих поставок UserArea.findById("btn%_S_VBELN_%_APP_%-VALU_PUSH").Press() ' Кнопка "Загрузка из буфера" session.findById("wnd[1]/tbar[0]/btn[24]").Press() ' Кнопка "Скопировать" (F8) pressF8() ' Кнопка "Выполнить" (F8) pressF8() ' Пункт меню "Параметры настройки -> Варианты просмотра -> Выбрать..." Menubar.findById("menu[3]/menu[0]/menu[1]").Select() ' Выбираем первый формат в списке (должен быть "Lexa_1") session.findById("wnd[1]/usr/lbl[1,3]").setFocus() ' Кнопка "Enter" pressEnter() </script> </job>
В скрипте используется копирование столбца с номерами поставок из транзакции VL06O с предварительной прокруткой таблицы до конца (чтобы скопировались все поставки).
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> data_prihoda = InputBox("Введите дату в формате: 010213, 01022013, 01.02.13, 01.02.2013") If (data_prihoda = "") Then WScript.Quit vremya_prihoda = InputBox("Введите время в формате: 0130, 01:30") If (vremya_prihoda = "") Then WScript.Quit ' Диалог выбора файла Set inputStream = selectFile(False) ' Запускаем транзакцию startTransaction("VL32N") ' Перебираем строки, пока не встретится пустая Do While (Not inputStream.AtEndOfLine) ' Читаем строку из файла postavka = inputStream.ReadLine() ' Вставляем номер поставки UserArea.findById("ctxtLIKP-VBELN").Text = postavka ' Нажимаем "Enter" pressEnter() ' Переключаемся на вкладку "Транспортировка" UserArea.findById("tabsTAXI_TABSTRIP_OVERVIEW/tabpT\02").Select() ' Вставляем дату UserArea.findById("tabsTAXI_TABSTRIP_OVERVIEW/tabpT\02/ssubSUBSCREEN_BODY:SAPMV50A:1208/ctxtLIKP-TDDAT").Text = data_prihoda ' Вставляем время UserArea.findById("tabsTAXI_TABSTRIP_OVERVIEW/tabpT\02/ssubSUBSCREEN_BODY:SAPMV50A:1208/ctxtLIKP-TDUHR").Text = vremya_prihoda ' Нажимаем "Enter" один раз или несколько, если проблемы с датой Do ' Нажимаем "Enter" pressEnter() Loop While (Len(Statusbar.text) > 0) ' Нажимаем "Сохранить" Wnd0.findById("tbar[0]/btn[11]").Press() Loop ' Нажимаем "Назад" pressF3() inputStream.Close() MsgBox "Готово!", vbSystemModal Or vbInformation </script> </job>
Номера входящих поставок должны быть в текстовом файле в один столбец. Скрипт запрашивает дату и время, после этого перебирает все поставки, прописывает «ПланировТранс», сохраняет поставку. Если в строке статуса появляется какое-либо сообщение – скрипт нажимает Enter до тех пор, пока строка статуса не станет пустой.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Завод zavod = InputBox("Введите код завода") If (zavod = "") Then WScript.Quit ' Склад-отправитель sklad_source = InputBox("Введите код склада-отправителя") If (sklad_source = "") Then WScript.Quit ' Склад-получатель sklad_destination = InputBox("Введите код склада-получателя") If (sklad_destination = "") Then WScript.Quit ' Диалог выбора файла Set inputStream = selectFile(False) ' Запускаем транзакцию startTransaction("MB1B") ' Вводим вид движения UserArea.findById("ctxtRM07M-BWARTWA").Text = "311" ' Вводим завод UserArea.findById("ctxtRM07M-WERKS").Text = zavod ' Вводим склад-отправитель UserArea.findById("ctxtRM07M-LGORT").Text = sklad_source ' Кнопка "Enter" pressEnter() ' Вводим склад-получатель UserArea.findById("ctxtMSEGK-UMLGO").Text = sklad_destination ' Кнопка "Enter" pressEnter() ' Определяем количество строк в таблице Set simpleContainer = UserArea.findById("sub:SAPMM07M:0421") RowCount = simpleContainer.LoopRowCount intRow = 2 ' Читаем строки из файла, пока не достигнем конца Do While (Not inputStream.AtEndOfLine) ' Читаем строку из файла stroka = inputStream.ReadLine() ' Разбиваем строку по символам табуляции arr = Split(stroka, vbTab) material = arr(0) kolvo = Replace(arr(1), " ", "") ' Убираем пробелы в количестве SAP_pos = (intRow - 2) Mod RowCount UserArea.findById("sub:SAPMM07M:0421/ctxtMSEG-MATNR[" & SAP_pos & ",7]").Text = material UserArea.findById("sub:SAPMM07M:0421/txtMSEG-ERFMG[" & SAP_pos & ",26]").Text = kolvo ' Нажимаем кнопку "Новый", если таблица закончилась If (SAP_pos = (RowCount - 1)) Then Wnd0.findById("tbar[1]/btn[19]").Press() intRow = intRow + 1 If (intRow > 1000) Then inputStream.Close() MsgBox "Заполнено 999 позиций!", vbSystemModal Or vbCritical WScript.Quit End If Loop ' Кнопка "Enter" pressEnter() inputStream.Close() MsgBox "Готово!", vbSystemModal Or vbInformation </script> </job>
Скрипт в начале работы запрашивает завод и склады, далее читает из текстового файла материал и количество (разделенные табуляцией), вводит их в таблицу, автоматически прокручивая ее. За один запуск скрипта можно перенести не более 1000 позиций.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> ' Завод zavod = InputBox("Введите код завода") If (zavod = "") Then WScript.Quit ' Склад-отправитель sklad_source = InputBox("Введите код склада-отправителя") If (sklad_source = "") Then WScript.Quit ' Склад-получатель sklad_destination = InputBox("Введите код склада-получателя") If (sklad_destination = "") Then WScript.Quit ' Диалог выбора файла Set inputStream = selectFile(False) ' Запускаем транзакцию startTransaction("MB1B") ' Вводим вид движения UserArea.findById("ctxtRM07M-BWARTWA").Text = "311" ' Вводим завод UserArea.findById("ctxtRM07M-WERKS").Text = zavod ' Вводим склад-отправитель UserArea.findById("ctxtRM07M-LGORT").Text = sklad_source ' Кнопка "Enter" pressEnter() ' Вводим склад-получатель UserArea.findById("ctxtMSEGK-UMLGO").Text = sklad_destination ' Кнопка "Enter" pressEnter() ' Определяем количество строк в таблице Set simpleContainer = UserArea.findById("sub:SAPMM07M:0421") RowCount = simpleContainer.LoopRowCount intRow = 2 ' Читаем строки из файла, пока не достигнем конца Do While (Not inputStream.AtEndOfLine) ' Читаем строку из файла stroka = inputStream.ReadLine() ' Разбиваем строку по символам табуляции arr = Split(stroka, vbTab) material = arr(0) serial = arr(1) SAP_pos = (intRow - 2) Mod RowCount UserArea.findById("sub:SAPMM07M:0421/ctxtMSEG-MATNR[" & SAP_pos & ",7]").Text = material UserArea.findById("sub:SAPMM07M:0421/txtMSEG-ERFMG[" & SAP_pos & ",26]").Text = "1" ' Кнопка "Enter" pressEnter() ' Вставляем серийник session.findById("wnd[1]/usr/tblSAPLIPW1TC_SERIAL_NUMBERS/ctxtRIPW0-SERNR[0,0]").Text = serial ' Кнопка "ОК" session.findById("wnd[1]/tbar[0]/btn[0]").Press() ' Нажимаем кнопку "Новый", если таблица закончилась If (SAP_pos = (RowCount - 1)) Then Wnd0.findById("tbar[1]/btn[19]").Press() intRow = intRow + 1 If (intRow > 1000) Then inputStream.Close() MsgBox "Заполнено 999 позиций!", vbSystemModal Or vbCritical WScript.Quit End If Loop ' Нажимаем "Enter" pressEnter() inputStream.Close() MsgBox "Готово!", vbSystemModal Or vbInformation </script> </job>
Скрипт работает аналогично предыдущему скрипту, только в файле вместо количества должен быть серийник, а в табличной части скрипт сам ставит по каждому материалу количество 1.
<job> <script language="VBScript" src="SDK.vbs"></script> <script language="VBScript"> zavod = 8888 zatreboval = 12345 mvz = "7777666666" note = "Примечание к заявке" ' Список товаров. Если какой-то товар не нужен, нужно проставить 0 в количестве itemsArray = Array( _ Array(111111, 50, "Бумага А4"), _ Array(222222, 50, "Бумага туалетная"), _ Array(333333, 0, "Жидкое мыло"), _ Array(444444, 0, "Краска штемпельная"), _ Array(555555, 10, "Маркер"), _ Array(666666, 0, "Скобы для степлера"), _ ) ' Запускаем транзакцию startTransaction("ME51N") ' Выбираем нужный вид заявки - NB UserArea.findByName("MEREQ_TOPLINE-BSART", "GuiComboBox").Key = "NB" ' Разворачиваем верхний контейнер, если он развернут Set buttonTop = UserArea.findByName("SUB1:SAPLMEVIEWS:4000", "GuiSimpleContainer").findByName("DYN_4000-BUTTON", "GuiButton") If (Right(buttonTop.Tooltip, 2) = "F2") Then buttonTop.Press() ' Заполняем примечание заголовка guiTexteditId = UserArea.findByName("TEXT_EDITOR_0101", "GuiCustomControl").Id & "/shellcont/shell" UserArea.findById(guiTexteditId).Text = note pos = 0 For Each item In itemsArray If (item(1) > 0) Then ' Заполняем одну строку в таблице fill_row pos, item(0), item(1), zavod, zatreboval ' Кнопка "Enter" pressEnter() ' Прописываем МВЗ UserArea.findByName("COBL-KOSTL", "GuiCTextField").Text = mvz ' Кнопка "Enter" pressEnter() pos = pos + 1 End If Next MsgBox "Готово!", vbSystemModal Or vbInformation </script> </job>
Предварительно в скрипте проставляются количества для материалов, которые должны быть в заявке. Если указано 0, то такой материал в заявку не добавляется. Для каждого материала в заявке автоматически прописывается МВЗ. Скрипт не рассчитан на работу с большим количеством материалов (они не влезут в видимую часть таблицы).
Есть еще другие и более сложные скрипты, где используется три транзакции в одном скрипте, но там транзакции специфические для компании.
На этом пока все...