Skip to content

Commit 22a26d6

Browse files
Module prices
1 parent cc0bc26 commit 22a26d6

21 files changed

+805
-28
lines changed

backend/api/urls.py

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
UserModulesView,
1717
ModuleDetailView,
1818
get_module_bom_list_items,
19+
module_cost_stats,
1920
rate_component,
2021
get_average_rating,
2122
get_module_status,
@@ -209,6 +210,11 @@
209210
get_module_bom_list_items,
210211
name="module-bom-list-items",
211212
),
213+
path(
214+
"module/cost-stats/<uuid:module_id>/",
215+
module_cost_stats,
216+
name="module-cost-stats",
217+
),
212218
path(
213219
"shopping-list/inventory/add/",
214220
add_all_user_shopping_list_to_inventory,

backend/modules/admin.py

+27
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,33 @@ class ModuleAdmin(BaseAdmin):
8686
)
8787
},
8888
),
89+
(
90+
"Cost Information",
91+
{
92+
"fields": (
93+
# Built cost group
94+
"cost_built",
95+
"cost_built_link",
96+
"cost_built_third_party",
97+
# PCB only cost group
98+
"cost_pcb_only",
99+
"cost_pcb_only_link",
100+
"cost_pcb_only_third_party",
101+
# PCB plus front cost group
102+
"cost_pcb_plus_front",
103+
"cost_pcb_plus_front_link",
104+
"cost_pcb_plus_front_third_party",
105+
# Kit cost group
106+
"cost_kit",
107+
"cost_kit_link",
108+
"cost_kit_third_party",
109+
# Partial kit cost group
110+
"cost_partial_kit",
111+
"cost_partial_kit_link",
112+
"cost_partial_kit_third_party",
113+
)
114+
},
115+
),
89116
(
90117
"Other Info",
91118
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Generated by Django 5.0 on 2025-02-13 06:37
2+
3+
import djmoney.models.fields
4+
from django.db import migrations
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('modules', '0023_alter_module_rack_unit'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='module',
16+
name='cost_built',
17+
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default_currency='USD', max_digits=10, null=True),
18+
),
19+
migrations.AddField(
20+
model_name='module',
21+
name='cost_built_currency',
22+
field=djmoney.models.fields.CurrencyField(choices=[('AUD', 'Australian Dollar (A$)'), ('GBP', 'British Pound (£)'), ('CAD', 'Canadian Dollar (C$)'), ('CNY', 'Chinese Yuan (¥)'), ('EUR', 'Euro (€)'), ('HKD', 'Hong Kong Dollar (HK$)'), ('INR', 'Indian Rupee (₹)'), ('JPY', 'Japanese Yen (¥)'), ('NZD', 'New Zealand Dollar (NZ$)'), ('NOK', 'Norwegian Krone (kr)'), ('SGD', 'Singapore Dollar (S$)'), ('KRW', 'South Korean Won (₩)'), ('SEK', 'Swedish Krona (kr)'), ('CHF', 'Swiss Franc (Fr.)'), ('USD', 'US Dollar ($)')], default='USD', editable=False, max_length=3, null=True),
23+
),
24+
migrations.AddField(
25+
model_name='module',
26+
name='cost_kit',
27+
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default_currency='USD', max_digits=10, null=True),
28+
),
29+
migrations.AddField(
30+
model_name='module',
31+
name='cost_kit_currency',
32+
field=djmoney.models.fields.CurrencyField(choices=[('AUD', 'Australian Dollar (A$)'), ('GBP', 'British Pound (£)'), ('CAD', 'Canadian Dollar (C$)'), ('CNY', 'Chinese Yuan (¥)'), ('EUR', 'Euro (€)'), ('HKD', 'Hong Kong Dollar (HK$)'), ('INR', 'Indian Rupee (₹)'), ('JPY', 'Japanese Yen (¥)'), ('NZD', 'New Zealand Dollar (NZ$)'), ('NOK', 'Norwegian Krone (kr)'), ('SGD', 'Singapore Dollar (S$)'), ('KRW', 'South Korean Won (₩)'), ('SEK', 'Swedish Krona (kr)'), ('CHF', 'Swiss Franc (Fr.)'), ('USD', 'US Dollar ($)')], default='USD', editable=False, max_length=3, null=True),
33+
),
34+
migrations.AddField(
35+
model_name='module',
36+
name='cost_partial_kit',
37+
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default_currency='USD', max_digits=10, null=True),
38+
),
39+
migrations.AddField(
40+
model_name='module',
41+
name='cost_partial_kit_currency',
42+
field=djmoney.models.fields.CurrencyField(choices=[('AUD', 'Australian Dollar (A$)'), ('GBP', 'British Pound (£)'), ('CAD', 'Canadian Dollar (C$)'), ('CNY', 'Chinese Yuan (¥)'), ('EUR', 'Euro (€)'), ('HKD', 'Hong Kong Dollar (HK$)'), ('INR', 'Indian Rupee (₹)'), ('JPY', 'Japanese Yen (¥)'), ('NZD', 'New Zealand Dollar (NZ$)'), ('NOK', 'Norwegian Krone (kr)'), ('SGD', 'Singapore Dollar (S$)'), ('KRW', 'South Korean Won (₩)'), ('SEK', 'Swedish Krona (kr)'), ('CHF', 'Swiss Franc (Fr.)'), ('USD', 'US Dollar ($)')], default='USD', editable=False, max_length=3, null=True),
43+
),
44+
migrations.AddField(
45+
model_name='module',
46+
name='cost_pcb_only',
47+
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default_currency='USD', max_digits=10, null=True),
48+
),
49+
migrations.AddField(
50+
model_name='module',
51+
name='cost_pcb_only_currency',
52+
field=djmoney.models.fields.CurrencyField(choices=[('AUD', 'Australian Dollar (A$)'), ('GBP', 'British Pound (£)'), ('CAD', 'Canadian Dollar (C$)'), ('CNY', 'Chinese Yuan (¥)'), ('EUR', 'Euro (€)'), ('HKD', 'Hong Kong Dollar (HK$)'), ('INR', 'Indian Rupee (₹)'), ('JPY', 'Japanese Yen (¥)'), ('NZD', 'New Zealand Dollar (NZ$)'), ('NOK', 'Norwegian Krone (kr)'), ('SGD', 'Singapore Dollar (S$)'), ('KRW', 'South Korean Won (₩)'), ('SEK', 'Swedish Krona (kr)'), ('CHF', 'Swiss Franc (Fr.)'), ('USD', 'US Dollar ($)')], default='USD', editable=False, max_length=3, null=True),
53+
),
54+
migrations.AddField(
55+
model_name='module',
56+
name='cost_pcb_plus_front',
57+
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=2, default_currency='USD', max_digits=10, null=True),
58+
),
59+
migrations.AddField(
60+
model_name='module',
61+
name='cost_pcb_plus_front_currency',
62+
field=djmoney.models.fields.CurrencyField(choices=[('AUD', 'Australian Dollar (A$)'), ('GBP', 'British Pound (£)'), ('CAD', 'Canadian Dollar (C$)'), ('CNY', 'Chinese Yuan (¥)'), ('EUR', 'Euro (€)'), ('HKD', 'Hong Kong Dollar (HK$)'), ('INR', 'Indian Rupee (₹)'), ('JPY', 'Japanese Yen (¥)'), ('NZD', 'New Zealand Dollar (NZ$)'), ('NOK', 'Norwegian Krone (kr)'), ('SGD', 'Singapore Dollar (S$)'), ('KRW', 'South Korean Won (₩)'), ('SEK', 'Swedish Krona (kr)'), ('CHF', 'Swiss Franc (Fr.)'), ('USD', 'US Dollar ($)')], default='USD', editable=False, max_length=3, null=True),
63+
),
64+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Generated by Django 5.0 on 2025-02-13 07:56
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('modules', '0024_module_cost_built_module_cost_built_currency_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='module',
15+
name='cost_built_link',
16+
field=models.URLField(blank=True, null=True),
17+
),
18+
migrations.AddField(
19+
model_name='module',
20+
name='cost_built_third_party',
21+
field=models.BooleanField(default=False),
22+
),
23+
migrations.AddField(
24+
model_name='module',
25+
name='cost_kit_link',
26+
field=models.URLField(blank=True, null=True),
27+
),
28+
migrations.AddField(
29+
model_name='module',
30+
name='cost_kit_third_party',
31+
field=models.BooleanField(default=False),
32+
),
33+
migrations.AddField(
34+
model_name='module',
35+
name='cost_partial_kit_link',
36+
field=models.URLField(blank=True, null=True),
37+
),
38+
migrations.AddField(
39+
model_name='module',
40+
name='cost_partial_kit_third_party',
41+
field=models.BooleanField(default=False),
42+
),
43+
migrations.AddField(
44+
model_name='module',
45+
name='cost_pcb_only_link',
46+
field=models.URLField(blank=True, null=True),
47+
),
48+
migrations.AddField(
49+
model_name='module',
50+
name='cost_pcb_only_third_party',
51+
field=models.BooleanField(default=False),
52+
),
53+
migrations.AddField(
54+
model_name='module',
55+
name='cost_pcb_plus_front_link',
56+
field=models.URLField(blank=True, null=True),
57+
),
58+
migrations.AddField(
59+
model_name='module',
60+
name='cost_pcb_plus_front_third_party',
61+
field=models.BooleanField(default=False),
62+
),
63+
]

