mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-10-06 21:42:05 +00:00
Deduplicate 3CX forwarding payload and add shift type to pick command
Extract _update_forwarding helper in ThreeCXClient to share the payload between queue and ring group methods. Add optional day/night argument to /oncall pick so users can target a specific weekend shift.
This commit is contained in:
parent
0d119f494b
commit
c3b35ed62e
3 changed files with 49 additions and 81 deletions
|
|
@ -24,8 +24,8 @@ def update_queue_routing(
|
||||||
queue = client.get_queue(queue_number)
|
queue = client.get_queue(queue_number)
|
||||||
client.update_queue_forwarding(
|
client.update_queue_forwarding(
|
||||||
queue_id=queue["Id"],
|
queue_id=queue["Id"],
|
||||||
closed_destination=extension,
|
closed=extension,
|
||||||
holiday_destination=extension,
|
holiday=extension,
|
||||||
)
|
)
|
||||||
logger.info("Updated queue %s to forward to Ext %s", queue_number, extension)
|
logger.info("Updated queue %s to forward to Ext %s", queue_number, extension)
|
||||||
return {"extension": extension, "queue": queue_number}
|
return {"extension": extension, "queue": queue_number}
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,33 @@ class ThreeCXClient:
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
return resp.json().get("value", [])
|
return resp.json().get("value", [])
|
||||||
|
|
||||||
|
def _update_forwarding(
|
||||||
|
self, resource: str, resource_id: int, closed: str, holiday: str
|
||||||
|
):
|
||||||
|
payload = {
|
||||||
|
"OutOfOfficeRoute": {
|
||||||
|
"IsPromptEnabled": False,
|
||||||
|
"Route": {"To": "Extension", "Number": closed, "External": ""},
|
||||||
|
},
|
||||||
|
"HolidaysRoute": {
|
||||||
|
"IsPromptEnabled": False,
|
||||||
|
"Route": {"To": "Extension", "Number": holiday, "External": ""},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp = self.session.patch(
|
||||||
|
f"{self.base_url}/xapi/v1/{resource}({resource_id})",
|
||||||
|
json=payload,
|
||||||
|
)
|
||||||
|
resp.raise_for_status()
|
||||||
|
logger.info(
|
||||||
|
"Updated %s %s: closed->Ext %s, holiday->Ext %s",
|
||||||
|
resource,
|
||||||
|
resource_id,
|
||||||
|
closed,
|
||||||
|
holiday,
|
||||||
|
)
|
||||||
|
return resp.status_code
|
||||||
|
|
||||||
def get_ring_group(self, extension_number: str) -> dict:
|
def get_ring_group(self, extension_number: str) -> dict:
|
||||||
"""Fetch ring group config by extension number."""
|
"""Fetch ring group config by extension number."""
|
||||||
resp = self.session.get(
|
resp = self.session.get(
|
||||||
|
|
@ -93,42 +120,9 @@ class ThreeCXClient:
|
||||||
return resp.json()
|
return resp.json()
|
||||||
|
|
||||||
def update_ring_group_forwarding(
|
def update_ring_group_forwarding(
|
||||||
self,
|
self, ring_group_id: int, closed: str, holiday: str
|
||||||
ring_group_id: int,
|
|
||||||
closed_destination: str,
|
|
||||||
holiday_destination: str,
|
|
||||||
):
|
):
|
||||||
"""Update the OutOfOfficeRoute and HolidaysRoute on a ring group."""
|
return self._update_forwarding("RingGroups", ring_group_id, closed, holiday)
|
||||||
payload = {
|
|
||||||
"OutOfOfficeRoute": {
|
|
||||||
"IsPromptEnabled": False,
|
|
||||||
"Route": {
|
|
||||||
"To": "Extension",
|
|
||||||
"Number": closed_destination,
|
|
||||||
"External": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"HolidaysRoute": {
|
|
||||||
"IsPromptEnabled": False,
|
|
||||||
"Route": {
|
|
||||||
"To": "Extension",
|
|
||||||
"Number": holiday_destination,
|
|
||||||
"External": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resp = self.session.patch(
|
|
||||||
f"{self.base_url}/xapi/v1/RingGroups({ring_group_id})",
|
|
||||||
json=payload,
|
|
||||||
)
|
|
||||||
resp.raise_for_status()
|
|
||||||
logger.info(
|
|
||||||
"Updated ring group %s: closed->Ext %s, holiday->Ext %s",
|
|
||||||
ring_group_id,
|
|
||||||
closed_destination,
|
|
||||||
holiday_destination,
|
|
||||||
)
|
|
||||||
return resp.status_code
|
|
||||||
|
|
||||||
def get_queue(self, extension_number: str) -> dict:
|
def get_queue(self, extension_number: str) -> dict:
|
||||||
"""Fetch queue config by extension number."""
|
"""Fetch queue config by extension number."""
|
||||||
|
|
@ -138,40 +132,5 @@ class ThreeCXClient:
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
return resp.json()
|
return resp.json()
|
||||||
|
|
||||||
def update_queue_forwarding(
|
def update_queue_forwarding(self, queue_id: int, closed: str, holiday: str):
|
||||||
self,
|
return self._update_forwarding("Queues", queue_id, closed, holiday)
|
||||||
queue_id: int,
|
|
||||||
closed_destination: str,
|
|
||||||
holiday_destination: str,
|
|
||||||
):
|
|
||||||
"""Update the OutOfOfficeRoute and HolidaysRoute on a queue."""
|
|
||||||
payload = {
|
|
||||||
"OutOfOfficeRoute": {
|
|
||||||
"IsPromptEnabled": False,
|
|
||||||
"Route": {
|
|
||||||
"To": "Extension",
|
|
||||||
"Number": closed_destination,
|
|
||||||
"External": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"HolidaysRoute": {
|
|
||||||
"IsPromptEnabled": False,
|
|
||||||
"Route": {
|
|
||||||
"To": "Extension",
|
|
||||||
"Number": holiday_destination,
|
|
||||||
"External": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resp = self.session.patch(
|
|
||||||
f"{self.base_url}/xapi/v1/Queues({queue_id})",
|
|
||||||
json=payload,
|
|
||||||
)
|
|
||||||
resp.raise_for_status()
|
|
||||||
logger.info(
|
|
||||||
"Updated queue %s: closed->Ext %s, holiday->Ext %s",
|
|
||||||
queue_id,
|
|
||||||
closed_destination,
|
|
||||||
holiday_destination,
|
|
||||||
)
|
|
||||||
return resp.status_code
|
|
||||||
|
|
|
||||||
|
|
@ -377,9 +377,11 @@ def create_app(
|
||||||
respond(text=f"Linked your account to *{employee['name']}* (Ext {ext}).")
|
respond(text=f"Linked your account to *{employee['name']}* (Ext {ext}).")
|
||||||
|
|
||||||
def _handle_pick(respond, schedule, user_id, text, channel_id, client):
|
def _handle_pick(respond, schedule, user_id, text, channel_id, client):
|
||||||
parts = text.split(maxsplit=1)
|
parts = text.split()
|
||||||
if len(parts) < 2:
|
if len(parts) < 2:
|
||||||
respond(text="Usage: `/oncall pick <date>` (e.g. `/oncall pick friday`)")
|
respond(
|
||||||
|
text="Usage: `/oncall pick <date> [day|night]` (e.g. `/oncall pick friday`)"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
employee = schedule.get_employee_by_slack_id(user_id)
|
employee = schedule.get_employee_by_slack_id(user_id)
|
||||||
|
|
@ -389,10 +391,14 @@ def create_app(
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
date = parse_date(parts[1])
|
explicit_shift = (
|
||||||
|
parts[2] if len(parts) > 2 and parts[2] in ("day", "night") else None
|
||||||
|
)
|
||||||
|
date_text = parts[1]
|
||||||
|
date = parse_date(date_text)
|
||||||
if not date:
|
if not date:
|
||||||
respond(
|
respond(
|
||||||
text=f"Couldn't parse date: `{parts[1]}`. Try: today, tomorrow, friday, 4/5, 2026-04-05"
|
text=f"Couldn't parse date: `{date_text}`. Try: today, tomorrow, friday, 4/5, 2026-04-05"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -403,9 +409,11 @@ def create_app(
|
||||||
|
|
||||||
day_name = date.strftime("%A")
|
day_name = date.strftime("%A")
|
||||||
|
|
||||||
# On weekends, find the first available shift (day then night)
|
if explicit_shift:
|
||||||
shift_type = "night"
|
shift_type = explicit_shift
|
||||||
if day_name in WEEKEND_DAYS:
|
ext, name, source = schedule.resolve_shift(date_str, day_name, shift_type)
|
||||||
|
elif day_name in WEEKEND_DAYS:
|
||||||
|
shift_type = "night"
|
||||||
for st in ("day", "night"):
|
for st in ("day", "night"):
|
||||||
ext, name, source = schedule.resolve_shift(date_str, day_name, st)
|
ext, name, source = schedule.resolve_shift(date_str, day_name, st)
|
||||||
if source == "available":
|
if source == "available":
|
||||||
|
|
@ -414,6 +422,7 @@ def create_app(
|
||||||
else:
|
else:
|
||||||
ext, name, source = schedule.resolve_shift(date_str, day_name)
|
ext, name, source = schedule.resolve_shift(date_str, day_name)
|
||||||
else:
|
else:
|
||||||
|
shift_type = "night"
|
||||||
ext, name, source = schedule.resolve_shift(date_str, day_name)
|
ext, name, source = schedule.resolve_shift(date_str, day_name)
|
||||||
|
|
||||||
# Already assigned to someone else (not open)
|
# Already assigned to someone else (not open)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue