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.
- karrio/server/graph/__init__.py +1 -0
- karrio/server/graph/admin.py +3 -0
- karrio/server/graph/apps.py +5 -0
- karrio/server/graph/forms.py +59 -0
- karrio/server/graph/management/__init__.py +0 -0
- karrio/server/graph/management/commands/__init__.py +0 -0
- karrio/server/graph/management/commands/export_schema.py +9 -0
- karrio/server/graph/migrations/0001_initial.py +37 -0
- karrio/server/graph/migrations/0002_auto_20210512_1353.py +22 -0
- karrio/server/graph/migrations/__init__.py +0 -0
- karrio/server/graph/models.py +44 -0
- karrio/server/graph/schema.py +46 -0
- karrio/server/graph/schemas/__init__.py +2 -0
- karrio/server/graph/schemas/base/__init__.py +367 -0
- karrio/server/graph/schemas/base/inputs.py +582 -0
- karrio/server/graph/schemas/base/mutations.py +871 -0
- karrio/server/graph/schemas/base/types.py +1365 -0
- karrio/server/graph/serializers.py +388 -0
- karrio/server/graph/templates/graphql/graphiql.html +142 -0
- karrio/server/graph/templates/karrio/email_change_email.html +13 -0
- karrio/server/graph/templates/karrio/email_change_email.txt +13 -0
- karrio/server/graph/templates/karrio/password_reset_email.html +14 -0
- karrio/server/graph/tests/__init__.py +9 -0
- karrio/server/graph/tests/base.py +124 -0
- karrio/server/graph/tests/test_carrier_connections.py +219 -0
- karrio/server/graph/tests/test_metafield.py +404 -0
- karrio/server/graph/tests/test_rate_sheets.py +348 -0
- karrio/server/graph/tests/test_templates.py +677 -0
- karrio/server/graph/tests/test_user_info.py +71 -0
- karrio/server/graph/urls.py +10 -0
- karrio/server/graph/utils.py +304 -0
- karrio/server/graph/views.py +93 -0
- karrio/server/settings/graph.py +7 -0
- karrio_server_graph-2025.5rc1.dist-info/METADATA +29 -0
- karrio_server_graph-2025.5rc1.dist-info/RECORD +37 -0
- karrio_server_graph-2025.5rc1.dist-info/WHEEL +5 -0
- 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
|
+
)
|