Пользователи Exchange FreeBusy информация, охватывающая повторяющиеся встречи - PullRequest
0 голосов
/ 21 декабря 2018

Я пытаюсь получить FreeBusy информацию для ряда пользователей Outlook, которая охватывает их (и мои) повторяющиеся встречи.

Я могу заставить код работать для обычных встреч, но застреваю, когда пытаюсь также убедиться, что люди не посещают повторяющиеся встречи (что не возвращается с функцией «Свободный занят»).

Public Sub GetFreeBusyForAPerson()
     Dim usersList As Outlook.AddressEntries
     Dim oEntry As Outlook.AddressEntry
     Dim oContact As Object
     Set usersList = Outlook.Application.Session.AddressLists.Item("All Users").AddressEntries
     Set oEntry=usersList.Item("Jones; Jonathan")
     Debug.Print 
    Mid(oEntry.GetExchangeUser().GetFreeBusy(CDate("08/01/2019"), 60, False), 1, 48)
End Sub

Я вернусь 000000000000000000000000000000000000000000000000 Я знаю, что у этого человека повторяются встречи в рассматриваемый день, но это не показано.

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Я нашел ваш вопрос интригующим.У меня нет доступа к GetExchangeUser().GetFreeBusy, поэтому я не мог знать, правильно ли вы использовали метод.Возможно, кто-то с соответствующими знаниями сделает вас правильно.Но что, если проблема была с GetFreeBusy, был ли альтернативный подход, который дал бы вам ту функциональность, которую вы искали.Прошло несколько лет с тех пор, как я играл с элементами календаря, и я подумал, что было бы интересно освежить мои знания.

Я помню, что у меня есть доступ к календарям моих коллег.Но если это невозможно, какая альтернатива доступна?Установка макроса Outlook в нескольких системах не может быть автоматизирована, поэтому я решил попробовать Excel.Книга Excel, содержащая макрос доступа к Outlook, может быть легко распространена.Может ли этот макрос получить доступ к календарю по умолчанию, извлечь необходимую информацию и отправить ее вам по электронной почте?Это не было бы идеальным решением, но если бы оно сработало, я думаю, что оно дало бы приемлемое второе место.Если бы это работало, код, разработанный в Excel, мог бы распространяться как макрос Outlook и связываться с правилом, которое активировало макрос при отправке электронного письма с определенной темой.Это дало бы вам почти такой же контроль над процессом, как вы надеялись получить с помощью текущего решения.

Ключевой вопрос был: мог ли макрос Excel получить доступ ко всем данным в календаре Outlook?Доступ к календарю оказался проще, чем я ожидал.Однако найти исключения для повторяющихся элементов оказалось непросто, так как я нашел документацию запутанной.Тем не менее, с осторожным использованием Debug's Watch для изучения содержимого AppointmentItem и повторяющихся AppointmentItem * RecurringPattern я смог обнаружить, где хранились исключения.

К тому времени, когда у меня былоЗакончив мой следственный макрос, Дмитрий заявил, что GetFreeBusy может обрабатывать повторяющиеся встречи.Читая его ответы на другие вопросы, становится ясно, что он обладает значительным опытом, поэтому я склонен ему верить.Он задавался вопросом, не создает ли CDate("08/01/2019") дату, которую вы ожидали.Из ваших ответов это не представляется вероятным.Вы могли бы попробовать.DateSerial(2019, 1, 8), который устранит любую двусмысленность, но я сомневаюсь, что в этом проблема.

Я думал, что мой макрос расследования будет полезен.Я протестировал его только в записях календаря, поэтому может потребоваться дальнейшая отладка.Ваши AppointmentItem будут содержать свойства, которых у меня нет, поэтому вам может потребоваться улучшить мой макрос.

Мой макрос управляется тремя константами:

Const DateReportLen As Long = 1            '\ Together identify the length of
Const DateReportLenType As String = "yyyy" '/ the report period
Const DateReportStartOffset As Long = -363 '\ The offset from today to the start of
                                           '| the report period. Set to a positive
                                           '/ value for a date in the future

Начинается период отчета макросана Now() + DateReportStartOffset.Значение -365 позволяет иметь период, начинающийся 1 января 2018 года. Две константы DateReportLen позволяют мне установить дату окончания периода равным году после даты начала.Вам нужно будет откорректировать эти значения, чтобы отправлять отчеты только 8 января 2019 года или, возможно, с несколькими днями по обе стороны.

