I'm using Excel and VBA to get SAP to download data from SAP through RFC using INST_EXECUTE_REPORT.
It works like a charm when I have specific input parameters. I just build up .Tables("PARA") with the screen name of the parameter and the desired value. I can even use this method for date ranges.
The challenge is when I don't know exactly the input parameters. For example, I wanted to identify all internal orders with a specific text in the description, e.g. CODE40.
Is there any way to use wildcards with INST_EXECUTE_REPORT? When the program passed into INST_EXECUTE_REPORT is executed normally as a transaction on screen, I can set the parameter to *CODE40* and SAP automatically applies a wildcard search. But I can't get that to work with VBA.
I can simulate using wildcards when accessing individual tables with BBP_RFC_READ_TABLE by using LIKE statements in the selection option, but I need a similar functionality for whole reports, not individual tables.
Can anyone help?
Best regards,
The code I'm using is as follows:
Set ObjR3_EXECUTE_REPORT = ObjR3.Add("INST_EXECUTE_REPORT")
With ObjR3_EXECUTE_REPORT
Set ObjR3_EXECUTE_REPORT_Name = .Exports("PROGRAM")
Set ObjR3_EXECUTE_REPORT_Para = .Tables("PARA")
Set ObjR3_EXECUTE_REPORT_Result = .Tables("RESULT_TAB")
Set ObjR3_EXECUTE_REPORT_Output = .Tables("OUTPUT_TAB")
End With
ObjR3_EXECUTE_REPORT_Name.Value = ReportName
'Build up the table with the fields to be selected
f = 1
For a = LBound(aParameters) To UBound(aParameters)
aParameterPair = aParameters(a)
aParameterInput = aParameterPair(UBound(aParameterPair))
sParameterName = aParameterPair(LBound(aParameterPair))
For c = LBound(aParameterInput) To UBound(aParameterInput)
sParameterInput = aParameterInput(c)
ObjR3_EXECUTE_REPORT_Para.AppendRow
ObjR3_EXECUTE_REPORT_Para(f, "PARA_NAME") = sParameterName
ObjR3_EXECUTE_REPORT_Para(f, "PARA_VALUE") = sParameterInput
Debug.Print sParameterName & " " & sParameterInput
f = f + 1
Next c
Next a
Related
I have been trying to get Excel to apply a formula over a set of columns and then extend the pattern across the entire set of rows.
This has led to the following code:
For i = 0 To avgsheetNames.Count - 1
If Contains(CStr(avgsheetNames(i)), "Scores") = True Then
With mainWorkBook.Worksheets(avgsheetNames(i))
strFormulas(1) = "=SUM(Aggregated_Internal_Scores!I2:I7)/6"
strFormulas(2) = "=SUM(Aggregated_Internal_Scores!J2:J7)/6"
strFormulas(3) = "=SUM(Aggregated_Internal_Scores!K2:K7)/6"
strFormulas(4) = "=SUM(Aggregated_Internal_Scores!L2:L7)/6"
strFormulas(5) = "=SUM(Aggregated_Internal_Scores!M2:M7)/6"
strFormulas(6) = "=SUM(Aggregated_Internal_Scores!N2:N7)/6"
strFormulas2(1) = "=SUM(Aggregated_Internal_Scores!I8:I13)/6"
strFormulas2(2) = "=SUM(Aggregated_Internal_Scores!J8:J13)/6"
strFormulas2(3) = "=SUM(Aggregated_Internal_Scores!K8:K13)/6"
strFormulas2(4) = "=SUM(Aggregated_Internal_Scores!L8:L13)/6"
strFormulas2(5) = "=SUM(Aggregated_Internal_Scores!M8:M13)/6"
strFormulas2(6) = "=SUM(Aggregated_Internal_Scores!N8:N13)/6"
mainWorkBook.Worksheets(avgsheetNames(i)).Range("C2:H2").Formula = strFormulas
mainWorkBook.Worksheets(avgsheetNames(i)).Range("C3:H3").Formula = strFormulas2
mainWorkBook.Worksheets(avgsheetNames(i)).Range("C2:H3").AutoFill Destination:=mainWorkBook.Worksheets(avgsheetNames(i)).Range("C2:H32")
End With
End If
As you can see I have tried to provide the pattern I am going for where the values extracted from the "Aggregated_Internal_Scores" sheet should follow the pattern I2:I7 > I8:I13 > I14:I19 and so on.
However, when the macro has been executed what I get is I2:I7 > I8:I13 > I4:I9 > I10:I15?
It seems Excel is taking the block C2:H3 as the pattern and just incrementing by 2 at the start of every block.
Can you anyone explain where I have gone wrong and how I can specify that I want the extraction of sheet values to follow a certain pattern?
Thank you in advance!
Use:
mainWorkBook.Worksheets(avgsheetNames(i)).Range("C2:H32").Formula = "=SUM(INDEX(Aggregated_Internal_Scores!I:I,(ROW($ZZ1)-1)*6+2):INDEX(Aggregated_Internal_Scores!I:I,(ROW($ZZ1)-1)*6+7))/6"
Replace everything inside the If with that.
If one has Office 365 with dynamic array formula then use:
mainWorkBook.Worksheets(avgsheetNames(i)).Range("C2:H32").Formula2 = "=SUM(INDEX(Aggregated_Internal_Scores!I:I,SEQUENCE(6,,(ROW($ZZ1)-1)*6+2))/6"
My Excel macro reads the answers to a survey from a set of Excel files. The answers of a survey contain a score (from 1 to 4) and a description. The goal is to generate a a matrix. Each cell of the matrix has a color that represents the score. I would like the user to be able to modify the layout of these cell. To make it easy to the user, I created a template matrix and a button. The user should be able to modify the layout of the cells and on a click of a button, a set of styles (Score 1, Score 2,...) should be generated. Once the matrix is created, the Workbook should be to function without the survey files.
I have tried a couple of things:
Try 1
ThisWorkbook.Styles.Add "Score 1", BasedOn:=cell1
This gives errors. I don't fully understand when they occur, but one of the causes is when the user modifies the cell layout by selecting another style.
Try 2
ThisWorkbook.Styles("Score 1").Delete
ThisWorkbook.Styles.Add "Score 1", BasedOn:=cell1
This is not a good idea: all cells loose their styling when it is executed a second time.
Try 3: Current
Copy the most frequently used properties of the cells layout and copy them to the style. If this style is deleted by the user, it is recreated. This procedures is not ideal, since most style properties won't be covered.
Is there a way to update a cell style that is more general? I would like there to be as little room as possible to make the workbook in an inconsistent and non-functional state.
I sticked with try 3. Because it required a lot of code for all properties that seemed possible to be edited, and because of copying borders is tricky, I post the result.
'xR1_Template: the cell to base the style on
'nm_Style: the name of the style
Public Function Upsert_Style(xR1_Template As Excel.Range, nm_Style As String) As Excel.Style
Dim xStyle As Excel.Style
Set xStyle = Fn.TryGet(ThisWorkbook.Styles, nm_Style)
If Fn.IsNothing(xStyle) Then
Set xStyle = ThisWorkbook.Styles.Add(nm_Style)
End If
xStyle.Font.Color = xR1_Template.Font.Color
xStyle.Font.Bold = xR1_Template.Font.Bold
xStyle.Font.Name = xR1_Template.Font.Name
xStyle.Font.Italic = xR1_Template.Font.Italic
xStyle.Font.Size = xR1_Template.Font.Size
xStyle.Font.Strikethrough = xR1_Template.Font.Strikethrough
xStyle.Font.Subscript = xR1_Template.Font.Subscript
xStyle.Font.Superscript = xR1_Template.Font.Superscript
xStyle.Font.Underline = xR1_Template.Font.Underline
xStyle.Interior.Color = xR1_Template.Interior.Color
xStyle.Interior.Pattern = xR1_Template.Interior.Pattern
xStyle.Interior.PatternColor = xR1_Template.Interior.PatternColor
'NOTE: necessary to delete all borders first. There's no way to delete them one by one.
xStyle.Borders.LineStyle = xlNone
Dim iBorder As Long
For iBorder = 1 To xR1_Template.Borders.Count
Dim xBorder As Excel.Border
'NOTE: The Borders property claims to work with xlBordersIndex argument, but this is not true.
' Normal indexing is used.
Set xBorder = xR1_Template.Borders(iBorder)
'NOTE: "none-style" borders (=no border), should be skipped.
' Once they are retrieved using the Borders property, they are always visible.
' Setting them with xlLineStyle.xlLineStyleNone does not hide them.
If xBorder.LineStyle <> XlLineStyle.xlLineStyleNone Then
Dim xBorder_Style As Excel.Border
Set xBorder_Style = xStyle.Borders(iBorder)
xBorder_Style.Color = xBorder.Color
xBorder_Style.LineStyle = xBorder.LineStyle
xBorder_Style.Weight = xBorder.Weight
End If
Next iBorder
xStyle.AddIndent = xR1_Template.AddIndent
xStyle.FormulaHidden = xR1_Template.FormulaHidden
xStyle.HorizontalAlignment = xR1_Template.HorizontalAlignment
xStyle.IndentLevel = xR1_Template.IndentLevel
xStyle.NumberFormat = xR1_Template.NumberFormat
xStyle.NumberFormatLocal = xR1_Template.NumberFormatLocal
xStyle.Orientation = xR1_Template.Orientation
xStyle.ShrinkToFit = xR1_Template.ShrinkToFit
xStyle.VerticalAlignment = xR1_Template.VerticalAlignment
xStyle.WrapText = xR1_Template.WrapText
xStyle.IndentLevel = xR1_Template.IndentLevel
Set Upsert_Style = xStyle
End Function
I am trying to export some text from annotation fields in Nuance Power PDF to Excel using VBA. I added the Nuance Power PDF reference to Excel VBA (PDF Plus).
I used it and it works well but the text returned from fields is empty.
Set PDFApp = CreateObject("NuancePDF.App")
Set dvDoc = CreateObject("NuancePDF.DVDoc")
dvDoc.Open("\\adpdc-2\Users$\a.goudinoux\Documents\Macro Formulaire\fiche.pdf")
Set ddDoc = dvDoc.GetDDDoc()
Set ddPage = ddDoc.AcquirePage(0)
nbannots = ddPage.GetNumAnnots() - 1
For i = 0 To nbannots
Texte = ""
Set ddAnnot = ddPage.GetAnnot(i)
Set ddText = ddDoc.CreateTextSelect(0, ddAnnot.GetRect())
ThisWorkbook.Sheets(1).Cells(1, i) = ddAnnot.GetTitle()
For k = 0 To ddText.GetNumText()
Texte = Texte & ddText.GetText(k)
Next
ThisWorkbook.Sheets(1).Cells(2, i) = Texte
Next
Part of the PDF document :
Results :
As you can see the first line is working but not the second one.
I thought the problem was with ddText but ddText.GetNumText() gives the right number of text elements in the text selection (ex : 2, 5, 4, etc...) when I run my program in Debug Mode.
I think the problem is from the function GetText(k).
I made it work once but I can't find my code back..
Do you see any mistake ?
Either your annotations are more complex than indicated or you're overthinking it.
Just read the annotation with GetContents and call it a day.
Set PDFApp = CreateObject("NuancePDF.App")
Set dvDoc = CreateObject("NuancePDF.DVDoc")
dvDoc.Open("\\adpdc-2\Users$\a.goudinoux\Documents\Macro Formulaire\fiche.pdf")
Set ddDoc = dvDoc.GetDDDoc()
Set ddPage = ddDoc.AcquirePage(0)
nbannots = ddPage.GetNumAnnots() - 1
For i = 0 To nbannots
Set ddAnnot = ddPage.GetAnnot(i)
ThisWorkbook.Sheets(1).Cells(1, i) = ddAnnot.GetTitle
ThisWorkbook.Sheets(1).Cells(2, i) = ddAnnot.GetContents
Next i
I have the below VBA code and A and B are holding some strings. I want to concatenate these values with some other strings and store the result in a different cell, but I want only the strings in A and B to be formatted as bold and the rest as normal text.
Set A = Worksheets("Mapping").Cells(rowNumber, columnNumber)
Set B = Worksheets("Mapping").Cells(rowNumber, 3)
' E.g.: A="currency", B="Small Int"
Worksheets("TestCases").Cells(i, 2) = "Verify the column " & A & " has same Data type " & B & " in code as well as Requirement document"
Expected output:
Verify the column currency has same Data type Small Int in code as well as Requirement document
Note: The values of A and B keep changing, so we cannot use the Characters() function.
Any help will be highly appreciated.
You can use the Characters() method - you just need to keep track of the length of the substrings. Personally, I would store the static strings in variables so that I can change them later without having to recalculate the indexes by hand:
' Untested
Set A = Worksheets("Mapping").Cells(rowNumber, columnNumber)
Set B = Worksheets("Mapping").Cells(rowNumber, 3)
Dim S1 = "Verify the column "
Dim S2 = " has same Data type "
Dim S3 = " in code as well as Requirement document"
With Worksheets("TestCases").Cells(i, 2)
.Value = S1 & A & S2 & B & S3
.Characters(Len(S1), Len(A)).Font.Bold
.Characters(Len(S1)+Len(A)+Len(S2), Len(B)).Font.Bold
End With
The function to change the font style is:
[Cells/Cell range].Font.FontStyle = "Bold"
Therefore something like might work:
Worksheets("Mapping").Cells(rowNumber, columnNumber).Font.FontStyle = "Bold"
You can also make things have underlines, strikethroughs etc... I found this really helpful blog post which goes through everything you should need to know:
http://software-solutions-online.com/excel-vba-formating-cells-and-ranges/#Jump4
I think you should have searched for this information yourself... Nevertheless this is the code that you should use to convert some cell data to bold:
Worksheets("Mapping").Cells(rowNumber, columnNumber).Font.Bold = True
I need to know how to connect Excel with SAP using RFC. I have not managed to import any SAP data to Excel using the codes found so far.
I would like to be able to import data from any known transaction (e.g. a bill of materials from transaction CO03). From this I would try to understand how to extract other type of tables.
My goal is to be able to import any SAP data on a Excel spreadsheet using RFC. That would be a good start.
Do I need a special SAP account? How to verify my account is enabled to perform this type of tasks?
It is not possible to call any standard transaction remotely as most of them are legacy-like and doesn't return anything directly.
There are couple of ways to fetch data from any transaction but they are out of the scope of this question. The most practical way of retrieveing data from SAP to Excel is to find proper BAPI or remote-enabled FM, (including writing own wrapper FM) and this is the way I gonna describe here.
You don't need special account, you just need to have proper authorizations for RFC-calls, which mainly comprise of S_RFC authorization object
If you use BAPI, you can omit this point. If you created own wrapper, then you have to assure it is remote-enabled.
And then you can call your FM in VBA code and return results to Excel book. Here is the sample code:
' Logging in
Dim retcd As Boolean
Dim SilentLogon As Boolean
Set LogonControl = CreateObject("SAP.LogonControl.1")
Set objBAPIControl = CreateObject("SAP.Functions")
Set R3Connection = LogonControl.NewConnection
R3Connection.Client = "700"
R3Connection.ApplicationServer = "server_address"
R3Connection.Language = "EN"
R3Connection.User = "sap_user"
R3Connection.Password = "sap_pass"
R3Connection.System = "system_id"
R3Connection.SystemNumber = "sys_num"
R3Connection.UseSAPLogonIni = False
retcd = R3Connection.Logon(0, SilentLogon)
If retcd <> True Then MsgBox "Logon failed": Exit Sub
' Declaring FM interface
objBAPIControl.Connection = R3Connection
Set objgetaddress = objBAPIControl.Add("ZNM_GET_EMPLOYEE_DETAILS")
Set objkunnr = objgetaddress.Tables("ET_KUNNR")
Set objaddress = objgetaddress.Tables("ET_CUST_LIST")
' Filling select-options values table from sheet
Dim sht As Worksheet
Set sht = ThisWorkbook.ActiveSheet
If sht.Cells(6, 2).Value <> " " Then
objkunnr.Rows.Add
objkunnr.Value(1, "SIGN") = sht.Cells(6, 2).Value
objkunnr.Value(1, "OPTION") = sht.Cells(6, 3).Value
objkunnr.Value(1, "LOW") = sht.Cells(6, 4).Value
objkunnr.Value(1, "HIGH") = sht.Cells(6, 5).Value
R3Connection.Logoff
P.S. For all this to work in your VBA project you should add references to SAP ActiveX controls, which are located in %ProgramFiles%\SAP\FronEnd\SAPgui directory:
wdtaocxU.ocx
wdtfuncU.ocx
wdtlogU.ocx
wdobapiU.ocx
So references list of your VBA project should look like this
Additionally to Excel solution you may try this open source MS Access application I created long time ago and used many times:
https://blogs.sap.com/2013/08/16/read-data-from-sap-tables-into-ms-access-2003-database/