Skip to content
Open
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
43 changes: 42 additions & 1 deletion desk/src/pages/ticket/TicketNew.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
<div
class="flex flex-col gap-5 py-6 h-full flex-1 self-center overflow-auto mx-auto w-full max-w-4xl px-5"
>
<div v-if="afterHoursSettings.data?.outside_working_hours_message && !isDismissed"
class="form-message border-bottom yellow max-w-4xl rounded bg-yellow-100 flex py-1.5 px-2 justify-between items-center"
>
<p
class="text-sm text-yellow-800 px-2.5 py-2">
{{ afterHoursSettings.data.outside_working_hours_message }}
</p>
<Button icon="x" @click="dismissBanner" class="bg-yellow-100 hover:bg-yellow-200 text-yellow-800" />
</div>
<!-- custom fields descriptions -->
<div v-if="Boolean(template.data?.about)" class="">
<div class="prose-f" v-html="sanitize(template.data.about)" />
Expand Down Expand Up @@ -154,11 +163,11 @@ const router = useRouter();
const { $dialog } = globalStore();
const { updateOnboardingStep } = useOnboarding("helpdesk");
const { isManager, userId: userID } = useAuthStore();

const subject = ref("");
const description = ref("");
const attachments = ref([]);
const templateFields = reactive({});
const isDismissed = ref(false);

const template = createResource({
url: "helpdesk.helpdesk.doctype.hd_ticket_template.api.get_one",
Expand Down Expand Up @@ -266,6 +275,12 @@ const ticket = createResource({
},
});

const afterHoursSettings = createResource({
url: "helpdesk.helpdesk.doctype.hd_ticket_template.api.get_customer_portal_settings",
cache: "afterHoursWarning",
auto: true,
});

function sanitize(html: string) {
return sanitizeHtml(html, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
Expand Down Expand Up @@ -301,4 +316,30 @@ onMounted(() => {
},
});
});


function getTodayKey() {
return new Date().toISOString().split("T")[0];
}

function dismissBanner() {
try {
const todayKey = getTodayKey();
localStorage.setItem(`dismiss_banner_${todayKey}`, "true");
isDismissed.value = true;
} catch (error) {
console.error("Error saving banner dismissal:", error);
}
}

onMounted(() => {
try {
const todayKey = getTodayKey();
const dismissed = localStorage.getItem(`dismiss_banner_${todayKey}`);
isDismissed.value = dismissed === "true";
} catch (error) {
console.error("Error reading banner dismissal:", error);
}
});

</script>
30 changes: 29 additions & 1 deletion helpdesk/helpdesk/doctype/hd_settings/hd_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
"default_ticket_status",
"column_break_yfbu",
"ticket_reopen_status",
"working_hours_section",
"working_hours_notification",
"column_break_working_hours",
"set_outside_working_hours_message",
"workflow_tab",
"skip_email_workflow",
"instantly_send_email",
Expand Down Expand Up @@ -441,6 +445,22 @@
"options": "HD Ticket Status",
"reqd": 1
},
{
"fieldname": "working_hours_section",
"fieldtype": "Section Break",
"label": "Outside Working Hours Settings"
},
{
"default": "0",
"description": "Let customers know they're raising a ticket outside working hours, and when they can expect a reply.",
"fieldname": "working_hours_notification",
"fieldtype": "Check",
"label": "Show Message Outside Working Hours"
},
{
"fieldname": "column_break_working_hours",
"fieldtype": "Column Break"
},
{
"depends_on": "auto_close_tickets",
"fieldname": "auto_close_status",
Expand All @@ -449,12 +469,20 @@
"link_filters": "[[\"HD Ticket Status\",\"category\",\"in\",[\"Paused\",\"Resolved\",null]]]",
"mandatory_depends_on": "eval: doc.auto_close_tickets",
"options": "HD Ticket Status"
},
{
"depends_on": "working_hours_notification",
"description": "By default the following message is displayed \u201cYour ticket is outside office hours. For non-critical issues, expect a response by Monday.\u201d",
"fieldname": "set_outside_working_hours_message",
"fieldtype": "Small Text",
"label": "Set Outside Working Hours Message",
"placeholder": "Add your custom message here"
}
],
"grid_page_length": 50,
"issingle": 1,
"links": [],
"modified": "2025-08-29 13:34:17.018321",
"modified": "2025-10-29 21:05:04.116492",
"modified_by": "Administrator",
"module": "Helpdesk",
"name": "HD Settings",
Expand Down
14 changes: 14 additions & 0 deletions helpdesk/helpdesk/doctype/hd_ticket_template/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from pypika import JoinType

from helpdesk.helpdesk.doctype.hd_form_script.hd_form_script import get_form_script
from helpdesk.utils import (
is_outside_working_hours
)
from helpdesk.utils import check_permissions

DOCTYPE_TEMPLATE = "HD Ticket Template"
Expand All @@ -32,6 +35,17 @@ def get_one(name: str):
"HD Ticket", apply_on_new_page=True, is_customer_portal=False
),
}

@frappe.whitelist()
def get_customer_portal_settings():
settings = frappe.get_single("HD Settings")
show_message = bool(settings.working_hours_notification)
msg_content=settings.set_outside_working_hours_message
message = msg_content or "Your ticket is outside office hours, unless it is a critical issue, you will get a response by Monday"
outside_hours = is_outside_working_hours()
return {
"outside_working_hours_message": message if show_message and outside_hours else "",
}


def get_fields_meta(template: str):
Expand Down
59 changes: 59 additions & 0 deletions helpdesk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from frappe.model.document import Document
from frappe.query_builder import Order
from frappe.realtime import get_website_room
from frappe.utils import now_datetime,get_time
from frappe.utils import floor
from frappe.utils.safe_exec import get_safe_globals
from frappe.utils.telemetry import capture as _capture
Expand Down Expand Up @@ -187,6 +188,64 @@ def get_agents_team():
return teams


def is_outside_working_hours():
"""Return True if current time is outside SLA or Helpdesk working hours."""

current_time = now_datetime()
current_weekday = current_time.weekday()

day_map = {
0: "Monday",
1: "Tuesday",
2: "Wednesday",
3: "Thursday",
4: "Friday",
5: "Saturday",
6: "Sunday",
}

current_day_name = day_map[current_weekday]
sla_doc = frappe.db.get_value(
"HD Service Level Agreement", {"default_sla": 1}, "name"
)

if sla_doc:
sla = frappe.get_doc("HD Service Level Agreement", sla_doc)
working_hours = sla.get_working_hours()

if current_day_name not in working_hours:
return True

start_time, end_time = working_hours[current_day_name]

start_dt = current_time.replace(
hour=start_time.seconds // 3600,
minute=(start_time.seconds // 60) % 60,
second=0,
microsecond=0,
)
end_dt = current_time.replace(
hour=end_time.seconds // 3600,
minute=(end_time.seconds // 60) % 60,
second=0,
microsecond=0,
)

if not (start_dt <= current_time < end_dt):
return True

return False

# Default Sat and Sun
if current_weekday in [5, 6]:
return True

if not (9 <= current_time.hour < 18):
return True

return False


contact_default_columns = [
{
"label": "Name",
Expand Down