Complete workplace ticket interactions
This commit is contained in:
parent
21958eca15
commit
f118a777d3
@ -1,3 +1,5 @@
|
||||
import base64
|
||||
|
||||
from odoo import fields, http
|
||||
from odoo.http import request
|
||||
|
||||
@ -86,6 +88,7 @@ class McsCorporateWebsite(http.Controller):
|
||||
"status_key": ticket.state,
|
||||
"customer": ticket.partner_id.name or ticket.customer_name,
|
||||
"assigned_team": dict(ticket._fields["service_area"].selection).get(ticket.service_area),
|
||||
"assigned_agent": ticket.user_id.name or "",
|
||||
"created": ticket.create_date,
|
||||
"updated": ticket.write_date,
|
||||
"updated_label": fields.Datetime.to_string(ticket.write_date) if ticket.write_date else "",
|
||||
@ -286,6 +289,41 @@ class McsCorporateWebsite(http.Controller):
|
||||
messages = ticket.message_ids.sorted(lambda item: item.date)
|
||||
return self._workplace_render("mcs_corporate_website.workplace_ticket_detail", {"ticket": ticket, "messages": messages})
|
||||
|
||||
@http.route(["/workplace/tickets/<int:ticket_id>/reply"], type="http", auth="user", website=True, methods=["POST"])
|
||||
def workplace_ticket_reply(self, ticket_id, **post):
|
||||
role = self._role()
|
||||
ticket = request.env["mcs.support.ticket"].sudo().search(self._ticket_domain(role) + [("id", "=", ticket_id)], limit=1)
|
||||
if not ticket:
|
||||
return request.not_found()
|
||||
body = (post.get("reply") or "").strip()
|
||||
attachments = self._attach_uploaded_files(ticket)
|
||||
if body or attachments:
|
||||
ticket.message_post(
|
||||
body=body or "Attachment added.",
|
||||
attachment_ids=attachments.ids,
|
||||
message_type="comment",
|
||||
subtype_xmlid="mail.mt_comment",
|
||||
)
|
||||
return request.redirect("/workplace/tickets/%s" % ticket.id)
|
||||
|
||||
@http.route(["/workplace/tickets/<int:ticket_id>/close"], type="http", auth="user", website=True, methods=["POST"])
|
||||
def workplace_ticket_close(self, ticket_id, **post):
|
||||
role = self._role()
|
||||
ticket = request.env["mcs.support.ticket"].sudo().search(self._ticket_domain(role) + [("id", "=", ticket_id)], limit=1)
|
||||
if not ticket:
|
||||
return request.not_found()
|
||||
ticket.action_close()
|
||||
return request.redirect("/workplace/tickets/%s" % ticket.id)
|
||||
|
||||
@http.route(["/workplace/tickets/<int:ticket_id>/reopen"], type="http", auth="user", website=True, methods=["POST"])
|
||||
def workplace_ticket_reopen(self, ticket_id, **post):
|
||||
role = self._role()
|
||||
ticket = request.env["mcs.support.ticket"].sudo().search(self._ticket_domain(role) + [("id", "=", ticket_id)], limit=1)
|
||||
if not ticket:
|
||||
return request.not_found()
|
||||
ticket.action_reopen()
|
||||
return request.redirect("/workplace/tickets/%s" % ticket.id)
|
||||
|
||||
@http.route(["/workplace/knowledge"], type="http", auth="user", website=True)
|
||||
def workplace_knowledge(self, **kwargs):
|
||||
return self._workplace_render("mcs_corporate_website.workplace_knowledge", {"articles": self._knowledge(self._role())})
|
||||
@ -311,8 +349,26 @@ class McsCorporateWebsite(http.Controller):
|
||||
"description": (post.get("description") or "").strip(),
|
||||
}
|
||||
)
|
||||
self._attach_uploaded_files(ticket)
|
||||
return request.redirect("/support/thanks/%s" % ticket.access_token)
|
||||
|
||||
def _attach_uploaded_files(self, ticket):
|
||||
Attachment = request.env["ir.attachment"].sudo()
|
||||
attachments = Attachment.browse()
|
||||
for upload in request.httprequest.files.getlist("attachments"):
|
||||
if not upload or not upload.filename:
|
||||
continue
|
||||
attachments |= Attachment.create(
|
||||
{
|
||||
"name": upload.filename,
|
||||
"datas": base64.b64encode(upload.stream.read()),
|
||||
"res_model": "mcs.support.ticket",
|
||||
"res_id": ticket.id,
|
||||
"mimetype": upload.mimetype,
|
||||
}
|
||||
)
|
||||
return attachments
|
||||
|
||||
@http.route(["/support/thanks/<string:token>"], type="http", auth="public", website=True)
|
||||
def support_thanks(self, token, **kwargs):
|
||||
ticket = request.env["mcs.support.ticket"].sudo().search([("access_token", "=", token)], limit=1)
|
||||
|
||||
@ -15,6 +15,7 @@ class McsSupportTicket(models.Model):
|
||||
customer_email = fields.Char(required=True)
|
||||
customer_phone = fields.Char()
|
||||
partner_id = fields.Many2one("res.partner", string="Customer", tracking=True)
|
||||
user_id = fields.Many2one("res.users", string="Assigned Agent", tracking=True)
|
||||
company_id = fields.Many2one(
|
||||
"res.company",
|
||||
default=lambda self: self.env.company,
|
||||
@ -95,3 +96,6 @@ class McsSupportTicket(models.Model):
|
||||
|
||||
def action_close(self):
|
||||
self.write({"state": "closed"})
|
||||
|
||||
def action_reopen(self):
|
||||
self.write({"state": "in_progress"})
|
||||
|
||||
@ -671,6 +671,11 @@
|
||||
box-shadow: 0 10px 24px rgba(28, 78, 216, 0.2);
|
||||
}
|
||||
|
||||
.mcs-wp-btn--secondary {
|
||||
background: #334155;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.mcs-table-wrap {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
@ -796,6 +801,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.mcs-upload {
|
||||
border: 1px dashed #B8C1D1;
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
background: #F8FAFC;
|
||||
|
||||
span {
|
||||
color: var(--text-secondary);
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.mcs-search {
|
||||
width: min(420px, 100%);
|
||||
border: 1px solid var(--border);
|
||||
@ -803,6 +820,80 @@
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
body:has(form[action="/web/login"]) {
|
||||
background: #F6F7F9;
|
||||
|
||||
#wrapwrap {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
linear-gradient(90deg, #101114 0%, #101114 48%, #F6F7F9 48%, #F6F7F9 100%);
|
||||
}
|
||||
|
||||
main {
|
||||
min-height: calc(100vh - 76px);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 48px 24px;
|
||||
}
|
||||
|
||||
main::before {
|
||||
content: "Your workplace. Connected.\\A Attendance, support and collaboration in one place.";
|
||||
white-space: pre-line;
|
||||
position: fixed;
|
||||
left: 8vw;
|
||||
top: 38vh;
|
||||
max-width: 440px;
|
||||
color: #fff;
|
||||
font-size: 3.1rem;
|
||||
line-height: 1.05;
|
||||
font-weight: 820;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
form[action="/web/login"] {
|
||||
width: min(430px, 100%);
|
||||
margin-left: 42vw;
|
||||
padding: 34px;
|
||||
border: 1px solid #E6E8EC;
|
||||
border-radius: 14px;
|
||||
background: #fff;
|
||||
box-shadow: 0 24px 70px rgba(17, 24, 39, 0.14);
|
||||
|
||||
.form-control {
|
||||
min-height: 46px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
width: 100%;
|
||||
min-height: 46px;
|
||||
border-radius: 10px;
|
||||
background: #1C4ED8;
|
||||
border-color: #1C4ED8;
|
||||
font-weight: 800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
body:has(form[action="/web/login"]) {
|
||||
#wrapwrap {
|
||||
background: #F6F7F9;
|
||||
}
|
||||
|
||||
main::before {
|
||||
position: static;
|
||||
color: #17181B;
|
||||
font-size: 2.2rem;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
form[action="/web/login"] {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mcs-timeline {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
<field name="customer_email"/>
|
||||
<field name="customer_phone"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="user_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="service_area"/>
|
||||
@ -66,6 +67,7 @@
|
||||
<field name="subject"/>
|
||||
<field name="customer_name"/>
|
||||
<field name="customer_email"/>
|
||||
<field name="user_id"/>
|
||||
<filter string="Open" name="open" domain="[('state', 'not in', ['resolved', 'closed'])]"/>
|
||||
<filter string="Urgent" name="urgent" domain="[('priority', '=', '2')]"/>
|
||||
<group expand="0" string="Group By">
|
||||
|
||||
@ -196,7 +196,7 @@
|
||||
<label>Description<textarea name="description" required="required"/></label>
|
||||
<label>Contact Person<input name="customer_name" t-att-value="wp_user.name" required="required"/></label>
|
||||
<label>Email<input type="email" name="customer_email" t-att-value="wp_user.email" required="required"/></label>
|
||||
<label>Attachments<input type="file" name="attachments" multiple="multiple"/></label>
|
||||
<label class="mcs-upload">Attachments<input type="file" name="attachments" multiple="multiple"/><span>Drop files here or choose attachments</span></label>
|
||||
<button class="mcs-wp-btn" type="submit">Create Ticket</button>
|
||||
</form>
|
||||
<aside class="mcs-wp-card"><h2>Support hours</h2><p>Standard support requests are reviewed during business hours. Urgent production issues should include affected system, business impact, and escalation contact.</p><div class="mcs-list-row"><span>Expected response</span><strong>1 business day</strong></div><div class="mcs-list-row"><span>Emergency</span><strong>Mark Urgent</strong></div></aside>
|
||||
@ -208,8 +208,8 @@
|
||||
<t t-call="mcs_corporate_website.workplace_layout">
|
||||
<section class="mcs-wp-page-head"><div><p t-esc="ticket.name"/><h1 t-esc="ticket.subject"/></div><span class="mcs-status" t-esc="ticket.state"/></section>
|
||||
<section class="mcs-wp-two">
|
||||
<article class="mcs-wp-card"><div class="mcs-card-head"><h2>Conversation</h2></div><div class="mcs-timeline"><div class="mcs-message"><strong t-esc="ticket.customer_name"/><p t-esc="ticket.description"/></div><t t-foreach="messages" t-as="message"><div class="mcs-message mcs-message--support"><strong t-esc="message.author_id.name"/><p t-out="message.body"/></div></t></div><form class="mcs-reply"><textarea placeholder="Write a reply"/><button class="mcs-wp-btn" type="button">Send Reply</button></form></article>
|
||||
<aside class="mcs-wp-card"><h2>Ticket details</h2><div class="mcs-list-row"><span>Status</span><strong t-esc="ticket.state"/></div><div class="mcs-list-row"><span>Priority</span><strong t-esc="ticket.priority"/></div><div class="mcs-list-row"><span>Assigned Team</span><strong t-esc="ticket.service_area"/></div><div class="mcs-list-row"><span>Created</span><strong><span t-field="ticket.create_date"/></strong></div></aside>
|
||||
<article class="mcs-wp-card"><div class="mcs-card-head"><h2>Conversation</h2></div><div class="mcs-timeline"><div class="mcs-message"><strong t-esc="ticket.customer_name"/><p t-esc="ticket.description"/></div><t t-foreach="messages" t-as="message"><div class="mcs-message mcs-message--support"><strong t-esc="message.author_id.name"/><p t-out="message.body"/></div></t></div><form t-att-action="'/workplace/tickets/%s/reply' % ticket.id" method="post" enctype="multipart/form-data" class="mcs-reply"><input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/><textarea name="reply" placeholder="Write a reply"/><input type="file" name="attachments" multiple="multiple"/><button class="mcs-wp-btn" type="submit">Send Reply</button></form></article>
|
||||
<aside class="mcs-wp-card"><h2>Ticket details</h2><div class="mcs-list-row"><span>Status</span><strong t-esc="ticket.state"/></div><div class="mcs-list-row"><span>Priority</span><strong t-esc="ticket.priority"/></div><div class="mcs-list-row"><span>Assigned Team</span><strong t-esc="ticket.service_area"/></div><div class="mcs-list-row"><span>Assigned Agent</span><strong t-esc="ticket.user_id.name or '-'"/></div><div class="mcs-list-row"><span>Created</span><strong><span t-field="ticket.create_date"/></strong></div><form t-att-action="'/workplace/tickets/%s/close' % ticket.id" method="post"><input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/><button class="mcs-wp-btn" type="submit">Close Ticket</button></form><form t-att-action="'/workplace/tickets/%s/reopen' % ticket.id" method="post" class="mt-2"><input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/><button class="mcs-wp-btn mcs-wp-btn--secondary" type="submit">Reopen Ticket</button></form></aside>
|
||||
</section>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user