From bc04ca3727e7aec31ca59ac6a980ce27f3b34763 Mon Sep 17 00:00:00 2001 From: James Newlands Date: Tue, 17 Apr 2018 23:05:22 +1000 Subject: [PATCH 1/4] First rough pass at adding customer orders model and some views/templates/admin stuff for same --- InvenTree/InvenTree/settings.py | 1 + InvenTree/InvenTree/urls.py | 3 + .../migrations/0004_auto_20180417_2127.py | 20 +++++ InvenTree/customer_orders/__init__.py | 0 InvenTree/customer_orders/admin.py | 15 ++++ InvenTree/customer_orders/apps.py | 5 ++ .../migrations/0001_initial.py | 37 ++++++++++ .../migrations/0002_auto_20180417_2205.py | 73 +++++++++++++++++++ .../customer_orders/migrations/__init__.py | 0 InvenTree/customer_orders/models.py | 64 ++++++++++++++++ .../templates/customer_orders/index.html | 25 +++++++ InvenTree/customer_orders/tests.py | 3 + InvenTree/customer_orders/urls.py | 9 +++ InvenTree/customer_orders/views.py | 8 ++ .../migrations/0011_auto_20180417_2127.py | 21 ++++++ 15 files changed, 284 insertions(+) create mode 100644 InvenTree/build/migrations/0004_auto_20180417_2127.py create mode 100644 InvenTree/customer_orders/__init__.py create mode 100644 InvenTree/customer_orders/admin.py create mode 100644 InvenTree/customer_orders/apps.py create mode 100644 InvenTree/customer_orders/migrations/0001_initial.py create mode 100644 InvenTree/customer_orders/migrations/0002_auto_20180417_2205.py create mode 100644 InvenTree/customer_orders/migrations/__init__.py create mode 100644 InvenTree/customer_orders/models.py create mode 100644 InvenTree/customer_orders/templates/customer_orders/index.html create mode 100644 InvenTree/customer_orders/tests.py create mode 100644 InvenTree/customer_orders/urls.py create mode 100644 InvenTree/customer_orders/views.py create mode 100644 InvenTree/stock/migrations/0011_auto_20180417_2127.py diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 6ce09ad104..fe22396242 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -51,6 +51,7 @@ INSTALLED_APPS = [ 'stock.apps.StockConfig', 'supplier.apps.SupplierConfig', 'build.apps.BuildConfig', + 'customer_orders.apps.CustomerOrdersConfig' ] MIDDLEWARE = [ diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index da9e2573a9..2fbfba3e0d 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -13,6 +13,8 @@ from supplier.urls import supplier_urls from build.urls import build_urls +from customer_orders.urls import customer_orders_urls + from django.conf import settings from django.conf.urls.static import static @@ -71,6 +73,7 @@ urlpatterns = [ url(r'^stock/', include(stock_urls)), url(r'^supplier/', include(supplier_urls)), url(r'^build/', include(build_urls)), + url(r'^customer-orders/', include(customer_orders_urls)), url(r'^admin/', admin.site.urls), url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')), diff --git a/InvenTree/build/migrations/0004_auto_20180417_2127.py b/InvenTree/build/migrations/0004_auto_20180417_2127.py new file mode 100644 index 0000000000..3898af57ea --- /dev/null +++ b/InvenTree/build/migrations/0004_auto_20180417_2127.py @@ -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), + ), + ] diff --git a/InvenTree/customer_orders/__init__.py b/InvenTree/customer_orders/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/InvenTree/customer_orders/admin.py b/InvenTree/customer_orders/admin.py new file mode 100644 index 0000000000..f2919066ca --- /dev/null +++ b/InvenTree/customer_orders/admin.py @@ -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) \ No newline at end of file diff --git a/InvenTree/customer_orders/apps.py b/InvenTree/customer_orders/apps.py new file mode 100644 index 0000000000..7196157c41 --- /dev/null +++ b/InvenTree/customer_orders/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CustomerOrdersConfig(AppConfig): + name = 'customer_orders' diff --git a/InvenTree/customer_orders/migrations/0001_initial.py b/InvenTree/customer_orders/migrations/0001_initial.py new file mode 100644 index 0000000000..64f76be5ff --- /dev/null +++ b/InvenTree/customer_orders/migrations/0001_initial.py @@ -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')]), + ), + ] diff --git a/InvenTree/customer_orders/migrations/0002_auto_20180417_2205.py b/InvenTree/customer_orders/migrations/0002_auto_20180417_2205.py new file mode 100644 index 0000000000..44de420e53 --- /dev/null +++ b/InvenTree/customer_orders/migrations/0002_auto_20180417_2205.py @@ -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'), + ), + ] diff --git a/InvenTree/customer_orders/migrations/__init__.py b/InvenTree/customer_orders/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/InvenTree/customer_orders/models.py b/InvenTree/customer_orders/models.py new file mode 100644 index 0000000000..93171fe2a7 --- /dev/null +++ b/InvenTree/customer_orders/models.py @@ -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") + diff --git a/InvenTree/customer_orders/templates/customer_orders/index.html b/InvenTree/customer_orders/templates/customer_orders/index.html new file mode 100644 index 0000000000..4c49b9d019 --- /dev/null +++ b/InvenTree/customer_orders/templates/customer_orders/index.html @@ -0,0 +1,25 @@ +{% extends "base.html" %} +{% load static %} + +{% block content %} + +{% if customer_orders.all|length > 0 %} +

