No RFC authorization for function module RFC PING from VBA? - vba

Good morning, everybody!
I've been looking for the solution in the last days but I really have not managed to succeed: I am trying to make a VBA code to:
log into SAP,
run some transactions,
export to excel.
But even the "log into SAP" part is not OK!
I tried several codes, the one below OPENS the SAP logon screen, but does not fill in any fields.
In the first attempt, I Used CreateObject("Sapgui.ScriptingCtrl.1"):
Sub Entrar_SAP()
If Not IsObject(SAPguiApp) Then
Set SAPguiApp = CreateObject("Sapgui.ScriptingCtrl.1")
End If
If Not IsObject(Connection) Then
Set Connection = SAPguiApp.OpenConnection("xxxxxxx)", True)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
session.findById("wnd[0]/usr/txtRSYST-MANDT").Text = "100"
session.findById("wnd[0]/usr/txtRSYST-BNAME").Text = "user"
session.findById("wnd[0]/usr/pwdRSYST-BCODE").Text = "pass"
session.findById("wnd[0]/usr/txtRSYST-LANGU").Text = "PT"
session.findById("wnd[0]/usr/txtRSYST-LANGU").SetFocus
session.findById("wnd[0]/usr/txtRSYST-LANGU").caretPosition = 2
session.findById("wnd[0]").sendVKey 0
In the second attempt, I tried CreateObject("SAP.Functions"), it showed:
"RFC error received. No RFC authorization for function module RFC PING"
The code is:
'Declaration
Dim objBAPIControl As Object 'Function Control (Collective object)
Dim sapConnection As Object 'Connection object
Set objBAPIControl = CreateObject("SAP.Functions")
Set sapConnection = objBAPIControl.Connection
sapConnection.Client = "xxxxx"
sapConnection.User = "xxxxxx"
sapConnection.Language = "PT"
sapConnection.hostname = "xxxxx"
sapConnection.Password = "xxxxxxxx" 'Fake password
sapConnection.SystemNumber = "4"
sapConnection.System = "xxxxxx)"
sapConnection.Logon
If sapConnection.Logon(1, True) <> True Then
MsgBox "No connection to R/3!"
Exit Sub 'End program
End If
Can someone please help me? Thanks!!

First of all, RFC is a perfectly fine method for interacting with SAP. It's not out of support.
Second, you don't have enough authorization so your code will not work even if you get the syntax right. "RFC error received. No RFC authorization for function module RFC PING". Ask your SAP team to give you access to execute RFCs remotely. Ask for SAP_S_RFCACL.
On a side note, your main object of running some transactions and exporting to Excel is quite easy to do in SAP. Maybe you should just ask your SAP team to do it for you instead of developing it in VBA?

I assume your pulling via an RFC read Table. This Connection will work fine for those.
Dim LogonControl As Object
Dim conn As Object
Dim retcd As Boolean
Set LogonControl = CreateObject("SAP.LogonControl.1")
Set conn = LogonControl.NewConnection
conn.System = "strSystemName"
conn.Client = "100"
conn.Language = "EN"
conn.User = "sUserName"
conn.Password = "strPassword"
retcd = conn.Logon(0, True) 'True = No logon GUI 'False = logon GUI
If retcd <> True Then
MsgBox "Login failed for- " & strSystemName & " -UserName or Password are incorrect, check them and run try again ."
Exit Sub
End If
Set funcControl = CreateObject("SAP.Functions")
funcControl.Connection = conn
From this Point on you can make your RFC call without any issues.
But to be truthful though, Above is almost exactly what you have as your second example. your RFC Error your getting seems like you don't have security settings for SAP to make RFC calls to whatever table your pulling from and not a problem with your login code.
Disclaimer: RFC_READ_TABLE is NOT supported by SAP and is more of a backdoor then a day to day method for pulling data.
Edit1: To Cover the Comments and not turn this into a discussion I will try and Summarize them here.
Firstly
the pop-up: If you want the pop-up for the log in then you need to change this line of code
retcd = conn.Logon(0, True)
to
retcd = conn.Logon(0, False) 'This one DISPLAYS the pop-up
Secondly
The Permissions: RFC_Read_Table uses Very Different Security Settings then a SAP t-Code uses, The technical Difference is difficult to explain but for a rule of thumb, If you cant access the SAP Table (t-Code SE16) you most likely not be able to pull it from RFC Read Table
Thirdly
If your company has Multiple SAP boxes (DEV, production, test) the Systemname would be EXACTLY what shows up on the box selection screen of SAP under name. assuming you were getting an RFC error from your second code block then the box name you used in that code would be the correct one.

