За несколько лет работы в 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, то такой материал в заявку не добавляется. Для каждого материала в заявке автоматически прописывается МВЗ. Скрипт не рассчитан на работу с большим количеством материалов (они не влезут в видимую часть таблицы).
Есть еще другие и более сложные скрипты, где используется три транзакции в одном скрипте, но там транзакции специфические для компании.
На этом пока все...