Макрос создает на рабочем столе файл с именем «Calendar.txt». Вы можетеизмените местоположение и имя, если хотите.Этот файл содержит каждое свойство, которое я считаю релевантным для каждого AppointmentItem, который находится внутри или частично в течение отчетного периода.Изучив эти свойства, вы можете обнаружить, что календарь вашего коллеги отличается от ожидаемого.

Обратите внимание, что мой макрос не работает, если Outlook открыт.Я не исследовал эту проблему

Макрос нуждается в ссылке на «Microsoft Outlook nn.n Library», где «nn.n» указывает версию Office, которую вы используете.

Макрос, которыйДля вывода файла необходима ссылка на «Microsoft ActiveX Data Objects nn Library».«Nn» был «6.1» в течение нескольких лет.

Option Explicit
Sub DiagCal()

  ' Requires reference to Microsoft Outlook nn.n Library
  ' where "nn.n" identifies the version of Office you are using.

  Const DateReportLen As Long = 1            '\ Together identify the length of
  Const DateReportLenType As String = "yyyy" '/ the report period
  Const DateReportStartOffset As Long = -363 '\ The offset from today to the start of
                                             '| the report period. Set to a positive
                                             '/ value for a date in the future

  Dim AppointToReport As New Collection
  Dim AppOutlook As New Outlook.Application
  Dim CalEnt As Object
  Dim CalEntClass As Long
  Dim DateReportEnd As Date
  Dim DateReportStart As Date
  Dim FileBody As String
  Dim FldrCal As Outlook.Folder
  Dim InxAir As Long
  Dim InxFC As Long
  Dim PathDesktop As String

  PathDesktop = CreateObject("WScript.Shell").SpecialFolders("Desktop")

  ' Identify date range to be reported on
  DateReportStart = DateSerial(Year(Now), Month(Now), Day(Now) + DateReportStartOffset)
  DateReportEnd = DateAdd(DateReportLenType, DateReportLen, DateReportStart)

  ' This assumes the calendar of interest is the default calendar.
  ' This is almost certainly true.
  Set FldrCal = AppOutlook.Session.GetDefaultFolder(olFolderCalendar)

  For InxFC = 1 To FldrCal.Items.Count

    Set CalEnt = FldrCal.Items(InxFC)

    ' Occasionally I get syncronisation errors.  This code avoids them.
    CalEntClass = -1
    On Error Resume Next
    CalEntClass = CalEnt.Class
    On Error GoTo 0

    ' I have never found anything but appointments in
    ' Calendar but test just in case
    If CalEntClass = olAppointment Then
      Call DiagCalRecordEntry(CalEnt, DateReportStart, DateReportEnd, AppointToReport)
    End If

  Next InxFC

  FileBody = "Calendar entries within or partially within " & _
             Format(DateReportStart, "d mmm yy") & _
             " to " & Format(DateReportEnd, "d mmm yy") & vbLf & _
             "Total calendar entries: " & FldrCal.Items.Count & vbLf & _
             "Calendar entries within or partially within report period: " & _
             AppointToReport.Count

  For InxAir = 1 To AppointToReport.Count
    FileBody = FileBody & vbLf & String(70, "=")
    FileBody = FileBody & vbLf & AppointToReport(InxAir)(1)
  Next

  Call PutTextFileUtf8NoBom(PathDesktop & "\Calendar.txt", FileBody)

