Sep 19, 2017 4:46 PM
7 Posts
topic has been resolvedResolved

Help w/Calendar Invitation - Specifically $PreventReplies

  • Category: Application Development
  • Platform: All Platforms
  • Release: 9.0.1
  • Role: Developer
  • Tags:
  • Replies: 8

I have some code in an application which creates and sends a meeting invitation.  In Notes everything works as expected, in other mail clients (specifically Gmail and Outlook) I'm having an issue I have not been able to resolve.  In the creation of the invitation I'm setting $PreventReplies = "1" which per the documentation "Indicates whether or not Chair wants replies back" and set to 1 indicates that no reply is to be sent.  What this means is that when a user accepts/declines the invitation or any updates to it the chair does NOT get updated (this is what I need).

 

The issue is that in both Gmail and Outlook when the user accepts the invitation a reply IS sent to the chair.

 

Here is the routine for anyone wanting to see the whole thing.

 

Sub SendNotes(scheduleDoc As NotesDocument, currUserName As String, whatAction)
 
 ' Send a Calendar Appointment invitiation using Notes style Calendaring and Scheduling built-in the mail template
 Dim SendTo As String  ' A comma separated string
 Dim CopyTo As String  ' A comma separated string
 Dim language As String
 Dim invitation As NotesDocument
 Dim startdttm As NotesDateTime
 Dim enddttm As NotesDateTime
 Dim rtitem As NotesRichTextItem
 Dim tasktype As String
 Dim tmpItem As NotesItem
 
 SendTo = Join(scheduleDoc.CalEntryInvitees, ",")
 CopyTo = ""
 language = "en-US"
 Set invitation = New NotesDocument(scheduleDoc.ParentDatabase)
 
 With invitation
  .ReplaceItemValue "$altPrincipal", currUserName
  .ReplaceItemValue "$CSVersion", "2"
  .ReplaceItemValue "$FromPreferredLanguage", language
  .ReplaceItemValue "$PreventReplies", "1"  ' Indicates whether or not Chair wants replies back
  .ReplaceItemValue "$PublicAccess", "1"
  .ReplaceItemValue "$SignatureStatus", "0"
  .ReplaceItemValue "$SMTPKeepNotesItems", "1"
  .ReplaceItemValue "AppointmentType", "3"
  .ReplaceItemValue "Chair", currUserName
  .ReplaceItemValue "Encrypt", "0"
  .ReplaceItemValue "Form", "Notice"
  .ReplaceItemValue "Location", scheduleDoc.CalEntryLocDefault(0)
  .ReplaceItemValue "PreventCounter", "1"  ' Prevents the user from proposing a different meeting date/time
  .ReplaceItemValue "PreventDelegate", "1" ' Prevents the user from delegating this meeting to someone else
  .ReplaceItemValue "Principal", currUserName
  Set tmpItem = New NotesItem(invitation, "RequiredAttendees", Split(SendTo, ","), NAMES)
  tmpItem.IsSummary = True
  Set tmpItem = New NotesItem(invitation, "SendTo", Split(SendTo, ","), NAMES)
  tmpItem.IsSummary = True
  If CopyTo = "" Then
   .ReplaceItemValue "CopyTo", ""
  Else
   Set tmpItem = New NotesItem(invitation, "CopyTo", Split(CopyTo, ","), NAMES)
   tmpItem.IsSummary = True
  End If
  .ReplaceItemValue "StorageRequiredNames", "1"
  
  ' Compute the Date and time fields
  Set startdttm = New NotesDateTime(Trim(scheduleDoc.StartDate(0) & " " & scheduleDoc.StartTime(0)))
  Set enddttm = New NotesDateTime(Trim(scheduleDoc.EndDate(0) & " " & scheduleDoc.EndTime(0)))
  Set invitation.StartDateTime = startdttm
  invitation.StartDate =  startdttm.DateOnly
  invitation.StartTime =  startdttm.TimeOnly
  invitation.StartTimeZone = Evaluate({@GetCurrentTimeZone})
  Set invitation.EndDateTime = enddttm
  invitation.EndDate = enddttm.DateOnly
  invitation.EndTime = enddttm.TimeOnly
  invitation.EndTimeZone = Evaluate({@GetCurrentTimeZone})

  Select Case whatAction
   Case "SAVE"
    ' Send first time invitation
    .ReplaceItemValue "$CSWISL", Evaluate({@Explode("$S:1;$L:1;$B:1;$R:1;$E:1;$W:1;$O:1;$M:1;RequiredAttendees:1;INetRequiredNames:1;AltRequiredNames:1;StorageRequiredNames:1;OptionalAttendees:1;INetOptionalNames:1;AltOptionalNames:1;StorageOptionalNames:1"; ";")})
    .ReplaceItemValue "$HFFlags", "1"
    .ReplaceItemValue "$IconSwitcher", "Meeting"
    .ReplaceItemValue "$NameLanguageTags", Left(language, 2)
    .ReplaceItemValue "$StorageCc", ""
    .ReplaceItemValue "$StorageTo", "1"
    .ReplaceItemValue "$TableSwitcher", "Description"
    .ReplaceItemValue "$WatchedItems", Evaluate({@Explode("$S;$L;$B;$R;$E;$W;$O;$M;RequiredAttendees;INetRequiredNames;AltRequiredNames;StorageRequiredNames;OptionalAttendees;INetOptionalNames;AltOptionalNames;StorageOptionalNames"; ";")})
    .ReplaceItemValue "ApptUNID", .UniversalID
    .ReplaceItemValue "IsBroadcast", "0"
    .ReplaceItemValue "Logo", "StdNotesLtr25"
    .ReplaceItemValue "NoticeType", "I"
    .ReplaceItemValue "OrgTable", "C0"
    .ReplaceItemValue "SchedulerSwitcher", "1"
    .ReplaceItemValue "Sign", ""
    .ReplaceItemValue "subject", "Invitation:  " + scheduleDoc.SubjectText(0) + "(" + startdttm.DateOnly + " " + startdttm.TimeOnly + " in " + scheduleDoc.CalEntryLocDefault(0) + ")"
    .ReplaceItemValue "topic", "Invitation:  " + scheduleDoc.SubjectText(0)
    .ReplaceItemValue "SequenceNum", scheduleDoc.SequenceNum(0)
    .ReplaceItemValue "UpdateSeq", scheduleDoc.UpdateSeq(0)
    .ReplaceItemValue "_ViewIcon", 133
   Case "CHANGE"
    ' Send notice update
    .ReplaceItemValue "$CSFlags", "w"
    Dim updateSeq As String
    updateSeq = CStr(scheduleDoc.UpdateSeq(0))
    Print updateSeq
    .ReplaceItemValue "$CSWISL", Split("$L:1;$R:1;$E:1;$W:1;$O:1;$M:1;RequiredAttendees:1;INetRequiredNames:1;AltRequiredNames:1;StorageRequiredNames:1;OptionalAttendees:1;INetOptionalNames:1;AltOptionalNames:1;StorageOptionalNames:1;$S:" & updateSeq & ";$B:" & updateSeq, ";")
    Call .MakeResponse(invitation.ParentDatabase.GetProfileDocument("(CalendarProfile)"))
    Set tmpItem = .GetFirstItem("$REF")
    ForAll v In tmpItem.Values
     v = scheduleDoc.meetingdocid(0)
    End ForAll
    .ReplaceItemValue "$REFOPTIONS", "1"
    .ReplaceItemValue "ApptUNID", scheduleDoc.meetingdocid
    
    .ReplaceItemValue "NoticeType", "U"
    
    .ReplaceItemValue "subject", "Update: " + scheduleDoc.SubjectText(0)
    .ReplaceItemValue "topic", "Update: " + scheduleDoc.SubjectText(0)
    .ReplaceItemValue "SequenceNum", scheduleDoc.SequenceNum(0)
    .ReplaceItemValue "UpdateSeq", scheduleDoc.UpdateSeq(0)
    
    .ReplaceItemValue "_ViewIcon", 33
    .ReplaceItemValue "$Abstract", scheduleDoc.Comments(0)
   Case "DELETE"
    ' Send cancellation notice
    .ReplaceItemValue "$CSFlags", "w"
    updateSeq = CStr(scheduleDoc.UpdateSeq(0))
    Print updateSeq
    .ReplaceItemValue "$CSWISL", Split("$L:1;$R:1;$E:1;$W:1;$O:1;$M:1;RequiredAttendees:1;INetRequiredNames:1;AltRequiredNames:1;StorageRequiredNames:1;OptionalAttendees:1;INetOptionalNames:1;AltOptionalNames:1;StorageOptionalNames:1;$S:" & updateSeq & ";$B:" & updateSeq, ";")
    Call .MakeResponse(invitation.ParentDatabase.GetProfileDocument("(CalendarProfile)"))
    Set tmpItem = .GetFirstItem("$REF")
    ForAll v In tmpItem.Values
      v = scheduleDoc.meetingdocid(0)
     End ForAll
    .ReplaceItemValue "$REFOPTIONS", "1"
    .ReplaceItemValue "ApptUNID", scheduleDoc.meetingdocid
    
    .ReplaceItemValue "NoticeType", "C"
    
    .ReplaceItemValue "subject", "Cancelled: " + scheduleDoc.SubjectText(0)
    .ReplaceItemValue "topic", "Cancelled: " + scheduleDoc.SubjectText(0)
    .ReplaceItemValue "SequenceNum", scheduleDoc.SequenceNum(0)
    .ReplaceItemValue "UpdateSeq", scheduleDoc.UpdateSeq(0)
    
    .ReplaceItemValue "_ViewIcon", 81
   Case Else
    ' Error getting the whatAction, define an error then go to ErrorHandler
    MessageBox "No action was found, please report this issue to the support center.", 0+16+0+0, "No Action Performed"
    Exit Sub
  End Select
 End With
 
 ' Set the Body RT field
 Set rtitem = New NotesRichTextItem(invitation, "Body" )
 With rtItem
  .AppendText(scheduleDoc.Comments(0))
 End With
 
 ' Send the invitation
 Invitation.Send(False)
 
