Container type import from excel files

This commit is contained in:
Dirk Jahnke 2022-04-01 19:28:10 +02:00
parent 9396cd4903
commit 61edb7e538
7 changed files with 209 additions and 11 deletions

View File

@ -30,9 +30,6 @@
</div> </div>
</div> </div>
<table>
</table>
<!-- Action buttons --> <!-- Action buttons -->
<div class="row"> <div class="row">

View File

@ -0,0 +1,18 @@
{% extends "base.html" %}
{% load static %}
{% block title %}Edit Container: {{ container.named_id }}{% endblock %}
{% block content %}
<div class="container">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<div>
<input type="submit" class="btn btn-primary" value="Save">
<a class="btn btn-primary" href="{% url 'container:list' %}">Container List</a>
</div>
</form>
</div>
{% endblock content %}

View File

@ -0,0 +1,63 @@
{% extends "base.html" %}
{% load static %}
{% block title %}Container Type Import{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-12">
<h2>Container Type Import: {{ import_file }}</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% if not import_file %}
<input type="file" id="import_file" name="import_file" class="form-control">
{% endif %}
{% if import_file %}
<label for="first_data_row">First data row:</label><input type="number" min="1" max="10" size="3" name="first_data_row" id="first_data_row" value="1"><br />
<input type="submit" class="btn btn-primary" value="import" name="import-cmd">
{% else %}
<input type="submit" class="btn btn-primary" value="show" name="show-cmd">
{% endif %}
<div>
{% if import_file %}
File to be imported: {{ import_file }}
{% endif %}
<br>
{% for file in FILES %}
File: {{ file.name }} ({{ file.size }} Bytes)
{% endfor %}
</div>
<div>
<table class="table">
<tr>
<td>Row</td>
<td>ID</td>
<td>Description</td>
<td>Width</td>
<td>Length</td>
<td>Height</td>
<td>Cover</td>
<td>Inner Width</td>
<td>Inner Length</td>
<td>Inner Height</td>
<td>Available</td>
<td>Stores Container</td>
</tr>
{% for row in excel_data %}
<tr>
{% for col in row %}
<td>{{ col }}<input type="hidden" value="{{ col }}" name="data_{{ row.0 }}_{{ forloop.counter }}"></td>
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
</form>
</div>
</div>
</div>
{% endblock content %}

View File

@ -22,7 +22,7 @@
<tbody> <tbody>
{% for ctype in container_type_list %} {% for ctype in container_type_list %}
<tr> <tr>
<td><a href="{% url 'container:container_type_detail' ctype.id %}"><div>{{ ctype.named_id }}</div></a></td> <td><a href="{% url 'container:container_type_update' ctype.id %}"><div>{{ ctype.named_id }}</div></a></td>
<td><div>{{ ctype.description }}</div></td> <td><div>{{ ctype.description }}</div></td>
<td><div>{% if ctype.width %}{{ ctype.width }}x{{ ctype.length }}x{{ ctype.height }}{% endif %}</div></td> <td><div>{% if ctype.width %}{{ ctype.width }}x{{ ctype.length }}x{{ ctype.height }}{% endif %}</div></td>
<td><div>{% if ctype.inner_width %}{{ ctype.inner_width }}x{{ ctype.inner_length }}x{{ ctype.inner_height }}{% endif %}</div></td> <td><div>{% if ctype.inner_width %}{{ ctype.inner_width }}x{{ ctype.inner_length }}x{{ ctype.inner_height }}{% endif %}</div></td>
@ -66,6 +66,9 @@
<a class="btn btn-primary" href="{% url 'container:add' %}" role="button">+ Container</a> <a class="btn btn-primary" href="{% url 'container:add' %}" role="button">+ Container</a>
<a class="btn btn-primary" href="{% url 'asset:add' %}" role="button">+ Asset</a> <a class="btn btn-primary" href="{% url 'asset:add' %}" role="button">+ Asset</a>
</div> </div>
<div class="col-sm-12">
<a class="btn btn-primary" href="{% url 'container:container_type_import' %}" role="button">Import Container Types</a>
</div>
</div> </div>
<!-- End Action buttons --> <!-- End Action buttons -->

View File

