Save SM37 rows with sorting via GUI Script? - excel

The following SAP GUI Script for SAP 740 saves the SM37 list to a text file.
Before saving the list, I'd like to sort the list by Start date and Start time.
I can display the popup to select Sort fields. On left side there is a table control with current Sort columns (job name, created by, progress, scheduled start date, scheduled start time), on right side there is a table control with all possible Sort columns, each of these left and right Sort columns can be selected, and between the two table controls there are buttons to move Sort columns from left to right or vice versa.
Now, to select Sort columns, I have to select rows of table controls, but I don't know how to do it. Can you help me?
Public Sub RunSM37Cancelled()
Dim W_Ret As Boolean
W_Ret = Attach_Session
If Not W_Ret Then
Exit Sub
End If
On Error GoTo disperr
objSess.findById("wnd[0]").maximize
objSess.findById("wnd[0]/tbar[0]/okcd").Text = "sm37"
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/txtBTCH2170-JOBNAME").Text = "*"
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/txtBTCH2170-USERNAME").Text = "*"
objSess.findById("wnd[0]/usr/txtBTCH2170-USERNAME").SetFocus
objSess.findById("wnd[0]/usr/txtBTCH2170-USERNAME").caretPosition = 1
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/chkBTCH2170-SCHEDUL").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-READY").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-RUNNING").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-FINISHED").Selected = False
objSess.findById("wnd[0]/usr/chkBTCH2170-ABORTED").Selected = True
objSess.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").Text = Format(Now()-1,"mm/dd/yyyy")
objSess.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").SetFocus
objSess.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").caretPosition = 10
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").Text = Format(Now(), "mm/dd/yyyy")
objSess.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").SetFocus
objSess.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").caretPosition = 10
objSess.findById("wnd[0]").sendVKey 0
objSess.findById("wnd[0]/tbar[1]/btn[8]").press
objSess.findById("wnd[0]/usr/lbl[80,10]").SetFocus
objSess.findById("wnd[0]/usr/lbl[80,10]").caretPosition = 5
objSess.findById("wnd[0]").sendVKey 2
objSess.findById("wnd[0]/usr/lbl[91,10]").SetFocus
objSess.findById("wnd[0]/usr/lbl[91,10]").caretPosition = 4
objSess.findById("wnd[0]").sendVKey 2
' Display sort dialog (41 = Ctrl+Shift+F5 = menu Edit > Sort in ascending order)
objSess.findById("wnd[0]/tbar[1]/btn[41]").press
' <<<< Here, how to select lines in left and right table controls?
' Downloading the file
fileobjSess.findById("wnd[0]/mbar/menu[5]/menu[5]/menu[2]/menu[1]").Select
objSess.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").Select
objSess.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").SetFocus
objSess.findById("wnd[1]/tbar[0]/btn[0]").press
objSess.findById("wnd[1]/usr/ctxtDY_PATH").Text = ffilepath
objSess.findById("wnd[1]/usr/ctxtDY_FILENAME").Text = ffilename
objSess.findById("wnd[1]/usr/ctxtDY_FILENAME").caretPosition = 8
objSess.findById("wnd[1]/tbar[0]/btn[11]").press
Exit Sub
disperr:
MsgBox "Error occured while retrieving data", vbCritical + vbOKOnly
End Sub

