karrio-server-graph 2025.5__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.
Files changed (39) hide show
  1. karrio/server/graph/__init__.py +1 -0
  2. karrio/server/graph/admin.py +3 -0
  3. karrio/server/graph/apps.py +5 -0
  4. karrio/server/graph/forms.py +57 -0
  5. karrio/server/graph/management/__init__.py +0 -0
  6. karrio/server/graph/management/commands/__init__.py +0 -0
  7. karrio/server/graph/management/commands/export_schema.py +9 -0
  8. karrio/server/graph/migrations/0001_initial.py +37 -0
  9. karrio/server/graph/migrations/0002_auto_20210512_1353.py +22 -0
  10. karrio/server/graph/migrations/__init__.py +0 -0
  11. karrio/server/graph/models.py +44 -0
  12. karrio/server/graph/schema.py +44 -0
  13. karrio/server/graph/schemas/__init__.py +2 -0
  14. karrio/server/graph/schemas/base/__init__.py +385 -0
  15. karrio/server/graph/schemas/base/inputs.py +612 -0
  16. karrio/server/graph/schemas/base/mutations.py +1033 -0
  17. karrio/server/graph/schemas/base/types.py +1406 -0
  18. karrio/server/graph/serializers.py +388 -0
  19. karrio/server/graph/templates/graphql/graphiql.html +142 -0
  20. karrio/server/graph/templates/karrio/email_change_email.html +13 -0
  21. karrio/server/graph/templates/karrio/email_change_email.txt +13 -0
  22. karrio/server/graph/templates/karrio/password_reset_email.html +14 -0
  23. karrio/server/graph/tests/__init__.py +9 -0
  24. karrio/server/graph/tests/base.py +153 -0
  25. karrio/server/graph/tests/test_carrier_connections.py +239 -0
  26. karrio/server/graph/tests/test_metafield.py +404 -0
  27. karrio/server/graph/tests/test_partial_shipments.py +603 -0
  28. karrio/server/graph/tests/test_rate_sheets.py +354 -0
  29. karrio/server/graph/tests/test_registration.py +209 -0
  30. karrio/server/graph/tests/test_templates.py +677 -0
  31. karrio/server/graph/tests/test_user_info.py +71 -0
  32. karrio/server/graph/urls.py +10 -0
  33. karrio/server/graph/utils.py +308 -0
  34. karrio/server/graph/views.py +91 -0
  35. karrio/server/settings/graph.py +7 -0
  36. karrio_server_graph-2025.5.dist-info/METADATA +29 -0
  37. karrio_server_graph-2025.5.dist-info/RECORD +39 -0
  38. karrio_server_graph-2025.5.dist-info/WHEEL +5 -0
  39. karrio_server_graph-2025.5.dist-info/top_level.txt +2 -0