@ -1,19 +1,21 @@
from django.urls import path from django.urls import path
from container.views import ContainerListView, ContainerUpdateView, ContainerCreateView, ContainerDetailView, ContainerDeleteView, ContainerPrintLabelView from container.views import ContainerListView, ContainerUpdateView, ContainerCreateView, ContainerDetailView, ContainerDeleteView, ContainerPrintLabelView, ContainerImportView
from container.views import ContainerTypeListView, ContainerTypeDetailView, ContainerTypeCreateView, ContainerTypeUpdateView, ContainerTypeDeleteView from container.views import ContainerTypeListView, ContainerTypeDetailView, ContainerTypeCreateView, ContainerTypeUpdateView, ContainerTypeDeleteView, ContainerTypeImportView
app_name = 'container' app_name = 'container'
urlpatterns = [ urlpatterns = [
path('', ContainerListView.as_view(), name='list'), path('', ContainerListView.as_view(), name='list'),
path('<int:pk>/', ContainerDetailView.as_view(), name='detail'), path('<int:pk>/', ContainerDetailView.as_view(), name='detail'),
path('add/', ContainerCreateView.as_view(), name='add'), path('add/', ContainerCreateView.as_view(), name='add'),
path('import/', ContainerImportView.as_view(), name='container_import'),
path('edit/<int:pk>/', ContainerUpdateView.as_view(), name='update'), path('edit/<int:pk>/', ContainerUpdateView.as_view(), name='update'),
path('label/<int:pk>/', ContainerPrintLabelView.as_view(), name='print_label'), path('label/<int:pk>/', ContainerPrintLabelView.as_view(), name='print_label'),
path('delete/<int:pk>/', ContainerDeleteView.as_view(), name='delete'), path('delete/<int:pk>/', ContainerDeleteView.as_view(), name='delete'),
path('type/', ContainerTypeListView.as_view(), name='container_type_list'), path('type/', ContainerTypeListView.as_view(), name='container_type_list'),
path('type/<int:pk>/', ContainerTypeDetailView.as_view(), name='container_type_detail'), path('type/<int:pk>/', ContainerTypeDetailView.as_view(), name='container_type_detail'),
path('type/add/', ContainerTypeCreateView.as_view(), name='container_type_add'), path('type/add/', ContainerTypeCreateView.as_view(), name='container_type_add'),
path('type/import/', ContainerTypeImportView.as_view(), name='container_type_import'),
path('type/edit/<int:pk>/', ContainerTypeUpdateView.as_view(), name='container_type_update'), path('type/edit/<int:pk>/', ContainerTypeUpdateView.as_view(), name='container_type_update'),
path('type/delete/<int:pk>/', ContainerTypeDeleteView.as_view(), name='container_type_delete'), path('type/delete/<int:pk>/', ContainerTypeDeleteView.as_view(), name='container_type_delete'),
] ]

View File