To select a row by its position in a table control, you need to determine the name of the table control, then use the method tableControl.getAbsoluteRow(row) to get the instance of the row, and set its property Selected = True. Example :
tableControl = objSess.findById("wnd[1]/usr/tblSAPLSKBHTC_FIELD_LIST_820")
tableControl.getAbsoluteRow(6).Selected = True
Now, to answer your specific question (ALV sorting in SM37), you also need to press additional buttons to select the Sort fields.
The Sort dialog screen is made of two table controls. You may first press the button "Hide all fields" to move all fields to the right table control (fields not selected), then select the fields on the right table control (as explained in the first paragraph) and press the buttons "Show sel. fields (Ctrl+F3)" and "Copy (Enter)".
You need to know the row number of the field you want to select in the right table control. In an ABAP 7.52 system, these fields are listed in this sequence (first one is row 1, second one is row 2 and so on):
Job name
Spool list
Job documentation
created by
status
start date
start time
duration
...
You also need to know the name of the right table control. For that, you may select the menu System > Status, double click the number of "screen/dynpro" which displays the technical names of screen elements. In your case, you see TC_FIELD_LIST_820. You also see that the screen belongs to the program SAPLSKBH.
The final program would look like this:
ffilepath = "your path here"
ffilename = "Test.txt"
With objSess
.findById("wnd[0]").Maximize
.findById("wnd[0]/tbar[0]/okcd").Text = "/nsm37"
.findById("wnd[0]").sendVKey 0
.findById("wnd[0]/usr/txtBTCH2170-JOBNAME").Text = "*"
.findById("wnd[0]/usr/txtBTCH2170-USERNAME").Text = "*"
.findById("wnd[0]/usr/chkBTCH2170-SCHEDUL").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-READY").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-RUNNING").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-FINISHED").Selected = False
.findById("wnd[0]/usr/chkBTCH2170-ABORTED").Selected = True
.findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").Text = Format(Now() - 1, "mm/dd/yyyy")
' .findById("wnd[0]/usr/ctxtBTCH2170-FROM_DATE").Text = Format(Now() - 1, "dd/mm/yyyy")
.findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").Text = Format(Now(), "mm/dd/yyyy")
' .findById("wnd[0]/usr/ctxtBTCH2170-TO_DATE").Text = Format(Now(), "dd/mm/yyyy")
.findById("wnd[0]/tbar[1]/btn[8]").press
' Display sort dialog (41 = Ctrl+Shift+F5 = menu Edit > Sort in ascending order)
.findById("wnd[0]/tbar[1]/btn[41]").press
' Remove all previous sort fields (press pushbutton named "APP_FL_ALL")
.findById("wnd[1]/usr/btnAPP_FL_ALL").press
' Select sort field(s) (row 6=start date, row 7=start time)
with .findById("wnd[1]/usr/tblSAPLSKBHTC_FIELD_LIST_820")
.getAbsoluteRow(6).Selected = True
.getAbsoluteRow(7).Selected = True
end with
' Press pushbutton "Show sel. fields"
.findById("wnd[1]/usr/btnAPP_WL_SING").press
' Press key "Enter" (corresponds to pushbutton "Copy (Enter)")
.findById("wnd[1]/tbar[0]/btn[0]").press
' Downloading the file
.findById("wnd[0]/mbar/menu[5]/menu[5]/menu[2]/menu[1]").Select
.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").Select
.findById("wnd[1]/tbar[0]/btn[0]").press
.findById("wnd[1]/usr/ctxtDY_PATH").Text = ffilepath
.findById("wnd[1]/usr/ctxtDY_FILENAME").Text = ffilename
.findById("wnd[1]/tbar[0]/btn[11]").press
End With

Related

update data via macro from another workbook

