karrio-server-documents 2025.5rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of karrio-server-documents might be problematic. Click here for more details.

Files changed (36) hide show
  1. karrio/server/documents/__init__.py +0 -0
  2. karrio/server/documents/admin.py +93 -0
  3. karrio/server/documents/apps.py +13 -0
  4. karrio/server/documents/filters.py +14 -0
  5. karrio/server/documents/generator.py +240 -0
  6. karrio/server/documents/migrations/0001_initial.py +69 -0
  7. karrio/server/documents/migrations/0002_alter_documenttemplate_related_objects.py +18 -0
  8. karrio/server/documents/migrations/0003_rename_related_objects_documenttemplate_related_object.py +18 -0
  9. karrio/server/documents/migrations/0004_documenttemplate_active.py +18 -0
  10. karrio/server/documents/migrations/0005_alter_documenttemplate_description_and_more.py +23 -0
  11. karrio/server/documents/migrations/0006_documenttemplate_metadata.py +25 -0
  12. karrio/server/documents/migrations/0007_alter_documenttemplate_related_object.py +18 -0
  13. karrio/server/documents/migrations/0008_documenttemplate_options.py +26 -0
  14. karrio/server/documents/migrations/__init__.py +0 -0
  15. karrio/server/documents/models.py +61 -0
  16. karrio/server/documents/serializers/__init__.py +4 -0
  17. karrio/server/documents/serializers/base.py +89 -0
  18. karrio/server/documents/serializers/documents.py +9 -0
  19. karrio/server/documents/signals.py +31 -0
  20. karrio/server/documents/tests/__init__.py +6 -0
  21. karrio/server/documents/tests/test_generator.py +455 -0
  22. karrio/server/documents/tests/test_templates.py +318 -0
  23. karrio/server/documents/urls.py +11 -0
  24. karrio/server/documents/utils.py +2486 -0
  25. karrio/server/documents/views/__init__.py +0 -0
  26. karrio/server/documents/views/printers.py +233 -0
  27. karrio/server/documents/views/templates.py +216 -0
  28. karrio/server/graph/schemas/__init__.py +1 -0
  29. karrio/server/graph/schemas/documents/__init__.py +46 -0
  30. karrio/server/graph/schemas/documents/inputs.py +38 -0
  31. karrio/server/graph/schemas/documents/mutations.py +51 -0
  32. karrio/server/graph/schemas/documents/types.py +43 -0
  33. karrio_server_documents-2025.5rc1.dist-info/METADATA +19 -0
  34. karrio_server_documents-2025.5rc1.dist-info/RECORD +36 -0
  35. karrio_server_documents-2025.5rc1.dist-info/WHEEL +5 -0
  36. karrio_server_documents-2025.5rc1.dist-info/top_level.txt +2 -0
