How to read all data from SAP GUI window with VBA - vba

I'm trying to automate T-Code-VA03.
I enter the PO number in PO number text box and press F8.
This prompts a window which contains multiple rows of labels.
My requirement is, I want to select the one with latest date. I tried to record the script for it and below the code.
session.findById("wnd[0]/usr/txtRV45S-BSTNK").text = "123456789"
session.findById("wnd[0]/usr/txtRV45S-BSTNK").setFocus
session.findById("wnd[0]/usr/txtRV45S-BSTNK").caretPosition = 8
session.findById("wnd[0]").sendVKey 8
session.findById("wnd[1]/usr/lbl[49,6]").setFocus
session.findById("wnd[1]/usr/lbl[49,6]").caretPosition = 0
I can see there are labels with indexes. How can I iterate through whole window and take the focus to row with latest date?

With VB script you could try the following:
. . .
session.findById("wnd[0]").sendVKey 8
for i = 6 to 99
on error resume next
session.findById("wnd[1]/usr/lbl[49," & cstr(i) & "]").setFocus
if err.number <> 0 then Exit for
on error goto 0
session.findById("wnd[1]/usr/lbl[49," & cstr(i) & "]").caretPosition = 0
next
Regards,
ScriptMan

If you really need to do something like iterating through window and taking the focus to row with latest date, do not do it with VBA, because you may get into lots of problems.
Having said the one above, try with sendkeys https://msdn.microsoft.com/en-us/vba/excel-vba/articles/application-sendkeys-method-excel and send TAB. Then make a code searching for "Item" in your form. After this, send tab 8 times to go to the PO Date. Write the date on a list. Send TAB again 11 times to the next date. Write it on a list. And so, until there are no more dates.
Anyhow, as I mentioned, this is not a great solution. The best way is simply to ask the DB Admin for read-only access to the DB or a customized view. With it, you can make a robust solution, which reads the latest date.

Related

Word VBA: Static Status dialog window

I've created a form that works well with macros running in the background to validate data and then print the document to a specific printer on the network.
The key element of this process is a production number value which I would like to keep a running log of and display in a static status dialog window. In other words, a popup window similar to a MsgBox that would not interfere with other actions on the form, but float on top of the document.
Visual concept of this would be...
User could shift the window away from their work if needed. Close the window if they desired, but pragmatically I want to re-pop/refresh the data in the window each time the background macro completes.
I can't use MsgBox, because it forces a closure of the window before the user can continue working on the document. I just want this visible to the user so they know what was last worked on and the few prior to that.
Any idea what control I might be able to use, or switch to MsgBox that would allow the user to continue working?
Ken...
PS: I found this and am trying to find a way to make this work for me. So far I have managed to get to function in the manner I want, but the lingering issue is how to call this PS script and include the information I need to display.
Alternatives to MsgBox in VBScript - StackOverflow
PPS: I opted to go a slightly different route and release the form with a MsgBox that is displayed at the end of the macro. I describe this in the solution noted below.
Instead of using a MsgBox, please consider using a VBA Userform. They're not much more complicated to use than a MegBox, but you can set them to be Modeless. Modeless dialogs remain open on-screen while you work on the Word document. Here'is Microsoft's page on setting dialogs as Modal or Modeless: Show method
If you search on VBA modeless dialog, you'll find many other helpful pages on the subject.
After doing much research, I've come back to revising my macro to incorporate static variables and a MsgBox at the end to report the last 5 production numbers that have been printed.
To provide a means of bringing up this MsgBox for reference, between printing runs, I created an OnlyNum variable as string and replaced the MsgBox I had for letting the users know they were only to use numbers in this field with that message. The end of that trap diverted the flow to the bottom of the macro (where the MsgBox that displayed the last five print jobs has been placed).
So, when the status MsgBox is displayed as a result of printing it only shows the last five events. If the trap captures it, it shows the message letting the user know to only use numerals and then displays the last five events.
Code reference:
Private Sub CommandButton1_Click()
Dim Prod As String
Dim Temp As String
Dim OnlyNum As String
Static ProdNum1 As String
Static ProdNum2 As String
Static ProdNum3 As String
Static ProdNum4 As String
Static ProdNum5 As String
'Check for only numeric value of TextBox1.Text
If Not IsNumeric(TextBox1.Value) Then
OnlyNum = "only numbers allowed" & vbCrLf & vbCrLf
Cancel = True
GoTo NotToday
End If
'Remove any spaces from TextBox1.Text
Prod = Replace(TextBox1.Text, " ", "")
'If the resulting lenght is equal to 7 Print it.
If Len(Prod) = 7 Then
ActiveDocument.PrintOut
'Update recent production numbers (5 in total)
ProdNum5 = ProdNum4
ProdNum4 = ProdNum3
ProdNum3 = ProdNum2
ProdNum2 = ProdNum1
ProdNum1 = Prod & " - " & Now() ' Insert a new production number with timestamp
TextBox1.Text = "" 'Clear the value of TextBox1.Text to prepare for the next Production number
Else
MsgBox ("Production Numbers must be 7 digits and contain only numerials.")
End If
NotToday:
Application.ActivePrinter = Temp
MsgBox (OnlyNum & ProdNum1 & vbCrLf & ProdNum2 & vbCrLf & ProdNum3 & vbCrLf & ProdNum4 & vbCrLf & ProdNum5)
OnlyNum = "" 'Reset value of OnlyNum
End Sub