You can bypass RFC controls and just go for a normal scripting that imitates a human user and manually introduces username and password. Credit to The Script Man from the SAP forums:
Sub SapLogin()
'Logs onto SAP system
Dim SapGuiApp As Object
Dim oConnection As Object
Dim session As Object
Dim SAPCon As Object, SAPSesi As Object
Dim SAPGUIAuto As Object, SAPApp As Object
Dim system As String
system = "XX" 'SAP system you will log on to like "01. ENGINEERING PRODUCTION [EG1]
If SapGuiApp Is Nothing Then
Set SapGuiApp = CreateObject("Sapgui.ScriptingCtrl.1")
End If
If oConnection Is Nothing Then
Set oConnection = SapGuiApp.OpenConnection(system, True)
End If
If SAPSesi Is Nothing Then
Set SAPSesi = oConnection.Children(0)
End If
Application.DisplayAlerts = FALSE
With SAPSesi
.FindById("wnd[0]/usr/txtRSYST-MANDT").Text = "100"
.FindById("wnd[0]/usr/txtRSYST-BNAME").Text = "USERNAME"
.FindById("wnd[0]/usr/pwdRSYST-BCODE").Text = "PASSWORD"
.FindById("wnd[0]/usr/txtRSYST-LANGU").Text = "EN"
.FindById("wnd[0]").SendVKey 0
'start extraction
.FindById("wnd[0]").Maximize
.FindById("wnd[0]/tbar[0]/okcd").Text = "/TCODEYOUWANTTORUN"
.FindById("wnd[0]").SendVKey 0
'...
'etc
'...
End With
Application.DisplayAlerts = True
MsgBox "After clicking OK, this SAP session is terminated."
End Sub

Related

win32com and SAP-GUI

