Added pages for /supplier/

- Supplier list view
- Supplier detail view /supplier/<pk>/
- Added create / edit / delete views for supplier
- Supplier part detail at /supplier/part/<pk>
- Added create / edit / delete views for supplier part
- Added some templates to make things easier
This commit is contained in:
Oliver 2018-04-15 15:35:01 +10:00
parent 8232baeed7
commit ab4b91cd46
25 changed files with 321 additions and 119 deletions

View File

@ -12,7 +12,7 @@ class EditPartForm(forms.ModelForm):
self.helper = FormHelper()
self.helper.form_id = 'id-edit-part-form'
self.helper.form_class = 'blueForms'
#self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
#self.helper.form_action = 'submit'
@ -38,7 +38,7 @@ class EditCategoryForm(forms.ModelForm):
self.helper = FormHelper()
self.helper.form_id = 'id-edit-part-form'
self.helper.form_class = 'blueForms'
#self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
#self.helper.form_action = 'submit'

View File

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class='panel panel-primary'>
<div class='panel-heading'>
{% block obj_title %}
Object title goes here
{% endblock %}
</div>
<div class='panel-body'>
{% load crispy_forms_tags %}
{% crispy form %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,26 @@
{% extends "base.html" %}
{% block content %}
<div class="panel panel-danger">
<div class="panel-heading">
{% block del_title %}
Deletion title goes here
{% endblock %}
</div>
<div class="panel-body">
<p><b>This is a permanent action and cannot be undone.</b></p>
{% block del_body %}
Deletion body goes here
{% endblock %}
<form action="" method="post">{% csrf_token %}
<input type="submit" name='confirm' value="Confirm" />
<input type="submit" name="cancel" value="Cancel" />
</form>
</div>
</div>
{% endblock %}

View File

@ -1,12 +1,10 @@
{% extends 'base.html' %}
{% extends 'delete_obj.html' %}
{% block content %}
{% block del_title %}
Are you sure you want to delete category '{{ category.name }}'?
{% endblock %}
<div class="panel panel-danger">
<div class="panel-heading">Are you sure you want to delete category '{{ category.name }}'?</div>
<div class='panel-body'>
<p><b>Deleting this category is a permanent action and cannot be undone.</b></p>
{% block del_body %}
{% if category.children.all|length > 0 %}
<p>This category contains {{ category.children.all|length }} child categories.<br>
@ -40,11 +38,4 @@
</ul>
{% endif %}
<form action="" method="post">{% csrf_token %}
<input type="submit" name='confirm' value="Confirm" />
<input type="submit" name="cancel" value="Cancel" />
</form>
</div>
</div>
{% endblock %}

View File

@ -17,10 +17,10 @@
<div class='container-fluid'>
<a href="{% url 'category-create' %}?category={{ category.id }}">
<button class="btn btn-default">New Category</button>
<button class="btn btn-success">New Category</button>
</a>
<a href="{% url 'part-create' %}?category={{ category.id }}">
<button class="btn btn-default">New Part</button>
<button class="btn btn-success">New Part</button>
</a>
<a href="{% url 'category-edit' category.id %}">

View File

@ -1,16 +1,5 @@
{% extends "base.html" %}
{% block content %}
{% include "part/cat_link.html" with category=category %}
<div class='panel panel-primary'>
<div class='panel-heading'>Edit details for category '{{ category.name }}'</div>
<div class='panel-body'>
{% load crispy_forms_tags %}
{% crispy form %}
</div>
</div>
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Edit category '{{ category.name }}'
{% endblock %}

View File

@ -1,16 +1,5 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
{% include "part/cat_link.html" with category=category %}
<div class='panel panel-primary'>
<div class='panel-heading'>Create a new part category{% if category %} in category '{{ category.name }}'{% endif %}</div>
<div class='panel-body'>
{% load crispy_forms_tags %}
{% crispy form %}
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Create a new part category{% if category %} in category '{{ category.name }}'{% endif %}
{% endblock %}

View File

@ -1,18 +1,5 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
{% include "part/cat_link.html" with category=category %}
<div class='panel panel-primary'>
<div class='panel-heading'>Create a new part{% if category %} in category '{{ category.name }}'{% endif %}</div>
<div class='panel-body'>
{% load crispy_forms_tags %}
{% crispy form %}
</div>
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Create a new part{% if category %} in category '{{ category.name }}'{% endif %}
{% endblock %}

View File

@ -1,12 +1,11 @@
{% extends 'part/part_base.html' %}
{% extends "delete_obj.html" %}
{% block details %}
<div class="panel panel-danger">
<div class="panel-heading">Are you sure you want to delete part '{{ part.name }}'?</div>
<div class="panel-body">
{% block del_title %}
Are you sure you want to delete part '{{ part.name }}'?
{% endblock %}
<p><b>Deleting this part is a permanent action and cannot be undone.</b></p>
{% block del_body %}
{% if part.usedInCount > 0 %}
<p>This part is used in BOMs for {{ part.usedInCount }} other parts. If you delete this part, the BOMs for the following parts will be updated:
@ -41,11 +40,4 @@
<p>There are {{ part.serials.all|length }} unique parts tracked for '{{ part.name }}'. Deleting this part will permanently remove this tracking information.</p>
{% endif %}
<form action="" method="post">{% csrf_token %}
<input type="submit" name='confirm' value="Confirm" />
<input type="submit" name="cancel" value="Cancel" />
</form>
</div>
</div>
{% endblock %}

View File

@ -1,15 +1,5 @@
{% extends "part/part_base.html" %}
{% block details %}
<div class='panel panel-primary'>
<div class='panel-heading'>Edit details for part '{{ part.name }}'</div>
<div class='panel-body'>
{% load crispy_forms_tags %}
{% crispy form %}
</div>
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Edit details for part '{{ part.name }}'
{% endblock %}

View File

@ -11,10 +11,10 @@
<div class='container-fluid'>
<a href="{% url 'category-create' %}">
<button class="btn btn-default">New Category</button>
<button class="btn btn-success">New Category</button>
</a>
<a href="{% url 'part-create' %}">
<button class="btn btn-default">New Part</button>
<button class="btn btn-success">New Part</button>
</a>
</div>
{% endblock %}

View File

@ -4,8 +4,6 @@ from django.views.generic.base import RedirectView
from . import views
from . import api
app_nam='part'
# URL list for part category API
part_cat_api_urls = [
@ -63,7 +61,7 @@ part_category_urls = [
part_urls = [
# Create a new category
url(r'^new_category/?', views.CategoryCreate.as_view(), name='category-create'),
url(r'^category/new/?', views.CategoryCreate.as_view(), name='category-create'),
# Create a new part
url(r'^new/?', views.PartCreate.as_view(), name='part-create'),

View File

@ -0,0 +1,57 @@
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from .models import Supplier, SupplierPart
class EditSupplierForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(EditSupplierForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-edit-part-form'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
#self.helper.form_action = 'submit'
self.helper.add_input(Submit('submit', 'Submit'))
class Meta:
model = Supplier
fields = [
'name',
'description',
'website',
'address',
'phone',
'email',
'contact',
'notes'
]
class EditSupplierPartForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(EditSupplierPartForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-edit-part-form'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
#self.helper.form_action = 'submit'
self.helper.add_input(Submit('submit', 'Submit'))
class Meta:
model = SupplierPart
fields = [
'supplier',
'SKU',
'part',
'description',
'URL',
'manufacturer',
'MPN',
]

View File

@ -10,7 +10,9 @@ from part.models import Part
class Supplier(Company):
""" Represents a manufacturer or supplier
"""
pass
def get_absolute_url(self):
return "/supplier/{id}/".format(id=self.id)
class Manufacturer(Company):
@ -32,12 +34,15 @@ class SupplierPart(models.Model):
- A Part may be available from multiple suppliers
"""
def get_absolute_url(self):
return "/supplier/part/{id}/".format(id=self.id)
class Meta:
unique_together = ('part', 'supplier', 'SKU')
# Link to an actual part
# The part will have a field 'supplier_parts' which links to the supplier part options
part = models.ForeignKey(Part, null=True, blank=True, on_delete=models.CASCADE,
part = models.ForeignKey(Part, null=True, blank=True, on_delete=models.SET_NULL,
related_name='supplier_parts')
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE,
@ -46,7 +51,7 @@ class SupplierPart(models.Model):
SKU = models.CharField(max_length=100)
manufacturer = models.ForeignKey(Manufacturer, blank=True, null=True, on_delete=models.CASCADE)
manufacturer = models.ForeignKey(Manufacturer, blank=True, null=True, on_delete=models.SET_NULL)
MPN = models.CharField(max_length=100, blank=True)
URL = models.URLField(blank=True)

View File

@ -0,0 +1,5 @@
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Create a new supplier
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends "delete_obj.html" %}
{% block del_title %}
Are you sure you want to delete supplier '{{ supplier.name }}'?
{% endblock %}
{% block del_body %}
{% if supplier.parts.all|length > 0 %}
<p>There are {{ supplier.parts.all|length }} parts sourced from this supplier.<br>
If this supplier is deleted, these child categories will also be deleted.</p>
<ul class='list-group'>
{% for part in supplier.parts.all %}
<li class='list-group-item'><b>{{ part.SKU }}</b><i>Part - {{ part.part.name }}</i></li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}

View File

@ -6,6 +6,12 @@
<div class="col-sm-6">
<h3>{{ supplier.name }}</h3>
<p>{{ supplier.description }}</p>
<p><a href="{% url 'supplier-edit' supplier.id %}">
<button class="btn btn-info">Edit supplier details</button>
</a></p>
<p><a href="{% url 'supplier-delete' supplier.id %}">
<button class="btn btn-danger">Delete supplier</button>
</a></p>
</div>
<div class="col-sm-6">
<table class="table">
@ -38,7 +44,7 @@
</div>
</div>
{% if supplier.parts.all|length > 0 %}
<h4>Supplier Parts</h3>
<table class="table table-striped">
<tr>
<th>SKU</th>
@ -50,14 +56,20 @@
{% for part in supplier.parts.all %}
<tr>
<td><a href="{% url 'supplier-part-detail' part.id %}">{{ part.SKU }}</a></td>
<td><a href="{% url 'part-detail' part.part.id %}">{{ part.part.name }}</a></td>
<td>
{% if part.part %}
<a href="{% url 'part-detail' part.part.id %}">{{ part.part.name }}</a>
{% endif %}
</td>
<td>Manufacturer name goes here</td>
<td>MPN goes here</td>
<td>{{ part.URL }}</td>
{% endfor %}
</table>
{% else %}
There are currently no parts sourced from this supplier.
{% endif %}
<div class='container-fluid'>
<a href="{% url 'supplier-part-create' %}?supplier={{ supplier.id }}">
<button class="btn btn-success">New Supplier Part</button>
</a>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Edit details for supplier '{{ supplier.name }}'
{% endblock %}

View File

@ -19,4 +19,10 @@
{% endfor %}
</ul>
<div class='container-fluid'>
<a href="{% url 'supplier-create' %}">
<button class="btn btn-success">New Supplier</button>
</a>
</div>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Create a new supplier part
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends 'delete_obj.html' %}
{% block del_title %}
Are you sure you want to delete this supplier part?
{% endblock %}

View File

@ -2,13 +2,39 @@
{% block content %}
<ul>
<li>Part: <a href="{% url 'part-detail' part.part.id %}">{{ part.part.name }}</a></li>
<li>Supplier: <a href="{% url 'supplier-detail' part.supplier.id %}">{{ part.supplier.name }}</a></li>
<li>SKU: {{ part.SKU }}</li>
<li>Manufacturer name goes here</li>
<li>MPN goes here</li>
<li>URL: {{ part.URL }}</li>
</ul>
<h3>Supplier part information</h3>
<table class="table">
<tr><td>SKU</td><td>{{ part.SKU }}</tr></tr>
<tr><td>Supplier</td><td><a href="{% url 'supplier-detail' part.supplier.id %}">{{ part.supplier.name }}</a></td></tr>
<tr>
<td>Part</td>
<td>
{% if part.part %}
<a href="{% url 'part-detail' part.part.id %}">{{ part.part.name }}</a>
{% endif %}
</td>
</tr>
{% if part.URL %}
<tr><td><URL></td><td><a href="{{ part.URL }}">{{ part.URL }}</a></td></tr>
{% endif %}
{% if part.description %}
<tr><td>Description</td><td>{{ part.description }}</td></tr>
{% endif %}
{% if part.manufacturer %}
<tr><td>Manufacturer</td><td>TODO</td></tr>
<tr><td>MPN</td><td>TODO</td></tr>
{% endif %}
</table>
<br>
<p><a href="{% url 'supplier-part-edit' part.id %}">
<button class="btn btn-info">Edit supplier details</button>
</a></p>
<p><a href="{% url 'supplier-part-delete' part.id %}">
<button class="btn btn-danger">Delete supplier part</button>
</a></p>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends "create_edit_obj.html" %}
{% block obj_title %}
Edit supplier part '{{ part.SKU }}'
{% endblock %}

View File

@ -49,14 +49,25 @@ supplier_api_urls = [
"""
supplier_detail_urls = [
#url(r'edit/?', views.SupplierEdit.as_view(), name='supplier-edit'),
#url(r'delete/?', views.SupplierDelete.as_view(), name='supplier-delete'),
url(r'edit/?', views.SupplierEdit.as_view(), name='supplier-edit'),
url(r'delete/?', views.SupplierDelete.as_view(), name='supplier-delete'),
url(r'^.*$', views.SupplierDetail.as_view(), name='supplier-detail'),
]
supplier_part_detail_urls = [
url(r'edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'),
url(r'delete/?', views.SupplierPartDelete.as_view(), name='supplier-part-delete'),
url('^.*$', views.SupplierPartDetail.as_view(), name='supplier-part-detail'),
]
supplier_urls = [
url(r'^part/(?P<pk>\d+)/', views.partDetail, name='supplier-part-detail'),
url(r'part/(?P<pk>\d+)/', include(supplier_part_detail_urls)),
url(r'part/new/?', views.SupplierPartCreate.as_view(), name='supplier-part-create'),
url(r'new/?', views.SupplierCreate.as_view(), name='supplier-create'),
url(r'^(?P<pk>\d+)/', include(supplier_detail_urls)),

View File

@ -7,6 +7,9 @@ from django.views.generic.edit import UpdateView, DeleteView, CreateView
from .models import Supplier, SupplierPart
from .forms import EditSupplierForm
from .forms import EditSupplierPartForm
class SupplierIndex(ListView):
model = Supplier
template_name = 'supplier/index.html'
@ -18,16 +21,75 @@ class SupplierIndex(ListView):
class SupplierDetail(DetailView):
context_obect = 'supplier'
context_obect_name = 'supplier'
template_name = 'supplier/detail.html'
queryset = Supplier.objects.all()
model = Supplier
def partDetail(request, pk):
""" The supplier part-detail page shows detailed information
on a particular supplier part
"""
class SupplierEdit(UpdateView):
model = Supplier
form_class = EditSupplierForm
template_name = 'supplier/edit.html'
context_object_name = 'supplier'
part = get_object_or_404(SupplierPart, pk=pk)
return render(request, 'supplier/partdetail.html', {'part': part})
class SupplierCreate(CreateView):
model = Supplier
form_class = EditSupplierForm
template_name = "supplier/create.html"
class SupplierDelete(DeleteView):
model = Supplier
success_url = '/supplier/'
template_name = 'supplier/delete.html'
def post(self, request, *args, **kwargs):
if 'confirm' in request.POST:
return super(SupplierDelete, self).post(request, *args, **kwargs)
else:
return HttpResponseRedirect(self.get_object().get_absolute_url())
class SupplierPartDetail(DetailView):
model = SupplierPart
template_name = 'supplier/partdetail.html'
context_object_name = 'part'
queryset = SupplierPart.objects.all()
class SupplierPartEdit(UpdateView):
model = SupplierPart
template_name = 'supplier/partedit.html'
context_object_name = 'part'
form_class = EditSupplierPartForm
class SupplierPartCreate(CreateView):
model = SupplierPart
form_class = EditSupplierPartForm
template_name = 'supplier/partcreate.html'
context_object_name = 'part'
def get_initial(self):
initials = super(SupplierPartCreate, self).get_initial().copy()
supplier_id = self.request.GET.get('supplier', None)
if supplier_id:
initials['supplier'] = get_object_or_404(Supplier, pk=supplier_id)
return initials
class SupplierPartDelete(DeleteView):
model = SupplierPart
success_url = '/supplier/'
template_name = 'supplier/partdelete.html'
def post(self, request, *args, **kwargs):
if 'confirm' in request.POST:
return super(SupplierPartDelete, self).post(request, *args, **kwargs)
else:
return HttpResponseRedirect(self.get_object().get_absolute_url())