karrio-server-pricing 2026.1.3__py3-none-any.whl → 2026.1.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/pricing/models.py +16 -8
- karrio/server/pricing/signals.py +40 -3
- {karrio_server_pricing-2026.1.3.dist-info → karrio_server_pricing-2026.1.5.dist-info}/METADATA +1 -1
- {karrio_server_pricing-2026.1.3.dist-info → karrio_server_pricing-2026.1.5.dist-info}/RECORD +6 -6
- {karrio_server_pricing-2026.1.3.dist-info → karrio_server_pricing-2026.1.5.dist-info}/WHEEL +0 -0
- {karrio_server_pricing-2026.1.3.dist-info → karrio_server_pricing-2026.1.5.dist-info}/top_level.txt +0 -0
karrio/server/pricing/models.py
CHANGED
|
@@ -193,14 +193,22 @@ class Markup(core.Entity):
|
|
|
193
193
|
else (rate.total_charge * (typing.cast(float, self.amount) / 100))
|
|
194
194
|
)
|
|
195
195
|
total_charge = lib.to_decimal(rate.total_charge + amount)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
196
|
+
|
|
197
|
+
# Only add to extra_charges if the markup is visible.
|
|
198
|
+
# Non-visible markups (e.g., plan-based platform fees) are
|
|
199
|
+
# included in total_charge but hidden from the breakdown.
|
|
200
|
+
extra_charges = (
|
|
201
|
+
rate.extra_charges + [
|
|
202
|
+
karrio.ChargeDetails(
|
|
203
|
+
name=typing.cast(str, self.name),
|
|
204
|
+
amount=amount,
|
|
205
|
+
currency=rate.currency,
|
|
206
|
+
id=self.id,
|
|
207
|
+
)
|
|
208
|
+
]
|
|
209
|
+
if self.is_visible
|
|
210
|
+
else rate.extra_charges
|
|
211
|
+
)
|
|
204
212
|
|
|
205
213
|
return datatypes.Rate(
|
|
206
214
|
**{
|
karrio/server/pricing/signals.py
CHANGED
|
@@ -34,11 +34,17 @@ def apply_custom_markups(context: Context, result):
|
|
|
34
34
|
Apply active markups to rate quotes.
|
|
35
35
|
|
|
36
36
|
This function is called after rates are fetched from carriers.
|
|
37
|
-
It applies all active markups that match the organization context
|
|
37
|
+
It applies all active markups that match the organization context
|
|
38
|
+
and the tenant's pricing plan.
|
|
38
39
|
|
|
39
40
|
Markup scoping via organization_ids JSONField:
|
|
40
41
|
- Markups with org ID in organization_ids apply only to that org
|
|
41
42
|
- Markups with empty organization_ids are system-wide
|
|
43
|
+
|
|
44
|
+
Plan filtering via metadata.plan:
|
|
45
|
+
- Markups with no plan in metadata are global (apply to all plans)
|
|
46
|
+
- Markups with metadata.plan only apply when the tenant's plan matches
|
|
47
|
+
- Plan is resolved from: request filter > org metadata > default "launch"
|
|
42
48
|
"""
|
|
43
49
|
org_id = getattr(context.org, "id", None)
|
|
44
50
|
|
|
@@ -46,8 +52,10 @@ def apply_custom_markups(context: Context, result):
|
|
|
46
52
|
# Filter markups that either:
|
|
47
53
|
# 1. Have the current organization in their organization_ids list
|
|
48
54
|
# 2. Have an empty organization_ids list (system-wide markups)
|
|
55
|
+
# Note: icontains is used instead of __contains for cross-DB
|
|
56
|
+
# compatibility (SQLite does not support JSON containment lookups).
|
|
49
57
|
_filters = (
|
|
50
|
-
Q(active=True,
|
|
58
|
+
Q(active=True, organization_ids__icontains=org_id)
|
|
51
59
|
| Q(active=True, organization_ids=[]),
|
|
52
60
|
)
|
|
53
61
|
else:
|
|
@@ -56,9 +64,38 @@ def apply_custom_markups(context: Context, result):
|
|
|
56
64
|
|
|
57
65
|
markups = models.Markup.objects.filter(*_filters)
|
|
58
66
|
|
|
67
|
+
# Resolve the tenant's plan for plan-based markup filtering.
|
|
68
|
+
# Priority: explicit request filter > org metadata > default "launch"
|
|
69
|
+
request_plan = None
|
|
70
|
+
context_data = None
|
|
71
|
+
if hasattr(context, "_full_data"):
|
|
72
|
+
context_data = context._full_data
|
|
73
|
+
elif hasattr(context, "data"):
|
|
74
|
+
context_data = context.data
|
|
75
|
+
|
|
76
|
+
if context_data:
|
|
77
|
+
filters = context_data.get("filters") or {}
|
|
78
|
+
request_plan = filters.get("plan")
|
|
79
|
+
|
|
80
|
+
if request_plan:
|
|
81
|
+
tenant_plan = request_plan
|
|
82
|
+
else:
|
|
83
|
+
org_metadata = getattr(
|
|
84
|
+
getattr(context, "org", None), "metadata", {}
|
|
85
|
+
) or {}
|
|
86
|
+
tenant_plan = org_metadata.get("plan", "launch")
|
|
87
|
+
|
|
88
|
+
# Filter markups by plan:
|
|
89
|
+
# Apply if markup has no plan in metadata (global) OR plan matches tenant's plan
|
|
90
|
+
def matches_plan(markup):
|
|
91
|
+
markup_plan = (markup.metadata or {}).get("plan")
|
|
92
|
+
return markup_plan is None or markup_plan == tenant_plan
|
|
93
|
+
|
|
94
|
+
applicable_markups = [m for m in markups if matches_plan(m)]
|
|
95
|
+
|
|
59
96
|
return functools.reduce(
|
|
60
97
|
lambda cumulated_result, markup: markup.apply_charge(cumulated_result),
|
|
61
|
-
|
|
98
|
+
applicable_markups,
|
|
62
99
|
result,
|
|
63
100
|
)
|
|
64
101
|
|
{karrio_server_pricing-2026.1.3.dist-info → karrio_server_pricing-2026.1.5.dist-info}/RECORD
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
karrio/server/pricing/__init__.py,sha256=zXpxAFuHsCdAaESYGLRvdqCs7CXtIn8cF688jV4ufQc,64
|
|
2
2
|
karrio/server/pricing/admin.py,sha256=vDYvoFk9M6bGK6NBoJCRkxL5dla4sibNfej69_RIOT8,5642
|
|
3
3
|
karrio/server/pricing/apps.py,sha256=LBpxtFvuUn36DjMiPlQL51V5WfVMDf7N4QS3IUs_Pcs,431
|
|
4
|
-
karrio/server/pricing/models.py,sha256=
|
|
4
|
+
karrio/server/pricing/models.py,sha256=AfgSmMcN7H22_qLRlK5InWmdfnZi_YHMtQD-LJJhMr0,12040
|
|
5
5
|
karrio/server/pricing/serializers.py,sha256=48panQv9ZyLzkVa94XzOqbXxFm0daMK1_jOVJwQiNbI,574
|
|
6
|
-
karrio/server/pricing/signals.py,sha256=-
|
|
6
|
+
karrio/server/pricing/signals.py,sha256=-Q-SN0wElBhBJRfBF5Iez7Qkxte1fQ0eLpnOOJzPBkw,8034
|
|
7
7
|
karrio/server/pricing/tests.py,sha256=iaTqsY2pSPR1YRy9TqjhkfvRN8776l0Zoh4xeT0awQc,24818
|
|
8
8
|
karrio/server/pricing/views.py,sha256=xc1IQHrsij7j33TUbo-_oewy3vs03pw_etpBWaMYJl0,63
|
|
9
9
|
karrio/server/pricing/migrations/0001_initial.py,sha256=KKEklxf8Q1-IQn-8ZchbCi3-zmIyjn80DaGqPgRRI5w,52327
|
|
@@ -86,7 +86,7 @@ karrio/server/pricing/migrations/0077_migrate_surcharge_to_markup_data.py,sha256
|
|
|
86
86
|
karrio/server/pricing/migrations/0078_cleanup.py,sha256=aEO5ceQ6-35jz3mGblQ2RD_144Uu-gVAjaEckqHM1OM,4263
|
|
87
87
|
karrio/server/pricing/migrations/0079_fee_snapshot_model.py,sha256=n18S32UPAp_WMzVL4_Hf96drwGPE72pc45Ul2qPs-nk,9843
|
|
88
88
|
karrio/server/pricing/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
|
-
karrio_server_pricing-2026.1.
|
|
90
|
-
karrio_server_pricing-2026.1.
|
|
91
|
-
karrio_server_pricing-2026.1.
|
|
92
|
-
karrio_server_pricing-2026.1.
|
|
89
|
+
karrio_server_pricing-2026.1.5.dist-info/METADATA,sha256=0TayHwWKp9oIXYgD6rqDflmIK5Qdu9BT-KDN49g04VM,684
|
|
90
|
+
karrio_server_pricing-2026.1.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
91
|
+
karrio_server_pricing-2026.1.5.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
|
|
92
|
+
karrio_server_pricing-2026.1.5.dist-info/RECORD,,
|
|
File without changes
|
{karrio_server_pricing-2026.1.3.dist-info → karrio_server_pricing-2026.1.5.dist-info}/top_level.txt
RENAMED
|
File without changes
|