Running a report directly and from a navigation form - reference issue

I have a form in MS Access (365) which accepts various selection criteria and runs a report with those criteria built into the wherecondition of a DoCmd.OpenReport command. The report is run via a button with On Click VBA code, since the wherecondition has to be built according to which, if any, criteria have been chosen. That all works fine when I open the selection criteria form directly. I want to open the selection criteria form via a navigation form, since there will be other, similar reports with selection criteria that I want to run from within the same navigation form.
As stated above, everything works when I open the selection criteria form directly and run the report but when I tried it via a navigation form, it didn't work. That's ok, I found a solution on the MS Dev Center site which works when I run the selection criteria form (and then the report) from the navigation form. All fine. But then (of course) the references within the button On Click code don't work when I open the selection criteria form directly and run the report. I would like to be able to run the selection criteria form and then the report from both positions - directly from MS Access and via the navigation form. There will presumably be some way to achieve this but (as I said above, I am new to MS Access and VBA) I could spend a lot of time clutching at shadows. Hopefully, someone will be able to tell me the simplest way to do this?
Code sample with relevant comments below. On runnning the selection criteria form and report directly, the line commented as AAA works ok, MsgBox ABB and DDD and those beyond all show; on running them via the navigation form, line BBB works ok, MsgBox ABB and DDD and those beyond all show (well, they would except that I haven't yet coded the [NavigationSubform] option into all the other whereconditon building stuff). When I switch the lines AAA and BBB (ie, comment the other one out) MsgBox AAA show ok, then it fails with:
Can't find referenced form "frmSelectSpeciesSiteDates"
before reaching MsgBox DDD.
MsgBox "ABB"
'If Not Forms![frmSelectSpeciesSiteDates]![cboCommonName] = "" Then
' AAA Works when frmSelectSpeciesSiteDates is run directly
If Not Forms![frmNavSelectiveReports]![NavigationSubform].[Form]![cboCommonName] = "" Then
' BBB Works when frmSelectSpeciesSiteDates is called from a navigation form
strWhereCondition = strWhereCondition & "[common name] = " & Chr(34) & Me![cboCommonName] & Chr(34)
End If
MsgBox "DDD"
You have a form named frmSelectSpeciesSiteDates which has a combobox named cboCommonName. The form also includes VBA code which uses the combobox value to modify a string variable ...
strWhereCondition = strWhereCondition & "[common name] = " & Chr(34) & Me![cboCommonName] & Chr(34)
However you only want to modify the string when the combobox contains something other than an empty string. And that is where you're struggling. You reference the combobox one way when the form is opened directly as a top-level form, and another way when it is contained in a navigation form ...
Forms![frmSelectSpeciesSiteDates]![cboCommonName]
Forms![frmNavSelectiveReports]![NavigationSubform].[Form]![cboCommonName]
I suggest you abandon both of those and refer to the combobox the same as where you modify the string (Me!cboCommonName) ...
If Not Me!cboCommonName = "" Then
strWhereCondition = strWhereCondition & "[common name] = " & Chr(34) & Me!cboCommonName & Chr(34)
End If

VBA SeleniumBasic - Clickables no longer work after missing one

I built a very complex SeleniumBasic via VBA via Excel Addin setup that interacts with one of the leading ticketing system websites to scrap and populate data. The system interacts with 90+ different fields/clickables with 3 different pages, 6 different tabs, and nested popups...deployed to 120 users who use the automations about 20 times per day.
And it has been working flawlessly for over a year...
We have just provisioned 20 more users on the same system, and their automations refuse to work.
Here is where I am at with my research:
I am able to manually step through code on the new system and have it successfully go through the entire automation, so the issue probably has something to do with the speed VBA/Selenium is trying to interact with the website.
Once the system is unable to find a field or clickable, it refuses to find any other ones after that.
The way the system is built in order to go as fast as possible is via standard VBA error handling. It fails to find something, it goes to the error handler, the error handler says to wait for one second then try again. Again, this system has been working flawlessly for over a year and is currently working on 120 user's systems.
To see if maybe Selenium was refusing to reload the clickable, I broke out the error handling from a Resume to a Resume Next, and then had a do while loop with a boolean flag to keep trying until it was successful, but after the first failure, it refused to find anything else, including different fields
The one thing the 20 new users have in common is that they are all using v66 of Chrome, whereas all of the systems that are working have old copies of Chrome that are at least 9 months old
Thinking this might be an issue, I grabbed all of the ChromeDrivers and systematically went through one by one to test if we got a different performance with a different ChromeDriver, but all of the ChromeDrivers had the same error
So that is where I stand. I'm wondering if there is some key insight I am missing or a workaround that will get newer versions of Chrome to retry the fields. Or...do I need to try a VBA/Selenium tool other than SeleniumBasic to fix this. Or...do I need to roll back these 20 users to older versions of Chrome.
Thanks for sharing your expertise.
''''Check to see if there are any aliases=================================
For AliasCheck = 2 To AliasCounter + 1
If Hash = Sheets("Temp Subjects & Locations").Range("AY" & AliasCheck) Then
AliasName = Sheets("Temp Subjects & Locations").Range("AY" & AliasCheck)
AliasCount = AliasCount + 1
AliasDisplayName = Sheets("Temp Subjects & Locations").Range("AZ" & AliasCheck)
temp1 = ""
temp2 = ""
Call countryDictionary
'drops the country back into Excel to later remove the dupes
temp1 = Sheets("Temp Subjects & Locations").Range("BA" & AliasCheck)
temp2 = dict(temp1)
Sheets("Temp Subjects & Locations").Range("BG" & AliasCount + 1) = temp2
''''Click to add AKA's names
iframeText = "iframe_win_" & AddParty
robot.SwitchToDefaultContent
robot.SwitchToFrame iframeText
iframeTracker = iframeTracker + 1
iframeText = "iframe_win_" & iframeTracker
robot.SwitchToDefaultContent
robot.SwitchToFrame iframeText
robot.FindElementById("X_SUBJECT_ALTERNATE_NM.X_ALTERNATE_NM").SendKeys (AliasDisplayName)
robot.FindElementById("dijit_form_Button_0").Click
End If
Next AliasCheck
The AddParty variable is a way to track the number of the pop-up we came from.
The iFrameTracker variable is a way to track the number of the pop-up we are going to...the system sequentially numbers its pop-ups...instead of legible names...
The newer systems will make it down to the SendKeys and then decide not to work. On a resume next, it will then refuse to find the OK button ("dijit_form_Button_0")
Here is the code I was playing around with to see if I could get it to retry using a "Resume Next" instead of a "Resume"
robot.FindElementById("X_SUBJECT_ALTERNATE_NM.X_ALTERNATE_NM").SendKeys (AliasDisplayName)
Do While FailRetry = True
FailRetry = False
robot.FindElementById("X_SUBJECT_ALTERNATE_NM.X_ALTERNATE_NM").SendKeys (AliasDisplayName)
Loop
errHandler4:
If errorCounter < 21 Then
Application.wait (Now + TimeValue("00:00:01"))
errorCounter = errorCounter + 1
FailRetry = True
Resume Next
Else
MsgBox "Reached 20 second timeout. Stopping processing."
Exit Sub
End If

How to make an if statement to stop access from running query?

I'm using Microsoft access and I want to make an if statement that basically does:
if the search criteria are all blank, then open a message box that says "something I write" and an OK button. The ok would throw you back to the search from and not run query.
My issue is that if all of the search criteria are left blank and someone hits search, it'll crash access. So I wanna make something that'll stop someone from running the query in blank. I am using a form with 6 different criteria's called Standards, Duds, ID, Desc1, Desc2, and Excel.
Just to let everyone know too, I am pretty stupid when it comes to coding and stuff so if you could spell it out in a way a 4 year old could understand that'd be great.
I would like something that reads:
If [Forms]![Search]![Standards] AND [Forms]![Search]![CADID] is blank then
MsgBox("You cant do this") - and then this would send you back to the form
ElseIf
Run the query normally.
Currently my code looks a bit like:
SELECT DISTINCT Standards.Name, Standards.[Catalog Id], - then a bunch of other tables and their respective columns
WHERE(((Standards.Name)Like"*"& [Forms]![Search]![Standards] & "*") AND ((Standards.[Catalog ID]) Like "*" & [Forms]![Search]![CADID] & "*"));
I dont know why it ends there. Where it reads [Standards] and [CADID] after WHERE are the text boxes a user and write in a form.let me know how much more detail you need.
Not sure what your search code is, but here's a template to work with. Put this in the On-click event of the button that executes your search and make sure you add whatever code executes your search in place of the comment I've left in the else part of the If statement below.
If _
(IsNull([Forms]![Search]![Standards]) Or _
[Forms]![Search]![Standards] = "") And _
(IsNull([Forms]![Search]![CADID]) Or _
[Forms]![Search]![CADID]) = "" _
Then
MsgBox "Please complete both Standards and CADID fields before searching", vbCritical Or vbOKOnly, "Search Error"
Else
' your search code here
End If

Use toggle buttons to update a record in Access

Hopefully not too difficult question but I cannot figure this out and have been unable to find anything searching the forums.
I want to convert the output of my toggle boxes from 1,2,3,4,5 to the text each button displays.
Couldn't find any setting on the toggle boxes properties themselves so decided I would have to write a macro/vba to do it from the table but as it's quite new to me I am struggling on syntax.
I have tried doing this on the inbuilt data macro mainly, but also tried it via a query and vba and still couldn't figure it out.
[don't have any reputation yet so have not been allowed to post pics of my macro attmept]
please help! Any solution using vba, data macro or a query would be great
EDIT
To be specific rather than a message box I want to update field1 in my table "Major Equipment" based off the option group selection this is my latest attempt but still not sure how to reference the option group. Do I need to set grp equal to the option group and if so how? Is it something like forms!myform!optiongroup ?
Option Compare Database
Function MyFunc(grp As OptionGroup)
Dim rcrdset As Recordset
set grp =
Set rcrdset = Application.CurrentDb.OpenRecordset("Major Equipment", dbOpenDynaset)
Select Case grp.Value
Case 1
With rcrdset
.AddNew
![Field1] = "Not Reviewed"
Case 2
.AddNew
![Field1] = "Reviewed"
Case Else
MsgBox "Error"
End Select
End Function
Also just realised since these toggle buttons will be updated by the user and so I probably need an update rather than addnew?
http://i59.tinypic.com/2ym8wet.jpg
Your buttons are part of an Option Group. That is what you must reference. Below is a snippet from my net search.
From the AfterUpdate() event of your Option Group:
Call MyFunc(Me.MyGroup)
... which will use Select Case to evaluate:
Function MyFunc(grp As OptionGroup)
Select case grp.Value
Case 1
MsgBox "Option value is 1."
Case 2
MsgBox "Option value is 2."
Case Else
MsgBox "Huh?"
End Select
End Function
If you are entirely new to VBA, there are a half-dozen things to learn here, but they will serve you well. VBA provides a bit less-friendly-looking start than a macro, but I can tell you have more adventures ahead and I suggest you skip macros. For most needs, VBA will serve you better; and it's much easier to trouble shoot or provide details when you need advice.
To convert this to a useful function, you will fill a string variable rather than raising a message box. Then you can use the string variable to do something like run an update query. Your latest edit suggests you will go for something like:
strSQL = "UPDATE [Major Equipment] " _
& "SET Field1='" & strUserSelection & "' " _
& "WHERE MyID=" & lngThisRecord
DoCmd.RunSQL strSQL
Your last edit proposes using a DAO recordset. I think you might be fine with the humble DoCmd. Less to learn. You can hammer out a prototype of the query in good ol' Access; then switch to SQL View and paste the query into your VBA module. Insert variables as seen above, taking care with the quote marks. If it doesn't work, use Debug.Print to grab the value for strSQL and take that back to good ol' Access where you can poke at it into shape; use your findings to improve the VBA.