mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-01 13:06:45 +00:00
First rough pass at adding customer orders model and some views/templates/admin stuff for same
This commit is contained in:
parent
960f697d02
commit
bc04ca3727
@ -51,6 +51,7 @@ INSTALLED_APPS = [
|
|||||||
'stock.apps.StockConfig',
|
'stock.apps.StockConfig',
|
||||||
'supplier.apps.SupplierConfig',
|
'supplier.apps.SupplierConfig',
|
||||||
'build.apps.BuildConfig',
|
'build.apps.BuildConfig',
|
||||||
|
'customer_orders.apps.CustomerOrdersConfig'
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -13,6 +13,8 @@ from supplier.urls import supplier_urls
|
|||||||
|
|
||||||
from build.urls import build_urls
|
from build.urls import build_urls
|
||||||
|
|
||||||
|
from customer_orders.urls import customer_orders_urls
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
@ -71,6 +73,7 @@ urlpatterns = [
|
|||||||
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'^build/', include(build_urls)),
|
url(r'^build/', include(build_urls)),
|
||||||
|
url(r'^customer-orders/', include(customer_orders_urls)),
|
||||||
|
|
||||||
url(r'^admin/', admin.site.urls),
|
url(r'^admin/', admin.site.urls),
|
||||||
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
|
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
|
20
InvenTree/build/migrations/0004_auto_20180417_2127.py
Normal file
20
InvenTree/build/migrations/0004_auto_20180417_2127.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2018-04-17 11:27
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('build', '0003_build_part'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='build',
|
||||||
|
name='status',
|
||||||
|
field=models.PositiveIntegerField(choices=[('20', 'Allocated'), ('30', 'Cancelled'), ('40', 'Complete'), ('10', 'Pending')], default=10),
|
||||||
|
),
|
||||||
|
]
|
0
InvenTree/customer_orders/__init__.py
Normal file
0
InvenTree/customer_orders/__init__.py
Normal file
15
InvenTree/customer_orders/admin.py
Normal file
15
InvenTree/customer_orders/admin.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from import_export.admin import ImportExportModelAdmin
|
||||||
|
|
||||||
|
from .models import CustomerOrder, CustomerOrderLine
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerOrderAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CustomerOrderLineAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(CustomerOrder, CustomerOrderAdmin)
|
||||||
|
admin.site.register(CustomerOrderLine, CustomerOrderLineAdmin)
|
5
InvenTree/customer_orders/apps.py
Normal file
5
InvenTree/customer_orders/apps.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerOrdersConfig(AppConfig):
|
||||||
|
name = 'customer_orders'
|
37
InvenTree/customer_orders/migrations/0001_initial.py
Normal file
37
InvenTree/customer_orders/migrations/0001_initial.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2018-04-17 11:27
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('supplier', '0007_auto_20180416_1253'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CustomerOrder',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('customer', models.ForeignKey(blank=True, help_text='Customer that placed this order', null=True, on_delete=django.db.models.deletion.SET_NULL, to='supplier.Customer')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CustomerOrderLine',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('line_number', models.PositiveIntegerField(default=0)),
|
||||||
|
('customer_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customer_orders.CustomerOrder')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='customerorderline',
|
||||||
|
unique_together=set([('customer_order', 'line_number')]),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,73 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2018-04-17 12:05
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('part', '0019_auto_20180416_1249'),
|
||||||
|
('customer_orders', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorder',
|
||||||
|
name='created_date',
|
||||||
|
field=models.DateField(auto_now_add=True, default=django.utils.timezone.now, help_text='Date order entered in system'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorder',
|
||||||
|
name='customer_ref',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=100),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorder',
|
||||||
|
name='internal_ref',
|
||||||
|
field=models.CharField(default=0, max_length=100, unique=True),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorder',
|
||||||
|
name='issued_date',
|
||||||
|
field=models.DateField(blank=True, default=django.utils.timezone.now, help_text='Date order issued by customer'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorder',
|
||||||
|
name='notes',
|
||||||
|
field=models.TextField(blank=True, default='', help_text='Order notes'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorderline',
|
||||||
|
name='notes',
|
||||||
|
field=models.TextField(blank=True, help_text='Line notes'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorderline',
|
||||||
|
name='part',
|
||||||
|
field=models.ForeignKey(default=0, help_text='Part', on_delete=django.db.models.deletion.CASCADE, to='part.Part'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerorderline',
|
||||||
|
name='quantity',
|
||||||
|
field=models.IntegerField(default=1, help_text='Quantity of part'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='customerorderline',
|
||||||
|
name='customer_order',
|
||||||
|
field=models.ForeignKey(help_text='Order this line belongs to', on_delete=django.db.models.deletion.CASCADE, to='customer_orders.CustomerOrder'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='customerorderline',
|
||||||
|
name='line_number',
|
||||||
|
field=models.PositiveIntegerField(default=0, help_text='Line number'),
|
||||||
|
),
|
||||||
|
]
|
0
InvenTree/customer_orders/migrations/__init__.py
Normal file
0
InvenTree/customer_orders/migrations/__init__.py
Normal file
64
InvenTree/customer_orders/models.py
Normal file
64
InvenTree/customer_orders/models.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from supplier.models import Customer
|
||||||
|
from part.models import Part
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerOrder(models.Model):
|
||||||
|
"""
|
||||||
|
An order from a customer, made up of multiple 'lines'
|
||||||
|
"""
|
||||||
|
# Reference 'number' internal to company, must be unique
|
||||||
|
internal_ref = models.CharField(max_length=100, unique=True)
|
||||||
|
|
||||||
|
# TODO: Should the Customer model move to the customer_orders app?
|
||||||
|
# Orders can exist even if the customer doesn't in the database
|
||||||
|
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL,
|
||||||
|
blank=True, null=True, help_text="Customer that placed this order")
|
||||||
|
|
||||||
|
# Reference from customer, if provided
|
||||||
|
customer_ref = models.CharField(max_length=100, blank=True, default="")
|
||||||
|
|
||||||
|
# TODO: Should the customer and customer_ref together be unique?
|
||||||
|
|
||||||
|
# Date the order was entered into system
|
||||||
|
created_date = models.DateField(auto_now_add=True, blank=True, help_text="Date order entered "
|
||||||
|
"in system")
|
||||||
|
|
||||||
|
# Date the order was issued on the paperwork, if provided
|
||||||
|
issued_date = models.DateField(blank=True, help_text="Date order issued by customer")
|
||||||
|
|
||||||
|
# Order notes
|
||||||
|
notes = models.TextField(blank=True, default="", help_text="Order notes")
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerOrderLine(models.Model):
|
||||||
|
"""
|
||||||
|
A line on an order from a customer, corresponding to some quantity of some parts (hopefully just one part per line
|
||||||
|
in a sane world, but maybe not).
|
||||||
|
|
||||||
|
The line describes the Part ordered, but something needs to associate the StockItem assigned, possibly that will
|
||||||
|
be the StockItem itself.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = [
|
||||||
|
('customer_order', 'line_number')
|
||||||
|
]
|
||||||
|
|
||||||
|
# Point to a specific customer order
|
||||||
|
customer_order = models.ForeignKey(CustomerOrder, on_delete=models.CASCADE, help_text="Order this line belongs to")
|
||||||
|
|
||||||
|
line_number = models.PositiveIntegerField(default=0, help_text="Line number")
|
||||||
|
|
||||||
|
# TODO: for now, each line corresponds to some quantity of some part, but in future we might want more flexibility
|
||||||
|
part = models.ForeignKey(Part, blank=True, help_text="Part")
|
||||||
|
|
||||||
|
# TODO: should quantity field here somehow related to quantity field of related part? Views will handle this, right?
|
||||||
|
quantity = models.IntegerField(blank=True, help_text="Quantity of part")
|
||||||
|
|
||||||
|
# Line notes
|
||||||
|
notes = models.TextField(blank=True, help_text="Line notes")
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if customer_orders.all|length > 0 %}
|
||||||
|
<h4>Customer Orders</h4>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>Internal Ref</th>
|
||||||
|
<th>Customer</th>
|
||||||
|
<th>Customer Ref</th>
|
||||||
|
</tr>
|
||||||
|
{% for order in customer_orders %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ order.internal_ref }}</td>
|
||||||
|
<td>{{ order.customer }}</td>
|
||||||
|
<td>{{ order.customer_ref }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
3
InvenTree/customer_orders/tests.py
Normal file
3
InvenTree/customer_orders/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
9
InvenTree/customer_orders/urls.py
Normal file
9
InvenTree/customer_orders/urls.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from django.conf.urls import url, include
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
# URL list for customer orders web interface
|
||||||
|
customer_orders_urls = [
|
||||||
|
# Top level order list
|
||||||
|
url(r'^.*$', views.CustomerOrderIndex.as_view(), name='customer-order-index'),
|
||||||
|
]
|
8
InvenTree/customer_orders/views.py
Normal file
8
InvenTree/customer_orders/views.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from django.views.generic import DetailView, ListView
|
||||||
|
|
||||||
|
from .models import CustomerOrder
|
||||||
|
|
||||||
|
class CustomerOrderIndex(ListView):
|
||||||
|
model = CustomerOrder
|
||||||
|
template_name = 'customer_orders/index.html'
|
||||||
|
context_object_name = 'customer_orders'
|
21
InvenTree/stock/migrations/0011_auto_20180417_2127.py
Normal file
21
InvenTree/stock/migrations/0011_auto_20180417_2127.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2018-04-17 11:27
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('stock', '0010_stockitem_build'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stockitem',
|
||||||
|
name='status',
|
||||||
|
field=models.PositiveIntegerField(choices=[(10, 'OK'), (50, 'Attention needed'), (55, 'Damaged'), (60, 'Destroyed')], default=10, validators=[django.core.validators.MinValueValidator(0)]),
|
||||||
|
),
|
||||||
|
]
|
Loading…
x
Reference in New Issue
Block a user