My SAP-GUI has Scripting installed and Scripting is enabled.
Like in this screenshot:
In this Introduction to SAP GUI Scripting in "Step 2: Setup your SAP System" you need to call RZ11.
I don't have permissions to call RZ11.
Is there a way to detect this (sapgui/user_scripting on or off) via a script?
At the moment I use below code, but the list of connections is always empty:
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
sapgui = win32com.client.GetObject("SAPGUI")
system = query.get('system')
client = query.get('mandant')
session = False
application = sapgui.GetScriptingEngine
seen = []
for i_conn in range(0, application.Connections.Count):
seen.append('i_conn=%s session_count=%s' % (i_conn, application.Connections.Item(i_conn).Sessions.Count))
for i_sess in range(0, application.Connections.Item(i_conn).Sessions.Count):
session_info = application.Connections.Item(i_conn).Sessions.Item(i_sess).Info
system_of_session = session_info.SystemName
client_of_session = session_info.Client
if system_of_session == system and client_of_session == client:
connection = application.Connections.Item(i_conn).Children(i_sess)
session = connection.Children(i_sess)
break
seen.append('system=%s client=%s' % (system_of_session, client_of_session))
if session:
break
else:
info_popup('You are not logged into system %s in Client %s! Seen:\n%s' % (
system, client, '\n'.join(seen)))
return
When you don't have sufficient priviledges in sap, the fact that you can't connect is a pretty good indication that the user does not have scripting enable (assuming the user has a active sap session running), other wise you could just test with 'session.findById("wnd[0]/usr/tblSAPLCMDITCTRL_3500").getAbsoluteRow(3).selected = true' and check for errors.
Also, I suggest you factor in "SAPGUISERVER' in your sapgui = win32com.client.GetObject("SAPGUI") connection if "SAPGUI" fails.
As I know sapgui/user_scripting is a system-level = application level setting but not a user-level. So, if you have no permissions to run RZ11 tcode then you have no opportunity or permissions to read applicaton server settings and, of course, no permissions to change it. You have to contact your basis administrator to verify this application settings with him.
You see, SAP limited scripting abilities due to possible vulnerability, that's why scripting support should be turned on both on client side and on application server side.
If you have access to interrogate the registery you could write a cutom function to check SAPGUI is installed and flagged e.g:
Public Sub CheckKey()
Const cRegKey As String = "HKEY_CURRENT_USER\Software\SAP\SAPGUI Front\SAP Frontend Server\Security\UserScripting"
If CheckSAPGUI(cRegKey) Then
MsgBox "User has SAPGUI installed and initialized", vbOKOnly Or vbInformation, Application.Name
Else
MsgBox "User does not have SAPGUI installed", vbOKOnly Or vbCritical, Application.Name
End If
End Sub
Public Function CheckSAPGUI(RegKey As String) As Boolean
Dim rtn As Variant
On Error Resume Next
rtn = vbNullString
With CreateObject("wscript.shell")
rtn = .RegRead(RegKey)
End With
If Len(rtn) = 0 Then
CheckSAPGUI = False
ElseIf Val(rtn) <> 1 Then
CheckSAPGUI = False
Else
CheckSAPGUI = True
End If
On Error GoTo 0
End Function
You should be able to modify the MsgBox comments to better suit how you want to interact with your end user

email from SQL ASP

I have a web portal based upon a SQL database, that we use to update progress. When a record has been updated in the queue the web form is supposed to send an email message.
Currently the web portal is not sending the message, and I am not sure of the point of failure. The portal itself is being updated as I can see the updated record in the SQL table. Just not receiving the email.
Update 04/27/18
So I am trying to attack this from a new avenue, and it is working kind of....
What I have done, is sent the form off to an external website using php, and it will send an email.
What I am wondering is how can I pass variables? I have been reading instructions for an hour, and it just doesn't make sense to me.
Essentially I want to pass one variable from the following query
thequery = "SELECT loginemail FROM users WHERE referrerId = " & request.Form("referrerID") & ""
objRS.open thequery, objConn, adOpenStatic, adLockReadOnly
and then pass it with something like this
<form action="https://xxxxxx.com/hello.php?loginemail" method="post" name="updateclientform" id="updateclientform">
On the php form side send the email based upon the variable "loginemail"
$to = trim(objRS("loginemail"));
Anyone help? PLEASE
CDO may not be supported by MS anymore - like Classic ASP itself, but it still works. I would look into a setting up a script in your ASP application to send the mail using CDO. That way you can better control any SQL injection threats and manage the whole process in one place.
Here is an example CDO mail script.
<%
'* Declare mailobject variables.
Dim validEmail, email_to, objCDOMail, objConf
Sub SetMailObject()
'* set up CDO config
Set objConf=Server.CreateObject("CDO.Configuration")
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mysmtp.server.com"
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "myusername"
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "mypassword"
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = False
objConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60
objConf.Fields.Update
' Create an instance of the NewMail object.
Set objCDOMail = Server.CreateObject("CDO.Message")
Set objCDOMail.Configuration=objConf
End Sub
Sub sendLoginEmail(email_to)
'* Call Sub to set mail object settings
SetMailObject()
'* Set the mail objects
objCDOMail.From = "myadmin#mydomain.com"
objCDOMail.To = email_to
objCDOMail.Bcc = ""
objCDOMail.Subject = "My mail subject"
objCDOMail.TextBody = "My email body"
'* Send the message
objCDOMail.Send
'* Set the object to nothing
Set objCDOMail = Nothing
End Sub
If Request("loginemail") <> "" Then
validEmail = Request("loginemail")
'* strongly suggest to perform some cleansing and validation of the email here
Call sendLoginEmail(validEmail)
End If
%>

