From 15682521127771d83c1aa4bbed9c64624539b81d Mon Sep 17 00:00:00 2001 From: jedi Date: Sun, 9 Feb 2025 18:32:00 +0100 Subject: [PATCH] show all item timestamps in timeline --- core/inventory/models.py | 8 +++ core/inventory/serializers.py | 16 +++++ core/inventory/tests/v2/test_items.py | 44 ++++++------- web/src/components/Timeline.vue | 18 ++++++ web/src/components/TimelineCreated.vue | 83 +++++++++++++++++++++++++ web/src/components/TimelineDeleted.vue | 83 +++++++++++++++++++++++++ web/src/components/TimelineReturned.vue | 83 +++++++++++++++++++++++++ 7 files changed, 313 insertions(+), 22 deletions(-) create mode 100644 web/src/components/TimelineCreated.vue create mode 100644 web/src/components/TimelineDeleted.vue create mode 100644 web/src/components/TimelineReturned.vue diff --git a/core/inventory/models.py b/core/inventory/models.py index 231094e..c782bcb 100644 --- a/core/inventory/models.py +++ b/core/inventory/models.py @@ -1,6 +1,9 @@ from itertools import groupby from django.db import models +from django.db.models.signals import pre_save +from django.dispatch import receiver +from django.utils import timezone from django_softdelete.models import SoftDeleteModel, SoftDeleteManager @@ -64,6 +67,11 @@ class Item(SoftDeleteModel): return '[' + str(self.id) + ']' + self.description +@receiver(pre_save, sender=Item) +def item_updated(sender, instance, **kwargs): + instance.updated_at = timezone.now() + + class Container(SoftDeleteModel): id = models.AutoField(primary_key=True) name = models.CharField(max_length=255) diff --git a/core/inventory/serializers.py b/core/inventory/serializers.py index 2aa1135..0661476 100644 --- a/core/inventory/serializers.py +++ b/core/inventory/serializers.py @@ -132,6 +132,22 @@ class ItemSerializer(BasicItemSerializer): 'cid': placement.container.id, 'box': placement.container.name }) + + if obj.created_at: + timeline.append({ + 'type': 'created', + 'timestamp': obj.created_at, + }) + if obj.returned_at: + timeline.append({ + 'type': 'returned', + 'timestamp': obj.returned_at, + }) + if obj.deleted_at: + timeline.append({ + 'type': 'deleted', + 'timestamp': obj.deleted_at, + }) return sorted(timeline, key=lambda x: x['timestamp']) diff --git a/core/inventory/tests/v2/test_items.py b/core/inventory/tests/v2/test_items.py index 0c85eb4..34c4739 100644 --- a/core/inventory/tests/v2/test_items.py +++ b/core/inventory/tests/v2/test_items.py @@ -63,28 +63,28 @@ class ItemTestCase(TestCase): self.assertEqual(response.json()[0]['file'], None) self.assertEqual(response.json()[0]['returned'], False) self.assertEqual(response.json()[0]['event'], self.event.slug) - self.assertEqual(len(response.json()[0]['timeline']), 4) - self.assertEqual(response.json()[0]['timeline'][0]['type'], 'placement') - self.assertEqual(response.json()[0]['timeline'][1]['type'], 'comment') - self.assertEqual(response.json()[0]['timeline'][2]['type'], 'issue_relation') - self.assertEqual(response.json()[0]['timeline'][3]['type'], 'placement') - self.assertEqual(response.json()[0]['timeline'][1]['id'], comment.id) - self.assertEqual(response.json()[0]['timeline'][2]['id'], match.id) - self.assertEqual(response.json()[0]['timeline'][3]['id'], placement.id) - self.assertEqual(response.json()[0]['timeline'][0]['box'], 'BOX1') - self.assertEqual(response.json()[0]['timeline'][0]['cid'], self.box1.id) - self.assertEqual(response.json()[0]['timeline'][1]['comment'], 'test') - self.assertEqual(response.json()[0]['timeline'][1]['timestamp'], - comment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) - self.assertEqual(response.json()[0]['timeline'][2]['status'], 'possible') - self.assertEqual(response.json()[0]['timeline'][2]['timestamp'], - match.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) - self.assertEqual(response.json()[0]['timeline'][2]['issue_thread']['name'], "test issue") - self.assertEqual(response.json()[0]['timeline'][2]['issue_thread']['event'], "EVENT") - self.assertEqual(response.json()[0]['timeline'][2]['issue_thread']['state'], "pending_new") - self.assertEqual(response.json()[0]['timeline'][3]['box'], 'BOX2') - self.assertEqual(response.json()[0]['timeline'][3]['cid'], self.box2.id) - self.assertEqual(response.json()[0]['timeline'][3]['timestamp'], + self.assertEqual(len(response.json()[0]['timeline']), 5) + self.assertEqual(response.json()[0]['timeline'][0]['type'], 'created') + self.assertEqual(response.json()[0]['timeline'][1]['type'], 'placement') + self.assertEqual(response.json()[0]['timeline'][2]['type'], 'comment') + self.assertEqual(response.json()[0]['timeline'][3]['type'], 'issue_relation') + self.assertEqual(response.json()[0]['timeline'][4]['type'], 'placement') + self.assertEqual(response.json()[0]['timeline'][2]['id'], comment.id) + self.assertEqual(response.json()[0]['timeline'][3]['id'], match.id) + self.assertEqual(response.json()[0]['timeline'][4]['id'], placement.id) + self.assertEqual(response.json()[0]['timeline'][1]['box'], 'BOX1') + self.assertEqual(response.json()[0]['timeline'][1]['cid'], self.box1.id) + self.assertEqual(response.json()[0]['timeline'][0]['timestamp'], item.created_at.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) + self.assertEqual(response.json()[0]['timeline'][2]['comment'], 'test') + self.assertEqual(response.json()[0]['timeline'][2]['timestamp'], comment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) + self.assertEqual(response.json()[0]['timeline'][3]['status'], 'possible') + self.assertEqual(response.json()[0]['timeline'][3]['timestamp'], match.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) + self.assertEqual(response.json()[0]['timeline'][3]['issue_thread']['name'], "test issue") + self.assertEqual(response.json()[0]['timeline'][3]['issue_thread']['event'], "EVENT") + self.assertEqual(response.json()[0]['timeline'][3]['issue_thread']['state'], "pending_new") + self.assertEqual(response.json()[0]['timeline'][4]['box'], 'BOX2') + self.assertEqual(response.json()[0]['timeline'][4]['cid'], self.box2.id) + self.assertEqual(response.json()[0]['timeline'][4]['timestamp'], placement.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) self.assertEqual(len(response.json()[0]['related_issues']), 1) self.assertEqual(response.json()[0]['related_issues'][0]['name'], "test issue") diff --git a/web/src/components/Timeline.vue b/web/src/components/Timeline.vue index 0099c03..ee0ca4d 100644 --- a/web/src/components/Timeline.vue +++ b/web/src/components/Timeline.vue @@ -24,6 +24,15 @@ + + + + + + + + + @@ -35,6 +44,9 @@ + + +

{{ item }}

  • @@ -58,10 +70,16 @@ import TimelineShippingVoucher from "@/components/TimelineShippingVoucher.vue"; import AsyncButton from "@/components/inputs/AsyncButton.vue"; import TimelinePlacement from "@/components/TimelinePlacement.vue"; import TimelineRelatedTicket from "@/components/TimelineRelatedTicket.vue"; +import TimelineCreated from "@/components/TimelineCreated.vue"; +import TimelineReturned from "@/components/TimelineReturned.vue"; +import TimelineDeleted from "@/components/TimelineDeleted.vue"; export default { name: 'Timeline', components: { + TimelineDeleted, + TimelineReturned, + TimelineCreated, TimelineRelatedTicket, TimelinePlacement, TimelineShippingVoucher, diff --git a/web/src/components/TimelineCreated.vue b/web/src/components/TimelineCreated.vue new file mode 100644 index 0000000..126272c --- /dev/null +++ b/web/src/components/TimelineCreated.vue @@ -0,0 +1,83 @@ + + + + + \ No newline at end of file diff --git a/web/src/components/TimelineDeleted.vue b/web/src/components/TimelineDeleted.vue new file mode 100644 index 0000000..076467d --- /dev/null +++ b/web/src/components/TimelineDeleted.vue @@ -0,0 +1,83 @@ + + + + + \ No newline at end of file diff --git a/web/src/components/TimelineReturned.vue b/web/src/components/TimelineReturned.vue new file mode 100644 index 0000000..6eb740b --- /dev/null +++ b/web/src/components/TimelineReturned.vue @@ -0,0 +1,83 @@ + + + + + \ No newline at end of file