karrio-server-core 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.

Potentially problematic release.


This version of karrio-server-core might be problematic. Click here for more details.

Files changed (241) 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 +313 -0
  6. karrio/server/core/context_processors.py +12 -0
  7. karrio/server/core/datatypes.py +369 -0
  8. karrio/server/core/dataunits.py +156 -0
  9. karrio/server/core/exceptions.py +200 -0
  10. karrio/server/core/fields.py +12 -0
  11. karrio/server/core/filters.py +823 -0
  12. karrio/server/core/gateway.py +720 -0
  13. karrio/server/core/management/commands/cli.py +19 -0
  14. karrio/server/core/management/commands/create_oauth_client.py +41 -0
  15. karrio/server/core/middleware.py +95 -0
  16. karrio/server/core/migrations/0001_initial.py +28 -0
  17. karrio/server/core/migrations/0002_apilogindex.py +69 -0
  18. karrio/server/core/migrations/0003_apilogindex_test_mode.py +62 -0
  19. karrio/server/core/migrations/0004_metafield.py +74 -0
  20. karrio/server/core/migrations/0005_alter_metafield_type_alter_metafield_value.py +23 -0
  21. karrio/server/core/migrations/__init__.py +0 -0
  22. karrio/server/core/models/__init__.py +48 -0
  23. karrio/server/core/models/base.py +70 -0
  24. karrio/server/core/models/entity.py +22 -0
  25. karrio/server/core/models/metafield.py +144 -0
  26. karrio/server/core/models/third_party.py +21 -0
  27. karrio/server/core/oauth_validators.py +171 -0
  28. karrio/server/core/permissions.py +37 -0
  29. karrio/server/core/renderers.py +11 -0
  30. karrio/server/core/router.py +3 -0
  31. karrio/server/core/serializers.py +1898 -0
  32. karrio/server/core/signals.py +57 -0
  33. karrio/server/core/tests.py +98 -0
  34. karrio/server/core/urls.py +12 -0
  35. karrio/server/core/utils.py +479 -0
  36. karrio/server/core/validators.py +416 -0
  37. karrio/server/core/views/__init__.py +2 -0
  38. karrio/server/core/views/api.py +133 -0
  39. karrio/server/core/views/metadata.py +44 -0
  40. karrio/server/core/views/oauth.py +74 -0
  41. karrio/server/core/views/references.py +82 -0
  42. karrio/server/core/views/schema.py +310 -0
  43. karrio/server/filters/__init__.py +2 -0
  44. karrio/server/filters/abstract.py +26 -0
  45. karrio/server/iam/__init__.py +0 -0
  46. karrio/server/iam/admin.py +3 -0
  47. karrio/server/iam/apps.py +21 -0
  48. karrio/server/iam/migrations/0001_initial.py +33 -0
  49. karrio/server/iam/migrations/__init__.py +0 -0
  50. karrio/server/iam/models.py +48 -0
  51. karrio/server/iam/permissions.py +134 -0
  52. karrio/server/iam/serializers.py +39 -0
  53. karrio/server/iam/signals.py +20 -0
  54. karrio/server/iam/tests.py +3 -0
  55. karrio/server/iam/views.py +3 -0
  56. karrio/server/openapi.py +75 -0
  57. karrio/server/providers/__init__.py +1 -0
  58. karrio/server/providers/admin.py +364 -0
  59. karrio/server/providers/apps.py +10 -0
  60. karrio/server/providers/extension/__init__.py +1 -0
  61. karrio/server/providers/extension/models/__init__.py +1 -0
  62. karrio/server/providers/extension/models/allied_express.py +22 -0
  63. karrio/server/providers/extension/models/allied_express_local.py +22 -0
  64. karrio/server/providers/extension/models/amazon_shipping.py +27 -0
  65. karrio/server/providers/extension/models/aramex.py +25 -0
  66. karrio/server/providers/extension/models/asendia_us.py +21 -0
  67. karrio/server/providers/extension/models/australiapost.py +20 -0
  68. karrio/server/providers/extension/models/boxknight.py +19 -0
  69. karrio/server/providers/extension/models/bpost.py +21 -0
  70. karrio/server/providers/extension/models/canadapost.py +21 -0
  71. karrio/server/providers/extension/models/canpar.py +19 -0
  72. karrio/server/providers/extension/models/chronopost.py +22 -0
  73. karrio/server/providers/extension/models/colissimo.py +22 -0
  74. karrio/server/providers/extension/models/dhl_express.py +23 -0
  75. karrio/server/providers/extension/models/dhl_parcel_de.py +25 -0
  76. karrio/server/providers/extension/models/dhl_poland.py +22 -0
  77. karrio/server/providers/extension/models/dhl_universal.py +19 -0
  78. karrio/server/providers/extension/models/dicom.py +20 -0
  79. karrio/server/providers/extension/models/dpd.py +37 -0
  80. karrio/server/providers/extension/models/dpdhl.py +26 -0
  81. karrio/server/providers/extension/models/easypost.py +20 -0
  82. karrio/server/providers/extension/models/eshipper.py +21 -0
  83. karrio/server/providers/extension/models/fedex.py +25 -0
  84. karrio/server/providers/extension/models/fedex_ws.py +24 -0
  85. karrio/server/providers/extension/models/freightcom.py +21 -0
  86. karrio/server/providers/extension/models/generic.py +35 -0
  87. karrio/server/providers/extension/models/geodis.py +22 -0
  88. karrio/server/providers/extension/models/hay_post.py +22 -0
  89. karrio/server/providers/extension/models/laposte.py +19 -0
  90. karrio/server/providers/extension/models/locate2u.py +22 -0
  91. karrio/server/providers/extension/models/nationex.py +22 -0
  92. karrio/server/providers/extension/models/purolator.py +21 -0
  93. karrio/server/providers/extension/models/roadie.py +18 -0
  94. karrio/server/providers/extension/models/royalmail.py +19 -0
  95. karrio/server/providers/extension/models/sendle.py +22 -0
  96. karrio/server/providers/extension/models/tge.py +63 -0
  97. karrio/server/providers/extension/models/tnt.py +23 -0
  98. karrio/server/providers/extension/models/ups.py +23 -0
  99. karrio/server/providers/extension/models/usps.py +23 -0
  100. karrio/server/providers/extension/models/usps_international.py +23 -0
  101. karrio/server/providers/extension/models/usps_wt.py +24 -0
  102. karrio/server/providers/extension/models/usps_wt_international.py +24 -0
  103. karrio/server/providers/extension/models/zoom2u.py +23 -0
  104. karrio/server/providers/migrations/0001_initial.py +140 -0
  105. karrio/server/providers/migrations/0002_carrier_active.py +18 -0
  106. karrio/server/providers/migrations/0003_auto_20201230_0820.py +24 -0
  107. karrio/server/providers/migrations/0004_auto_20210212_0554.py +178 -0
  108. karrio/server/providers/migrations/0005_auto_20210212_0555.py +18 -0
  109. karrio/server/providers/migrations/0006_australiapostsettings.py +29 -0
  110. karrio/server/providers/migrations/0007_auto_20210213_0206.py +21 -0
  111. karrio/server/providers/migrations/0008_auto_20210214_0409.py +30 -0
  112. karrio/server/providers/migrations/0009_auto_20210308_0302.py +18 -0
  113. karrio/server/providers/migrations/0010_auto_20210409_0852.py +32 -0
  114. karrio/server/providers/migrations/0011_auto_20210409_0853.py +21 -0
  115. karrio/server/providers/migrations/0012_alter_carrier_options.py +17 -0
  116. karrio/server/providers/migrations/0013_tntsettings.py +30 -0
  117. karrio/server/providers/migrations/0014_auto_20210612_1608.py +46 -0
  118. karrio/server/providers/migrations/0015_auto_20210615_1601.py +28 -0
  119. karrio/server/providers/migrations/0016_alter_purolatorsettings_user_token.py +18 -0
  120. karrio/server/providers/migrations/0017_auto_20210805_0359.py +1293 -0
  121. karrio/server/providers/migrations/0018_alter_fedexsettings_user_key.py +18 -0
  122. karrio/server/providers/migrations/0019_dhlpolandsettings_servicelevel.py +65 -0
  123. karrio/server/providers/migrations/0020_genericsettings_labeltemplate.py +52 -0
  124. karrio/server/providers/migrations/0021_auto_20211231_2353.py +40 -0
  125. karrio/server/providers/migrations/0022_carrier_metadata.py +18 -0
  126. karrio/server/providers/migrations/0023_auto_20220124_1916.py +27 -0
  127. karrio/server/providers/migrations/0024_alter_genericsettings_custom_carrier_name.py +19 -0
  128. karrio/server/providers/migrations/0025_alter_servicelevel_service_code.py +19 -0
  129. karrio/server/providers/migrations/0026_auto_20220208_0132.py +59 -0
  130. karrio/server/providers/migrations/0027_auto_20220304_1340.py +29 -0
  131. karrio/server/providers/migrations/0028_auto_20220323_1500.py +33 -0
  132. karrio/server/providers/migrations/0029_easypostsettings.py +27 -0
  133. karrio/server/providers/migrations/0030_amazonmwssettings.py +29 -0
  134. karrio/server/providers/migrations/0031_delete_amazonmwssettings.py +18 -0
  135. karrio/server/providers/migrations/0032_alter_carrier_test.py +18 -0
  136. karrio/server/providers/migrations/0033_auto_20220708_1350.py +22 -0
  137. karrio/server/providers/migrations/0034_amazonmwssettings_dpdhlsettings.py +47 -0
  138. karrio/server/providers/migrations/0035_alter_carrier_capabilities.py +43 -0
  139. karrio/server/providers/migrations/0036_upsfreightsettings.py +31 -0
  140. karrio/server/providers/migrations/0037_chronopostsettings.py +29 -0
  141. karrio/server/providers/migrations/0038_alter_genericsettings_label_template.py +19 -0
  142. karrio/server/providers/migrations/0039_auto_20220906_0612.py +23 -0
  143. karrio/server/providers/migrations/0040_dpdhlsettings_services.py +18 -0
  144. karrio/server/providers/migrations/0041_auto_20221105_0705.py +38 -0
  145. karrio/server/providers/migrations/0042_auto_20221215_1642.py +23 -0
  146. karrio/server/providers/migrations/0043_alter_genericsettings_account_number_and_more.py +39 -0
  147. karrio/server/providers/migrations/0044_carrier_carrier_capabilities.py +64 -0
  148. karrio/server/providers/migrations/0045_alter_carrier_active_alter_carrier_carrier_id.py +31 -0
  149. karrio/server/providers/migrations/0046_remove_dpdhlsettings_signature_and_more.py +41 -0
  150. karrio/server/providers/migrations/0047_dpdsettings.py +286 -0
  151. karrio/server/providers/migrations/0048_servicelevel_min_weight_servicelevel_transit_days_and_more.py +64 -0
  152. karrio/server/providers/migrations/0049_boxknightsettings_geodissettings_lapostesettings_and_more.py +156 -0
  153. karrio/server/providers/migrations/0050_carrier_is_system_alter_carrier_metadata_and_more.py +106 -0
  154. karrio/server/providers/migrations/0051_rename_username_upssettings_client_id_and_more.py +31 -0
  155. karrio/server/providers/migrations/0052_alter_upssettings_account_number_and_more.py +20 -0
  156. karrio/server/providers/migrations/0053_locate2usettings.py +281 -0
  157. karrio/server/providers/migrations/0054_zoom2usettings.py +280 -0
  158. karrio/server/providers/migrations/0055_rename_amazonmwssettings_amazonshippingsettings_and_more.py +44 -0
  159. karrio/server/providers/migrations/0056_asendiaussettings_geodissettings_code_client_and_more.py +75 -0
  160. karrio/server/providers/migrations/0057_alter_servicelevel_weight_unit_belgianpostsettings.py +51 -0
  161. karrio/server/providers/migrations/0058_alliedexpresssettings.py +38 -0
  162. karrio/server/providers/migrations/0059_ratesheet.py +81 -0
  163. karrio/server/providers/migrations/0060_belgianpostsettings_rate_sheet_and_more.py +73 -0
  164. karrio/server/providers/migrations/0061_alliedexpresssettings_service_type.py +17 -0
  165. karrio/server/providers/migrations/0062_sendlesettings_account_country_code.py +257 -0
  166. karrio/server/providers/migrations/0063_servicelevel_metadata.py +25 -0
  167. karrio/server/providers/migrations/0064_alliedexpresslocalsettings.py +43 -0
  168. karrio/server/providers/migrations/0065_servicelevel_carrier_service_code_and_more.py +66 -0
  169. karrio/server/providers/migrations/0066_rename_fedexsettings_fedexwssettings_and_more.py +28 -0
  170. karrio/server/providers/migrations/0067_fedexsettings.py +283 -0
  171. karrio/server/providers/migrations/0068_fedexsettings_track_api_key_and_more.py +38 -0
  172. karrio/server/providers/migrations/0069_alter_canadapostsettings_contract_id_and_more.py +23 -0
  173. karrio/server/providers/migrations/0070_tgesettings_alter_carrier_capabilities.py +65 -0
  174. karrio/server/providers/migrations/0071_alter_tgesettings_my_toll_token.py +18 -0
  175. karrio/server/providers/migrations/0072_rename_eshippersettings_eshipperxmlsettings_and_more.py +28 -0
  176. karrio/server/providers/migrations/0073_delete_eshipperxmlsettings.py +41 -0
  177. karrio/server/providers/migrations/0074_eshippersettings.py +38 -0
  178. karrio/server/providers/migrations/0075_haypostsettings.py +40 -0
  179. karrio/server/providers/migrations/0076_rename_customer_registration_id_uspsinternationalsettings_account_number_and_more.py +125 -0
  180. karrio/server/providers/migrations/0077_uspswtinternationalsettings_uspswtsettings_and_more.py +165 -0
  181. karrio/server/providers/migrations/0078_auto_20240813_1552.py +120 -0
  182. karrio/server/providers/migrations/0079_alter_carrier_options_alter_ratesheet_created_by.py +31 -0
  183. karrio/server/providers/migrations/0080_alter_aramexsettings_account_country_code_and_more.py +3025 -0
  184. karrio/server/providers/migrations/0081_remove_alliedexpresssettings_carrier_ptr_and_more.py +338 -0
  185. karrio/server/providers/migrations/__init__.py +0 -0
  186. karrio/server/providers/models/__init__.py +17 -0
  187. karrio/server/providers/models/carrier.py +309 -0
  188. karrio/server/providers/models/config.py +30 -0
  189. karrio/server/providers/models/service.py +62 -0
  190. karrio/server/providers/models/sheet.py +60 -0
  191. karrio/server/providers/models/template.py +39 -0
  192. karrio/server/providers/models/utils.py +58 -0
  193. karrio/server/providers/router.py +3 -0
  194. karrio/server/providers/serializers/__init__.py +3 -0
  195. karrio/server/providers/serializers/base.py +277 -0
  196. karrio/server/providers/signals.py +27 -0
  197. karrio/server/providers/tests.py +3 -0
  198. karrio/server/providers/urls.py +11 -0
  199. karrio/server/providers/views/__init__.py +0 -0
  200. karrio/server/providers/views/carriers.py +269 -0
  201. karrio/server/providers/views/connections.py +176 -0
  202. karrio/server/samples.py +352 -0
  203. karrio/server/serializers/__init__.py +2 -0
  204. karrio/server/serializers/abstract.py +506 -0
  205. karrio/server/tracing/__init__.py +0 -0
  206. karrio/server/tracing/admin.py +63 -0
  207. karrio/server/tracing/apps.py +8 -0
  208. karrio/server/tracing/migrations/0001_initial.py +41 -0
  209. karrio/server/tracing/migrations/0002_auto_20220710_1307.py +22 -0
  210. karrio/server/tracing/migrations/0003_auto_20221105_0317.py +43 -0
  211. karrio/server/tracing/migrations/0004_tracingrecord_carrier_account_idx.py +24 -0
  212. karrio/server/tracing/migrations/0005_optimise_tracingrecord_request_log_idx.py +25 -0
  213. karrio/server/tracing/migrations/0006_alter_tracingrecord_options_and_more.py +49 -0
  214. karrio/server/tracing/migrations/__init__.py +0 -0
  215. karrio/server/tracing/models.py +80 -0
  216. karrio/server/tracing/tests.py +3 -0
  217. karrio/server/tracing/utils.py +112 -0
  218. karrio/server/user/__init__.py +0 -0
  219. karrio/server/user/admin.py +96 -0
  220. karrio/server/user/apps.py +7 -0
  221. karrio/server/user/forms.py +35 -0
  222. karrio/server/user/migrations/0001_initial.py +41 -0
  223. karrio/server/user/migrations/0002_token.py +29 -0
  224. karrio/server/user/migrations/0003_token_test_mode.py +20 -0
  225. karrio/server/user/migrations/0004_group.py +26 -0
  226. karrio/server/user/migrations/0005_token_label.py +21 -0
  227. karrio/server/user/migrations/0006_workspaceconfig.py +63 -0
  228. karrio/server/user/migrations/__init__.py +0 -0
  229. karrio/server/user/models.py +203 -0
  230. karrio/server/user/serializers.py +46 -0
  231. karrio/server/user/templates/registration/login.html +108 -0
  232. karrio/server/user/templates/registration/registration_confirm_email.html +10 -0
  233. karrio/server/user/templates/registration/registration_confirm_email.txt +3 -0
  234. karrio/server/user/tests.py +3 -0
  235. karrio/server/user/urls.py +10 -0
  236. karrio/server/user/utils.py +60 -0
  237. karrio/server/user/views.py +9 -0
  238. karrio_server_core-2025.5rc1.dist-info/METADATA +32 -0
  239. karrio_server_core-2025.5rc1.dist-info/RECORD +241 -0
  240. karrio_server_core-2025.5rc1.dist-info/WHEEL +5 -0
  241. karrio_server_core-2025.5rc1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,62 @@
