Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Background reports #9199

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
10 changes: 5 additions & 5 deletions .github/workflows/qc_checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ jobs:
INVENTREE_PYTHON_TEST_PASSWORD: testpassword
INVENTREE_SITE_URL: http://127.0.0.1:12345
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_LOG_LEVEL: WARNING

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # [email protected]
Expand Down Expand Up @@ -358,7 +358,7 @@ jobs:
INVENTREE_DB_HOST: "127.0.0.1"
INVENTREE_DB_PORT: 5432
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_LOG_LEVEL: WARNING
INVENTREE_CONSOLE_LOG: false
INVENTREE_CACHE_HOST: localhost
INVENTREE_PLUGINS_ENABLED: true
Expand Down Expand Up @@ -408,7 +408,7 @@ jobs:
INVENTREE_DB_HOST: "127.0.0.1"
INVENTREE_DB_PORT: 3306
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_LOG_LEVEL: WARNING
INVENTREE_CONSOLE_LOG: false
INVENTREE_PLUGINS_ENABLED: true

Expand Down Expand Up @@ -455,7 +455,7 @@ jobs:
INVENTREE_DB_HOST: "127.0.0.1"
INVENTREE_DB_PORT: 5432
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_LOG_LEVEL: WARNING
INVENTREE_PLUGINS_ENABLED: false

services:
Expand Down Expand Up @@ -498,7 +498,7 @@ jobs:
INVENTREE_DB_ENGINE: sqlite3
INVENTREE_DB_NAME: /home/runner/work/InvenTree/db.sqlite3
INVENTREE_DEBUG: true
INVENTREE_LOG_LEVEL: INFO
INVENTREE_LOG_LEVEL: WARNING
INVENTREE_PLUGINS_ENABLED: false

steps:
Expand Down
6 changes: 5 additions & 1 deletion src/backend/InvenTree/InvenTree/api_version.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
"""InvenTree API version information."""

# InvenTree API version
INVENTREE_API_VERSION = 317
INVENTREE_API_VERSION = 318

"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""


INVENTREE_API_TEXT = """

v318 - 2025-03-03 : https://github.com/inventree/InvenTree/pull/9199
- Add detail API endpoint for the LabelOutput model
- Add detail API endpoint for the ReportOutput model

v317 - 2025-02-26 : https://github.com/inventree/InvenTree/pull/9143
- Default 'overdue' field to False in Build serializer
- Add allow_null to various fields in Build, Settings, Order, Part, and Stock serializers
Expand Down
4 changes: 2 additions & 2 deletions src/backend/InvenTree/plugin/base/label/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,12 @@ def print_labels(
)

# Update the progress of the print job
output.progress += int(100 / N)
output.progress += 1
output.save()

# Mark the output as complete
output.complete = True
output.progress = 100
output.progress = N

# Add in the generated file (if applicable)
output.output = self.get_generated_file(**print_args)
Expand Down
43 changes: 26 additions & 17 deletions src/backend/InvenTree/plugin/builtin/labels/inventree_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing import cast

from django.conf import settings
from django.http import JsonResponse
from django.utils.translation import gettext_lazy as _

from rest_framework import serializers
Expand Down Expand Up @@ -79,34 +78,44 @@ def print_labels(self, label: LabelTemplate, output, items, request, **kwargs):
'printing_options': kwargs['printing_options'].get('driver_options', {}),
}

# save the current used printer as last used printer
# only the last ten used printers are saved so that this list doesn't grow infinitely
last_used_printers = get_last_used_printers(request.user)
machine_pk = str(machine.pk)
if machine_pk in last_used_printers:
last_used_printers.remove(machine_pk)
last_used_printers.insert(0, machine_pk)
InvenTreeUserSetting.set_setting(
'LAST_USED_PRINTING_MACHINES',
','.join(last_used_printers[:10]),
user=request.user,
)
if output:
user = output.user
elif request:
user = request.user
else:
user = None

# Save the current used printer as last used printer
# Only the last ten used printers are saved so that this list doesn't grow infinitely
if user and user.is_authenticated:
last_used_printers = get_last_used_printers(user)
machine_pk = str(machine.pk)
if machine_pk in last_used_printers:
last_used_printers.remove(machine_pk)
last_used_printers.insert(0, machine_pk)
InvenTreeUserSetting.set_setting(
'LAST_USED_PRINTING_MACHINES',
','.join(last_used_printers[:10]),
user=user,
)

offload_task(
call_machine_function,
machine.pk,
'print_labels',
label,
items,
output=output,
force_sync=settings.TESTING or driver.USE_BACKGROUND_WORKER,
group='plugin',
**print_kwargs,
)

return JsonResponse({
'success': True,
'message': f'{len(items)} labels printed',
})
# Inform the user that the process has been offloaded to the printer
if output:
output.output = None
output.complete = True
output.save()

class PrintingOptionsSerializer(serializers.Serializer):
"""Printing options serializer that adds a machine select and the machines options."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ def print_labels(

