2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-01 13:06:45 +00:00

Updates for purchase order line items

- Display list of line items
- Add a form to create a new line item
This commit is contained in:
Oliver Walters 2019-06-05 20:59:30 +10:00
parent e199ed2281
commit be6b1ae2f8
9 changed files with 274 additions and 12 deletions

23
InvenTree/order/forms.py Normal file
View File

@ -0,0 +1,23 @@
"""
Django Forms for interacting with Order objects
"""
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from InvenTree.forms import HelperForm
from .models import PurchaseOrder, PurchaseOrderLineItem
class EditPurchaseOrderLineItemForm(HelperForm):
class Meta:
model = PurchaseOrderLineItem
fields = [
'order',
'part',
'quantity',
'reference',
'received'
]

View File

@ -0,0 +1,20 @@
# Generated by Django 2.2 on 2019-06-05 10:36
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('company', '0005_auto_20190525_2356'),
('order', '0004_purchaseorder_status'),
]
operations = [
migrations.AddField(
model_name='purchaseorderlineitem',
name='part',
field=models.ForeignKey(blank=True, help_text='Supplier part', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='orders', to='company.SupplierPart'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2 on 2019-06-05 10:56
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('company', '0005_auto_20190525_2356'),
('order', '0005_purchaseorderlineitem_part'),
]
operations = [
migrations.AlterUniqueTogether(
name='purchaseorderlineitem',
unique_together={('order', 'part')},
),
]

View File

@ -4,7 +4,7 @@ from django.contrib.auth.models import User
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from company.models import Company from company.models import Company, SupplierPart
from InvenTree.status_codes import OrderStatus from InvenTree.status_codes import OrderStatus
@ -108,11 +108,24 @@ class PurchaseOrderLineItem(OrderLineItem):
""" """
order = models.ForeignKey(PurchaseOrder, on_delete=models.CASCADE, class Meta:
unique_together = (
('order', 'part')
)
order = models.ForeignKey(
PurchaseOrder, on_delete=models.CASCADE,
related_name='lines', related_name='lines',
help_text=_('Purchase Order') help_text=_('Purchase Order')
) )
# TODO - foreign key references to part and stockitem objects # TODO - foreign key references to part and stockitem objects
part = models.ForeignKey(
SupplierPart, on_delete=models.SET_NULL,
blank=True, null=True,
related_name='orders',
help_text=_("Supplier part"),
)
received = models.PositiveIntegerField(default=0, help_text=_('Number of items received')) received = models.PositiveIntegerField(default=0, help_text=_('Number of items received'))

View File

@ -1,9 +1,106 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% load static %}
Purchase Order: {{ order.reference }} {% block page_title %}
<br><hr> InvenTree | {{ order }}
Description: {{ order.description }} {% endblock %}
{% block content %}
<div class='row'>
<div class='col-sm-6'>
<div class='media'>
<div class='media-left'>
<img class='part-thumb'
{% if order.supplier.image %}
src="{{ order.supplier.image.url }}"
{% else %}
src="{% static 'img/blank_image.png' %}"
{% endif %}
/>
</div>
<div class='media-body'>
<h4>{{ order }}</h4>
<p>{{ order.description }}</p>
{% if order.URL %}
<a href="{{ order.URL }}">{{ order.URL }}</a>
{% endif %}
</div>
</div>
</div>
<div class='col-sm-6'>
<table class='table'>
<tr>
<td>Status</td>
<td>{% include "order/order_status.html" %}</td>
</tr>
<tr>
<td>Created</td>
<td>{{ order.creation_date }}</td>
</tr>
<tr>
<td>Created By</td>
<td>{{ order.created_by }}</td>
</tr>
{% if order.issue_date %}
<tr>
<td>Issued</td>
<td>{{ order.issue_date }}</td>
</tr>
{% endif %}
</table>
</div>
</div>
<hr>
<h4>Order Items</h4>
<button type='button' class='btn btn-default' id='new-po-line'>Add Line Item</button>
<table class='table table-striped table-condensed' id='po-lines-table'>
<tr>
<th data-field='line'>Line</th>
<th data-field='part'>Part</th>
<th data-field='reference'>Reference</th>
<th data-field='quantity'>Quantity</th>
<th data-field='received'>Received</th>
</tr>
{% for line in order.lines.all %}
<tr>
<td>{{ forloop.counter }}</td>
<td></td>
<td>{{ line.reference }}</td>
<td>{{ line.quantity }}</td>
<td>{{ line.received }}</td>
</tr>
{% endfor %}
</table>
{% if order.notes %}
<hr>
<div class='panel panel-default'>
<div class='panel-heading'><b>Notes</b></div>
<div class='panel-body'>{{ order.notes }}</div>
</div>
{% endif %}
{% endblock %}
{% block js_ready %}
$('#new-po-line').click(function() {
launchModalForm("{% url 'po-line-item-create' %}",
{
reload: true,
data: {
order: {{ order.id }},
},
}
);
});
$("#po-lines-table").bootstrapTable({
});
{% endblock %} {% endblock %}

View File

@ -2,6 +2,10 @@
{% load static %} {% load static %}
{% block page_title %}
InvenTree | Purchase Orders
{% endblock %}
{% block content %} {% block content %}
<h4>Purchase Orders</h4> <h4>Purchase Orders</h4>

View File

@ -14,11 +14,18 @@ purchase_order_detail_urls = [
url(r'^.*$', views.PurchaseOrderDetail.as_view(), name='purchase-order-detail'), url(r'^.*$', views.PurchaseOrderDetail.as_view(), name='purchase-order-detail'),
] ]
po_line_urls = [
url(r'^new/', views.POLineItemCreate.as_view(), name='po-line-item-create'),
]
purchase_order_urls = [ purchase_order_urls = [
# Display detail view for a single purchase order # Display detail view for a single purchase order
url(r'^(?P<pk>\d+)/', include(purchase_order_detail_urls)), url(r'^(?P<pk>\d+)/', include(purchase_order_detail_urls)),
url(r'^line/', include(po_line_urls)),
# Display complete list of purchase orders # Display complete list of purchase orders
url(r'^.*$', views.PurchaseOrderIndex.as_view(), name='purchase-order-index'), url(r'^.*$', views.PurchaseOrderIndex.as_view(), name='purchase-order-index'),
] ]

