karrio-server-pricing 2026.1.1__py3-none-any.whl → 2026.1.4__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/admin.py +119 -23
- karrio/server/pricing/apps.py +5 -1
- karrio/server/pricing/migrations/0076_create_markup_and_fee_models.py +258 -0
- karrio/server/pricing/migrations/0077_migrate_surcharge_to_markup_data.py +70 -0
- karrio/server/pricing/migrations/0078_cleanup.py +109 -0
- karrio/server/pricing/migrations/0079_fee_snapshot_model.py +283 -0
- karrio/server/pricing/models.py +268 -87
- karrio/server/pricing/serializers.py +16 -11
- karrio/server/pricing/signals.py +138 -12
- karrio/server/pricing/tests.py +397 -9
- {karrio_server_pricing-2026.1.1.dist-info → karrio_server_pricing-2026.1.4.dist-info}/METADATA +1 -1
- {karrio_server_pricing-2026.1.1.dist-info → karrio_server_pricing-2026.1.4.dist-info}/RECORD +14 -10
- {karrio_server_pricing-2026.1.1.dist-info → karrio_server_pricing-2026.1.4.dist-info}/WHEEL +1 -1
- {karrio_server_pricing-2026.1.1.dist-info → karrio_server_pricing-2026.1.4.dist-info}/top_level.txt +0 -0
karrio/server/pricing/admin.py
CHANGED
|
@@ -1,55 +1,151 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Django admin configuration for Pricing module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
1
5
|
import importlib
|
|
2
6
|
|
|
3
7
|
from django import forms
|
|
4
8
|
from django.contrib import admin
|
|
5
|
-
from karrio.server.pricing.models import
|
|
9
|
+
from karrio.server.pricing.models import Markup, Fee
|
|
6
10
|
|
|
7
11
|
if importlib.util.find_spec("karrio.server.orgs") is not None:
|
|
8
12
|
import karrio.server.orgs.models as orgs
|
|
9
13
|
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
# MARKUP ADMIN
|
|
17
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MarkupAdmin(admin.ModelAdmin):
|
|
21
|
+
"""Admin interface for Markup model."""
|
|
22
|
+
|
|
23
|
+
list_display = ("name", "amount", "markup_type", "active", "is_visible")
|
|
24
|
+
list_filter = ("active", "is_visible", "markup_type")
|
|
25
|
+
search_fields = ("name", "carrier_codes", "service_codes")
|
|
26
|
+
readonly_fields = ("id",)
|
|
27
|
+
|
|
12
28
|
fieldsets = (
|
|
13
|
-
(None, {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
(None, {
|
|
30
|
+
"fields": (
|
|
31
|
+
"id",
|
|
32
|
+
("name", "active"),
|
|
33
|
+
("amount", "markup_type"),
|
|
34
|
+
"is_visible",
|
|
35
|
+
)
|
|
36
|
+
}),
|
|
37
|
+
("Filters", {
|
|
38
|
+
"classes": ("collapse",),
|
|
39
|
+
"description": "Leave empty to apply to all carriers/services/connections",
|
|
40
|
+
"fields": (
|
|
41
|
+
"carrier_codes",
|
|
42
|
+
"service_codes",
|
|
43
|
+
"connection_ids",
|
|
44
|
+
),
|
|
45
|
+
}),
|
|
46
|
+
("Metadata", {
|
|
47
|
+
"classes": ("collapse",),
|
|
48
|
+
"fields": ("metadata",),
|
|
49
|
+
}),
|
|
25
50
|
)
|
|
26
51
|
|
|
27
52
|
if importlib.util.find_spec("karrio.server.orgs") is not None:
|
|
28
53
|
|
|
29
|
-
class
|
|
54
|
+
class MarkupForm(forms.ModelForm):
|
|
30
55
|
class Meta:
|
|
31
|
-
model =
|
|
56
|
+
model = Markup
|
|
32
57
|
fields = "__all__"
|
|
33
58
|
|
|
34
59
|
def __init__(self, *args, **kwargs):
|
|
35
60
|
super().__init__(*args, **kwargs)
|
|
36
61
|
|
|
37
62
|
if kwargs.get("instance") is not None:
|
|
38
|
-
|
|
63
|
+
org_ids = kwargs["instance"].organization_ids or []
|
|
64
|
+
self.fields["organizations"].initial = (
|
|
65
|
+
orgs.Organization.objects.filter(id__in=org_ids)
|
|
66
|
+
)
|
|
39
67
|
|
|
40
68
|
organizations = forms.ModelMultipleChoiceField(
|
|
41
|
-
queryset=orgs.Organization.objects.all(),
|
|
69
|
+
queryset=orgs.Organization.objects.all(),
|
|
70
|
+
required=False,
|
|
71
|
+
help_text="Organizations this markup applies to. Leave empty for global.",
|
|
42
72
|
)
|
|
43
73
|
|
|
44
74
|
def save(self, commit=True):
|
|
45
|
-
instance = super().save(commit=
|
|
46
|
-
instance.save()
|
|
75
|
+
instance = super().save(commit=False)
|
|
47
76
|
organizations = self.cleaned_data.get("organizations", [])
|
|
48
|
-
instance.org.
|
|
77
|
+
instance.organization_ids = [str(org.id) for org in organizations]
|
|
78
|
+
instance.save()
|
|
49
79
|
return instance
|
|
50
80
|
|
|
51
|
-
form =
|
|
81
|
+
form = MarkupForm
|
|
52
82
|
fieldsets += ((None, {"fields": ("organizations",)}),)
|
|
53
83
|
|
|
54
84
|
|
|
55
|
-
admin.site.register(
|
|
85
|
+
admin.site.register(Markup, MarkupAdmin)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
89
|
+
# FEE ADMIN (Read-only)
|
|
90
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class FeeAdmin(admin.ModelAdmin):
|
|
94
|
+
"""Admin interface for Fee model (read-only)."""
|
|
95
|
+
|
|
96
|
+
list_display = ("name", "amount", "currency", "carrier_code", "service_code", "created_at")
|
|
97
|
+
list_filter = ("fee_type", "carrier_code", "currency", "test_mode")
|
|
98
|
+
search_fields = ("name", "shipment_id", "markup_id", "account_id")
|
|
99
|
+
readonly_fields = (
|
|
100
|
+
"id", "shipment_id", "markup_id", "account_id", "name", "amount", "currency",
|
|
101
|
+
"fee_type", "percentage", "carrier_code", "service_code",
|
|
102
|
+
"connection_id", "test_mode", "created_at",
|
|
103
|
+
)
|
|
104
|
+
date_hierarchy = "created_at"
|
|
105
|
+
|
|
106
|
+
fieldsets = (
|
|
107
|
+
(None, {
|
|
108
|
+
"fields": ("id", "shipment_id", "markup_id", "account_id")
|
|
109
|
+
}),
|
|
110
|
+
("Fee Details", {
|
|
111
|
+
"fields": (
|
|
112
|
+
"name",
|
|
113
|
+
("amount", "currency"),
|
|
114
|
+
("fee_type", "percentage"),
|
|
115
|
+
)
|
|
116
|
+
}),
|
|
117
|
+
("Context", {
|
|
118
|
+
"fields": (
|
|
119
|
+
"carrier_code",
|
|
120
|
+
"service_code",
|
|
121
|
+
"connection_id",
|
|
122
|
+
"test_mode",
|
|
123
|
+
)
|
|
124
|
+
}),
|
|
125
|
+
("Timestamps", {
|
|
126
|
+
"fields": ("created_at",)
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def has_add_permission(self, request):
|
|
131
|
+
"""Fees are created automatically, not manually."""
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
def has_change_permission(self, request, obj=None):
|
|
135
|
+
"""Fees should not be edited."""
|
|
136
|
+
return False
|
|
137
|
+
|
|
138
|
+
def has_delete_permission(self, request, obj=None):
|
|
139
|
+
"""Allow deletion for cleanup purposes."""
|
|
140
|
+
return True
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
admin.site.register(Fee, FeeAdmin)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
147
|
+
# LEGACY ALIAS
|
|
148
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
# For backward compatibility
|
|
151
|
+
SurchargeAdmin = MarkupAdmin
|
karrio/server/pricing/apps.py
CHANGED
|
@@ -7,6 +7,10 @@ class PricingConfig(AppConfig):
|
|
|
7
7
|
verbose_name = _("Shipping Markup")
|
|
8
8
|
|
|
9
9
|
def ready(self):
|
|
10
|
-
from karrio.server.pricing.signals import
|
|
10
|
+
from karrio.server.pricing.signals import (
|
|
11
|
+
register_rate_post_processing,
|
|
12
|
+
register_fee_capture,
|
|
13
|
+
)
|
|
11
14
|
|
|
12
15
|
register_rate_post_processing()
|
|
16
|
+
register_fee_capture()
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Generated migration for Markup and Fee models
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
import django.db.models.deletion
|
|
6
|
+
import karrio.server.core.models
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
"""
|
|
11
|
+
Create new Markup and Fee models.
|
|
12
|
+
|
|
13
|
+
This is part of the Surcharge -> Markup refactoring:
|
|
14
|
+
- Markup model replaces Surcharge with JSONField-based filters
|
|
15
|
+
- Fee model tracks applied markups for usage statistics
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
dependencies = [
|
|
19
|
+
("pricing", "0075_alter_surcharge_carriers_alter_surcharge_services"),
|
|
20
|
+
("manager", "0079_remove_carrier_fk_fields"),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
operations = [
|
|
24
|
+
# Create Markup model
|
|
25
|
+
migrations.CreateModel(
|
|
26
|
+
name="Markup",
|
|
27
|
+
fields=[
|
|
28
|
+
(
|
|
29
|
+
"created_at",
|
|
30
|
+
models.DateTimeField(auto_now_add=True),
|
|
31
|
+
),
|
|
32
|
+
(
|
|
33
|
+
"updated_at",
|
|
34
|
+
models.DateTimeField(auto_now=True),
|
|
35
|
+
),
|
|
36
|
+
(
|
|
37
|
+
"id",
|
|
38
|
+
models.CharField(
|
|
39
|
+
default=functools.partial(
|
|
40
|
+
karrio.server.core.models.uuid, prefix="mkp_"
|
|
41
|
+
),
|
|
42
|
+
editable=False,
|
|
43
|
+
max_length=50,
|
|
44
|
+
primary_key=True,
|
|
45
|
+
serialize=False,
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
(
|
|
49
|
+
"name",
|
|
50
|
+
models.CharField(
|
|
51
|
+
help_text="The markup name (label) that will appear in the rate breakdown",
|
|
52
|
+
max_length=100,
|
|
53
|
+
unique=True,
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
(
|
|
57
|
+
"active",
|
|
58
|
+
models.BooleanField(
|
|
59
|
+
default=True,
|
|
60
|
+
help_text="Whether the markup is active and will be applied to rates",
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
(
|
|
64
|
+
"amount",
|
|
65
|
+
models.FloatField(
|
|
66
|
+
default=0.0,
|
|
67
|
+
help_text="The markup amount or percentage to add to the quote.",
|
|
68
|
+
),
|
|
69
|
+
),
|
|
70
|
+
(
|
|
71
|
+
"markup_type",
|
|
72
|
+
models.CharField(
|
|
73
|
+
choices=[("AMOUNT", "AMOUNT"), ("PERCENTAGE", "PERCENTAGE")],
|
|
74
|
+
default="AMOUNT",
|
|
75
|
+
help_text="Determine whether the markup is in percentage or net amount.",
|
|
76
|
+
max_length=25,
|
|
77
|
+
),
|
|
78
|
+
),
|
|
79
|
+
(
|
|
80
|
+
"is_visible",
|
|
81
|
+
models.BooleanField(
|
|
82
|
+
default=True,
|
|
83
|
+
help_text="Whether to show this markup in the rate breakdown to users",
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
(
|
|
87
|
+
"carrier_codes",
|
|
88
|
+
models.JSONField(
|
|
89
|
+
blank=True,
|
|
90
|
+
default=list,
|
|
91
|
+
help_text="List of carrier codes to apply the markup to.",
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
(
|
|
95
|
+
"service_codes",
|
|
96
|
+
models.JSONField(
|
|
97
|
+
blank=True,
|
|
98
|
+
default=list,
|
|
99
|
+
help_text="List of service codes to apply the markup to.",
|
|
100
|
+
),
|
|
101
|
+
),
|
|
102
|
+
(
|
|
103
|
+
"connection_ids",
|
|
104
|
+
models.JSONField(
|
|
105
|
+
blank=True,
|
|
106
|
+
default=list,
|
|
107
|
+
help_text="List of connection IDs to apply the markup to.",
|
|
108
|
+
),
|
|
109
|
+
),
|
|
110
|
+
(
|
|
111
|
+
"organization_ids",
|
|
112
|
+
models.JSONField(
|
|
113
|
+
blank=True,
|
|
114
|
+
default=list,
|
|
115
|
+
help_text="List of organization IDs to apply the markup to.",
|
|
116
|
+
),
|
|
117
|
+
),
|
|
118
|
+
(
|
|
119
|
+
"metadata",
|
|
120
|
+
models.JSONField(
|
|
121
|
+
blank=True,
|
|
122
|
+
default=dict,
|
|
123
|
+
help_text="Additional metadata for the markup",
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
],
|
|
127
|
+
options={
|
|
128
|
+
"verbose_name": "Markup",
|
|
129
|
+
"verbose_name_plural": "Markups",
|
|
130
|
+
"db_table": "markup",
|
|
131
|
+
"ordering": ["-created_at"],
|
|
132
|
+
},
|
|
133
|
+
),
|
|
134
|
+
# Create Fee model
|
|
135
|
+
migrations.CreateModel(
|
|
136
|
+
name="Fee",
|
|
137
|
+
fields=[
|
|
138
|
+
(
|
|
139
|
+
"id",
|
|
140
|
+
models.CharField(
|
|
141
|
+
default=functools.partial(
|
|
142
|
+
karrio.server.core.models.uuid, prefix="fee_"
|
|
143
|
+
),
|
|
144
|
+
editable=False,
|
|
145
|
+
max_length=50,
|
|
146
|
+
primary_key=True,
|
|
147
|
+
serialize=False,
|
|
148
|
+
),
|
|
149
|
+
),
|
|
150
|
+
(
|
|
151
|
+
"name",
|
|
152
|
+
models.CharField(
|
|
153
|
+
help_text="The fee name at time of application",
|
|
154
|
+
max_length=100,
|
|
155
|
+
),
|
|
156
|
+
),
|
|
157
|
+
(
|
|
158
|
+
"amount",
|
|
159
|
+
models.FloatField(
|
|
160
|
+
help_text="The fee amount in the shipment's currency",
|
|
161
|
+
),
|
|
162
|
+
),
|
|
163
|
+
(
|
|
164
|
+
"currency",
|
|
165
|
+
models.CharField(
|
|
166
|
+
help_text="Currency code (e.g., USD, EUR)",
|
|
167
|
+
max_length=3,
|
|
168
|
+
),
|
|
169
|
+
),
|
|
170
|
+
(
|
|
171
|
+
"markup_type",
|
|
172
|
+
models.CharField(
|
|
173
|
+
choices=[("AMOUNT", "AMOUNT"), ("PERCENTAGE", "PERCENTAGE")],
|
|
174
|
+
help_text="Whether this was a fixed amount or percentage markup",
|
|
175
|
+
max_length=25,
|
|
176
|
+
),
|
|
177
|
+
),
|
|
178
|
+
(
|
|
179
|
+
"markup_percentage",
|
|
180
|
+
models.FloatField(
|
|
181
|
+
blank=True,
|
|
182
|
+
help_text="Original percentage if this was a percentage-based markup",
|
|
183
|
+
null=True,
|
|
184
|
+
),
|
|
185
|
+
),
|
|
186
|
+
(
|
|
187
|
+
"carrier_code",
|
|
188
|
+
models.CharField(
|
|
189
|
+
help_text="Carrier code at time of shipment creation",
|
|
190
|
+
max_length=50,
|
|
191
|
+
),
|
|
192
|
+
),
|
|
193
|
+
(
|
|
194
|
+
"service_code",
|
|
195
|
+
models.CharField(
|
|
196
|
+
blank=True,
|
|
197
|
+
help_text="Service code at time of shipment creation",
|
|
198
|
+
max_length=100,
|
|
199
|
+
null=True,
|
|
200
|
+
),
|
|
201
|
+
),
|
|
202
|
+
(
|
|
203
|
+
"connection_id",
|
|
204
|
+
models.CharField(
|
|
205
|
+
help_text="Connection ID used for this shipment",
|
|
206
|
+
max_length=50,
|
|
207
|
+
),
|
|
208
|
+
),
|
|
209
|
+
(
|
|
210
|
+
"created_at",
|
|
211
|
+
models.DateTimeField(auto_now_add=True),
|
|
212
|
+
),
|
|
213
|
+
(
|
|
214
|
+
"markup",
|
|
215
|
+
models.ForeignKey(
|
|
216
|
+
blank=True,
|
|
217
|
+
help_text="The markup that generated this fee",
|
|
218
|
+
null=True,
|
|
219
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
220
|
+
related_name="fees",
|
|
221
|
+
to="pricing.markup",
|
|
222
|
+
),
|
|
223
|
+
),
|
|
224
|
+
(
|
|
225
|
+
"shipment",
|
|
226
|
+
models.ForeignKey(
|
|
227
|
+
help_text="The shipment this fee was applied to",
|
|
228
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
229
|
+
related_name="fees",
|
|
230
|
+
to="manager.shipment",
|
|
231
|
+
),
|
|
232
|
+
),
|
|
233
|
+
],
|
|
234
|
+
options={
|
|
235
|
+
"verbose_name": "Fee",
|
|
236
|
+
"verbose_name_plural": "Fees",
|
|
237
|
+
"db_table": "fee",
|
|
238
|
+
"ordering": ["-created_at"],
|
|
239
|
+
},
|
|
240
|
+
),
|
|
241
|
+
# Add indexes for Fee model
|
|
242
|
+
migrations.AddIndex(
|
|
243
|
+
model_name="fee",
|
|
244
|
+
index=models.Index(fields=["shipment_id"], name="fee_shipmen_d4e9f2_idx"),
|
|
245
|
+
),
|
|
246
|
+
migrations.AddIndex(
|
|
247
|
+
model_name="fee",
|
|
248
|
+
index=models.Index(fields=["markup_id"], name="fee_markup__29f8a1_idx"),
|
|
249
|
+
),
|
|
250
|
+
migrations.AddIndex(
|
|
251
|
+
model_name="fee",
|
|
252
|
+
index=models.Index(fields=["carrier_code"], name="fee_carrier_3c7b8e_idx"),
|
|
253
|
+
),
|
|
254
|
+
migrations.AddIndex(
|
|
255
|
+
model_name="fee",
|
|
256
|
+
index=models.Index(fields=["created_at"], name="fee_created_a1b2c3_idx"),
|
|
257
|
+
),
|
|
258
|
+
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Data migration: Surcharge -> Markup
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def migrate_surcharges_to_markups(apps, schema_editor):
|
|
7
|
+
"""
|
|
8
|
+
Migrate existing Surcharge records to new Markup model.
|
|
9
|
+
|
|
10
|
+
Mappings:
|
|
11
|
+
- id: chrg_xxx -> mkp_xxx (preserve original ID for fee tracking)
|
|
12
|
+
- surcharge_type -> markup_type
|
|
13
|
+
- carriers -> carrier_codes
|
|
14
|
+
- services -> service_codes
|
|
15
|
+
- carrier_accounts (M2M) -> connection_ids (JSONField)
|
|
16
|
+
"""
|
|
17
|
+
Surcharge = apps.get_model("pricing", "Surcharge")
|
|
18
|
+
Markup = apps.get_model("pricing", "Markup")
|
|
19
|
+
|
|
20
|
+
for surcharge in Surcharge.objects.all():
|
|
21
|
+
# Get carrier account IDs from M2M relation
|
|
22
|
+
connection_ids = list(
|
|
23
|
+
surcharge.carrier_accounts.values_list("id", flat=True)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Create Markup record with mapped data
|
|
27
|
+
# Preserve original ID to maintain fee tracking
|
|
28
|
+
Markup.objects.create(
|
|
29
|
+
id=surcharge.id, # Keep original ID (chrg_xxx)
|
|
30
|
+
name=surcharge.name,
|
|
31
|
+
active=surcharge.active,
|
|
32
|
+
amount=surcharge.amount,
|
|
33
|
+
markup_type=surcharge.surcharge_type, # Same values (AMOUNT/PERCENTAGE)
|
|
34
|
+
is_visible=True, # New field, default visible
|
|
35
|
+
carrier_codes=surcharge.carriers or [],
|
|
36
|
+
service_codes=surcharge.services or [],
|
|
37
|
+
connection_ids=connection_ids,
|
|
38
|
+
metadata={},
|
|
39
|
+
created_at=surcharge.created_at,
|
|
40
|
+
updated_at=surcharge.updated_at,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
print(f"Migrated surcharge {surcharge.id} -> markup")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def reverse_migration(apps, schema_editor):
|
|
47
|
+
"""
|
|
48
|
+
Reverse the migration by clearing Markup table.
|
|
49
|
+
Note: This doesn't restore Surcharge data - use with caution.
|
|
50
|
+
"""
|
|
51
|
+
Markup = apps.get_model("pricing", "Markup")
|
|
52
|
+
Markup.objects.all().delete()
|
|
53
|
+
print("Cleared Markup table")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Migration(migrations.Migration):
|
|
57
|
+
"""
|
|
58
|
+
Data migration to convert Surcharge records to Markup records.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
dependencies = [
|
|
62
|
+
("pricing", "0076_create_markup_and_fee_models"),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
operations = [
|
|
66
|
+
migrations.RunPython(
|
|
67
|
+
migrate_surcharges_to_markups,
|
|
68
|
+
reverse_migration,
|
|
69
|
+
),
|
|
70
|
+
]
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Generated by Django 5.2.10 on 2026-01-22 14:29
|
|
2
|
+
|
|
3
|
+
import django.core.validators
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
("pricing", "0077_migrate_surcharge_to_markup_data"),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.RemoveField(
|
|
16
|
+
model_name="surcharge",
|
|
17
|
+
name="carrier_accounts",
|
|
18
|
+
),
|
|
19
|
+
migrations.RenameIndex(
|
|
20
|
+
model_name="fee",
|
|
21
|
+
new_name="fee_shipmen_cf6644_idx",
|
|
22
|
+
old_name="fee_shipmen_d4e9f2_idx",
|
|
23
|
+
),
|
|
24
|
+
migrations.RenameIndex(
|
|
25
|
+
model_name="fee",
|
|
26
|
+
new_name="fee_markup__6438ea_idx",
|
|
27
|
+
old_name="fee_markup__29f8a1_idx",
|
|
28
|
+
),
|
|
29
|
+
migrations.RenameIndex(
|
|
30
|
+
model_name="fee",
|
|
31
|
+
new_name="fee_carrier_86bb46_idx",
|
|
32
|
+
old_name="fee_carrier_3c7b8e_idx",
|
|
33
|
+
),
|
|
34
|
+
migrations.RenameIndex(
|
|
35
|
+
model_name="fee",
|
|
36
|
+
new_name="fee_created_050ccc_idx",
|
|
37
|
+
old_name="fee_created_a1b2c3_idx",
|
|
38
|
+
),
|
|
39
|
+
migrations.AlterField(
|
|
40
|
+
model_name="fee",
|
|
41
|
+
name="markup",
|
|
42
|
+
field=models.ForeignKey(
|
|
43
|
+
blank=True,
|
|
44
|
+
help_text="The markup that generated this fee (null if markup was deleted)",
|
|
45
|
+
null=True,
|
|
46
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
47
|
+
related_name="fees",
|
|
48
|
+
to="pricing.markup",
|
|
49
|
+
),
|
|
50
|
+
),
|
|
51
|
+
migrations.AlterField(
|
|
52
|
+
model_name="markup",
|
|
53
|
+
name="amount",
|
|
54
|
+
field=models.FloatField(
|
|
55
|
+
default=0.0,
|
|
56
|
+
help_text="\n The markup amount or percentage to add to the quote.\n For AMOUNT type: the exact dollar amount to add.\n For PERCENTAGE type: the percentage (e.g., 5 means 5%).\n ",
|
|
57
|
+
validators=[django.core.validators.MinValueValidator(0.0)],
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
migrations.AlterField(
|
|
61
|
+
model_name="markup",
|
|
62
|
+
name="carrier_codes",
|
|
63
|
+
field=models.JSONField(
|
|
64
|
+
blank=True,
|
|
65
|
+
default=list,
|
|
66
|
+
help_text='\n List of carrier codes to apply the markup to (e.g., ["fedex", "ups"]).\n Empty list means apply to all carriers.\n ',
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
migrations.AlterField(
|
|
70
|
+
model_name="markup",
|
|
71
|
+
name="connection_ids",
|
|
72
|
+
field=models.JSONField(
|
|
73
|
+
blank=True,
|
|
74
|
+
default=list,
|
|
75
|
+
help_text='\n List of connection IDs to apply the markup to (e.g., ["car_xxx", "car_yyy"]).\n Supports all connection types: CarrierConnection, SystemConnection, BrokeredConnection.\n Empty list means apply to all connections.\n ',
|
|
76
|
+
),
|
|
77
|
+
),
|
|
78
|
+
migrations.AlterField(
|
|
79
|
+
model_name="markup",
|
|
80
|
+
name="markup_type",
|
|
81
|
+
field=models.CharField(
|
|
82
|
+
choices=[("AMOUNT", "AMOUNT"), ("PERCENTAGE", "PERCENTAGE")],
|
|
83
|
+
default="AMOUNT",
|
|
84
|
+
help_text="\n Determine whether the markup is in percentage or net amount.\n AMOUNT: rate ($22) + amount (1) = $23\n PERCENTAGE: rate ($22) * 5% = $23.10\n ",
|
|
85
|
+
max_length=25,
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
migrations.AlterField(
|
|
89
|
+
model_name="markup",
|
|
90
|
+
name="organization_ids",
|
|
91
|
+
field=models.JSONField(
|
|
92
|
+
blank=True,
|
|
93
|
+
default=list,
|
|
94
|
+
help_text="\n List of organization IDs to apply the markup to.\n Empty list means apply to all organizations (system-wide).\n ",
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
migrations.AlterField(
|
|
98
|
+
model_name="markup",
|
|
99
|
+
name="service_codes",
|
|
100
|
+
field=models.JSONField(
|
|
101
|
+
blank=True,
|
|
102
|
+
default=list,
|
|
103
|
+
help_text='\n List of service codes to apply the markup to (e.g., ["fedex_ground", "ups_next_day"]).\n Empty list means apply to all services.\n ',
|
|
104
|
+
),
|
|
105
|
+
),
|
|
106
|
+
migrations.DeleteModel(
|
|
107
|
+
name="Surcharge",
|
|
108
|
+
),
|
|
109
|
+
]
|