End Sub
Sub DiagCalRecordEntry(ByRef CalEnt As Object, _
                       ByVal DateReportStart As Date, _
                       ByVal DateReportEnd As Date, _
                       ByRef AppointToReport As Collection, _
                       Optional ByVal OriginalDate As Date)

  ' If calendar entry is within or partially within report range, add
  ' its details to AppointToReport

  Dim AllDayEvent As Boolean
  Dim AppointDtls As String
  Dim AppointId As String
  Dim AppointIdMaster As String
  Dim BusyStatus As String
  Dim DateRecurrEnd As Date
  Dim DateRecurrStart As Date
  Dim DateAppointEnd As Date
  Dim DateAppointStart As Date
  Dim DayOfMonth As Long
  Dim DayOfWeekMask As String
  Dim DayOfWeekMaskCode As Long
  Dim DurationEntry As Long
  Dim DurationRecurr As Long
  Dim InxE As Long
  Dim Instance As Long
  Dim Interval As Long
  Dim Location As String
  Dim MonthOfYear As Long
  Dim NoEndDate As Boolean
  Dim NumOccurrences As Long
  Dim RecurrenceState As String
  Dim RecurrenceType As String
  Dim RecurrPattern As Outlook.RecurrencePattern
  Dim Subject As String
  Dim TimeStart As Date
  Dim TimeEnd As Date

  'Debug.Assert False

  ' Get values from calendar entry which identify if entry is within
  ' report range
  With CalEnt
    DateAppointStart = .Start
    DateAppointEnd = .End
    Select Case .RecurrenceState
      Case olApptNotRecurring
        'Debug.Assert False
        RecurrenceState = "Non-recurring calendar entry"
      Case olApptMaster
        'Debug.Assert False
        RecurrenceState = "Master calendar entry"
      Case olApptException
        'Debug.Assert False
        RecurrenceState = "Exception to Master calendar entry"
      Case olApptOccurrence
        Debug.Assert False
        ' I believe this state can only exist if GetOccurrence() is used
        ' to get a single occurrence of a Master entery. I do not believe
        ' it can appear as a calendar entry
        RecurrenceState = "Occurrence"
      Case Else
        Debug.Assert False
        RecurrenceState = "Unrecognised (" & .RecurrenceState & ")"
    End Select
  End With

  If RecurrenceState = "Master calendar entry" Then
    'Debug.Assert False
    Set RecurrPattern = CalEnt.GetRecurrencePattern()
    With RecurrPattern
      DateRecurrStart = .PatternStartDate
      DateRecurrEnd = .PatternEndDate
    End With
    If DateRecurrStart <= DateReportEnd And _
       DateRecurrEnd >= DateReportStart Then
      ' Some or all occurences of this Master entry are within report range
      'Debug.Assert False
    Else
      ' No occurences of this Master entry are within report range
      'Debug.Assert False
      Exit Sub
    End If
  Else
    ' Non recurring or exception appointment
    If DateAppointStart <= DateReportEnd And _
       DateAppointEnd >= DateReportStart Then
      ' Entry is within report range
      'Debug.Assert False
    Else
      ' Non recurring entry is not within report range
      'Debug.Assert False
      Exit Sub
    End If
  End If

  ' Calendar entry is within or partially within report period

  ' Get remaining properties from entry
  'Debug.Assert False
  With CalEnt
    AllDayEvent = .AllDayEvent
    AppointId = .GlobalAppointmentID
    Select Case .BusyStatus
      Case olBusy
        'Debug.Assert False
        BusyStatus = "Busy"
      Case olFree
        'Debug.Assert False
        BusyStatus = "Free"
      Case olOutOfOffice
       'Debug.Assert False
       BusyStatus = "Out of Office"
      Case olTentative
        Debug.Assert False
        BusyStatus = "Tentative appointment"
      Case olWorkingElsewhere
        'Debug.Assert False
        BusyStatus = "Working elsewhere"
      Case Else
        Debug.Assert False
        BusyStatus = "Not recognised (" & .BusyStatus & ")"
    End Select
    Location = .Location
    Subject = .Subject
  End With

  If RecurrenceState = "Exception to Master calendar entry" Then
    RecurrenceState = RecurrenceState & vbLf & _
                      "Master's Id: " & CalEnt.Parent.GlobalAppointmentID & vbLf & _
                      "Original Date: " & OriginalDate
  End If

  AppointDtls = RecurrenceState & vbLf & _
                "AllDayEvent: " & AllDayEvent & vbLf & _
                "AppointId: " & AppointId & vbLf & _
                "BusyStatus: " & BusyStatus & vbLf & _
                "DateAppointStart: " & DateAppointStart & vbLf & _
                "DateAppointEnd: " & DateAppointEnd & vbLf & _
                "DurationEntry: " & DurationEntry & vbLf & _
                "Location: " & Location & vbLf & _
                "Subject: " & Subject

  If RecurrenceState <> "Master calendar entry" Then
    ' AppointDtls complete for this appointment
    Call StoreSingleAppoint(Format(DateAppointStart, "yyyymmddhhmm"), _
                            AppointDtls, AppointToReport)
  Else
    'Debug.Assert False
    With RecurrPattern
      ' Not all parameters have a meaningful value for all RecurrenceTypes
      ' but the value always appears to be of the correct data type.
      DateRecurrStart = .PatternStartDate
      DateRecurrEnd = .PatternEndDate
      DayOfMonth = .DayOfMonth
      DayOfWeekMaskCode = .DayOfWeekMask
      DayOfWeekMask = ""
      If DayOfWeekMaskCode >= olSaturday Then
        Debug.Assert False
        DayOfWeekMask = "+Saturday"
        DayOfWeekMaskCode = DayOfWeekMaskCode - olSaturday
      End If
      If DayOfWeekMaskCode >= olFriday Then
        'Debug.Assert False
        DayOfWeekMask = "+Friday" & DayOfWeekMask
        DayOfWeekMaskCode = DayOfWeekMaskCode - olFriday
      End If
      If DayOfWeekMaskCode >= olThursday Then
        'Debug.Assert False
        DayOfWeekMask = "+Thursday" & DayOfWeekMask
        DayOfWeekMaskCode = DayOfWeekMaskCode - olThursday
      End If
      If DayOfWeekMaskCode >= olWednesday Then
        'Debug.Assert False
        DayOfWeekMask = "+Wednesday" & DayOfWeekMask
        DayOfWeekMaskCode = DayOfWeekMaskCode - olWednesday
      End If
      If DayOfWeekMaskCode >= olTuesday Then
        'Debug.Assert False
        DayOfWeekMask = "+Tuesday" & DayOfWeekMask
        DayOfWeekMaskCode = DayOfWeekMaskCode - olTuesday
      End If
      If DayOfWeekMaskCode >= olMonday Then
        'Debug.Assert False
        DayOfWeekMask = "+Monday" & DayOfWeekMask
        DayOfWeekMaskCode = DayOfWeekMaskCode - olMonday
      End If
      If DayOfWeekMaskCode >= olSunday Then
        'Debug.Assert False
        DayOfWeekMask = "+Sunday" & DayOfWeekMask
      End If
      If DayOfWeekMask = "" Then
        'Debug.Assert False
        DayOfWeekMask = "None"
      Else
        'Debug.Assert False
        DayOfWeekMask = Mid$(DayOfWeekMask, 2) ' Remove leading +
      End If
      DurationRecurr = .Duration
      Instance = .Instance
      Interval = .Interval
      MonthOfYear = .MonthOfYear
      NoEndDate = .NoEndDate
      NumOccurrences = .Occurrences
      Select Case .RecurrenceType
        Case olRecursDaily
          'Debug.Assert False
          RecurrenceType = "Daily"
        Case olRecursMonthly
          Debug.Assert False
          RecurrenceType = "Monthly"
        Case olRecursMonthNth
          Debug.Assert False
          RecurrenceType = "MonthNth"
        Case olRecursWeekly
          'Debug.Assert False
          RecurrenceType = "Weekly"
        Case olRecursYearly
          'Debug.Assert False
          RecurrenceType = "Yearly"
        Case olRecursYearNth
          Debug.Assert False
          RecurrenceType = "YearNth"
        Case Else
          Debug.Assert False
          RecurrenceType = "Unrecognised Value (" & RecurrenceType & ")"
      End Select
      TimeStart = .StartTime
      TimeEnd = .EndTime
    End With

    AppointDtls = AppointDtls & vbLf & "DateRecurrStart: " & DateRecurrStart _
                              & vbLf & "DateRecurrEnd: " & DateRecurrEnd _
                              & vbLf & "DayOfMonth: " & DayOfMonth _
                              & vbLf & "DayOfWeekMask: " & DayOfWeekMask _
                              & vbLf & "DurationRecurr: " & DurationRecurr _
                              & vbLf & "Instance: " & Instance _
                              & vbLf & "Interval: " & Interval _
                              & vbLf & "MonthOfYear: " & MonthOfYear _
                              & vbLf & "NoEndDate: " & NoEndDate _
                              & vbLf & "NumOccurrences: " & NumOccurrences _
                              & vbLf & "RecurrenceType: " & RecurrenceType _
                              & vbLf & "TimeStart: " & TimeStart & " (" & CDbl(TimeStart) & ")" _
                              & vbLf & "TimeEnd: " & TimeEnd & " (" & CDbl(TimeEnd) & ")"

    For InxE = 1 To RecurrPattern.Exceptions.Count
      AppointDtls = AppointDtls & vbLf & "Exception " & InxE & " for occurrence on " & _
                                   RecurrPattern.Exceptions.Item(InxE).OriginalDate
    Next

    Call StoreSingleAppoint(Format(DateRecurrStart, "yyyymmddhhmm"), _
                            AppointDtls, AppointToReport)

    For InxE = 1 To RecurrPattern.Exceptions.Count
      Call DiagCalRecordEntry(RecurrPattern.Exceptions.Item(InxE).AppointmentItem, _
                              DateReportStart, DateReportEnd, AppointToReport, _
                              RecurrPattern.Exceptions.Item(InxE).OriginalDate)
    Next

  End If ' RecurrenceState <> "Master calendar entry"

