From 9f4208573136b10c2de60c9592d4ab2dd54c4cc1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 15 Apr 2018 12:07:14 +1000 Subject: [PATCH] Add list page for tracking info - Needs filtering (currently displays ALL unique parts) --- InvenTree/InvenTree/urls.py | 4 ++- InvenTree/part/urls.py | 2 +- .../migrations/0003_auto_20180415_0147.py | 31 +++++++++++++++++++ .../migrations/0004_parttrackinginfo_user.py | 23 ++++++++++++++ InvenTree/track/models.py | 27 +++++++--------- InvenTree/track/templates/track/index.html | 31 +++++++++++++++++++ InvenTree/track/urls.py | 18 +++++++++-- InvenTree/track/views.py | 18 +++++++++++ 8 files changed, 133 insertions(+), 21 deletions(-) create mode 100644 InvenTree/track/migrations/0003_auto_20180415_0147.py create mode 100644 InvenTree/track/migrations/0004_parttrackinginfo_user.py create mode 100644 InvenTree/track/templates/track/index.html diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 099de2fc05..47d4caf7c5 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -19,6 +19,8 @@ from django.conf.urls.static import static 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 track.urls import unique_urls, part_track_urls @@ -71,8 +73,8 @@ urlpatterns = [ url(r'^part/', include(part_urls)), url(r'^stock/', include(stock_urls)), - url(r'^supplier/', include(supplier_urls)), + url(r'^track/', include(tracking_urls)), url(r'^api-doc/', include_docs_urls(title='InvenTree API')), diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index e59a75a520..2277f24f77 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -77,7 +77,7 @@ part_urls = [ # Top level part list (display top level parts and categories) 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'), ] diff --git a/InvenTree/track/migrations/0003_auto_20180415_0147.py b/InvenTree/track/migrations/0003_auto_20180415_0147.py new file mode 100644 index 0000000000..ee74a6c253 --- /dev/null +++ b/InvenTree/track/migrations/0003_auto_20180415_0147.py @@ -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), + ), + ] diff --git a/InvenTree/track/migrations/0004_parttrackinginfo_user.py b/InvenTree/track/migrations/0004_parttrackinginfo_user.py new file mode 100644 index 0000000000..76ddb5e2a3 --- /dev/null +++ b/InvenTree/track/migrations/0004_parttrackinginfo_user.py @@ -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), + ), + ] diff --git a/InvenTree/track/models.py b/InvenTree/track/models.py index 4be11184d2..a3ead6affe 100644 --- a/InvenTree/track/models.py +++ b/InvenTree/track/models.py @@ -2,32 +2,19 @@ from __future__ import unicode_literals from rest_framework.exceptions import ValidationError from django.utils.translation import ugettext as _ 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 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): """ A unique instance of a Part object. Used for tracking parts based on serial numbers, and tracking all events in the life of a part """ - objects = UniquePartManager() - class Meta: # Cannot have multiple parts with same serial number unique_together = ('part', 'serial') @@ -48,6 +35,7 @@ class UniquePart(models.Model): PART_IN_STOCK = 10 PART_SHIPPED = 20 PART_RETURNED = 30 + PART_REPAIRED = 35 PART_DAMAGED = 40 PART_DESTROYED = 50 @@ -56,6 +44,7 @@ class UniquePart(models.Model): PART_IN_STOCK: _("In stock"), PART_SHIPPED: _("Shipped"), PART_RETURNED: _("Returned"), + PART_REPAIRED: _("Repaired"), PART_DAMAGED: _("Damaged"), PART_DESTROYED: _("Destroyed") } @@ -73,5 +62,11 @@ class PartTrackingInfo(models.Model): """ part = models.ForeignKey(UniquePart, on_delete=models.CASCADE, related_name='tracking_info') + 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) diff --git a/InvenTree/track/templates/track/index.html b/InvenTree/track/templates/track/index.html new file mode 100644 index 0000000000..87eb68e411 --- /dev/null +++ b/InvenTree/track/templates/track/index.html @@ -0,0 +1,31 @@ +{% include "base.html" %} + +{% block content %} + +

Part Tracking

+ + + +{% if is_paginated %} + +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/track/urls.py b/InvenTree/track/urls.py index 37327b1ada..7dc359f341 100644 --- a/InvenTree/track/urls.py +++ b/InvenTree/track/urls.py @@ -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 -part_track_urls = [ +""" +TODO - Implement JSON API for part serial number tracking +part_track_api_urls = [ url(r'^(?P[0-9]+)/?$', api.PartTrackingDetail.as_view(), name='parttrackinginfo-detail'), url(r'^\?.*/?$', api.PartTrackingList.as_view()), url(r'^$', api.PartTrackingList.as_view()) ] -unique_urls = [ +unique_api_urls = [ # Detail for a single unique part url(r'^(?P[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()), ] +""" + +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'), +] \ No newline at end of file diff --git a/InvenTree/track/views.py b/InvenTree/track/views.py index e69de29bb2..ad473fbab7 100644 --- a/InvenTree/track/views.py +++ b/InvenTree/track/views.py @@ -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') \ No newline at end of file