@ -1,6 +1,7 @@
from django.views import generic from django.views import generic
from .models import Container, ContainerType from .models import Container, ContainerType
import logging, json import logging, json, re
from django.core.exceptions import ObjectDoesNotExist
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -29,6 +30,23 @@ class ContainerCreateView(generic.CreateView):
return super().form_valid(form) return super().form_valid(form)
class ContainerImportView(generic.TemplateView):
template_name = 'container_import.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if 'start_import' in self.request.POST:
context['import_file'] = self.request.POST['import_file']
return context
def get(self, *args, **kwargs):
return super().get(self.request, args, **kwargs)
def post(self):
return super().render_to_response(self)
class ContainerUpdateView(generic.UpdateView): class ContainerUpdateView(generic.UpdateView):
model = Container model = Container
# template_name = 'container/detail.html' # template_name = 'container/detail.html'
@ -87,8 +105,8 @@ class ContainerPrintLabelView(generic.DetailView):
context['barcode_img'] = pil_to_html_imgdata(label_image, fmt='PNG') context['barcode_img'] = pil_to_html_imgdata(label_image, fmt='PNG')
context['logs'].append('Image created') context['logs'].append('Image created')
if num_copies > 0: if num_copies > 0:
#from brother_ql.devicedependent import models, label_type_specs, label_sizes # from brother_ql.devicedependent import models, label_type_specs, label_sizes
#from brother_ql.devicedependent import ENDLESS_LABEL, DIE_CUT_LABEL, ROUND_DIE_CUT_LABEL # from brother_ql.devicedependent import ENDLESS_LABEL, DIE_CUT_LABEL, ROUND_DIE_CUT_LABEL
from brother_ql import BrotherQLRaster, create_label from brother_ql import BrotherQLRaster, create_label
from brother_ql.backends import backend_factory, guess_backend from brother_ql.backends import backend_factory, guess_backend
@ -127,7 +145,7 @@ class ContainerPrintLabelView(generic.DetailView):
be_class = backend_factory(selected_backend)['backend_class'] be_class = backend_factory(selected_backend)['backend_class']
be = be_class(config['PRINTER']['PRINTER']) be = be_class(config['PRINTER']['PRINTER'])
context['logs'].append('Got backend driver') context['logs'].append('Got backend driver')
for i in range(1,num_copies): for i in range(1, num_copies):
be.write(qlr.data) be.write(qlr.data)
context['logs'].append('Data sent to printer') context['logs'].append('Data sent to printer')
@ -163,7 +181,7 @@ class ContainerTypeDetailView(generic.DetailView):
class ContainerTypeCreateView(generic.CreateView): class ContainerTypeCreateView(generic.CreateView):
model = ContainerType model = ContainerType
# template_name = 'container/detail.html' template_name = 'container/container_type_form.html'
fields = ['named_id', 'description', 'width', 'length', 'height', 'inner_width', 'inner_length', 'inner_height', fields = ['named_id', 'description', 'width', 'length', 'height', 'inner_width', 'inner_length', 'inner_height',
'has_cover', 'contains_container'] 'has_cover', 'contains_container']
@ -176,6 +194,7 @@ class ContainerTypeCreateView(generic.CreateView):
class ContainerTypeUpdateView(generic.UpdateView): class ContainerTypeUpdateView(generic.UpdateView):
model = ContainerType model = ContainerType
# template_name = 'container/detail.html' # template_name = 'container/detail.html'
template_name = 'container/container_type_form.html'
fields = ['named_id', 'description', 'width', 'length', 'height', 'inner_width', 'inner_length', 'inner_height', fields = ['named_id', 'description', 'width', 'length', 'height', 'inner_width', 'inner_length', 'inner_height',
'has_cover', 'contains_container'] 'has_cover', 'contains_container']
@ -186,3 +205,95 @@ class ContainerTypeUpdateView(generic.UpdateView):
class ContainerTypeDeleteView(generic.DetailView): class ContainerTypeDeleteView(generic.DetailView):
model = ContainerType model = ContainerType
class ContainerTypeImportView(generic.TemplateView):
template_name = 'container/container_type_import.html'
def get_context_data(self, **kwargs):
# print('get_context_data')
context = super().get_context_data(**kwargs)
context['import_file'] = self.request.FILES['import_file'] if 'import_file' in self.request.FILES else ''
if context['import_file'] != '':
# if 'show-cmd' in self.request.POST:
# print('Show button pressed')
context['filename'] = self.request.FILES['import_file'].name
context['filesize'] = self.request.FILES['import_file'].size
context['content_type'] = self.request.FILES['import_file'].content_type
import openpyxl as excel
workbook = excel.open(self.request.FILES['import_file'])
sheet = workbook.active
sheet_data = []
row_num = 1
for row in sheet.values:
row_data = [row_num]
row_num = row_num + 1
for col in row:
row_data.append(col if col is not None else '')
sheet_data.append(row_data)
context['excel_data'] = sheet_data
return context
def post(self, request):
# print('POST method executed')
if 'import-cmd' in request.POST:
# print('import button pressed')
first_data_row = int(request.POST['first_data_row']) if 'first_data_row' in request.POST else 0
# context['first_data_row'] = first_data_row
# print('first_data_row=%d' % first_data_row)
p = re.compile(r'^data_(\d+)_(\d+)$')
import_data = {}
for key in request.POST:
match = p.match(key)
if match:
key_row, key_col = match.group(1, 2)
row_num = int(key_row)
col_num = int(key_col)
if row_num >= first_data_row:
value = request.POST[key]
if row_num not in import_data:
import_data[row_num] = {}
import_data[row_num][col_num] = value
# print('Value row=%d, col=%d, value=%s' % (row_num, col_num, value))
for col in import_data:
c7 = import_data[col][7]
c12 = import_data[col][12]
has_cover = True if c7 == 'j' or c7 == 'J' or c7 == 'y' or c7 == 'Y' else False
contains_container = True if c12 == 'j' or c12 == 'J' or c12 == 'y' or c12 == 'Y' else False
try:
ct = ContainerType.objects.get(named_id=import_data[col][2])
# Update entry
ct.description = None if import_data[col][3] == '' else import_data[col][3]
ct.width = None if import_data[col][4] == '' else import_data[col][4]
ct.length = None if import_data[col][5] == '' else import_data[col][5]
ct.height = None if import_data[col][6] == '' else import_data[col][6]
ct.inner_width = None if import_data[col][8] == '' else import_data[col][8]
ct.inner_length = None if import_data[col][9] == '' else import_data[col][9]
ct.inner_height = None if import_data[col][10] == '' else import_data[col][10]
ct.has_cover = has_cover
ct.contains_container = contains_container
ct.changed_by_id = request.user.id
# print('Updated %s' % import_data[col][2])
except ObjectDoesNotExist:
# Create a new entry
ct = ContainerType.objects.create(
named_id=import_data[col][2],
description=None if import_data[col][3] == '' else import_data[col][3],
width=None if import_data[col][4] == '' else import_data[col][4],
length=None if import_data[col][5] == '' else import_data[col][5],
height=None if import_data[col][6] == '' else import_data[col][6],
inner_width=None if import_data[col][8] == '' else import_data[col][8],
inner_length=None if import_data[col][9] == '' else import_data[col][9],
inner_height=None if import_data[col][10] == '' else import_data[col][10],
has_cover=has_cover,
contains_container=contains_container,
created_by_id=request.user.id,
changed_by_id=request.user.id
)
# print('Created %s' % import_data[col][2])
finally:
ct.save()
return super().get(request)

View File

@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.2/ref/settings/
""" """
from pathlib import Path from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
@ -128,3 +129,6 @@ STATICFILES_DIRS = [
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')