Skip to content

Commit 50302f4

Browse files
authored
Merge pull request #2 from aahnik/feat/event-registrations
Dynamic event registrations with custom form fields and payment options
2 parents 40fa042 + aa136db commit 50302f4

18 files changed

+1167
-349
lines changed

.vscode/settings.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"files.associations": {
3-
"*.html": "jinja-html"
4-
}
3+
"*.html": "django-html"
4+
},
5+
"python.languageServer": "None"
56
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 4.2.1 on 2024-12-27 19:11
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("donations", "0001_initial"),
9+
]
10+
11+
operations = [
12+
migrations.AlterField(
13+
model_name="donationtier",
14+
name="visible",
15+
field=models.BooleanField(
16+
default=False, verbose_name="Show on Donations Page ?"
17+
),
18+
),
19+
]

src/donations/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class DonationTier(models.Model):
2121
name = models.CharField(max_length=256)
2222
description = models.CharField(max_length=1024)
2323
amount = models.PositiveIntegerField(validators=[MaxValueValidator(10000)])
24-
visible = models.BooleanField(default=False)
24+
visible = models.BooleanField(verbose_name="Show on Donations Page ?", default=False)
2525

2626
def __str__(self):
2727
return self.name

src/donations/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from .forms import DonationForm
55
from .models import DonationConfig, DonationTier, DonationReceived
66
from temple_web.myconfig import PaymentGatewayConfig
7-
from .upi_gateway import create_order, check_order_status
7+
from utils.payment.upi_gateway import create_order, check_order_status
88
from uuid import uuid4
99
from datetime import date
1010
from utils.adirect import adirect
@@ -20,7 +20,7 @@
2020

2121
def donations(request):
2222
donation_config = DonationConfig.get_solo()
23-
donation_tiers = DonationTier.objects.all()
23+
donation_tiers = DonationTier.objects.filter(visible=True)
2424
context = {"donation_config": donation_config, "donation_tiers": donation_tiers}
2525
return render(request, "donations/donations.html", context=context)
2626

src/haps/admin.py

Lines changed: 141 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
from django.contrib import admin
2-
from .models import EventRegistration, Event
2+
from .models import EventRegistration, Event, EventFormField
3+
4+
5+
class EventFormFieldInline(admin.TabularInline):
6+
model = EventFormField
7+
extra = 1
8+
ordering = ['order']
39

410