End Sub

Sep 19, 2017 10:10 PM
293 Posts
Can't

Hate to say it but as you discovered inter operability issues with notes to gmail and outlook.     Did you try manually to send the invite with the no reply to gmail and outlook?  It likely will fail for the prevent replies and if it doesn't capture the fields on that invite and compare it to the doc you are creating with lotusscript.

Sep 20, 2017 9:27 AM
7 Posts
A Little Progress

I created an invitation from my Notes calendar and selected the "Do not receive responses from invitees" option.  From Gmail I did get a response when the user accepted the invitation...from Outlook I did not receive a response when the user accepted the invitation.  Now the question would be why?  What flag was set that caused Outlook to not send a response?

Sep 22, 2017 1:14 PM
34 Posts
Final tidbits
I missed this thread earlier but it seems you got it working which is good.

Broadcast is also described in the schema doc but you probably didn't notice once you saw $PreventReplies.  Without checking the template and code I would guess it is similar in reason to the $BusyPriority / BookFreeTime items.  They are 2 that are used for nearly the same function and exist solely for legacy reasons going back to R4.5.  

The reason you get a response from GMail but not Outlook when you say "no responses" is that when we send RSVP=FALSE on the invite, only Outlook is actually paying attention to it.  GMail does not.  I would guess that is because they do not have the concept of a broadcast (at least not that I have ever been able to find), they expect invitees to always respond.  

