karrio-server-graph 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.
Files changed (37) 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 +59 -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 +46 -0
  13. karrio/server/graph/schemas/__init__.py +2 -0
  14. karrio/server/graph/schemas/base/__init__.py +367 -0
  15. karrio/server/graph/schemas/base/inputs.py +582 -0
  16. karrio/server/graph/schemas/base/mutations.py +871 -0
  17. karrio/server/graph/schemas/base/types.py +1365 -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 +124 -0
  25. karrio/server/graph/tests/test_carrier_connections.py +219 -0
  26. karrio/server/graph/tests/test_metafield.py +404 -0
  27. karrio/server/graph/tests/test_rate_sheets.py +348 -0
  28. karrio/server/graph/tests/test_templates.py +677 -0
  29. karrio/server/graph/tests/test_user_info.py +71 -0
  30. karrio/server/graph/urls.py +10 -0
  31. karrio/server/graph/utils.py +304 -0
  32. karrio/server/graph/views.py +93 -0
  33. karrio/server/settings/graph.py +7 -0
  34. karrio_server_graph-2025.5rc1.dist-info/METADATA +29 -0
  35. karrio_server_graph-2025.5rc1.dist-info/RECORD +37 -0
  36. karrio_server_graph-2025.5rc1.dist-info/WHEEL +5 -0
  37. karrio_server_graph-2025.5rc1.dist-info/top_level.txt +2 -0