511
@admin.register(Event)
@@ -11,24 +17,144 @@ class EventAdmin(admin.ModelAdmin):
1117
"start_time",
1218
"accept_reg",
1319
"show_on_home",
20+
"login_required",
21+
"registration_fee",
1422
"event_page",
1523
]
16-
list_filter = ["show_on_home", "accept_reg"]
17-
fields = [
18-
"name",
19-
"description",
20-
"cover_image",
21-
"venue",
22-
"start_time",
23-
"end_time",
24-
"accept_reg",
25-
"show_on_home",
26-
"content",
24+
list_filter = ["show_on_home", "accept_reg", "login_required"]
25+
fieldsets = [
26+
(None, {
27+
'fields': [
28+
"name",
29+
"description",
30+
"cover_image",
31+
"venue",
32+
"start_time",
33+
"end_time",
34+
]
35+
}),
36+
('Registration Settings', {
37+
'fields': [
38+
"accept_reg",
39+
"login_required",
40+
"registration_fee",
41+
],
42+
'description': 'Configure how users can register for this event'
43+
}),
44+
('Display Settings', {
45+
'fields': [
46+
"show_on_home",
47+
"content",
48+
]
49+
})
2750
]
51+
inlines = [EventFormFieldInline]
2852

2953

3054
@admin.register(EventRegistration)
3155
class EventRegistrationAdmin(admin.ModelAdmin):
32-
search_fields = ["event", "user"]
33-
list_display = ["event", "user_name", "user_whatsapp", "user", "user_profile_link"]
34-
list_filter = ["event__name"]
56+
search_fields = ["event__name", "user__email", "order_id", "client_txn_id"]
57+
list_display = [
58+
"registration_number",
59+
"event",
60+
"user_name",
61+
"user_whatsapp",
62+
"datetime",
63+
"amount",
64+
"payment_status",
65+
"order_id",
66+
"payment_date_time",
67+
]
68+
list_filter = ["event__name", "payment_status"]
69+
readonly_fields = [
70+
"datetime",
71+
"form_responses",
72+
"payment_status",
73+
"order_id",
74+
"client_txn_id",
75+
"payment_date_time",
76+
"payment_data",
77+
"get_payment_details"
78+
]
79+
80+
fieldsets = [
81+
(None, {
82+
'fields': [
83+
"event",
84+
"user",
85+
"datetime",
86+
"amount",
87+
"form_responses",
88+
]
89+
}),
90+
('Payment Information', {
91+
'fields': [
92+
"payment_status",
93+
"order_id",
94+
"client_txn_id",
95+
"payment_date_time",
96+
],
97+
'classes': ['collapse']
98+
}),
99+
('Payment Diagnostic Data', {
100+
'fields': [
101+
"get_payment_details",
102+
],
103+
'classes': ['collapse'],
104+
'description': 'Detailed payment transaction data from UPI gateway'
105+
})
106+
]
107+
108+
def has_change_permission(self, request, obj=None):
109+
return False
110+
111+
def has_delete_permission(self, request, obj=None):
112+
return False
113+
114+
def has_add_permission(self, request):
115+
return False
116+
117+
def get_queryset(self, request):
118+
return super().get_queryset(request).select_related('event', 'user')
119+
120+
def registration_number(self, obj):
121+
return obj.registration_number
122+
registration_number.short_description = "Registration No."
123+
124+
def get_payment_details(self, obj):
125+
if not obj.payment_data:
126+
return "No payment data available"
127+
128+
# Format payment data for display
129+
details = []
130+
if obj.payment_data.get('customer_vpa'):
131+
details.append(f"Customer UPI: {obj.payment_data['customer_vpa']}")
132+
if obj.payment_data.get('upi_txn_id'):
133+
details.append(f"UPI Transaction ID: {obj.payment_data['upi_txn_id']}")
134+
if obj.payment_data.get('status'):
135+
details.append(f"Status: {obj.payment_data['status']}")
136+
if obj.payment_data.get('remark'):
137+
details.append(f"Remark: {obj.payment_data['remark']}")
138+
if obj.payment_data.get('txnAt'):
139+
details.append(f"Transaction Time: {obj.payment_data['txnAt']}")
140+
141+
# Merchant details
142+
merchant = obj.payment_data.get('merchant', {})
143+
if merchant:
144+
details.append("Merchant Details:")
145+
if merchant.get('name'):
146+
details.append(f" - Name: {merchant['name']}")
147+
if merchant.get('upi_id'):
148+
details.append(f" - UPI ID: {merchant['upi_id']}")
149+
150+
# User defined fields
151+
for i in range(1, 4):
152+
udf = obj.payment_data.get(f'udf{i}')
153+
if udf:
154+
details.append(f"UDF{i}: {udf}")
155+
156+
if obj.payment_data.get('createdAt'):
157+
details.append(f"Created At: {obj.payment_data['createdAt']}")
158+
159+
return "\n".join(details)
160+
get_payment_details.short_description = "Payment Details"
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Generated by Django 4.2.1 on 2024-12-27 19:11
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
dependencies = [
10+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
11+
("haps", "0004_event_content"),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name="event",
17+
name="login_required",
18+
field=models.BooleanField(
19+
default=True, verbose_name="Login required for registration?"
20+
),
21+
),
22+
migrations.AddField(
23+
model_name="event",
24+
name="registration_fee",
25+
field=models.PositiveIntegerField(
26+
blank=True, help_text="Leave blank for free registration", null=True
27+
),
28+
),
29+
migrations.AddField(
30+
model_name="eventregistration",
31+
name="amount",
32+
field=models.PositiveIntegerField(blank=True, null=True),
33+
),
34+
migrations.AddField(
35+
model_name="eventregistration",
36+
name="form_responses",
37+
field=models.JSONField(default=dict),
38+
),
39+
migrations.AddField(
40+
model_name="eventregistration",
41+
name="order_id",
42+
field=models.CharField(blank=True, max_length=100, null=True),
43+
),
44+
migrations.AddField(
45+
model_name="eventregistration",
46+
name="payment_status",
47+
field=models.CharField(
48+
choices=[
49+
("pending", "Pending"),
50+
("success", "Success"),
51+
("failure", "Failure"),
52+
],
53+
default="pending",
54+
max_length=10,
55+
),
56+
),
57+
migrations.AlterField(
58+
model_name="eventregistration",
59+
name="user",
60+
field=models.ForeignKey(
61+
blank=True,
62+
null=True,
63+
on_delete=django.db.models.deletion.CASCADE,
64+
to=settings.AUTH_USER_MODEL,
65+
),
66+
),
67+
migrations.CreateModel(
68+
name="EventFormField",
69+
fields=[
70+
(
71+
"id",
72+
models.BigAutoField(
73+
auto_created=True,
74+
primary_key=True,
75+
serialize=False,
76+
verbose_name="ID",
77+
),
78+
),
79+
("field_label", models.CharField(max_length=100)),
80+
(
81+
"field_type",
82+
models.CharField(
83+
choices=[
84+
("text", "Text Input"),
85+
("number", "Number Input"),
86+
("email", "Email Input"),
87+
("textarea", "Text Area"),
88+
],
89+
max_length=20,
90+
),
91+
),
92+
("required", models.BooleanField(default=True)),
93+
("order", models.PositiveIntegerField(default=0)),
94+
("help_text", models.CharField(blank=True, max_length=200)),
95+
(
96+
"event",
97+
models.ForeignKey(
98+
on_delete=django.db.models.deletion.CASCADE,
99+
related_name="form_fields",
100+
to="haps.event",
101+
),
102+
),
103+
],
104+
options={
105+
"ordering": ["order"],
106+
"unique_together": {("event", "field_label")},
107+
},
108+
),
109+
]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Generated by Django 4.2.1 on 2024-12-29 19:34
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("haps", "0005_event_login_required_event_registration_fee_and_more"),
9+
]
10+
11+
operations = [
12+
migrations.AddField(
13+
model_name="eventregistration",
14+
name="client_txn_id",
15+
field=models.CharField(
16+
blank=True, db_index=True, max_length=128, null=True, unique=True
17+
),
18+
),
19+
migrations.AddField(
20+
model_name="eventregistration",
21+
name="payment_data",
22+
field=models.JSONField(
23+
default=dict,
24+
help_text="\n Stores payment-related data from UPI gateway including:\n - customer_vpa: Customer's UPI ID\n - upi_txn_id: UPI transaction ID\n - status: Detailed payment status\n - remark: Payment remarks/failure reason\n - txnAt: Transaction timestamp\n - merchant: Merchant details (name, upi_id)\n - udf1, udf2, udf3: User defined fields\n - redirect_url: Payment redirect URL\n - createdAt: Order creation time\n ",
25+
),
26+
),
27+
migrations.AddField(
28+
model_name="eventregistration",
29+
name="payment_date_time",
30+
field=models.DateTimeField(blank=True, null=True),
31+
),
32+
]

0 commit comments

Comments
 (0)