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:
parent
e199ed2281
commit
be6b1ae2f8
23
InvenTree/order/forms.py
Normal file
23
InvenTree/order/forms.py
Normal 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'
|
||||||
|
]
|
@ -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'),
|
||||||
|
),
|
||||||
|
]
|
18
InvenTree/order/migrations/0006_auto_20190605_2056.py
Normal file
18
InvenTree/order/migrations/0006_auto_20190605_2056.py
Normal 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')},
|
||||||
|
),
|
||||||
|
]
|
@ -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'))
|
||||||
|
@ -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 %}
|
@ -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>
|
||||||
|
@ -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'),
|
||||||
]
|
]
|
||||||
|
@ -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'
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user