View File

@ -7,7 +7,10 @@ from __future__ import unicode_literals
from django.views.generic import DetailView, ListView from django.views.generic import DetailView, ListView
from .models import PurchaseOrder from .models import PurchaseOrder, PurchaseOrderLineItem
from .forms import EditPurchaseOrderLineItemForm
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
from InvenTree.status_codes import OrderStatus from InvenTree.status_codes import OrderStatus
@ -19,8 +22,8 @@ class PurchaseOrderIndex(ListView):
template_name = 'order/purchase_orders.html' template_name = 'order/purchase_orders.html'
context_object_name = 'orders' context_object_name = 'orders'
def get_context_data(self): def get_context_data(self, **kwargs):
ctx = super().get_context_data() ctx = super().get_context_data(**kwargs)
ctx['OrderStatus'] = OrderStatus ctx['OrderStatus'] = OrderStatus
@ -33,3 +36,76 @@ class PurchaseOrderDetail(DetailView):
context_object_name = 'order' context_object_name = 'order'
queryset = PurchaseOrder.objects.all().prefetch_related('lines') queryset = PurchaseOrder.objects.all().prefetch_related('lines')
template_name = 'order/purchase_order_detail.html' template_name = 'order/purchase_order_detail.html'
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['OrderStatus'] = OrderStatus
return ctx
class POLineItemCreate(AjaxCreateView):
""" AJAX view for creating a new PurchaseOrderLineItem object
"""
model = PurchaseOrderLineItem
context_object_name = 'line'
form_class = EditPurchaseOrderLineItemForm
ajax_template_name = 'modal_form.html'
ajax_form_action = 'Add Line Item'
def get_form(self):
""" Limit choice options based on the selected order, etc
"""
form = super().get_form()
order_id = form['order'].value()
try:
order = PurchaseOrder.objects.get(id=order_id)
query = form.fields['part'].queryset
# Only allow parts from the selected supplier
query = query.filter(supplier=order.supplier.id)
print('limiting queryset')
form.fields['part'].queryset = query
except PurchaseOrder.DoesNotExist:
print('error')
pass
return form
def get_initial(self):
""" Extract initial data for the line item.
- The 'order' will be passed as a query parameter
- Use this to set the 'order' field and limit the options for 'part'
"""
initials = super().get_initial().copy()
order_id = self.request.GET.get('order', None)
if order_id:
try:
order = PurchaseOrder.objects.get(id=order_id)
initials['order'] = order
except PurchaseOrder.DoesNotExist:
pass
return initials
class POLineItemEdit(AjaxUpdateView):
model = PurchaseOrderLineItem
form_class = EditPurchaseOrderLineItemForm
ajax_template_name = 'modal_form.html'
ajax_form_action = 'Edit Line Item'

View File

@ -297,6 +297,10 @@
margin-bottom: 5px; margin-bottom: 5px;
} }
.panel-body {
padding: 10px;
}
.panel-group .panel { .panel-group .panel {
border-radius: 2px; border-radius: 2px;
} }