1
+ import functools
2
+ import django.db.models as models
3
+ import django.core.validators as validators
4
+
5
+ import karrio.server.core.models as core
6
+ import karrio.server.core.datatypes as datatypes
7
+
8
+
9
+ @core.register_model
10
+ class ServiceLevel(core.OwnedEntity):
11
+ class Meta:
12
+ db_table = "service-level"
13
+ verbose_name = "Service Level"
14
+ verbose_name_plural = "Service Levels"
15
+ ordering = ["-created_at"]
16
+
17
+ id = models.CharField(
18
+ max_length=50,
19
+ primary_key=True,
20
+ default=functools.partial(core.uuid, prefix="svc_"),
21
+ editable=False,
22
+ )
23
+ service_name = models.CharField(max_length=50)
24
+ service_code = models.CharField(
25
+ max_length=50, validators=[validators.RegexValidator(r"^[a-z0-9_]+$")]
26
+ )
27
+ carrier_service_code = models.CharField(max_length=50, null=True, blank=True)
28
+ description = models.CharField(max_length=250, null=True, blank=True)
29
+ active = models.BooleanField(null=True, default=True)
30
+
31
+ currency = models.CharField(
32
+ max_length=4, choices=datatypes.CURRENCIES, null=True, blank=True
33
+ )
34
+
35
+ transit_days = models.IntegerField(blank=True, null=True)
36
+ transit_time = models.FloatField(blank=True, null=True)
37
+
38
+ max_width = models.FloatField(blank=True, null=True)
39
+ max_height = models.FloatField(blank=True, null=True)
40
+ max_length = models.FloatField(blank=True, null=True)
41
+ dimension_unit = models.CharField(
42
+ max_length=2, choices=datatypes.DIMENSION_UNITS, null=True, blank=True
43
+ )
44
+
45
+ min_weight = models.FloatField(blank=True, null=True)
46
+ max_weight = models.FloatField(blank=True, null=True)
47
+ weight_unit = models.CharField(
48
+ max_length=2, choices=datatypes.WEIGHT_UNITS, null=True, blank=True
49
+ )
50
+
51
+ domicile = models.BooleanField(null=True)
52
+ international = models.BooleanField(null=True)
53
+
54
+ zones = models.JSONField(blank=True, null=True, default=core.field_default([]))
55
+ metadata = models.JSONField(blank=True, null=True, default=core.field_default({}))
56
+
57
+ def __str__(self):
58
+ return f"{self.id} | {self.service_name}"
59
+
60
+ @property
61
+ def object_type(self):
62
+ return "service_level"
@@ -0,0 +1,60 @@
1
+ import functools
2
+ import django.db.models as models
3
+ import django.utils.translation as translation
4
+
5
+ import django.conf as conf
6
+ import karrio.server.core.models as core
7
+
8
+ _ = translation.gettext_lazy
9
+
10
+
11
+ @core.register_model
12
+ class RateSheet(core.OwnedEntity):
13
+ class Meta:
14
+ db_table = "rate-sheet"
15
+ verbose_name = "Rate Sheet"
16
+ verbose_name_plural = "Rate Sheets"
17
+ ordering = ["-created_at"]
18
+
19
+ id = models.CharField(
20
+ max_length=50,
21
+ editable=False,
22
+ primary_key=True,
23
+ default=functools.partial(core.uuid, prefix="rsht_"),
24
+ )
25
+ name = models.CharField(_("name"), max_length=50, db_index=True)
26
+ slug = models.CharField(_("slug"), max_length=50, db_index=True)
27
+ carrier_name = models.CharField(max_length=50, db_index=True)
28
+ is_system = models.BooleanField(default=False, db_index=True)
29
+ services = models.ManyToManyField(
30
+ "ServiceLevel", blank=True, related_name="service_sheet"
31
+ )
32
+ metadata = models.JSONField(
33
+ blank=True,
34
+ null=True,
35
+ default=core.field_default({}),
36
+ )
37
+
38
+ created_by = models.ForeignKey(
39
+ conf.settings.AUTH_USER_MODEL,
40
+ blank=True,
41
+ null=True,
42
+ on_delete=models.CASCADE,
43
+ editable=False,
44
+ )
45
+
46
+ def delete(self, *args, **kwargs):
47
+ self.services.all().delete()
48
+ return super().delete(*args, **kwargs)
49
+
50
+ @property
51
+ def object_type(self):
52
+ return "rate-sheet"
53
+
54
+ @property
55
+ def carriers(self):
56
+ import karrio.server.providers.models as providers
57
+
58
+ return providers.Carrier.objects.filter(
59
+ carrier_code=self.carrier_name, rate_sheet__id=self.id
60
+ )
@@ -0,0 +1,39 @@
1
+ import functools
2
+ import django.db.models as models
3
+ import django.core.validators as validators
4
+ import karrio.server.core.models as core
5
+
6
+
7
+ LABEL_TEMPLATE_TYPES = [
8
+ ("SVG", "SVG"),
9
+ ("ZPL", "ZPL"),
10
+ ]
11
+
12
+
13
+ @core.register_model
14
+ class LabelTemplate(core.OwnedEntity):
15
+ class Meta:
16
+ db_table = "label-template"
17
+ verbose_name = "Label Template"
18
+ verbose_name_plural = "Label Templates"
19
+ ordering = ["-created_at"]
20
+
21
+ id = models.CharField(
22
+ max_length=50,
23
+ primary_key=True,
24
+ default=functools.partial(core.uuid, prefix="tpl_"),
25
+ editable=False,
26
+ )
27
+ slug = models.SlugField(
28
+ max_length=30,
29
+ validators=[validators.RegexValidator(r"^[a-z0-9_]+$")],
30
+ )
31
+ template = models.TextField()
32
+ template_type = models.CharField(max_length=3, choices=LABEL_TEMPLATE_TYPES)
33
+ width = models.IntegerField(null=True, blank=True)
34
+ height = models.IntegerField(null=True, blank=True)
35
+ shipment_sample = models.JSONField(blank=True, null=True, default=dict)
36
+
37
+ @property
38
+ def object_type(self):
39
+ return "label_template"
@@ -0,0 +1,58 @@
1
+ import django.db.models as models
2
+ import django.core.cache as caching
3
+
4
+ import karrio.lib as lib
5
+
6
+
7
+ def has_rate_sheet(carrier_name: str):
8
+ def decorator(model: models.Model):
9
+ # Add a rate sheet relation to the model
10
+ model.add_to_class(
11
+ "rate_sheet",
12
+ models.ForeignKey(
13
+ "RateSheet",
14
+ null=True,
15
+ blank=True,
16
+ on_delete=models.SET_NULL,
17
+ ),
18
+ )
19
+
20
+ # Add a service list property to the model
21
+ setattr(
22
+ model,
23
+ "service_list",
24
+ property(
25
+ lambda self: (
26
+ self.services
27
+ if self.rate_sheet is None and hasattr(self, "services")
28
+ else self.rate_sheet.services.all()
29
+ )
30
+ ),
31
+ )
32
+
33
+ # Add a default services property to the model
34
+ # skip if it already exists (overridden)
35
+ if not hasattr(model, "default_services"):
36
+ setattr(
37
+ model,
38
+ "default_services",
39
+ property(
40
+ lambda self: lib.to_dict(
41
+ getattr(
42
+ getattr(
43
+ __import__(
44
+ f"karrio.mappers.{carrier_name}", fromlist=["units"]
45
+ ),
46
+ "units",
47
+ None,
48
+ ),
49
+ "DEFAULT_SERVICES",
50
+ [],
51
+ )
52
+ )
53
+ ),
54
+ )
55
+
56
+ return model
57
+
58
+ return decorator
@@ -0,0 +1,3 @@
1
+ from rest_framework.routers import DefaultRouter
2
+
3
+ router = DefaultRouter(trailing_slash=False)
@@ -0,0 +1,3 @@
1
+ from karrio.server.serializers import *
2
+ from karrio.server.core.serializers import *
3
+ from karrio.server.providers.serializers.base import *
@@ -0,0 +1,277 @@
1
+ import typing
2
+ import django.db.transaction as transaction
3
+
4
+ import karrio.lib as lib
5
+ import karrio.references as references
6
+ import karrio.server.openapi as openapi
7
+ import karrio.server.core.utils as utils
8
+ import karrio.server.serializers as serializers
9
+ import karrio.server.core.dataunits as dataunits
10
+ import karrio.server.providers.models as providers
11
+ from karrio.server.core.serializers import CARRIERS
12
+
13
+
14
+ def generate_carrier_serializers() -> typing.Dict[str, serializers.Serializer]:
15
+
16
+ def _create_serializer(carrier_name: str) -> serializers.Serializer:
17
+ fields = dataunits.REFERENCE_MODELS["connection_fields"][carrier_name]
18
+ return type(
19
+ carrier_name,
20
+ (serializers.Serializer,),
21
+ {
22
+ key: serializers.field_to_serializer(field)
23
+ for key, field in fields.items()
24
+ },
25
+ )
26
+
27
+ return {
28
+ carrier_name: _create_serializer(carrier_name)
29
+ for carrier_name in dataunits.REFERENCE_MODELS["carriers"].keys()
30
+ }
31
+
32
+
33
+ CONNECTION_SERIALIZERS = generate_carrier_serializers()
34
+
35
+
36
+ @openapi.extend_schema_field(
37
+ openapi.PolymorphicProxySerializer(
38
+ component_name="ConnectionCredentialsField",
39
+ serializers=CONNECTION_SERIALIZERS.values(),
40
+ resource_type_field_name=None,
41
+ )
42
+ )
43
+ class ConnectionCredentialsField(serializers.DictField):
44
+ pass
45
+
46
+
47
+ @serializers.owned_model_serializer
48
+ class CarrierConfigModelSerializer(serializers.ModelSerializer):
49
+ class Meta:
50
+ model = providers.CarrierConfig
51
+ exclude = ["created_at", "updated_at", "created_by"]
52
+ extra_kwargs = {field: {"read_only": True} for field in ["id"]}
53
+
54
+
55
+ class CarrierConnectionData(serializers.Serializer):
56
+
57
+ carrier_name = serializers.ChoiceField(
58
+ choices=CARRIERS,
59
+ required=True,
60
+ help_text="A carrier connection type.",
61
+ )
62
+ carrier_id = serializers.CharField(
63
+ required=True,
64
+ help_text="A carrier connection friendly name.",
65
+ )
66
+ credentials = ConnectionCredentialsField(
67
+ required=True,
68
+ help_text="Carrier connection credentials.",
69
+ )
70
+ capabilities = serializers.StringListField(
71
+ required=False,
72
+ allow_null=True,
73
+ help_text="""The carrier enabled capabilities.""",
74
+ )
75
+ config = serializers.PlainDictField(
76
+ required=False,
77
+ default={},
78
+ help_text="Carrier connection custom config.",
79
+ )
80
+ metadata = serializers.PlainDictField(
81
+ required=False,
82
+ default={},
83
+ help_text="User metadata for the carrier.",
84
+ )
85
+ active = serializers.BooleanField(
86
+ required=False,
87
+ default=True,
88
+ help_text="The active flag indicates whether the carrier account is active or not.",
89
+ )
90
+
91
+
92
+ class CarrierConnectionUpdateData(serializers.Serializer):
93
+ carrier_id = serializers.CharField(
94
+ required=False, help_text="A carrier connection friendly name."
95
+ )
96
+ credentials = serializers.PlainDictField(
97
+ required=False,
98
+ help_text="Carrier connection credentials.",
99
+ )
100
+ capabilities = serializers.StringListField(
101
+ required=False,
102
+ allow_null=True,
103
+ help_text="""The carrier enabled capabilities.""",
104
+ )
105
+ config = serializers.PlainDictField(
106
+ required=False,
107
+ default={},
108
+ help_text="Carrier connection custom config.",
109
+ )
110
+ metadata = serializers.PlainDictField(
111
+ required=False,
112
+ default={},
113
+ help_text="User metadata for the carrier.",
114
+ )
115
+ active = serializers.BooleanField(
116
+ required=False,
117
+ help_text="The active flag indicates whether the carrier account is active or not.",
118
+ )
119
+
120
+
121
+ class CarrierConnection(serializers.Serializer):
122
+ id = serializers.CharField(
123
+ required=True,
124
+ help_text="A unique carrier connection identifier",
125
+ )
126
+ object_type = serializers.CharField(
127
+ default="carrier-connection",
128
+ help_text="Specifies the object type",
129
+ )
130
+ carrier_name = serializers.ChoiceField(
131
+ choices=CARRIERS,
132
+ required=True,
133
+ help_text="A carrier connection type.",
134
+ )
135
+ display_name = serializers.CharField(
136
+ required=False,
137
+ help_text="The carrier connection type verbose name.",
138
+ )
139
+ carrier_id = serializers.CharField(
140
+ required=True,
141
+ help_text="A carrier connection friendly name.",
142
+ )
143
+ credentials = ConnectionCredentialsField(
144
+ required=False,
145
+ help_text="Carrier connection credentials.",
146
+ )
147
+ capabilities = serializers.StringListField(
148
+ required=False,
149
+ allow_null=True,
150
+ help_text="""The carrier enabled capabilities.""",
151
+ )
152
+ config = serializers.PlainDictField(
153
+ required=False,
154
+ default={},
155
+ help_text="Carrier connection custom config.",
156
+ )
157
+ metadata = serializers.PlainDictField(
158
+ required=False,
159
+ default={},
160
+ help_text="User metadata for the carrier.",
161
+ )
162
+ is_system = serializers.BooleanField(
163
+ required=True,
164
+ help_text="The carrier connection is provided by the system admin.",
165
+ )
166
+ active = serializers.BooleanField(
167
+ required=True,
168
+ help_text="The active flag indicates whether the carrier account is active or not.",
169
+ )
170
+ test_mode = serializers.BooleanField(
171
+ required=True,
172
+ help_text="The test flag indicates whether to use a carrier configured for test.",
173
+ )
174
+
175
+
176
+ @serializers.owned_model_serializer
177
+ class CarrierConnectionModelSerializer(serializers.ModelSerializer):
178
+ class Meta:
179
+ model = providers.Carrier
180
+ exclude = ["created_at", "updated_at", "created_by"]
181
+
182
+ carrier_name = serializers.ChoiceField(
183
+ required=True, choices=CARRIERS, help_text="Indicates a carrier (type)"
184
+ )
185
+ capabilities = serializers.StringListField(
186
+ required=False,
187
+ allow_null=True,
188
+ help_text="""The carrier enabled capabilities.""",
189
+ )
190
+ config = serializers.PlainDictField(
191
+ required=False,
192
+ allow_null=True,
193
+ help_text="Carrier connection custom config.",
194
+ )
195
+
196
+ @transaction.atomic
197
+ @utils.error_wrapper
198
+ def create(
199
+ self,
200
+ validated_data: dict,
201
+ context: serializers.Context,
202
+ **kwargs,
203
+ ) -> providers.Carrier:
204
+ config = validated_data.pop("config")
205
+ carrier_name = validated_data.pop("carrier_name")
206
+ default_capabilities = references.get_carrier_capabilities(carrier_name)
207
+ capabilities = lib.identity(
208
+ validated_data.get("capabilities")
209
+ if any(validated_data.get("capabilities") or [])
210
+ else default_capabilities
211
+ )
212
+
213
+ validated_data.update(test_mode=context.test_mode)
214
+ validated_data.update(carrier_code=carrier_name)
215
+ validated_data.update(
216
+ capabilities=[_ for _ in capabilities if _ in default_capabilities]
217
+ )
218
+ validated_data.update(
219
+ credentials=CONNECTION_SERIALIZERS[carrier_name]
220
+ .map(data=validated_data["credentials"])
221
+ .data
222
+ )
223
+
224
+ instance = super().create(validated_data, context=context, **kwargs)
225
+
226
+ if config is not None:
227
+ CarrierConfigModelSerializer.map(
228
+ context=context,
229
+ data={"carrier": instance.pk, "config": config},
230
+ ).save()
231
+
232
+ return providers.Carrier.objects.get(pk=instance.pk)
233
+
234
+ @transaction.atomic
235
+ @utils.error_wrapper
236
+ def update(
237
+ self,
238
+ instance: providers.Carrier,
239
+ validated_data: dict,
240
+ **kwargs,
241
+ ) -> providers.Carrier:
242
+ if any(validated_data.get("capabilities") or []):
243
+ default_capabilities = references.get_carrier_capabilities(instance.ext)
244
+ capabilities = validated_data.get("capabilities")
245
+ instance.capabilities = [
246
+ _ for _ in capabilities if _ in default_capabilities
247
+ ]
248
+
249
+ if "credentials" in validated_data:
250
+ data = serializers.process_dictionaries_mutations(
251
+ ["credentials"],
252
+ validated_data,
253
+ instance,
254
+ )
255
+ validated_data.update(
256
+ credentials=CONNECTION_SERIALIZERS[instance.ext]
257
+ .map(data=data["credentials"])
258
+ .data
259
+ )
260
+
261
+ if "config" in validated_data:
262
+ data = serializers.process_dictionaries_mutations(
263
+ ["config"],
264
+ dict(config=validated_data.pop("config")),
265
+ instance,
266
+ )
267
+ lib.identity(
268
+ CarrierConfigModelSerializer.map(
269
+ instance=instance.carrier_config,
270
+ context=kwargs.get("context"),
271
+ data={"carrier": instance.pk, **data},
272
+ )
273
+ .save()
274
+ .instance
275
+ )
276
+
277
+ return super().update(instance, validated_data, **kwargs)
@@ -0,0 +1,27 @@
1
+ import logging
2
+ from django.db.models import signals
3
+
4
+ import karrio.references as ref
5
+ import karrio.server.core.utils as utils
6
+ import karrio.server.providers.models as models
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ def register_signals():
12
+ signals.post_save.connect(carrier_changed, sender=models.Carrier)
13
+
14
+ logger.info("karrio.providers signals registered...")
15
+
16
+
17
+ @utils.disable_for_loaddata
18
+ def carrier_changed(
19
+ sender, instance, created, raw, using, update_fields, *args, **kwargs
20
+ ):
21
+ """Setup default capabilities when carrier are created."""
22
+ if not created:
23
+ return
24
+
25
+ if len(instance.capabilities or []) == 0:
26
+ instance.capabilities = ref.get_carrier_capabilities(instance.carrier_code)
27
+ instance.save()
@@ -0,0 +1,3 @@
1
+ from django.test import TestCase
2
+
3
+ # TODO: Write carriers API tests
@@ -0,0 +1,11 @@
1
+ """
2
+ karrio server providers module urls
3
+ """
4
+
5
+ from django.urls import include, path
6
+
7
+ app_name = "karrio.server.providers"
8
+ urlpatterns = [
9
+ path("v1/", include("karrio.server.providers.views.carriers")),
10
+ path("v1/", include("karrio.server.providers.views.connections")),
11
+ ]
File without changes