From f510a086bdea4d55b22455aebec534dd4886eed2 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Fri, 25 Sep 2026 22:05:22 +0200 Subject: [PATCH] feat(interventions): trace notes, documents and element links in full timeline - Add 'note', 'document', and 'link' event types to InterventionTimeLine - Record timeline events for note additions/edits/deletions (standalone and batch) - Record document uploads and deletions (desktop and mobile APIs) - Record asset linking/unlinking with friendly names and linked interventions - Display detailed items exclusively in the toggleable "Historique complet" view - Maintain shortname display for all event authors - Update and compile FR, EN and NL translation catalogs - Add comprehensive test coverage for all new timeline event records --- .../locale/en/LC_MESSAGES/django.mo | Bin 121073 -> 123206 bytes .../locale/en/LC_MESSAGES/django.po | 134 ++++++++ .../locale/fr/LC_MESSAGES/django.mo | Bin 136681 -> 138813 bytes .../locale/fr/LC_MESSAGES/django.po | 134 ++++++++ .../locale/nl/LC_MESSAGES/django.mo | Bin 126538 -> 128790 bytes .../locale/nl/LC_MESSAGES/django.po | 133 ++++++++ ...5_alter_interventiontimeline_event_type.py | 18 ++ loko/interventions/models.py | 21 ++ .../services/timeline_service.py | 289 ++++++++++++++++++ .../static/interventions/timeline.css | 15 +- .../detail/card_chronologie.html | 35 ++- .../interventions/detail/styles.html | 15 +- .../tests/test_timeline_history.py | 236 +++++++++++++- loko/interventions/views/detail.py | 40 ++- loko/interventions/views/helpers.py | 49 ++- loko/interventions/views/mobile.py | 15 + loko/interventions/views/notes_docs.py | 57 +++- 17 files changed, 1171 insertions(+), 20 deletions(-) create mode 100644 loko/interventions/migrations/0015_alter_interventiontimeline_event_type.py diff --git a/loko/interventions/locale/en/LC_MESSAGES/django.mo b/loko/interventions/locale/en/LC_MESSAGES/django.mo index 0e5c6107ff007525e093ad336460923f7f272c03..1dcf27f493a573b823f5c7d41ba758a17b4c8d56 100644 GIT binary patch delta 35446 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 mr_Q}P1-IhjoRl~zm*ceacbr(Q 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 delta 34348 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 diff --git a/loko/interventions/locale/fr/LC_MESSAGES/django.po b/loko/interventions/locale/fr/LC_MESSAGES/django.po index 8a2aa86..e5c7136 100644 --- a/loko/interventions/locale/fr/LC_MESSAGES/django.po +++ b/loko/interventions/locale/fr/LC_MESSAGES/django.po @@ -8347,3 +8347,137 @@ msgstr "Mise à jour de l'assignation" msgid "Champs modifiés : %(fields)s" msgstr "Champs modifiés : %(fields)s" +#: interventions/models.py:1259 +msgid "Lien" +msgstr "Lien" + +#: interventions/services/timeline_service.py:417 +#, python-format +msgid "Note ajoutée (%(type)s)" +msgstr "Note ajoutée (%(type)s)" + +#: interventions/services/timeline_service.py:418 +msgid "Ajout" +msgstr "Ajout" + +#: interventions/services/timeline_service.py:423 +#, python-format +msgid "Note modifiée (%(type)s)" +msgstr "Note modifiée (%(type)s)" + +#: interventions/services/timeline_service.py:433 +msgid "Mise à jour" +msgstr "Mise à jour" + +#: interventions/services/timeline_service.py:435 +#, python-format +msgid "Note supprimée (%(type)s)" +msgstr "Note supprimée (%(type)s)" + +#: interventions/services/timeline_service.py:436 +msgid "Suppression" +msgstr "Suppression" + +#: interventions/services/timeline_service.py:441 +#, python-format +msgid "Note : %(action)s" +msgstr "Note : %(action)s" + +#: interventions/services/timeline_service.py:465 +#, python-format +msgid "Document ajouté : %(name)s" +msgstr "Document ajouté : %(name)s" + +#: interventions/services/timeline_service.py:467 +#, python-format +msgid "%(count)d documents ajoutés : %(names)s" +msgstr "%(count)d documents ajoutés : %(names)s" + +#: interventions/services/timeline_service.py:472 +msgid "Document(s) ajouté(s)" +msgstr "Document(s) ajouté(s)" + +#: interventions/services/timeline_service.py:478 +#, python-format +msgid "Document supprimé : %(name)s" +msgstr "Document supprimé : %(name)s" + +#: interventions/services/timeline_service.py:480 +#, python-format +msgid "%(count)d documents supprimés : %(names)s" +msgstr "%(count)d documents supprimés : %(names)s" + +#: interventions/services/timeline_service.py:485 +msgid "Document(s) supprimé(s)" +msgstr "Document(s) supprimé(s)" + +#: interventions/services/timeline_service.py:490 +#, python-format +msgid "Document : %(action)s" +msgstr "Document : %(action)s" + +#: interventions/services/timeline_service.py:549 +#, python-format +msgid "Équipement lié : %(name)s" +msgstr "Équipement lié : %(name)s" + +#: interventions/services/timeline_service.py:551 +#, python-format +msgid "%(count)d équipements liés : %(names)s" +msgstr "%(count)d équipements liés : %(names)s" + +#: interventions/services/timeline_service.py:557 +#, python-format +msgid "Équipement délié : %(name)s" +msgstr "Équipement délié : %(name)s" + +#: interventions/services/timeline_service.py:559 +#, python-format +msgid "%(count)d équipements déliés : %(names)s" +msgstr "%(count)d équipements déliés : %(names)s" + +#: interventions/services/timeline_service.py:564 +#, python-format +msgid "Équipements modifiés (+%(added)d, -%(removed)d)" +msgstr "Équipements modifiés (+%(added)d, -%(removed)d)" + +#: interventions/services/timeline_service.py:570 +msgid "Équipement(s) lié(s)" +msgstr "Équipement(s) lié(s)" + +#: interventions/services/timeline_service.py:576 +msgid "Équipement(s) délié(s)" +msgstr "Équipement(s) délié(s)" + +#: interventions/services/timeline_service.py:603 +#, python-format +msgid "%(relation)s liée : %(target)s" +msgstr "%(relation)s liée : %(target)s" + +#: interventions/services/timeline_service.py:608 +#, python-format +msgid "%(count)d %(relation)ss liées : %(targets)s" +msgstr "%(count)d %(relation)ss liées : %(targets)s" + +#: interventions/services/timeline_service.py:614 +#, python-format +msgid "%(relation)s liée(s)" +msgstr "%(relation)s liée(s)" + +#: interventions/services/timeline_service.py:620 +#, python-format +msgid "%(relation)s déliée : %(target)s" +msgstr "%(relation)s déliée : %(target)s" + +#: interventions/services/timeline_service.py:625 +#, python-format +msgid "%(count)d %(relation)ss déliées : %(targets)s" +msgstr "%(count)d %(relation)ss déliées : %(targets)s" + +#: interventions/services/timeline_service.py:631 +#, python-format +msgid "%(relation)s déliée(s)" +msgstr "%(relation)s déliée(s)" + + + diff --git a/loko/interventions/locale/nl/LC_MESSAGES/django.mo b/loko/interventions/locale/nl/LC_MESSAGES/django.mo index 475ac13c19a9b1df361f0a11912705a592fd030f..3f33f2eee291babe544a769b79afe51ca305d149 100644 GIT binary patch delta 35632 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 Ba`ylL diff --git a/loko/interventions/locale/nl/LC_MESSAGES/django.po b/loko/interventions/locale/nl/LC_MESSAGES/django.po index 2263962..e52720a 100644 --- a/loko/interventions/locale/nl/LC_MESSAGES/django.po +++ b/loko/interventions/locale/nl/LC_MESSAGES/django.po @@ -8281,3 +8281,136 @@ msgstr "Toewijzing bijgewerkt" msgid "Champs modifiés : %(fields)s" msgstr "Gewijzigde velden: %(fields)s" +#: interventions/models.py:1259 +msgid "Lien" +msgstr "Koppeling" + +#: interventions/services/timeline_service.py:417 +#, python-format +msgid "Note ajoutée (%(type)s)" +msgstr "Notitie toegevoegd (%(type)s)" + +#: interventions/services/timeline_service.py:418 +msgid "Ajout" +msgstr "Toevoeging" + +#: interventions/services/timeline_service.py:423 +#, python-format +msgid "Note modifiée (%(type)s)" +msgstr "Notitie gewijzigd (%(type)s)" + +#: interventions/services/timeline_service.py:433 +msgid "Mise à jour" +msgstr "Bijwerking" + +#: interventions/services/timeline_service.py:435 +#, python-format +msgid "Note supprimée (%(type)s)" +msgstr "Notitie verwijderd (%(type)s)" + +#: interventions/services/timeline_service.py:436 +msgid "Suppression" +msgstr "Verwijdering" + +#: interventions/services/timeline_service.py:441 +#, python-format +msgid "Note : %(action)s" +msgstr "Notitie: %(action)s" + +#: interventions/services/timeline_service.py:465 +#, python-format +msgid "Document ajouté : %(name)s" +msgstr "Document toegevoegd: %(name)s" + +#: interventions/services/timeline_service.py:467 +#, python-format +msgid "%(count)d documents ajoutés : %(names)s" +msgstr "%(count)d documenten toegevoegd: %(names)s" + +#: interventions/services/timeline_service.py:472 +msgid "Document(s) ajouté(s)" +msgstr "Toegevoegd(e) document(en)" + +#: interventions/services/timeline_service.py:478 +#, python-format +msgid "Document supprimé : %(name)s" +msgstr "Document verwijderd: %(name)s" + +#: interventions/services/timeline_service.py:480 +#, python-format +msgid "%(count)d documents supprimés : %(names)s" +msgstr "%(count)d documenten verwijderd: %(names)s" + +#: interventions/services/timeline_service.py:485 +msgid "Document(s) supprimé(s)" +msgstr "Verwijderd(e) document(en)" + +#: interventions/services/timeline_service.py:490 +#, python-format +msgid "Document : %(action)s" +msgstr "Document: %(action)s" + +#: interventions/services/timeline_service.py:549 +#, python-format +msgid "Équipement lié : %(name)s" +msgstr "Apparaat gekoppeld: %(name)s" + +#: interventions/services/timeline_service.py:551 +#, python-format +msgid "%(count)d équipements liés : %(names)s" +msgstr "%(count)d apparaten gekoppeld: %(names)s" + +#: interventions/services/timeline_service.py:557 +#, python-format +msgid "Équipement délié : %(name)s" +msgstr "Apparaat ontkoppeld: %(name)s" + +#: interventions/services/timeline_service.py:559 +#, python-format +msgid "%(count)d équipements déliés : %(names)s" +msgstr "%(count)d apparaten ontkoppeld: %(names)s" + +#: interventions/services/timeline_service.py:564 +#, python-format +msgid "Équipements modifiés (+%(added)d, -%(removed)d)" +msgstr "Apparaten gewijzigd (+%(added)d, -%(removed)d)" + +#: interventions/services/timeline_service.py:570 +msgid "Équipement(s) lié(s)" +msgstr "Gekoppeld(e) appara(a)t(en)" + +#: interventions/services/timeline_service.py:576 +msgid "Équipement(s) délié(s)" +msgstr "Ontkoppeld(e) appara(a)t(en)" + +#: interventions/services/timeline_service.py:603 +#, python-format +msgid "%(relation)s liée : %(target)s" +msgstr "%(relation)s gekoppeld: %(target)s" + +#: interventions/services/timeline_service.py:608 +#, python-format +msgid "%(count)d %(relation)ss liées : %(targets)s" +msgstr "%(count)d %(relation)ss gekoppeld: %(targets)s" + +#: interventions/services/timeline_service.py:614 +#, python-format +msgid "%(relation)s liée(s)" +msgstr "Gekoppelde %(relation)s(s)" + +#: interventions/services/timeline_service.py:620 +#, python-format +msgid "%(relation)s déliée : %(target)s" +msgstr "%(relation)s ontkoppeld: %(target)s" + +#: interventions/services/timeline_service.py:625 +#, python-format +msgid "%(count)d %(relation)ss déliées : %(targets)s" +msgstr "%(count)d %(relation)ss ontkoppeld: %(targets)s" + +#: interventions/services/timeline_service.py:631 +#, python-format +msgid "%(relation)s déliée(s)" +msgstr "Ontkoppelde %(relation)s(s)" + + diff --git a/loko/interventions/migrations/0015_alter_interventiontimeline_event_type.py b/loko/interventions/migrations/0015_alter_interventiontimeline_event_type.py new file mode 100644 index 0000000..4018d8e --- /dev/null +++ b/loko/interventions/migrations/0015_alter_interventiontimeline_event_type.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.7 on 2026-09-25 19:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('interventions', '0014_interventiontimeline_event_description_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='interventiontimeline', + name='event_type', + field=models.CharField(choices=[('creation', 'Création'), ('status_change', 'Changement de statut'), ('transfer', 'Transfert'), ('assignment', 'Assignation'), ('modification', 'Modification'), ('note', 'Note'), ('document', 'Document'), ('link', 'Lien')]), + ), + ] diff --git a/loko/interventions/models.py b/loko/interventions/models.py index 6bb4156..47c4c3b 100644 --- a/loko/interventions/models.py +++ b/loko/interventions/models.py @@ -1254,6 +1254,9 @@ ACTION_TYPE_CHOICES = { 'transfer': _('Transfert'), 'assignment': _('Assignation'), 'modification': _('Modification'), + 'note': _('Note'), + 'document': _('Document'), + 'link': _('Lien'), } STATUS_COLOR_MAP = { @@ -1295,6 +1298,18 @@ class InterventionTimeLine(models.Model): def is_modification(self): return self.event_type == 'modification' + @property + def is_note(self): + return self.event_type == 'note' + + @property + def is_document(self): + return self.event_type == 'document' + + @property + def is_link(self): + return self.event_type == 'link' + @property def is_status_change(self): return self.event_type == 'status_change' @@ -1320,6 +1335,9 @@ class InterventionTimeLine(models.Model): 'assignment': 'bg-info text-dark', 'transfer': 'bg-warning text-dark', 'modification': 'bg-secondary', + 'note': 'bg-info text-dark', + 'document': 'bg-secondary', + 'link': 'bg-dark', }.get(self.event_type, 'bg-secondary') def get_icon(self): @@ -1329,6 +1347,9 @@ class InterventionTimeLine(models.Model): 'assignment': 'bi-person-check-fill', 'transfer': 'bi-arrow-left-right', 'modification': 'bi-pencil-fill', + 'note': 'bi-chat-left-text-fill', + 'document': 'bi-paperclip', + 'link': 'bi-link-45deg', }.get(self.event_type, 'bi-dot') diff --git a/loko/interventions/services/timeline_service.py b/loko/interventions/services/timeline_service.py index 9dafed7..7008b7e 100644 --- a/loko/interventions/services/timeline_service.py +++ b/loko/interventions/services/timeline_service.py @@ -8,6 +8,7 @@ from django.contrib.auth import get_user_model from interventions.models import ( Intervention, InterventionTimeLine, + InterventionNote, MAINTAIN_CHOICES, ORIGIN_TYPE_CHOICES, STATUS_CHOICES, @@ -391,3 +392,291 @@ class InterventionChangeTracker: ) return assignment_event, modification_event + + +def truncate_text(text: Optional[str], max_len: int = 120) -> str: + """Tronque un texte pour un affichage concis dans l'historique.""" + if not text: + return "" + text = text.strip().replace('\r\n', ' ').replace('\n', ' ') + if len(text) <= max_len: + return text + return text[:max_len - 3] + "..." + + +def record_note_event( + intervention: Intervention, + user, + action: str, # 'create', 'update', 'delete' + note_type: str, + content: str, + old_note_type: Optional[str] = None, + old_content: Optional[str] = None, + event_time=None, +) -> InterventionTimeLine: + """Enregistre un événement lié aux notes dans la chronologie.""" + type_choices = dict(InterventionNote.NoteType.choices) + type_label = type_choices.get(note_type, note_type) + old_type_label = type_choices.get(old_note_type, old_note_type) if old_note_type else None + + changes = {} + if action == 'create': + desc = _("Note ajoutée (%(type)s)") % {'type': type_label} + changes['note_action'] = {'label': str(_("Action")), 'old': None, 'new': str(_("Ajout"))} + changes['note_type'] = {'label': str(_("Type de note")), 'old': None, 'new': str(type_label)} + if content: + changes['content'] = {'label': str(_("Contenu")), 'old': None, 'new': truncate_text(content)} + elif action == 'update': + desc = _("Note modifiée (%(type)s)") % {'type': type_label} + if old_note_type and old_note_type != note_type: + changes['note_type'] = {'label': str(_("Type de note")), 'old': str(old_type_label), 'new': str(type_label)} + if old_content is not None and old_content != content: + changes['content'] = { + 'label': str(_("Contenu")), + 'old': truncate_text(old_content), + 'new': truncate_text(content), + } + if not changes: + changes['note_action'] = {'label': str(_("Action")), 'old': None, 'new': str(_("Mise à jour"))} + elif action == 'delete': + desc = _("Note supprimée (%(type)s)") % {'type': type_label} + changes['note_action'] = {'label': str(_("Action")), 'old': str(_("Suppression")), 'new': None} + changes['note_type'] = {'label': str(_("Type de note")), 'old': str(type_label), 'new': None} + if content: + changes['content'] = {'label': str(_("Contenu")), 'old': truncate_text(content), 'new': None} + else: + desc = _("Note : %(action)s") % {'action': action} + + return record_timeline_event( + intervention=intervention, + user=user, + event_type='note', + description=str(desc), + field_changes=changes, + event_time=event_time, + ) + + +def record_document_event( + intervention: Intervention, + user, + action: str, # 'upload', 'delete' + filenames: list, + event_time=None, +) -> Optional[InterventionTimeLine]: + """Enregistre un événement de document (téléversement ou suppression).""" + if not filenames: + return None + + import os + clean_filenames = [os.path.basename(str(f)) for f in filenames if f] + if not clean_filenames: + return None + + changes = {} + names_str = ", ".join(clean_filenames) + + if action == 'upload': + if len(clean_filenames) == 1: + desc = _("Document ajouté : %(name)s") % {'name': clean_filenames[0]} + else: + desc = _("%(count)d documents ajoutés : %(names)s") % { + 'count': len(clean_filenames), + 'names': names_str, + } + changes['documents'] = { + 'label': str(_("Document(s) ajouté(s)")), + 'old': None, + 'new': names_str, + } + elif action == 'delete': + if len(clean_filenames) == 1: + desc = _("Document supprimé : %(name)s") % {'name': clean_filenames[0]} + else: + desc = _("%(count)d documents supprimés : %(names)s") % { + 'count': len(clean_filenames), + 'names': names_str, + } + changes['documents'] = { + 'label': str(_("Document(s) supprimé(s)")), + 'old': names_str, + 'new': None, + } + else: + desc = _("Document : %(action)s") % {'action': action} + + return record_timeline_event( + intervention=intervention, + user=user, + event_type='document', + description=str(desc), + field_changes=changes, + event_time=event_time, + ) + + +def resolve_asset_label(asset_obj, ct=None) -> str: + """Retourne une désignation lisible d'un équipement.""" + if not asset_obj: + return "" + if hasattr(asset_obj, 'get_name') and callable(asset_obj.get_name): + name = asset_obj.get_name() + elif hasattr(asset_obj, 'name') and asset_obj.name: + name = str(asset_obj.name) + else: + name = str(asset_obj) + + if ct and hasattr(ct, 'name') and ct.name: + return f"{name} ({ct.name})" + return str(name) + + +def get_asset_labels_from_pairs(pairs) -> list: + """Résout une collection de (content_type_id, object_id) en liste de désignations lisibles.""" + if not pairs: + return [] + from collections import defaultdict + from django.contrib.contenttypes.models import ContentType + + by_ct = defaultdict(set) + for ct_id, obj_id in pairs: + by_ct[ct_id].add(obj_id) + + labels = [] + ct_map = {ct.id: ct for ct in ContentType.objects.filter(id__in=by_ct.keys())} + for ct_id, obj_ids in by_ct.items(): + ct = ct_map.get(ct_id) + if not ct: + continue + model_class = ct.model_class() + if not model_class: + continue + obj_map = {obj.pk: obj for obj in model_class.objects.filter(pk__in=obj_ids)} + for obj_id in obj_ids: + asset_obj = obj_map.get(obj_id) + if asset_obj: + labels.append(resolve_asset_label(asset_obj, ct)) + else: + labels.append(f"{ct.model} #{obj_id}") + return labels + + +def record_asset_link_event( + intervention: Intervention, + user, + added_asset_names: Optional[list] = None, + removed_asset_names: Optional[list] = None, + event_time=None, +) -> Optional[InterventionTimeLine]: + """Enregistre un événement de liaison / déliaison d'équipements (assets).""" + added_names = [str(n) for n in (added_asset_names or []) if n] + removed_names = [str(n) for n in (removed_asset_names or []) if n] + + if not added_names and not removed_names: + return None + + changes = {} + if added_names and not removed_names: + if len(added_names) == 1: + desc = _("Équipement lié : %(name)s") % {'name': added_names[0]} + else: + desc = _("%(count)d équipements liés : %(names)s") % { + 'count': len(added_names), + 'names': ", ".join(added_names), + } + elif removed_names and not added_names: + if len(removed_names) == 1: + desc = _("Équipement délié : %(name)s") % {'name': removed_names[0]} + else: + desc = _("%(count)d équipements déliés : %(names)s") % { + 'count': len(removed_names), + 'names': ", ".join(removed_names), + } + else: + desc = _("Équipements modifiés (+%(added)d, -%(removed)d)") % { + 'added': len(added_names), + 'removed': len(removed_names), + } + + if added_names: + changes['linked_assets'] = { + 'label': str(_("Équipement(s) lié(s)")), + 'old': None, + 'new': ", ".join(added_names), + } + if removed_names: + changes['unlinked_assets'] = { + 'label': str(_("Équipement(s) délié(s)")), + 'old': ", ".join(removed_names), + 'new': None, + } + + return record_timeline_event( + intervention=intervention, + user=user, + event_type='link', + description=str(desc), + field_changes=changes, + event_time=event_time, + ) + + +def record_relation_link_event( + intervention: Intervention, + user, + relation_label: str, + target_labels: list, + action: str = 'link', + event_time=None, +) -> Optional[InterventionTimeLine]: + """Enregistre un événement de liaison avec un autre élément (ex: intervention liée).""" + targets = [str(t) for t in target_labels if t] + if not targets: + return None + + targets_str = ", ".join(targets) + changes = {} + + if action == 'link': + if len(targets) == 1: + desc = _("%(relation)s liée : %(target)s") % { + 'relation': relation_label, + 'target': targets[0], + } + else: + desc = _("%(count)d %(relation)ss liées : %(targets)s") % { + 'count': len(targets), + 'relation': relation_label, + 'targets': targets_str, + } + changes['linked_items'] = { + 'label': str(_("%(relation)s liée(s)") % {'relation': relation_label}), + 'old': None, + 'new': targets_str, + } + else: + if len(targets) == 1: + desc = _("%(relation)s déliée : %(target)s") % { + 'relation': relation_label, + 'target': targets[0], + } + else: + desc = _("%(count)d %(relation)ss déliées : %(targets)s") % { + 'count': len(targets), + 'relation': relation_label, + 'targets': targets_str, + } + changes['unlinked_items'] = { + 'label': str(_("%(relation)s déliée(s)") % {'relation': relation_label}), + 'old': targets_str, + 'new': None, + } + + return record_timeline_event( + intervention=intervention, + user=user, + event_type='link', + description=str(desc), + field_changes=changes, + event_time=event_time, + ) diff --git a/loko/interventions/static/interventions/timeline.css b/loko/interventions/static/interventions/timeline.css index e27fa1d..742d99a 100644 --- a/loko/interventions/static/interventions/timeline.css +++ b/loko/interventions/static/interventions/timeline.css @@ -200,11 +200,24 @@ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.07); } -.history-item-modification .history-timeline-card { +.history-item-modification .history-timeline-card, +.history-item-detailed .history-timeline-card { background-color: #fafbfc; border-left: 3px solid #94a3b8; } +.history-timeline-item[data-event-type="note"] .history-timeline-card { + border-left: 3px solid #0dcaf0; +} + +.history-timeline-item[data-event-type="document"] .history-timeline-card { + border-left: 3px solid #6c757d; +} + +.history-timeline-item[data-event-type="link"] .history-timeline-card { + border-left: 3px solid #212529; +} + .history-changes { background: #f8fafc; border-radius: 6px; diff --git a/loko/interventions/templates/interventions/detail/card_chronologie.html b/loko/interventions/templates/interventions/detail/card_chronologie.html index 8e97430..ad3ac8e 100644 --- a/loko/interventions/templates/interventions/detail/card_chronologie.html +++ b/loko/interventions/templates/interventions/detail/card_chronologie.html @@ -29,8 +29,8 @@ onclick="switchHistoryTimeline('full')" title="{% translate 'Afficher toutes les modifications détaillées' %}"> {% translate "Historique complet" %} - {% if timeline_modification_count %} - +{{ timeline_modification_count }} + {% if timeline_detailed_count or timeline_modification_count %} + +{{ timeline_detailed_count|default:timeline_modification_count }} {% endif %} @@ -42,7 +42,7 @@ {% if events_list %}

{% for event in events_list %} -
@@ -79,6 +79,15 @@ {% elif event.event_type == 'modification' %} {% translate "Modification" %} {{ event.event_description|default:_("Attributs modifiés") }} + {% elif event.event_type == 'note' %} + {% translate "Note" %} + {{ event.event_description }} + {% elif event.event_type == 'document' %} + {% translate "Document" %} + {{ event.event_description }} + {% elif event.event_type == 'link' %} + {% translate "Lien" %} + {{ event.event_description }} {% else %} {{ event.get_event_type_display }} {% if event.to_status %} @@ -104,16 +113,16 @@ {% for field_key, change in event.field_changes.items %}
{{ change.label|default:field_key }} - {% if change.old %} + {% if change.old and change.new %} {{ change.old }} - {% else %} - ({% translate "vide" %}) - {% endif %} - - {% if change.new %} + {{ change.new }} + {% elif change.new %} + {{ change.new }} + {% elif change.old %} + {{ change.old }} {% else %} - ({% translate "vide" %}) + ({% translate "vide" %}) {% endif %}
{% endfor %} @@ -138,7 +147,7 @@ function switchHistoryTimeline(mode) { const defaultBtn = document.getElementById('btnHistoryDefault'); const fullBtn = document.getElementById('btnHistoryFull'); const badge = document.getElementById('historyCounterBadge'); - const modItems = document.querySelectorAll('.history-item-modification'); + const detailedItems = document.querySelectorAll('.history-item-detailed, .history-item-modification'); const section = document.getElementById('section-chronologie'); const defaultCount = section ? section.dataset.defaultCount : ''; const totalCount = section ? section.dataset.totalCount : ''; @@ -146,12 +155,12 @@ function switchHistoryTimeline(mode) { if (mode === 'full') { defaultBtn?.classList.remove('active'); fullBtn?.classList.add('active'); - modItems.forEach(el => el.classList.remove('d-none')); + detailedItems.forEach(el => el.classList.remove('d-none')); if (badge && totalCount) badge.textContent = totalCount; } else { fullBtn?.classList.remove('active'); defaultBtn?.classList.add('active'); - modItems.forEach(el => el.classList.add('d-none')); + detailedItems.forEach(el => el.classList.add('d-none')); if (badge && defaultCount) badge.textContent = defaultCount; } } diff --git a/loko/interventions/templates/interventions/detail/styles.html b/loko/interventions/templates/interventions/detail/styles.html index 10de605..fe1cdcc 100644 --- a/loko/interventions/templates/interventions/detail/styles.html +++ b/loko/interventions/templates/interventions/detail/styles.html @@ -546,11 +546,24 @@ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.07); } - .history-item-modification .history-timeline-card { + .history-item-modification .history-timeline-card, + .history-item-detailed .history-timeline-card { background-color: #fafbfc; border-left: 3px solid #94a3b8; } + .history-timeline-item[data-event-type="note"] .history-timeline-card { + border-left: 3px solid #0dcaf0; + } + + .history-timeline-item[data-event-type="document"] .history-timeline-card { + border-left: 3px solid #6c757d; + } + + .history-timeline-item[data-event-type="link"] .history-timeline-card { + border-left: 3px solid #212529; + } + .history-changes { background: #f8fafc; border-radius: 6px; diff --git a/loko/interventions/tests/test_timeline_history.py b/loko/interventions/tests/test_timeline_history.py index 3b6e9eb..54c3f3a 100644 --- a/loko/interventions/tests/test_timeline_history.py +++ b/loko/interventions/tests/test_timeline_history.py @@ -4,14 +4,30 @@ from django.contrib.auth import get_user_model from django.urls import reverse from django.utils import timezone +from django.core.files.uploadedfile import SimpleUploadedFile +from django.contrib.contenttypes.models import ContentType + from common.models import UserConfig, Role, Thematic from contracts.models import Company, CompanyTeam, CompanyMember -from interventions.models import Intervention, InterventionTimeLine +from interventions.models import ( + Intervention, + InterventionTimeLine, + InterventionNote, + InterventionDocument, + InterventionAsset, + InterventionLink, +) +from assets.models import TrafficLightIntersection from interventions.services.timeline_service import ( record_timeline_event, record_assignment_event, + record_note_event, + record_document_event, + record_asset_link_event, + record_relation_link_event, InterventionChangeTracker, ) +from interventions.views.helpers import _sync_intervention_assets_data, _handle_notes_update class TimelineHistoryTests(TestCase): @@ -233,3 +249,221 @@ class TimelineHistoryTests(TestCase): with translation.override('fr'): response_fr = self.client.get(url, HTTP_ACCEPT_LANGUAGE='fr') self.assertContains(response_fr, 'Historique complet') + + def test_timeline_model_new_event_types(self): + """Test properties, badge classes, and icons for note, document, and link event types.""" + # Note event + event_note = record_note_event( + intervention=self.intervention, + user=self.user, + action='create', + note_type='work_done', + content='Remplacement du contrôleur effectué.', + ) + self.assertTrue(event_note.is_note) + self.assertFalse(event_note.is_default_visible) + self.assertEqual(event_note.get_badge_class(), 'bg-info text-dark') + self.assertEqual(event_note.get_icon(), 'bi-chat-left-text-fill') + self.assertIn('note_type', event_note.field_changes) + self.assertIn('content', event_note.field_changes) + + # Document event + event_doc = record_document_event( + intervention=self.intervention, + user=self.user, + action='upload', + filenames=['rapport_technique.pdf', 'photo_avant.jpg'], + ) + self.assertTrue(event_doc.is_document) + self.assertFalse(event_doc.is_default_visible) + self.assertEqual(event_doc.get_badge_class(), 'bg-secondary') + self.assertEqual(event_doc.get_icon(), 'bi-paperclip') + self.assertIn('rapport_technique.pdf', event_doc.event_description) + + # Link event + event_link = record_asset_link_event( + intervention=self.intervention, + user=self.user, + added_asset_names=['Carrefour Louise (Carrefour)'], + removed_asset_names=['Carrefour Trône (Carrefour)'], + ) + self.assertTrue(event_link.is_link) + self.assertFalse(event_link.is_default_visible) + self.assertEqual(event_link.get_badge_class(), 'bg-dark') + self.assertEqual(event_link.get_icon(), 'bi-link-45deg') + self.assertIn('linked_assets', event_link.field_changes) + self.assertIn('unlinked_assets', event_link.field_changes) + + def test_note_views_timeline_recording(self): + """Test that adding, updating, and deleting notes via views records timeline events.""" + self.client.login(username='agent_test', password='secret_password') + + # 1. Add Note + add_url = reverse('interventions:intervention_add_note', args=[self.intervention.id]) + resp = self.client.post(add_url, { + 'note_type': 'important_info', + 'content': 'Attention au câble sous tension', + }) + self.assertEqual(resp.status_code, 200) + + note_event = self.intervention.events.filter(event_type='note').last() + self.assertIsNotNone(note_event) + self.assertEqual(note_event.event_user, self.user) + self.assertIn('Attention au câble', note_event.field_changes['content']['new']) + + created_note = InterventionNote.objects.filter(intervention=self.intervention).last() + + # 2. Update Note + update_url = reverse('interventions:intervention_update_note', args=[self.intervention.id, created_note.id]) + resp_update = self.client.post(update_url, { + 'note_type': 'important_info', + 'content': 'Attention au câble sous tension (mis à jour)', + }) + self.assertEqual(resp_update.status_code, 200) + + update_event = self.intervention.events.filter(event_type='note').last() + self.assertIsNotNone(update_event) + self.assertIn('old', update_event.field_changes['content']) + self.assertIn('mis à jour', update_event.field_changes['content']['new']) + + # 3. Delete Note + delete_url = reverse('interventions:intervention_delete_note', args=[self.intervention.id, created_note.id]) + resp_del = self.client.post(delete_url) + self.assertEqual(resp_del.status_code, 200) + + del_event = self.intervention.events.filter(event_type='note').last() + self.assertIsNotNone(del_event) + self.assertIn(del_event.field_changes['note_action']['old'], ['Suppression', 'Deletion']) + + def test_batch_notes_update_timeline_recording(self): + """Test _handle_notes_update records timeline events for notes in batch mode.""" + from django.test.client import RequestFactory + factory = RequestFactory() + request = factory.post('/fake-url') + request.user = self.user + + # Create note directly first + existing_note = InterventionNote.objects.create( + intervention=self.intervention, + note_type='work_done', + content='Note initiale', + note_author=self.user, + note_time=timezone.now(), + ) + + notes_data = { + 'new_notes': [{'note_type': 'comment', 'content': 'Nouvelle note en batch'}], + 'updated_notes': [{'id': existing_note.id, 'note_type': 'comment', 'content': 'Note modifiée en batch'}], + 'deleted_notes': [], + } + + success, errors = _handle_notes_update(request, self.intervention, notes_data) + self.assertTrue(success) + self.assertEqual(len(errors), 0) + + note_events = list(self.intervention.events.filter(event_type='note')) + self.assertGreaterEqual(len(note_events), 2) + descriptions = [e.event_description for e in note_events] + self.assertTrue(any('Note ajoutée' in d or 'Note added' in d for d in descriptions)) + self.assertTrue(any('Note modifiée' in d or 'Note updated' in d for d in descriptions)) + + def test_document_views_timeline_recording(self): + """Test adding and deleting a document logs document events in timeline.""" + self.client.login(username='agent_test', password='secret_password') + + # 1. Add document + add_url = reverse('interventions:intervention_add_document', args=[self.intervention.id]) + test_file = SimpleUploadedFile("schema_test.pdf", b"file_content_binary", content_type="application/pdf") + resp = self.client.post(add_url, {'documents': [test_file]}) + self.assertEqual(resp.status_code, 302) + + doc_event = self.intervention.events.filter(event_type='document').last() + self.assertIsNotNone(doc_event) + self.assertEqual(doc_event.event_user, self.user) + self.assertIn('schema_test.pdf', doc_event.event_description) + + created_doc = InterventionDocument.objects.filter(intervention=self.intervention).last() + + # 2. Delete document + del_url = reverse('interventions:intervention_delete_document', args=[self.intervention.id, created_doc.id]) + resp_del = self.client.post(del_url) + self.assertEqual(resp_del.status_code, 200) + + del_event = self.intervention.events.filter(event_type='document').last() + self.assertIsNotNone(del_event) + self.assertTrue('Document supprimé' in del_event.event_description or 'Document deleted' in del_event.event_description) + + def test_asset_link_timeline_recording(self): + """Test linking and unlinking an asset records link events.""" + asset = TrafficLightIntersection.objects.create(code='TL-001', name_fr='Carrefour Arts-Loi') + ct = ContentType.objects.get_for_model(TrafficLightIntersection) + + # Sync asset to intervention + _sync_intervention_assets_data( + intervention=self.intervention, + normalized_assets=[{'model': 'trafficlightintersection', 'object_id': asset.id}], + user=self.user, + ) + + link_event = self.intervention.events.filter(event_type='link').last() + self.assertIsNotNone(link_event) + self.assertEqual(link_event.event_user, self.user) + self.assertIn('Carrefour Arts-Loi', link_event.event_description) + self.assertIn('linked_assets', link_event.field_changes) + + # Unlink asset + _sync_intervention_assets_data( + intervention=self.intervention, + normalized_assets=[], + user=self.user, + ) + + unlink_event = self.intervention.events.filter(event_type='link').last() + self.assertIsNotNone(unlink_event) + self.assertTrue('délié' in unlink_event.event_description or 'unlinked' in unlink_event.event_description.lower()) + self.assertIn('unlinked_assets', unlink_event.field_changes) + + def test_intervention_link_timeline_recording(self): + """Test linking two interventions records link events on both sides.""" + target_intervention = Intervention.objects.create( + title='Target Linked Intervention', + status='in_preparation', + thematic=self.thematic, + ) + + self.client.login(username='agent_test', password='secret_password') + url = reverse('interventions:link_existing_interventions', args=[self.intervention.id]) + resp = self.client.post(url, {'codes': target_intervention.code}) + self.assertEqual(resp.status_code, 302) + + # Event on origin intervention + origin_link_event = self.intervention.events.filter(event_type='link').last() + self.assertIsNotNone(origin_link_event) + self.assertEqual(origin_link_event.event_user, self.user) + self.assertIn(target_intervention.code, origin_link_event.event_description) + + # Event on target intervention + target_link_event = target_intervention.events.filter(event_type='link').last() + self.assertIsNotNone(target_link_event) + self.assertEqual(target_link_event.event_user, self.user) + self.assertIn(self.intervention.code, target_link_event.event_description) + + def test_detail_view_shows_all_in_full_history(self): + """Test that notes, documents, and links appear as detailed events in timeline.""" + record_note_event(self.intervention, self.user, action='create', note_type='comment', content='Note test') + record_document_event(self.intervention, self.user, action='upload', filenames=['doc_test.png']) + record_relation_link_event(self.intervention, self.user, relation_label='Intervention', target_labels=['I999999']) + + self.client.login(username='agent_test', password='secret_password') + url = reverse('interventions:intervention_detail', args=[self.intervention.id]) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + + self.assertIn('timeline_detailed_count', response.context) + # Note, document, link are all non-default-visible (detailed) + self.assertGreaterEqual(response.context['timeline_detailed_count'], 3) + self.assertContains(response, 'history-item-detailed') + self.assertContains(response, 'data-event-type="note"') + self.assertContains(response, 'data-event-type="document"') + self.assertContains(response, 'data-event-type="link"') + diff --git a/loko/interventions/views/detail.py b/loko/interventions/views/detail.py index e6f81ba..0c8eb03 100644 --- a/loko/interventions/views/detail.py +++ b/loko/interventions/views/detail.py @@ -63,7 +63,12 @@ from interventions.models import (InterventionSubscription, Intervention, Interv InterventionPostPeriodQuantity, InterventionEmailLog, InterventionAssignment) from interventions.models import STATUS_CHOICES, STATUS_ORDERS, MAINTAIN_CHOICES, TYPE_CHOICES, ORIGIN_TYPE_CHOICES, PAUSE_REASON_CHOICES, get_type_choices from interventions.services.document_sequencing import get_sequenced_intervention_documents -from interventions.services.timeline_service import InterventionChangeTracker +from interventions.services.timeline_service import ( + InterventionChangeTracker, + record_asset_link_event, + record_relation_link_event, + get_asset_labels_from_pairs, +) from interventions.views.forms import (InterventionForm, InterventionNoteForm, InterventionDocumentForm, InterventionOccupationForm, PreventiveInterventionForm, AssetsLinkForm, LinkExistingInterventionsForm) @@ -678,7 +683,8 @@ def intervention_detail(request, intervention_id): timeline_events.insert(insert_idx, synth_event) timeline_default_count = sum(1 for e in timeline_events if e.is_default_visible) - timeline_modification_count = sum(1 for e in timeline_events if e.is_modification) + timeline_detailed_count = sum(1 for e in timeline_events if not e.is_default_visible) + timeline_modification_count = timeline_detailed_count context = { "intervention": intervention, @@ -763,6 +769,7 @@ def intervention_detail(request, intervention_id): # Timeline / Chronologie 'timeline_events': timeline_events, 'timeline_default_count': timeline_default_count, + 'timeline_detailed_count': timeline_detailed_count, 'timeline_modification_count': timeline_modification_count, 'timeline_total_count': len(timeline_events), # Historique des envois d'emails (ordre chronologique) @@ -885,6 +892,24 @@ def link_existing_interventions(request, intervention_id): already_codes.append(target.code) if created_codes: + record_relation_link_event( + intervention=intervention, + user=request.user, + relation_label=str(_("Intervention")), + target_labels=created_codes, + action='link', + ) + for target_code in created_codes: + target = found_map.get(target_code) + if target: + record_relation_link_event( + intervention=target, + user=request.user, + relation_label=str(_("Intervention")), + target_labels=[intervention.code], + action='link', + ) + messages.success( request, ngettext( @@ -2204,6 +2229,9 @@ def intervention_link_assets(request, intervention_id): to_add = target_pairs - existing_pairs to_del = existing_pairs - target_pairs + removed_labels = get_asset_labels_from_pairs(to_del) if to_del else [] + added_labels = get_asset_labels_from_pairs(to_add) if to_add else [] + created_count = 0 deleted_count = 0 operations_deleted = 0 @@ -2232,6 +2260,14 @@ def intervention_link_assets(request, intervention_id): InterventionAsset.objects.bulk_create(objs) created_count = len(objs) + if to_add or to_del: + record_asset_link_event( + intervention=intervention, + user=request.user, + added_asset_names=added_labels, + removed_asset_names=removed_labels, + ) + except Exception as e: messages.error(request, f"{_("Erreur de synchro")}: {e}") return redirect("interventions:intervention_detail", intervention_id) diff --git a/loko/interventions/views/helpers.py b/loko/interventions/views/helpers.py index b62dd00..0c38e89 100644 --- a/loko/interventions/views/helpers.py +++ b/loko/interventions/views/helpers.py @@ -53,6 +53,11 @@ from dateutil.relativedelta import relativedelta from common.private_files.helpers import build_private_url from common.utils import get_short_name +from interventions.services.timeline_service import ( + record_note_event, + record_asset_link_event, + get_asset_labels_from_pairs, +) from interventions.models import (InterventionSubscription, Intervention, InterventionAsset, InterventionTimeLine, InterventionContractPost, InterventionDocument, InterventionNote, InterventionLocation, InterventionLink, InterventionSubType, ContractPauseReasonAssignment, @@ -1595,6 +1600,9 @@ def _sync_intervention_assets_data( to_add = target_pairs - existing_pairs to_remove = existing_pairs - target_pairs + removed_labels = get_asset_labels_from_pairs(to_remove) if to_remove else [] + added_labels = get_asset_labels_from_pairs(to_add) if to_add else [] + created_count = 0 deleted_count = 0 operations_deleted = 0 @@ -1641,6 +1649,15 @@ def _sync_intervention_assets_data( InterventionAsset.objects.bulk_create(new_relations) created_count = len(new_relations) + if to_add or to_remove: + event_user = user or (request.user if request and getattr(request, 'user', None) else None) + record_asset_link_event( + intervention=intervention, + user=event_user, + added_asset_names=added_labels, + removed_asset_names=removed_labels, + ) + operations_created = 0 if to_add: assets_with_ct = _resolve_assets_from_pairs(to_add) @@ -2457,13 +2474,20 @@ def _handle_notes_update(request, intervention, notes_data): continue try: - InterventionNote.objects.create( + note_inst = InterventionNote.objects.create( intervention=intervention, content=content, note_type=note_type, note_author=request.user, note_time=timezone.now() ) + record_note_event( + intervention=intervention, + user=request.user, + action='create', + note_type=note_type, + content=content, + ) success = True except Exception as e: errors.append(_('Error creating note: %(error)s') % {'error': str(e)}) @@ -2487,11 +2511,24 @@ def _handle_notes_update(request, intervention, notes_data): errors.append(_('You do not have permission to edit this note')) continue + old_note_type = note.note_type + old_content = note.content + note.content = content note.note_type = note_type note.updated_by = request.user note.updated_at = timezone.now() note.save() + + record_note_event( + intervention=intervention, + user=request.user, + action='update', + note_type=note_type, + content=content, + old_note_type=old_note_type, + old_content=old_content, + ) success = True except InterventionNote.DoesNotExist: errors.append(_('Note not found: %(note_id)s') % {'note_id': note_id}) @@ -2510,7 +2547,17 @@ def _handle_notes_update(request, intervention, notes_data): errors.append(_('You do not have permission to delete this note')) continue + del_note_type = note.note_type + del_content = note.content note.delete() + + record_note_event( + intervention=intervention, + user=request.user, + action='delete', + note_type=del_note_type, + content=del_content, + ) success = True except InterventionNote.DoesNotExist: errors.append(_('Note not found: %(note_id)s') % {'note_id': note_id}) diff --git a/loko/interventions/views/mobile.py b/loko/interventions/views/mobile.py index 7922ff4..f670019 100644 --- a/loko/interventions/views/mobile.py +++ b/loko/interventions/views/mobile.py @@ -53,6 +53,7 @@ from dateutil.relativedelta import relativedelta from common.private_files.helpers import build_private_url from common.utils import get_short_name +from interventions.services.timeline_service import record_document_event from interventions import views from interventions.models import (InterventionSubscription, Intervention, InterventionAsset, InterventionTimeLine, InterventionContractPost, InterventionDocument, InterventionNote, InterventionLocation, InterventionLink, @@ -1214,6 +1215,13 @@ def mobile_upload_photo_api(request, intervention_id): file=upload, uploaded_by=request.user, ) + filename = getattr(upload, 'name', '') or getattr(doc, 'filename', None) or getattr(doc.file, 'name', '') or str(doc.id) + record_document_event( + intervention=intervention, + user=request.user, + action='upload', + filenames=[filename], + ) except Exception as e: logger.exception("Erreur lors de l\'upload de la photo mobile") return JsonResponse({'success': False, 'error': _('Erreur lors de l\'enregistrement de la photo.')}, status=500) @@ -1259,8 +1267,15 @@ def mobile_delete_photo_api(request, intervention_id, document_id): status=403 ) + filename = getattr(doc, 'filename', None) or getattr(doc.file, 'name', '') or str(doc.id) try: doc.delete() + record_document_event( + intervention=intervention, + user=request.user, + action='delete', + filenames=[filename], + ) except Exception: logger.exception("Erreur lors de la suppression du document mobile") return JsonResponse({'success': False, 'error': _('Erreur lors de la suppression du document.')}, status=500) diff --git a/loko/interventions/views/notes_docs.py b/loko/interventions/views/notes_docs.py index 17c42f3..358d9e5 100644 --- a/loko/interventions/views/notes_docs.py +++ b/loko/interventions/views/notes_docs.py @@ -53,6 +53,10 @@ from dateutil.relativedelta import relativedelta from common.private_files.helpers import build_private_url from common.utils import get_short_name +from interventions.services.timeline_service import ( + record_note_event, + record_document_event, +) from interventions.models import (InterventionSubscription, Intervention, InterventionAsset, InterventionTimeLine, InterventionContractPost, InterventionDocument, InterventionNote, InterventionLocation, InterventionLink, ContractPauseReasonAssignment, @@ -171,6 +175,14 @@ def intervention_add_note(request, intervention_id): note_instance.note_time = now() note_instance.save() + record_note_event( + intervention=intervention, + user=request.user, + action='create', + note_type=note_instance.note_type, + content=note_instance.content, + ) + return JsonResponse({ 'success': True, 'note': _serialize_note(note_instance, request.user) @@ -186,6 +198,9 @@ def intervention_update_note(request, intervention_id, note_id): if not can_edit_note(request.user, request.user.config, note): return JsonResponse({'success': False, 'error': _('Vous ne pouvez pas modifier cette note.')}, status=403) + old_note_type = note.note_type + old_content = note.content + form = InterventionNoteForm(request.POST, instance=note) if form.is_valid(): note_instance = form.save(commit=False) @@ -193,6 +208,16 @@ def intervention_update_note(request, intervention_id, note_id): note_instance.save(update_fields=['content', 'note_type', 'updated_at', 'updated_by']) note.refresh_from_db(fields=['content', 'note_type', 'updated_at', 'updated_by']) + record_note_event( + intervention=intervention, + user=request.user, + action='update', + note_type=note.note_type, + content=note.content, + old_note_type=old_note_type, + old_content=old_content, + ) + return JsonResponse({ 'success': True, 'note': _serialize_note(note, request.user) @@ -208,7 +233,18 @@ def intervention_delete_note(request, intervention_id, note_id): if not can_edit_note(request.user, request.user.config, note): return JsonResponse({'success': False, 'error': _('Vous ne pouvez pas supprimer cette note.')}, status=403) + note_type = note.note_type + content = note.content note.delete() + + record_note_event( + intervention=intervention, + user=request.user, + action='delete', + note_type=note_type, + content=content, + ) + return JsonResponse({'success': True}) @@ -220,8 +256,17 @@ def intervention_add_document(request, intervention_id): form = InterventionDocumentForm(request.POST, request.FILES) if form.is_valid(): files = form.cleaned_data["documents"] + filenames = [] for file in files: - InterventionDocument.objects.create(intervention=intervention, file=file, uploaded_by=request.user) + doc = InterventionDocument.objects.create(intervention=intervention, file=file, uploaded_by=request.user) + filenames.append(getattr(file, 'name', '') or str(doc.id)) + + record_document_event( + intervention=intervention, + user=request.user, + action='upload', + filenames=filenames, + ) messages.success(request, _("Document(s) sauvegardé(s) avec succès !")) return redirect_with_variant('interventions:intervention_detail', variant=variant, url_kwargs={'intervention_id': intervention_id}) @@ -249,12 +294,22 @@ def intervention_delete_document(request, intervention_id, document_id): if not can_delete_document(request.user, user_config, document): return JsonResponse({'success': False, 'error': _('Vous ne pouvez pas supprimer ce document.')}, status=403) + filename = getattr(document.file, 'name', '') or str(document.id) + if document.file: document.file.delete(save=False) if document.thumbnail: document.thumbnail.delete(save=False) document.delete() + + record_document_event( + intervention=intervention, + user=request.user, + action='delete', + filenames=[filename], + ) + return JsonResponse({'success': True})