Skip to content

Commit

Permalink
Merge pull request #2 from aahnik/feat/event-registrations
Browse files Browse the repository at this point in the history
Dynamic event registrations with custom form fields and payment options
  • Loading branch information
aahnik authored Dec 29, 2024
2 parents 40fa042 + aa136db commit 50302f4
Show file tree
Hide file tree
Showing 18 changed files with 1,167 additions and 349 deletions.
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"files.associations": {
"*.html": "jinja-html"
}
"*.html": "django-html"
},
"python.languageServer": "None"
}
19 changes: 19 additions & 0 deletions src/donations/migrations/0002_alter_donationtier_visible.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.1 on 2024-12-27 19:11

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("donations", "0001_initial"),
]

operations = [
migrations.AlterField(
model_name="donationtier",
name="visible",
field=models.BooleanField(
default=False, verbose_name="Show on Donations Page ?"
),
),
]
2 changes: 1 addition & 1 deletion src/donations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class DonationTier(models.Model):
name = models.CharField(max_length=256)
description = models.CharField(max_length=1024)
amount = models.PositiveIntegerField(validators=[MaxValueValidator(10000)])
visible = models.BooleanField(default=False)
visible = models.BooleanField(verbose_name="Show on Donations Page ?", default=False)

def __str__(self):
return self.name
Expand Down
4 changes: 2 additions & 2 deletions src/donations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .forms import DonationForm
from .models import DonationConfig, DonationTier, DonationReceived
from temple_web.myconfig import PaymentGatewayConfig
from .upi_gateway import create_order, check_order_status
from utils.payment.upi_gateway import create_order, check_order_status
from uuid import uuid4
from datetime import date
from utils.adirect import adirect
Expand All @@ -20,7 +20,7 @@

def donations(request):
donation_config = DonationConfig.get_solo()
donation_tiers = DonationTier.objects.all()
donation_tiers = DonationTier.objects.filter(visible=True)
context = {"donation_config": donation_config, "donation_tiers": donation_tiers}
return render(request, "donations/donations.html", context=context)

Expand Down
156 changes: 141 additions & 15 deletions src/haps/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
from django.contrib import admin
from .models import EventRegistration, Event
from .models import EventRegistration, Event, EventFormField


class EventFormFieldInline(admin.TabularInline):
model = EventFormField
extra = 1
ordering = ['order']


