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,1365 @@
1
+ import typing
2
+ import logging
3
+ import datetime
4
+ import strawberry
5
+ import django.db.models as models
6
+ import django.db.models.functions as functions
7
+ from django.conf import settings
8
+ from strawberry.types import Info
9
+ from django.contrib.auth import get_user_model
10
+ from django.utils.translation import gettext_lazy as _
11
+
12
+ import karrio.lib as lib
13
+ import karrio.server.conf as conf
14
+ import karrio.server.user.models as auth
15
+ import karrio.server.core.models as core
16
+ import karrio.server.graph.utils as utils
17
+ import karrio.server.graph.models as graph
18
+ import karrio.server.core.filters as filters
19
+ import karrio.server.orders.models as orders
20
+ import karrio.server.manager.models as manager
21
+ import karrio.server.tracing.models as tracing
22
+ import karrio.server.providers.models as providers
23
+ import karrio.server.orders.filters as order_filters
24
+ import karrio.server.user.serializers as user_serializers
25
+ import karrio.server.graph.schemas.base.inputs as inputs
26
+
27
+ User = get_user_model()
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ @strawberry.type
32
+ class UserType:
33
+ email: str
34
+ full_name: str
35
+ is_staff: bool
36
+ is_active: bool
37
+ date_joined: datetime.datetime
38
+ is_superuser: typing.Optional[bool] = strawberry.UNSET
39
+ last_login: typing.Optional[datetime.datetime] = strawberry.UNSET
40
+
41
+ @strawberry.field
42
+ def permissions(self: User, info) -> typing.Optional[typing.List[str]]:
43
+ # Return permissions from token if exists
44
+ if hasattr(getattr(info.context.request, "token", None), "permissions"):
45
+ return info.context.request.token.permissions
46
+
47
+ # Return permissions from user
48
+ return info.context.request.user.permissions
49
+
50
+ @staticmethod
51
+ @utils.authentication_required
52
+ def resolve(info) -> typing.Optional["UserType"]:
53
+ return User.objects.get(id=info.context.request.user.id)
54
+
55
+
56
+ @strawberry.type
57
+ class WorkspaceConfigType:
58
+ object_type: str
59
+
60
+ @property
61
+ def config(self: auth.WorkspaceConfig) -> dict:
62
+ try:
63
+ return lib.to_dict(self.config)
64
+ except:
65
+ return self.config
66
+
67
+ # general preferences
68
+ # region
69
+
70
+ @strawberry.field
71
+ def default_currency(
72
+ self: auth.WorkspaceConfig,
73
+ ) -> typing.Optional[utils.CurrencyCodeEnum]:
74
+ return self.config.get("default_currency")
75
+
76
+ @strawberry.field
77
+ def default_country_code(
78
+ self: auth.WorkspaceConfig,
79
+ ) -> typing.Optional[utils.CountryCodeEnum]:
80
+ return self.config.get("default_country_code")
81
+
82
+ @strawberry.field
83
+ def default_weight_unit(
84
+ self: auth.WorkspaceConfig,
85
+ ) -> typing.Optional[utils.WeightUnitEnum]:
86
+ return self.config.get("default_weight_unit")
87
+
88
+ @strawberry.field
89
+ def default_dimension_unit(
90
+ self: auth.WorkspaceConfig,
91
+ ) -> typing.Optional[utils.DimensionUnitEnum]:
92
+ return self.config.get("default_dimension_unit")
93
+
94
+ @strawberry.field
95
+ def state_tax_id(self: auth.WorkspaceConfig) -> typing.Optional[str]:
96
+ return self.config.get("state_tax_id")
97
+
98
+ @strawberry.field
99
+ def federal_tax_id(self: auth.WorkspaceConfig) -> typing.Optional[str]:
100
+ return self.config.get("federal_tax_id")
101
+
102
+ @strawberry.field
103
+ def default_label_type(
104
+ self: auth.WorkspaceConfig,
105
+ ) -> typing.Optional[utils.LabelTypeEnum]:
106
+ return self.config.get("default_label_type")
107
+
108
+ # endregion
109
+
110
+ # default options preferences
111
+ # region
112
+
113
+ @strawberry.field
114
+ def insured_by_default(
115
+ self: auth.WorkspaceConfig,
116
+ ) -> typing.Optional[bool]:
117
+ return self.config.get("insured_by_default")
118
+
119
+ # endregion
120
+
121
+ # customs identifiers
122
+ # region
123
+
124
+ @strawberry.field
125
+ def customs_aes(self: auth.WorkspaceConfig) -> typing.Optional[str]:
126
+ return self.config.get("customs_aes")
127
+
128
+ @strawberry.field
129
+ def customs_eel_pfc(self: auth.WorkspaceConfig) -> typing.Optional[str]:
130
+ return self.config.get("customs_eel_pfc")
131
+
132
+ @strawberry.field
133
+ def customs_license_number(self: auth.WorkspaceConfig) -> typing.Optional[str]:
134
+ return self.config.get("customs_license_number")
135
+
136
+ @strawberry.field
137
+ def customs_certificate_number(self: auth.WorkspaceConfig) -> typing.Optional[str]:
138
+ return self.config.get("customs_certificate_number")
139
+
140
+ @strawberry.field
141
+ def customs_nip_number(self: auth.WorkspaceConfig) -> typing.Optional[str]:
142
+ return self.config.get("customs_nip_number")
143
+
144
+ @strawberry.field
145
+ def customs_eori_number(self: auth.WorkspaceConfig) -> typing.Optional[str]:
146
+ return self.config.get("customs_eori_number")
147
+
148
+ @strawberry.field
149
+ def customs_vat_registration_number(
150
+ self: auth.WorkspaceConfig,
151
+ ) -> typing.Optional[str]:
152
+ return self.config.get("customs_vat_registration_number")
153
+
154
+ # endregion
155
+
156
+ # label printing
157
+ # region
158
+
159
+ @strawberry.field
160
+ def label_message_1(self: auth.WorkspaceConfig) -> typing.Optional[str]:
161
+ return self.config.get("label_message_1")
162
+
163
+ @strawberry.field
164
+ def label_message_2(self: auth.WorkspaceConfig) -> typing.Optional[str]:
165
+ return self.config.get("label_message_2")
166
+
167
+ @strawberry.field
168
+ def label_message_3(self: auth.WorkspaceConfig) -> typing.Optional[str]:
169
+ return self.config.get("label_message_3")
170
+
171
+ @strawberry.field
172
+ def label_logo(self: auth.WorkspaceConfig) -> typing.Optional[str]:
173
+ return self.config.get("label_logo")
174
+
175
+ # endregion
176
+
177
+ @staticmethod
178
+ @utils.authentication_required
179
+ def resolve(info) -> typing.Optional["WorkspaceConfigType"]:
180
+ return auth.WorkspaceConfig.access_by(info.context.request).first()
181
+
182
+
183
+ @strawberry.type
184
+ class SystemUsageType:
185
+ total_errors: typing.Optional[int] = None
186
+ order_volume: typing.Optional[float] = None
187
+ total_requests: typing.Optional[int] = None
188
+ total_trackers: typing.Optional[int] = None
189
+ total_shipments: typing.Optional[int] = None
190
+ organization_count: typing.Optional[int] = None
191
+ user_count: typing.Optional[int] = None
192
+ total_shipping_spend: typing.Optional[float] = None
193
+ api_errors: typing.Optional[typing.List[utils.UsageStatType]] = None
194
+ api_requests: typing.Optional[typing.List[utils.UsageStatType]] = None
195
+ order_volumes: typing.Optional[typing.List[utils.UsageStatType]] = None
196
+ shipment_count: typing.Optional[typing.List[utils.UsageStatType]] = None
197
+ shipping_spend: typing.Optional[typing.List[utils.UsageStatType]] = None
198
+ tracker_count: typing.Optional[typing.List[utils.UsageStatType]] = None
199
+
200
+ @staticmethod
201
+ @utils.authentication_required
202
+ def resolve(
203
+ info,
204
+ filter: typing.Optional[utils.UsageFilter] = strawberry.UNSET,
205
+ ) -> "SystemUsageType":
206
+ _test_mode = info.context.request.test_mode
207
+ _test_filter = dict(test_mode=_test_mode)
208
+ _filter = {
209
+ "date_before": datetime.datetime.now(),
210
+ "date_after": (datetime.datetime.now() - datetime.timedelta(days=30)),
211
+ **(filter if not utils.is_unset(filter) else utils.UsageFilter()).to_dict(),
212
+ }
213
+
214
+ api_requests = (
215
+ filters.LogFilter(
216
+ _filter,
217
+ core.APILogIndex.objects.filter(**_test_filter),
218
+ )
219
+ .qs.annotate(date=functions.TruncDay("requested_at"))
220
+ .values("date")
221
+ .annotate(count=models.Count("id"))
222
+ .order_by("-date")
223
+ )
224
+ api_errors = (
225
+ filters.LogFilter(
226
+ {**_filter, "status": "failed"},
227
+ core.APILogIndex.objects.filter(**_test_filter),
228
+ )
229
+ .qs.annotate(date=functions.TruncDay("requested_at"))
230
+ .values("date")
231
+ .annotate(count=models.Count("id"))
232
+ .order_by("-date")
233
+ )
234
+ order_volumes = (
235
+ order_filters.OrderFilters(
236
+ dict(
237
+ created_before=_filter["date_before"],
238
+ created_after=_filter["date_after"],
239
+ ),
240
+ orders.Order.objects.filter(**_test_filter).exclude(
241
+ status__in=["cancelled", "unfulfilled"]
242
+ ),
243
+ )
244
+ .qs.annotate(date=functions.TruncDay("created_at"))
245
+ .values("date")
246
+ .annotate(
247
+ count=models.Sum(
248
+ models.F("line_items__value_amount")
249
+ * models.F("line_items__quantity")
250
+ )
251
+ )
252
+ .order_by("-date")
253
+ )
254
+ shipment_count = (
255
+ filters.ShipmentFilters(
256
+ dict(
257
+ created_before=_filter["date_before"],
258
+ created_after=_filter["date_after"],
259
+ ),
260
+ manager.Shipment.objects.filter(**_test_filter),
261
+ )
262
+ .qs.annotate(date=functions.TruncDay("created_at"))
263
+ .values("date")
264
+ .annotate(count=models.Count("id"))
265
+ .order_by("-date")
266
+ )
267
+ shipping_spend = (
268
+ filters.ShipmentFilters(
269
+ dict(
270
+ created_before=_filter["date_before"],
271
+ created_after=_filter["date_after"],
272
+ ),
273
+ manager.Shipment.objects.filter(**_test_filter).exclude(
274
+ status__in=["cancelled", "draft"]
275
+ ),
276
+ )
277
+ .qs.annotate(date=functions.TruncDay("created_at"))
278
+ .values("date")
279
+ .annotate(
280
+ count=models.Sum(
281
+ functions.Cast("selected_rate__total_charge", models.FloatField())
282
+ )
283
+ )
284
+ .order_by("-date")
285
+ )
286
+ tracker_count = (
287
+ filters.TrackerFilters(
288
+ dict(
289
+ created_before=_filter["date_before"],
290
+ created_after=_filter["date_after"],
291
+ ),
292
+ manager.Tracking.objects.filter(**_test_filter),
293
+ )
294
+ .qs.annotate(date=functions.TruncDay("created_at"))
295
+ .values("date")
296
+ .annotate(count=models.Count("id"))
297
+ .order_by("-date")
298
+ )
299
+
300
+ total_errors = sum([item["count"] for item in api_errors], 0)
301
+ total_requests = sum([item["count"] for item in api_requests], 0)
302
+ total_trackers = sum([item["count"] for item in tracker_count], 0)
303
+ total_shipments = sum([item["count"] for item in shipment_count], 0)
304
+ order_volume = lib.to_money(sum([item["count"] for item in order_volumes], 0.0))
305
+ total_shipping_spend = lib.to_money(
306
+ sum([item["count"] for item in shipping_spend], 0.0)
307
+ )
308
+ user_count = User.objects.count()
309
+ organization_count = 1
310
+
311
+ if conf.settings.MULTI_ORGANIZATIONS:
312
+ import karrio.server.orgs.models as orgs
313
+
314
+ organization_count = orgs.Organization.objects.count()
315
+
316
+ return SystemUsageType(
317
+ order_volume=order_volume,
318
+ total_errors=total_errors,
319
+ total_requests=total_requests,
320
+ total_trackers=total_trackers,
321
+ total_shipments=total_shipments,
322
+ organization_count=organization_count,
323
+ user_count=user_count,
324
+ total_shipping_spend=total_shipping_spend,
325
+ api_errors=[utils.UsageStatType.parse(item) for item in api_errors],
326
+ api_requests=[utils.UsageStatType.parse(item) for item in api_requests],
327
+ order_volumes=[utils.UsageStatType.parse(item) for item in order_volumes],
328
+ shipment_count=[utils.UsageStatType.parse(item) for item in shipment_count],
329
+ shipping_spend=[utils.UsageStatType.parse(item) for item in shipping_spend],
330
+ tracker_count=[utils.UsageStatType.parse(item) for item in tracker_count],
331
+ )
332
+
333
+
334
+ @strawberry.type
335
+ class MetafieldType:
336
+ object_type: str
337
+ id: str
338
+ key: str
339
+ is_required: bool
340
+ type: utils.MetafieldTypeEnum
341
+ value: typing.Optional[utils.JSON] = None
342
+
343
+ @strawberry.field
344
+ def parsed_value(self: core.Metafield) -> typing.Optional[utils.JSON]:
345
+ """Return the value parsed according to its type."""
346
+ return self.get_parsed_value()
347
+
348
+ @staticmethod
349
+ @utils.authentication_required
350
+ def resolve(info, id: str) -> typing.Optional["MetafieldType"]:
351
+ return core.Metafield.access_by(info.context.request).filter(id=id).first()
352
+
353
+ @staticmethod
354
+ @utils.authentication_required
355
+ def resolve_list(
356
+ info,
357
+ filter: typing.Optional[inputs.MetafieldFilter] = strawberry.UNSET,
358
+ ) -> utils.Connection["MetafieldType"]:
359
+ _filter = filter if not utils.is_unset(filter) else inputs.MetafieldFilter()
360
+ queryset = core.Metafield.access_by(info.context.request)
361
+
362
+ # Apply filters
363
+ if not utils.is_unset(_filter.key):
364
+ queryset = queryset.filter(key__icontains=_filter.key)
365
+ if not utils.is_unset(_filter.type):
366
+ queryset = queryset.filter(type=_filter.type)
367
+ if not utils.is_unset(_filter.is_required):
368
+ queryset = queryset.filter(is_required=_filter.is_required)
369
+
370
+ return utils.paginated_connection(queryset, **_filter.pagination())
371
+
372
+
373
+ @strawberry.type
374
+ class LogType:
375
+ object_type: str
376
+ id: int
377
+ user: typing.Optional[UserType]
378
+ requested_at: typing.Optional[datetime.datetime]
379
+ response_ms: typing.Optional[int]
380
+ path: typing.Optional[str]
381
+ remote_addr: typing.Optional[str]
382
+ host: typing.Optional[str]
383
+ method: typing.Optional[str]
384
+ status_code: typing.Optional[int]
385
+ test_mode: typing.Optional[bool]
386
+
387
+ @strawberry.field
388
+ def data(self: core.APILog) -> typing.Optional[utils.JSON]:
389
+ try:
390
+ return lib.to_dict(self.data)
391
+ except:
392
+ return self.data
393
+
394
+ @strawberry.field
395
+ def response(self: core.APILog) -> typing.Optional[utils.JSON]:
396
+ try:
397
+ return lib.to_dict(self.response)
398
+ except:
399
+ return self.response
400
+
401
+ @strawberry.field
402
+ def query_params(self: core.APILog) -> typing.Optional[utils.JSON]:
403
+ try:
404
+ return lib.to_dict(self.query_params)
405
+ except:
406
+ return self.query_params
407
+
408
+ @strawberry.field
409
+ def records(
410
+ self: tracing.TracingRecord, info: Info
411
+ ) -> typing.List["TracingRecordType"]:
412
+ queryset = tracing.TracingRecord.objects.filter(meta__request_log_id=self.id)
413
+
414
+ if User.objects.filter(
415
+ id=info.context.request.user.id, is_staff=False
416
+ ).exists():
417
+ # exclude system carriers records if user is not staff
418
+ system_carriers = [
419
+ item["id"]
420
+ for item in providers.Carrier.system_carriers.all().values("id")
421
+ ]
422
+ queryset = queryset.exclude(meta__carrier_account_id__in=system_carriers)
423
+
424
+ return queryset
425
+
426
+ @staticmethod
427
+ @utils.authentication_required
428
+ def resolve(info, id: int) -> typing.Optional["LogType"]:
429
+ return core.APILogIndex.access_by(info.context.request).filter(id=id).first()
430
+
431
+ @staticmethod
432
+ @utils.authentication_required
433
+ def resolve_list(
434
+ info,
435
+ filter: typing.Optional[inputs.LogFilter] = strawberry.UNSET,
436
+ ) -> utils.Connection["LogType"]:
437
+ _filter = filter if not utils.is_unset(filter) else inputs.LogFilter()
438
+ queryset = filters.LogFilter(
439
+ _filter.to_dict(), core.APILogIndex.access_by(info.context.request)
440
+ ).qs
441
+ return utils.paginated_connection(queryset, **_filter.pagination())
442
+
443
+
444
+ @strawberry.type
445
+ class TracingRecordType:
446
+ object_type: str
447
+ id: typing.Optional[str]
448
+ key: typing.Optional[str]
449
+ timestamp: typing.Optional[float]
450
+ test_mode: typing.Optional[bool]
451
+ created_by: typing.Optional[UserType]
452
+ created_at: typing.Optional[datetime.datetime]
453
+ updated_at: typing.Optional[datetime.datetime]
454
+
455
+ @strawberry.field
456
+ def record(self: tracing.TracingRecord) -> typing.Optional[utils.JSON]:
457
+ try:
458
+ return lib.to_dict(self.record)
459
+ except:
460
+ return self.record
461
+
462
+ @strawberry.field
463
+ def meta(self: tracing.TracingRecord) -> typing.Optional[utils.JSON]:
464
+ try:
465
+ return lib.to_dict(self.meta)
466
+ except:
467
+ return self.meta
468
+
469
+ @staticmethod
470
+ @utils.authentication_required
471
+ def resolve(info, id: str) -> typing.Optional["TracingRecordType"]:
472
+ return (
473
+ tracing.TracingRecord.access_by(info.context.request).filter(id=id).first()
474
+ )
475
+
476
+ @staticmethod
477
+ @utils.authentication_required
478
+ def resolve_list(
479
+ info,
480
+ filter: typing.Optional[inputs.TracingRecordFilter] = strawberry.UNSET,
481
+ ) -> utils.Connection["TracingRecordType"]:
482
+ _filter = filter if not utils.is_unset(filter) else inputs.TracingRecordFilter()
483
+ queryset = filters.TracingRecordFilter(
484
+ _filter.to_dict(), tracing.TracingRecord.access_by(info.context.request)
485
+ ).qs
486
+ return utils.paginated_connection(queryset, **_filter.pagination())
487
+
488
+
489
+ @strawberry.type
490
+ class TokenType:
491
+ object_type: str
492
+ key: str
493
+ label: str
494
+ test_mode: bool
495
+ created: datetime.datetime
496
+
497
+ @strawberry.field
498
+ def permissions(self: auth.Token, info) -> typing.Optional[typing.List[str]]:
499
+ return self.permissions
500
+
501
+ @staticmethod
502
+ @utils.authentication_required
503
+ def resolve(info, org_id: typing.Optional[str] = strawberry.UNSET) -> "TokenType":
504
+ return user_serializers.TokenSerializer.retrieve_token(
505
+ info.context.request,
506
+ **({"org_id": org_id} if org_id is not strawberry.UNSET else {}),
507
+ )
508
+
509
+
510
+ @strawberry.type
511
+ class APIKeyType:
512
+ object_type: str
513
+ key: str
514
+ label: str
515
+ test_mode: bool
516
+ created: datetime.datetime
517
+
518
+ @strawberry.field
519
+ def permissions(self: auth.Token, info) -> typing.Optional[typing.List[str]]:
520
+ return self.permissions
521
+
522
+ @staticmethod
523
+ @utils.authentication_required
524
+ def resolve_list(
525
+ info,
526
+ ) -> typing.List["APIKeyType"]:
527
+ _filters = {
528
+ "user__id": info.context.request.user.id,
529
+ "test_mode": info.context.request.test_mode,
530
+ **(
531
+ {"org__id": info.context.request.org.id}
532
+ if getattr(info.context.request, "org", None) is not None
533
+ and settings.MULTI_ORGANIZATIONS
534
+ else {}
535
+ ),
536
+ }
537
+ keys = auth.Token.objects.filter(**_filters)
538
+
539
+ if keys.exists():
540
+ return keys
541
+
542
+ user_serializers.TokenSerializer.map(
543
+ data={}, context=info.context.request
544
+ ).save()
545
+
546
+ return auth.Token.objects.filter(**_filters)
547
+
548
+
549
+ @strawberry.type
550
+ class MessageType:
551
+ carrier_name: typing.Optional[str]
552
+ carrier_id: typing.Optional[str]
553
+ message: typing.Optional[str]
554
+ code: typing.Optional[str]
555
+ details: typing.Optional[utils.JSON] = None
556
+
557
+ @staticmethod
558
+ def parse(charge: dict):
559
+ return MessageType(
560
+ **{k: v for k, v in charge.items() if k in MessageType.__annotations__}
561
+ )
562
+
563
+
564
+ @strawberry.type
565
+ class ChargeType:
566
+ name: typing.Optional[str] = None
567
+ amount: typing.Optional[float] = None
568
+ currency: utils.CurrencyCodeEnum = None
569
+
570
+ @staticmethod
571
+ def parse(charge: dict):
572
+ return ChargeType(
573
+ **{k: v for k, v in charge.items() if k in ChargeType.__annotations__}
574
+ )
575
+
576
+
577
+ @strawberry.type
578
+ class RateType:
579
+ id: str
580
+ object_type: str
581
+ carrier_name: str
582
+ carrier_id: str
583
+ service: str
584
+ test_mode: bool
585
+ total_charge: float
586
+ currency: utils.CurrencyCodeEnum
587
+ extra_charges: typing.List[ChargeType]
588
+ meta: typing.Optional[utils.JSON] = None
589
+ transit_days: typing.Optional[int] = None
590
+
591
+ @staticmethod
592
+ def parse(rate: dict):
593
+ return RateType(
594
+ **{
595
+ "object_type": "rate",
596
+ **{k: v for k, v in rate.items() if k in RateType.__annotations__},
597
+ "extra_charges": [
598
+ ChargeType.parse(charge)
599
+ for charge in (rate.get("extra_charges") or [])
600
+ ],
601
+ }
602
+ )
603
+
604
+
605
+ @strawberry.type
606
+ class CommodityType:
607
+ id: str
608
+ object_type: str
609
+ weight: float
610
+ quantity: int
611
+ metadata: utils.JSON
612
+ sku: typing.Optional[str]
613
+ title: typing.Optional[str]
614
+ hs_code: typing.Optional[str]
615
+ description: typing.Optional[str]
616
+ value_amount: typing.Optional[float]
617
+ weight_unit: typing.Optional[utils.WeightUnitEnum]
618
+ origin_country: typing.Optional[utils.CountryCodeEnum]
619
+ value_currency: typing.Optional[utils.CurrencyCodeEnum]
620
+ created_at: typing.Optional[datetime.datetime]
621
+ updated_at: typing.Optional[datetime.datetime]
622
+ created_by: typing.Optional[UserType]
623
+ parent_id: typing.Optional[str] = None
624
+ parent: typing.Optional["CommodityType"] = None
625
+ unfulfilled_quantity: typing.Optional[int] = None
626
+
627
+
628
+ @strawberry.type
629
+ class AddressType:
630
+ id: str
631
+ object_type: str
632
+ postal_code: typing.Optional[str]
633
+ city: typing.Optional[str]
634
+ federal_tax_id: typing.Optional[str]
635
+ state_tax_id: typing.Optional[str]
636
+ person_name: typing.Optional[str]
637
+ company_name: typing.Optional[str]
638
+ country_code: utils.CountryCodeEnum
639
+ email: typing.Optional[str]
640
+ phone_number: typing.Optional[str]
641
+ state_code: typing.Optional[str]
642
+ suburb: typing.Optional[str]
643
+ residential: typing.Optional[bool]
644
+ street_number: typing.Optional[str]
645
+ address_line1: typing.Optional[str]
646
+ address_line2: typing.Optional[str]
647
+ created_at: typing.Optional[datetime.datetime]
648
+ updated_at: typing.Optional[datetime.datetime]
649
+ created_by: typing.Optional[UserType]
650
+ validate_location: typing.Optional[bool]
651
+ validation: typing.Optional[utils.JSON] = None
652
+
653
+
654
+ @strawberry.type
655
+ class ParcelType:
656
+ id: str
657
+ object_type: str
658
+ weight: typing.Optional[float]
659
+ width: typing.Optional[float]
660
+ height: typing.Optional[float]
661
+ length: typing.Optional[float]
662
+ packaging_type: typing.Optional[str]
663
+ package_preset: typing.Optional[str]
664
+ description: typing.Optional[str]
665
+ content: typing.Optional[str]
666
+ is_document: typing.Optional[bool]
667
+ weight_unit: typing.Optional[utils.WeightUnitEnum]
668
+ dimension_unit: typing.Optional[utils.DimensionUnitEnum]
669
+ freight_class: typing.Optional[str]
670
+ reference_number: typing.Optional[str]
671
+ created_at: datetime.datetime
672
+ updated_at: datetime.datetime
673
+ created_by: UserType
674
+
675
+ @strawberry.field
676
+ def items(self: manager.Parcel) -> typing.List[CommodityType]:
677
+ return self.items.all()
678
+
679
+
680
+ @strawberry.type
681
+ class DutyType:
682
+ paid_by: typing.Optional[utils.PaidByEnum] = None
683
+ currency: typing.Optional[utils.CurrencyCodeEnum] = None
684
+ account_number: typing.Optional[str] = None
685
+ declared_value: typing.Optional[float] = None
686
+ bill_to: typing.Optional[AddressType] = None
687
+
688
+
689
+ @strawberry.type
690
+ class CustomsType:
691
+ id: str
692
+ object_type: str
693
+ certify: typing.Optional[bool] = strawberry.UNSET
694
+ commercial_invoice: typing.Optional[bool] = strawberry.UNSET
695
+ content_type: typing.Optional[utils.CustomsContentTypeEnum] = strawberry.UNSET
696
+ content_description: typing.Optional[str] = strawberry.UNSET
697
+ incoterm: typing.Optional[utils.IncotermCodeEnum] = strawberry.UNSET
698
+ invoice: typing.Optional[str] = strawberry.UNSET
699
+ invoice_date: typing.Optional[str] = strawberry.UNSET
700
+ signer: typing.Optional[str] = strawberry.UNSET
701
+ created_at: typing.Optional[datetime.datetime] = strawberry.UNSET
702
+ updated_at: typing.Optional[datetime.datetime] = strawberry.UNSET
703
+ created_by: typing.Optional[UserType] = strawberry.UNSET
704
+ options: typing.Optional[utils.JSON] = strawberry.UNSET
705
+ duty_billing_address: typing.Optional[AddressType] = strawberry.UNSET
706
+
707
+ @strawberry.field
708
+ def duty(self: manager) -> typing.Optional[DutyType]:
709
+ if self.duty is None:
710
+ return None
711
+
712
+ return DutyType(**self.duty)
713
+
714
+ @strawberry.field
715
+ def commodities(self: manager.Customs) -> typing.List[CommodityType]:
716
+ return self.commodities.all()
717
+
718
+
719
+ @strawberry.type
720
+ class AddressTemplateType:
721
+ id: str
722
+ object_type: str
723
+ label: str
724
+ address: AddressType
725
+ is_default: typing.Optional[bool] = None
726
+
727
+ @staticmethod
728
+ @utils.authentication_required
729
+ def resolve_list(
730
+ info,
731
+ filter: typing.Optional[inputs.AddressFilter] = strawberry.UNSET,
732
+ ) -> utils.Connection["AddressTemplateType"]:
733
+ _filter = inputs.AddressFilter() if utils.is_unset(filter) else filter
734
+ _search = _filter.to_dict()
735
+ _query = models.Q()
736
+
737
+ if any(_search.get("label") or ""):
738
+ _value = _search.get("label")
739
+ _query = _query | models.Q(label__icontains=_value)
740
+
741
+ if any(_search.get("address") or ""):
742
+ _value = _search.get("address")
743
+ _query = (
744
+ _query
745
+ | models.Q(address__address_line1__icontains=_value)
746
+ | models.Q(address__address_line2__icontains=_value)
747
+ | models.Q(address__postal_code__icontains=_value)
748
+ | models.Q(address__person_name__icontains=_value)
749
+ | models.Q(address__company_name__icontains=_value)
750
+ | models.Q(address__country_code__icontains=_value)
751
+ | models.Q(address__city__icontains=_value)
752
+ | models.Q(address__email__icontains=_value)
753
+ | models.Q(address__phone_number__icontains=_value)
754
+ )
755
+
756
+ if any(_search.get("keyword") or ""):
757
+ _value = _search.get("keyword")
758
+ _query = (
759
+ _query
760
+ | models.Q(label__icontains=_value)
761
+ | models.Q(address__address_line1__icontains=_value)
762
+ | models.Q(address__address_line2__icontains=_value)
763
+ | models.Q(address__postal_code__icontains=_value)
764
+ | models.Q(address__person_name__icontains=_value)
765
+ | models.Q(address__company_name__icontains=_value)
766
+ | models.Q(address__country_code__icontains=_value)
767
+ | models.Q(address__city__icontains=_value)
768
+ | models.Q(address__email__icontains=_value)
769
+ | models.Q(address__phone_number__icontains=_value)
770
+ )
771
+
772
+ _queryset = graph.Template.access_by(info.context.request).filter(
773
+ _query, address__isnull=False
774
+ )
775
+
776
+ return utils.paginated_connection(_queryset, **_filter.pagination())
777
+
778
+
779
+ @strawberry.type
780
+ class ParcelTemplateType:
781
+ id: str
782
+ object_type: str
783
+ label: str
784
+ parcel: ParcelType
785
+ is_default: typing.Optional[bool]
786
+
787
+ @staticmethod
788
+ @utils.authentication_required
789
+ def resolve_list(
790
+ info,
791
+ filter: typing.Optional[inputs.TemplateFilter] = strawberry.UNSET,
792
+ ) -> utils.Connection["ParcelTemplateType"]:
793
+ _filter = inputs.TemplateFilter() if filter == strawberry.UNSET else filter
794
+ _search = _filter.to_dict()
795
+ _query = models.Q()
796
+
797
+ if any(_search.get("label") or ""):
798
+ _value = _search.get("label")
799
+ _query = _query | models.Q(label__icontains=_value)
800
+
801
+ if any(_search.get("keyword") or ""):
802
+ _value = _search.get("keyword")
803
+ _query = _query | models.Q(label__icontains=_value)
804
+
805
+ queryset = graph.Template.access_by(info.context.request).filter(
806
+ _query,
807
+ parcel__isnull=False,
808
+ )
809
+
810
+ return utils.paginated_connection(queryset, **_filter.pagination())
811
+
812
+
813
+ @strawberry.type
814
+ class CustomsTemplateType:
815
+ id: str
816
+ object_type: str
817
+ label: str
818
+ customs: CustomsType
819
+ is_default: typing.Optional[bool]
820
+
821
+ @staticmethod
822
+ @utils.authentication_required
823
+ def resolve_list(
824
+ info,
825
+ filter: typing.Optional[inputs.TemplateFilter] = strawberry.UNSET,
826
+ ) -> utils.Connection["CustomsTemplateType"]:
827
+ _filter = filter if not utils.is_unset(filter) else inputs.TemplateFilter()
828
+
829
+ queryset = graph.Template.access_by(info.context.request).filter(
830
+ customs__isnull=False,
831
+ **(
832
+ {"label__icontain": _filter.label}
833
+ if _filter.label is not strawberry.UNSET
834
+ else {}
835
+ ),
836
+ )
837
+ return utils.paginated_connection(queryset, **_filter.pagination())
838
+
839
+
840
+ @strawberry.type
841
+ class DefaultTemplatesType:
842
+ default_address: typing.Optional[AddressTemplateType] = None
843
+ default_customs: typing.Optional[CustomsTemplateType] = None
844
+ default_parcel: typing.Optional[ParcelTemplateType] = None
845
+
846
+ @staticmethod
847
+ @utils.authentication_required
848
+ def resolve(info) -> "DefaultTemplatesType":
849
+ templates = graph.Template.access_by(info.context.request).filter(
850
+ is_default=True
851
+ )
852
+
853
+ return DefaultTemplatesType( # type: ignore
854
+ default_address=templates.filter(address__isnull=False).first(),
855
+ default_customs=templates.filter(customs__isnull=False).first(),
856
+ default_parcel=templates.filter(parcel__isnull=False).first(),
857
+ )
858
+
859
+
860
+ @strawberry.type
861
+ class TrackingEventType:
862
+ description: typing.Optional[str] = None
863
+ location: typing.Optional[str] = None
864
+ code: typing.Optional[str] = None
865
+ date: typing.Optional[str] = None
866
+ time: typing.Optional[str] = None
867
+ latitude: typing.Optional[float] = None
868
+ longitude: typing.Optional[float] = None
869
+
870
+ @staticmethod
871
+ def parse(charge: dict):
872
+ return TrackingEventType(
873
+ **{
874
+ k: v
875
+ for k, v in charge.items()
876
+ if k in TrackingEventType.__annotations__
877
+ }
878
+ )
879
+
880
+
881
+ @strawberry.type
882
+ class TrackingInfoType:
883
+ carrier_tracking_link: typing.Optional[str] = None
884
+ customer_name: typing.Optional[str] = None
885
+ expected_delivery: typing.Optional[str] = None
886
+ note: typing.Optional[str] = None
887
+ order_date: typing.Optional[str] = None
888
+ order_id: typing.Optional[str] = None
889
+ package_weight: typing.Optional[str] = None
890
+ package_weight_unit: typing.Optional[str] = None
891
+ shipment_package_count: typing.Optional[str] = None
892
+ shipment_pickup_date: typing.Optional[str] = None
893
+ shipment_delivery_date: typing.Optional[str] = None
894
+ shipment_service: typing.Optional[str] = None
895
+ shipment_origin_country: typing.Optional[str] = None
896
+ shipment_origin_postal_code: typing.Optional[str] = None
897
+ shipment_destination_country: typing.Optional[str] = None
898
+ shipment_destination_postal_code: typing.Optional[str] = None
899
+ shipping_date: typing.Optional[str] = None
900
+ signed_by: typing.Optional[str] = None
901
+ source: typing.Optional[str] = None
902
+
903
+ @staticmethod
904
+ def parse(charge: dict):
905
+ return TrackingInfoType(
906
+ **{k: v for k, v in charge.items() if k in TrackingInfoType.__annotations__}
907
+ )
908
+
909
+
910
+ @strawberry.type
911
+ class TrackerType:
912
+ id: str
913
+ object_type: str
914
+ tracking_number: str
915
+ test_mode: bool
916
+ metadata: utils.JSON
917
+ status: utils.TrackerStatusEnum
918
+ delivered: typing.Optional[bool]
919
+ estimated_delivery: typing.Optional[datetime.date]
920
+ document_image_url: typing.Optional[str]
921
+ signature_image_url: typing.Optional[str]
922
+ options: typing.Optional[utils.JSON]
923
+ meta: typing.Optional[utils.JSON]
924
+ shipment: typing.Optional["ShipmentType"]
925
+ created_at: datetime.datetime
926
+ updated_at: datetime.datetime
927
+ created_by: UserType
928
+
929
+ @strawberry.field
930
+ def carrier_id(self: manager.Tracking) -> str:
931
+ return getattr(self.tracking_carrier, "carrier_id", None)
932
+
933
+ @strawberry.field
934
+ def carrier_name(self: manager.Tracking) -> str:
935
+ return getattr(self.tracking_carrier, "carrier_name", None)
936
+
937
+ @strawberry.field
938
+ def info(self: manager.Tracking) -> typing.Optional[TrackingInfoType]:
939
+ return TrackingInfoType.parse(self.info) if self.info else None
940
+
941
+ @strawberry.field
942
+ def events(self: manager.Tracking) -> typing.List[TrackingEventType]:
943
+ return [TrackingEventType.parse(msg) for msg in self.events or []]
944
+
945
+ @strawberry.field
946
+ def messages(self: manager.Tracking) -> typing.List[MessageType]:
947
+ return [MessageType.parse(msg) for msg in self.messages or []]
948
+
949
+ @strawberry.field
950
+ def tracking_carrier(
951
+ self: manager.Tracking,
952
+ ) -> typing.Optional["CarrierConnectionType"]:
953
+ return self.tracking_carrier
954
+
955
+ @staticmethod
956
+ @utils.authentication_required
957
+ def resolve(info, id: str) -> typing.Optional["TrackerType"]:
958
+ return manager.Tracking.access_by(info.context.request).filter(id=id).first()
959
+
960
+ @staticmethod
961
+ @utils.authentication_required
962
+ def resolve_list(
963
+ info,
964
+ filter: typing.Optional[inputs.TrackerFilter] = strawberry.UNSET,
965
+ ) -> utils.Connection["TrackerType"]:
966
+ _filter = filter if not utils.is_unset(filter) else inputs.TrackerFilter()
967
+ queryset = filters.TrackerFilters(
968
+ _filter.to_dict(), manager.Tracking.access_by(info.context.request)
969
+ ).qs
970
+ return utils.paginated_connection(queryset, **_filter.pagination())
971
+
972
+
973
+ @strawberry.type
974
+ class ManifestType:
975
+ id: str
976
+ object_type: str
977
+ test_mode: bool
978
+ metadata: utils.JSON
979
+ meta: utils.JSON
980
+ options: utils.JSON
981
+ address: AddressType
982
+ shipment_identifiers: typing.List[str]
983
+ manifest_url: typing.Optional[str]
984
+ reference: typing.Optional[str]
985
+ created_at: datetime.datetime
986
+ updated_at: datetime.datetime
987
+
988
+ @strawberry.field
989
+ def carrier_id(self: manager.Manifest) -> str:
990
+ return getattr(self.manifest_carrier, "carrier_id", None)
991
+
992
+ @strawberry.field
993
+ def carrier_name(self: manager.Manifest) -> str:
994
+ return getattr(self.manifest_carrier, "carrier_name", None)
995
+
996
+ @strawberry.field
997
+ def messages(self: manager.Manifest) -> typing.List[MessageType]:
998
+ return [MessageType.parse(msg) for msg in self.messages or []]
999
+
1000
+ @strawberry.field
1001
+ def manifest_carrier(
1002
+ self: manager.Manifest,
1003
+ ) -> typing.Optional["CarrierConnectionType"]:
1004
+ return self.manifest_carrier
1005
+
1006
+ @staticmethod
1007
+ @utils.authentication_required
1008
+ @utils.authorization_required(["manage_shipments"])
1009
+ def resolve(info, id: str) -> typing.Optional["ManifestType"]:
1010
+ return manager.Manifest.access_by(info.context.request).filter(id=id).first()
1011
+
1012
+ @staticmethod
1013
+ @utils.authentication_required
1014
+ @utils.authorization_required(["manage_shipments"])
1015
+ def resolve_list(
1016
+ info,
1017
+ filter: typing.Optional[inputs.ManifestFilter] = strawberry.UNSET,
1018
+ ) -> utils.Connection["ManifestType"]:
1019
+ _filter = filter if not utils.is_unset(filter) else inputs.ManifestFilter()
1020
+ queryset = filters.ManifestFilters(
1021
+ _filter.to_dict(), manager.Manifest.access_by(info.context.request)
1022
+ ).qs
1023
+ return utils.paginated_connection(queryset, **_filter.pagination())
1024
+
1025
+
1026
+ @strawberry.type
1027
+ class PaymentType:
1028
+ account_number: typing.Optional[str] = None
1029
+ paid_by: typing.Optional[utils.PaidByEnum] = None
1030
+ currency: typing.Optional[utils.CurrencyCodeEnum] = None
1031
+
1032
+
1033
+ @strawberry.type
1034
+ class ShipmentType:
1035
+ id: str
1036
+ object_type: str
1037
+ test_mode: bool
1038
+ shipper: AddressType
1039
+ recipient: AddressType
1040
+ options: utils.JSON
1041
+ metadata: utils.JSON
1042
+ status: utils.ShipmentStatusEnum
1043
+ return_address: typing.Optional[AddressType]
1044
+ billing_address: typing.Optional[AddressType]
1045
+ meta: typing.Optional[utils.JSON]
1046
+ label_type: typing.Optional[utils.LabelTypeEnum]
1047
+ tracking_number: typing.Optional[str]
1048
+ shipment_identifier: typing.Optional[str]
1049
+ tracking_url: typing.Optional[str]
1050
+ reference: typing.Optional[str]
1051
+ customs: typing.Optional[CustomsType]
1052
+ services: typing.Optional[typing.List[str]]
1053
+ service: typing.Optional[str]
1054
+ carrier_ids: typing.List[str]
1055
+ selected_rate_id: typing.Optional[str]
1056
+ tracker_id: typing.Optional[str]
1057
+ label_url: typing.Optional[str]
1058
+ invoice_url: typing.Optional[str]
1059
+ tracker: typing.Optional[TrackerType]
1060
+ created_at: datetime.datetime
1061
+ updated_at: datetime.datetime
1062
+ created_by: UserType
1063
+
1064
+ @strawberry.field
1065
+ def carrier_id(self: manager.Shipment) -> typing.Optional[str]:
1066
+ return getattr(self.selected_rate_carrier, "carrier_id", None)
1067
+
1068
+ @strawberry.field
1069
+ def carrier_name(self: manager.Shipment) -> typing.Optional[str]:
1070
+ return getattr(self.selected_rate_carrier, "carrier_name", None)
1071
+
1072
+ @strawberry.field
1073
+ def parcels(self: manager.Shipment) -> typing.List[ParcelType]:
1074
+ return self.parcels.all()
1075
+
1076
+ @strawberry.field
1077
+ def rates(self: manager.Shipment) -> typing.List[RateType]:
1078
+ return [RateType.parse(rate) for rate in self.rates or []]
1079
+
1080
+ @strawberry.field
1081
+ def selected_rate(self: manager.Shipment) -> typing.Optional[RateType]:
1082
+ return RateType.parse(self.selected_rate) if self.selected_rate else None
1083
+
1084
+ @strawberry.field
1085
+ def selected_rate_carrier(
1086
+ self: manager.Shipment,
1087
+ ) -> typing.Optional["CarrierConnectionType"]:
1088
+ return self.selected_rate_carrier
1089
+
1090
+ @strawberry.field
1091
+ def payment(self: manager.Shipment) -> typing.Optional[PaymentType]:
1092
+ return PaymentType(**self.payment) if self.payment else None
1093
+
1094
+ @strawberry.field
1095
+ def messages(self: manager.Shipment) -> typing.List[MessageType]:
1096
+ return [MessageType.parse(msg) for msg in self.messages or []]
1097
+
1098
+ @staticmethod
1099
+ @utils.authentication_required
1100
+ @utils.authorization_required(["manage_shipments"])
1101
+ def resolve(info, id: str) -> typing.Optional["ShipmentType"]:
1102
+ return manager.Shipment.access_by(info.context.request).filter(id=id).first()
1103
+
1104
+ @staticmethod
1105
+ @utils.authentication_required
1106
+ @utils.authorization_required(["manage_shipments"])
1107
+ def resolve_list(
1108
+ info,
1109
+ filter: typing.Optional[inputs.ShipmentFilter] = strawberry.UNSET,
1110
+ ) -> utils.Connection["ShipmentType"]:
1111
+ _filter = filter if not utils.is_unset(filter) else inputs.ShipmentFilter()
1112
+ queryset = filters.ShipmentFilters(
1113
+ _filter.to_dict(), manager.Shipment.access_by(info.context.request)
1114
+ ).qs
1115
+ return utils.paginated_connection(queryset, **_filter.pagination())
1116
+
1117
+
1118
+ @strawberry.type
1119
+ class ServiceZoneType:
1120
+ object_type: str
1121
+ label: typing.Optional[str] = None
1122
+ rate: typing.Optional[float] = None
1123
+
1124
+ min_weight: typing.Optional[float] = None
1125
+ max_weight: typing.Optional[float] = None
1126
+
1127
+ transit_days: typing.Optional[int] = None
1128
+ transit_time: typing.Optional[float] = None
1129
+
1130
+ radius: typing.Optional[float] = None
1131
+ latitude: typing.Optional[float] = None
1132
+ longitude: typing.Optional[float] = None
1133
+
1134
+ cities: typing.Optional[typing.List[str]] = None
1135
+ postal_codes: typing.Optional[typing.List[str]] = None
1136
+ country_codes: typing.Optional[typing.List[utils.CountryCodeEnum]] = None
1137
+
1138
+ @staticmethod
1139
+ def parse(zone: dict):
1140
+ return ServiceZoneType(
1141
+ **{
1142
+ "object_type": "zone",
1143
+ **{
1144
+ k: v
1145
+ for k, v in zone.items()
1146
+ if k in ServiceZoneType.__annotations__
1147
+ },
1148
+ }
1149
+ )
1150
+
1151
+
1152
+ @strawberry.type
1153
+ class ServiceLevelType:
1154
+ id: str
1155
+ object_type: str
1156
+ service_name: typing.Optional[str]
1157
+ service_code: typing.Optional[str]
1158
+ carrier_service_code: typing.Optional[str]
1159
+ description: typing.Optional[str]
1160
+ active: typing.Optional[bool]
1161
+
1162
+ currency: typing.Optional[utils.CurrencyCodeEnum]
1163
+ transit_days: typing.Optional[int]
1164
+ transit_time: typing.Optional[float]
1165
+
1166
+ max_width: typing.Optional[float]
1167
+ max_height: typing.Optional[float]
1168
+ max_length: typing.Optional[float]
1169
+ dimension_unit: typing.Optional[utils.DimensionUnitEnum]
1170
+
1171
+ max_weight: typing.Optional[float]
1172
+ weight_unit: typing.Optional[utils.WeightUnitEnum]
1173
+
1174
+ domicile: typing.Optional[bool]
1175
+ international: typing.Optional[bool]
1176
+
1177
+ @strawberry.field
1178
+ def zones(self: providers.ServiceLevel) -> typing.List[ServiceZoneType]:
1179
+ return [ServiceZoneType.parse(zone) for zone in self.zones or []]
1180
+
1181
+ @strawberry.field
1182
+ def metadata(self: providers.RateSheet) -> typing.Optional[utils.JSON]:
1183
+ try:
1184
+ return lib.to_dict(self.metadata)
1185
+ except:
1186
+ return self.metadata
1187
+
1188
+
1189
+ @strawberry.type
1190
+ class LabelTemplateType:
1191
+ id: str
1192
+ object_type: str
1193
+ slug: typing.Optional[str]
1194
+ template: typing.Optional[str]
1195
+ width: typing.Optional[int]
1196
+ height: typing.Optional[int]
1197
+ shipment_sample: typing.Optional[utils.JSON]
1198
+ template_type: typing.Optional[utils.LabelTemplateTypeEnum]
1199
+
1200
+
1201
+ @strawberry.type
1202
+ class RateSheetType:
1203
+ object_type: str
1204
+ id: str
1205
+ name: str
1206
+ slug: str
1207
+ carrier_name: utils.CarrierNameEnum
1208
+
1209
+ @strawberry.field
1210
+ def metadata(self: providers.RateSheet) -> typing.Optional[utils.JSON]:
1211
+ try:
1212
+ return lib.to_dict(self.metadata)
1213
+ except:
1214
+ return self.metadata
1215
+
1216
+ @strawberry.field
1217
+ def carriers(self: providers.RateSheet) -> typing.List["CarrierConnectionType"]:
1218
+ return self.carriers
1219
+
1220
+ @strawberry.field
1221
+ def services(self: providers.RateSheet) -> typing.List[ServiceLevelType]:
1222
+ return self.services.all()
1223
+
1224
+ @staticmethod
1225
+ @utils.authentication_required
1226
+ @utils.authorization_required(["manage_carriers"])
1227
+ def resolve(info, id: str) -> typing.Optional["RateSheetType"]:
1228
+ return providers.RateSheet.access_by(info.context.request).filter(id=id).first()
1229
+
1230
+ @staticmethod
1231
+ @utils.authentication_required
1232
+ @utils.authorization_required(["manage_carriers"])
1233
+ def resolve_list(
1234
+ info,
1235
+ filter: typing.Optional[inputs.RateSheetFilter] = strawberry.UNSET,
1236
+ ) -> utils.Connection["RateSheetType"]:
1237
+ _filter = filter if not utils.is_unset(filter) else inputs.RateSheetFilter()
1238
+ queryset = filters.RateSheetFilter(
1239
+ _filter.to_dict(), providers.RateSheet.access_by(info.context.request)
1240
+ ).qs
1241
+ return utils.paginated_connection(queryset, **_filter.pagination())
1242
+
1243
+
1244
+ @strawberry.type
1245
+ class SystemConnectionType:
1246
+ id: str
1247
+ active: bool
1248
+ carrier_id: str
1249
+ display_name: str
1250
+ test_mode: bool
1251
+ capabilities: typing.List[str]
1252
+ created_at: typing.Optional[datetime.datetime]
1253
+ updated_at: typing.Optional[datetime.datetime]
1254
+
1255
+ @strawberry.field
1256
+ def carrier_name(self: providers.Carrier) -> str:
1257
+ return getattr(self, "settings", self).carrier_name
1258
+
1259
+ @strawberry.field
1260
+ def enabled(self: providers.Carrier, info: Info) -> bool:
1261
+ if hasattr(self, "active_orgs"):
1262
+ return self.active_orgs.filter(id=info.context.request.org.id).exists()
1263
+
1264
+ return self.active_users.filter(id=info.context.request.user.id).exists()
1265
+
1266
+ @strawberry.field
1267
+ def config(self: providers.Carrier, info: Info) -> typing.Optional[utils.JSON]:
1268
+ return getattr(self, "config", None)
1269
+
1270
+ @staticmethod
1271
+ @utils.authentication_required
1272
+ def resolve_list(
1273
+ info,
1274
+ filter: typing.Optional[inputs.CarrierFilter] = strawberry.UNSET,
1275
+ ) -> typing.List["SystemConnectionType"]:
1276
+ _filter = filter if not utils.is_unset(filter) else inputs.CarrierFilter()
1277
+ connections = filters.CarrierFilters(
1278
+ _filter.to_dict(),
1279
+ providers.Carrier.system_carriers.filter(
1280
+ active=True,
1281
+ test_mode=getattr(info.context.request, "test_mode", False),
1282
+ ),
1283
+ ).qs
1284
+ return connections
1285
+
1286
+
1287
+ @strawberry.type
1288
+ class CarrierConnectionType:
1289
+ id: str
1290
+ carrier_id: str
1291
+ carrier_name: str
1292
+ display_name: str
1293
+ active: bool
1294
+ is_system: bool
1295
+ test_mode: bool
1296
+ credentials: utils.JSON
1297
+ capabilities: typing.List[str]
1298
+ rate_sheet: typing.Optional[RateSheetType] = None
1299
+
1300
+ @strawberry.field
1301
+ def metadata(self: providers.Carrier, info: Info) -> typing.Optional[utils.JSON]:
1302
+ return getattr(self, "metadata", None)
1303
+
1304
+ @strawberry.field
1305
+ def config(self: providers.Carrier, info: Info) -> typing.Optional[utils.JSON]:
1306
+ return getattr(self, "config", None)
1307
+
1308
+ def rate_sheet(
1309
+ self: providers.Carrier, info: Info
1310
+ ) -> typing.Optional[RateSheetType]:
1311
+ return getattr(self, "rate_sheet", None)
1312
+
1313
+ @staticmethod
1314
+ @utils.utils.error_wrapper
1315
+ @utils.authentication_required
1316
+ @utils.authorization_required(["manage_carriers"])
1317
+ def resolve_list_legacy(
1318
+ info,
1319
+ filter: typing.Optional[inputs.CarrierFilter] = strawberry.UNSET,
1320
+ ) -> typing.List["CarrierConnectionType"]:
1321
+ _filter = filter if not utils.is_unset(filter) else inputs.CarrierFilter()
1322
+ connections = filters.CarrierFilters(
1323
+ _filter.to_dict(),
1324
+ providers.Carrier.access_by(info.context.request).filter(is_system=False),
1325
+ ).qs
1326
+ return connections
1327
+
1328
+ @staticmethod
1329
+ @utils.utils.error_wrapper
1330
+ @utils.authentication_required
1331
+ @utils.authorization_required(["manage_carriers"])
1332
+ def resolve(
1333
+ info,
1334
+ id: str,
1335
+ ) -> typing.Optional["CarrierConnectionType"]:
1336
+ connection = (
1337
+ providers.Carrier.access_by(info.context.request).filter(id=id).first()
1338
+ )
1339
+ return connection
1340
+
1341
+ @staticmethod
1342
+ @utils.utils.error_wrapper
1343
+ @utils.authentication_required
1344
+ @utils.authorization_required(["manage_carriers"])
1345
+ def resolve_list(
1346
+ info,
1347
+ filter: typing.Optional[inputs.CarrierFilter] = strawberry.UNSET,
1348
+ ) -> utils.Connection["CarrierConnectionType"]:
1349
+ _filter = filter if not utils.is_unset(filter) else inputs.CarrierFilter()
1350
+ queryset = filters.CarrierFilters(
1351
+ _filter.to_dict(),
1352
+ providers.Carrier.access_by(info.context.request).filter(is_system=False),
1353
+ ).qs
1354
+ connections = utils.paginated_connection(queryset, **_filter.pagination())
1355
+
1356
+ return utils.Connection(
1357
+ page_info=connections.page_info,
1358
+ edges=[
1359
+ utils.Edge(
1360
+ node=edge.node,
1361
+ cursor=edge.cursor,
1362
+ )
1363
+ for edge in connections.edges
1364
+ ],
1365
+ )