Select the first 25 items of a certain column in SAP GUI whose name I know - vba

I'm trying to select the first 25 items of a certain column in SAP GUI whose name I know. I recorded a script and it came like that shown below.
As you can see the name of the columns are ST_RESERVA, FEVOR, AUFNR, MATNR, ZAGRLOGISTICO and MATNR.
The code works fine but I think I could simplify this using FOR with the rows going to 1 until 25 and the column fixed. Any ideas?
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject app, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell/shellcont[1]/shell").setCurrentCell 10,"ST_RESERVA"
set coll1 = app.createGuiCollection
coll1.add "10,ST_RESERVA"
coll1.add "10,FEVOR"
coll1.add "10,AUFNR"
coll1.add "10,MATNR"
coll1.add "10,ZAGRLOGISTICO"
coll1.add "10,MAKTX"
coll1.add "11,ST_RESERVA"
coll1.add "11,FEVOR"
coll1.add "11,AUFNR"
coll1.add "11,MATNR"
coll1.add "11,ZAGRLOGISTICO"
coll1.add "11,MAKTX"
coll1.add "12,ST_RESERVA"
coll1.add "12,FEVOR"
coll1.add "12,AUFNR"
coll1.add "12,MATNR"
coll1.add "12,ZAGRLOGISTICO"
coll1.add "12,MAKTX"
coll1.add "13,ST_RESERVA"
coll1.add "13,FEVOR"
coll1.add "13,AUFNR"
coll1.add "13,MATNR"
' and the list goes on until the first 25 items are selected from the tables above.
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell/shellcont[1]/shell").selectedCells = coll1
set coll1 = nothing

Related

VBA Loop Not Pasting Correctly from Excel

