06/09 Allow customer to reply admin answer

This commit is contained in:
2026-06-09 16:50:44 -04:00
parent 46af7ec19b
commit f69ad4f805
2 changed files with 78 additions and 2 deletions
+54 -1
View File
@@ -182,7 +182,7 @@ def my_tickets():
# ── Customer: ticket detail ───────────────────────────────────────────────────
@bp.route('/my-tickets/<int:ticket_id>')
@bp.route('/my-tickets/<int:ticket_id>', methods=['GET', 'POST'])
@login_required
def my_ticket_detail(ticket_id):
if current_user.role != 'customer':
@@ -192,6 +192,36 @@ def my_ticket_detail(ticket_id):
if ticket is None or ticket.customer_id != current_user.id:
abort(404)
if request.method == 'POST':
if ticket.status == 'closed':
flash('This ticket is closed and cannot receive new replies.', 'warning')
return redirect(url_for('support.my_ticket_detail', ticket_id=ticket_id))
body = request.form.get('body', '').strip()
if not body:
flash('Reply cannot be empty.', 'warning')
return redirect(url_for('support.my_ticket_detail', ticket_id=ticket_id))
reply = SupportTicketReply(
ticket_id = ticket.id,
user_id = current_user.id,
body = body,
created_at = now_eastern(),
)
db.session.add(reply)
# Reopen if it was answered so admin sees there's a follow-up
if ticket.status == 'answered':
ticket.status = 'open'
db.session.commit()
log_action(ACTION_CREATE, 'SupportTicketReply', reply.id,
f'ticket #{ticket.id}',
f'customer reply by {current_user.username}')
_notify_admins_customer_reply(ticket, reply)
flash('Your reply has been sent.', 'success')
return redirect(url_for('support.my_ticket_detail', ticket_id=ticket_id))
replies = ticket.replies.order_by(SupportTicketReply.created_at.asc()).all()
return render_template('support/my_ticket_detail.html',
ticket=ticket, replies=replies)
@@ -316,3 +346,26 @@ def _notify_customer_reply(ticket, reply):
send_email = True,
)
db.session.commit()
def _notify_admins_customer_reply(ticket, reply):
"""Notify admins when a customer adds a follow-up reply to their ticket."""
admins = User.query.filter_by(role='admin', active=True).all()
if not admins:
return
customer_label = ticket.customer.display_name if ticket.customer else 'Unknown'
link = url_for('support.admin_ticket_detail', ticket_id=ticket.id)
title = f'Customer reply on ticket #{ticket.id} from {customer_label}'
body = (f'Re: {ticket.subject}\n\n'
f'{reply.body[:400]}{"" if len(reply.body) > 400 else ""}')
for admin in admins:
notify(
recipient = admin,
title = title,
body = body,
link = link,
send_email = True,
)
db.session.commit()
+24 -1
View File
@@ -60,7 +60,30 @@
</div>
{% endif %}
<div class="text-center mt-2">
{% if ticket.status != 'closed' %}
<div class="card shadow-sm mt-3">
<div class="card-header"><i class="bi bi-reply me-2"></i>Add a Follow-up</div>
<div class="card-body">
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="mb-3">
<textarea name="body" class="form-control" rows="4" required
placeholder="Type your follow-up message…"></textarea>
</div>
<button type="submit" class="btn btn-primary btn-sm">
<i class="bi bi-send me-1"></i>Send Reply
</button>
</form>
</div>
</div>
{% else %}
<div class="alert alert-secondary mt-3">
<i class="bi bi-lock me-2"></i>This request is closed.
<a href="{{ url_for('support.chat') }}">Start a new chat</a> if you need further help.
</div>
{% endif %}
<div class="text-center mt-3">
<a href="{{ url_for('support.chat') }}" class="btn btn-outline-primary btn-sm">
<i class="bi bi-chat-dots me-1"></i>Ask another question
</a>