Do not include alarm related items on your workflow emails.  Alarms are set based on each users profile settings and not something others will pull from your workflow.


Do not put any "prefix" on your Topic value:
  .ReplaceItemValue "topic", "Invitation:  " + scheduleDoc.SubjectText(0)
...
    .ReplaceItemValue "topic", "Cancelled: " + scheduleDoc.SubjectText(0)
Only Subject gets that kind of info / mangling.  Topic should be the unmodified "subject".  
Bruce

IBM
Sep 20, 2017 10:33 AM
293 Posts
Export

Export both the doc created by lotusscript and via the client and compare the fields.

Sep 20, 2017 4:50 PM
7 Posts
Getting there...new issue now though, getting an error in Notes client

I've been doing that to help this process.  :)  Here's what I have from this round of testing....

 

This is a list of fields that exist in the invitation created from my calendar that do not exist in the invitation created from my LotusScript:

      Broadcast
    

Conversely, here is a list of fields that exist in the LotusScript invitation that do not exist in the one created from my calendar:

      $AlarmDisabled
      Alarms
     
So with all this in mind I have tested the LotusScript invitation with Boradcast="1" to match what was created from my calendar.  This seems to work for Outlook, unfortunately not for Gmail...honestly this is alright.  HOWEVER!  When I cancel the meeting and go to open the cancellation notice in the Notes client I get this error:

     Field: 'tmpHideTimeZone': Incorrect data type for operator or @Function: Time/Date expected

 

