Persist status-change comments transactionally with the update (#37)

A comment accompanying a status change (required or user-supplied) was
posted via a separate, independent HTTP call/write (add_comment.php,
or a second add_comment call in lt.ticketStatus.submit()'s
requires_comment retry path) before the status update itself. A failure
partway through — or the client never issuing the second call — could
leave a "reason" comment persisted with no matching status change, or
vice versa, with no rollback tying the two together.

api/update_ticket.php and api/ticket_status_api.php now post the comment
and apply the status update inside one transaction, rolling back both on
any failure. assets/js/ticket.js and lt.ticketStatus.submit() in
assets/js/base.js no longer make a separate add_comment.php call; they
pass the comment directly to update_ticket.php, which persists it
server-side alongside the status change.

Verified against real MariaDB by extracting the live ApiTicketController
and the ticket_status_api.php transaction logic and running them
directly: a forced optimistic-lock conflict correctly rolled back both
the comment and the status change, and a successful call persisted
exactly one comment alongside the status change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117oBw2jN4kALYeS8HPq4zV
This commit is contained in:
2026-09-11 21:41:48 -04:00
co-authored by Claude Sonnet 5
parent d205a9577a
commit 310dcd0840
4 changed files with 98 additions and 61 deletions
+8 -5
View File
@@ -2858,8 +2858,11 @@
TICKET STATUS CHANGE (comment-aware)
lt.ticketStatus.submit(ticketId, newStatus, { comment? }) → Promise<data>
Posts /api/update_ticket.php. If the server rejects with
requires_comment, opens a comment modal, persists the comment via
/api/add_comment.php, then retries the update once WITH the comment.
requires_comment, opens a comment modal, then retries the update once
WITH the comment — update_ticket.php persists it in the same DB
transaction as the status change itself, so there's no separate
add_comment.php call that could leave an orphaned comment if the
status update then failed.
Rejects with err.cancelled === true if the user cancels the modal.
================================================================ */
function _statusCommentModal(newStatus) {
@@ -2922,9 +2925,9 @@
cancelErr.cancelled = true;
throw cancelErr;
}
// Persist the comment, then retry the status change with it included.
return api.post('/api/add_comment.php', { ticket_id: id, comment_text: comment })
.then(() => api.post('/api/update_ticket.php', { ticket_id: id, status: newStatus, comment: comment }));
// Retry with the comment included — update_ticket.php persists it
// transactionally with the status update itself.
return api.post('/api/update_ticket.php', { ticket_id: id, status: newStatus, comment: comment });
});
});
},