karrio-server-core 2025.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- karrio/server/conf.py +54 -0
- karrio/server/core/__init__.py +3 -0
- karrio/server/core/admin.py +1 -0
- karrio/server/core/apps.py +10 -0
- karrio/server/core/authentication.py +347 -0
- karrio/server/core/config.py +31 -0
- karrio/server/core/context_processors.py +12 -0
- karrio/server/core/datatypes.py +394 -0
- karrio/server/core/dataunits.py +187 -0
- karrio/server/core/exceptions.py +404 -0
- karrio/server/core/fields.py +12 -0
- karrio/server/core/filters.py +837 -0
- karrio/server/core/gateway.py +1011 -0
- karrio/server/core/logging.py +403 -0
- karrio/server/core/management/commands/cli.py +19 -0
- karrio/server/core/management/commands/create_oauth_client.py +41 -0
- karrio/server/core/management/commands/runserver.py +5 -0
- karrio/server/core/middleware.py +197 -0
- karrio/server/core/migrations/0001_initial.py +28 -0
- karrio/server/core/migrations/0002_apilogindex.py +69 -0
- karrio/server/core/migrations/0003_apilogindex_test_mode.py +62 -0
- karrio/server/core/migrations/0004_metafield.py +74 -0
- karrio/server/core/migrations/0005_alter_metafield_type_alter_metafield_value.py +23 -0
- karrio/server/core/migrations/0006_add_api_log_requested_at_index.py +22 -0
- karrio/server/core/migrations/__init__.py +0 -0
- karrio/server/core/models/__init__.py +48 -0
- karrio/server/core/models/base.py +103 -0
- karrio/server/core/models/entity.py +24 -0
- karrio/server/core/models/metafield.py +144 -0
- karrio/server/core/models/third_party.py +21 -0
- karrio/server/core/oauth_validators.py +170 -0
- karrio/server/core/permissions.py +36 -0
- karrio/server/core/renderers.py +11 -0
- karrio/server/core/router.py +3 -0
- karrio/server/core/serializers.py +1971 -0
- karrio/server/core/signals.py +55 -0
- karrio/server/core/telemetry.py +573 -0
- karrio/server/core/tests.py +99 -0
- karrio/server/core/tests_resource_token.py +411 -0
- karrio/server/core/urls.py +12 -0
- karrio/server/core/utils.py +1025 -0
- karrio/server/core/validators.py +264 -0
- karrio/server/core/views/__init__.py +2 -0
- karrio/server/core/views/api.py +133 -0
- karrio/server/core/views/metadata.py +44 -0
- karrio/server/core/views/oauth.py +75 -0
- karrio/server/core/views/references.py +82 -0
- karrio/server/core/views/schema.py +310 -0
- karrio/server/filters/__init__.py +2 -0
- karrio/server/filters/abstract.py +26 -0
- karrio/server/iam/__init__.py +0 -0
- karrio/server/iam/admin.py +3 -0
- karrio/server/iam/apps.py +21 -0
- karrio/server/iam/migrations/0001_initial.py +33 -0
- karrio/server/iam/migrations/__init__.py +0 -0
- karrio/server/iam/models.py +48 -0
- karrio/server/iam/permissions.py +155 -0
- karrio/server/iam/serializers.py +54 -0
- karrio/server/iam/signals.py +18 -0
- karrio/server/iam/tests.py +3 -0
- karrio/server/iam/views.py +3 -0
- karrio/server/openapi.py +75 -0
- karrio/server/providers/__init__.py +1 -0
- karrio/server/providers/admin.py +364 -0
- karrio/server/providers/apps.py +10 -0
- karrio/server/providers/management/commands/migrate_rate_sheets.py +101 -0
- karrio/server/providers/migrations/0001_initial.py +140 -0
- karrio/server/providers/migrations/0002_carrier_active.py +18 -0
- karrio/server/providers/migrations/0003_auto_20201230_0820.py +24 -0
- karrio/server/providers/migrations/0004_auto_20210212_0554.py +178 -0
- karrio/server/providers/migrations/0005_auto_20210212_0555.py +18 -0
- karrio/server/providers/migrations/0006_australiapostsettings.py +29 -0
- karrio/server/providers/migrations/0007_auto_20210213_0206.py +21 -0
- karrio/server/providers/migrations/0008_auto_20210214_0409.py +30 -0
- karrio/server/providers/migrations/0009_auto_20210308_0302.py +18 -0
- karrio/server/providers/migrations/0010_auto_20210409_0852.py +32 -0
- karrio/server/providers/migrations/0011_auto_20210409_0853.py +21 -0
- karrio/server/providers/migrations/0012_alter_carrier_options.py +17 -0
- karrio/server/providers/migrations/0013_tntsettings.py +30 -0
- karrio/server/providers/migrations/0014_auto_20210612_1608.py +46 -0
- karrio/server/providers/migrations/0015_auto_20210615_1601.py +28 -0
- karrio/server/providers/migrations/0016_alter_purolatorsettings_user_token.py +18 -0
- karrio/server/providers/migrations/0017_auto_20210805_0359.py +1293 -0
- karrio/server/providers/migrations/0018_alter_fedexsettings_user_key.py +18 -0
- karrio/server/providers/migrations/0019_dhlpolandsettings_servicelevel.py +65 -0
- karrio/server/providers/migrations/0020_genericsettings_labeltemplate.py +52 -0
- karrio/server/providers/migrations/0021_auto_20211231_2353.py +40 -0
- karrio/server/providers/migrations/0022_carrier_metadata.py +18 -0
- karrio/server/providers/migrations/0023_auto_20220124_1916.py +27 -0
- karrio/server/providers/migrations/0024_alter_genericsettings_custom_carrier_name.py +19 -0
- karrio/server/providers/migrations/0025_alter_servicelevel_service_code.py +19 -0
- karrio/server/providers/migrations/0026_auto_20220208_0132.py +59 -0
- karrio/server/providers/migrations/0027_auto_20220304_1340.py +29 -0
- karrio/server/providers/migrations/0028_auto_20220323_1500.py +33 -0
- karrio/server/providers/migrations/0029_easypostsettings.py +27 -0
- karrio/server/providers/migrations/0030_amazonmwssettings.py +29 -0
- karrio/server/providers/migrations/0031_delete_amazonmwssettings.py +18 -0
- karrio/server/providers/migrations/0032_alter_carrier_test.py +18 -0
- karrio/server/providers/migrations/0033_auto_20220708_1350.py +22 -0
- karrio/server/providers/migrations/0034_amazonmwssettings_dpdhlsettings.py +47 -0
- karrio/server/providers/migrations/0035_alter_carrier_capabilities.py +43 -0
- karrio/server/providers/migrations/0036_upsfreightsettings.py +31 -0
- karrio/server/providers/migrations/0037_chronopostsettings.py +29 -0
- karrio/server/providers/migrations/0038_alter_genericsettings_label_template.py +19 -0
- karrio/server/providers/migrations/0039_auto_20220906_0612.py +23 -0
- karrio/server/providers/migrations/0040_dpdhlsettings_services.py +18 -0
- karrio/server/providers/migrations/0041_auto_20221105_0705.py +38 -0
- karrio/server/providers/migrations/0042_auto_20221215_1642.py +23 -0
- karrio/server/providers/migrations/0043_alter_genericsettings_account_number_and_more.py +39 -0
- karrio/server/providers/migrations/0044_carrier_carrier_capabilities.py +64 -0
- karrio/server/providers/migrations/0045_alter_carrier_active_alter_carrier_carrier_id.py +31 -0
- karrio/server/providers/migrations/0046_remove_dpdhlsettings_signature_and_more.py +41 -0
- karrio/server/providers/migrations/0047_dpdsettings.py +286 -0
- karrio/server/providers/migrations/0048_servicelevel_min_weight_servicelevel_transit_days_and_more.py +64 -0
- karrio/server/providers/migrations/0049_boxknightsettings_geodissettings_lapostesettings_and_more.py +156 -0
- karrio/server/providers/migrations/0050_carrier_is_system_alter_carrier_metadata_and_more.py +106 -0
- karrio/server/providers/migrations/0051_rename_username_upssettings_client_id_and_more.py +31 -0
- karrio/server/providers/migrations/0052_alter_upssettings_account_number_and_more.py +20 -0
- karrio/server/providers/migrations/0053_locate2usettings.py +281 -0
- karrio/server/providers/migrations/0054_zoom2usettings.py +280 -0
- karrio/server/providers/migrations/0055_rename_amazonmwssettings_amazonshippingsettings_and_more.py +44 -0
- karrio/server/providers/migrations/0056_asendiaussettings_geodissettings_code_client_and_more.py +75 -0
- karrio/server/providers/migrations/0057_alter_servicelevel_weight_unit_belgianpostsettings.py +51 -0
- karrio/server/providers/migrations/0058_alliedexpresssettings.py +38 -0
- karrio/server/providers/migrations/0059_ratesheet.py +81 -0
- karrio/server/providers/migrations/0060_belgianpostsettings_rate_sheet_and_more.py +73 -0
- karrio/server/providers/migrations/0061_alliedexpresssettings_service_type.py +17 -0
- karrio/server/providers/migrations/0062_sendlesettings_account_country_code.py +257 -0
- karrio/server/providers/migrations/0063_servicelevel_metadata.py +25 -0
- karrio/server/providers/migrations/0064_alliedexpresslocalsettings.py +43 -0
- karrio/server/providers/migrations/0065_servicelevel_carrier_service_code_and_more.py +66 -0
- karrio/server/providers/migrations/0066_rename_fedexsettings_fedexwssettings_and_more.py +28 -0
- karrio/server/providers/migrations/0067_fedexsettings.py +283 -0
- karrio/server/providers/migrations/0068_fedexsettings_track_api_key_and_more.py +38 -0
- karrio/server/providers/migrations/0069_alter_canadapostsettings_contract_id_and_more.py +23 -0
- karrio/server/providers/migrations/0070_tgesettings_alter_carrier_capabilities.py +65 -0
- karrio/server/providers/migrations/0071_alter_tgesettings_my_toll_token.py +18 -0
- karrio/server/providers/migrations/0072_rename_eshippersettings_eshipperxmlsettings_and_more.py +28 -0
- karrio/server/providers/migrations/0073_delete_eshipperxmlsettings.py +41 -0
- karrio/server/providers/migrations/0074_eshippersettings.py +38 -0
- karrio/server/providers/migrations/0075_haypostsettings.py +40 -0
- karrio/server/providers/migrations/0076_rename_customer_registration_id_uspsinternationalsettings_account_number_and_more.py +125 -0
- karrio/server/providers/migrations/0077_uspswtinternationalsettings_uspswtsettings_and_more.py +165 -0
- karrio/server/providers/migrations/0078_auto_20240813_1552.py +120 -0
- karrio/server/providers/migrations/0079_alter_carrier_options_alter_ratesheet_created_by.py +31 -0
- karrio/server/providers/migrations/0080_alter_aramexsettings_account_country_code_and_more.py +3025 -0
- karrio/server/providers/migrations/0081_remove_alliedexpresssettings_carrier_ptr_and_more.py +338 -0
- karrio/server/providers/migrations/0082_add_zone_identifiers.py +50 -0
- karrio/server/providers/migrations/0083_add_optimized_rate_sheet_structure.py +33 -0
- karrio/server/providers/migrations/0084_alter_servicelevel_currency.py +168 -0
- karrio/server/providers/migrations/0085_populate_dhl_parcel_de_oauth_credentials.py +82 -0
- karrio/server/providers/migrations/0086_rename_dhl_parcel_de_customer_number_to_billing_number.py +71 -0
- karrio/server/providers/migrations/__init__.py +0 -0
- karrio/server/providers/models/__init__.py +16 -0
- karrio/server/providers/models/carrier.py +387 -0
- karrio/server/providers/models/config.py +30 -0
- karrio/server/providers/models/service.py +192 -0
- karrio/server/providers/models/sheet.py +287 -0
- karrio/server/providers/models/template.py +39 -0
- karrio/server/providers/models/utils.py +58 -0
- karrio/server/providers/router.py +3 -0
- karrio/server/providers/serializers/__init__.py +3 -0
- karrio/server/providers/serializers/base.py +538 -0
- karrio/server/providers/signals.py +25 -0
- karrio/server/providers/templates/providers/oauth_callback.html +105 -0
- karrio/server/providers/tests/__init__.py +5 -0
- karrio/server/providers/tests/test_connections.py +895 -0
- karrio/server/providers/urls.py +11 -0
- karrio/server/providers/views/__init__.py +0 -0
- karrio/server/providers/views/carriers.py +267 -0
- karrio/server/providers/views/connections.py +496 -0
- karrio/server/samples.py +352 -0
- karrio/server/serializers/__init__.py +2 -0
- karrio/server/serializers/abstract.py +602 -0
- karrio/server/tracing/__init__.py +0 -0
- karrio/server/tracing/admin.py +63 -0
- karrio/server/tracing/apps.py +8 -0
- karrio/server/tracing/migrations/0001_initial.py +41 -0
- karrio/server/tracing/migrations/0002_auto_20220710_1307.py +22 -0
- karrio/server/tracing/migrations/0003_auto_20221105_0317.py +43 -0
- karrio/server/tracing/migrations/0004_tracingrecord_carrier_account_idx.py +24 -0
- karrio/server/tracing/migrations/0005_optimise_tracingrecord_request_log_idx.py +25 -0
- karrio/server/tracing/migrations/0006_alter_tracingrecord_options_and_more.py +49 -0
- karrio/server/tracing/migrations/0007_tracingrecord_tracing_created_at_idx.py +19 -0
- karrio/server/tracing/migrations/__init__.py +0 -0
- karrio/server/tracing/models.py +82 -0
- karrio/server/tracing/tests.py +3 -0
- karrio/server/tracing/utils.py +109 -0
- karrio/server/user/__init__.py +0 -0
- karrio/server/user/admin.py +96 -0
- karrio/server/user/apps.py +7 -0
- karrio/server/user/forms.py +35 -0
- karrio/server/user/migrations/0001_initial.py +41 -0
- karrio/server/user/migrations/0002_token.py +29 -0
- karrio/server/user/migrations/0003_token_test_mode.py +20 -0
- karrio/server/user/migrations/0004_group.py +26 -0
- karrio/server/user/migrations/0005_token_label.py +21 -0
- karrio/server/user/migrations/0006_workspaceconfig.py +63 -0
- karrio/server/user/migrations/0007_user_metadata.py +25 -0
- karrio/server/user/migrations/__init__.py +0 -0
- karrio/server/user/models.py +218 -0
- karrio/server/user/serializers.py +47 -0
- karrio/server/user/templates/registration/login.html +108 -0
- karrio/server/user/templates/registration/registration_confirm_email.html +10 -0
- karrio/server/user/templates/registration/registration_confirm_email.txt +3 -0
- karrio/server/user/tests.py +3 -0
- karrio/server/user/urls.py +10 -0
- karrio/server/user/utils.py +60 -0
- karrio/server/user/views.py +9 -0
- karrio_server_core-2025.5.dist-info/METADATA +32 -0
- karrio_server_core-2025.5.dist-info/RECORD +213 -0
- karrio_server_core-2025.5.dist-info/WHEEL +5 -0
- karrio_server_core-2025.5.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import attr
|
|
2
|
+
import typing
|
|
3
|
+
import jstruct
|
|
4
|
+
import karrio.core.units as units
|
|
5
|
+
from karrio.core.models import (
|
|
6
|
+
DocumentDetails,
|
|
7
|
+
Documents,
|
|
8
|
+
Images,
|
|
9
|
+
Parcel,
|
|
10
|
+
Message,
|
|
11
|
+
Address as BaseAddress,
|
|
12
|
+
TrackingRequest as BaseTrackingRequest,
|
|
13
|
+
ShipmentDetails,
|
|
14
|
+
Payment,
|
|
15
|
+
Customs,
|
|
16
|
+
RateRequest as BaseRateRequest,
|
|
17
|
+
ShipmentRequest as BaseShipmentRequest,
|
|
18
|
+
ShipmentCancelRequest,
|
|
19
|
+
ChargeDetails,
|
|
20
|
+
PickupRequest as BasePickupRequest,
|
|
21
|
+
PickupDetails,
|
|
22
|
+
PickupUpdateRequest as BasePickupUpdateRequest,
|
|
23
|
+
PickupCancelRequest as BasePickupCancelRequest,
|
|
24
|
+
ConfirmationDetails as Confirmation,
|
|
25
|
+
TrackingEvent,
|
|
26
|
+
TrackingInfo,
|
|
27
|
+
ManifestDocument,
|
|
28
|
+
TrackingDetails,
|
|
29
|
+
DocumentFile,
|
|
30
|
+
DocumentUploadRequest,
|
|
31
|
+
ManifestRequest,
|
|
32
|
+
ManifestDetails,
|
|
33
|
+
RequestPayload,
|
|
34
|
+
OAuthAuthorizePayload,
|
|
35
|
+
OAuthAuthorizeRequest,
|
|
36
|
+
WebhookEventDetails,
|
|
37
|
+
WebhookRegistrationDetails,
|
|
38
|
+
WebhookDeregistrationRequest,
|
|
39
|
+
WebhookRegistrationRequest,
|
|
40
|
+
DutiesCalculationRequest,
|
|
41
|
+
DutiesCalculationDetails,
|
|
42
|
+
InsuranceRequest,
|
|
43
|
+
InsuranceDetails,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
COUNTRIES = [(c.name, c.name) for c in units.Country]
|
|
48
|
+
CURRENCIES = [(c.name, c.name) for c in units.Currency]
|
|
49
|
+
WEIGHT_UNITS = [(c.name, c.name) for c in units.WeightUnit]
|
|
50
|
+
DIMENSION_UNITS = [(c.name, c.name) for c in units.DimensionUnit]
|
|
51
|
+
CAPABILITIES_CHOICES = [(c, c) for c in units.CarrierCapabilities.get_capabilities()]
|
|
52
|
+
LABEL_TYPES = [(c.name, c.name) for c in list(units.LabelType)]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CarrierSettings:
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
carrier_name: str,
|
|
59
|
+
carrier_id: str,
|
|
60
|
+
test_mode: bool = None,
|
|
61
|
+
active: bool = None,
|
|
62
|
+
id: str = None,
|
|
63
|
+
display_name: str = None,
|
|
64
|
+
**kwargs
|
|
65
|
+
):
|
|
66
|
+
self.carrier_name = carrier_name
|
|
67
|
+
self.display_name = display_name
|
|
68
|
+
self.carrier_id = carrier_id
|
|
69
|
+
self.active = active
|
|
70
|
+
self.test_mode = test_mode
|
|
71
|
+
self.id = id
|
|
72
|
+
|
|
73
|
+
for name, value in kwargs.items():
|
|
74
|
+
if name not in ["carrier_ptr", "created_by", "active_users", "active_orgs"]:
|
|
75
|
+
self.__setattr__(name, value)
|
|
76
|
+
|
|
77
|
+
# TODO: rename this to avoid confusion
|
|
78
|
+
def to_dict(self):
|
|
79
|
+
return {
|
|
80
|
+
name: value
|
|
81
|
+
for name, value in self.__dict__.items()
|
|
82
|
+
if name
|
|
83
|
+
not in [
|
|
84
|
+
"carrier_name",
|
|
85
|
+
"created_by",
|
|
86
|
+
"active",
|
|
87
|
+
"capabilities",
|
|
88
|
+
"active_users",
|
|
89
|
+
"active_orgs",
|
|
90
|
+
*([] if self.carrier_name == "generic" else ["display_name"]),
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def create(cls, data: dict):
|
|
96
|
+
return cls(**data)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@attr.s(auto_attribs=True)
|
|
100
|
+
class AddressValidation:
|
|
101
|
+
success: bool
|
|
102
|
+
meta: dict = {}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@attr.s(auto_attribs=True)
|
|
106
|
+
class Address(BaseAddress):
|
|
107
|
+
id: str = None
|
|
108
|
+
postal_code: str = None
|
|
109
|
+
city: str = None
|
|
110
|
+
person_name: str = None
|
|
111
|
+
company_name: str = None
|
|
112
|
+
country_code: str = None
|
|
113
|
+
email: str = None
|
|
114
|
+
phone_number: str = None
|
|
115
|
+
|
|
116
|
+
state_code: str = None
|
|
117
|
+
residential: bool = False
|
|
118
|
+
|
|
119
|
+
address_line1: str = ""
|
|
120
|
+
address_line2: str = None
|
|
121
|
+
street_number: str = None
|
|
122
|
+
suite: str = None
|
|
123
|
+
|
|
124
|
+
federal_tax_id: str = None
|
|
125
|
+
state_tax_id: str = None
|
|
126
|
+
|
|
127
|
+
validate_location: bool = None
|
|
128
|
+
validation: jstruct.JStruct[AddressValidation] = None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@attr.s(auto_attribs=True)
|
|
132
|
+
class PickupRequest(BasePickupRequest):
|
|
133
|
+
pickup_date: str
|
|
134
|
+
ready_time: str
|
|
135
|
+
closing_time: str
|
|
136
|
+
address: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
137
|
+
|
|
138
|
+
parcels: typing.List[Parcel] = jstruct.JList[Parcel]
|
|
139
|
+
shipment_identifiers: typing.List[str] = []
|
|
140
|
+
package_location: str = None
|
|
141
|
+
metadata: typing.Dict = {}
|
|
142
|
+
options: typing.Dict = {}
|
|
143
|
+
instruction: str = None
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@attr.s(auto_attribs=True)
|
|
147
|
+
class PickupUpdateRequest(BasePickupUpdateRequest):
|
|
148
|
+
confirmation_number: str
|
|
149
|
+
pickup_date: str
|
|
150
|
+
ready_time: str
|
|
151
|
+
closing_time: str
|
|
152
|
+
address: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
153
|
+
|
|
154
|
+
parcels: typing.List[Parcel] = jstruct.JList[Parcel]
|
|
155
|
+
shipment_identifiers: typing.List[str] = []
|
|
156
|
+
package_location: str = None
|
|
157
|
+
options: typing.Dict = {}
|
|
158
|
+
instruction: str = None
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@attr.s(auto_attribs=True)
|
|
162
|
+
class PickupCancelRequest(BasePickupCancelRequest):
|
|
163
|
+
confirmation_number: str
|
|
164
|
+
|
|
165
|
+
address: Address = jstruct.JStruct[Address]
|
|
166
|
+
pickup_date: str = None
|
|
167
|
+
reason: str = None
|
|
168
|
+
options: typing.Dict = {}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@attr.s(auto_attribs=True)
|
|
172
|
+
class Rate:
|
|
173
|
+
carrier_name: str
|
|
174
|
+
carrier_id: str
|
|
175
|
+
|
|
176
|
+
currency: str = None
|
|
177
|
+
transit_days: int = None
|
|
178
|
+
service: str = None
|
|
179
|
+
total_charge: float = 0.0
|
|
180
|
+
extra_charges: typing.List[ChargeDetails] = []
|
|
181
|
+
estimated_delivery: str = None
|
|
182
|
+
id: str = None
|
|
183
|
+
meta: dict = None
|
|
184
|
+
test_mode: bool = None
|
|
185
|
+
object_type: str = "rate"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@attr.s(auto_attribs=True)
|
|
189
|
+
class RateRequest(BaseRateRequest):
|
|
190
|
+
shipper: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
191
|
+
recipient: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
192
|
+
parcels: typing.List[Parcel] = jstruct.JList[Parcel, jstruct.REQUIRED]
|
|
193
|
+
|
|
194
|
+
payment: Payment = jstruct.JStruct[Payment]
|
|
195
|
+
customs: Customs = jstruct.JStruct[Customs]
|
|
196
|
+
return_address: Address = jstruct.JStruct[Address]
|
|
197
|
+
billing_address: Address = jstruct.JStruct[Address]
|
|
198
|
+
|
|
199
|
+
services: typing.List[str] = []
|
|
200
|
+
options: typing.Dict = {}
|
|
201
|
+
reference: str = ""
|
|
202
|
+
|
|
203
|
+
carrier_ids: typing.List[str] = []
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@attr.s(auto_attribs=True)
|
|
207
|
+
class ShipmentRequest(BaseShipmentRequest):
|
|
208
|
+
service: str
|
|
209
|
+
selected_rate_id: str # type: ignore
|
|
210
|
+
|
|
211
|
+
shipper: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
212
|
+
recipient: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
213
|
+
parcels: typing.List[Parcel] = jstruct.JList[Parcel, jstruct.REQUIRED]
|
|
214
|
+
rates: typing.List[Rate] = jstruct.JList[Rate, jstruct.REQUIRED]
|
|
215
|
+
|
|
216
|
+
payment: Payment = jstruct.JStruct[Payment]
|
|
217
|
+
customs: Customs = jstruct.JStruct[Customs]
|
|
218
|
+
return_address: Address = jstruct.JStruct[Address]
|
|
219
|
+
billing_address: Address = jstruct.JStruct[Address]
|
|
220
|
+
|
|
221
|
+
options: typing.Dict = {}
|
|
222
|
+
reference: str = ""
|
|
223
|
+
label_type: str = None
|
|
224
|
+
id: str = None
|
|
225
|
+
|
|
226
|
+
metadata: typing.Dict = {}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@attr.s(auto_attribs=True)
|
|
230
|
+
class Shipment:
|
|
231
|
+
carrier_id: str
|
|
232
|
+
carrier_name: str
|
|
233
|
+
tracking_number: str
|
|
234
|
+
shipment_identifier: str
|
|
235
|
+
service: str
|
|
236
|
+
selected_rate_id: str
|
|
237
|
+
|
|
238
|
+
shipper: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
239
|
+
recipient: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
240
|
+
parcels: typing.List[Parcel] = jstruct.JList[Parcel, jstruct.REQUIRED]
|
|
241
|
+
rates: typing.List[Rate] = jstruct.JList[Rate, jstruct.REQUIRED]
|
|
242
|
+
selected_rate: Rate = jstruct.JStruct[Rate, jstruct.REQUIRED]
|
|
243
|
+
docs: Documents = jstruct.JStruct[Documents, jstruct.REQUIRED]
|
|
244
|
+
|
|
245
|
+
payment: Payment = jstruct.JStruct[Payment]
|
|
246
|
+
customs: Customs = jstruct.JStruct[Customs]
|
|
247
|
+
billing_address: Address = jstruct.JStruct[Address]
|
|
248
|
+
|
|
249
|
+
options: typing.Dict = {}
|
|
250
|
+
reference: str = ""
|
|
251
|
+
label_type: str = None
|
|
252
|
+
tracking_url: str = None
|
|
253
|
+
tracker_id: str = None
|
|
254
|
+
status: str = ""
|
|
255
|
+
metadata: typing.Dict = {}
|
|
256
|
+
meta: dict = {}
|
|
257
|
+
id: str = None
|
|
258
|
+
|
|
259
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
260
|
+
created_at: str = None
|
|
261
|
+
test_mode: bool = None
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@attr.s(auto_attribs=True)
|
|
265
|
+
class Pickup:
|
|
266
|
+
carrier_id: str
|
|
267
|
+
carrier_name: str
|
|
268
|
+
|
|
269
|
+
pickup_date: str
|
|
270
|
+
ready_time: str
|
|
271
|
+
closing_time: str
|
|
272
|
+
confirmation_number: str
|
|
273
|
+
address: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
274
|
+
parcels: typing.List[Parcel] = jstruct.JList[Parcel, jstruct.REQUIRED]
|
|
275
|
+
|
|
276
|
+
pickup_charge: ChargeDetails = jstruct.JStruct[ChargeDetails]
|
|
277
|
+
instruction: str = None
|
|
278
|
+
package_location: str = None
|
|
279
|
+
metadata: typing.Dict = {}
|
|
280
|
+
options: typing.Dict = {}
|
|
281
|
+
meta: dict = {}
|
|
282
|
+
id: str = None
|
|
283
|
+
|
|
284
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
285
|
+
test_mode: bool = None
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
@attr.s(auto_attribs=True)
|
|
289
|
+
class TrackingRequest(BaseTrackingRequest):
|
|
290
|
+
tracking_numbers: typing.List[str]
|
|
291
|
+
account_numer: str = None
|
|
292
|
+
reference: str = None
|
|
293
|
+
options: typing.Dict = {}
|
|
294
|
+
info: TrackingInfo = jstruct.JStruct[TrackingInfo]
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
@attr.s(auto_attribs=True)
|
|
298
|
+
class Tracking:
|
|
299
|
+
carrier_name: str
|
|
300
|
+
carrier_id: str
|
|
301
|
+
tracking_number: str
|
|
302
|
+
events: typing.List[TrackingEvent] = jstruct.JList[TrackingEvent]
|
|
303
|
+
|
|
304
|
+
status: str = "unknown"
|
|
305
|
+
info: TrackingInfo = jstruct.JStruct[TrackingInfo]
|
|
306
|
+
images: Images = jstruct.JStruct[Images]
|
|
307
|
+
estimated_delivery: str = None
|
|
308
|
+
delivered: bool = None
|
|
309
|
+
test_mode: bool = None
|
|
310
|
+
options: typing.Dict = {}
|
|
311
|
+
meta: dict = None
|
|
312
|
+
id: str = None
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@attr.s(auto_attribs=True)
|
|
316
|
+
class DocumentUploadResponse:
|
|
317
|
+
carrier_name: str
|
|
318
|
+
carrier_id: str
|
|
319
|
+
documents: typing.List[DocumentDetails] = jstruct.JList[DocumentDetails]
|
|
320
|
+
reference: str = ""
|
|
321
|
+
|
|
322
|
+
test_mode: bool = None
|
|
323
|
+
options: typing.Dict = {}
|
|
324
|
+
meta: dict = None
|
|
325
|
+
id: str = None
|
|
326
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
@attr.s(auto_attribs=True)
|
|
330
|
+
class Manifest:
|
|
331
|
+
carrier_id: str
|
|
332
|
+
carrier_name: str
|
|
333
|
+
|
|
334
|
+
shipment_identifiers: typing.List[str]
|
|
335
|
+
address: Address = jstruct.JStruct[Address, jstruct.REQUIRED]
|
|
336
|
+
doc: ManifestDocument = jstruct.JStruct[ManifestDocument]
|
|
337
|
+
|
|
338
|
+
reference: str = None
|
|
339
|
+
metadata: typing.Dict = {}
|
|
340
|
+
options: typing.Dict = {}
|
|
341
|
+
meta: dict = {}
|
|
342
|
+
id: str = None
|
|
343
|
+
|
|
344
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
345
|
+
test_mode: bool = None
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
@attr.s(auto_attribs=True)
|
|
349
|
+
class ConfirmationResponse:
|
|
350
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
351
|
+
confirmation: Confirmation = jstruct.JStruct[Confirmation]
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
@attr.s(auto_attribs=True)
|
|
355
|
+
class PickupResponse:
|
|
356
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
357
|
+
pickup: Pickup = jstruct.JStruct[Pickup]
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@attr.s(auto_attribs=True)
|
|
361
|
+
class RateResponse:
|
|
362
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
363
|
+
rates: typing.List[Rate] = jstruct.JList[Rate]
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@attr.s(auto_attribs=True)
|
|
367
|
+
class TrackingResponse:
|
|
368
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
369
|
+
tracking: Tracking = jstruct.JStruct[Tracking]
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
@attr.s(auto_attribs=True)
|
|
373
|
+
class ManifestResponse:
|
|
374
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
375
|
+
manifest: Manifest = jstruct.JStruct[Manifest]
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@attr.s(auto_attribs=True)
|
|
379
|
+
class DutiesResponse:
|
|
380
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
381
|
+
duties: DutiesCalculationDetails = jstruct.JStruct[DutiesCalculationDetails]
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
@attr.s(auto_attribs=True)
|
|
385
|
+
class InsuranceResponse:
|
|
386
|
+
messages: typing.List[Message] = jstruct.JList[Message]
|
|
387
|
+
insurance: InsuranceDetails = jstruct.JStruct[InsuranceDetails]
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
@attr.s(auto_attribs=True)
|
|
391
|
+
class Error:
|
|
392
|
+
code: str = None
|
|
393
|
+
message: str = None
|
|
394
|
+
details: typing.Dict = None
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
from constance import config
|
|
2
|
+
from django.urls import reverse
|
|
3
|
+
from rest_framework.request import Request
|
|
4
|
+
|
|
5
|
+
import karrio.lib as lib
|
|
6
|
+
import karrio.references as ref
|
|
7
|
+
import karrio.core.units as units
|
|
8
|
+
import karrio.server.conf as conf
|
|
9
|
+
import karrio.server.core.utils as utils
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
PACKAGE_MAPPERS = ref.collect_providers_data()
|
|
13
|
+
REFERENCE_MODELS = {
|
|
14
|
+
**ref.collect_references(),
|
|
15
|
+
"customs_content_type": {c.name: c.value for c in list(units.CustomsContentType)},
|
|
16
|
+
"incoterms": {c.name: c.value for c in list(units.Incoterm)},
|
|
17
|
+
}
|
|
18
|
+
REFERENCE_EXCLUSIONS = [
|
|
19
|
+
"currencies",
|
|
20
|
+
"incoterms",
|
|
21
|
+
"weight_units",
|
|
22
|
+
"dimension_units",
|
|
23
|
+
"payment_types",
|
|
24
|
+
"option_names",
|
|
25
|
+
"customs_content_type",
|
|
26
|
+
"options",
|
|
27
|
+
]
|
|
28
|
+
CARRIER_NAMES = list(sorted(set([*REFERENCE_MODELS["carriers"].keys(), "generic"])))
|
|
29
|
+
CARRIER_HUBS = list(sorted(REFERENCE_MODELS["carrier_hubs"].keys()))
|
|
30
|
+
NON_HUBS_CARRIERS = [
|
|
31
|
+
carrier_name for carrier_name in CARRIER_NAMES if carrier_name not in CARRIER_HUBS
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def contextual_metadata(request: Request):
|
|
36
|
+
# Detect HTTPS from headers (for proxied environments like Caddy/ALB)
|
|
37
|
+
is_https = False
|
|
38
|
+
if hasattr(request, 'META'):
|
|
39
|
+
# Check X-Forwarded-Proto header (set by load balancers/proxies)
|
|
40
|
+
forwarded_proto = request.META.get('HTTP_X_FORWARDED_PROTO', '').lower()
|
|
41
|
+
# Check if request is secure (Django's built-in HTTPS detection)
|
|
42
|
+
is_secure = getattr(request, 'is_secure', lambda: False)()
|
|
43
|
+
is_https = forwarded_proto == 'https' or is_secure
|
|
44
|
+
|
|
45
|
+
if hasattr(request, "build_absolute_uri"):
|
|
46
|
+
_host: str = request.build_absolute_uri(
|
|
47
|
+
reverse("karrio.server.core:metadata", kwargs={})
|
|
48
|
+
)
|
|
49
|
+
# Override protocol if we detected HTTPS but build_absolute_uri returned HTTP
|
|
50
|
+
if is_https and _host.startswith('http://'):
|
|
51
|
+
_host = _host.replace('http://', 'https://', 1)
|
|
52
|
+
else:
|
|
53
|
+
_host = "/"
|
|
54
|
+
|
|
55
|
+
host = _host[:-1] if _host[-1] == "/" else _host
|
|
56
|
+
name = lib.identity(
|
|
57
|
+
getattr(conf.settings.tenant, "name", conf.settings.APP_NAME)
|
|
58
|
+
if conf.settings.MULTI_TENANTS
|
|
59
|
+
else getattr(config, "APP_NAME", None) or conf.settings.APP_NAME
|
|
60
|
+
)
|
|
61
|
+
website = lib.identity(
|
|
62
|
+
getattr(conf.settings.tenant, "website", conf.settings.APP_WEBSITE)
|
|
63
|
+
if conf.settings.MULTI_TENANTS
|
|
64
|
+
else getattr(config, "APP_WEBSITE", None) or conf.settings.APP_WEBSITE
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Batch fetch all feature flags
|
|
68
|
+
flag_names = [flag for flag, _ in conf.settings.FEATURE_FLAGS]
|
|
69
|
+
|
|
70
|
+
if conf.settings.MULTI_TENANTS:
|
|
71
|
+
# In multi-tenancy mode, feature flags come from tenant.feature_flags (JSON field)
|
|
72
|
+
# No N+1 issue since it's a single field access on an already-loaded tenant object
|
|
73
|
+
tenant = conf.settings.tenant
|
|
74
|
+
tenant_flags = getattr(tenant, "feature_flags", {}) if tenant else {}
|
|
75
|
+
feature_flags = {
|
|
76
|
+
flag: tenant_flags.get(flag, getattr(conf.settings, flag, None))
|
|
77
|
+
for flag in flag_names
|
|
78
|
+
}
|
|
79
|
+
else:
|
|
80
|
+
# In single-tenant mode, batch fetch from Constance to avoid N+1 queries
|
|
81
|
+
constance_values = utils.batch_get_constance_values(flag_names)
|
|
82
|
+
feature_flags = {
|
|
83
|
+
flag: (
|
|
84
|
+
constance_values.get(flag)
|
|
85
|
+
if flag in constance_values
|
|
86
|
+
else getattr(conf.settings, flag, None)
|
|
87
|
+
)
|
|
88
|
+
for flag in flag_names
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
"VERSION": conf.settings.VERSION,
|
|
93
|
+
"APP_NAME": name,
|
|
94
|
+
"APP_WEBSITE": website,
|
|
95
|
+
"HOST": f"{host}/",
|
|
96
|
+
"ADMIN": f"{host}/admin",
|
|
97
|
+
"GRAPHQL": f"{host}/graphql",
|
|
98
|
+
"OPENAPI": f"{host}/openapi",
|
|
99
|
+
**feature_flags,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def contextual_reference(request: Request = None, reduced: bool = True):
|
|
104
|
+
import karrio.server.core.gateway as gateway
|
|
105
|
+
import karrio.server.core.validators as validators
|
|
106
|
+
import karrio.server.core.middleware as middleware
|
|
107
|
+
|
|
108
|
+
request = request or middleware.SessionContext.get_current_request()
|
|
109
|
+
is_authenticated = lib.identity(
|
|
110
|
+
request.user.is_authenticated if hasattr(request, "user") else False
|
|
111
|
+
)
|
|
112
|
+
references = {
|
|
113
|
+
**contextual_metadata(request),
|
|
114
|
+
"ADDRESS_AUTO_COMPLETE": lib.failsafe(
|
|
115
|
+
lambda: validators.Address.get_info(is_authenticated),
|
|
116
|
+
None,
|
|
117
|
+
),
|
|
118
|
+
**{
|
|
119
|
+
k: v
|
|
120
|
+
for k, v in REFERENCE_MODELS.items()
|
|
121
|
+
if k not in (REFERENCE_EXCLUSIONS if reduced else [])
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
def _get_generic_carriers():
|
|
126
|
+
# Get all carriers, then filter by extension instead of hardcoded slug
|
|
127
|
+
system_custom_carriers = [
|
|
128
|
+
c for c in gateway.Carriers.list(system_only=True)
|
|
129
|
+
if c.ext == "generic"
|
|
130
|
+
]
|
|
131
|
+
custom_carriers = [
|
|
132
|
+
c
|
|
133
|
+
for c in (
|
|
134
|
+
gateway.Carriers.list(context=request).exclude(is_system=True)
|
|
135
|
+
if is_authenticated
|
|
136
|
+
else []
|
|
137
|
+
)
|
|
138
|
+
if c.ext == "generic"
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
extra_carriers = {
|
|
142
|
+
c.carrier_code: c.display_name
|
|
143
|
+
for c in custom_carriers
|
|
144
|
+
}
|
|
145
|
+
system_carriers = {
|
|
146
|
+
c.carrier_code: c.display_name
|
|
147
|
+
for c in system_custom_carriers
|
|
148
|
+
}
|
|
149
|
+
extra_services = {
|
|
150
|
+
c.carrier_code: {
|
|
151
|
+
s.service_code: s.service_code
|
|
152
|
+
for s in c.services
|
|
153
|
+
or [
|
|
154
|
+
lib.to_object(lib.models.ServiceLevel, _)
|
|
155
|
+
for _ in references["service_levels"][c.ext]
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
for c in custom_carriers
|
|
159
|
+
}
|
|
160
|
+
extra_service_names = {
|
|
161
|
+
name: {key: key.upper().replace("_", " ") for key, _ in value.items()}
|
|
162
|
+
for name, value in extra_services.items()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
references.update(
|
|
166
|
+
dict(
|
|
167
|
+
custom_carriers=extra_carriers,
|
|
168
|
+
services={**references["services"], **extra_services},
|
|
169
|
+
carriers={**references["carriers"], **system_carriers},
|
|
170
|
+
service_names={**references["service_names"], **extra_service_names},
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if request is not None and "generic" in CARRIER_NAMES:
|
|
175
|
+
_get_generic_carriers()
|
|
176
|
+
|
|
177
|
+
return references
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_carrier_details(
|
|
181
|
+
carrier_name: str,
|
|
182
|
+
contextual_reference: dict = None,
|
|
183
|
+
) -> dict:
|
|
184
|
+
return ref.get_carrier_details(
|
|
185
|
+
carrier_name,
|
|
186
|
+
contextual_reference=contextual_reference or contextual_reference(),
|
|
187
|
+
)
|