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 @@
{{ item }}