@@ -0,0 +1 @@
1
+ __path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
@@ -0,0 +1,3 @@
1
+ from django.contrib import admin
2
+
3
+ # Register your models here.
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class GraphConfig(AppConfig):
5
+ name = 'karrio.server.graph'
@@ -0,0 +1,59 @@
1
+ import logging
2
+ import django.forms as forms
3
+ import django.contrib.auth.forms as auth
4
+ import django.core.exceptions as exceptions
5
+ import django.contrib.auth.tokens as tokens
6
+ import django_email_verification.confirm as confirm
7
+
8
+ import karrio.server.conf as conf
9
+ import karrio.server.user.forms as user_forms
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class UserRegistrationForm(user_forms.SignUpForm):
15
+ pass
16
+
17
+
18
+ class PasswordChangeForm(auth.PasswordChangeForm):
19
+ def __init__(self, user=None, *args, **kwargs):
20
+ super().__init__(user, *args, **kwargs)
21
+
22
+
23
+ class ConfirmPasswordResetForm(auth.SetPasswordForm):
24
+ uid = forms.CharField(required=True, max_length=100)
25
+ token = forms.CharField(required=True, max_length=100)
26
+
27
+ def __init__(self, user=None, *args, **kwargs):
28
+ super().__init__(user, *args, **kwargs)
29
+
30
+ def clean_token(self):
31
+ token = self.cleaned_data["token"]
32
+ valid_link = tokens.default_token_generator.check_token(self.user, token)
33
+
34
+ if not valid_link:
35
+ raise exceptions.ValidationError("invalid or expired url token")
36
+
37
+
38
+ class ResetPasswordRequestForm(auth.PasswordResetForm):
39
+ redirect_url = forms.URLField()
40
+ from_email = confirm._get_validated_field("EMAIL_FROM_ADDRESS")
41
+
42
+ def save(self, **kwargs):
43
+ try:
44
+ super().save(
45
+ **{
46
+ **kwargs,
47
+ "extra_email_context": dict(
48
+ app_name=conf.settings.app_name,
49
+ redirect_url=self.cleaned_data["redirect_url"],
50
+ ),
51
+ "email_template_name": "karrio/password_reset_email.html",
52
+ "from_email": self.from_email,
53
+ }
54
+ )
55
+ except Exception as e:
56
+ logger.error(f"An error occurred while sending the email: {e}")
57
+ raise exceptions.ValidationError(
58
+ "An error occurred while sending the email"
59
+ )
File without changes
File without changes
@@ -0,0 +1,9 @@
1
+ from django.core.management import BaseCommand
2
+ from strawberry.printer import print_schema
3
+
4
+ from karrio.server.graph.schema import schema
5
+
6
+ class Command(BaseCommand):
7
+ help = 'Exports the strawberry graphql schema'
8
+ def handle(self, *args, **options):
9
+ print(print_schema(schema))
@@ -0,0 +1,37 @@
1
+ # Generated by Django 3.1.7 on 2021-03-26 14:53
2
+
3
+ from django.conf import settings
4
+ from django.db import migrations, models
5
+ import django.db.models.deletion
6
+ import karrio.server.core.models
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ initial = True
12
+
13
+ dependencies = [
14
+ ('manager', '0009_auto_20210326_1425'),
15
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
16
+ ]
17
+
18
+ operations = [
19
+ migrations.CreateModel(
20
+ name='Template',
21
+ fields=[
22
+ ('created_at', models.DateTimeField(auto_now_add=True)),
23
+ ('updated_at', models.DateTimeField(auto_now=True)),
24
+ ('id', models.CharField(default=karrio.server.core.models.uuid, editable=False, max_length=50, primary_key=True, serialize=False)),
25
+ ('label', models.CharField(max_length=50)),
26
+ ('is_default', models.BooleanField(null=True)),
27
+ ('address', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='manager.address')),
28
+ ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
29
+ ('customs', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='manager.customs')),
30
+ ('parcel', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='manager.parcel')),
31
+ ],
32
+ options={
33
+ 'db_table': 'template',
34
+ 'ordering': ['-created_at'],
35
+ },
36
+ ),
37
+ ]
@@ -0,0 +1,22 @@
1
+ # Generated by Django 3.2.2 on 2021-05-12 13:53
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('graph', '0001_initial'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterModelOptions(
14
+ name='template',
15
+ options={'ordering': ['-is_default', '-created_by']},
16
+ ),
17
+ migrations.AlterField(
18
+ model_name='template',
19
+ name='is_default',
20
+ field=models.BooleanField(blank=True, default=False),
21
+ ),
22
+ ]
File without changes
@@ -0,0 +1,44 @@
1
+ from django.conf import settings
2
+ from django.db import models
3
+
4
+ from karrio.server.core.models import OwnedEntity, uuid, register_model
5
+ from karrio.server.manager.models import Customs, Parcel, Address
6
+
7
+
8
+ @register_model
9
+ class Template(OwnedEntity):
10
+ HIDDEN_PROPS = (*(("org",) if settings.MULTI_ORGANIZATIONS else tuple()),)
11
+
12
+ class Meta:
13
+ db_table = "template"
14
+ ordering = ["-is_default", "-created_by"]
15
+
16
+ id = models.CharField(max_length=50, primary_key=True, default=uuid, editable=False)
17
+ label = models.CharField(max_length=50)
18
+ is_default = models.BooleanField(blank=True, default=False)
19
+
20
+ address = models.OneToOneField(
21
+ Address, on_delete=models.CASCADE, null=True, blank=True
22
+ )
23
+ customs = models.OneToOneField(
24
+ Customs, on_delete=models.CASCADE, null=True, blank=True
25
+ )
26
+ parcel = models.OneToOneField(
27
+ Parcel, on_delete=models.CASCADE, null=True, blank=True
28
+ )
29
+
30
+ def delete(self, *args, **kwargs):
31
+ attachment = next(
32
+ (
33
+ entity
34
+ for entity in [self.address, self.customs, self.parcel]
35
+ if entity is not None
36
+ ),
37
+ super(),
38
+ )
39
+
40
+ return attachment.delete(*args, **kwargs)
41
+
42
+ @property
43
+ def object_type(self):
44
+ return "template"
@@ -0,0 +1,46 @@
1
+ import pkgutil
2
+ import logging
3
+ import strawberry
4
+ import strawberry
5
+ import strawberry.schema.config as config
6
+
7
+ import karrio.server.graph.schemas as schemas
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ QUERIES: list = []
12
+ MUTATIONS: list = []
13
+ EXTRA_TYPES: list = []
14
+
15
+ # Register karrio graphql schemas
16
+ for _, name, _ in pkgutil.iter_modules(schemas.__path__): # type: ignore
17
+ try:
18
+ schema = __import__(f"{schemas.__name__}.{name}", fromlist=[name])
19
+ if hasattr(schema, "Query"):
20
+ QUERIES.append(schema.Query)
21
+ if hasattr(schema, "Mutation"):
22
+ MUTATIONS.append(schema.Mutation)
23
+ if hasattr(schema, "extra_types"):
24
+ EXTRA_TYPES += schema.extra_types
25
+ except Exception as e:
26
+ logger.warning(f'Failed to register "{name}" schema')
27
+ logger.exception(e)
28
+
29
+
30
+ @strawberry.type
31
+ class Query(*QUERIES): # type: ignore
32
+ pass
33
+
34
+
35
+ @strawberry.type
36
+ class Mutation(*MUTATIONS): # type: ignore
37
+ pass
38
+
39
+
40
+ schema = strawberry.Schema( # type: ignore
41
+ query=Query,
42
+ mutation=Mutation,
43
+ types=[*EXTRA_TYPES],
44
+ config=config.StrawberryConfig(auto_camel_case=False),
45
+ extensions=[],
46
+ )
@@ -0,0 +1,2 @@
1
+ # type: ignore
2
+ __path__ = __import__("pkgutil").extend_path(__path__, __name__)
@@ -0,0 +1,367 @@
1
+ import typing
2
+ import strawberry
3
+ from strawberry.types import Info
4
+
5
+ import karrio.server.core.models as core
6
+ import karrio.server.graph.models as graph
7
+ import karrio.server.manager.models as manager
8
+ import karrio.server.providers.models as providers
9
+ import karrio.server.manager.serializers as manager_serializers
10
+ import karrio.server.graph.schemas.base.mutations as mutations
11
+ import karrio.server.graph.schemas.base.inputs as inputs
12
+ import karrio.server.graph.schemas.base.types as types
13
+ import karrio.server.graph.utils as utils
14
+
15
+ # extra_types = [*types.CarrierSettings.values()]
16
+ extra_types = []
17
+
18
+
19
+ @strawberry.type
20
+ class Query:
21
+ user: types.UserType = strawberry.field(resolver=types.UserType.resolve)
22
+ token: types.TokenType = strawberry.field(resolver=types.TokenType.resolve)
23
+ api_keys: typing.List[types.APIKeyType] = strawberry.field(
24
+ resolver=types.APIKeyType.resolve_list
25
+ )
26
+ workspace_config: typing.Optional[types.WorkspaceConfigType] = strawberry.field(
27
+ resolver=types.WorkspaceConfigType.resolve
28
+ )
29
+ system_usage: types.SystemUsageType = strawberry.field(
30
+ resolver=types.SystemUsageType.resolve
31
+ )
32
+
33
+ user_connections: typing.List[types.CarrierConnectionType] = strawberry.field(
34
+ resolver=types.CarrierConnectionType.resolve_list_legacy
35
+ )
36
+ system_connections: typing.List[types.SystemConnectionType] = strawberry.field(
37
+ resolver=types.SystemConnectionType.resolve_list
38
+ )
39
+
40
+ default_templates: types.DefaultTemplatesType = strawberry.field(
41
+ resolver=types.DefaultTemplatesType.resolve
42
+ )
43
+ address_templates: utils.Connection[types.AddressTemplateType] = strawberry.field(
44
+ resolver=types.AddressTemplateType.resolve_list
45
+ )
46
+ customs_templates: utils.Connection[types.CustomsTemplateType] = strawberry.field(
47
+ resolver=types.CustomsTemplateType.resolve_list
48
+ )
49
+ parcel_templates: utils.Connection[types.ParcelTemplateType] = strawberry.field(
50
+ resolver=types.ParcelTemplateType.resolve_list
51
+ )
52
+
53
+ log: typing.Optional[types.LogType] = strawberry.field(
54
+ resolver=types.LogType.resolve
55
+ )
56
+ logs: utils.Connection[types.LogType] = strawberry.field(
57
+ resolver=types.LogType.resolve_list
58
+ )
59
+
60
+ tracing_record: typing.Optional[types.TracingRecordType] = strawberry.field(
61
+ resolver=types.TracingRecordType.resolve
62
+ )
63
+ tracing_records: utils.Connection[types.TracingRecordType] = strawberry.field(
64
+ resolver=types.TracingRecordType.resolve_list
65
+ )
66
+
67
+ shipment: typing.Optional[types.ShipmentType] = strawberry.field(
68
+ resolver=types.ShipmentType.resolve
69
+ )
70
+ shipments: utils.Connection[types.ShipmentType] = strawberry.field(
71
+ resolver=types.ShipmentType.resolve_list
72
+ )
73
+
74
+ tracker: typing.Optional[types.TrackerType] = strawberry.field(
75
+ resolver=types.TrackerType.resolve
76
+ )
77
+ trackers: utils.Connection[types.TrackerType] = strawberry.field(
78
+ resolver=types.TrackerType.resolve_list
79
+ )
80
+
81
+ rate_sheet: typing.Optional[types.RateSheetType] = strawberry.field(
82
+ resolver=types.RateSheetType.resolve
83
+ )
84
+ rate_sheets: utils.Connection[types.RateSheetType] = strawberry.field(
85
+ resolver=types.RateSheetType.resolve_list
86
+ )
87
+
88
+ manifest: typing.Optional[types.ManifestType] = strawberry.field(
89
+ resolver=types.ManifestType.resolve
90
+ )
91
+ manifests: utils.Connection[types.ManifestType] = strawberry.field(
92
+ resolver=types.ManifestType.resolve_list
93
+ )
94
+
95
+ carrier_connection: typing.Optional[types.CarrierConnectionType] = strawberry.field(
96
+ resolver=types.CarrierConnectionType.resolve
97
+ )
98
+ carrier_connections: utils.Connection[types.CarrierConnectionType] = (
99
+ strawberry.field(resolver=types.CarrierConnectionType.resolve_list)
100
+ )
101
+
102
+ metafield: typing.Optional[types.MetafieldType] = strawberry.field(
103
+ resolver=types.MetafieldType.resolve
104
+ )
105
+ metafields: utils.Connection[types.MetafieldType] = strawberry.field(
106
+ resolver=types.MetafieldType.resolve_list
107
+ )
108
+
109
+
110
+ @strawberry.type
111
+ class Mutation:
112
+ @strawberry.mutation
113
+ def update_user(
114
+ self, info: Info, input: inputs.UpdateUserInput
115
+ ) -> mutations.UserUpdateMutation:
116
+ return mutations.UserUpdateMutation.mutate(info, **input.to_dict())
117
+
118
+ @strawberry.mutation
119
+ def register_user(
120
+ self, info: Info, input: inputs.RegisterUserMutationInput
121
+ ) -> mutations.RegisterUserMutation:
122
+ return mutations.RegisterUserMutation.mutate(info, **input.to_dict())
123
+
124
+ @strawberry.mutation
125
+ def update_workspace_config(
126
+ self, info: Info, input: inputs.WorkspaceConfigMutationInput
127
+ ) -> mutations.WorkspaceConfigMutation:
128
+ return mutations.WorkspaceConfigMutation.mutate(info, **input.to_dict())
129
+
130
+ @strawberry.mutation
131
+ def mutate_token(
132
+ self, info: Info, input: inputs.TokenMutationInput
133
+ ) -> mutations.TokenMutation:
134
+ return mutations.TokenMutation.mutate(info, **input.to_dict())
135
+
136
+ @strawberry.mutation
137
+ def create_api_key(
138
+ self, info: Info, input: inputs.CreateAPIKeyMutationInput
139
+ ) -> mutations.CreateAPIKeyMutation:
140
+ return mutations.CreateAPIKeyMutation.mutate(info, **input.to_dict())
141
+
142
+ @strawberry.mutation
143
+ def delete_api_key(
144
+ self, info: Info, input: inputs.DeleteAPIKeyMutationInput
145
+ ) -> mutations.DeleteAPIKeyMutation:
146
+ return mutations.DeleteAPIKeyMutation.mutate(info, **input.to_dict())
147
+
148
+ @strawberry.mutation
149
+ def request_email_change(
150
+ self, info: Info, input: inputs.RequestEmailChangeMutationInput
151
+ ) -> mutations.RequestEmailChangeMutation:
152
+ return mutations.RequestEmailChangeMutation.mutate(info, **input.to_dict())
153
+
154
+ @strawberry.mutation
155
+ def confirm_email_change(
156
+ self, info: Info, input: inputs.ConfirmEmailChangeMutationInput
157
+ ) -> mutations.ConfirmEmailChangeMutation:
158
+ return mutations.ConfirmEmailChangeMutation.mutate(info, **input.to_dict())
159
+
160
+ @strawberry.mutation
161
+ def confirm_email(
162
+ self, info: Info, input: inputs.ConfirmEmailMutationInput
163
+ ) -> mutations.ConfirmEmailMutation:
164
+ return mutations.ConfirmEmailMutation.mutate(info, **input.to_dict())
165
+
166
+ @strawberry.mutation
167
+ def change_password(
168
+ self, info: Info, input: inputs.ChangePasswordMutationInput
169
+ ) -> mutations.ChangePasswordMutation:
170
+ return mutations.ChangePasswordMutation.mutate(info, **input.to_dict())
171
+
172
+ @strawberry.mutation
173
+ def request_password_reset(
174
+ self, info: Info, input: inputs.RequestPasswordResetMutationInput
175
+ ) -> mutations.RequestPasswordResetMutation:
176
+ return mutations.RequestPasswordResetMutation.mutate(info, **input.to_dict())
177
+
178
+ @strawberry.mutation
179
+ def confirm_password_reset(
180
+ self, info: Info, input: inputs.ConfirmPasswordResetMutationInput
181
+ ) -> mutations.ConfirmPasswordResetMutation:
182
+ return mutations.ConfirmPasswordResetMutation.mutate(info, **input.to_dict())
183
+
184
+ @strawberry.mutation
185
+ def enable_multi_factor(
186
+ self, info: Info, input: inputs.EnableMultiFactorMutationInput
187
+ ) -> mutations.EnableMultiFactorMutation:
188
+ return mutations.EnableMultiFactorMutation.mutate(info, **input.to_dict())
189
+
190
+ @strawberry.mutation
191
+ def confirm_multi_factor(
192
+ self, info: Info, input: inputs.ConfirmMultiFactorMutationInput
193
+ ) -> mutations.ConfirmMultiFactorMutation:
194
+ return mutations.ConfirmMultiFactorMutation.mutate(info, **input.to_dict())
195
+
196
+ @strawberry.mutation
197
+ def disable_multi_factor(
198
+ self, info: Info, input: inputs.DisableMultiFactorMutationInput
199
+ ) -> mutations.DisableMultiFactorMutation:
200
+ return mutations.DisableMultiFactorMutation.mutate(info, **input.to_dict())
201
+
202
+ @strawberry.mutation
203
+ def create_address_template(
204
+ self, info: Info, input: inputs.CreateAddressTemplateInput
205
+ ) -> mutations.CreateAddressTemplateMutation:
206
+ return mutations.CreateAddressTemplateMutation.mutate(info, **input.to_dict())
207
+
208
+ @strawberry.mutation
209
+ def update_address_template(
210
+ self, info: Info, input: inputs.UpdateAddressTemplateInput
211
+ ) -> mutations.UpdateAddressTemplateMutation:
212
+ return mutations.UpdateAddressTemplateMutation.mutate(info, **input.to_dict())
213
+
214
+ @strawberry.mutation
215
+ def create_customs_template(
216
+ self, info: Info, input: inputs.CreateCustomsTemplateInput
217
+ ) -> mutations.CreateCustomsTemplateMutation:
218
+ return mutations.CreateCustomsTemplateMutation.mutate(info, **input.to_dict())
219
+
220
+ @strawberry.mutation
221
+ def update_customs_template(
222
+ self, info: Info, input: inputs.UpdateCustomsTemplateInput
223
+ ) -> mutations.UpdateCustomsTemplateMutation:
224
+ return mutations.UpdateCustomsTemplateMutation.mutate(info, **input.to_dict())
225
+
226
+ @strawberry.mutation
227
+ def create_parcel_template(
228
+ self, info: Info, input: inputs.CreateParcelTemplateInput
229
+ ) -> mutations.CreateParcelTemplateMutation:
230
+ return mutations.CreateParcelTemplateMutation.mutate(info, **input.to_dict())
231
+
232
+ @strawberry.mutation
233
+ def update_parcel_template(
234
+ self, info: Info, input: inputs.UpdateParcelTemplateInput
235
+ ) -> mutations.UpdateParcelTemplateMutation:
236
+ return mutations.UpdateParcelTemplateMutation.mutate(info, **input.to_dict())
237
+
238
+ @strawberry.mutation
239
+ def create_carrier_connection(
240
+ self, info: Info, input: inputs.CreateCarrierConnectionMutationInput
241
+ ) -> mutations.CreateCarrierConnectionMutation:
242
+ return mutations.CreateCarrierConnectionMutation.mutate(info, **input.to_dict())
243
+
244
+ @strawberry.mutation
245
+ def update_carrier_connection(
246
+ self, info: Info, input: inputs.UpdateCarrierConnectionMutationInput
247
+ ) -> mutations.UpdateCarrierConnectionMutation:
248
+ return mutations.UpdateCarrierConnectionMutation.mutate(info, **input.to_dict())
249
+
250
+ @strawberry.mutation
251
+ def mutate_system_connection(
252
+ self, info: Info, input: inputs.SystemCarrierMutationInput
253
+ ) -> mutations.SystemCarrierMutation:
254
+ return mutations.SystemCarrierMutation.mutate(info, **input.to_dict())
255
+
256
+ @strawberry.mutation
257
+ def delete_carrier_connection(
258
+ self, info: Info, input: inputs.DeleteMutationInput
259
+ ) -> mutations.DeleteMutation:
260
+ return mutations.DeleteMutation.mutate(
261
+ info, model=providers.Carrier, **input.to_dict()
262
+ )
263
+
264
+ @strawberry.mutation
265
+ def partial_shipment_update(
266
+ self, info: Info, input: inputs.PartialShipmentMutationInput
267
+ ) -> mutations.PartialShipmentMutation:
268
+ return mutations.PartialShipmentMutation.mutate(info, **input.to_dict())
269
+
270
+ @strawberry.mutation
271
+ def mutate_metadata(
272
+ self, info: Info, input: inputs.MetadataMutationInput
273
+ ) -> mutations.MetadataMutation:
274
+ return mutations.MetadataMutation.mutate(info, **input.to_dict())
275
+
276
+ @strawberry.mutation
277
+ def change_shipment_status(
278
+ self, info: Info, input: inputs.ChangeShipmentStatusMutationInput
279
+ ) -> mutations.ChangeShipmentStatusMutation:
280
+ return mutations.ChangeShipmentStatusMutation.mutate(info, **input.to_dict())
281
+
282
+ @strawberry.mutation
283
+ def delete_template(
284
+ self, info: Info, input: inputs.DeleteMutationInput
285
+ ) -> mutations.DeleteMutation:
286
+ return mutations.DeleteMutation.mutate(
287
+ info, model=graph.Template, **input.to_dict()
288
+ )
289
+
290
+ @strawberry.mutation
291
+ def discard_commodity(
292
+ self, info: Info, input: inputs.DeleteMutationInput
293
+ ) -> mutations.DeleteMutation:
294
+ return mutations.DeleteMutation.mutate(
295
+ info,
296
+ model=manager.Commodity,
297
+ validator=manager_serializers.can_mutate_commodity,
298
+ **input.to_dict()
299
+ )
300
+
301
+ @strawberry.mutation
302
+ def discard_customs(
303
+ self, info: Info, input: inputs.DeleteMutationInput
304
+ ) -> mutations.DeleteMutation:
305
+ return mutations.DeleteMutation.mutate(
306
+ info,
307
+ model=manager.Customs,
308
+ validator=manager_serializers.can_mutate_customs,
309
+ **input.to_dict()
310
+ )
311
+
312
+ @strawberry.mutation
313
+ def discard_parcel(
314
+ self, info: Info, input: inputs.DeleteMutationInput
315
+ ) -> mutations.DeleteMutation:
316
+ return mutations.DeleteMutation.mutate(
317
+ info,
318
+ model=manager.Parcel,
319
+ validator=manager_serializers.can_mutate_parcel,
320
+ **input.to_dict()
321
+ )
322
+
323
+ @strawberry.mutation
324
+ def create_rate_sheet(
325
+ self, info: Info, input: inputs.CreateRateSheetMutationInput
326
+ ) -> mutations.CreateRateSheetMutation:
327
+ return mutations.CreateRateSheetMutation.mutate(info, **input.to_dict())
328
+
329
+ @strawberry.mutation
330
+ def update_rate_sheet(
331
+ self, info: Info, input: inputs.UpdateRateSheetMutationInput
332
+ ) -> mutations.UpdateRateSheetMutation:
333
+ return mutations.UpdateRateSheetMutation.mutate(info, **input.to_dict())
334
+
335
+ @strawberry.mutation
336
+ def delete_rate_sheet(
337
+ self, info: Info, input: inputs.DeleteMutationInput
338
+ ) -> mutations.DeleteMutation:
339
+ return mutations.DeleteMutation.mutate(
340
+ info, model=providers.RateSheet, **input.to_dict()
341
+ )
342
+
343
+ @strawberry.mutation
344
+ def create_metafield(
345
+ self, info: Info, input: inputs.CreateMetafieldInput
346
+ ) -> mutations.CreateMetafieldMutation:
347
+ return mutations.CreateMetafieldMutation.mutate(info, **input.to_dict())
348
+
349
+ @strawberry.mutation
350
+ def update_metafield(
351
+ self, info: Info, input: inputs.UpdateMetafieldInput
352
+ ) -> mutations.UpdateMetafieldMutation:
353
+ return mutations.UpdateMetafieldMutation.mutate(info, **input.to_dict())
354
+
355
+ @strawberry.mutation
356
+ def delete_metafield(
357
+ self, info: Info, input: inputs.DeleteMutationInput
358
+ ) -> mutations.DeleteMutation:
359
+ return mutations.DeleteMutation.mutate(
360
+ info, model=core.Metafield, **input.to_dict()
361
+ )
362
+
363
+ @strawberry.mutation
364
+ def update_service_zone(
365
+ self, info: Info, input: inputs.UpdateServiceZoneMutationInput
366
+ ) -> mutations.UpdateServiceZoneMutation:
367
+ return mutations.UpdateServiceZoneMutation.mutate(info, **input.to_dict())