mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add list page for tracking info
- Needs filtering (currently displays ALL unique parts)
This commit is contained in:
parent
cb5e2f1a8c
commit
9f42085731
@ -19,6 +19,8 @@ from django.conf.urls.static import static
|
|||||||
|
|
||||||
from django.views.generic.base import RedirectView
|
from django.views.generic.base import RedirectView
|
||||||
|
|
||||||
|
from track.urls import tracking_urls
|
||||||
|
|
||||||
#from project.urls import prj_urls, prj_part_urls, prj_cat_urls, prj_run_urls
|
#from project.urls import prj_urls, prj_part_urls, prj_cat_urls, prj_run_urls
|
||||||
#from track.urls import unique_urls, part_track_urls
|
#from track.urls import unique_urls, part_track_urls
|
||||||
|
|
||||||
@ -71,8 +73,8 @@ urlpatterns = [
|
|||||||
|
|
||||||
url(r'^part/', include(part_urls)),
|
url(r'^part/', include(part_urls)),
|
||||||
url(r'^stock/', include(stock_urls)),
|
url(r'^stock/', include(stock_urls)),
|
||||||
|
|
||||||
url(r'^supplier/', include(supplier_urls)),
|
url(r'^supplier/', include(supplier_urls)),
|
||||||
|
url(r'^track/', include(tracking_urls)),
|
||||||
|
|
||||||
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
|
url(r'^api-doc/', include_docs_urls(title='InvenTree API')),
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ part_urls = [
|
|||||||
# Top level part list (display top level parts and categories)
|
# Top level part list (display top level parts and categories)
|
||||||
url('', views.PartIndex.as_view(), name='part-index'),
|
url('', views.PartIndex.as_view(), name='part-index'),
|
||||||
|
|
||||||
url(r'^.*$', RedirectView.as_view(url='list', permanent=False), name='part-index'),
|
url(r'^.*$', RedirectView.as_view(url='', permanent=False), name='part-index'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
31
InvenTree/track/migrations/0003_auto_20180415_0147.py
Normal file
31
InvenTree/track/migrations/0003_auto_20180415_0147.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2018-04-15 01:47
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('track', '0002_auto_20180413_1440'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='parttrackinginfo',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(default='tracking information', max_length=250),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='parttrackinginfo',
|
||||||
|
name='notes',
|
||||||
|
field=models.CharField(blank=True, max_length=1024),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='uniquepart',
|
||||||
|
name='status',
|
||||||
|
field=models.IntegerField(choices=[(0, 'In progress'), (35, 'Repaired'), (40, 'Damaged'), (10, 'In stock'), (50, 'Destroyed'), (20, 'Shipped'), (30, 'Returned')], default=0),
|
||||||
|
),
|
||||||
|
]
|
23
InvenTree/track/migrations/0004_parttrackinginfo_user.py
Normal file
23
InvenTree/track/migrations/0004_parttrackinginfo_user.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2018-04-15 01:50
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('track', '0003_auto_20180415_0147'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='parttrackinginfo',
|
||||||
|
name='user',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
@ -2,32 +2,19 @@ from __future__ import unicode_literals
|
|||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.db import models
|
from django.db import models
|
||||||
# from django.contrib.auth.models import User
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from supplier.models import Customer
|
from supplier.models import Customer
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
|
|
||||||
|
|
||||||
class UniquePartManager(models.Manager):
|
|
||||||
|
|
||||||
def create(self, *args, **kwargs):
|
|
||||||
|
|
||||||
part = kwargs.get('part', None)
|
|
||||||
|
|
||||||
if not part.trackable:
|
|
||||||
raise ValidationError("Unique part cannot be created for a non-trackable part")
|
|
||||||
|
|
||||||
return super(UniquePartManager, self).create(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class UniquePart(models.Model):
|
class UniquePart(models.Model):
|
||||||
""" A unique instance of a Part object.
|
""" A unique instance of a Part object.
|
||||||
Used for tracking parts based on serial numbers,
|
Used for tracking parts based on serial numbers,
|
||||||
and tracking all events in the life of a part
|
and tracking all events in the life of a part
|
||||||
"""
|
"""
|
||||||
|
|
||||||
objects = UniquePartManager()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
# Cannot have multiple parts with same serial number
|
# Cannot have multiple parts with same serial number
|
||||||
unique_together = ('part', 'serial')
|
unique_together = ('part', 'serial')
|
||||||
@ -48,6 +35,7 @@ class UniquePart(models.Model):
|
|||||||
PART_IN_STOCK = 10
|
PART_IN_STOCK = 10
|
||||||
PART_SHIPPED = 20
|
PART_SHIPPED = 20
|
||||||
PART_RETURNED = 30
|
PART_RETURNED = 30
|
||||||
|
PART_REPAIRED = 35
|
||||||
PART_DAMAGED = 40
|
PART_DAMAGED = 40
|
||||||
PART_DESTROYED = 50
|
PART_DESTROYED = 50
|
||||||
|
|
||||||
@ -56,6 +44,7 @@ class UniquePart(models.Model):
|
|||||||
PART_IN_STOCK: _("In stock"),
|
PART_IN_STOCK: _("In stock"),
|
||||||
PART_SHIPPED: _("Shipped"),
|
PART_SHIPPED: _("Shipped"),
|
||||||
PART_RETURNED: _("Returned"),
|
PART_RETURNED: _("Returned"),
|
||||||
|
PART_REPAIRED: _("Repaired"),
|
||||||
PART_DAMAGED: _("Damaged"),
|
PART_DAMAGED: _("Damaged"),
|
||||||
PART_DESTROYED: _("Destroyed")
|
PART_DESTROYED: _("Destroyed")
|
||||||
}
|
}
|
||||||
@ -73,5 +62,11 @@ class PartTrackingInfo(models.Model):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
part = models.ForeignKey(UniquePart, on_delete=models.CASCADE, related_name='tracking_info')
|
part = models.ForeignKey(UniquePart, on_delete=models.CASCADE, related_name='tracking_info')
|
||||||
|
|
||||||
date = models.DateField(auto_now_add=True, editable=False)
|
date = models.DateField(auto_now_add=True, editable=False)
|
||||||
notes = models.CharField(max_length=500)
|
|
||||||
|
title = models.CharField(max_length=250)
|
||||||
|
|
||||||
|
notes = models.CharField(max_length=1024, blank=True)
|
||||||
|
|
||||||
|
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)
|
||||||
|
31
InvenTree/track/templates/track/index.html
Normal file
31
InvenTree/track/templates/track/index.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% include "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h3>Part Tracking</h3>
|
||||||
|
|
||||||
|
<ul class='list-group'>
|
||||||
|
{% for part in parts.all %}
|
||||||
|
<li class='list-group-item'>
|
||||||
|
{{ part.part.name }} - SN {{ part.serial }}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% if is_paginated %}
|
||||||
|
<div class="pagination">
|
||||||
|
<span class="page-links">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
|
||||||
|
{% endif %}
|
||||||
|
<span class="page-current">
|
||||||
|
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
|
||||||
|
</span>
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a href="?page={{ page_obj.next_page_number }}">next</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -1,15 +1,18 @@
|
|||||||
from django.conf.urls import url
|
from django.conf.urls import url, include
|
||||||
|
from django.views.generic.base import RedirectView
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
part_track_urls = [
|
"""
|
||||||
|
TODO - Implement JSON API for part serial number tracking
|
||||||
|
part_track_api_urls = [
|
||||||
url(r'^(?P<pk>[0-9]+)/?$', api.PartTrackingDetail.as_view(), name='parttrackinginfo-detail'),
|
url(r'^(?P<pk>[0-9]+)/?$', api.PartTrackingDetail.as_view(), name='parttrackinginfo-detail'),
|
||||||
|
|
||||||
url(r'^\?.*/?$', api.PartTrackingList.as_view()),
|
url(r'^\?.*/?$', api.PartTrackingList.as_view()),
|
||||||
url(r'^$', api.PartTrackingList.as_view())
|
url(r'^$', api.PartTrackingList.as_view())
|
||||||
]
|
]
|
||||||
|
|
||||||
unique_urls = [
|
unique_api_urls = [
|
||||||
|
|
||||||
# Detail for a single unique part
|
# Detail for a single unique part
|
||||||
url(r'^(?P<pk>[0-9]+)/?$', api.UniquePartDetail.as_view(), name='uniquepart-detail'),
|
url(r'^(?P<pk>[0-9]+)/?$', api.UniquePartDetail.as_view(), name='uniquepart-detail'),
|
||||||
@ -18,3 +21,12 @@ unique_urls = [
|
|||||||
url(r'^\?.*/?$', api.UniquePartList.as_view()),
|
url(r'^\?.*/?$', api.UniquePartList.as_view()),
|
||||||
url(r'^$', api.UniquePartList.as_view()),
|
url(r'^$', api.UniquePartList.as_view()),
|
||||||
]
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
|
tracking_urls = [
|
||||||
|
|
||||||
|
# List ALL tracked items
|
||||||
|
url('', views.TrackIndex.as_view(), name='track-index'),
|
||||||
|
|
||||||
|
url(r'^.*$', RedirectView.as_view(url='', permanent=False), name='track-index'),
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from django.views.generic import DetailView, ListView
|
||||||
|
from django.views.generic.edit import UpdateView, DeleteView, CreateView
|
||||||
|
|
||||||
|
from .models import UniquePart, PartTrackingInfo
|
||||||
|
|
||||||
|
|
||||||
|
class TrackIndex(ListView):
|
||||||
|
model = UniquePart
|
||||||
|
template_name = 'track/index.html'
|
||||||
|
context_object_name = 'parts'
|
||||||
|
paginate_by = 50
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return UniquePart.objects.order_by('part__name', 'serial')
|
Loading…
Reference in New Issue
Block a user