Skip to content
Merged
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
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@ All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## 0.6.8 — 2026-11-02

A minor addition: a way to write or clear a ticket's take-into-account stamp,
through the legacy v1 API. GLPI stamps the date on the first write by an
account allowed to take a ticket into account, so a connector that writes to a
ticket it has just created leaves a time-to-own of nearly zero. The v2 `Ticket`
schema exposes the date as read-only and ignores `_do_not_compute_takeintoaccount`.
Both helpers need `v1_base_url` / `v1_user_token` and raise `RuntimeError`
without them. Existing methods are unchanged.

### Added

- **`change_ticket_take_into_account(ticket_id, *, take_into_account_date,
take_into_account_duration, do_not_compute=True, disable_notifications=True)`**
on both clients. It writes the ticket's take-into-account date (an aware
value is converted to `server_timezone`) and its duration in seconds. GLPI
writes a null date whenever the duration is 0. `do_not_compute` sends
`_do_not_compute_takeintoaccount` and `disable_notifications` sends
`_disablenotif`; a `False` flag is left out of the request, because GLPI
tests `_disablenotif` for presence. A refused write raises
`GlpiProtocolError`.
- **`clear_ticket_take_into_account(ticket_id, *, do_not_compute=True,
disable_notifications=True)`** on both clients: the change above with a null
date and a 0 duration.

## 0.6.7 — 2026-10-30

A minor addition: group recursion and a user's profile/entity authorizations,
Expand Down
39 changes: 39 additions & 0 deletions docs/user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,45 @@ worked.
rows = await client.list_user_authorizations(2568)
await client.update_user_authorization(rows[0].id, entity_id=493, recursive=True)

Writing the take-into-account stamp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

GLPI stamps ``take_into_account_date`` on a ticket the first time an account
allowed to take it into account writes to it, which makes the time-to-own
statistic nearly zero for a ticket a connector has just created. The v2
``Ticket`` schema exposes the date as read-only and ignores the
``_do_not_compute_takeintoaccount`` flag, so both helpers below go through the
legacy v1 session (``v1_base_url`` and ``v1_user_token``); without one they
raise ``RuntimeError``, and a refused write raises ``GlpiProtocolError``.

* ``change_ticket_take_into_account(ticket_id, *, take_into_account_date,
take_into_account_duration, do_not_compute=True, disable_notifications=True)``
writes the date (an aware value is converted to ``server_timezone``, a
naive one is taken as already on it) and the duration in seconds. GLPI
writes a null date whenever the duration is 0.
* ``clear_ticket_take_into_account(ticket_id, *, do_not_compute=True,
disable_notifications=True)`` is that change with a null date and a 0
duration.

``do_not_compute`` sends ``_do_not_compute_takeintoaccount``, which keeps GLPI
from stamping the ticket again in the same write; with it off, a clear made
by an account allowed to take the ticket into account is undone at once.
``disable_notifications`` sends ``_disablenotif``, which suppresses the
"ticket updated" notification. GLPI tests ``_disablenotif`` for presence, so a
``False`` flag is left out of the request rather than sent as ``false``. Read
the result back with ``get_ticket`` (``take_into_account_date`` and
``take_into_account_duration``).

.. code-block:: python

await client.clear_ticket_take_into_account(321)
await client.change_ticket_take_into_account(
321,
take_into_account_date=datetime(2026, 11, 2, 9, 30, tzinfo=UTC),
take_into_account_duration=600,
disable_notifications=False,
)

Documents linked to a followup
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
2 changes: 1 addition & 1 deletion glpi_python_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
date_window,
)

__version__ = "0.6.7"
__version__ = "0.6.8"

