VBA: clear data from an object(Array) (SAP Object in VBA) - vba

I am an SAP developer with little knowledge of VBA.
I am creating an VBA to post data to SAP using a BAPI. The coding is working fine & I am able to post data into SAP. My problem is I have several rows in my excel, I have to loop the rows one by one & upload data in SAP, after each upload i need to clear the contents, I am unaware of what syntax needs to be used to clear the data of the object variable. Below is the code snippet..
Set objbapicontrol = CreateObject("SAP.Functions")
Set objbapi = objbapicontrol.Add("BAPI_PO_CREATE1")
Set poheader = objbapi.exports.Item("POHEADER")
Set poitems = objbapi.tables.Item("POITEM")
For Each row In [POHEAD].Rows '##PO Header
If row.Columns(row.ListObject.ListColumns("SAP_PO_NUM").Index).Value = "" Then
ponum = (row.Columns(row.ListObject.ListColumns("PONumber").Index).Value)
poheader.Value("COMP_CODE") = (row.Columns(row.ListObject.ListColumns("COCD").Index).Value)
i = "00001"
n = 1
'###Loop Detail
For Each rowd In [PODET].Rows '##PO Detail
If (rowd.Columns(rowd.ListObject.ListColumns("PONumber").Index).Value) = ponum Then
poitem = (rowd.Columns(rowd.ListObject.ListColumns("Itemnumber").Index).Value)
poitems.Rows.Add
poitemsx.Rows.Add
poitems.Value(n, "PO_ITEM") = i
poitems.Value(n, "MATERIAL") = Material
Next '##PO Detail
returnfunc = objbapi.call
ponumber = objbapi.imports("EXPPURCHASEORDER")
Set retmess = objbapi.tables.Item("RETURN")
Set poitems = Nothing
next
I am using the code "Set POITEMS = NOTHING" but again when I set the object, the previous data is not cleared & duplicate enteries are created in SAP
Thanks in Advance!!
Regards,
Anil Malhotra

try using Set poitems = objbapi.tables.Item("POITEM") under the For loop.
set poitems= NOTHING will destroy the object but sometimes do not clear data. I faced this issue and was solved by moving the object creating code to the loop.
Hope it helps :)

Related

Multi criteria filter in VBA (Not equal to)

