mirror of
https://github.com/itflow-org/itflow
synced 2026-08-23 16:05:12 +00:00
Fix ticket schedule cancellation never cancelling the calendar event
This commit is contained in:
@@ -3062,7 +3062,7 @@ if (isset($_POST['edit_ticket_schedule'])) {
|
|||||||
|
|
||||||
|
|
||||||
/// Create iCal event
|
/// Create iCal event
|
||||||
$cal_str = createiCalStr($schedule, $cal_subject, $cal_description, $cal_location);
|
$cal_str = createiCalStr($schedule, $cal_subject, $cal_description, $cal_location, getTicketCalendarUid($ticket_id));
|
||||||
|
|
||||||
// Notify the agent of the scheduled work
|
// Notify the agent of the scheduled work
|
||||||
$data[] = [
|
$data[] = [
|
||||||
@@ -3183,7 +3183,6 @@ if (isset($_GET['cancel_ticket_schedule'])) {
|
|||||||
$ticket_number = intval($row['ticket_number']);
|
$ticket_number = intval($row['ticket_number']);
|
||||||
$ticket_subject = escapeSql($row['ticket_subject']);
|
$ticket_subject = escapeSql($row['ticket_subject']);
|
||||||
$ticket_schedule = escapeSql($row['ticket_schedule']);
|
$ticket_schedule = escapeSql($row['ticket_schedule']);
|
||||||
$ticket_cal_str = escapeSql($row['ticket_cal_str']);
|
|
||||||
|
|
||||||
// Don't Enforce Client Access if Ticket doesn't have an assigned client
|
// Don't Enforce Client Access if Ticket doesn't have an assigned client
|
||||||
if ($client_id) {
|
if ($client_id) {
|
||||||
@@ -3203,9 +3202,6 @@ if (isset($_GET['cancel_ticket_schedule'])) {
|
|||||||
$config_ticket_from_name = escapeSql($config_ticket_from_name);
|
$config_ticket_from_name = escapeSql($config_ticket_from_name);
|
||||||
$session_company_name = escapeSql($session_company_name);
|
$session_company_name = escapeSql($session_company_name);
|
||||||
|
|
||||||
//Create iCal event
|
|
||||||
$cal_str = createiCalStrCancel($ticket_cal_str);
|
|
||||||
|
|
||||||
//Send emails
|
//Send emails
|
||||||
|
|
||||||
$sql = mysqli_query($mysqli, "SELECT client_name, contact_email, contact_name, ticket_client_id, ticket_details, ticket_number,
|
$sql = mysqli_query($mysqli, "SELECT client_name, contact_email, contact_name, ticket_client_id, ticket_details, ticket_number,
|
||||||
@@ -3229,6 +3225,10 @@ if (isset($_GET['cancel_ticket_schedule'])) {
|
|||||||
$user_name = escapeSql($row['user_name']);
|
$user_name = escapeSql($row['user_name']);
|
||||||
$user_email = escapeSql($row['user_email']);
|
$user_email = escapeSql($row['user_email']);
|
||||||
|
|
||||||
|
//Create the iCal cancellation - same UID and subject as the original invite
|
||||||
|
$cal_subject = $ticket_number . ": " . $client_name . " - " . $ticket_subject;
|
||||||
|
$cal_str = createiCalStrCancel($ticket_schedule, $cal_subject, getTicketCalendarUid($ticket_id));
|
||||||
|
|
||||||
// Notify the agent of the cancellation
|
// Notify the agent of the cancellation
|
||||||
$data[] = [
|
$data[] = [
|
||||||
// User Email
|
// User Email
|
||||||
|
|||||||
@@ -415,7 +415,16 @@ function addToMailQueue($data) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createiCalStr($datetime, $title, $description, $location) {
|
function getTicketCalendarUid($ticket_id) {
|
||||||
|
// An invite and its later cancellation MUST carry the same UID or the
|
||||||
|
// recipient's calendar client cannot match them up. Derive it from the
|
||||||
|
// ticket so it is stable across both, rather than from the current time.
|
||||||
|
$ticket_id = intval($ticket_id);
|
||||||
|
$host = $_SERVER['SERVER_NAME'] ?? 'itflow';
|
||||||
|
return "ticket-$ticket_id@$host";
|
||||||
|
}
|
||||||
|
|
||||||
|
function createiCalStr($datetime, $title, $description, $location, $uid = null) {
|
||||||
require_once "../libs/zapcal/zapcallib.php";
|
require_once "../libs/zapcal/zapcallib.php";
|
||||||
|
|
||||||
// Create the iCal object
|
// Create the iCal object
|
||||||
@@ -431,8 +440,11 @@ function createiCalStr($datetime, $title, $description, $location) {
|
|||||||
// Todo: adjust this for actual duration
|
// Todo: adjust this for actual duration
|
||||||
$event->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime($datetime)));
|
$event->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime($datetime)));
|
||||||
$event->addNode(new ZCiCalDataNode("DTSTAMP:" . ZCiCal::fromSqlDateTime()));
|
$event->addNode(new ZCiCalDataNode("DTSTAMP:" . ZCiCal::fromSqlDateTime()));
|
||||||
$uid = date('Y-m-d-H-i-s') . "@" . $_SERVER['SERVER_NAME'];
|
if (empty($uid)) {
|
||||||
|
$uid = date('Y-m-d-H-i-s') . "@" . ($_SERVER['SERVER_NAME'] ?? 'itflow');
|
||||||
|
}
|
||||||
$event->addNode(new ZCiCalDataNode("UID:" . $uid));
|
$event->addNode(new ZCiCalDataNode("UID:" . $uid));
|
||||||
|
$event->addNode(new ZCiCalDataNode("SEQUENCE:0"));
|
||||||
$event->addNode(new ZCiCalDataNode("LOCATION:" . $location));
|
$event->addNode(new ZCiCalDataNode("LOCATION:" . $location));
|
||||||
$event->addNode(new ZCiCalDataNode("DESCRIPTION:" . $description));
|
$event->addNode(new ZCiCalDataNode("DESCRIPTION:" . $description));
|
||||||
// Todo: add organizer details
|
// Todo: add organizer details
|
||||||
@@ -442,31 +454,27 @@ function createiCalStr($datetime, $title, $description, $location) {
|
|||||||
return $cal_event->export();
|
return $cal_event->export();
|
||||||
}
|
}
|
||||||
|
|
||||||
function createiCalStrCancel($originaliCalStr) {
|
function createiCalStrCancel($datetime, $title, $uid) {
|
||||||
require_once "../libs/zapcal/zapcallib.php";
|
require_once "../libs/zapcal/zapcallib.php";
|
||||||
|
|
||||||
// Import the original iCal string
|
// Build the cancellation fresh. There is no stored copy of the original
|
||||||
$cal_event = new ZCiCal($originaliCalStr);
|
// invite to reopen - the match is made by UID, not by the body.
|
||||||
|
$cal_event = new ZCiCal();
|
||||||
|
|
||||||
// Iterate through the iCalendar object to find VEVENT nodes
|
// METHOD belongs on the VCALENDAR, not on the VEVENT
|
||||||
foreach($cal_event->tree->child as $node) {
|
$cal_event->tree->data['METHOD'] = new ZCiCalDataNode("METHOD:CANCEL");
|
||||||
if($node->getName() == "VEVENT") {
|
|
||||||
// Check if STATUS node exists, update it, or add a new one
|
$event = new ZCiCalNode("VEVENT", $cal_event->curnode);
|
||||||
$statusFound = false;
|
$event->addNode(new ZCiCalDataNode("UID:" . $uid));
|
||||||
foreach($node->data as $key => $value) {
|
$event->addNode(new ZCiCalDataNode("SUMMARY:" . $title));
|
||||||
if($key == "STATUS") {
|
if (!empty($datetime)) {
|
||||||
$value->setValue("CANCELLED");
|
$event->addNode(new ZCiCalDataNode("DTSTART:" . ZCiCal::fromSqlDateTime($datetime)));
|
||||||
$statusFound = true;
|
$event->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime($datetime)));
|
||||||
break; // Exit the loop once the STATUS is updated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If STATUS node is not found, add a new STATUS node
|
|
||||||
if (!$statusFound) {
|
|
||||||
$node->addNode(new ZCiCalDataNode("STATUS:CANCELLED"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$event->addNode(new ZCiCalDataNode("DTSTAMP:" . ZCiCal::fromSqlDateTime()));
|
||||||
|
// Must outrank the invite's SEQUENCE:0 or clients ignore the cancellation
|
||||||
|
$event->addNode(new ZCiCalDataNode("SEQUENCE:1"));
|
||||||
|
$event->addNode(new ZCiCalDataNode("STATUS:CANCELLED"));
|
||||||
|
|
||||||
// Return the modified iCal string
|
|
||||||
return $cal_event->export();
|
return $cal_event->export();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user