idx += n_cells

# Update printing progress
output.progress += 1
output.save()

if len(pages) == 0:
raise ValidationError(_('No labels were generated'))

Expand All @@ -152,7 +156,7 @@ def print_labels(

output.output = ContentFile(document, 'labels.pdf')

output.progress = 100
output.progress = n_labels
output.complete = True
output.save()

Expand Down
94 changes: 78 additions & 16 deletions src/backend/InvenTree/report/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,16 +194,32 @@ def post(self, request, *args, **kwargs):

def print(self, template, items_to_print, plugin, request):
"""Print this label template against a number of provided items."""
import report.tasks
from InvenTree.tasks import offload_task

if plugin_serializer := plugin.get_printing_options_serializer(
request, data=request.data, context=self.get_serializer_context()
):
plugin_serializer.is_valid(raise_exception=True)

output = template.print(
items_to_print,
plugin,
# Generate a new LabelOutput object to print against
output = report.models.LabelOutput.objects.create(
template=template,
plugin=plugin.slug,
user=request.user,
progress=0,
items=len(items_to_print),
complete=False,
output=None,
)

offload_task(
report.tasks.print_labels,
template.pk,
[item.pk for item in items_to_print],
output.pk,
plugin.slug,
options=(plugin_serializer.data if plugin_serializer else {}),
request=request,
)

output.refresh_from_db()
Expand Down Expand Up @@ -255,8 +271,30 @@ def post(self, request, *args, **kwargs):
return self.print(template, instances, request)

def print(self, template, items_to_print, request):
"""Print this report template against a number of provided items."""
output = template.print(items_to_print, request)
"""Print this report template against a number of provided items.

This functionality is offloaded to the background worker process,
which will update the status of the ReportOutput object as it progresses.
"""
import report.tasks
from InvenTree.tasks import offload_task

# Generate a new ReportOutput object
output = report.models.ReportOutput.objects.create(
template=template,
user=request.user,
progress=0,
items=len(items_to_print),
complete=False,
output=None,
)

item_ids = [item.pk for item in items_to_print]

# Offload the task to the background worker
offload_task(report.tasks.print_reports, template.pk, item_ids, output.pk)

output.refresh_from_db()

return Response(
report.serializers.ReportOutputSerializer(output).data, status=201
Expand Down Expand Up @@ -317,24 +355,36 @@ class TemplateOutputMixin:
ordering_field_aliases = {'model_type': 'template__model_type'}


class LabelOutputList(
TemplatePermissionMixin, TemplateOutputMixin, BulkDeleteMixin, ListAPI
):
"""List endpoint for LabelOutput objects."""
class LabelOutputMixin(TemplatePermissionMixin, TemplateOutputMixin):
"""Mixin class for a label output API endpoint."""

queryset = report.models.LabelOutput.objects.all()
serializer_class = report.serializers.LabelOutputSerializer


class ReportOutputList(
TemplatePermissionMixin, TemplateOutputMixin, BulkDeleteMixin, ListAPI
):
"""List endpoint for ReportOutput objects."""
class LabelOutputList(LabelOutputMixin, BulkDeleteMixin, ListAPI):
"""List endpoint for LabelOutput objects."""


class LabelOutputDetail(LabelOutputMixin, RetrieveUpdateDestroyAPI):
"""Detail endpoint for LabelOutput objects."""


class ReportOutputMixin(TemplatePermissionMixin, TemplateOutputMixin):
"""Mixin class for a report output API endpoint."""

queryset = report.models.ReportOutput.objects.all()
serializer_class = report.serializers.ReportOutputSerializer


class ReportOutputList(ReportOutputMixin, BulkDeleteMixin, ListAPI):
"""List endpoint for ReportOutput objects."""


class ReportOutputDetail(ReportOutputMixin, RetrieveUpdateDestroyAPI):
"""Detail endpoint for ReportOutput objects."""


label_api_urls = [
# Printing endpoint
path('print/', LabelPrint.as_view(), name='api-label-print'),
Expand Down Expand Up @@ -364,7 +414,12 @@ class ReportOutputList(
# Label outputs
path(
'output/',
include([path('', LabelOutputList.as_view(), name='api-label-output-list')]),
include([
path(
'<int:pk>/', LabelOutputDetail.as_view(), name='api-label-output-detail'
),
path('', LabelOutputList.as_view(), name='api-label-output-list'),
]),
),
]

Expand Down Expand Up @@ -397,7 +452,14 @@ class ReportOutputList(
# Generated report outputs
path(
'output/',
include([path('', ReportOutputList.as_view(), name='api-report-output-list')]),
include([
path(
'<int:pk>/',
ReportOutputDetail.as_view(),
name='api-report-output-detail',
),
path('', ReportOutputList.as_view(), name='api-report-output-list'),
]),
),
# Report assets
path(
Expand Down
Loading
Loading