@@ -0,0 +1,153 @@
1
+ import json
2
+ import dataclasses
3
+ from django.urls import reverse
4
+ from rest_framework import status
5
+ from django.contrib.auth import get_user_model
6
+ from rest_framework.test import APITestCase as BaseAPITestCase, APIClient
7
+
8
+ from karrio.server.core.logging import logger
9
+ from karrio.server.user.models import Token
10
+ import karrio.server.providers.models as providers
11
+
12
+
13
+ @dataclasses.dataclass
14
+ class Result:
15
+ data: dict = None
16
+ status_code: str = None
17
+
18
+
19
+ class GraphTestCase(BaseAPITestCase):
20
+ def setUp(self) -> None:
21
+ self.maxDiff = None
22
+ # Loguru is already configured globally in settings
23
+
24
+ # Setup user and API Token.
25
+ self.user = get_user_model().objects.create_superuser(
26
+ "admin@example.com", "test"
27
+ )
28
+
29
+ self.token = Token.objects.create(user=self.user, test_mode=False)
30
+
31
+ # Create organization for multi-org support (if enabled)
32
+ from django.conf import settings
33
+ if settings.MULTI_ORGANIZATIONS:
34
+ from karrio.server.orgs.models import Organization, TokenLink
35
+ self.organization = Organization.objects.create(
36
+ name="Test Organization",
37
+ slug="test-org"
38
+ )
39
+ # Add user as owner (triggers permission sync via signals)
40
+ owner = self.organization.add_user(self.user, is_admin=True)
41
+ self.organization.change_owner(owner)
42
+ self.organization.save()
43
+
44
+ # Link token to organization
45
+ TokenLink.objects.create(
46
+ item=self.token,
47
+ org=self.organization
48
+ )
49
+
50
+ # Setup API client.
51
+ self.client = APIClient()
52
+ self.client.credentials(HTTP_AUTHORIZATION="Token " + self.token.key)
53
+
54
+ # Setup test carrier connections.
55
+ self.carrier = providers.Carrier.objects.create(
56
+ carrier_code="canadapost",
57
+ carrier_id="canadapost",
58
+ test_mode=False,
59
+ created_by=self.user,
60
+ credentials=dict(
61
+ username="6e93d53968881714",
62
+ customer_number="2004381",
63
+ contract_id="42708517",
64
+ password="0bfa9fcb9853d1f51ee57a",
65
+ ),
66
+ capabilities=["pickup", "rating", "tracking", "shipping"],
67
+ )
68
+ self.ups_carrier = providers.Carrier.objects.create(
69
+ carrier_code="ups",
70
+ carrier_id="ups_package",
71
+ test_mode=False,
72
+ created_by=self.user,
73
+ credentials=dict(
74
+ client_id="test",
75
+ client_secret="test",
76
+ account_number="000000",
77
+ ),
78
+ capabilities=["pickup", "rating", "tracking", "shipping"],
79
+ )
80
+ self.fedex_carrier = providers.Carrier.objects.create(
81
+ carrier_code="fedex",
82
+ carrier_id="fedex_express",
83
+ test_mode=False,
84
+ credentials=dict(
85
+ api_key="test",
86
+ secret_key="password",
87
+ account_number="000000",
88
+ track_api_key="test",
89
+ track_secret_key="password",
90
+ ),
91
+ capabilities=["pickup", "rating", "tracking", "shipping"],
92
+ is_system=True,
93
+ )
94
+ self.dhl_carrier = providers.Carrier.objects.create(
95
+ carrier_code="dhl_universal",
96
+ carrier_id="dhl_universal",
97
+ test_mode=False,
98
+ is_system=True,
99
+ credentials=dict(
100
+ consumer_key="test",
101
+ consumer_secret="password",
102
+ ),
103
+ capabilities=["tracking"],
104
+ )
105
+
106
+ def query(
107
+ self,
108
+ query: str,
109
+ operation_name: str = None,
110
+ variables: dict = None,
111
+ org_id: str = None,
112
+ ) -> Result:
113
+ url = reverse("karrio.server.graph:graphql")
114
+ data = dict(
115
+ query=query,
116
+ variables=variables,
117
+ operation_name=operation_name,
118
+ )
119
+
120
+ response = self.client.post(
121
+ url, data, **({"x-org-id": org_id} if org_id else {})
122
+ )
123
+
124
+ return Result(
125
+ status_code=response.status_code,
126
+ data=json.loads(response.content),
127
+ )
128
+
129
+ def getJWTToken(self, email: str, password: str) -> str:
130
+ url = reverse("jwt-obtain-pair")
131
+ data = dict(
132
+ email=email,
133
+ password=password,
134
+ )
135
+ response = self.client.post(url, data)
136
+
137
+ return response.data.get("access")
138
+
139
+ def assertResponseNoErrors(self, result: Result):
140
+ if (
141
+ result.status_code not in [status.HTTP_200_OK, status.HTTP_201_CREATED]
142
+ or result.data.get("errors") is not None
143
+ ):
144
+ logger.error("GraphQL response has errors",
145
+ status_code=result.status_code,
146
+ response_data=result.data)
147
+
148
+ if result.status_code != status.HTTP_201_CREATED:
149
+ self.assertEqual(result.status_code, status.HTTP_200_OK)
150
+ else:
151
+ self.assertEqual(result.status_code, status.HTTP_201_CREATED)
152
+
153
+ assert result.data.get("errors") is None
@@ -0,0 +1,239 @@
1
+ import karrio.lib as lib
2
+ from unittest.mock import ANY
3
+ from karrio.server.graph.tests.base import GraphTestCase
4
+
5
+
6
+ class TestSystemConnections(GraphTestCase):
7
+ def test_query_system_connections(self):
8
+ response = self.query(
9
+ """
10
+ query get_system_connections {
11
+ system_connections {
12
+ edges {
13
+ node {
14
+ id
15
+ carrier_id
16
+ carrier_name
17
+ active
18
+ test_mode
19
+ }
20
+ }
21
+ }
22
+ }
23
+ """,
24
+ operation_name="get_system_connections",
25
+ )
26
+ response_data = response.data
27
+
28
+ self.assertResponseNoErrors(response)
29
+ self.assertDictEqual(
30
+ lib.to_dict(response_data),
31
+ SYSTEM_CONNECTIONS,
32
+ )
33
+
34
+
35
+ class TestUserConnections(GraphTestCase):
36
+ def test_query_user_connections(self):
37
+ response = self.query(
38
+ """
39
+ query get_user_connections {
40
+ user_connections {
41
+ edges {
42
+ node {
43
+ id
44
+ carrier_id
45
+ carrier_name
46
+ active
47
+ test_mode
48
+ credentials
49
+ }
50
+ }
51
+ }
52
+ }
53
+ """,
54
+ operation_name="get_user_connections",
55
+ )
56
+ response_data = response.data
57
+
58
+ self.assertResponseNoErrors(response)
59
+ self.assertDictEqual(
60
+ lib.to_dict(response_data),
61
+ USER_CONNECTIONS,
62
+ )
63
+
64
+ def test_create_user_connection(self):
65
+ response = self.query(
66
+ """
67
+ mutation create_connection($data: CreateCarrierConnectionMutationInput!) {
68
+ create_carrier_connection(input: $data) {
69
+ connection {
70
+ id
71
+ carrier_id
72
+ carrier_name
73
+ active
74
+ test_mode
75
+ credentials
76
+ }
77
+ }
78
+ }
79
+ """,
80
+ operation_name="create_connection",
81
+ variables=CONNECTION_DATA,
82
+ )
83
+ response_data = response.data
84
+
85
+ self.assertResponseNoErrors(response)
86
+ self.assertDictEqual(response_data, CONNECTION_RESPONSE)
87
+
88
+ def test_update_user_connection(self):
89
+ response = self.query(
90
+ """
91
+ mutation update_connection($data: UpdateCarrierConnectionMutationInput!) {
92
+ update_carrier_connection(input: $data) {
93
+ connection {
94
+ carrier_id
95
+ credentials
96
+ }
97
+ }
98
+ }
99
+ """,
100
+ operation_name="update_connection",
101
+ variables={
102
+ "data": {
103
+ "id": self.carrier.id,
104
+ **CONNECTION_UPDATE_DATA["data"],
105
+ },
106
+ },
107
+ )
108
+ response_data = response.data
109
+
110
+ self.assertResponseNoErrors(response)
111
+ self.assertDictEqual(
112
+ lib.to_dict(response_data),
113
+ lib.to_dict(CONNECTION_UPDATE_RESPONSE),
114
+ )
115
+
116
+
117
+ SYSTEM_CONNECTIONS = {
118
+ "data": {
119
+ "system_connections": {
120
+ "edges": [
121
+ {
122
+ "node": {
123
+ "active": True,
124
+ "carrier_id": "dhl_universal",
125
+ "carrier_name": "dhl_universal",
126
+ "id": ANY,
127
+ "test_mode": False,
128
+ }
129
+ },
130
+ {
131
+ "node": {
132
+ "active": True,
133
+ "carrier_id": "fedex_express",
134
+ "carrier_name": "fedex",
135
+ "id": ANY,
136
+ "test_mode": False,
137
+ }
138
+ },
139
+ ]
140
+ }
141
+ }
142
+ }
143
+
144
+ USER_CONNECTIONS = {
145
+ "data": {
146
+ "user_connections": {
147
+ "edges": [
148
+ {
149
+ "node": {
150
+ "active": True,
151
+ "carrier_id": "ups_package",
152
+ "carrier_name": "ups",
153
+ "credentials": {
154
+ "account_number": "000000",
155
+ "client_id": "test",
156
+ "client_secret": "test",
157
+ },
158
+ "id": ANY,
159
+ "test_mode": False,
160
+ }
161
+ },
162
+ {
163
+ "node": {
164
+ "active": True,
165
+ "carrier_id": "canadapost",
166
+ "carrier_name": "canadapost",
167
+ "credentials": {
168
+ "contract_id": "42708517",
169
+ "customer_number": "2004381",
170
+ "password": "0bfa9fcb9853d1f51ee57a",
171
+ "username": "6e93d53968881714",
172
+ },
173
+ "id": ANY,
174
+ "test_mode": False,
175
+ }
176
+ },
177
+ ]
178
+ }
179
+ }
180
+ }
181
+
182
+ CONNECTION_DATA = {
183
+ "data": {
184
+ "carrier_name": "sendle",
185
+ "carrier_id": "sendle",
186
+ "credentials": {
187
+ "sendle_id": "test_sendle_id",
188
+ "api_key": "test_api_key",
189
+ },
190
+ }
191
+ }
192
+
193
+ CONNECTION_RESPONSE = {
194
+ "data": {
195
+ "create_carrier_connection": {
196
+ "connection": {
197
+ "id": ANY,
198
+ "active": True,
199
+ "carrier_id": "sendle",
200
+ "carrier_name": "sendle",
201
+ "test_mode": False,
202
+ "credentials": {
203
+ "api_key": "test_api_key",
204
+ "sendle_id": "test_sendle_id",
205
+ "account_country_code": None,
206
+ },
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ CONNECTION_UPDATE_DATA = {
213
+ "data": {
214
+ "carrier_id": "canadapost_updated",
215
+ "credentials": {
216
+ "username": "6e93d53968881714_updated",
217
+ "customer_number": "2004381_updated",
218
+ "contract_id": "42708517_updated",
219
+ "password": "0bfa9fcb9853d1f51ee57a_updated",
220
+ },
221
+ }
222
+ }
223
+
224
+ CONNECTION_UPDATE_RESPONSE = {
225
+ "data": {
226
+ "update_carrier_connection": {
227
+ "connection": {
228
+ "carrier_id": "canadapost_updated",
229
+ "credentials": {
230
+ "account_country_code": "CA",
231
+ "contract_id": "42708517_updated",
232
+ "customer_number": "2004381_updated",
233
+ "password": "0bfa9fcb9853d1f51ee57a_updated",
234
+ "username": "6e93d53968881714_updated",
235
+ },
236
+ }
237
+ }
238
+ }
239
+ }