Any thoughts on this new issue?

Sep 20, 2017 5:29 PM
293 Posts
Check

Look at  the button that does the cancel.   Chances are there is a another field in the invite that does not exist in your lotusscript invite and the cancel code does not create the " tmpHideTimeZone " field.  Search in the code fore tmpHideTimeZone  and see what that is based in the original doc that you need to add.  

 

 

In addition I house a snippet of code in openntf.org that you might want to compare your code against,

 

https://openntf.org/XSnippets.nsf/snippet.xsp?id=create-calendar-entry-with-lotusscript

 

 

Sep 21, 2017 10:26 AM
7 Posts
tmpHideTimeZone Field Findings

Interesting findings...

I found that the tmpHideTimeZone field exists in a few forms in the standard mail template and in the @Formula it references 8 fields.  Below is a list of those fields and the datatype associated with each in documents generated from both my Notes calendar and the LotusScript.

 

                      From Calendar      From LotusScript
-----------------------------------------------------------------------------------
StartTimeZone       Text             
EndTimeZone        Text            

StartTime
StartDateTime       Time/Date      Time/Date
StartDate               Time/Date      Text

EndTime
EndDateTime        Time/Date      Time/Date
EndDate

 

Now here's the interesting part, these fields are all set in ONE place in the LotusScript...in the initial invitation and subsequent updates the StartDate is of Time/Date type, only on cancellations is it somehow flipped to Text (NOWHERE else in my code are these fields set, I've already looked).  Below is the code snippet that sets these values.  I guess my next step is to explicitly set the datatype to Time/Date on the StartDate field and see how that works out.

 

' Compute the Date and time fields

Set startdttm = New NotesDateTime(Trim(scheduleDoc.StartDate(0) & " " & scheduleDoc.StartTime(0)))

Set enddttm = New NotesDateTime(Trim(scheduleDoc.EndDate(0) & " " & scheduleDoc.EndTime(0)))

Set invitation.StartDateTime = startdttm

invitation.StartDate = startdttm.DateOnly

invitation.StartTime = startdttm.TimeOnly

invitation.StartTimeZone =

Evaluate({@GetCurrentTimeZone})

Set invitation.EndDateTime = enddttm

invitation.EndDate = enddttm.DateOnly

invitation.EndTime = enddttm.TimeOnly

invitation.EndTimeZone =

Evaluate({@GetCurrentTimeZone})

Sep 21, 2017 4:01 PM
7 Posts
Success!!!

The offending fields were:
     StartDate
     StartTime
     EndTime
 

I changed the StartDate a bit so it is forced to be Time/Date datatype and since StartTime and EndTime were not needed when sending a cancellation notice I eliminated them.

Thank you for all the guidance!!  :D