Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 31 additions & 25 deletions backend/control/admin.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
from django.contrib import admin

from control.models import Printer, LocalPrinterParams
from control.forms import LocalPrinterParamsForm
# Register your models here.
from control.models import GutenbergJob, PrintingProperties, PrinterPermissions, LocalPrinterParams, Printer, \
JobArtefact


class PrintingPropertiesInline(admin.TabularInline):
model = PrintingProperties


class JobArtefactAdmin(admin.TabularInline):
model = JobArtefact


class GutenbergJobAdmin(admin.ModelAdmin):
inlines = [PrintingPropertiesInline, JobArtefactAdmin]
readonly_fields = ('pages', 'date_created', 'date_processed', 'date_finished')
list_display = ('date_created', 'owner', 'name', 'job_type', 'status', 'pages')
list_filter = ('date_created', 'owner', 'job_type', 'status')


class LocalPrinterParamsInline(admin.StackedInline):
model = LocalPrinterParams
form = LocalPrinterParamsForm


class PrinterPermissionsAdmin(admin.TabularInline):
model = PrinterPermissions
can_delete = False
verbose_name_plural = 'Parametry Drukarki Lokalnej / Manual Duplex'

fieldsets = (
('Ustawienia Podstawowe CUPS', {
'fields': (
'cups_printer_name',
'print_grayscale_param',
'print_color_param',
'print_one_sided_param',
'print_two_sided_long_edge_param',
'print_two_sided_short_edge_param',
)
}),
('Konfiguracja Ręcznego Dupleksu (Manual Duplex)', {
'fields': (
'duplex_first_pass_pages',
'duplex_first_pass_order',
'duplex_second_pass_order',
'duplex_add_blank_page_if_odd',
)
}),
('Instrukcja Przełożenia Papieru dla Użytkownika', {
'fields': (
'duplex_sheet_face',
'duplex_rotate_180',
)
}),
)


class PrinterAdmin(admin.ModelAdmin):
inlines = [LocalPrinterParamsInline, PrinterPermissionsAdmin]
inlines = [LocalPrinterParamsInline]
list_display = ('name', 'display_order')
ordering = ('display_order', 'name')


admin.site.register(Printer, PrinterAdmin)
admin.site.register(GutenbergJob, GutenbergJobAdmin)
108 changes: 108 additions & 0 deletions backend/control/duplex_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from dataclasses import dataclass
from .models import (
OrientationRequested,
PaperFaceOrientation,
DuplexPassOrder,
DuplexPrintOrder,
JobStatus
)

@dataclass
class ManualDuplexInstruction:
face_instruction: str
rotation_instruction: str
face_up: bool
rotate_180: bool
is_landscape: bool


class ManualDuplexPlan:
def __init__(self, first_pass_pages: list[int], second_pass_pages: list[int], needs_blank_page: bool):
self.first_pass_pages = first_pass_pages
self.second_pass_pages = second_pass_pages
self.needs_blank_page = needs_blank_page


def calculate_duplex_pages(total_pages: int, printer_params) -> ManualDuplexPlan:
"""
Oblicza kolejność stron dla pierwszego i drugiego przebiegu druku ręcznego.
"""
needs_blank_page = (total_pages % 2 != 0) and printer_params.duplex_add_blank_page_if_odd
effective_total = total_pages + (1 if needs_blank_page else 0)

all_pages = list(range(1, effective_total + 1))

odd_pages = [p for p in all_pages if p % 2 != 0]
even_pages = [p for p in all_pages if p % 2 == 0]

if printer_params.duplex_first_pass_pages == DuplexPassOrder.ODD_FIRST:
first_pass = odd_pages
second_pass = even_pages
else:
first_pass = even_pages
second_pass = odd_pages

if printer_params.duplex_first_pass_order == DuplexPrintOrder.REVERSE:
first_pass.reverse()

if printer_params.duplex_second_pass_order == DuplexPrintOrder.REVERSE:
second_pass.reverse()

return ManualDuplexPlan(
first_pass_pages=first_pass,
second_pass_pages=second_pass,
needs_blank_page=needs_blank_page
)


def get_duplex_instruction(printer_params, printing_properties=None) -> ManualDuplexInstruction:
face_up = printer_params.duplex_sheet_face == PaperFaceOrientation.FACE_UP
if face_up:
face_text = "Umieść wydrukowane kartki w podajniku ZADRUKOWANĄ STRONĄ DO GÓRY."
else:
face_text = "Umieść wydrukowane kartki w podajniku ZADRUKOWANĄ STRONĄ DO DOŁU."

is_landscape = False
if printing_properties:
is_landscape = printing_properties.orientation_requested == OrientationRequested.LANDSCAPE

should_rotate = printer_params.duplex_rotate_180

if is_landscape:
rotation_text = "Obróć arkusze w poziomie (górna krawędź skierowana do wewnątrz podajnika)."
else:
if should_rotate:
rotation_text = "Obróć cały stos kart o 180 stopni przed włożeniem."
else:
rotation_text = "Włóż papier bez obracania (góra strony skierowana w tę samą stronę)."

return ManualDuplexInstruction(
face_instruction=face_text,
rotation_instruction=rotation_text,
face_up=face_up,
rotate_180=should_rotate,
is_landscape=is_landscape
)


def get_job_duplex_status_info(job):
if not job.printer or not hasattr(job.printer, 'localprinterparams'):
return None

params = job.printer.localprinterparams
props = getattr(job, 'properties', None)

instruction = get_duplex_instruction(params, props)

return {
"job_id": job.id,
"status": job.status,
"requires_user_action": job.status == JobStatus.WAITING_FOR_MANUAL_DUPLEX,
"instructions": {
"face_text": instruction.face_instruction,
"rotation_text": instruction.rotation_instruction,
"face_up": instruction.face_up,
"rotate_180": instruction.rotate_180,
"is_landscape": instruction.is_landscape,
}
}
Loading
Loading