I am trying to create an anonymized schedule for the conference rooms on our floor via Excel VBA.
The source data is stored in different Outlook calendars (every room has its own) and I got access to them via the "shared calendar" functionality of Outlook.
The problem I am currently having is fully automating the data retrieval process. I got everything else working fine, however, it requires the user to manually select the (currently) five different calendars from a small pop-up window, which is rather tiresome.
I have tried using the GetDefaultFolder(olFolderCalendar).Items approach, but this only seems to work for the local calendar not shared ones from the network (Exchange).
Is there a way to address these room calendars directly so that I can automate my process?
best regards,
daZza
Here's my current code, cut down to the relevant parts:
Set olNS = olApp.GetNamespace("MAPI")
For x = 1 To 5
Set myCalItems = olNS.PickFolder.Items
With myCalItems
.Sort "[Start]", False
.IncludeRecurrences = True
End With
StringToCheck = "[Start] >= " & Quote(StartDate & " 12:00 AM") & " AND [End] <= " & Quote(EndDate & " 11:59 PM")
Set ItemstoCheck = myCalItems.Restrict(StringToCheck)
' Do stuff with every item in "ItemstoCheck"
' ...
' ...
' ...
Next
Have you looked into the Namespace.GetSharedDefaultFolder method?
Related
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/
This is probably a really easy question, but here what I have
I have a load of code that works fine but then when it comes to saving the document I can only get it to save as a specific name, but I want it to save as "Visitors Diary Recruitment (something unique)" so that it doesn't overwrite the document each time I run it and instead creates a new document.
With wApp
.ActiveDocument.SaveAs2 (path)
.ActiveWindow.Close
.Quit
Set wApp = Nothing
Set wDoc = Nothing
End With
End Sub
You could save the document with a unique Id (there are many options for this - depending on your need):
Random number
Use a datetime stamp
Use a Guid
Using a random number:
set uniqueName = Int(25 * Rnd()) + 1 //25 is the amount of random numbers you want
Using a DateTime:
set uniqueName = Format(Now(), "MMMM dd, yyyy hh:mm AM/PM")
Using a Guid - I havn't done this myself yet, although i'm certain there must be a way to generate one. (This might help)
Then change your SaveAs to this:
ActiveDocument.SaveAs2 ("C:\Users\colesa\Desktop\Recruitment Macros\Visitor Diary Recruitment" +uniqueName + ".doc")
I am currently using Outlook 2010 and I am currently able to manually search a folder in outlook by using the "More" button and adding attachments:yes and attachment contains: where I input the filename to find an email and get the timestamp from when it was sent. I have thousands of attachments for which I need to do this and I would like to automate the process but I am an outlook vba noobie and I do not know the command to perform the search by attachment name, I have tried googling this but to no avail any help would be greatly appreciated thanks!
You can use Restrict https://msdn.microsoft.com/en-us/library/office/ff869597.aspx
Example here: http://www.jpsoftwaretech.com/save-all-attachments-from-selected-folder/
Set newItems = itms.Restrict("[Attachment] > 0")
Combined with:
attName = MsgAttach.Item(attachmentNumber)
If InStr(attName, "search string here") Then
Debug.Print "- " & attName
End If
Outlook Object Model will not let you search for an item with a particular attachment file name. You can explicitly loop through all items in the folder and check the attachment filename, but that will be highly inefficient.
On the Extended MAPI level (C++ or Delphi) you can create a subrestriction on the attachments. If using Redemption is an option (I am its author), it allows to specify Attachments in RDOItems.Find/Restrict:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set vFolder = Session.GetFolderFromID(Application.ActiveExplorer.CurrentFolder.EntryID)
set vItems = vFolder.Items
set vMsg = vItems.Find("Attachments LIKE '%.zip%' ")
while not (vMsg Is Nothing)
MsgBox vMsg.Subject
set vMsg = vItems.FindNext
wend
I'm finding that when I read the GlobalAppointmentID of a recurring event in Outlook via my Excel-VBA code, things start acting odd.
Here's part of the code that I've been using to try to understand the root cause of this behavior:
For Each otItem In resCal
If otItem.Class = olAppointment Then
Set cItm = otItem
If calItem.Subject = "Coffee Date" Then
Debug.Print "Coffee orig " & cItm.Start
Debug.Print "Coffee orig 1.1 " & cItm.Start
Debug.Print cItm.GlobalAppointmentID
Debug.Print cItm.GlobalAppointmentID
Debug.Print "Coffee orig 1.5 " & cItm.Start
End If
End If
Next otItem
This produces the following output:
Coffee orig 4/16/2015 10:00:00 AM
Coffee orig 1.1 4/16/2015 10:00:00 AM
[Global Appointment ID redacted, but identical]
[Global Appointment ID redacted, but identical]
Coffee orig 1.5 2/19/2015 10:00:00 AM
4/16 is the instance of the recurring event that I would like to record. However, when I call the GlobalAppointmentID property, it changes the value of the .Start property to that of the first instance of the recurring event. I've tested and can implement a workaround that involves me storing the start date in a variable before calling GlobalAppointmentID, however I would like to try to diagnose and fix the root cause of the issue to ensure that it isn't causing any problems that I haven't noticed yet. Can anyone shed some light on what is causing this issue?
Thanks!
the problem does not occur when I call the AppointmentItem by index instead of looping via For Each
I'd recommend using the for loop instead and releasing the object as soon as possible. This is particularly important if your code attempts to enumerate more than 256 Outlook items in a collection that is stored on a Microsoft Exchange Server. If you do not release these objects in a timely manner, you can reach the limit imposed by Exchange on the maximum number of items opened at any one time. Declare an object in the function scope (loop scope) and set it to Nothing to release the reference to the object as soon as possible.
I recently took another look at my code and determined the source of the problem. Here’s the snippets of code that were causing the problem:
With oItms
.Sort "[Start]", False
.IncludeRecurrences = True
End With
Set rCal = oItms.Restrict("[Start] >= '" & CStr(date) & "'")
With rCal
.Sort "[Start]", False
.IncludeRecurrences = True
End With
Specifically, running the “.Sort” and the “.IncludeRecurrances” on rCal without calling the “.Restrict” method caused the problem. I determined that the 2nd “With” was redundant as is, so I removed it. I can now call any property in any order, without having to worry about the values changing.
I am currently working on a Outlook 2010 VBA macro to pull information from a email messages and place it into an Excel file. The idea is that each email has the same fields in tables embedded in the email message every time (name, order number, date, etc.) and that data is put into a spreadsheet. To do this, I have currently used the following code to get the table and move it into Excel:
'This code is inside a for each loop for each message
Set excelWorksheet2 = excelWorkbook.Worksheets.item(2)
Set excelWorksheet3 = excelWorkbook.Worksheets.item(3)
Set excelWorksheet4 = excelWorkbook.Worksheets.Add(After:=excelWorkbook.Sheets(excelWorkbook.Sheets.count))
Dim mailObj As Outlook.MailItem
Dim doc As Word.Document
Set doc = mailObj.GetInspector.WordEditor
Dim table1, table2, table3 As Object
Set table3 = doc.Tables(4).Range
Set table2 = doc.Tables(3).Range
Set table1 = doc.Tables(2).Range
table1.Copy
excelWorksheet2.Paste
table2.Copy
excelWorksheet4.Paste
table3.Copy
excelWorksheet3.Paste
Set table1 = Nothing
Set table2 = Nothing
Set table3 = Nothing
'I do much more of this to get the data from each table and put it into a master worksheet...
excelWorksheet.Cells(rows, cols + 1).Value = excelWorksheet2.Cells(4, 2).Value 'Contract Number
excelWorksheet.Cells(rows, cols + 2).Value = excelWorksheet2.Cells(4, 4).Value 'Contractor Name
Set doc = Nothing
Set excelWorksheet2 = Nothing
Set excelWorksheet3 = Nothing
Set excelWorksheet4 = Nothing
I get the following errors every so often, but it doesn't occur on the same data, it is sort of random and seems to occur on the Outlook/email side only:
"The requested member of the collection does not exist." (Error code
5941) at the .Range line
"Method 'Copy' of object 'Range' failed" at the .Copy
line
Sometimes both of these errors occur if I step through, if the copy fails, the macro will crash.
I have tried:
Putting in 2 second delays
Go through fewer emails (this code usually fails when I select > 10
emails to process)
Clearing the clipboard after every email
Close/deallocate objects through Nothing (not sure if
this is the best practice as I'm more of a C/C++/C#/Java guy)
None of these seemed to remotely fix this issue as both errors pop up frequently, but intermittently.
I'm truly at a loss as to what the next step would be in debugging this issue, any help would be much appreciated!
Based on research I have been doing on the issue of the WordEditor tables, it seems as the amount of copy/paste operations and the searching HTML tables just simply do not allow for reliable behavior. One possible solution to this could be to copy the entire email into Excel and parse the tables that way (this still requires copy/paste).
What I did to solve this problem (indirectly) is to save all the emails as HTML files (through Outlook.Application running in Excel: email.SaveAs folderPath + fileName + ".html", olHTML) in a temporary directory and have Excel open the HTML files in a workbook and work with the data that way. This has been much more reliable (added overhead though) and allows for large volumes of emails to be exported to Excel properly.
If anyone wants the exact code to my problem, message me (vindansam at hotmail.com, it's a tad long and has some proprietary information in it).
It's too bad that the WordEditor seems to not handle the information well, maybe Microsoft will beef things up in the next version of Office.