backend/modules/models.py

+32
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from djmoney.models.fields import MoneyField
12
from django.db import models
23
from django.template.defaultfilters import slugify
34
from components.models import Component
@@ -155,6 +156,37 @@ class Module(BaseModel):
155156
null=True,
156157
help_text="Select the module category (e.g., Eurorack, Pedals, Serge).",
157158
)
159+
# Cost fields with MoneyField
160+
cost_built = MoneyField(
161+
max_digits=10, decimal_places=2, default_currency="USD", blank=True, null=True
162+
)
163+
cost_built_link = models.URLField(blank=True, null=True)
164+
cost_built_third_party = models.BooleanField(default=False)
165+
166+
cost_pcb_only = MoneyField(
167+
max_digits=10, decimal_places=2, default_currency="USD", blank=True, null=True
168+
)
169+
cost_pcb_only_link = models.URLField(blank=True, null=True)
170+
cost_pcb_only_third_party = models.BooleanField(default=False)
171+
172+
cost_pcb_plus_front = MoneyField(
173+
max_digits=10, decimal_places=2, default_currency="USD", blank=True, null=True
174+
)
175+
cost_pcb_plus_front_link = models.URLField(blank=True, null=True)
176+
cost_pcb_plus_front_third_party = models.BooleanField(default=False)
177+
178+
cost_kit = MoneyField(
179+
max_digits=10, decimal_places=2, default_currency="USD", blank=True, null=True
180+
)
181+
cost_kit_link = models.URLField(blank=True, null=True)
182+
cost_kit_third_party = models.BooleanField(default=False)
183+
184+
cost_partial_kit = MoneyField(
185+
max_digits=10, decimal_places=2, default_currency="USD", blank=True, null=True
186+
)
187+
cost_partial_kit_link = models.URLField(blank=True, null=True)
188+
cost_partial_kit_third_party = models.BooleanField(default=False)
189+
158190
slug = models.SlugField(blank=True, unique=True)
159191
allow_comments = models.BooleanField("allow comments", default=True)
160192