I've created a macro that uses 5 columns to paste data into SAP GUI using a loop. However, once it gets to row 30 or 40, it stops pasting the data correctly where it pastes the same number. Not sure if I should add something to enhance the code? All responses will be greatly appreciated, thank you!
On Error Resume Next
Dim Application
If Not IsObject(Application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set Application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = Application.Children(0)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject Application, "on"
End If
i = 2
Do Until Cells(i, 1) = ""
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/ctxtGV_MATNR").Text = Cells(i, 1)
session.findById("wnd[0]/usr/ctxtGV_WERKS").Text = Cells(i, 2)
session.findById("wnd[0]/usr/ctxtGV_WERKS").SetFocus
session.findById("wnd[0]/usr/ctxtGV_WERKS").caretPosition = 4
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/txtZIP_MM02_STRUCTURE-EISBE_P").Text = Cells(i, 3)
session.findById("wnd[0]/usr/ctxtZIP_MM02_STRUCTURE-EISBE_RD").Text = Cells(i, 4)
session.findById("wnd[0]/usr/ctxtZIP_MM02_STRUCTURE-EISBE_RD").SetFocus
session.findById("wnd[0]/usr/ctxtZIP_MM02_STRUCTURE-EISBE_RD").caretPosition = 10
session.findById("wnd[0]/usr/ctxtZIP_MM02_STRUCTURE-EISBE_RD").caretPosition = 10
session.findById("wnd[0]/tbar[1]/btn[21]").press
session.findById("wnd[0]/usr/cntlTEXTEDIT/shellcont/shell").Text = Cells(i, 5) + vbCr + "" + vbCr + ""
session.findById("wnd[0]/usr/cntlTEXTEDIT/shellcont/shell").setSelectionIndexes 99, 99
session.findById("wnd[0]/tbar[0]/btn[11]").press
i = i + 1
Loop
End Sub
Problem with your solution is that the control showing table wont let you access basicaly anything further than what is visible (not actually true, another 3 or so rows may be loaded into memory though).
What you need to do is to refresh the table either by using the "Next Page (Page down)" button from the upper bar of SAP GUI or manipulate the scrollbar.
Either way, remember that the row index will reset back to the beginning so you would need to reset your counter too.
You may find it easier to not contain all the code in On Error Resume Next too.
Example for one of the kinds of shell tables:
For i = 0 To session.findById("wnd[0]/shellcont/shell").rowcount - 1
session.findById("wnd[0]/shellcont/shell").firstVisibleRow = i
Next

VBScript, click save to continue Script

i have a certain problem with A VBScript when i try to automate a procedure with VBA/VBS macro.
It enters a contract number in VBS and does some standardized changes in VA03, but for some there are some incoplete information, then this pop-up window appears:
I only want my script to click Save and continue in case this happens for a certain contract number.
It did not work with Applications.DisplayAlerts = False, and also i guess it will not work with Error Handler as practically this is not an Error.
It should be with a simple IF statement, but i do not know how i should put the wording.
Can anyone please help, my research in the net got me nowhere :(
Code (Although it is working, i only need a piece which will handle the above stopper):
today = Format(Date, "dd.mm.yyyy")
Application.DisplayAlerts = False
'We declared the variables for the while function in excel
Dim cont As String
Dim row As Integer
Dim rep As String
Dim j As Integer
j = 2
'Those are the commands with which we make SAP available for the VBA code
Set SapGuiAuto = GetObject("SAPGUI")
Set SAPApp = SapGuiAuto.GetScriptingEngine
Set SAPCon = SAPApp.Children(0)
Set Session = SAPCon.Children(0)
If IsObject(WScript) Then
WScript.ConnectObject Session, "on"
WScript.ConnectObject Application, "on"
End If
Session.findById("wnd[0]").maximize
Session.findById("wnd[0]/tbar[0]/btn[3]").press
Session.findById("wnd[0]/tbar[0]/btn[3]").press
Session.findById("wnd[0]/tbar[0]/okcd").Text = "va42"
Session.findById("wnd[0]").sendVKey 0
'We start the loop inside the macro book and give values to our variables
With ThisWorkbook
While Cells(j, 1) <> ""
cont = Cells(j, 1).Value
row = Cells(j, 3).Value
rep = Cells(j, 4).Value
' enter VBS code
'In this part we change the inst to REMV
Session.findById("wnd[0]").maximize
Session.findById("wnd[0]/usr/ctxtVBAK-VBELN").Text = cont
Session.findById("wnd[0]/usr/ctxtVBAK-VBELN").caretPosition = 8
Session.findById("wnd[0]").sendVKey 0
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP_OVERVIEW/tabpT\01/ssubSUBSCREEN_BODY:SAPMV45A:4426/subSUBSCREEN_TC:SAPMV45A:4908/tblSAPMV45ATCTRL_U_ERF_KONTRAKT/ctxtVBAP-KDMAT[5," & CStr(row) & "]").SetFocus
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP_OVERVIEW/tabpT\01/ssubSUBSCREEN_BODY:SAPMV45A:4426/subSUBSCREEN_TC:SAPMV45A:4908/tblSAPMV45ATCTRL_U_ERF_KONTRAKT/ctxtVBAP-KDMAT[5," & CStr(row) & "]").caretPosition = 6
Session.findById("wnd[0]").sendVKey 2
'change date
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP_ITEM/tabpT\03").Select
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP/tabpT\03/ssubSUBSCREEN_BODY:SAPLV45W:4201/ctxtVEDA-VDEMDAT").Text = today
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP/tabpT\03/ssubSUBSCREEN_BODY:SAPLV45W:4201/ctxtVEDA-VDEMDAT").SetFocus
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP/tabpT\03/ssubSUBSCREEN_BODY:SAPLV45W:4201/ctxtVEDA-VDEMDAT").caretPosition = 10
'change INST to REMV
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP/tabpT\10").Select
Session.findById("wnd[0]/usr/tabsTAXI_TABSTRIP_ITEM/tabpT\10/ssubSUBSCREEN_BODY:SAPMV45A:4454/ctxtVBAP-KDMAT").Text = rep
'Deletes the first line in Technical Objects and saves the changes
Session.findById("wnd[0]/mbar/menu[3]/menu[9]").Select
Session.findById("wnd[0]/usr/tblSAPLIWOLOBJK_220").getAbsoluteRow(0).Selected = True
Session.findById("wnd[0]/tbar[1]/btn[19]").press
Session.findById("wnd[1]/usr/btnSPOP-OPTION1").press
Session.findById("wnd[0]/tbar[0]/btn[3]").press
Session.findById("wnd[0]/tbar[0]/btn[11]").press
'we make sure the loop goes through every row and then end it
j = j + 1
Wend
End With
End Sub
Best regards,
Mihail
First, I would record the missing piece of vbs program. Then you have to recognize where in the main program this piece must be installed. But I suspect it will happen after saving. The rough structure might look like this:
. . .
Session.findById("wnd[0]/tbar[0]/btn[11]").press
'------------------------------ new ---------------------------
on error resume next
'Suppose that's the missing piece of program
session.findById("wnd[1]/usr/btnSPOP-OPTION1").press
on error goto 0
'------------------------------ new ---------------------------
'we make sure the loop goes through every row and then end it
j = j + 1
Wend
. . .
Regards,
ScriptMan
I added the solution proposed by Script man above!
It worked perfectly!

vba code to copy a column from sap window and paste the values in excel sheet

i have a code that do some SAP transactions on the sap then select a whole column from a grid on a sap i am successful till here but i want to copy the column and past it in an excel sheet but i cant do that. i tried to open the context menu to choose copy text but it doesn't work i tried to send CTRL+C stroke from keyboard but also failed. if someone can help me with that i will be very grateful. here is my code:
Sub lolo()
If Not IsObject(App) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set App = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = App.Children(0)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject App, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/btn%_EQUNR_%_APP_%-VALU_PUSH").press
session.findById("wnd[1]/tbar[0]/btn[24]").press
session.findById("wnd[1]/tbar[0]/btn[8]").press
session.findById("wnd[0]/usr/txtSELCOUNT").Text = "1"
session.findById("wnd[0]/usr/txtSELCOUNT").SetFocus
session.findById("wnd[0]/usr/txtSELCOUNT").caretPosition = 14
session.findById("wnd[0]/tbar[1]/btn[8]").press
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").setCurrentCell -1, "PTTXT"
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").selectColumn "PTTXT"
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").contextMenu
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").selectContextMenuItem "&FILTER"
session.findById("wnd[1]").sendVKey 4
session.findById("wnd[2]/usr/lbl[1,23]").SetFocus
session.findById("wnd[2]/usr/lbl[1,23]").caretPosition = 2
session.findById("wnd[2]").sendVKey 2
session.findById("wnd[1]/tbar[0]/btn[0]").press
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").setCurrentCell -1, "CNTRC"
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").selectColumn "CNTRC"
Application.Wait (Now + TimeValue("0:00:03"))
SendKeys "^C"
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").contextMenu
End Sub
I expect the OP is no longer interested in the answer but thinking that people are still reading this question...
add a form to your vba project then the following code into your module
Dim DataObj As MSForms.DataObject
Set DataObj = New MSForms.DataObject
DataObj.GetFromClipboard
sString = DataObj.GetText(1)
This pulls the data from your clipboard into sString. You can then pass the string to a cell value.
I had the same problem, depending on the transaction I either got
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").contextMenu
session.findById("wnd[1]/tbar[0]/btn[0]").press
or
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").contextMenu
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").selectContextMenuItemBytext "Copy Text"
which both didn't copy the column.
What solved my predicament was this handy line:
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").SelectContextMenuItemByPosition "0"
Could you try with this? I've integrated parts of code that I use to extract data from these types of SAP sheets..
Sub lolo()
If Not IsObject(App) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set App = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = App.Children(0)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject App, "on"
End If
dim t as object
dim arr as variant
dim index1 as long
session.findById("wnd[0]/usr/btn%_EQUNR_%_APP_%-VALU_PUSH").press
session.findById("wnd[1]/tbar[0]/btn[24]").press
session.findById("wnd[1]/tbar[0]/btn[8]").press
session.findById("wnd[0]/usr/txtSELCOUNT").Text = "1"
session.findById("wnd[0]/usr/txtSELCOUNT").SetFocus
session.findById("wnd[0]/usr/txtSELCOUNT").caretPosition = 14
session.findById("wnd[0]/tbar[1]/btn[8]").press
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").setCurrentCell -1, "PTTXT"
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").selectColumn "PTTXT"
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").contextMenu
session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell").selectContextMenuItem "&FILTER"
session.findById("wnd[1]").sendVKey 4
session.findById("wnd[2]/usr/lbl[1,23]").SetFocus
session.findById("wnd[2]/usr/lbl[1,23]").caretPosition = 2
session.findById("wnd[2]").sendVKey 2
session.findById("wnd[1]/tbar[0]/btn[0]").press
Set t = session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell")
ReDim arr(0 To t.RowCount, 1 To 2)
arr(0, 1) = "Column1"
arr(0, 2) = "Column2"
For index1 = 1 To t.RowCount
If t.VisibleRowCount + t.FirstVisibleRow < index1 Then
t.FirstVisibleRow = index1
End If
arr(index1, 1) = t.GetCellValue(index1 - 1, "CNTRC")
'arr(index1, 2) = t.GetCellValue(index1 - 1, <any other column>)
Next index1
'To print it to excel alter this to fit into your excel sheet:
ThisWorkbook.Sheets(1).Range("A1:A" & UBound(arr) + 1).Offset(0, 0) = arr
end sub

Assistance needed in VBA to extract unique values based on one condition

I have a working code that extract the distinct values from a sheet, however it only gives me the total of distinct values.
I need it to be working with a certain condition, at the moment i have 13 different conditions, and each condition should get that specific value filled in to a specific cell on an other sheet.
example
condition 1: 46130288, the result of the distinct values should be filled into Sheet KPI cell D3
condition 2: 55202136, the result of the distinct values should be filled into Sheet KPI cell D6.
The Working code for a total of distinct values looks like this:
Sub CntOrder()
Dim Uni As Collection, cl As Range, LpRange As Range
Dim clswfrm As Range, clswcst As Range, myRng As Range
Dim TotUni As Long
'*************
Set myRng = Sheets("957").[E:E] 'define your sheet/range
'*************
On Error Resume Next
Set clswfrm = myRng.SpecialCells(xlFormulas)
Set clswcst = myRng.SpecialCells(xlConstants)
Set myRng = Nothing 'free up memory
On Error GoTo 0
If clswfrm Is Nothing And clswcst Is Nothing Then
MsgBox "No Unique Cells"
Exit Sub
ElseIf Not clswfrm Is Nothing And Not clswcst Is Nothing Then
Set LpRange = Union(clswcst, clswfrm)
ElseIf clswfrm Is Nothing Then Set LpRange = clswcst
Else: Set LpRange = clswfrm
End If
Set clswfrm = Nothing: Set clswcst = Nothing 'Free up memory
Set Uni = New Collection
On Error Resume Next
For Each cl In LpRange
Uni.Add cl.Value - 2, CStr(cl.Value) 'assign unique key string
Next cl
On Error GoTo 0
Set LpRange = Nothing 'free up memory
TotUni = Uni.Count
Set Uni = Nothing ''free up memory
Range("D2") = TotUni 'Work with the Unique value total here (replace msgbox)
End Sub
Hope someone could help me in getting the code above to check Sheet("957").Range("T:T") after the conditions to be met
Hopefully, this will get you started.
Sub CntOrder()
Dim Uni As Object
Dim r As Range, Target As Range
With Sheets("957")
Set Target = Intersect(.Columns("E"), .UsedRange) 'Set the Target range to the used portion of column E
End With
If Target Is Nothing Then
MsgBox "No Unique Cells"
Exit Sub
End If
Set Uni = CreateObject("Scripting.Dictionary")
For Each r In Target 'assign unique key & count occurence
Uni(r.Value) = Uni(r.Value) + 1 'The key is a variant type
Next
With Sheets("Sheet KPI")
.Range("D2") = Uni.Count
.Range("D3").Resize(Uni.Count).Value = Application.Transpose(Uni.Keys) 'Assign the unique value
.Range("E3").Resize(Uni.Count).Value = Application.Transpose(Uni.Items) ' Assign the counts of each unique vaule
End With
End Sub

Error when running a working macro from a Ribbon

Below is a macro for Excel2010 in VBA. It's working only when I open VBA Code editor and run from the menu Debug. I tried to put it to Ribbon and run it from there but I've got this error:
Run-time error '1004':
Application-defined or object-defined error
Additionally, when I change all Range() into .Worksheet(i).Range(), the procedure does not run at all with the same error. It's like .Range does not seem to be part of Worksheet(i). I have no experience in Excel 2010 VBA.
Sub CopyAndRearrange()
Dim ns As Integer
Dim i As Integer
ns = ActiveWorkbook.Worksheets.Count
ActiveWorkbook.Sheets(ns).Cells.ClearContents
For i = 1 To ns - 1
With ActiveWorkbook
.Worksheets(i).Activate
Range("E1") = CInt(.Worksheets(i).Name)
Range(Range("G1"), Range("A1").End(xlDown).Offset(0, 7)) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5"
Range(Range("I1"), Range("A1").End(xlDown).Offset(0, 8)) = "=RC[-6]"
Range(Range("G1"), Range("I1").End(xlDown)).Copy
Sheets(ns).Activate
If i = 1 Then
'Range(Range("G1"), Range("I1").End(xlDown)).Copy Destination:=Sheets(ns).Range("A1")
Sheets(ns).Range("A1").Select
Else
'Range(Range("G1"), Range("I1").End(xlDown)).Copy Destination:=Sheets(ns).Range("A1").End(xlDown).Offset(1, 0)
Sheets(ns).Range("A1").End(xlDown).Offset(1, 0).Select
End If
ActiveSheet.Paste Link:=True
Application.CutCopyMode = False
Application.ScreenUpdating = True
End With
Next
Sheets(ns).Range("A1").Select
End Sub
EDIT:
OK. I have slightly changed the code in hope I was wrong about referring to the right sheet etc. The problem is still there. The line: ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5" causes the problem. Surprisingly, it is not the first that I refer to Range in the an active sheet and for some reasons, I really don't know why, I've got the error!!! To exhaust all possibilities, I have also tried these:
Explicitly re-create a Module in VBA Window
Re-open the file
Record a macro and insert a code in there
Nothing's worked so far. I have given up but maybe someone in future will see the problem and give a solution here.
Public Sub CopyAndRearrange()
Dim ns As Integer
Dim i As Integer
Dim ws As Worksheet
Dim wb As Workbook
Dim rg1 As Range
Dim rg2 As Range
Dim cell As Range
Set wb = ThisWorkbook
ns = wb.Worksheets.Count
wb.Sheets(ns).Cells.ClearContents
For i = 1 To ns - 1
With wb
Set ws = wb.Worksheets(i)
ws.Activate
ActiveSheet.Range("E1") = CInt(ActiveSheet.Name)
Set rg1 = ActiveSheet.Range("G1")
Set rg2 = ActiveSheet.Range("A1").End(xlDown).Offset(0, 7)
ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5"
Set rg1 = ActiveSheet.Range("I1")
Set rg2 = ActiveSheet.Range("A1").End(xlDown).Offset(0, 8)
ActiveSheet.Range(rg1, rg2) = "=RC[-6]"
Set rg1 = ActiveSheet.Range("G1")
Set rg2 = ActiveSheet.Range("I1").End(xlDown)
ActiveSheet.Range(rg1, rg2).Copy
Sheets(ns).Activate
If i = 1 Then
ActiveSheet.Range("A1").Select
Else
ActiveSheet.Range("A1").End(xlDown).Offset(1, 0).Select
End If
ActiveSheet.Paste Link:=True
Application.CutCopyMode = False
Application.ScreenUpdating = True
End With
Next
Sheets(ns).Range("A1").Select
Set ws = Nothing
Set wb = Nothing
Set rg1 = Nothing
Set rg2 = Nothing
Set cell = Nothing
End Sub
Try the following:
Sub CopyAndRearrange(Control as IRibbionControl)
Adding the control allows the code to be executed from the ribbion.
I guess I found the answer to my own question.
The problem was missing bracket in this line:
ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5"
which should be:
ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5)"
If the error was more intelligible, I would not lose 2 days to look for this problem :/