How to show up a window of an application with VBA ? (Lotus Notes)

I want to display the Lotus Notes Window when the VBA code is writing the mail in Lotus Notes. I want the Lotus Notes window to be display during all of the operations.
I had tried this code:
Sub init_mail()
Dim oSess As Object
Dim ntsServer As String
Dim ntsMailFile As String
Set oSess = CreateObject("Notes.NotesSession")
ntsServer = oSess.GetEnvironmentString("MailServer", True)
ntsMailFile = oSess.GetEnvironmentString("MailFile", True)
Set odb = oSess.GetDatabase(ntsServer, ntsMailFile)
Set Workspace = CreateObject("Notes.NotesUIWorkspace")
Call Workspace.composedocument(, , "Memo")
Set uidoc = Workspace.CURRENTDOCUMENT
uidoc.Document.deliveryreport = "C"
uidoc.Document.Importance = "Haute"
uidoc.Visible = true
I thought that Visible could say that Lotus Note stay open and visible.
I assume "Visible" should not be utilize in this way. I've got this error:
Execution error '438'
object doesn't support this property or method
good luck with your venture, the OLE/COM Engine for Lotus Notes is antedeluvian and it's a royal pain to debug.
From your code I would hypothesise that you have little experience in LotusScript, you're using programming paradigms that will not work in LotusScript.
Generally I would recommend you first writing code that runs well in the Notes Client, and only when it works, then port it to VBA. Here the integrated Help File is your friend, it's one of the last remnants of when IBM did decent documentation for the Domino/Notes platform. You'll have to wrap your head around a couple of weird concepts (in this particular case, the difference between front-end and back-end documents), and deal with a plethora of maddening bugs.
The following will do what you want it to do. Note that the back-end document gets saved before being displayed in the workspace, this is to be able to display the Rich Text Field which is the body of the Mail.
Dim oSess As Object
Set oSess = CreateObject("Notes.NotesSession")
Dim ntsServer As String
ntsServer = oSess.GetEnvironmentString("MailServer", True)
Dim ntsMailFile As String
ntsMailFile = oSess.GetEnvironmentString("MailFile", True)
Dim Maildb As Object
Set Maildb = oSess.GetDatabase(ntsServer, ntsMailFile)
If Not Maildb.IsOpen Then
Maildb.OPENMAIL
End If
Set MailDoc = Maildb.CREATEDOCUMENT
Call MailDoc.REPLACEITEMVALUE("Form", "Memo")
Call MailDoc.REPLACEITEMVALUE("SendTo", "Joe Example")
Call MailDoc.REPLACEITEMVALUE("Subject", "Subject Text")
Set Body = MailDoc.CREATERICHTEXTITEM("Body")
Call Body.APPENDTEXT("Body text here")
Call Body.ADDNEWLINE(2)
Call MailDoc.Save(True, True)
Set Workspace = CreateObject("Notes.NotesUIWorkspace")
Call Workspace.EditDocument(True, MailDoc)

Unable to make a connection to ALM 12.5 using vb macro