backend/modules/serializers.py

+70
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
PcbVersion,
1717
ModuleBomListComponentForItemRating,
1818
)
19+
from djmoney.contrib.django_rest_framework.fields import MoneyField
1920

2021

2122
class ManufacturerSerializer(serializers.ModelSerializer):
@@ -236,3 +237,72 @@ class Meta:
236237
"suggested_component",
237238
"status",
238239
]
240+
241+
242+
class CostStatsSerializer(serializers.Serializer):
243+
low = serializers.DecimalField(max_digits=10, decimal_places=2)
244+
high = serializers.DecimalField(max_digits=10, decimal_places=2)
245+
average = serializers.DecimalField(max_digits=10, decimal_places=2)
246+
median = serializers.DecimalField(max_digits=10, decimal_places=2)
247+
248+
249+
class ModuleCostStatsSerializer(serializers.Serializer):
250+
module_id = serializers.UUIDField()
251+
module_name = serializers.CharField()
252+
overall = CostStatsSerializer()
253+
254+
cost_built = MoneyField(
255+
max_digits=10,
256+
decimal_places=2,
257+
default_currency="USD",
258+
required=False,
259+
allow_null=True,
260+
)
261+
cost_built_link = serializers.URLField(required=False, allow_null=True)
262+
cost_built_third_party = serializers.BooleanField(required=False, allow_null=True)
263+
264+
cost_pcb_only = MoneyField(
265+
max_digits=10,
266+
decimal_places=2,
267+
default_currency="USD",
268+
required=False,
269+
allow_null=True,
270+
)
271+
cost_pcb_only_link = serializers.URLField(required=False, allow_null=True)
272+
cost_pcb_only_third_party = serializers.BooleanField(
273+
required=False, allow_null=True
274+
)
275+
276+
cost_pcb_plus_front = MoneyField(
277+
max_digits=10,
278+
decimal_places=2,
279+
default_currency="USD",
280+
required=False,
281+
allow_null=True,
282+
)
283+
cost_pcb_plus_front_link = serializers.URLField(required=False, allow_null=True)
284+
cost_pcb_plus_front_third_party = serializers.BooleanField(
285+
required=False, allow_null=True
286+
)
287+
288+
cost_kit = MoneyField(
289+
max_digits=10,
290+
decimal_places=2,
291+
default_currency="USD",
292+
required=False,
293+
allow_null=True,
294+
)
295+
cost_kit_link = serializers.URLField(required=False, allow_null=True)
296+
cost_kit_third_party = serializers.BooleanField(required=False, allow_null=True)
297+
298+
cost_partial_kit = MoneyField(
299+
max_digits=10,
300+
decimal_places=2,
301+
default_currency="USD",
302+
required=False,
303+
allow_null=True,
304+
)
305+
cost_partial_kit_link = serializers.URLField(required=False, allow_null=True)
306+
cost_partial_kit_third_party = serializers.BooleanField(
307+
required=False, allow_null=True
308+
)

0 commit comments

Comments
 (0)