__all__ = [
"AsyncGlpiClient",
Expand Down
132 changes: 132 additions & 0 deletions glpi_python_client/_async/clients/api/assistance/_ticket.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
from __future__ import annotations

from collections.abc import AsyncIterator
from datetime import datetime

from glpi_python_client._async.clients.commons._constants import TICKET_ENDPOINT, GlpiId
from glpi_python_client._async.clients.commons._payloads import (
ensure_v1_write_accepted,
)
from glpi_python_client._async.clients.commons._transport import TransportMixin
from glpi_python_client.models.api_schema.assistance._ticket import (
DeleteTicket,
Expand All @@ -17,6 +21,8 @@
PostTicket,
)

_V1_TICKET_FEATURE_LABEL = "take-into-account writes"


class TicketMixin(TransportMixin):
"""CRUD helpers for ``/Assistance/Ticket``.
Expand Down Expand Up @@ -240,5 +246,131 @@ async def delete_ticket(
delete_model_cls=DeleteTicket,
)

async def change_ticket_take_into_account(
self,
ticket_id: GlpiId,
*,
take_into_account_date: datetime | None,
take_into_account_duration: int,
do_not_compute: bool = True,
disable_notifications: bool = True,
) -> None:
"""Write the take-into-account stamp of one ticket.

GLPI stamps ``take_into_account_date`` on the first write made by an
account allowed to take a ticket into account (and when a group is
assigned). The v2 ``Ticket`` schema exposes the date as read-only and
silently ignores ``_do_not_compute_takeintoaccount``, so the write
goes through the legacy v1 API, which requires
``v1_base_url``/``v1_user_token`` to be configured (pointing at the
legacy ``apirest.php``). GLPI records the change in the ticket
history either way.

Parameters
----------
ticket_id : int | str
Identifier of the ticket.
take_into_account_date : datetime | None
New take-into-account instant (v1 ``takeintoaccountdate``), or
``None`` for no stamp. An aware value is converted to the
server's clock; a naive one is taken to be on it already. GLPI
writes ``null`` instead whenever the duration is ``0``.
take_into_account_duration : int
Seconds from creation to the take-into-account (v1
``takeintoaccount_delay_stat``). GLPI treats ``0`` as "not taken
into account".
do_not_compute : bool, optional
``True`` (the default) sends ``_do_not_compute_takeintoaccount``
so GLPI keeps the values written. With ``False`` and a zero
duration, an account allowed to take the ticket into account
stamps it again with the current time in the same write.
disable_notifications : bool, optional
``True`` (the default) sends ``_disablenotif``, which suppresses
the "ticket updated" notification.

Raises
------
RuntimeError
When no legacy v1 session is configured on the client.
GlpiStatusError
When the legacy API returns a non-success status.
GlpiProtocolError
When the legacy API answers that the update was refused.
"""

v1 = self._require_v1_session(_V1_TICKET_FEATURE_LABEL)
stamp: str | None = None
if take_into_account_date is not None:
if take_into_account_date.tzinfo is not None:
take_into_account_date = take_into_account_date.astimezone(
self.server_timezone
)
stamp = take_into_account_date.strftime("%Y-%m-%d %H:%M:%S")
update: dict[str, object] = {
"id": int(ticket_id),
"takeintoaccountdate": stamp,
"takeintoaccount_delay_stat": take_into_account_duration,
}
# GLPI reads ``_disablenotif`` with isset(), so a False flag must be absent.
if do_not_compute:
update["_do_not_compute_takeintoaccount"] = True
if disable_notifications:
update["_disablenotif"] = True
payload = await v1.request_json(
"PUT",
f"Ticket/{ticket_id}",
json_body={"input": update},
failure_message=(
f"Failed to write the take-into-account stamp of ticket {ticket_id}"
),
)
ensure_v1_write_accepted(
payload, f"Writing the take-into-account stamp of ticket {ticket_id}"
)

async def clear_ticket_take_into_account(
self,
ticket_id: GlpiId,
*,
do_not_compute: bool = True,
disable_notifications: bool = True,
) -> None:
"""Clear the take-into-account stamp of one ticket.

The stamp collapses the time-to-own statistic to nearly zero for a
ticket a connector has just created and written to. This is
:meth:`change_ticket_take_into_account` with a ``None`` date and a
``0`` duration, so it has the same v1 requirement.

Parameters
----------
ticket_id : int | str
Identifier of the ticket.
do_not_compute : bool, optional
``True`` (the default) keeps GLPI from stamping the ticket again
in the same write. ``False`` lets an account allowed to take the
ticket into account undo the clear at once.
disable_notifications : bool, optional
``True`` (the default) suppresses the "ticket updated"
notification.

Raises
------
RuntimeError
When no legacy v1 session is configured on the client.
GlpiStatusError
When the legacy API returns a non-success status.
GlpiProtocolError
When the legacy API answers that the update was refused.
"""

await self.change_ticket_take_into_account(
ticket_id,
take_into_account_date=None,
take_into_account_duration=0,
do_not_compute=do_not_compute,
disable_notifications=disable_notifications,
)


__all__ = ["TicketMixin"]
Loading
Loading