I have 2 ALM's (11 and 12.5), with the below code, i am able to connect to ALM11, but it says invalid user name and password for 12.5 ALM, (user credentials are correct)
Function ALM_Connection(ByRef TDConnection, server, user, pwd)
On Error Resume Next
Dim fileArray
almLogin.connectionMessage.ForeColor = vbBlue
Set TDConnection = CreateObject("tdconnection")
sUserName = user
sPassword = pwd
If Trim(sUserName) = "" Or Trim(sPassword) = "" Then
almLogin.connectionMessage.ForeColor = vbRed
almLogin.connectionMessage.Caption = "Please Enter the data and click on 'Authenticate'"
ALM_Connection = False
Exit Function
End If
almLogin.connectionMessage.Caption = " Please Wait.. "
Application.Wait (Now + TimeValue("0:00:02"))
TDConnection.InitConnectionEx server
TDConnection.Login sUserName, sPassword
If (TDConnection.loggedin <> True) Then
almLogin.connectionMessage.ForeColor = vbRed
almLogin.connectionMessage.Caption = "Invalid UserName or Password"
ALM_Connection = False
Exit Function
Else
almLogin.connectionMessage.Caption = "Logged In Successfully"
ALM_Connection = True
End If
End Function
any help is appreciated
I generally use the below syntax to create the OTA object
Set TDconnection = CreateObject("tdapiole80.tdconnection")
However, Since the connection and authentication are enclosed inside "On Error Resume Next", the error message may not actually reflect the real cause.
So, this is what I would do to debug.
Remove the On Error Resume Next and check whether the code can create a TDConnection Object
Installing the correct version of HP ALM Addin.
Console out "err.description" to understand the real cause
As I can see from your code it throws message "Invalid UserName or Password" in any case when TDConnection.loggedin property is not True, but it can be because of other reason, e.g. wrong OTAClient.dll library (they are not backward compatible). So in general case you should register your ALM client on the machine (server_url/qcbin -> Tools -> Register client) and then try one more time.
If it doesn't help, you can try to rewrite your code using sample from official documentation http://alm-help.saas.hpe.com/en/12.50/api_refs/ota/topic96.html
This problem is due to the Project unavailable. Also check if you have access to any one of the projects in the v12.5.
Thanks.

Bloomberg API: How to check wether connection works?

I am implementing a tool which relies on Bloombergs blpapilib2, which is the Bloomberg API COM Lib 3.5.
Before giving my user access to any refresh-data functionality, I want to make sure that the connection works. My approach so far:
Check wether the library is available and linked. Basically a loop through references does the job.
Open a connection with session.Start() . I was hoping to get an error here, but it won't give me one. Thus, step 3.
Request some data and verify it (make sure its not empty)
Surporisingly, I cannot reliably reproduce getting an empty result. I expected my session relies on a user being looged into the terminal. It seems I was wrong; even if I log out, my request will be handled and return correct data.
I can imagine two scenarios:
some background caching in the bbcom-Server
an alternative authentication method is used
I have two questions:
Q1. What is the best way to make sure a user will be able to download data?
Q2. How can I verify whether a connection has been established successfully and a user is authenticated?
Thanks.
To "cut" the connection, you need to log out and log in on a different machine. If you simply log out the feed is still available using the API.
This is how I test the connection - I think it works fairly well. I have a BloombergWrapper class that handles all the low level stuff of communicating with the API and it has the following functions:
Private pSession As blpapicomLib2.Session
Private pService As blpapicomLib2.Service
Private Sub Class_Initialize()
Dim locStatusBar As Variant
Dim locBbResult As Variant
On Error GoTo error_handler
If Application.StatusBar = False Then locStatusBar = False Else locStatusBar = Application.StatusBar
Application.StatusBar = "Connecting to Bloomberg..."
Set pSession = New blpapicomLib2.session
pSession.Start
pSession.OpenService ("//blp/refdata")
Set pService = pSession.getService("//blp/refdata")
Application.StatusBar = locStatusBar
Exit Sub
error_handler:
If InStr(Err.Description, "timeout") Then
Call MsgBox("A Bloomberg timeout has occured. Make sure you are logged on your terminal.", vbCritical + vbOKOnly, "Bloomberg error...")
End If
If locStatusBar <> "" Then Application.StatusBar = locStatusBar
End Sub
Private Sub Class_Terminate()
pSession.Stop
Set pSession = Nothing
End Sub