End Sub

Public Sub PutTextFileUtf8NoBom(ByVal PathFileName As String, ByVal FileBody As String)

  ' Outputs FileBody as a text file named PathFileName using
  ' UTF-8 encoding without leading BOM

  ' Needs reference to "Microsoft ActiveX Data Objects n.n Library"
  ' Addition to original code says version 2.5. Tested with version 6.1.

  '  1Nov16  Copied from http://stackoverflow.com/a/4461250/973283
  '          but replaced literals with parameters.
  ' 15Aug17  Discovered routine was adding an LF to the end of the file.
  '          Added code to discard that LF.
  ' 11Oct17  Posted to StackOverflow
  '  9Aug18  Comment from rellampec suggested removal of adWriteLine from
  '          WriteTest statement would avoid adding LF.
  ' 30Sep18  Amended routine to remove adWriteLine from WriteTest statement
  '          and code to remove LF from file. Successfully tested new version.

  ' References: http://stackoverflow.com/a/4461250/973283
  '             https://www.w3schools.com/asp/ado_ref_stream.asp

  Dim BinaryStream As Object
  Dim UTFStream As Object

  Set UTFStream = CreateObject("adodb.stream")

  UTFStream.Type = adTypeText
  UTFStream.Mode = adModeReadWrite
  UTFStream.Charset = "UTF-8"
  UTFStream.Open
  UTFStream.WriteText FileBody

  UTFStream.Position = 3 'skip BOM

  Set BinaryStream = CreateObject("adodb.stream")
  BinaryStream.Type = adTypeBinary
  BinaryStream.Mode = adModeReadWrite
  BinaryStream.Open

  UTFStream.CopyTo BinaryStream

  UTFStream.Flush
  UTFStream.Close
  Set UTFStream = Nothing

  BinaryStream.SaveToFile PathFileName, adSaveCreateOverWrite
  BinaryStream.Flush
  BinaryStream.Close
  Set BinaryStream = Nothing

End Sub
Sub StoreSingleAppoint(ByVal SeqKey As String, _
                       ByVal AppointDtls As String, _
                       ByRef AppointToReport As Collection)

  ' Entries in AppointToReport are of the form:
  '    VBA.Array(SeqKey, AppointDtls)
  ' Add new entry to AppointToReport so entries are in ascending order by SeqKey

  Dim InxAtr As Long

  If AppointToReport.Count = 0 Then
    'Debug.Assert False
    ' first appointment
    AppointToReport.Add VBA.Array(SeqKey, AppointDtls)
    Else
    For InxAtr = AppointToReport.Count To 1 Step -1
      If SeqKey >= AppointToReport(InxAtr)(0) Then
        ' New appointment belongs after this existing entry
        'Debug.Assert False
        AppointToReport.Add VBA.Array(SeqKey, AppointDtls), , , InxAtr
        Exit Sub
      End If
    Next
    ' If get here, new appointment belongs before all existing appointments
    'Debug.Assert False
    AppointToReport.Add VBA.Array(SeqKey, AppointDtls), , 1
  End If

End Sub
0 голосов
/ 02 января 2019

FreeBusy будет работать в границах рабочего времени, установленного пользовательскими ресурсами Exchange, однако, похоже, что оно не работает вне этих времен.Будет продолжать исследовать и проверять, могу ли я (а) определить рабочее время пользователей обмена через VBA (хотя предварительное расследование показывает, что я не могу этого сделать), и (б) проверить, вернувшись в работу, работает ли функция с частными встречами (во время каждогоиз рабочих часов пользователей).Спасибо за всю помощь, я действительно наслаждаюсь этим сайтом и ценю оказанную помощь!

0 голосов
/ 26 декабря 2018

GetFreeBusy прекрасно работает с повторяющимися встречами.Вы уверены, что правильно закодировали дату?Предполагается, что «01.08.2009» будет 1 августа 2019 года или 8 января 2019 года?Помните, что текущая локаль используется для конвертации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...