I am using the below code in Blue prism for filtering in excel for multi criteria.
But i am not able to filter multi criteria for Not equal to scenario.
Dim wb As Object
Dim excel as Object
Dim range as Object
Try
wb = GetWorkbook(Handle, Workbook)
excel = wb.Application
range = excel.Range(FRange)
Dim listOfValues as Array
listOfValues = Split(FCriteria,";")
wb.worksheets(Worksheet).select
range.select
range.Autofilter(FCol,listOfValues,7)
Success = True
Catch e As Exception
Success = False
Message = e.Message
Finally
wb = Nothing
End Try
Please help me tweaking the script
I'm almost sure that there is no filter option to set a "negative list". You can specify either a (positive) list of values (this is what your code does so far, for this you have to set the 7 as third parameter), or you can give a maximum of 2 individual criteria (in Excel, choose "Custom Filter" to set them.
You should play with the filter directly in Excel and try to set it like you want. Once you are satisfied with it, clear the filter, record a macro and repeat the filtering. Go to the VBA editor and see what's in there. It is straightforward to translate this into C# code.
But:
It's not possible to set any filtering by code (neither C# nor VBA) that you cannot set via the Excel GUI
I would question what you are trying to do. Since you are using Blue Prism, you should be trying to access the underlying data in a BP Collection(VB DataTable), rather than applying a filter, which is a visual tool for humans to further play with the interface. The robot will still have to do something with the filtered data, and it far easier to write code to proceed with data during the loop.
Otherwise use the Filter Collection Page of the 'Utilities - Collection Manipulation' VBO to get a filtered collection.
Also you are using VBA Split function, when you should use Split in VB as a method of the String.
Try this for a new page in the 'Utilities - Collection Manipulation' VBO(untested):
Dim NewRow As DataRow
Collection_Out = Collection_In.Clone
Dim Select_Concat As String
Select_Concat = "NOT(" & fieldName & " = '" & [String].Join("' OR " & fieldName & " = '", FCriteria.Split(";"c)) & "')"
For Each parentRow As DataRow In Collection_In.Select(Select_Concat)
NewRow = Collection_Out.NewRow
For Each c As DataColumn In NewRow.Table.Columns
NewRow(c.ColumnName) = parentRow(c.ColumnName)
Next c
Collection_Out.Rows.Add(NewRow)
Next parentRow
NewRow = Nothing
Collection_In = Nothing
Inputs: Collection_In(Collection), fieldName(Text), FCriteria(Text)
Outputs: Collection_Out(Collection)
You first need to get the entire range into an unfiltered Collection(which will be your Collection_In to this page, and then get the filtered Collection out....

Loading Userform with Recordet Information Of Selected Item (How to make faster)

Im having a very minor issue, but is an issue nonetheless and its driving me nuts!
I have a Userform (VBA, using Excel as the Front End and Access as the Back End) which hast textboxes and a listbox.
What it does is fill the textboxes with information from an Access Database based on the selection the user makes on the listbox.
So if the user selects the entry with the "001" code, it goes to the Access DB, fecthes that record and populates the UserForm.
Below is the code:
Private Sub LtaInversiones_Click()
Dim rcon As Recordset
Dim sql As String
sql = "SELECT * FROM INVERSIONES WHERE CODIGO = "_
& LtaInversiones.List(LtaInversiones.ListIndex, 0)
Set rcon = BD.OpenRecordset(sql)
With rcon
CmbCodigo.Text = !Codigo
CmbTipo.Text = !TIPO
TxtTitulo.Text = !TITULO
TxtMonto.Text = !Monto
DTFCompra.Value = !FECHACOMPRA
DTFVencimiento.Value = !FECHAVENCIMIENTO
CmbPeriodicidad.Text = !periodicidad
TxtTCupon.Text = !TASACUPON
TxtPrecio.Text = !Precio
TxtRendimiento.Text = !rendimiento
TxtGPRedencion.Text = !GANANCIAPERDIDAREDENCION
TxtIAcum.Text = !INTERESESACUMULADOS
CmbEmisor.Text = !eMISOR
CmbOperador.Text = !OPERADOR
TxtNotas.Text = !NOTAS
If !FECHAREDENCION <> "" Then
DTFRedencion.Value = !FECHAREDENCION
ChkCInversion.Value = True
Else
ChkCInversion.Value = False
End If
.Close
End With
Set rcon = Nothing
CmdEliminar.Visible = True
CmdGuardar.Caption = "Modificar"
CmbCodigo.Enabled = True
The thing is, its working, but it slows down a bit. Ive tested the possible reasons, and it is definitely the fact that the query has to go look at what the list index is before going to the DB.
So I would like to ask you more experienced programmers (Im a lawyer by trade :/ ) If there is a better way of doing this.
The only thing that has ocurred to me is maybe loading all the records on initialization and then somehow accessing that data, as that would prevent the trip to the DB but am unsure whether that would improve performance or how to do it for that matter.
Thanks
What's stopping you from changing this:
LtaInversiones.List(LtaInversiones.ListIndex, 0)
to this?
LtaInversiones.Value
This will avoid a double lookup (List & ListIndex)
I personally avoid the "!" notation, preferring the fuller .Fields("ABC").Value
I'm not sure of any performance penalty or advantage there.

OTA - ALM 11.52 - Building Graphs through OTA

I am trying to create reports in the 'Analysis View' using OTA and HP ALM 11.52.
I've searched the OTA Reference Documentation and looked for samples online and I've found a few samples, but none seem to work.
There seem to be three methods utilised:
TDConnection.GraphBuilder.BuildGraph(GraphDefinition)
TDConnection.testFactory.BuildSummaryGraph("TS_STATUS", "TS_STATUS", "", 0, myFilter, False, False)
and a third method involving an AnalysisItemFactory object that I can't find anywhere in the OTA documentation.
I've tried the first two and they seem to run without triggering an error, however, no graph appears in ALM.
Is there a difference between these methods and which is the cleanest method?
Here are my attempts so far:
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Method 1: GraphBuilder
'Set GB = QCConnection.GraphBuilder
'Set G1 = GB.CreateGraphDefinition(2, 0)
'G1.Property(0) = "TS_NAME"
'G1.Property(1) = "TC_STATUS"
'Set tsf = QCConnection.TestSetFactory
'Set myFilter = tsf.Filter
'myFilter.Filter ("TC_STATUS") = "Not(N/A)"
'G1.Filter = "Filter: Status[Not N/A]"
'Set g = GB.BuildGraph(G1)
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Method 2: BuildSummaryGraph
'Dim testF
'Dim graph1
'Dim Filter
'Set testF = QCConnection.testFactory
'Set myFilter = testF.Filter
'myFilter.Filter("TS_STATUS") = "Not(N/A)"
'Set graph1 = _
'testF.BuildSummaryGraph("TC_NAME", "TS_STATUS", "", 0, myFilter, False, False)
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Method 3: AnalysisItemsFactory? I can't find any documentation on this object, yet I've seen it referenced in other code samples.
'Set aiFolderFact = QCConnection.AnalysisItemFolderFactory
'Set aiFact = QCConnection.AnalysisItemFactory ~~~ This line actually runs fine so I know it at least exists. But I am definitely not using the proper methods below.
'Set G1 = aiFact.AddItem("")
'G1.Field("AI_PARENT_ID") = 1001 'Public
'G1.Field("AI_TYPE") = "Graph"
'G1.Field("AI_SUB_TYPE") = "Progress Graph"
'G1.Field("AI_OWNER") = qcUserName.Value
'G1.Field("AI_MODULE") = "requirement"
'G1.Field("AI_NAME") = "test graph"
'G1.Post
As I mentioned previously, all of these scripts run error free, but I see no graph in the Analysis View. I've also noticed that there seem to be no "Name" or "Path" fields.
I've taken a look at the tables, and there seems to be 'Analysis_Item_Folder' and 'Analysis Items' tables so It's know it's possible to do this through the OTA client. Is there an AnalysisItemFactory and could someone please kindly provide a sample script of what I'm looking for?
I was able to generate a report with the help of this HP ALM forum entry.
As in the forum mentioned it is not an official documented feature of HP ALM. Therefore it can be that in the future it won't work without replacement. Please keep that in mind.
In case the forum entry may get deleted I copied the answer by a user called "delarosa62" here (date of copy 2015/9/8):
Hi MichaelMotes and the rest of the community members.
I developed a VBA code to generate dashboard standard reports automatically. I get the "successful exception" you have mentioned. However my report does not get generated in my hard disk.
I don't get any errors.
I have adapted your Visial Basic Code to VBA using OTA. I have the otareport 1.0 Type Library and otaxml type lib registered in the tools/reference option in the VBA module window.
I am pasting my code below hoping you guys can give me some insight on this. I am not getting any errors. Just the exception which includes a successful completion message.
Sub externalSTDReports()
Dim reqFact
Dim reqFilter
Dim reqList
Dim gTDConn As Object
Set gTDConn = CreateObject("TDApiOle80.TDConnection")
'QC Connection data
login_id = ActiveWorkbook.Sheets("CONFIG").Cells(9, 3).value
login_passwd = ActiveWorkbook.Sheets("CONFIG").Cells(10, 3).value
domain_name = ActiveWorkbook.Sheets("CONFIG").Cells(11, 3).value
project_name = ActiveWorkbook.Sheets("CONFIG").Cells(12, 3).value
server_name = ActiveWorkbook.Sheets("CONFIG").Cells(13, 3).value
gTDConn.InitConnectionEx server_name
gTDConn.login login_id, login_passwd
gTDConn.Connect domain_name, project_name
Set Rep = New OTAREPORTLib.Reporter
Call Rep.SetConnection(gTDConn, 0) ' This line doesn´t return errors. But I don´t know if it is correct
Set RepConf = Rep.ReportConfig
Rep.File = "C:\Users\cris\AppData\Local\Temp\TD_80\4c223b57\Reports\std.html"
Rep.Template = "C:\Users\cris\AppData\Local\Temp\TD_80\4c223b57\Reports\default.xsl"
'******************************************************** filter Reports
Set aiFact = gTDConn.AnalysisItemFolderFactory
Set reportFact = gTDConn.AnalysisItemFactory
Set aiFilter = aiFact.Filter
Set aiList = aiFilter.NewList
Set anf = reportFact.Filter
Dim FilterStr As String
For Each ai In anf.NewList
reportName = ai.Name
reportID = ai.id
If reportName = "tmp" Then
FilterStr = ai.Field("AI_FILTER_DATA")
RepConf.Filter = FilterStr
On Error Resume Next
'i is empty. Don´t know why
i = Rep.Generate(0, 0) MsgBox i & " --- " & Rep.File Debug.Print Rep.File '-------------------- Exit For
End If
Next
Set gTDConn = Nothing
Set aiFact = Nothing
Set reportFact = Nothing
Set aiFilter = Nothing
Set aiList = Nothing Set anf = Nothing
Set RepConfig = Nothing
Set Rep = Nothing
MsgBox "END "
End Sub 'Pls HELP!!
Graphs can be generated under analysis folder, its a bit of a process because you need a sound understanding of the database, XML and OTA API. There is no direct API available for building graphs, I have created the code samples below
https://github.com/sumeet-kushwah/ALM_OTA_Wrapper/blob/master/ALM_Wrapper/Analysis.cs
Check the following functions
CreateDefectAgeGraph
CreateExcelReport
CreateDefectSummaryGraph
CreateSummaryGraph
These functions are called from the tests available below
https://github.com/sumeet-kushwah/ALM_OTA_Wrapper/blob/master/ALM_Wrapper_Tests/ALM_Wrapper_Test.cs
Look for test function
Test_AnalysisAndDashboardScripts
If you have any questions regarding the process, please let me know.

Connect to a specific lotus notes database/documen via vba

I can connect to lotus notes via the following code. So basically I connect to the database: CLASTNAME/O=TEST/C=US.nsf
Set oSession = CreateObject("Notes.NotesSession")
Server = oSession.GetEnvironmentString("MailServer", True)
UserName = oSession.UserName
MailDbName = Left$(UserName, 1) & Right$(UserName, (Len(UserName) - InStr(1, UserName, " "))) & ".nsf"
'Open the mail database in notes
Set db = oSession.GETDATABASE("", MailDbName)
Set view = db.GetView("Customers") //ERROR
However, I want to connect to a specific database, which I have. Here is the document link:
<NDL>
<REPLICA C1451C8A:00575D55>
<VIEW OD3B89A25B:7D1FR7SA-OM4923732F:011L111C>
<NOTE OFAAAA64WE:GH1Q0W0W-IUZ0987MNB:2222F4LÖ>
<HINT>CN=ZZZUSDMS09/O=ZZZ/C=US</HINT>
<REM>Database 'UserName', View 'Customers', Document 'AG: A list of all company customers, Jannuary 9, 2009'</REM>
</NDL>
This is what I tried:
Sub notesBB()
'Const DATABASE = ""
Dim r As Integer
Dim i As Integer
Dim db As Object
Dim view As Object
Dim Entry As Object
Dim nav As Object
Dim oSession As Object 'The notes session
Dim nam As Object ' notes username
Dim v() As Variant ' to hold the subtotal values
Dim bills(12, 16) ' 12 months, 16 departments
r = 1
Worksheets(1).Range("A1:Z99").Clear
'##############################
'Start a session to notes
Set oSession = CreateObject("Notes.NotesSession")
Server = oSession.GetEnvironmentString("MailServer", True)
UserName = "CN=ZZZUSDMS09/O=ZZZ/C=US" 'oSession.UserName
CustomerDbName = "CZZZUSDMS09/O=ZZZ/C=US" & ".nsf"
'Open the mail database in notes
Set db = oSession.GETDATABASE("", CustomerDbName)
Set view = db.GetView("OD3B89A25B:7D1FR7SA-OM4923732F:011L111C")
view.AutoUpdate = True // here I get an error
Set nav = view.CreateViewNav
Set Entry = nav.GetFirst
Do Until Entry Is Nothing
If Entry.isCategory Then
r = r + 1
v = Entry.ColumnValues
For i = 1 To 16
bills(v(0), i) = v(4 + i)
Cells(4 + r, 2 + i) = bills(v(0), i)
Next
End If
Set Entry = nav.getNextCategory(Entry)
DoEvents
Loop
End Sub
However, as you can see I get an error hee: view.AutoUpdate = True // here I get an error
How to connect to this database via vba?
I really appreciate your answer!
Well, this doesn't look right:
CustomerDbName = "CZZZUSDMS09/O=ZZZ/C=US" & ".nsf"
'Open the mail database in notes
Set db = oSession.GETDATABASE("", CustomerDbName)
You're just appending ".nsf" to the user's fully disntinguished name in canonical form, and that would be an extremely unusual naming convention for databases on a server. Also, earlier in your code you retrieved the server name, but here you're specifying "" for the server name instead of using what you had retrieved, so the result is that the code will try to open the database on the local machine.
The NDL file is giving you the ReplicaID of the database here:
<REPLICA C1451C8A:00575D55>
You can use the OpenByReplicalID method instead:
repID = "C1451C8A00575D55" ' note that the : is removed
'Open the database by replica id
set db = new NotesDatabase("","")
If db.OpenByReplicaID( , "85255FA900747B84" ) Then
Print( db.Title & " was successfully opened" )
Else
Print( "Unable to open database" )
End If
The next problem, though, is that the NDL file is giving the view's UNID, not its name
<VIEW OD3B89A25B:7D1FR7SA-OM4923732F:011L111C>
There is no call in the Notes COM API that can retrieve a view by its UNID; you need the name for that. But do you really need to get the view? The NDL gives you the UNID of the document, here:
<NOTE OFAAAA64WE:GH1Q0W0W-IUZ0987MNB:2222F4LÖ>
So if your goal is to just get the specific document specified in the NDL, you can use a call to GetDocumentByUNID. Note, however that the actual UNID consists of only the 17 chars to the right of OF in the above tag, minus the : char. So your code would look like this:
unid = "AAAA64WEGH1Q0W0W" ' see note below!!
Set doc = db.GetDocumentByUnid(unid)
BTW, that UNID does not look legal. The chars should be hex, and the W, Q, and G are not. I'm going on the assumption that you (or someone) deliberately obfuscated the data in your NDL file.
If you do need to access the view, the NotesNoteCollection class may provide a way to get there, but it will not be trivial.
Finally, you may find this code from Stepehn Wissel helpful.
Specify the name of the view instead:
Set view = db.GetView("Customer")
Nice to see my code getting recycled ! it seems to me that you aren't using the correct database and view names. Are they not
Database 'UserName', and View 'Customers' ? (from your link). Whatever - when your XL VBA crashes out, in the Debug - Locals window, look for the object(s) that you have tried to instantiate with the SET command. If they show up as "nothing", you've got the SET command(s) wrong and trying to use the failed object (view) then crashes on the following line.
If your servername is "Yoda" I'd guess you need
Set db = session.getdatabase("Yoda", "Username.nsf")
Set view = db.GetView("Customers")

Remove sas content from Excel with VBA (MS Office Add-in)

I've figured out how to use the MS Office Add-in to run a SAS Stored Process from within Excel (using an input stream) to obtain outputs.
Everytime I run this, new columns are inserted to accommodate the new output. Also, additional content is added to the workbook.
My understanding of the SAS Add-in object model is poor, so I was hoping someone could help me:
1) Remove the existing content with VBA before running the process again; or
2) Write VBA code to refresh existing content only (within the same output range).
The code I'm using is:
Sub sasTests()
Application.ScreenUpdating = False
Dim sas As SASExcelAddIn
Set sas = Application.COMAddIns.Item("SAS.ExcelAddIn").Object
Dim inputStream As SASRanges
Set inputStream = New SASRanges
inputStream.Add "Prompts", Worksheets("sasInput").Range("sasInput")
sas.InsertStoredProcess "/Shared Data/C139/sasTests", _
Worksheets("sasOutput").Range("A1"), , , inputStream
End Sub
Many thanks!
PS. If anyone has any handy references for the SAS Add-in for MS Office, please provide links
You could clear the range containing the existing content with the .Clear method. If this range were in columns M:P, you could use the following line:
sheetNameHere.Range("M:P").Clear
If you added that line after setting
Application.ScreenUpdating = False
I believe this would imitate a "refresh" of the data.
This will remove all old components from the workbook. I am not sure how to refresh all but assuming its similar:
Sub DeleteSasContent()Dim sas As SASExcelAddIn
Set sas = Application.COMAddIns.Item("sas.exceladdin").Object
Dim stpList As SASStoredProcesses
Dim dataList As SASDataViews
Dim pivotList As SASPivotTables
Dim reportList As SASReports
Set stpList = sas.GetStoredProcesses(ThisWorkbook)
Set dataList = sas.GetDataViews(ThisWorkbook)
Set pivotList = sas.GetPivotTables(ThisWorkbook)
Set reportList = sas.GetReports(ThisWorkbook)
For i = 1 To stpList.Count
stpList.Item(i).Delete
Next i
For i = 1 To dataList.Count
dataList.Item(i).Delete
Next i
For i = 1 To pivotList.Count
pivotList.Item(i).Delete
Next i
For i = 1 To reportList.Count
reportList.Item(i).Delete
Next i
End Sub
See the SAS help here http://support.sas.com/kb/45/606.html