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
@@ -0,0 +1,318 @@
1
+ import json
2
+ from unittest.mock import ANY
3
+ from django.urls import reverse
4
+ from rest_framework import status
5
+ from karrio.server.core.tests import APITestCase
6
+ from karrio.server.graph.tests.base import GraphTestCase
7
+ from karrio.server.documents.models import DocumentTemplate
8
+
9
+
10
+ class TestDocumentTemplatesREST(APITestCase):
11
+ def test_create_document_template(self):
12
+ url = reverse("karrio.server.documents:document-template-list")
13
+ data = DOCUMENT_TEMPLATE_DATA
14
+
15
+ response = self.client.post(url, data)
16
+ response_data = json.loads(response.content)
17
+
18
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
19
+
20
+ # Check individual fields instead of strict dictionary comparison
21
+ self.assertEqual(response_data["name"], "Test Invoice Template")
22
+ self.assertEqual(response_data["slug"], "test_invoice")
23
+ self.assertEqual(response_data["description"], "A test invoice template")
24
+ self.assertEqual(response_data["object_type"], "document-template")
25
+ self.assertEqual(response_data["related_object"], "shipment")
26
+ self.assertEqual(response_data["active"], True)
27
+ self.assertEqual(response_data["metadata"], {"doc_type": "invoice", "version": "1.0"})
28
+ self.assertEqual(response_data["options"], {"page_size": "A4", "orientation": "portrait"})
29
+
30
+ # Check that ID field exists
31
+ self.assertIn("id", response_data)
32
+
33
+ def test_list_document_templates(self):
34
+ # Create a template first
35
+ DocumentTemplate.objects.create(
36
+ **{
37
+ "name": "Test Template",
38
+ "slug": "test_template",
39
+ "template": SAMPLE_HTML_TEMPLATE,
40
+ "description": "A test template",
41
+ "related_object": "shipment",
42
+ "created_by": self.user,
43
+ }
44
+ )
45
+
46
+ url = reverse("karrio.server.documents:document-template-list")
47
+ response = self.client.get(url)
48
+ response_data = json.loads(response.content)
49
+
50
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
51
+ self.assertIn("results", response_data)
52
+ self.assertEqual(len(response_data["results"]), 1)
53
+ self.assertEqual(response_data["results"][0]["name"], "Test Template")
54
+
55
+
56
+ class TestDocumentTemplateDetailsREST(APITestCase):
57
+ def setUp(self) -> None:
58
+ super().setUp()
59
+ self.template: DocumentTemplate = DocumentTemplate.objects.create(
60
+ **{
61
+ "name": "Test Template",
62
+ "slug": "test_template",
63
+ "template": SAMPLE_HTML_TEMPLATE,
64
+ "description": "A test template",
65
+ "related_object": "shipment",
66
+ "active": True,
67
+ "metadata": {"doc_type": "invoice"},
68
+ "options": {"page_size": "A4"},
69
+ "created_by": self.user,
70
+ }
71
+ )
72
+
73
+ def test_retrieve_document_template(self):
74
+ url = reverse(
75
+ "karrio.server.documents:document-template-details",
76
+ kwargs=dict(pk=self.template.pk),
77
+ )
78
+
79
+ response = self.client.get(url)
80
+ response_data = json.loads(response.content)
81
+
82
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
83
+
84
+ # Check individual fields instead of strict dictionary comparison
85
+ self.assertEqual(response_data["name"], "Test Template")
86
+ self.assertEqual(response_data["slug"], "test_template")
87
+ self.assertEqual(response_data["description"], "A test template")
88
+ self.assertEqual(response_data["object_type"], "document-template")
89
+ self.assertEqual(response_data["related_object"], "shipment")
90
+ self.assertEqual(response_data["active"], True)
91
+ self.assertEqual(response_data["metadata"], {"doc_type": "invoice"})
92
+ self.assertEqual(response_data["options"], {"page_size": "A4"})
93
+ self.assertEqual(response_data["template"], SAMPLE_HTML_TEMPLATE)
94
+
95
+ # Check that ID field exists
96
+ self.assertIn("id", response_data)
97
+
98
+ def test_update_document_template(self):
99
+ url = reverse(
100
+ "karrio.server.documents:document-template-details",
101
+ kwargs=dict(pk=self.template.pk),
102
+ )
103
+ data = DOCUMENT_TEMPLATE_UPDATE_DATA
104
+
105
+ response = self.client.patch(url, data)
106
+ response_data = json.loads(response.content)
107
+
108
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
109
+ self.assertDictEqual(response_data, DOCUMENT_TEMPLATE_UPDATE_RESPONSE)
110
+
111
+ def test_delete_document_template(self):
112
+ url = reverse(
113
+ "karrio.server.documents:document-template-details",
114
+ kwargs=dict(pk=self.template.pk),
115
+ )
116
+
117
+ response = self.client.delete(url)
118
+ response_data = json.loads(response.content)
119
+
120
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
121
+ # Verify template data is returned (soft delete behavior)
122
+ self.assertEqual(response_data.get("name"), "Test Template")
123
+ self.assertEqual(response_data.get("slug"), "test_template")
124
+ # The template should still be active (or check if it's marked as inactive)
125
+ self.assertIsNotNone(response_data.get("object_type"))
126
+
127
+
128
+ class TestDocumentTemplatesGraphQL(GraphTestCase):
129
+ def test_query_document_templates(self):
130
+ # Create a template first
131
+ DocumentTemplate.objects.create(
132
+ **{
133
+ "name": "GraphQL Test Template",
134
+ "slug": "graphql_test",
135
+ "template": SAMPLE_HTML_TEMPLATE,
136
+ "description": "A GraphQL test template",
137
+ "related_object": "order",
138
+ "created_by": self.user,
139
+ }
140
+ )
141
+
142
+ query = """
143
+ query {
144
+ document_templates {
145
+ edges {
146
+ node {
147
+ id
148
+ name
149
+ slug
150
+ description
151
+ related_object
152
+ active
153
+ object_type
154
+ }
155
+ }
156
+ }
157
+ }
158
+ """
159
+
160
+ result = self.query(query)
161
+ self.assertResponseNoErrors(result)
162
+
163
+ templates = result.data["data"]["document_templates"]["edges"]
164
+ self.assertEqual(len(templates), 1)
165
+ self.assertEqual(templates[0]["node"]["name"], "GraphQL Test Template")
166
+ self.assertEqual(templates[0]["node"]["slug"], "graphql_test")
167
+
168
+ def test_create_document_template_mutation(self):
169
+ mutation = """
170
+ mutation CreateDocumentTemplate($input: CreateDocumentTemplateMutationInput!) {
171
+ create_document_template(input: $input) {
172
+ template {
173
+ id
174
+ name
175
+ slug
176
+ description
177
+ related_object
178
+ active
179
+ }
180
+ errors {
181
+ field
182
+ messages
183
+ }
184
+ }
185
+ }
186
+ """
187
+
188
+ variables = {
189
+ "input": {
190
+ "name": "GraphQL Created Template",
191
+ "slug": "graphql_created",
192
+ "template": SAMPLE_HTML_TEMPLATE,
193
+ "description": "Created via GraphQL",
194
+ "related_object": "shipment",
195
+ "active": True,
196
+ }
197
+ }
198
+
199
+ result = self.query(mutation, variables=variables)
200
+ self.assertResponseNoErrors(result)
201
+
202
+ created_template = result.data["data"]["create_document_template"]["template"]
203
+ self.assertEqual(created_template["name"], "GraphQL Created Template")
204
+ self.assertEqual(created_template["slug"], "graphql_created")
205
+ self.assertTrue(created_template["active"])
206
+
207
+ def test_update_document_template_mutation(self):
208
+ # Create a template first
209
+ template = DocumentTemplate.objects.create(
210
+ **{
211
+ "name": "Original Template",
212
+ "slug": "original",
213
+ "template": SAMPLE_HTML_TEMPLATE,
214
+ "description": "Original description",
215
+ "related_object": "shipment",
216
+ "created_by": self.user,
217
+ }
218
+ )
219
+
220
+ mutation = """
221
+ mutation UpdateDocumentTemplate($input: UpdateDocumentTemplateMutationInput!) {
222
+ update_document_template(input: $input) {
223
+ template {
224
+ id
225
+ name
226
+ description
227
+ active
228
+ }
229
+ errors {
230
+ field
231
+ messages
232
+ }
233
+ }
234
+ }
235
+ """
236
+
237
+ variables = {
238
+ "input": {
239
+ "id": template.id,
240
+ "name": "Updated Template",
241
+ "description": "Updated description",
242
+ "active": False,
243
+ }
244
+ }
245
+
246
+ result = self.query(mutation, variables=variables)
247
+ self.assertResponseNoErrors(result)
248
+
249
+ updated_template = result.data["data"]["update_document_template"]["template"]
250
+ self.assertEqual(updated_template["name"], "Updated Template")
251
+ self.assertEqual(updated_template["description"], "Updated description")
252
+ self.assertFalse(updated_template["active"])
253
+
254
+
255
+ # Test Data and Fixtures
256
+ SAMPLE_HTML_TEMPLATE = """
257
+ <title>{{ title | default('Test Document') }}</title>
258
+ """
259
+
260
+ DOCUMENT_TEMPLATE_DATA = {
261
+ "name": "Test Invoice Template",
262
+ "slug": "test_invoice",
263
+ "template": SAMPLE_HTML_TEMPLATE,
264
+ "description": "A test invoice template",
265
+ "related_object": "shipment",
266
+ "active": True,
267
+ "metadata": {"doc_type": "invoice", "version": "1.0"},
268
+ "options": {"page_size": "A4", "orientation": "portrait"},
269
+ }
270
+
271
+ DOCUMENT_TEMPLATE_RESPONSE = {
272
+ "id": ANY,
273
+ "object_type": "document-template",
274
+ "name": "Test Invoice Template",
275
+ "slug": "test_invoice",
276
+ "template": SAMPLE_HTML_TEMPLATE,
277
+ "description": "A test invoice template",
278
+ "related_object": "shipment",
279
+ "active": True,
280
+ "metadata": {"doc_type": "invoice", "version": "1.0"},
281
+ "options": {"page_size": "A4", "orientation": "portrait"},
282
+ "preview_url": ANY,
283
+ }
284
+
285
+ DOCUMENT_TEMPLATE_DETAIL_RESPONSE = {
286
+ "active": True,
287
+ "description": "A test template",
288
+ "id": ANY,
289
+ "metadata": {"doc_type": "invoice"},
290
+ "name": "Test Template",
291
+ "object_type": "document-template",
292
+ "options": {"page_size": "A4"},
293
+ "related_object": "shipment",
294
+ "slug": "test_template",
295
+ "template": SAMPLE_HTML_TEMPLATE,
296
+ "preview_url": ANY,
297
+ }
298
+
299
+ DOCUMENT_TEMPLATE_UPDATE_DATA = {
300
+ "name": "Updated Test Template",
301
+ "description": "An updated test template",
302
+ "active": False,
303
+ "metadata": {"doc_type": "commercial_invoice", "version": "2.0"},
304
+ }
305
+
306
+ DOCUMENT_TEMPLATE_UPDATE_RESPONSE = {
307
+ "id": ANY,
308
+ "object_type": "document-template",
309
+ "name": "Updated Test Template",
310
+ "slug": "test_template",
311
+ "template": SAMPLE_HTML_TEMPLATE,
312
+ "description": "An updated test template",
313
+ "related_object": "shipment",
314
+ "active": False,
315
+ "metadata": {"doc_type": "commercial_invoice", "version": "2.0"},
316
+ "options": {"page_size": "A4"},
317
+ "preview_url": ANY,
318
+ }
@@ -0,0 +1,11 @@
1
+ """
2
+ karrio server documents module urls
3
+ """
4
+
5
+ from django.urls import include, path
6
+
7
+ app_name = "karrio.server.documents"
8
+ urlpatterns = [
9
+ path("", include("karrio.server.documents.views.printers")),
10
+ path("v1/", include("karrio.server.documents.views.templates")),
11
+ ]