I need some help with vba code. I'm self-lerning so please be understanding for simply cases ;)
I'm trying to create macro which will be looking for some records/cells in one workbook (FileA) (determined by 3 conditions) and then paste values to another workbook (FileB) and after that find in another tab in FileB some values where condition will be pasted value to match them with looking value (I belivie it could be done somehow with Vlookup but I get stuck).
Below problematic for me part of code (I'm working on some files found in work, no one use it now).
First issue is with Set Update, I don't know why it takes it as "Nothing"... conditions are true - I mean "pp1" is existing in column A in FileA.
Second issue shows when I change i start range to some "later" numbers, eg From i = 2280, macro is ignoring last line where should assign some values (again shows update2 as "nothing") but value if pp2 is existing in W column in tab data...
Dim name As String
name = "[path to file on sharepoint]"
Application.ScreenUpdating = False
Workbooks.Open Filename:=name
a = 1
For i = 2263 To 14000
If Workbooks("FileA").Sheets("Main").Cells(i, 11) = "CANCEL" And Workbooks("FileA").Sheets("Main").Cells(i, 6) = "DENIS" And Workbooks("FileA").Sheets("Main").Cells(i, 5) > 1301358454 Then
pp1 = Workbooks("FileA").Sheets("Main").Cells(i, 1)
If pp1 > 0 Then
Set Update = Workbooks("FileA").Worksheets("Main").Range("A:A").Find(pp1, lookat:=xlPart)
If Update > 0 Then
Update = Update.Row
Workbooks("FileB").Worksheets("lost").Cells(a, 1).Value = Workbooks("FileA").Worksheets("Main").Cells(Update, 5)
pp2 = Workbooks("FileB").Worksheets("lost").Cells(a, 1)
update2 = Workbooks("FileB").Worksheets("data").Range("W:W").Find(pp2, lookat:=xlPart).Row
Workbooks("FileB").Worksheets("lost").Cells(a, 5) = Workbooks("FileB").Worksheets("data").Cells(update2, 43)

Cycle through a loop in VBA

I have a form in VBA where I want a combo box (cboIncluded) to change its dropdown values according to what's chosen in a different combo box(cboSelectParty).
It provides choices correctly the first time I choose something from cboSelectParty, and if I choose again from either my If or elseif.
My problem is, if I have chosen from either the if or elseif (Fun climb party or climbing party), if won't go back to giving me correct options if I choose anything else.
Private Sub cboSelectParty_AfterUpdate()
cboIncluded.Value = ""
If cboSelectParty.Value = "Fun Climb Party" Then
cboIncluded.List = Sheets("PartyImport").Range("N3:N4").Value
ElseIf cboSelectParty.Value = "Climbing Party" Then
cboIncluded.List = Sheets("PartyImport").Range("O3:O6").Value
Else
cboIncluded.Value = Application.WorksheetFunction.VLookup(cboSelectParty.Value,
Sheets("PartyImport").Range("E2:H37"), 4, False)
End If
End Sub

Clear ComboBox Containig an Array VBA and Repopulate with Column Index

I have a sigle column ComboBox that I have populated with a dynamic array; however, I'd like the code to replace the value of the combo box with respective column from my ListBox.
'Prepares the Active Escorts list box.
ivb = 0
i = 0
With frmEntry
.listboxActiveEscorts.Clear
.listboxActiveEscorts.ColumnHeads = False
.listboxActiveEscorts.ColumnCount = "15"
.listboxActiveEscorts.ColumnWidths = "0,100,100,0,0,100,100,0,0,0,0,0,100,100,80"
i = 0
'Badge # combobox properties
ReDim vbArray(0 To vbArrayCount - 1)
For i = 0 To vbArrayCount - 1
ivb = ivb + 1
vbArray(ivb - 1) = loVisBadge.Range.Cells(i + 2, 1).Value
Next i
.cbxVisitorBadgeNumber.List = vbArray
End With
This population of the ComboBox executes beautifully, in my belief, but if you see a better way to implement the dynamic list, I'm all ears.
I have a button that I will use to reset the form, which also works for the most part. When an item is selected from the list, I am able to clear all controls except for the ComboxBox containing the array of values. I will be adding two additional arrays to each of the other ComboBoxes on the form, and I imagine I am going to have the same problem: "Could not set the value property. Invalid property value"
This is the code assigned to click event of the ListBox:
Private Sub listboxActiveEscorts_Click()
With frmEntry
.cbxEscortSelectName.Value = .listboxActiveEscorts.Column(1) + " " + .listboxActiveEscorts.Column(2)
.txtCredential.Value = .listboxActiveEscorts.Column(4)
.txtEscortCompany.Value = .listboxActiveEscorts.Column(3)
.cbxVisitorName.Value = .listboxActiveEscorts.Column(5) + " " + .listboxActiveEscorts.Column(6)
.txtVECompany.Value = .listboxActiveEscorts.Column(7)
.txtVEDOB.Value = .listboxActiveEscorts.Column(8)
.txtVEIdentification.Value = .listboxActiveEscorts.Column(9)
.txtVEIDNumber.Value = .listboxActiveEscorts.Column(10)
.txtVEExpirationDate.Value = .listboxActiveEscorts.Column(11)
.txtVEStart.Value = .listboxActiveEscorts.Column(12)
.txtVEEnd.Value = .listboxActiveEscorts.Column(13)
'.cbxVisitorBadgeNumber.Value = ""
.cbxVisitorBadgeNumber = vbNullString
.cbxVisitorBadgeNumber.Value = .listboxActiveEscorts.Column(14)
End With
End Sub
What am I missing here. I tried to ReDim the array that assigned the values, but that didn't work. Is it a data type thing, perhaps?
In the picture below, you'll see the values populated in the controls, all except the visitor badge # (ComboBox which throws the error...I have commented out the line for illustration purposes, so you'll see the visitor badge # is blank).

Dropdown list with Adodb query

I would like to create the dropdown list with the results from my query. I'm looking for help please because I don't know how to display this results on the list.
The exemple of the list:
My query is :
'DROPDOWN LIST
Private Sub cb_gest_Change()
If Not FSD.cb_gest.MatchFound And FSD.cb_gest <> "" Then
MsgBox "Saisie impossible, le gestionnaire n'existe pas !", , "ContrĂ´le
Gestionnaire"
FSD.cb_gest = ""
Else
FSD.Cells(29, COL_DATA) = FSD.cb_gest
End If
End Sub
'DROPDOWN LIST
Sub init_combo()
Dim Resultat As ADODB.Recordset
Dim Requete As String
FSD.cb_gest.Clear
Requete = "select lb_gestion from DB_GESTIONNAIRE "
Requete = Requete + "WHERE (d_deb_valid <= TRUNC(SYSDATE) OR d_deb_valid IS
NULL) AND (d_fin_valid >= TRUNC(SYSDATE) OR d_fin_valid IS NULL)"
Requete = Requete + " ORDER BY LB_GESTION"
Set Resultat = New ADODB.Recordset
Resultat.ActiveConnection = oBase
Resultat.Source = Requete
Resultat.Open
While Not Resultat.EOF
FSD.cb_gest.AddItem Resultat!lb_gestion
Resultat.MoveNext
Wend
If FSD.Cells(29, COL_DATA).Value <> "" Then
FSD.cb_gest = FSD.Cells(29, COL_DATA).Value
Else
FSD.Cells(29, COL_DATA).Value = ""
End If
End Sub
Thank you for your help !
Consider a different, codeless approach:
Add a new sheet to the host document / workbook
Import the external data from the "Data" Ribbon tab (select "From SQL Server")
Excel creates a ListObject table backed with a QueryTable object that uses a WorkbookConnection that can be configured to automatically refresh on open, or left alone as a one-time pull.
Select the produit column in the ListObject/table; Excel highlights the entire column content and leaves the heading un-selected.
From the "Formulas" Ribbon tab, click the "Define Name" command in the "Defined Names" group.
Name the range ProductsList, verify it refers to TableName[produit] so that it automatically grows and shrinks to fit the column contents.
Change the data validation list to =ProductsList.
Hide the worksheet housing the query and table, if needed.
No code needed, and the validation list will always keep up with the query results as they are refreshed.
Side note, the query appears to be making inefficient cross-joins, and at least one of them is a where-join that can be expressed as an inner join. Are you sure the query is yielding the expected records (I'm suspecting it's yielding a ton of duplicates, depending on how many records exist in the cross-joined tables)?
SELECT prod.cd_produit AS produit
FROM db_dossier sousc, db_produit prod, db_protocole proto, db_tiers tiers, db_personne pers
WHERE sousc.cd_dossier = 'SOUSC' AND sousc.lp_etat_doss NOT IN ('ANNUL','A30','IMPAY') AND sousc.is_produit = prod.is_produit
Instinct would be to remove the tables we're not selecting or filtering anything from - if this query produces the same expected output, then assuming primary and foreign keys are defined I believe its execution plan would be more efficient:
SELECT prod.cd_produit AS produit
FROM db_dossier AS sousc
INNER JOIN db_produit AS prod ON sousc.is_produit = prod.is_produit
WHERE sousc.cd_dossier = 'SOUSC' AND sousc.lp_etat_doss NOT IN ('ANNUL','A30','IMPAY')