File without changes
@@ -0,0 +1,233 @@
1
+ import io
2
+ import sys
3
+ import base64
4
+ import logging
5
+ from django.urls import re_path
6
+ from django.utils import timezone
7
+ from django.http import JsonResponse
8
+ from django.core.files.base import ContentFile
9
+ from django_downloadview import VirtualDownloadView
10
+ from rest_framework import status
11
+
12
+ import karrio.lib as lib
13
+ import karrio.server.openapi as openapi
14
+ import karrio.server.documents.models as models
15
+ import karrio.server.documents.generator as generator
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class TemplateDocsPrinter(VirtualDownloadView):
21
+ def get(
22
+ self,
23
+ request,
24
+ pk: str,
25
+ slug: str,
26
+ **kwargs,
27
+ ):
28
+ try:
29
+ """Generate a document."""
30
+ template = models.DocumentTemplate.objects.get(pk=pk, slug=slug)
31
+ query_params = request.GET.dict()
32
+
33
+ self.document = generator.Documents.generate_template(
34
+ template, query_params, context=request
35
+ )
36
+ self.name = f"{slug}.pdf"
37
+ self.attachment = "download" in query_params
38
+
39
+ response = super(TemplateDocsPrinter, self).get(request, pk, slug, **kwargs)
40
+ response["X-Frame-Options"] = "ALLOWALL"
41
+ return response
42
+ except Exception as e:
43
+ logger.exception(e)
44
+ _, __, exc_traceback = sys.exc_info()
45
+ trace = exc_traceback
46
+ while True:
47
+ trace = trace.tb_next
48
+ if "<template>" in str(trace.tb_frame) or not trace.tb_next:
49
+ break
50
+
51
+ return JsonResponse(
52
+ dict(error=str(e), line=getattr(trace, "tb_lineno", None)),
53
+ status=status.HTTP_409_CONFLICT,
54
+ )
55
+
56
+ def get_file(self):
57
+ return ContentFile(self.document.getvalue(), name=self.name)
58
+
59
+
60
+ class ShipmentDocsPrinter(VirtualDownloadView):
61
+ @openapi.extend_schema(exclude=True)
62
+ def get(
63
+ self,
64
+ request,
65
+ doc: str = "label",
66
+ format: str = "pdf",
67
+ **kwargs,
68
+ ):
69
+ """Retrieve a shipment label."""
70
+ from karrio.server.manager.models import Shipment
71
+
72
+ if doc not in ["label", "invoice"]:
73
+ return JsonResponse(
74
+ dict(error=f"Invalid document type: {doc}"),
75
+ status=status.HTTP_400_BAD_REQUEST,
76
+ )
77
+
78
+ query_params = request.GET.dict()
79
+ self.attachment = "download" in query_params
80
+ ids = query_params.get("shipments", "").split(",")
81
+
82
+ self.format = (format or "").lower()
83
+ self.name = f"{doc}s - {timezone.now()}.{self.format}"
84
+ _queryset = Shipment.objects.filter(id__in=ids)
85
+
86
+ if doc == "label":
87
+ _queryset = _queryset.filter(
88
+ label__isnull=False,
89
+ label_type__contains=self.format.upper(),
90
+ )
91
+ if doc == "invoice":
92
+ _queryset = _queryset.filter(invoice__isnull=False)
93
+
94
+ self.documents = _queryset.values_list(doc, "label_type")
95
+
96
+ response = super(ShipmentDocsPrinter, self).get(
97
+ request, doc, self.format, **kwargs
98
+ )
99
+ response["X-Frame-Options"] = "ALLOWALL"
100
+ return response
101
+
102
+ def get_file(self):
103
+ content = base64.b64decode(
104
+ lib.bundle_base64([doc for doc, _ in self.documents], self.format.upper())
105
+ )
106
+ buffer = io.BytesIO()
107
+ buffer.write(content)
108
+
109
+ return ContentFile(buffer.getvalue(), name=self.name)
110
+
111
+
112
+ class OrderDocsPrinter(VirtualDownloadView):
113
+ @openapi.extend_schema(exclude=True)
114
+ def get(
115
+ self,
116
+ request,
117
+ doc: str = "label",
118
+ format: str = "pdf",
119
+ **kwargs,
120
+ ):
121
+ """Retrieve a shipment label."""
122
+ from karrio.server.orders.models import Order
123
+
124
+ if doc not in ["label", "invoice"]:
125
+ return JsonResponse(
126
+ dict(error=f"Invalid document type: {doc}"),
127
+ status=status.HTTP_400_BAD_REQUEST,
128
+ )
129
+
130
+ query_params = request.GET.dict()
131
+ self.attachment = "download" in query_params
132
+ ids = query_params.get("orders", "").split(",")
133
+
134
+ self.format = (format or "").lower()
135
+ self.name = f"{doc}s - {timezone.now()}.{self.format}"
136
+ _queryset = Order.objects.filter(
137
+ id__in=ids, shipments__id__isnull=False
138
+ ).distinct()
139
+
140
+ if doc == "label":
141
+ _queryset = _queryset.filter(
142
+ shipments__label__isnull=False,
143
+ shipments__label_type__contains=self.format.upper(),
144
+ )
145
+ if doc == "invoice":
146
+ _queryset = _queryset.filter(shipments__invoice__isnull=False)
147
+
148
+ self.documents = list(
149
+ set(_queryset.values_list(f"shipments__{doc}", "shipments__label_type"))
150
+ )
151
+
152
+ response = super(OrderDocsPrinter, self).get(
153
+ request, doc, self.format, **kwargs
154
+ )
155
+ response["X-Frame-Options"] = "ALLOWALL"
156
+ return response
157
+
158
+ def get_file(self):
159
+ content = base64.b64decode(
160
+ lib.bundle_base64([doc for doc, _ in self.documents], self.format.upper())
161
+ )
162
+ buffer = io.BytesIO()
163
+ buffer.write(content)
164
+
165
+ return ContentFile(buffer.getvalue(), name=self.name)
166
+
167
+
168
+ class ManifestDocsPrinter(VirtualDownloadView):
169
+ @openapi.extend_schema(exclude=True)
170
+ def get(
171
+ self,
172
+ request,
173
+ doc: str = "manifest",
174
+ format: str = "pdf",
175
+ **kwargs,
176
+ ):
177
+ """Retrieve a shipment label."""
178
+ from karrio.server.manager.models import Manifest
179
+
180
+ if doc not in ["manifest"]:
181
+ return JsonResponse(
182
+ dict(error=f"Invalid document type: {doc}"),
183
+ status=status.HTTP_400_BAD_REQUEST,
184
+ )
185
+
186
+ query_params = request.GET.dict()
187
+ self.attachment = "download" in query_params
188
+ ids = query_params.get("manifests", "").split(",")
189
+
190
+ self.format = (format or "").lower()
191
+ self.name = f"{doc}s - {timezone.now()}.{self.format}"
192
+ queryset = Manifest.objects.filter(id__in=ids, manifest__isnull=False)
193
+
194
+ self.documents = queryset.values_list(doc, "reference")
195
+
196
+ response = super(ManifestDocsPrinter, self).get(
197
+ request, doc, self.format, **kwargs
198
+ )
199
+ response["X-Frame-Options"] = "ALLOWALL"
200
+ return response
201
+
202
+ def get_file(self):
203
+ content = base64.b64decode(
204
+ lib.bundle_base64([doc for doc, _ in self.documents], self.format.upper())
205
+ )
206
+ buffer = io.BytesIO()
207
+ buffer.write(content)
208
+
209
+ return ContentFile(buffer.getvalue(), name=self.name)
210
+
211
+
212
+ urlpatterns = [
213
+ re_path(
214
+ r"^documents/templates/(?P<pk>\w+).(?P<slug>\w+)",
215
+ TemplateDocsPrinter.as_view(),
216
+ name="templates-documents-print",
217
+ ),
218
+ re_path(
219
+ r"^documents/shipments/(?P<doc>[a-z0-9]+).(?P<format>[a-zA-Z0-9]+)",
220
+ ShipmentDocsPrinter.as_view(),
221
+ name="shipments-documents-print",
222
+ ),
223
+ re_path(
224
+ r"^documents/orders/(?P<doc>[a-z0-9]+).(?P<format>[a-zA-Z0-9]+)",
225
+ OrderDocsPrinter.as_view(),
226
+ name="orders-documents-print",
227
+ ),
228
+ re_path(
229
+ r"^documents/manifests/(?P<doc>[a-z0-9]+).(?P<format>[a-zA-Z0-9]+)",
230
+ ManifestDocsPrinter.as_view(),
231
+ name="manifests-documents-print",
232
+ ),
233
+ ]
@@ -0,0 +1,216 @@
1
+ import base64
2
+ import logging
3
+ import django.urls as urls
4
+ from rest_framework import status
5
+ from rest_framework.request import Request
6
+ from rest_framework.response import Response
7
+ import rest_framework.pagination as pagination
8
+
9
+ import karrio.lib as lib
10
+ import karrio.server.openapi as openapi
11
+ import karrio.server.core.views.api as api
12
+ import karrio.server.documents.models as models
13
+ import karrio.server.documents.generator as generator
14
+ import karrio.server.documents.serializers as serializers
15
+
16
+ ENDPOINT_ID = "&&&&$$" # This endpoint id is used to make operation ids unique make sure not to duplicate
17
+ logger = logging.getLogger(__name__)
18
+ DocumentTemplates = serializers.PaginatedResult(
19
+ "DocumentTemplateList", serializers.DocumentTemplate
20
+ )
21
+
22
+
23
+ class DocumentTemplateList(api.GenericAPIView):
24
+ queryset = models.DocumentTemplate.objects
25
+ pagination_class = type(
26
+ "CustomPagination",
27
+ (pagination.LimitOffsetPagination,),
28
+ dict(default_limit=20),
29
+ )
30
+ serializer_class = DocumentTemplates
31
+
32
+ @openapi.extend_schema(
33
+ tags=["Documents"],
34
+ operation_id=f"{ENDPOINT_ID}list",
35
+ extensions={"x-operationId": "listDocumentTemplates"},
36
+ summary="List all templates",
37
+ responses={
38
+ 200: DocumentTemplates(),
39
+ 404: serializers.ErrorResponse(),
40
+ 500: serializers.ErrorResponse(),
41
+ },
42
+ )
43
+ def get(self, request: Request):
44
+ """
45
+ Retrieve all templates.
46
+ """
47
+ templates = models.DocumentTemplate.access_by(request)
48
+ response = self.paginate_queryset(
49
+ serializers.DocumentTemplate(templates, many=True).data
50
+ )
51
+ return self.get_paginated_response(response)
52
+
53
+ @openapi.extend_schema(
54
+ tags=["Documents"],
55
+ operation_id=f"{ENDPOINT_ID}create",
56
+ extensions={"x-operationId": "createDocumentTemplate"},
57
+ summary="Create a template",
58
+ request=serializers.DocumentTemplateData(),
59
+ responses={
60
+ 201: serializers.DocumentTemplate(),
61
+ 400: serializers.ErrorResponse(),
62
+ 500: serializers.ErrorResponse(),
63
+ },
64
+ )
65
+ def post(self, request: Request):
66
+ """
67
+ Create a new template.
68
+ """
69
+ template = (
70
+ serializers.DocumentTemplateModelSerializer.map(
71
+ data=request.data, context=request
72
+ )
73
+ .save()
74
+ .instance
75
+ )
76
+
77
+ return Response(
78
+ serializers.DocumentTemplate(template).data,
79
+ status=status.HTTP_201_CREATED,
80
+ )
81
+
82
+
83
+ class DocumentTemplateDetail(api.APIView):
84
+
85
+ @openapi.extend_schema(
86
+ tags=["Documents"],
87
+ operation_id=f"{ENDPOINT_ID}retrieve",
88
+ extensions={"x-operationId": "retrieveDocumentTemplate"},
89
+ summary="Retrieve a template",
90
+ responses={
91
+ 200: serializers.DocumentTemplate(),
92
+ 400: serializers.ErrorResponse(),
93
+ 500: serializers.ErrorResponse(),
94
+ },
95
+ )
96
+ def get(self, request: Request, pk: str):
97
+ """
98
+ Retrieve a template.
99
+ """
100
+ template = models.DocumentTemplate.access_by(request).get(pk=pk)
101
+ return Response(serializers.DocumentTemplate(template).data)
102
+
103
+ @openapi.extend_schema(
104
+ tags=["Documents"],
105
+ operation_id=f"{ENDPOINT_ID}update",
106
+ extensions={"x-operationId": "updateDocumentTemplate"},
107
+ summary="Update a template",
108
+ request=serializers.DocumentTemplateData(),
109
+ responses={
110
+ 200: serializers.DocumentTemplate(),
111
+ 400: serializers.ErrorResponse(),
112
+ 404: serializers.ErrorResponse(),
113
+ 500: serializers.ErrorResponse(),
114
+ },
115
+ )
116
+ def patch(self, request: Request, pk: str):
117
+ """
118
+ update a template.
119
+ """
120
+ template = models.DocumentTemplate.access_by(request).get(pk=pk)
121
+
122
+ serializers.DocumentTemplateModelSerializer.map(
123
+ template,
124
+ data=request.data,
125
+ ).save()
126
+
127
+ return Response(serializers.DocumentTemplate(template).data)
128
+
129
+ @openapi.extend_schema(
130
+ tags=["Documents"],
131
+ operation_id=f"{ENDPOINT_ID}discard",
132
+ extensions={"x-operationId": "discardDocumentTemplate"},
133
+ summary="Delete a template",
134
+ responses={
135
+ 200: serializers.DocumentTemplate(),
136
+ 404: serializers.ErrorResponse(),
137
+ 409: serializers.ErrorResponse(),
138
+ 500: serializers.ErrorResponse(),
139
+ },
140
+ )
141
+ def delete(self, request: Request, pk: str):
142
+ """
143
+ Delete a template.
144
+ """
145
+ template = models.DocumentTemplate.access_by(request).get(pk=pk)
146
+
147
+ template.delete(keep_parents=True)
148
+
149
+ return Response(serializers.DocumentTemplate(template).data)
150
+
151
+
152
+ class DocumentGenerator(api.APIView):
153
+ @openapi.extend_schema(
154
+ tags=["Documents"],
155
+ operation_id=f"{ENDPOINT_ID}generateDocument",
156
+ summary="Generate a document",
157
+ request=serializers.DocumentData(),
158
+ responses={
159
+ 201: serializers.GeneratedDocument(),
160
+ 400: serializers.ErrorResponse(),
161
+ 404: serializers.ErrorResponse(),
162
+ 500: serializers.ErrorResponse(),
163
+ },
164
+ )
165
+ def post(self, request: Request):
166
+ """Generate any document.
167
+ This API is designed to be used to generate GS1 labels,
168
+ invoices and any document that requires external data.
169
+ """
170
+ data = serializers.DocumentData.map(data=request.data).data
171
+
172
+ if data.get("template") is None and data.get("template_id") is None:
173
+ raise serializers.ValidationError("template or template_id is required")
174
+
175
+ document_template = lib.identity(
176
+ None
177
+ if data.get("template_id") is None
178
+ else models.DocumentTemplate.objects.get(pk=data.get("template_id"))
179
+ )
180
+
181
+ doc_file = generator.Documents.generate(
182
+ getattr(document_template, "template", data.get("template")),
183
+ related_object=getattr(document_template, "related_object", None),
184
+ metadata=getattr(document_template, "metadata", {}),
185
+ data=data.get("data"),
186
+ options=data.get("options"),
187
+ doc_name=data.get("doc_name"),
188
+ doc_fomat=data.get("doc_format"),
189
+ )
190
+ document = serializers.GeneratedDocument.map(
191
+ data={
192
+ **data,
193
+ "doc_file": base64.b64encode(doc_file.getvalue()).decode("utf-8"),
194
+ }
195
+ )
196
+
197
+ return Response(document.data, status=status.HTTP_201_CREATED)
198
+
199
+
200
+ urlpatterns = [
201
+ urls.path(
202
+ "documents/templates",
203
+ DocumentTemplateList.as_view(),
204
+ name="document-template-list",
205
+ ),
206
+ urls.path(
207
+ "documents/templates/<str:pk>",
208
+ DocumentTemplateDetail.as_view(),
209
+ name="document-template-details",
210
+ ),
211
+ urls.path(
212
+ "documents/generate",
213
+ DocumentGenerator.as_view(),
214
+ name="document-generator",
215
+ ),
216
+ ]
@@ -0,0 +1 @@
1
+ __path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
@@ -0,0 +1,46 @@
1
+ import strawberry
2
+ from strawberry.types import Info
3
+
4
+ import karrio.server.graph.utils as utils
5
+ import karrio.server.graph.schemas.base as base
6
+ import karrio.server.graph.schemas.documents.mutations as mutations
7
+ import karrio.server.graph.schemas.documents.inputs as inputs
8
+ import karrio.server.graph.schemas.documents.types as types
9
+ import karrio.server.documents.models as models
10
+
11
+ extra_types: list = []
12
+
13
+
14
+ @strawberry.type
15
+ class Query:
16
+ document_template: types.DocumentTemplateType = strawberry.field(
17
+ resolver=types.DocumentTemplateType.resolve
18
+ )
19
+ document_templates: utils.Connection[types.DocumentTemplateType] = strawberry.field(
20
+ resolver=types.DocumentTemplateType.resolve_list
21
+ )
22
+
23
+
24
+ @strawberry.type
25
+ class Mutation:
26
+ @strawberry.mutation
27
+ def create_document_template(
28
+ self, info: Info, input: inputs.CreateDocumentTemplateMutationInput
29
+ ) -> mutations.CreateDocumentTemplateMutation:
30
+ return mutations.CreateDocumentTemplateMutation.mutate(info, **input.to_dict())
31
+
32
+ @strawberry.mutation
33
+ def update_document_template(
34
+ self, info: Info, input: inputs.UpdateDocumentTemplateMutationInput
35
+ ) -> mutations.UpdateDocumentTemplateMutation:
36
+ return mutations.UpdateDocumentTemplateMutation.mutate(info, **input.to_dict())
37
+
38
+ @strawberry.mutation
39
+ def delete_document_template(
40
+ self, info: Info, input: base.inputs.DeleteMutationInput
41
+ ) -> base.mutations.DeleteMutation:
42
+ return base.mutations.DeleteMutation.mutate(
43
+ info,
44
+ model=models.DocumentTemplate,
45
+ **input.to_dict()
46
+ )
@@ -0,0 +1,38 @@
1
+ import typing
2
+ import strawberry
3
+
4
+ import karrio.server.graph.utils as utils
5
+ import karrio.server.documents.serializers as serializers
6
+
7
+ TemplateRelatedObjectEnum: typing.Any = strawberry.enum(
8
+ serializers.TemplateRelatedObject
9
+ )
10
+
11
+
12
+ @strawberry.input
13
+ class CreateDocumentTemplateMutationInput(utils.BaseInput):
14
+ slug: str
15
+ name: str
16
+ template: str
17
+ active: typing.Optional[bool] = True
18
+ description: typing.Optional[str] = strawberry.UNSET
19
+ metadata: typing.Optional[utils.JSON] = strawberry.UNSET
20
+ related_object: typing.Optional[TemplateRelatedObjectEnum] = strawberry.UNSET
21
+
22
+
23
+ @strawberry.input
24
+ class UpdateDocumentTemplateMutationInput(utils.BaseInput):
25
+ id: str
26
+ slug: typing.Optional[str] = strawberry.UNSET
27
+ name: typing.Optional[str] = strawberry.UNSET
28
+ template: typing.Optional[str] = strawberry.UNSET
29
+ active: typing.Optional[bool] = strawberry.UNSET
30
+ description: typing.Optional[str] = strawberry.UNSET
31
+ related_object: typing.Optional[TemplateRelatedObjectEnum] = strawberry.UNSET
32
+
33
+
34
+ @strawberry.input
35
+ class DocumentTemplateFilter(utils.Paginated):
36
+ name: typing.Optional[str] = strawberry.UNSET
37
+ active: typing.Optional[bool] = strawberry.UNSET
38
+ related_object: typing.Optional[TemplateRelatedObjectEnum] = strawberry.UNSET
@@ -0,0 +1,51 @@
1
+ import typing
2
+ import strawberry
3
+ from strawberry.types import Info
4
+
5
+ import karrio.server.graph.utils as utils
6
+ import karrio.server.graph.schemas.documents.types as types
7
+ import karrio.server.graph.schemas.documents.inputs as inputs
8
+ import karrio.server.documents.serializers as serializers
9
+ import karrio.server.documents.models as models
10
+
11
+
12
+ @strawberry.type
13
+ class CreateDocumentTemplateMutation(utils.BaseMutation):
14
+ template: typing.Optional[types.DocumentTemplateType] = None
15
+
16
+ @staticmethod
17
+ @utils.authentication_required
18
+ @utils.authorization_required(["DOCUMENTS_MANAGEMENT", "manage_data"])
19
+ def mutate(
20
+ info: Info, **input: inputs.CreateDocumentTemplateMutationInput
21
+ ) -> "CreateDocumentTemplateMutation":
22
+ serializer = serializers.DocumentTemplateModelSerializer(
23
+ data=input,
24
+ context=info.context.request,
25
+ )
26
+ serializer.is_valid(raise_exception=True)
27
+
28
+ return CreateDocumentTemplateMutation(template=serializer.save()) # type:ignore
29
+
30
+
31
+ @strawberry.type
32
+ class UpdateDocumentTemplateMutation(utils.BaseMutation):
33
+ template: typing.Optional[types.DocumentTemplateType] = None
34
+
35
+ @staticmethod
36
+ @utils.authentication_required
37
+ @utils.authorization_required(["DOCUMENTS_MANAGEMENT", "manage_data"])
38
+ def mutate(
39
+ info: Info, **input: inputs.UpdateDocumentTemplateMutationInput
40
+ ) -> "UpdateDocumentTemplateMutation":
41
+ instance = models.DocumentTemplate.access_by(info.context.request).get(id=input["id"])
42
+
43
+ serializer = serializers.DocumentTemplateModelSerializer(
44
+ instance,
45
+ data=input,
46
+ partial=True,
47
+ context=info.context.request,
48
+ )
49
+ serializer.is_valid(raise_exception=True)
50
+
51
+ return UpdateDocumentTemplateMutation(template=serializer.save()) # type:ignore
@@ -0,0 +1,43 @@
1
+ import typing
2
+ import datetime
3
+ import strawberry
4
+
5
+ import karrio.lib as lib
6
+ import karrio.server.graph.utils as utils
7
+ import karrio.server.graph.schemas.base.types as base
8
+ import karrio.server.graph.schemas.documents.inputs as inputs
9
+ import karrio.server.documents.models as models
10
+ import karrio.server.documents.filters as filters
11
+
12
+
13
+ @strawberry.type
14
+ class DocumentTemplateType:
15
+ object_type: str
16
+ preview_url: typing.Optional[str]
17
+ id: str
18
+ name: str
19
+ slug: str
20
+ template: str
21
+ active: bool
22
+ description: typing.Optional[str]
23
+ related_object: typing.Optional[inputs.TemplateRelatedObjectEnum]
24
+ created_at: typing.Optional[datetime.datetime]
25
+ updated_at: typing.Optional[datetime.datetime]
26
+ created_by: typing.Optional[base.UserType]
27
+
28
+ @staticmethod
29
+ @utils.authentication_required
30
+ def resolve(info, id: str) -> typing.Optional["DocumentTemplateType"]:
31
+ return models.DocumentTemplate.access_by(info.context.request).filter(id=id).first()
32
+
33
+ @staticmethod
34
+ @utils.authentication_required
35
+ def resolve_list(
36
+ info,
37
+ filter: typing.Optional[inputs.DocumentTemplateFilter] = strawberry.UNSET,
38
+ ) -> utils.Connection["DocumentTemplateType"]:
39
+ _filter = filter if filter is not strawberry.UNSET else inputs.DocumentTemplateFilter()
40
+ queryset = filters.DocumentTemplateFilter(
41
+ _filter.to_dict(), models.DocumentTemplate.access_by(info.context.request)
42
+ ).qs
43
+ return utils.paginated_connection(queryset, **_filter.pagination())
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.4
2
+ Name: karrio_server_documents
3
+ Version: 2025.5rc1
4
+ Summary: Multi-carrier shipping API apps module
5
+ Author-email: karrio <hello@karrio.io>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/karrioapi/karrio
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: pyzint
12
+ Requires-Dist: weasyprint
13
+ Requires-Dist: karrio_server_core
14
+ Requires-Dist: karrio_server_graph
15
+ Requires-Dist: karrio_server_manager
16
+
17
+ # karrio-server
18
+
19
+ Karrio server documents module.