Skip to content
Snippets Groups Projects
Verified Commit ab9c4e66 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Add models for print jobs and allow triggering them

parent 506f6c2d
No related branches found
No related tags found
1 merge request!3Setup printer stuff
Pipeline #59955 passed
from django import forms from django import forms
from django.utils.translation import gettext as _
from django_select2.forms import ModelSelect2Widget from django_select2.forms import ModelSelect2Widget
from material import Layout
from aleksis.apps.kort.models import Card, CardPrinter from aleksis.apps.kort.models import Card, CardPrinter
...@@ -25,3 +27,15 @@ class CardPrinterForm(forms.ModelForm): ...@@ -25,3 +27,15 @@ class CardPrinterForm(forms.ModelForm):
class Meta: class Meta:
model = CardPrinter model = CardPrinter
fields = ["name", "location", "description"] fields = ["name", "location", "description"]
class PrinterSelectForm(forms.Form):
layout = Layout("printer")
printer = forms.ModelChoiceField(queryset=None, label=_("Card Printer"), required=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
printers = CardPrinter.objects.all()
self.fields["printer"].queryset = printers
if printers.count() == 1:
self.fields["printer"].initial = printers.first()
# Generated by Django 3.2.12 on 2022-03-15 18:57
from django.conf import settings
import django.contrib.sites.managers
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
('sites', '0002_alter_domain_unique'),
('kort', '0006_auto_20220310_2003'),
]
operations = [
migrations.AlterField(
model_name='card',
name='pdf_file',
field=models.FileField(blank=True, default='', upload_to='cards/', validators=[django.core.validators.FileExtensionValidator(['pdf'])], verbose_name='PDF file'),
preserve_default=False,
),
migrations.AlterField(
model_name='cardprinter',
name='oauth2_application',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='card_printers', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL, verbose_name='OAuth2 application'),
),
migrations.CreateModel(
name='CardPrintJob',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', models.JSONField(default=dict, editable=False)),
('status', models.CharField(choices=[('registered', 'Registered'), ('in_progress', 'In progress'), ('finished', 'Finished')], default='registered', max_length=255, verbose_name='Status')),
('status_text', models.TextField(blank=True, verbose_name='Status text')),
('card', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='kort.card', verbose_name='Card')),
('printer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='kort.cardprinter', verbose_name='Printer')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
],
options={
'verbose_name': 'Card print job',
'verbose_name_plural': 'Card print jobs',
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
),
]
...@@ -50,6 +50,7 @@ class PrintStatus(models.TextChoices): ...@@ -50,6 +50,7 @@ class PrintStatus(models.TextChoices):
REGISTERED = "registered", _("Registered") REGISTERED = "registered", _("Registered")
IN_PROGRESS = "in_progress", _("In progress") IN_PROGRESS = "in_progress", _("In progress")
FINISHED = "finished", _("Finished") FINISHED = "finished", _("Finished")
FAILED = "failed", _("Failed")
class CardPrinter(ExtensibleModel): class CardPrinter(ExtensibleModel):
...@@ -187,6 +188,13 @@ class Card(ExtensibleModel): ...@@ -187,6 +188,13 @@ class Card(ExtensibleModel):
return True return True
return generate_card_pdf.delay(self.pk) return generate_card_pdf.delay(self.pk)
def print_card(self, printer: CardPrinter):
job = CardPrintJob(card=self, printer=printer)
job.save()
if self.chip_number:
self.generate_pdf()
return job
def __str__(self): def __str__(self):
if self.chip_number: if self.chip_number:
return f"{self.person} ({self.chip_number})" return f"{self.person} ({self.chip_number})"
...@@ -195,3 +203,22 @@ class Card(ExtensibleModel): ...@@ -195,3 +203,22 @@ class Card(ExtensibleModel):
class Meta: class Meta:
verbose_name = _("Card") verbose_name = _("Card")
verbose_name_plural = _("Cards") verbose_name_plural = _("Cards")
class CardPrintJob(ExtensibleModel):
printer = models.ForeignKey(
CardPrinter, on_delete=models.CASCADE, verbose_name=_("Printer"), related_name="jobs"
)
card = models.ForeignKey(Card, on_delete=models.CASCADE, verbose_name=_("Card"))
status = models.CharField(
max_length=255,
verbose_name=_("Status"),
choices=PrintStatus.choices,
default=PrintStatus.REGISTERED,
)
status_text = models.TextField(verbose_name=_("Status text"), blank=True)
class Meta:
verbose_name = _("Card print job")
verbose_name_plural = _("Card print jobs")
...@@ -11,6 +11,8 @@ from django_tables2 import ( ...@@ -11,6 +11,8 @@ from django_tables2 import (
Table, Table,
) )
from aleksis.apps.kort.forms import PrinterSelectForm
class CardTable(Table): class CardTable(Table):
"""Table to list cards.""" """Table to list cards."""
...@@ -34,7 +36,9 @@ class CardTable(Table): ...@@ -34,7 +36,9 @@ class CardTable(Table):
) )
def render_actions(self, value, record): def render_actions(self, value, record):
return render_to_string("kort/card/actions.html", dict(pk=value, card=record)) return render_to_string(
"kort/card/actions.html", dict(pk=value, card=record, printer_form=PrinterSelectForm())
)
class CardPrinterTable(Table): class CardPrinterTable(Table):
...@@ -48,6 +52,8 @@ class CardPrinterTable(Table): ...@@ -48,6 +52,8 @@ class CardPrinterTable(Table):
current_status = Column(verbose_name=_("Current status"), accessor=A("pk")) current_status = Column(verbose_name=_("Current status"), accessor=A("pk"))
last_seen_at = DateTimeColumn(verbose_name=_("Last seen at")) last_seen_at = DateTimeColumn(verbose_name=_("Last seen at"))
jobs_count = Column(verbose_name=_("Running jobs"))
actions = Column(verbose_name=_("Actions"), accessor=A("pk")) actions = Column(verbose_name=_("Actions"), accessor=A("pk"))
def render_current_status(self, value, record): def render_current_status(self, value, record):
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
</div> </div>
</div> </div>
<div class="col s12 m12 l6"> <div class="col s12 m12 l6">
{% include "kort/card/print_form.html" %}
{% if card.pdf_file %} {% if card.pdf_file %}
<div id="card-pdf-{{ card.pk }}" style="height: 500px;"></div> <div id="card-pdf-{{ card.pk }}" style="height: 500px;"></div>
<script>PDFObject.embed("{{ card.pdf_file.url }}", "#card-pdf-{{ card.pk }}");</script> <script>PDFObject.embed("{{ card.pdf_file.url }}", "#card-pdf-{{ card.pk }}");</script>
......
{% load material_form i18n %}
<form action="{% url "print_card" card.pk %}" method="get">
<div class="card">
<div class="card-content">
<div class="card-title"><i class="material-icons left iconify"
data-icon="mdi:printer-outline"></i> {% trans "Print card" %}</div>
{% csrf_token %}
{% form form=printer_form %}{% endform %}
</div>
<div class="card-action-light">
<button type="submit" class="btn waves-effect waves-light">
<i class="material-icons left iconify" data-icon="mdi:printer-outline"></i>
{% trans "Print card" %}
</button>
</div>
</div>
</form>
...@@ -74,6 +74,34 @@ ...@@ -74,6 +74,34 @@
<code>kort-client setup {{ printer.config_filename }}</code> <code>kort-client setup {{ printer.config_filename }}</code>
</div> </div>
</div> </div>
{% else %}
<div class="card">
<div class="card-content">
<div class="card-title">{% trans "Print jobs" %}</div>
<table>
<tr>
<th>
{% trans "Card" %}
</th>
<th>
{% trans "Status" %}
</th>
</tr>
{% for job in printer.jobs.all %}
<tr>
<td>
<a href="{% url "card" job.card.pk %}">
{{ job.card }}
</a>
</td>
<td>
{{ job.status }}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
\ No newline at end of file
...@@ -13,6 +13,7 @@ urlpatterns = [ ...@@ -13,6 +13,7 @@ urlpatterns = [
name="generate_card_pdf", name="generate_card_pdf",
), ),
path("cards/<int:pk>/deactivate/", views.CardDeactivateView.as_view(), name="deactivate_card"), path("cards/<int:pk>/deactivate/", views.CardDeactivateView.as_view(), name="deactivate_card"),
path("cards/<int:pk>/print/", views.CardPrintView.as_view(), name="print_card"),
path("cards/<int:pk>/delete/", views.CardDeleteView.as_view(), name="delete_card"), path("cards/<int:pk>/delete/", views.CardDeleteView.as_view(), name="delete_card"),
path("printers/", views.CardPrinterListView.as_view(), name="card_printers"), path("printers/", views.CardPrinterListView.as_view(), name="card_printers"),
path("printers/create/", views.CardPrinterCreateView.as_view(), name="create_card_printer"), path("printers/create/", views.CardPrinterCreateView.as_view(), name="create_card_printer"),
......
import json import json
from django.contrib import messages from django.contrib import messages
from django.db.models import Count, Q
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.views import View from django.views import View
...@@ -12,8 +13,8 @@ from django_tables2 import SingleTableView ...@@ -12,8 +13,8 @@ from django_tables2 import SingleTableView
from reversion.views import RevisionMixin from reversion.views import RevisionMixin
from rules.contrib.views import PermissionRequiredMixin from rules.contrib.views import PermissionRequiredMixin
from aleksis.apps.kort.forms import CardForm, CardPrinterForm from aleksis.apps.kort.forms import CardForm, CardPrinterForm, PrinterSelectForm
from aleksis.apps.kort.models import Card, CardPrinter from aleksis.apps.kort.models import Card, CardPrinter, PrintStatus
from aleksis.apps.kort.tables import CardPrinterTable, CardTable from aleksis.apps.kort.tables import CardPrinterTable, CardTable
from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
from aleksis.core.util.celery_progress import render_progress_page from aleksis.core.util.celery_progress import render_progress_page
...@@ -33,7 +34,16 @@ class TestPDFView(RenderPDFView): ...@@ -33,7 +34,16 @@ class TestPDFView(RenderPDFView):
return context return context
class CardListView(PermissionRequiredMixin, RevisionMixin, SingleTableView): class PrinterSelectMixin:
def get_context_data(self, **kwargs):
print("Called and used?")
context = super().get_context_data(**kwargs)
context["printers"] = CardPrinter.objects.all()
context["printer_form"] = PrinterSelectForm()
return context
class CardListView(PermissionRequiredMixin, RevisionMixin, PrinterSelectMixin, SingleTableView):
"""List view for all cards.""" """List view for all cards."""
permission_required = "core.view_cards_rule" permission_required = "core.view_cards_rule"
...@@ -77,7 +87,31 @@ class CardDeactivateView(PermissionRequiredMixin, RevisionMixin, SingleObjectMix ...@@ -77,7 +87,31 @@ class CardDeactivateView(PermissionRequiredMixin, RevisionMixin, SingleObjectMix
return redirect(self.success_url) return redirect(self.success_url)
class CardDetailView(PermissionRequiredMixin, RevisionMixin, DetailView): class CardPrintView(PermissionRequiredMixin, RevisionMixin, SingleObjectMixin, View):
"""View used to create a print job for a card."""
permission_required = "core.delete_card_rule"
model = Card
success_url = reverse_lazy("cards")
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
self.object = self.get_object()
printer = self.request.GET.get("printer")
printer = get_object_or_404(CardPrinter, pk=printer)
self.object.print_card(printer)
messages.success(
request,
_(
"The print job for the card {} on the printer {} has been created successfully."
).format(self.object.person, printer.name),
)
return redirect(self.success_url)
class CardDetailView(PermissionRequiredMixin, RevisionMixin, PrinterSelectMixin, DetailView):
permission_required = "core.view_card_rule" permission_required = "core.view_card_rule"
model = Card model = Card
template_name = "kort/card/detail.html" template_name = "kort/card/detail.html"
...@@ -122,6 +156,13 @@ class CardPrinterListView(PermissionRequiredMixin, RevisionMixin, SingleTableVie ...@@ -122,6 +156,13 @@ class CardPrinterListView(PermissionRequiredMixin, RevisionMixin, SingleTableVie
model = CardPrinter model = CardPrinter
table_class = CardPrinterTable table_class = CardPrinterTable
def get_queryset(self):
return CardPrinter.objects.all().annotate(
jobs_count=Count(
"jobs", filter=~Q(jobs__status__in=[PrintStatus.FINISHED, PrintStatus.FAILED])
)
)
class CardPrinterCreateView(PermissionRequiredMixin, RevisionMixin, AdvancedCreateView): class CardPrinterCreateView(PermissionRequiredMixin, RevisionMixin, AdvancedCreateView):
"""View used to create a card printer.""" """View used to create a card printer."""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment