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.
Files changed (213) hide show
  1. karrio/server/conf.py +54 -0
  2. karrio/server/core/__init__.py +3 -0
  3. karrio/server/core/admin.py +1 -0
  4. karrio/server/core/apps.py +10 -0
  5. karrio/server/core/authentication.py +347 -0
  6. karrio/server/core/config.py +31 -0
  7. karrio/server/core/context_processors.py +12 -0
  8. karrio/server/core/datatypes.py +394 -0
  9. karrio/server/core/dataunits.py +187 -0
  10. karrio/server/core/exceptions.py +404 -0
  11. karrio/server/core/fields.py +12 -0
  12. karrio/server/core/filters.py +837 -0
  13. karrio/server/core/gateway.py +1011 -0
  14. karrio/server/core/logging.py +403 -0
  15. karrio/server/core/management/commands/cli.py +19 -0
  16. karrio/server/core/management/commands/create_oauth_client.py +41 -0
  17. karrio/server/core/management/commands/runserver.py +5 -0
  18. karrio/server/core/middleware.py +197 -0
  19. karrio/server/core/migrations/0001_initial.py +28 -0
  20. karrio/server/core/migrations/0002_apilogindex.py +69 -0
  21. karrio/server/core/migrations/0003_apilogindex_test_mode.py +62 -0
  22. karrio/server/core/migrations/0004_metafield.py +74 -0
  23. karrio/server/core/migrations/0005_alter_metafield_type_alter_metafield_value.py +23 -0
  24. karrio/server/core/migrations/0006_add_api_log_requested_at_index.py +22 -0
  25. karrio/server/core/migrations/__init__.py +0 -0
  26. karrio/server/core/models/__init__.py +48 -0
  27. karrio/server/core/models/base.py +103 -0
  28. karrio/server/core/models/entity.py +24 -0
  29. karrio/server/core/models/metafield.py +144 -0
  30. karrio/server/core/models/third_party.py +21 -0
  31. karrio/server/core/oauth_validators.py +170 -0
  32. karrio/server/core/permissions.py +36 -0
  33. karrio/server/core/renderers.py +11 -0
  34. karrio/server/core/router.py +3 -0
  35. karrio/server/core/serializers.py +1971 -0
  36. karrio/server/core/signals.py +55 -0
  37. karrio/server/core/telemetry.py +573 -0
  38. karrio/server/core/tests.py +99 -0
  39. karrio/server/core/tests_resource_token.py +411 -0
  40. karrio/server/core/urls.py +12 -0
  41. karrio/server/core/utils.py +1025 -0
  42. karrio/server/core/validators.py +264 -0
  43. karrio/server/core/views/__init__.py +2 -0
  44. karrio/server/core/views/api.py +133 -0
  45. karrio/server/core/views/metadata.py +44 -0
  46. karrio/server/core/views/oauth.py +75 -0
  47. karrio/server/core/views/references.py +82 -0
  48. karrio/server/core/views/schema.py +310 -0
  49. karrio/server/filters/__init__.py +2 -0
  50. karrio/server/filters/abstract.py +26 -0
  51. karrio/server/iam/__init__.py +0 -0
  52. karrio/server/iam/admin.py +3 -0
  53. karrio/server/iam/apps.py +21 -0
  54. karrio/server/iam/migrations/0001_initial.py +33 -0
  55. karrio/server/iam/migrations/__init__.py +0 -0
  56. karrio/server/iam/models.py +48 -0
  57. karrio/server/iam/permissions.py +155 -0
  58. karrio/server/iam/serializers.py +54 -0
  59. karrio/server/iam/signals.py +18 -0
  60. karrio/server/iam/tests.py +3 -0
  61. karrio/server/iam/views.py +3 -0
  62. karrio/server/openapi.py +75 -0
  63. karrio/server/providers/__init__.py +1 -0
  64. karrio/server/providers/admin.py +364 -0
  65. karrio/server/providers/apps.py +10 -0
  66. karrio/server/providers/management/commands/migrate_rate_sheets.py +101 -0
  67. karrio/server/providers/migrations/0001_initial.py +140 -0
  68. karrio/server/providers/migrations/0002_carrier_active.py +18 -0
  69. karrio/server/providers/migrations/0003_auto_20201230_0820.py +24 -0
  70. karrio/server/providers/migrations/0004_auto_20210212_0554.py +178 -0
  71. karrio/server/providers/migrations/0005_auto_20210212_0555.py +18 -0
  72. karrio/server/providers/migrations/0006_australiapostsettings.py +29 -0
  73. karrio/server/providers/migrations/0007_auto_20210213_0206.py +21 -0
  74. karrio/server/providers/migrations/0008_auto_20210214_0409.py +30 -0
  75. karrio/server/providers/migrations/0009_auto_20210308_0302.py +18 -0
  76. karrio/server/providers/migrations/0010_auto_20210409_0852.py +32 -0
  77. karrio/server/providers/migrations/0011_auto_20210409_0853.py +21 -0
  78. karrio/server/providers/migrations/0012_alter_carrier_options.py +17 -0
  79. karrio/server/providers/migrations/0013_tntsettings.py +30 -0
  80. karrio/server/providers/migrations/0014_auto_20210612_1608.py +46 -0
  81. karrio/server/providers/migrations/0015_auto_20210615_1601.py +28 -0
  82. karrio/server/providers/migrations/0016_alter_purolatorsettings_user_token.py +18 -0
  83. karrio/server/providers/migrations/0017_auto_20210805_0359.py +1293 -0
  84. karrio/server/providers/migrations/0018_alter_fedexsettings_user_key.py +18 -0
  85. karrio/server/providers/migrations/0019_dhlpolandsettings_servicelevel.py +65 -0
  86. karrio/server/providers/migrations/0020_genericsettings_labeltemplate.py +52 -0
  87. karrio/server/providers/migrations/0021_auto_20211231_2353.py +40 -0
  88. karrio/server/providers/migrations/0022_carrier_metadata.py +18 -0
  89. karrio/server/providers/migrations/0023_auto_20220124_1916.py +27 -0
  90. karrio/server/providers/migrations/0024_alter_genericsettings_custom_carrier_name.py +19 -0
  91. karrio/server/providers/migrations/0025_alter_servicelevel_service_code.py +19 -0
  92. karrio/server/providers/migrations/0026_auto_20220208_0132.py +59 -0
  93. karrio/server/providers/migrations/0027_auto_20220304_1340.py +29 -0
  94. karrio/server/providers/migrations/0028_auto_20220323_1500.py +33 -0
  95. karrio/server/providers/migrations/0029_easypostsettings.py +27 -0
  96. karrio/server/providers/migrations/0030_amazonmwssettings.py +29 -0
  97. karrio/server/providers/migrations/0031_delete_amazonmwssettings.py +18 -0
  98. karrio/server/providers/migrations/0032_alter_carrier_test.py +18 -0
  99. karrio/server/providers/migrations/0033_auto_20220708_1350.py +22 -0
  100. karrio/server/providers/migrations/0034_amazonmwssettings_dpdhlsettings.py +47 -0
  101. karrio/server/providers/migrations/0035_alter_carrier_capabilities.py +43 -0
  102. karrio/server/providers/migrations/0036_upsfreightsettings.py +31 -0
  103. karrio/server/providers/migrations/0037_chronopostsettings.py +29 -0
  104. karrio/server/providers/migrations/0038_alter_genericsettings_label_template.py +19 -0
  105. karrio/server/providers/migrations/0039_auto_20220906_0612.py +23 -0
  106. karrio/server/providers/migrations/0040_dpdhlsettings_services.py +18 -0
  107. karrio/server/providers/migrations/0041_auto_20221105_0705.py +38 -0
  108. karrio/server/providers/migrations/0042_auto_20221215_1642.py +23 -0
  109. karrio/server/providers/migrations/0043_alter_genericsettings_account_number_and_more.py +39 -0
  110. karrio/server/providers/migrations/0044_carrier_carrier_capabilities.py +64 -0
  111. karrio/server/providers/migrations/0045_alter_carrier_active_alter_carrier_carrier_id.py +31 -0
  112. karrio/server/providers/migrations/0046_remove_dpdhlsettings_signature_and_more.py +41 -0
  113. karrio/server/providers/migrations/0047_dpdsettings.py +286 -0
  114. karrio/server/providers/migrations/0048_servicelevel_min_weight_servicelevel_transit_days_and_more.py +64 -0
  115. karrio/server/providers/migrations/0049_boxknightsettings_geodissettings_lapostesettings_and_more.py +156 -0
  116. karrio/server/providers/migrations/0050_carrier_is_system_alter_carrier_metadata_and_more.py +106 -0
  117. karrio/server/providers/migrations/0051_rename_username_upssettings_client_id_and_more.py +31 -0
  118. karrio/server/providers/migrations/0052_alter_upssettings_account_number_and_more.py +20 -0
  119. karrio/server/providers/migrations/0053_locate2usettings.py +281 -0
  120. karrio/server/providers/migrations/0054_zoom2usettings.py +280 -0
  121. karrio/server/providers/migrations/0055_rename_amazonmwssettings_amazonshippingsettings_and_more.py +44 -0
  122. karrio/server/providers/migrations/0056_asendiaussettings_geodissettings_code_client_and_more.py +75 -0
  123. karrio/server/providers/migrations/0057_alter_servicelevel_weight_unit_belgianpostsettings.py +51 -0
  124. karrio/server/providers/migrations/0058_alliedexpresssettings.py +38 -0
  125. karrio/server/providers/migrations/0059_ratesheet.py +81 -0
  126. karrio/server/providers/migrations/0060_belgianpostsettings_rate_sheet_and_more.py +73 -0
  127. karrio/server/providers/migrations/0061_alliedexpresssettings_service_type.py +17 -0
  128. karrio/server/providers/migrations/0062_sendlesettings_account_country_code.py +257 -0
  129. karrio/server/providers/migrations/0063_servicelevel_metadata.py +25 -0
  130. karrio/server/providers/migrations/0064_alliedexpresslocalsettings.py +43 -0
  131. karrio/server/providers/migrations/0065_servicelevel_carrier_service_code_and_more.py +66 -0
  132. karrio/server/providers/migrations/0066_rename_fedexsettings_fedexwssettings_and_more.py +28 -0
  133. karrio/server/providers/migrations/0067_fedexsettings.py +283 -0
  134. karrio/server/providers/migrations/0068_fedexsettings_track_api_key_and_more.py +38 -0
  135. karrio/server/providers/migrations/0069_alter_canadapostsettings_contract_id_and_more.py +23 -0
  136. karrio/server/providers/migrations/0070_tgesettings_alter_carrier_capabilities.py +65 -0
  137. karrio/server/providers/migrations/0071_alter_tgesettings_my_toll_token.py +18 -0
  138. karrio/server/providers/migrations/0072_rename_eshippersettings_eshipperxmlsettings_and_more.py +28 -0
  139. karrio/server/providers/migrations/0073_delete_eshipperxmlsettings.py +41 -0
  140. karrio/server/providers/migrations/0074_eshippersettings.py +38 -0
  141. karrio/server/providers/migrations/0075_haypostsettings.py +40 -0
  142. karrio/server/providers/migrations/0076_rename_customer_registration_id_uspsinternationalsettings_account_number_and_more.py +125 -0
  143. karrio/server/providers/migrations/0077_uspswtinternationalsettings_uspswtsettings_and_more.py +165 -0
  144. karrio/server/providers/migrations/0078_auto_20240813_1552.py +120 -0
  145. karrio/server/providers/migrations/0079_alter_carrier_options_alter_ratesheet_created_by.py +31 -0
  146. karrio/server/providers/migrations/0080_alter_aramexsettings_account_country_code_and_more.py +3025 -0
  147. karrio/server/providers/migrations/0081_remove_alliedexpresssettings_carrier_ptr_and_more.py +338 -0
  148. karrio/server/providers/migrations/0082_add_zone_identifiers.py +50 -0
  149. karrio/server/providers/migrations/0083_add_optimized_rate_sheet_structure.py +33 -0
  150. karrio/server/providers/migrations/0084_alter_servicelevel_currency.py +168 -0
  151. karrio/server/providers/migrations/0085_populate_dhl_parcel_de_oauth_credentials.py +82 -0
  152. karrio/server/providers/migrations/0086_rename_dhl_parcel_de_customer_number_to_billing_number.py +71 -0
  153. karrio/server/providers/migrations/__init__.py +0 -0
  154. karrio/server/providers/models/__init__.py +16 -0
  155. karrio/server/providers/models/carrier.py +387 -0
  156. karrio/server/providers/models/config.py +30 -0
  157. karrio/server/providers/models/service.py +192 -0
  158. karrio/server/providers/models/sheet.py +287 -0
  159. karrio/server/providers/models/template.py +39 -0
  160. karrio/server/providers/models/utils.py +58 -0
  161. karrio/server/providers/router.py +3 -0
  162. karrio/server/providers/serializers/__init__.py +3 -0
  163. karrio/server/providers/serializers/base.py +538 -0
  164. karrio/server/providers/signals.py +25 -0
  165. karrio/server/providers/templates/providers/oauth_callback.html +105 -0
  166. karrio/server/providers/tests/__init__.py +5 -0
  167. karrio/server/providers/tests/test_connections.py +895 -0
  168. karrio/server/providers/urls.py +11 -0
  169. karrio/server/providers/views/__init__.py +0 -0
  170. karrio/server/providers/views/carriers.py +267 -0
  171. karrio/server/providers/views/connections.py +496 -0
  172. karrio/server/samples.py +352 -0
  173. karrio/server/serializers/__init__.py +2 -0
  174. karrio/server/serializers/abstract.py +602 -0
  175. karrio/server/tracing/__init__.py +0 -0
  176. karrio/server/tracing/admin.py +63 -0
  177. karrio/server/tracing/apps.py +8 -0
  178. karrio/server/tracing/migrations/0001_initial.py +41 -0
  179. karrio/server/tracing/migrations/0002_auto_20220710_1307.py +22 -0
  180. karrio/server/tracing/migrations/0003_auto_20221105_0317.py +43 -0
  181. karrio/server/tracing/migrations/0004_tracingrecord_carrier_account_idx.py +24 -0
  182. karrio/server/tracing/migrations/0005_optimise_tracingrecord_request_log_idx.py +25 -0
  183. karrio/server/tracing/migrations/0006_alter_tracingrecord_options_and_more.py +49 -0
  184. karrio/server/tracing/migrations/0007_tracingrecord_tracing_created_at_idx.py +19 -0
  185. karrio/server/tracing/migrations/__init__.py +0 -0
  186. karrio/server/tracing/models.py +82 -0
  187. karrio/server/tracing/tests.py +3 -0
  188. karrio/server/tracing/utils.py +109 -0
  189. karrio/server/user/__init__.py +0 -0
  190. karrio/server/user/admin.py +96 -0
  191. karrio/server/user/apps.py +7 -0
  192. karrio/server/user/forms.py +35 -0
  193. karrio/server/user/migrations/0001_initial.py +41 -0
  194. karrio/server/user/migrations/0002_token.py +29 -0
  195. karrio/server/user/migrations/0003_token_test_mode.py +20 -0
  196. karrio/server/user/migrations/0004_group.py +26 -0
  197. karrio/server/user/migrations/0005_token_label.py +21 -0
  198. karrio/server/user/migrations/0006_workspaceconfig.py +63 -0
  199. karrio/server/user/migrations/0007_user_metadata.py +25 -0
  200. karrio/server/user/migrations/__init__.py +0 -0
  201. karrio/server/user/models.py +218 -0
  202. karrio/server/user/serializers.py +47 -0
  203. karrio/server/user/templates/registration/login.html +108 -0
  204. karrio/server/user/templates/registration/registration_confirm_email.html +10 -0
  205. karrio/server/user/templates/registration/registration_confirm_email.txt +3 -0
  206. karrio/server/user/tests.py +3 -0
  207. karrio/server/user/urls.py +10 -0
  208. karrio/server/user/utils.py +60 -0
  209. karrio/server/user/views.py +9 -0
  210. karrio_server_core-2025.5.dist-info/METADATA +32 -0
  211. karrio_server_core-2025.5.dist-info/RECORD +213 -0
  212. karrio_server_core-2025.5.dist-info/WHEEL +5 -0
  213. karrio_server_core-2025.5.dist-info/top_level.txt +2 -0
@@ -0,0 +1,837 @@
1
+ import typing
2
+ import django.conf as conf
3
+ import django.db.models as models
4
+ import django.contrib.auth as auth
5
+
6
+ import karrio.server.core.serializers as serializers
7
+ import karrio.server.core.dataunits as dataunits
8
+ import karrio.server.tracing.models as tracing
9
+ import karrio.server.core.models as core
10
+ import karrio.server.filters as filters
11
+ import karrio.server.openapi as openapi
12
+
13
+ User = auth.get_user_model()
14
+
15
+
16
+ class UserFilter(filters.FilterSet):
17
+ id = filters.CharFilter(field_name="id", help_text="user id")
18
+ email = filters.CharFilter(field_name="email", help_text="user email")
19
+ is_active = filters.BooleanFilter(
20
+ help_text="This flag indicates whether to return active carriers only",
21
+ )
22
+ is_staff = filters.BooleanFilter(
23
+ help_text="This flag indicates whether to return active carriers only",
24
+ )
25
+ is_superuser = filters.BooleanFilter(
26
+ help_text="This flag indicates whether to return active carriers only",
27
+ )
28
+ order_by = filters.OrderingFilter(
29
+ fields=(
30
+ ("is_active", "is_active"),
31
+ ("is_staff", "is_staff"),
32
+ ("is_superuser", "is_superuser"),
33
+ ("date_joined", "date_joined"),
34
+ ("last_login", "last_login"),
35
+ ),
36
+ )
37
+
38
+ class Meta:
39
+ model = User
40
+ fields: list = []
41
+
42
+
43
+ class CarrierFilters(filters.FilterSet):
44
+ carrier_name = filters.CharFilter(
45
+ help_text=f"""
46
+ carrier_name used to fulfill the shipment
47
+ Values: {', '.join([f"`{c}`" for c in dataunits.CARRIER_NAMES])}
48
+ """,
49
+ )
50
+ active = filters.BooleanFilter(
51
+ help_text="This flag indicates whether to return active carriers only",
52
+ )
53
+ system_only = filters.BooleanFilter(
54
+ help_text="This flag indicates that only system carriers should be returned",
55
+ )
56
+ metadata_key = filters.CharFilter(
57
+ field_name="metadata",
58
+ method="metadata_key_filter",
59
+ help_text="connection metadata keys.",
60
+ )
61
+ metadata_value = filters.CharFilter(
62
+ field_name="metadata",
63
+ method="metadata_value_filter",
64
+ help_text="connection metadata value.",
65
+ )
66
+
67
+ parameters = [
68
+ openapi.OpenApiParameter(
69
+ "carrier_name",
70
+ type=openapi.OpenApiTypes.STR,
71
+ location=openapi.OpenApiParameter.QUERY,
72
+ description=(
73
+ "The unique carrier slug. <br/>"
74
+ f"Values: {', '.join([f'`{c}`' for c in dataunits.CARRIER_NAMES])}"
75
+ ),
76
+ ),
77
+ openapi.OpenApiParameter(
78
+ "active",
79
+ type=openapi.OpenApiTypes.BOOL,
80
+ location=openapi.OpenApiParameter.QUERY,
81
+ ),
82
+ openapi.OpenApiParameter(
83
+ "system_only",
84
+ type=openapi.OpenApiTypes.BOOL,
85
+ location=openapi.OpenApiParameter.QUERY,
86
+ ),
87
+ openapi.OpenApiParameter(
88
+ "metadata_key",
89
+ type=openapi.OpenApiTypes.STR,
90
+ location=openapi.OpenApiParameter.QUERY,
91
+ ),
92
+ openapi.OpenApiParameter(
93
+ "metadata_value",
94
+ type=openapi.OpenApiTypes.STR,
95
+ location=openapi.OpenApiParameter.QUERY,
96
+ ),
97
+ ]
98
+
99
+ class Meta:
100
+ import karrio.server.providers.models as providers
101
+
102
+ model = providers.Carrier
103
+ fields: typing.List[str] = []
104
+
105
+ def metadata_key_filter(self, queryset, name, value):
106
+ return queryset.filter(metadata__has_key=value)
107
+
108
+ def metadata_value_filter(self, queryset, name, value):
109
+ return queryset.filter(
110
+ id__in=[
111
+ o["id"]
112
+ for o in queryset.values("id", "metadata")
113
+ if value in (o.get("metadata") or {}).values()
114
+ ]
115
+ )
116
+
117
+
118
+ class CarrierConnectionFilter(filters.FilterSet):
119
+ carrier_name = filters.CharFilter(
120
+ help_text=f"""
121
+ carrier_name used to fulfill the shipment
122
+ Values: {', '.join([f"`{c}`" for c in dataunits.CARRIER_NAMES])}
123
+ """,
124
+ )
125
+ active = filters.BooleanFilter(
126
+ help_text="This flag indicates whether to return active carriers only",
127
+ )
128
+ system_only = filters.BooleanFilter(
129
+ help_text="This flag indicates that only system carriers should be returned",
130
+ )
131
+ metadata_key = filters.CharFilter(
132
+ field_name="metadata",
133
+ method="metadata_key_filter",
134
+ help_text="connection metadata keys.",
135
+ )
136
+ metadata_value = filters.CharFilter(
137
+ field_name="metadata",
138
+ method="metadata_value_filter",
139
+ help_text="connection metadata value.",
140
+ )
141
+
142
+ parameters = [
143
+ openapi.OpenApiParameter(
144
+ "carrier_name",
145
+ type=openapi.OpenApiTypes.STR,
146
+ location=openapi.OpenApiParameter.QUERY,
147
+ description=(
148
+ "The unique carrier slug. <br/>"
149
+ f"Values: {', '.join([f'`{c}`' for c in dataunits.CARRIER_NAMES])}"
150
+ ),
151
+ ),
152
+ openapi.OpenApiParameter(
153
+ "active",
154
+ type=openapi.OpenApiTypes.BOOL,
155
+ location=openapi.OpenApiParameter.QUERY,
156
+ ),
157
+ openapi.OpenApiParameter(
158
+ "system_only",
159
+ type=openapi.OpenApiTypes.BOOL,
160
+ location=openapi.OpenApiParameter.QUERY,
161
+ ),
162
+ openapi.OpenApiParameter(
163
+ "metadata_key",
164
+ type=openapi.OpenApiTypes.STR,
165
+ location=openapi.OpenApiParameter.QUERY,
166
+ ),
167
+ openapi.OpenApiParameter(
168
+ "metadata_value",
169
+ type=openapi.OpenApiTypes.STR,
170
+ location=openapi.OpenApiParameter.QUERY,
171
+ ),
172
+ ]
173
+
174
+ class Meta:
175
+ import karrio.server.providers.models as providers
176
+
177
+ model = providers.Carrier
178
+ fields: typing.List[str] = []
179
+
180
+ def metadata_key_filter(self, queryset, name, value):
181
+ return queryset.filter(metadata__has_key=value)
182
+
183
+ def metadata_value_filter(self, queryset, name, value):
184
+ return queryset.filter(
185
+ id__in=[
186
+ o["id"]
187
+ for o in queryset.values("id", "metadata")
188
+ if value in (o.get("metadata") or {}).values()
189
+ ]
190
+ )
191
+
192
+
193
+ class ShipmentFilters(filters.FilterSet):
194
+ keyword = filters.CharFilter(
195
+ method="keyword_filter",
196
+ help_text="shipment' keyword and indexes search",
197
+ )
198
+ tracking_number = filters.CharFilter(
199
+ field_name="tracking_number", lookup_expr="icontains"
200
+ )
201
+ id = filters.CharInFilter(
202
+ field_name="id",
203
+ lookup_expr="in",
204
+ help_text="id(s).",
205
+ )
206
+ address = filters.CharFilter(
207
+ method="address_filter",
208
+ help_text="shipment recipient address line",
209
+ )
210
+ created_after = filters.DateTimeFilter(
211
+ field_name="created_at",
212
+ lookup_expr="gte",
213
+ help_text="DateTime in format `YYYY-MM-DD H:M:S.fz`",
214
+ )
215
+ created_before = filters.DateTimeFilter(
216
+ field_name="created_at",
217
+ lookup_expr="lte",
218
+ help_text="DateTime in format `YYYY-MM-DD H:M:S.fz`",
219
+ )
220
+ carrier_name = filters.MultipleChoiceFilter(
221
+ method="carrier_filter",
222
+ choices=[(c, c) for c in dataunits.CARRIER_NAMES],
223
+ help_text=f"""
224
+ carrier_name used to fulfill the shipment
225
+ Values: {', '.join([f"`{c}`" for c in dataunits.CARRIER_NAMES])}
226
+ """,
227
+ )
228
+ reference = filters.CharFilter(
229
+ field_name="reference",
230
+ lookup_expr="icontains",
231
+ help_text="a shipment reference",
232
+ )
233
+ service = filters.CharInFilter(
234
+ method="service_filter",
235
+ field_name="selected_rate__service",
236
+ help_text="preferred carrier services.",
237
+ )
238
+ status = filters.MultipleChoiceFilter(
239
+ field_name="status",
240
+ choices=[(c.value, c.value) for c in list(serializers.ShipmentStatus)],
241
+ help_text=f"""
242
+ shipment status
243
+ Values: {', '.join([f"`{s.name}`" for s in list(serializers.ShipmentStatus)])}
244
+ """,
245
+ )
246
+ option_key = filters.CharFilter(
247
+ field_name="options",
248
+ method="option_key_filter",
249
+ help_text="shipment option keys.",
250
+ )
251
+ option_value = filters.CharFilter(
252
+ field_name="options",
253
+ method="option_value_filter",
254
+ help_text="shipment option value",
255
+ )
256
+ metadata_key = filters.CharFilter(
257
+ field_name="metadata",
258
+ method="metadata_key_filter",
259
+ help_text="shipment metadata keys.",
260
+ )
261
+ metadata_value = filters.CharFilter(
262
+ field_name="metadata",
263
+ method="metadata_value_filter",
264
+ help_text="shipment metadata value",
265
+ )
266
+ meta_key = filters.CharFilter(
267
+ field_name="meta",
268
+ method="meta_key_filter",
269
+ help_text="shipment meta keys.",
270
+ )
271
+ meta_value = filters.CharFilter(
272
+ field_name="meta",
273
+ method="meta_value_filter",
274
+ help_text="shipment meta value",
275
+ )
276
+ has_tracker = filters.BooleanFilter(
277
+ field_name="shipment_tracker",
278
+ help_text="shipment has tracker",
279
+ method="has_tracker_filter",
280
+ )
281
+ has_manifest = filters.BooleanFilter(
282
+ field_name="manifest",
283
+ help_text="shipment has manifest",
284
+ method="has_manifest_filter",
285
+ )
286
+
287
+ parameters = [
288
+ openapi.OpenApiParameter(
289
+ "tracking_number",
290
+ type=openapi.OpenApiTypes.STR,
291
+ location=openapi.OpenApiParameter.QUERY,
292
+ ),
293
+ openapi.OpenApiParameter(
294
+ "keyword",
295
+ type=openapi.OpenApiTypes.STR,
296
+ location=openapi.OpenApiParameter.QUERY,
297
+ ),
298
+ openapi.OpenApiParameter(
299
+ "id",
300
+ type=openapi.OpenApiTypes.STR,
301
+ location=openapi.OpenApiParameter.QUERY,
302
+ ),
303
+ openapi.OpenApiParameter(
304
+ "address",
305
+ type=openapi.OpenApiTypes.STR,
306
+ location=openapi.OpenApiParameter.QUERY,
307
+ ),
308
+ openapi.OpenApiParameter(
309
+ "created_after",
310
+ type=openapi.OpenApiTypes.DATETIME,
311
+ location=openapi.OpenApiParameter.QUERY,
312
+ ),
313
+ openapi.OpenApiParameter(
314
+ "created_before",
315
+ type=openapi.OpenApiTypes.DATETIME,
316
+ location=openapi.OpenApiParameter.QUERY,
317
+ ),
318
+ openapi.OpenApiParameter(
319
+ "carrier_name",
320
+ type=openapi.OpenApiTypes.STR,
321
+ location=openapi.OpenApiParameter.QUERY,
322
+ description=(
323
+ "The unique carrier slug. <br/>"
324
+ f"Values: {', '.join([f'`{c}`' for c in dataunits.CARRIER_NAMES])}"
325
+ ),
326
+ ),
327
+ openapi.OpenApiParameter(
328
+ "reference",
329
+ type=openapi.OpenApiTypes.STR,
330
+ location=openapi.OpenApiParameter.QUERY,
331
+ ),
332
+ openapi.OpenApiParameter(
333
+ "service",
334
+ type=openapi.OpenApiTypes.STR,
335
+ location=openapi.OpenApiParameter.QUERY,
336
+ ),
337
+ openapi.OpenApiParameter(
338
+ "status",
339
+ type=openapi.OpenApiTypes.STR,
340
+ location=openapi.OpenApiParameter.QUERY,
341
+ description=(
342
+ "Valid shipment status. <br/>"
343
+ f"Values: {', '.join([f'`{c.value}`' for c in list(serializers.ShipmentStatus)])}"
344
+ ),
345
+ ),
346
+ openapi.OpenApiParameter(
347
+ "option_key",
348
+ type=openapi.OpenApiTypes.STR,
349
+ location=openapi.OpenApiParameter.QUERY,
350
+ ),
351
+ openapi.OpenApiParameter(
352
+ "option_value",
353
+ type=openapi.OpenApiTypes.STR,
354
+ location=openapi.OpenApiParameter.QUERY,
355
+ ),
356
+ openapi.OpenApiParameter(
357
+ "metadata_key",
358
+ type=openapi.OpenApiTypes.STR,
359
+ location=openapi.OpenApiParameter.QUERY,
360
+ ),
361
+ openapi.OpenApiParameter(
362
+ "metadata_value",
363
+ type=openapi.OpenApiTypes.STR,
364
+ location=openapi.OpenApiParameter.QUERY,
365
+ ),
366
+ openapi.OpenApiParameter(
367
+ "meta_key",
368
+ type=openapi.OpenApiTypes.STR,
369
+ location=openapi.OpenApiParameter.QUERY,
370
+ ),
371
+ openapi.OpenApiParameter(
372
+ "meta_value",
373
+ type=openapi.OpenApiTypes.STR,
374
+ location=openapi.OpenApiParameter.QUERY,
375
+ ),
376
+ openapi.OpenApiParameter(
377
+ "has_tracker",
378
+ type=openapi.OpenApiTypes.BOOL,
379
+ location=openapi.OpenApiParameter.QUERY,
380
+ ),
381
+ openapi.OpenApiParameter(
382
+ "has_manifest",
383
+ type=openapi.OpenApiTypes.BOOL,
384
+ location=openapi.OpenApiParameter.QUERY,
385
+ ),
386
+ ]
387
+
388
+ class Meta:
389
+ import karrio.server.manager.models as manager
390
+
391
+ model = manager.Shipment
392
+ fields: typing.List[str] = []
393
+
394
+ def address_filter(self, queryset, name, value):
395
+ if "postgres" in conf.settings.DB_ENGINE:
396
+ from django.contrib.postgres.search import SearchVector
397
+
398
+ return queryset.annotate(
399
+ search=SearchVector(
400
+ "recipient__address_line1",
401
+ "recipient__address_line2",
402
+ "recipient__postal_code",
403
+ "recipient__person_name",
404
+ "recipient__company_name",
405
+ "recipient__country_code",
406
+ "recipient__city",
407
+ "recipient__email",
408
+ "recipient__phone_number",
409
+ )
410
+ ).filter(search=value)
411
+
412
+ return queryset.filter(
413
+ models.Q(id__icontains=value)
414
+ | models.Q(recipient__address_line1__icontains=value)
415
+ | models.Q(recipient__address_line2__icontains=value)
416
+ | models.Q(recipient__postal_code__icontains=value)
417
+ | models.Q(recipient__person_name__icontains=value)
418
+ | models.Q(recipient__company_name__icontains=value)
419
+ | models.Q(recipient__country_code__icontains=value)
420
+ | models.Q(recipient__city__icontains=value)
421
+ | models.Q(recipient__email__icontains=value)
422
+ | models.Q(recipient__phone_number__icontains=value)
423
+ )
424
+
425
+ def keyword_filter(self, queryset, name, value):
426
+ if "postgres" in conf.settings.DB_ENGINE:
427
+ from django.contrib.postgres.search import SearchVector
428
+
429
+ return queryset.annotate(
430
+ search=SearchVector(
431
+ "id",
432
+ "reference",
433
+ "tracking_number",
434
+ "recipient__address_line1",
435
+ "recipient__address_line2",
436
+ "recipient__postal_code",
437
+ "recipient__person_name",
438
+ "recipient__company_name",
439
+ "recipient__country_code",
440
+ "recipient__city",
441
+ "recipient__email",
442
+ "recipient__phone_number",
443
+ )
444
+ ).filter(search=value)
445
+
446
+ return queryset.filter(
447
+ models.Q(id__icontains=value)
448
+ | models.Q(recipient__address_line1__icontains=value)
449
+ | models.Q(recipient__address_line2__icontains=value)
450
+ | models.Q(recipient__postal_code__icontains=value)
451
+ | models.Q(recipient__person_name__icontains=value)
452
+ | models.Q(recipient__company_name__icontains=value)
453
+ | models.Q(recipient__country_code__icontains=value)
454
+ | models.Q(recipient__city__icontains=value)
455
+ | models.Q(recipient__email__icontains=value)
456
+ | models.Q(recipient__phone_number__icontains=value)
457
+ | models.Q(tracking_number__icontains=value)
458
+ | models.Q(reference__icontains=value)
459
+ )
460
+
461
+ def carrier_filter(self, queryset, name, values):
462
+ _filters = [
463
+ models.Q(selected_rate_carrier__carrier_code=value) for value in values
464
+ ]
465
+ query = models.Q(meta__rate_provider__in=values)
466
+
467
+ for item in _filters:
468
+ query |= item
469
+
470
+ return queryset.filter(query)
471
+
472
+ def service_filter(self, queryset, name, values):
473
+ return queryset.filter(models.Q(selected_rate__service__in=values))
474
+
475
+ def option_key_filter(self, queryset, name, value):
476
+ return queryset.filter(models.Q(options__has_key=value))
477
+
478
+ def option_value_filter(self, queryset, name, value):
479
+ return queryset.filter(
480
+ id__in=[
481
+ o["id"]
482
+ for o in queryset.values("id", "options")
483
+ if value in (o.get("options") or {}).values()
484
+ ]
485
+ )
486
+
487
+ def metadata_key_filter(self, queryset, name, value):
488
+ return queryset.filter(metadata__has_key=value)
489
+
490
+ def metadata_value_filter(self, queryset, name, value):
491
+ return queryset.filter(
492
+ id__in=[
493
+ o["id"]
494
+ for o in queryset.values("id", "metadata")
495
+ if value in (o.get("metadata") or {}).values()
496
+ ]
497
+ )
498
+
499
+ def meta_key_filter(self, queryset, name, value):
500
+ return queryset.filter(meta__has_key=value)
501
+
502
+ def meta_value_filter(self, queryset, name, value):
503
+ return queryset.filter(
504
+ id__in=[
505
+ o["id"]
506
+ for o in queryset.values("id", "meta")
507
+ if value in map(str, (o.get("meta") or {}).values())
508
+ ]
509
+ )
510
+
511
+ def has_tracker_filter(self, queryset, name, value):
512
+ return queryset.filter(shipment_tracker__isnull=not value)
513
+
514
+ def has_manifest_filter(self, queryset, name, value):
515
+ return queryset.filter(manifest__isnull=not value)
516
+
517
+
518
+ class TrackerFilters(filters.FilterSet):
519
+ tracking_number = filters.CharFilter(
520
+ field_name="tracking_number",
521
+ lookup_expr="icontains",
522
+ help_text="a tracking number",
523
+ )
524
+ created_after = filters.DateTimeFilter(
525
+ field_name="created_at",
526
+ lookup_expr="gte",
527
+ help_text="DateTime in format `YYYY-MM-DD H:M:S.fz`",
528
+ )
529
+ created_before = filters.DateTimeFilter(
530
+ field_name="created_at",
531
+ lookup_expr="lte",
532
+ help_text="DateTime in format `YYYY-MM-DD H:M:S.fz`",
533
+ )
534
+ carrier_name = filters.MultipleChoiceFilter(
535
+ method="carrier_filter",
536
+ choices=[(c, c) for c in dataunits.CARRIER_NAMES],
537
+ help_text=f"""
538
+ carrier_name used to fulfill the shipment
539
+ Values: {', '.join([f"`{c}`" for c in dataunits.CARRIER_NAMES])}
540
+ """,
541
+ )
542
+ status = filters.MultipleChoiceFilter(
543
+ field_name="status",
544
+ choices=[(c.value, c.value) for c in list(serializers.TrackerStatus)],
545
+ help_text=f"""
546
+ tracker status
547
+ Values: {', '.join([f"`{s.name}`" for s in list(serializers.TrackerStatus)])}
548
+ """,
549
+ )
550
+
551
+ parameters = [
552
+ openapi.OpenApiParameter(
553
+ "tracking_number",
554
+ type=openapi.OpenApiTypes.STR,
555
+ location=openapi.OpenApiParameter.QUERY,
556
+ ),
557
+ openapi.OpenApiParameter(
558
+ "created_after",
559
+ type=openapi.OpenApiTypes.DATETIME,
560
+ location=openapi.OpenApiParameter.QUERY,
561
+ ),
562
+ openapi.OpenApiParameter(
563
+ "created_before",
564
+ type=openapi.OpenApiTypes.DATETIME,
565
+ location=openapi.OpenApiParameter.QUERY,
566
+ ),
567
+ openapi.OpenApiParameter(
568
+ "carrier_name",
569
+ type=openapi.OpenApiTypes.STR,
570
+ location=openapi.OpenApiParameter.QUERY,
571
+ description=(
572
+ "The unique carrier slug. <br/>"
573
+ f"Values: {', '.join([f'`{c}`' for c in dataunits.CARRIER_NAMES])}"
574
+ ),
575
+ ),
576
+ openapi.OpenApiParameter(
577
+ "status",
578
+ type=openapi.OpenApiTypes.STR,
579
+ location=openapi.OpenApiParameter.QUERY,
580
+ description=(
581
+ "Valid tracker status. <br/>"
582
+ f"Values: {', '.join([f'`{c.value}`' for c in list(serializers.TrackerStatus)])}"
583
+ ),
584
+ ),
585
+ ]
586
+
587
+ class Meta:
588
+ import karrio.server.manager.models as manager
589
+
590
+ model = manager.Tracking
591
+ fields: typing.List[str] = []
592
+
593
+ def carrier_filter(self, queryset, name, values):
594
+ _filters = [models.Q(tracking_carrier__carrier_code=value) for value in values]
595
+ query = _filters.pop()
596
+
597
+ for item in _filters:
598
+ query |= item
599
+
600
+ return queryset.filter(query)
601
+
602
+
603
+ class LogFilter(filters.FilterSet):
604
+ query = filters.CharFilter(
605
+ method="query_filter",
606
+ help_text="search in entity_id, path, and other log fields",
607
+ )
608
+ api_endpoint = filters.CharFilter(field_name="path", lookup_expr="icontains")
609
+ remote_addr = filters.CharFilter(field_name="remote_addr", lookup_expr="exact")
610
+ date_after = filters.DateTimeFilter(field_name="requested_at", lookup_expr="gte")
611
+ date_before = filters.DateTimeFilter(field_name="requested_at", lookup_expr="lte")
612
+ entity_id = filters.CharFilter(field_name="entity_id")
613
+ method = filters.MultipleChoiceFilter(
614
+ field_name="method",
615
+ choices=[
616
+ ("GET", "GET"),
617
+ ("POST", "POST"),
618
+ ("PATCH", "PATCH"),
619
+ ("DELETE", "DELETE"),
620
+ ],
621
+ )
622
+ status = filters.ChoiceFilter(
623
+ method="status_filter",
624
+ choices=[("succeeded", "succeeded"), ("failed", "failed")],
625
+ )
626
+ status_code = filters.TypedMultipleChoiceFilter(
627
+ coerce=int,
628
+ field_name="status_code",
629
+ choices=[(s, s) for s in serializers.HTTP_STATUS],
630
+ )
631
+ keyword = filters.CharFilter(
632
+ method="keyword_filter",
633
+ help_text="search in entity_id and data",
634
+ )
635
+
636
+ class Meta:
637
+ model = core.APILogIndex
638
+ fields: typing.List[str] = []
639
+
640
+ def status_filter(self, queryset, name, value):
641
+ if value == "succeeded":
642
+ return queryset.filter(status_code__range=[200, 399])
643
+ elif value == "failed":
644
+ return queryset.filter(status_code__range=[400, 599])
645
+
646
+ return queryset
647
+
648
+ def query_filter(self, queryset, name, value):
649
+ return queryset.filter(
650
+ models.Q(entity_id__icontains=value) |
651
+ models.Q(data__icontains=value) |
652
+ models.Q(path__icontains=value) |
653
+ models.Q(remote_addr__icontains=value) |
654
+ models.Q(host__icontains=value) |
655
+ models.Q(method__icontains=value)
656
+ )
657
+
658
+ def keyword_filter(self, queryset, name, value):
659
+ return queryset.filter(
660
+ models.Q(entity_id__icontains=value) |
661
+ models.Q(data__icontains=value) |
662
+ models.Q(path__icontains=value) |
663
+ models.Q(remote_addr__icontains=value) |
664
+ models.Q(host__icontains=value) |
665
+ models.Q(method__icontains=value)
666
+ )
667
+
668
+ class TracingRecordFilter(filters.FilterSet):
669
+ key = filters.CharFilter(
670
+ field_name="key",
671
+ help_text="the tacing log key.",
672
+ )
673
+ request_log_id = filters.NumberFilter(
674
+ method="request_log_id_filter",
675
+ field_name="meta__request_log_id",
676
+ lookup_expr="icontains",
677
+ help_text="related request API log.",
678
+ )
679
+ date_after = filters.DateTimeFilter(field_name="requested_at", lookup_expr="gte")
680
+ date_before = filters.DateTimeFilter(field_name="requested_at", lookup_expr="lte")
681
+ keyword = filters.CharFilter(
682
+ method="keyword_filter",
683
+ help_text="search in key and meta",
684
+ )
685
+
686
+ class Meta:
687
+ model = tracing.TracingRecord
688
+ fields: list = []
689
+
690
+ def request_log_id_filter(self, queryset, name, value):
691
+ return queryset.filter(meta__request_log_id=value)
692
+
693
+ def keyword_filter(self, queryset, name, value):
694
+ return queryset.filter(
695
+ models.Q(key__icontains=value) |
696
+ models.Q(meta__icontains=value)
697
+ )
698
+
699
+
700
+ class UploadRecordFilter(filters.FilterSet):
701
+ shipment_id = filters.CharFilter(
702
+ field_name="shipment__id", help_text="related shipment id"
703
+ )
704
+ created_after = filters.DateTimeFilter(field_name="requested_at", lookup_expr="gte")
705
+ created_before = filters.DateTimeFilter(
706
+ field_name="requested_at", lookup_expr="lte"
707
+ )
708
+
709
+ parameters = [
710
+ openapi.OpenApiParameter(
711
+ "shipment_id",
712
+ type=openapi.OpenApiTypes.STR,
713
+ location=openapi.OpenApiParameter.QUERY,
714
+ ),
715
+ openapi.OpenApiParameter(
716
+ "created_after",
717
+ type=openapi.OpenApiTypes.DATETIME,
718
+ location=openapi.OpenApiParameter.QUERY,
719
+ ),
720
+ openapi.OpenApiParameter(
721
+ "created_before",
722
+ type=openapi.OpenApiTypes.DATETIME,
723
+ location=openapi.OpenApiParameter.QUERY,
724
+ ),
725
+ ]
726
+
727
+ class Meta:
728
+ import karrio.server.manager.models as manager
729
+
730
+ model = manager.DocumentUploadRecord
731
+ fields: list = []
732
+
733
+
734
+ class PickupFilters(filters.FilterSet):
735
+ parameters: list = []
736
+
737
+ class Meta:
738
+ import karrio.server.manager.models as manager
739
+
740
+ model = manager.Pickup
741
+ fields: list = []
742
+
743
+
744
+ class RateSheetFilter(filters.FilterSet):
745
+ keyword = filters.CharFilter(
746
+ method="keyword_filter",
747
+ help_text="rate sheet keyword and indexes search",
748
+ )
749
+
750
+ class Meta:
751
+ import karrio.server.providers.models as providers
752
+
753
+ model = providers.RateSheet
754
+ fields: typing.List[str] = []
755
+
756
+ def keyword_filter(self, queryset, name, value):
757
+ if "postgres" in conf.settings.DB_ENGINE:
758
+ from django.contrib.postgres.search import SearchVector
759
+
760
+ return queryset.annotate(
761
+ search=SearchVector(
762
+ "id",
763
+ "name",
764
+ "slug",
765
+ "carrier_name",
766
+ )
767
+ ).filter(search=value)
768
+
769
+ return queryset.filter(
770
+ models.Q(id__icontains=value)
771
+ | models.Q(name__icontains=value)
772
+ | models.Q(slug__icontains=value)
773
+ | models.Q(carrier_name__icontains=value)
774
+ )
775
+
776
+
777
+ class ManifestFilters(filters.FilterSet):
778
+ id = filters.CharInFilter(
779
+ field_name="id",
780
+ lookup_expr="in",
781
+ help_text="id(s).",
782
+ )
783
+ carrier_name = filters.MultipleChoiceFilter(
784
+ method="carrier_filter",
785
+ choices=[(c, c) for c in dataunits.CARRIER_NAMES],
786
+ help_text=f"""
787
+ carrier_name used to fulfill the shipment
788
+ Values: {', '.join([f"`{c}`" for c in dataunits.CARRIER_NAMES])}
789
+ """,
790
+ )
791
+ created_after = filters.DateTimeFilter(
792
+ field_name="created_at",
793
+ lookup_expr="gte",
794
+ help_text="DateTime in format `YYYY-MM-DD H:M:S.fz`",
795
+ )
796
+ created_before = filters.DateTimeFilter(
797
+ field_name="created_at",
798
+ lookup_expr="lte",
799
+ help_text="DateTime in format `YYYY-MM-DD H:M:S.fz`",
800
+ )
801
+
802
+ parameters = [
803
+ openapi.OpenApiParameter(
804
+ "carrier_name",
805
+ type=openapi.OpenApiTypes.STR,
806
+ location=openapi.OpenApiParameter.QUERY,
807
+ description=(
808
+ "The unique carrier slug. <br/>"
809
+ f"Values: {', '.join([f'`{c}`' for c in dataunits.CARRIER_NAMES])}"
810
+ ),
811
+ ),
812
+ openapi.OpenApiParameter(
813
+ "created_after",
814
+ type=openapi.OpenApiTypes.DATETIME,
815
+ location=openapi.OpenApiParameter.QUERY,
816
+ ),
817
+ openapi.OpenApiParameter(
818
+ "created_before",
819
+ type=openapi.OpenApiTypes.DATETIME,
820
+ location=openapi.OpenApiParameter.QUERY,
821
+ ),
822
+ ]
823
+
824
+ class Meta:
825
+ import karrio.server.manager.models as manager
826
+
827
+ model = manager.Manifest
828
+ fields: typing.List[str] = []
829
+
830
+ def carrier_filter(self, queryset, name, values):
831
+ _filters = [models.Q(manifest_carrier__carrier_code=value) for value in values]
832
+ query = _filters.pop()
833
+
834
+ for item in _filters:
835
+ query |= item
836
+
837
+ return queryset.filter(query)