Customer Orders

+ + + + + + + {% for order in customer_orders %} + + + + + + {% endfor %} +
Internal RefCustomerCustomer Ref
{{ order.internal_ref }}{{ order.customer }}{{ order.customer_ref }}
+ +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/customer_orders/tests.py b/InvenTree/customer_orders/tests.py new file mode 100644 index 0000000000..7ce503c2dd --- /dev/null +++ b/InvenTree/customer_orders/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/InvenTree/customer_orders/urls.py b/InvenTree/customer_orders/urls.py new file mode 100644 index 0000000000..fd734eee51 --- /dev/null +++ b/InvenTree/customer_orders/urls.py @@ -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'), +] \ No newline at end of file diff --git a/InvenTree/customer_orders/views.py b/InvenTree/customer_orders/views.py new file mode 100644 index 0000000000..16f9112c5c --- /dev/null +++ b/InvenTree/customer_orders/views.py @@ -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' diff --git a/InvenTree/stock/migrations/0011_auto_20180417_2127.py b/InvenTree/stock/migrations/0011_auto_20180417_2127.py new file mode 100644 index 0000000000..d9f8c2364d --- /dev/null +++ b/InvenTree/stock/migrations/0011_auto_20180417_2127.py @@ -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)]), + ), + ] From f2dc7380c291c72035fbb5955a3268d6d3e667dd Mon Sep 17 00:00:00 2001 From: James Newlands Date: Tue, 17 Apr 2018 23:07:55 +1000 Subject: [PATCH 2/4] Merge in some migrations from master --- .../build/migrations/0008_merge_20180417_2307.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 InvenTree/build/migrations/0008_merge_20180417_2307.py diff --git a/InvenTree/build/migrations/0008_merge_20180417_2307.py b/InvenTree/build/migrations/0008_merge_20180417_2307.py new file mode 100644 index 0000000000..70b385da04 --- /dev/null +++ b/InvenTree/build/migrations/0008_merge_20180417_2307.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2018-04-17 13:07 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('build', '0004_auto_20180417_2127'), + ('build', '0007_auto_20180417_1025'), + ] + + operations = [ + ] From 121315f15e74db84bc62ca7676e5052f45feb5bb Mon Sep 17 00:00:00 2001 From: James Newlands Date: Tue, 17 Apr 2018 23:10:06 +1000 Subject: [PATCH 3/4] Add link to table of orders to nav bar --- InvenTree/part/templates/navbar.html | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/part/templates/navbar.html b/InvenTree/part/templates/navbar.html index db8cae6aa7..3b3eeeeb52 100644 --- a/InvenTree/part/templates/navbar.html +++ b/InvenTree/part/templates/navbar.html @@ -9,6 +9,7 @@
  • Parts
  • Stock
  • Suppliers
  • +
  • Customer Orders
  • \ No newline at end of file From 6434bfc24ac8c98a3ad9f956a0f88a92d3dae8a4 Mon Sep 17 00:00:00 2001 From: James Newlands Date: Tue, 17 Apr 2018 23:12:35 +1000 Subject: [PATCH 4/4] Split table of customer orders into separate template from customer orders index page --- .../customer_orders/customer_orders_list.html | 14 ++++++++++++++ .../templates/customer_orders/index.html | 16 +--------------- 2 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 InvenTree/customer_orders/templates/customer_orders/customer_orders_list.html diff --git a/InvenTree/customer_orders/templates/customer_orders/customer_orders_list.html b/InvenTree/customer_orders/templates/customer_orders/customer_orders_list.html new file mode 100644 index 0000000000..c33d615951 --- /dev/null +++ b/InvenTree/customer_orders/templates/customer_orders/customer_orders_list.html @@ -0,0 +1,14 @@ + + + + + + + {% for order in customer_orders %} + + + + + + {% endfor %} +
    Internal RefCustomerCustomer Ref
    {{ order.internal_ref }}{{ order.customer }}{{ order.customer_ref }}
    \ No newline at end of file diff --git a/InvenTree/customer_orders/templates/customer_orders/index.html b/InvenTree/customer_orders/templates/customer_orders/index.html index 4c49b9d019..2987484fc7 100644 --- a/InvenTree/customer_orders/templates/customer_orders/index.html +++ b/InvenTree/customer_orders/templates/customer_orders/index.html @@ -5,21 +5,7 @@ {% if customer_orders.all|length > 0 %}

    Customer Orders

    - - - - - - - {% for order in customer_orders %} - - - - - - {% endfor %} -
    Internal RefCustomerCustomer Ref
    {{ order.internal_ref }}{{ order.customer }}{{ order.customer_ref }}
    - + {% include "customer_orders/customer_orders_list.html" with customer_orders=customer_orders %} {% endif %} {% endblock %} \ No newline at end of file