Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions drivers/place/visitor_mailer.cr
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,13 @@ class Place::VisitorMailer < PlaceOS::Driver

case guest_details
in GuestCheckin
# the same signal is fired for check-out (state=false), only notify the
# host of arrivals. checkin is nilable for backwards compatibility.
if guest_details.checkin == false
logger.debug { "ignoring guest checkin event as the visitor was checked out" }
return
end

send_checkedin_email(
@notify_checkin_template,
guest_details.attendee_email,
Expand Down
130 changes: 130 additions & 0 deletions drivers/place/visitor_mailer_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1705,4 +1705,134 @@ DriverSpecs.mock_driver "Place::VisitorMailer" do
system(:Mailer)[:last_to].should eq "old-host-n@example.com"
system(:Mailer)[:last_template].should eq ["visitor_invited", "notify_original_host"]
system(:Mailer)[:last_args]["event_date"].raw.should be_nil
# ==================================================================
# visitor check-in tests (PPT-2535)
# ==================================================================

# ------------------------------------------------------------------
# Test 39: guest_event — visitor check-in sends the notify_checkin
# email to the host. Payloads mirror what staff-api emits
# from bookings.cr#guest_checkin and events.cr#guest_checkin.
# ------------------------------------------------------------------

count_before_checkin = system(:Mailer)[:send_count].as_i
checked_in_before = status[:users_checked_in]?.try(&.as_i64) || 0_i64

booking_checkin_payload = {
action: "checkin",
id: 900_i64,
checkin: true,
booking_id: 900_i64,
resource_id: "visitor@external.com",
resource_ids: ["visitor@external.com"],
event_title: "Catch Up",
event_summary: "Catch Up",
event_starting: now + 3600,
attendee_name: "Visitor One",
attendee_email: "visitor@external.com",
host: "host@example.com",
zones: ["zone-building", "zone-room"],
}.to_json

publish("staff/guest/checkin", booking_checkin_payload)
sleep 1.0

system(:Mailer)[:send_count].should eq count_before_checkin + 1
system(:Mailer)[:last_to].should eq "host@example.com"
system(:Mailer)[:last_template].should eq ["visitor_invited", "notify_checkin"]
status[:users_checked_in].should eq checked_in_before + 1

args_checkin = system(:Mailer)[:last_args]
args_checkin["visitor_email"].should eq "visitor@external.com"
args_checkin["host_email"].should eq "host@example.com"
args_checkin["event_title"].should eq "Catch Up"

event_checkin_payload = {
action: "checkin",
id: 901_i64,
checkin: true,
system_id: "sys-room1",
event_id: "evt-900",
event_ical_uid: "ical-900",
host: "host@example.com",
resource: "room1@example.com",
event_title: "Catch Up",
event_summary: "Catch Up",
event_starting: now + 3600,
attendee_name: "Visitor One",
attendee_email: "visitor@external.com",
zones: ["zone-building", "zone-room"],
}.to_json

publish("staff/guest/checkin", event_checkin_payload)
sleep 1.0

system(:Mailer)[:send_count].should eq count_before_checkin + 2
system(:Mailer)[:last_to].should eq "host@example.com"
system(:Mailer)[:last_template].should eq ["visitor_invited", "notify_checkin"]

# ------------------------------------------------------------------
# Test 40: guest_event — check-in for an untitled booking (PPT-2535)
# bookings without a title or description signal
# event_title / event_summary as null. This previously failed
# to parse (event_summary was non-nilable) so the exception
# was swallowed and the host never received the notification.
# ------------------------------------------------------------------

count_before_untitled = system(:Mailer)[:send_count].as_i
errors_before_untitled = status[:error_count]?.try(&.as_i64) || 0_i64

untitled_checkin_payload = {
action: "checkin",
id: 902_i64,
checkin: true,
booking_id: 902_i64,
resource_id: "visitor@external.com",
resource_ids: ["visitor@external.com"],
event_title: nil,
event_summary: nil,
event_starting: now + 3600,
attendee_name: "Visitor One",
attendee_email: "visitor@external.com",
host: "host@example.com",
zones: ["zone-building", "zone-room"],
}.to_json

publish("staff/guest/checkin", untitled_checkin_payload)
sleep 1.0

system(:Mailer)[:send_count].should eq count_before_untitled + 1
system(:Mailer)[:last_to].should eq "host@example.com"
system(:Mailer)[:last_template].should eq ["visitor_invited", "notify_checkin"]
(status[:error_count]?.try(&.as_i64) || 0_i64).should eq errors_before_untitled

# ------------------------------------------------------------------
# Test 41: guest_event — visitor check-out (state=false) does NOT
# send the "visitor has arrived" email (PPT-2535)
# ------------------------------------------------------------------

count_before_checkout = system(:Mailer)[:send_count].as_i
checked_in_before_checkout = status[:users_checked_in].as_i64

checkout_payload = {
action: "checkin",
id: 903_i64,
checkin: false,
booking_id: 903_i64,
resource_id: "visitor@external.com",
resource_ids: ["visitor@external.com"],
event_title: "Catch Up",
event_summary: "Catch Up",
event_starting: now + 3600,
attendee_name: "Visitor One",
attendee_email: "visitor@external.com",
host: "host@example.com",
zones: ["zone-building", "zone-room"],
}.to_json

publish("staff/guest/checkin", checkout_payload)
sleep 1.0

system(:Mailer)[:send_count].should eq count_before_checkout
status[:users_checked_in].should eq checked_in_before_checkout
end
3 changes: 2 additions & 1 deletion drivers/place/visitor_models.cr
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ module Place

property checkin : Bool?
property event_title : String?
property event_summary : String
# nilable as bookings without a title or description signal null
property event_summary : String?
property event_starting : Int64
property attendee_name : String?
property attendee_email : String
Expand Down
Loading