@admin.register(Event)
Expand All @@ -11,24 +17,144 @@ class EventAdmin(admin.ModelAdmin):
"start_time",
"accept_reg",
"show_on_home",
"login_required",
"registration_fee",
"event_page",
]
list_filter = ["show_on_home", "accept_reg"]
fields = [
"name",
"description",
"cover_image",
"venue",
"start_time",
"end_time",
"accept_reg",
"show_on_home",
"content",
list_filter = ["show_on_home", "accept_reg", "login_required"]
fieldsets = [
(None, {
'fields': [
"name",
"description",
"cover_image",
"venue",
"start_time",
"end_time",
]
}),
('Registration Settings', {
'fields': [
"accept_reg",
"login_required",
"registration_fee",
],
'description': 'Configure how users can register for this event'
}),
('Display Settings', {
'fields': [
"show_on_home",
"content",
]
})
]
inlines = [EventFormFieldInline]


@admin.register(EventRegistration)
class EventRegistrationAdmin(admin.ModelAdmin):
search_fields = ["event", "user"]
list_display = ["event", "user_name", "user_whatsapp", "user", "user_profile_link"]
list_filter = ["event__name"]
search_fields = ["event__name", "user__email", "order_id", "client_txn_id"]
list_display = [
"registration_number",
"event",
"user_name",
"user_whatsapp",
"datetime",
"amount",
"payment_status",
"order_id",
"payment_date_time",
]
list_filter = ["event__name", "payment_status"]
readonly_fields = [
"datetime",
"form_responses",
"payment_status",
"order_id",
"client_txn_id",
"payment_date_time",
"payment_data",
"get_payment_details"
]

fieldsets = [
(None, {
'fields': [
"event",
"user",
"datetime",
"amount",
"form_responses",
]
}),
('Payment Information', {
'fields': [
"payment_status",
"order_id",
"client_txn_id",
"payment_date_time",
],
'classes': ['collapse']
}),
('Payment Diagnostic Data', {
'fields': [
"get_payment_details",
],
'classes': ['collapse'],
'description': 'Detailed payment transaction data from UPI gateway'
})
]

def has_change_permission(self, request, obj=None):
return False

def has_delete_permission(self, request, obj=None):
return False

def has_add_permission(self, request):
return False

def get_queryset(self, request):
return super().get_queryset(request).select_related('event', 'user')

def registration_number(self, obj):
return obj.registration_number
registration_number.short_description = "Registration No."

def get_payment_details(self, obj):
if not obj.payment_data:
return "No payment data available"

# Format payment data for display
details = []
if obj.payment_data.get('customer_vpa'):
details.append(f"Customer UPI: {obj.payment_data['customer_vpa']}")
if obj.payment_data.get('upi_txn_id'):
details.append(f"UPI Transaction ID: {obj.payment_data['upi_txn_id']}")
if obj.payment_data.get('status'):
details.append(f"Status: {obj.payment_data['status']}")
if obj.payment_data.get('remark'):
details.append(f"Remark: {obj.payment_data['remark']}")
if obj.payment_data.get('txnAt'):
details.append(f"Transaction Time: {obj.payment_data['txnAt']}")

# Merchant details
merchant = obj.payment_data.get('merchant', {})
if merchant:
details.append("Merchant Details:")
if merchant.get('name'):
details.append(f" - Name: {merchant['name']}")
if merchant.get('upi_id'):
details.append(f" - UPI ID: {merchant['upi_id']}")

# User defined fields
for i in range(1, 4):
udf = obj.payment_data.get(f'udf{i}')
if udf:
details.append(f"UDF{i}: {udf}")

if obj.payment_data.get('createdAt'):
details.append(f"Created At: {obj.payment_data['createdAt']}")

return "\n".join(details)
get_payment_details.short_description = "Payment Details"
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Generated by Django 4.2.1 on 2024-12-27 19:11

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("haps", "0004_event_content"),
]

operations = [
migrations.AddField(
model_name="event",
name="login_required",
field=models.BooleanField(
default=True, verbose_name="Login required for registration?"
),
),
migrations.AddField(
model_name="event",
name="registration_fee",
field=models.PositiveIntegerField(
blank=True, help_text="Leave blank for free registration", null=True
),
),
migrations.AddField(
model_name="eventregistration",
name="amount",
field=models.PositiveIntegerField(blank=True, null=True),
),
migrations.AddField(
model_name="eventregistration",
name="form_responses",
field=models.JSONField(default=dict),
),
migrations.AddField(
model_name="eventregistration",
name="order_id",
field=models.CharField(blank=True, max_length=100, null=True),
),
migrations.AddField(
model_name="eventregistration",
name="payment_status",
field=models.CharField(
choices=[
("pending", "Pending"),
("success", "Success"),
("failure", "Failure"),
],
default="pending",
max_length=10,
),
),
migrations.AlterField(
model_name="eventregistration",
name="user",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
migrations.CreateModel(
name="EventFormField",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("field_label", models.CharField(max_length=100)),
(
"field_type",
models.CharField(
choices=[
("text", "Text Input"),
("number", "Number Input"),
("email", "Email Input"),
("textarea", "Text Area"),
],
max_length=20,
),
),
("required", models.BooleanField(default=True)),
("order", models.PositiveIntegerField(default=0)),
("help_text", models.CharField(blank=True, max_length=200)),
(
"event",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="form_fields",
to="haps.event",
),
),
],
options={
"ordering": ["order"],
"unique_together": {("event", "field_label")},
},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 4.2.1 on 2024-12-29 19:34

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("haps", "0005_event_login_required_event_registration_fee_and_more"),
]

operations = [
migrations.AddField(
model_name="eventregistration",
name="client_txn_id",
field=models.CharField(
blank=True, db_index=True, max_length=128, null=True, unique=True
),
),
migrations.AddField(
model_name="eventregistration",
name="payment_data",
field=models.JSONField(
default=dict,
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 ",
),
),
migrations.AddField(
model_name="eventregistration",
name="payment_date_time",
field=models.DateTimeField(blank=True, null=True),
),
]
Loading

0 comments on commit 50302f4

Please sign in to comment.