Validate a TextBox before the _Change event is fired

I've got a form that has 3 TextBox controls on it: stock code, quantity, certificate number. The stock code TextBox is set to focus automatically when the form is loaded.
I've also attached a bar code scanner to my PC, as the user wants to be able to either scan a bar code to populate the TextBox, or manually type the data in.
The labels being scanned contain two bar codes. One is a certificate number and the other a stock code.
The stock bar code has a prefix of "SBC/", whilst a certificate bar code is prefixed with "C/".
When the user scans a bar code, if the TextBox in focus is the stock code TextBox, then I want to run a check as below.
Private Sub txtStockCode_Change()
On Error GoTo errError1
If Len(txtStockCode.Text) >= 5 Then
If bChangeCode Then
If Left(txtStockCode.Text, 2) = "C/" Then
msgbox "You have scanned the certificate barcode; please scan the stock barcode."
txtStockCode.Text = ""
Else
bChangeCode = False
txtStockCode.Text = Replace(txtStockCode.Text, "SBC/", "")
txtStockCode.Text = Replace(txtStockCode.Text, "*", "")
End If
End If
End If
Exit Sub
Let's say the focus is currently on the stock code TextBox.
If the stock bar code is scanned, the following should happen:
Stock code length is greater than 5
Left 5 characters do not = "C/", so correct code has been scanned
TextBox text value is updated to remove all * and the prefix of "SBC/"
E.g. "SBC/A12-TR0*" becomes "A12-TRO"
and
Certificate number length is greater than 5
Left 5 characters do = "C/", so incorrect code has been scanned
MsgBox to user
TextBox value is reset to ""
However, no matter which code is scanned into the stock code TextBox, the value is never validated.
E.g. "SBC/A12-TR0*" remains as "SBC/A12-TR0*" and "C/29760" remains as "C/29760"
As the validation code is the same in the certificate TextBox, the same pattern is repeated vice versa.
Why are my values not updating, or how can I validate the input before the _Change is fired?
EDIT
I've now changed my code to
Private Sub txtStockCode_Change
If txtStockCode.Text <> "" Then
txtStockCode.Text = Replace(txtStockCode.Text, "SBC/", "")
txtStockCode.Text = Replace(txtStockCode.Text, "*", "")
End If
End Sub
But it still displays the prefix of SBC/, yet is removing the two * characters (at the start and end of the barcode as is required for the scanner to read it as a barcode)
You could try to set the barcode reader to return Enter key at the end of the scanned barcode and then use the Keypress event to check it and make your changes.
Sub txtStockCode_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
If Len(txtStockCode.Text) >= 5 Then
If bChangeCode Then
If Left(txtStockCode.Text, 2) = "C/" Then
msgbox "You have scanned the certificate barcode; please scan the stock barcode."
txtStockCode.Text = ""
Else
bChangeCode = False
txtStockCode.Text = Replace(txtStockCode.Text, "SBC/", "")
txtStockCode.Text = Replace(txtStockCode.Text, "*", "")
End If
End If
End If
End If
End Sub

Resources