1
- from django .shortcuts import render
2
- from django .http import HttpRequest , Http404
3
- from .models import Event , EventRegistration
1
+ from django .shortcuts import render , redirect
2
+ from django .http import HttpRequest , HttpResponse
4
3
from django .contrib .auth .decorators import login_required
4
+ from django .contrib import messages
5
+ from .models import Event , EventRegistration
5
6
import logging
6
-
7
+ import json
8
+ from utils .payment .upi_gateway import create_order , check_order_status
9
+ from django .urls import reverse
10
+ from uuid import uuid4
11
+ from datetime import date
12
+ from utils .logging import critical_logger
7
13
8
14
log = logging .getLogger (__name__ )
9
15
@@ -23,10 +29,252 @@ def haps_item(request: HttpRequest, slug: str):
23
29
24
30
@login_required (login_url = "/users/register" )
25
31
def register_for_event (request : HttpRequest , slug : str ):
26
- event = Event .objects .get (slug = slug )
27
- registration = EventRegistration .objects .get_or_create (
28
- event = event , user = request .user
32
+ """Register for an event"""
33
+ try :
34
+ event = Event .objects .get (slug = slug )
35
+ except Event .DoesNotExist :
36
+ raise Http404 ("Event not found" )
37
+
38
+ if not event .accept_reg :
39
+ messages .error (request , "Registration is closed for this event." )
40
+ return redirect ('haps:event_item' , slug = slug )
41
+
42
+ if event .login_required and not request .user .is_authenticated :
43
+ messages .error (request , "Please login to register for this event." )
44
+ return redirect ('haps:event_item' , slug = slug )
45
+
46
+ if request .method == 'POST' :
47
+ # Collect form responses
48
+ form_responses = {}
49
+
50
+ # If not login required, collect basic info
51
+ if not event .login_required :
52
+ form_responses ['name' ] = request .POST .get ('name' )
53
+ form_responses ['whatsapp_number' ] = request .POST .get ('whatsapp_number' )
54
+
55
+ # Collect custom field responses
56
+ for field in event .form_fields .all ():
57
+ field_id = f'field_{ field .id } '
58
+ form_responses [field .field_label ] = request .POST .get (field_id )
59
+
60
+ # Create registration
61
+ registration = EventRegistration (
62
+ event = event ,
63
+ user = request .user if request .user .is_authenticated else None ,
64
+ form_responses = form_responses ,
65
+ amount = event .registration_fee if event .registration_fee else None
66
+ )
67
+ registration .save ()
68
+
69
+ # If payment required, redirect to payment page
70
+ if event .registration_fee :
71
+ return redirect ('haps:initiate_payment' , registration_id = registration .id )
72
+
73
+ messages .success (request , "Successfully registered for the event!" )
74
+ return render (request , "haps/register_success.html" ,
75
+ context = {"registration" : registration , "event" : event })
76
+
77
+ # If GET request with registration modal, return to event page
78
+ return redirect ('haps:event_item' , slug = slug )
79
+
80
+
81
+ def register_failure (request : HttpRequest , registration_id : int ):
82
+ """View for displaying registration failure page.
83
+ This is typically shown when payment fails."""
84
+
85
+ try :
86
+ registration = EventRegistration .objects .select_related ('event' , 'user' ).get (id = registration_id )
87
+ except EventRegistration .DoesNotExist :
88
+ raise Http404 ("Registration not found" )
89
+
90
+ # For testing, you can pass a remark through URL query parameter
91
+ remark = request .GET .get ('remark' , 'Payment was not completed' )
92
+
93
+ context = {
94
+ "registration" : registration ,
95
+ "event" : registration .event ,
96
+ "remark" : remark
97
+ }
98
+ return render (request , "haps/register_failure.html" , context = context )
99
+
100
+
101
+ def initiate_payment (request : HttpRequest , registration_id : int ):
102
+ """Initiate payment for event registration"""
103
+ try :
104
+ registration = EventRegistration .objects .select_related ('event' , 'user' ).get (id = registration_id )
105
+ except EventRegistration .DoesNotExist :
106
+ raise Http404 ("Registration not found" )
107
+
108
+ # Validate amount
109
+ if not registration .amount :
110
+ log .error (f"Registration { registration .id } has no amount set" )
111
+ messages .error (request , "Invalid registration amount" )
112
+ return redirect ('haps:register_failure' , registration_id = registration .id )
113
+
114
+ if registration .payment_status == 'success' :
115
+ messages .info (request , "Payment already completed" )
116
+ return redirect ('haps:register_success' , registration_id = registration .id )
117
+
118
+ # Generate unique transaction ID if not exists
119
+ if not registration .client_txn_id :
120
+ registration .client_txn_id = f"TempleWebPay-event-{ registration .id } -{ uuid4 ().hex [:8 ]} "
121
+ registration .save (update_fields = ['client_txn_id' ])
122
+
123
+ # Create callback URL
124
+ callback_url = request .build_absolute_uri (
125
+ reverse ('haps:payment_callback' )
126
+ )
127
+
128
+ # Get user details
129
+ name = None
130
+ if registration .user :
131
+ name = registration .user .get_full_name ()
132
+ if not name :
133
+ name = registration .user .username
134
+ else :
135
+ name = registration .form_responses .get ('name' )
136
+
137
+ if not name :
138
+ log .error (f"Registration { registration .id } has no customer name" )
139
+
140
+ # return redirect('haps:register_failure', registration_id=registration.id)
141
+ name = "Anonymous User"
142
+
143
+ mobile = registration .form_responses .get ('whatsapp_number' , '' )
144
+ email = registration .user .email if registration .user else ''
145
+
146
+ try :
147
+ # Create payment order
148
+ status , api_resp = create_order (
149
+ client_txn_id = registration .client_txn_id ,
150
+ redirect_url = callback_url ,
151
+ amount = registration .amount ,
152
+ product_info = f"Registration for { registration .event .name } " ,
153
+ customer_name = name ,
154
+ # customer_email=email,
155
+ # customer_mobile=mobile
156
+ )
157
+
158
+ if not status :
159
+ log .error (f"Payment gateway error for registration { registration .id } : { api_resp .text } " )
160
+ messages .error (request , "Payment gateway error. Please try again later." )
161
+ return redirect ('haps:register_failure' ,
162
+ registration_id = registration .id ,
163
+ remark = f"Payment gateway error: { api_resp .text } " )
164
+
165
+ # Save order ID and redirect to payment URL
166
+ registration .order_id = api_resp ["order_id" ]
167
+ registration .save (update_fields = ['order_id' ])
168
+
169
+ return redirect (api_resp ["payment_url" ])
170
+
171
+ except Exception as e :
172
+ log .error (f"Payment initiation failed for registration { registration .id } : { str (e )} " )
173
+ messages .error (request , "Failed to initiate payment. Please try again." )
174
+ return redirect ('haps:register_failure' , registration_id = registration .id )
175
+
176
+
177
+ def payment_callback (request : HttpRequest ):
178
+ """Handle payment gateway callback"""
179
+ log .debug ("Payment callback called" )
180
+ client_txn_id = request .GET .get ('client_txn_id' )
181
+ if not client_txn_id :
182
+ messages .error (request , "Invalid payment callback" )
183
+ return redirect ('haps:events' )
184
+
185
+ try :
186
+ registration = EventRegistration .objects .get (client_txn_id = client_txn_id )
187
+ except EventRegistration .DoesNotExist :
188
+ messages .error (request , "Registration not found" )
189
+ return redirect ('haps:events' )
190
+
191
+ # Prevent duplicate processing
192
+ if registration .payment_status == 'success' :
193
+ return redirect ('haps:register_success' , registration_id = registration .id )
194
+
195
+ # Check payment status
196
+ try :
197
+ status_data = check_order_status (client_txn_id )
198
+ if not status_data :
199
+ raise ValueError ("Empty response from payment gateway" )
200
+
201
+ # Store all payment diagnostic data
202
+ registration .payment_data = {
203
+ 'customer_vpa' : status_data .get ('customer_vpa' ),
204
+ 'upi_txn_id' : status_data .get ('upi_txn_id' ),
205
+ 'status' : status_data .get ('status' ),
206
+ 'remark' : status_data .get ('remark' ),
207
+ 'txnAt' : status_data .get ('txnAt' ),
208
+ 'merchant' : status_data .get ('Merchant' , {}),
209
+ 'udf1' : status_data .get ('udf1' ),
210
+ 'udf2' : status_data .get ('udf2' ),
211
+ 'udf3' : status_data .get ('udf3' ),
212
+ 'redirect_url' : status_data .get ('redirect_url' ),
213
+ 'createdAt' : status_data .get ('createdAt' )
214
+ }
215
+
216
+ # Update payment status
217
+ if status_data ['status' ] == 'success' :
218
+ registration .payment_status = 'success'
219
+ registration .payment_date_time = status_data .get ('txnAt' )
220
+ registration .save (update_fields = ['payment_status' , 'payment_date_time' , 'payment_data' ])
221
+ messages .success (request , "Payment successful!" )
222
+ return redirect ('haps:register_success' , registration_id = registration .id )
223
+ else :
224
+ registration .payment_status = 'failure'
225
+ registration .save (update_fields = ['payment_status' , 'payment_data' ])
226
+ return redirect ('haps:register_failure' ,
227
+ registration_id = registration .id ,
228
+ remark = status_data .get ('remark' , 'Payment failed' ))
229
+
230
+ except Exception as e :
231
+ log .error (f"Payment verification failed for registration { registration .id } : { str (e )} " )
232
+ registration .payment_data = {'error' : str (e )}
233
+ registration .payment_status = 'failure'
234
+ registration .save (update_fields = ['payment_status' , 'payment_data' ])
235
+ return redirect ('haps:register_failure' ,
236
+ registration_id = registration .id ,
237
+ remark = "Payment verification failed" )
238
+
239
+
240
+ def retry_payment (request : HttpRequest , registration_id : int ):
241
+ """Retry failed payment"""
242
+ try :
243
+ registration = EventRegistration .objects .get (id = registration_id )
244
+ except EventRegistration .DoesNotExist :
245
+ raise Http404 ("Registration not found" )
246
+
247
+ if registration .payment_status == 'success' :
248
+ messages .info (request , "Payment already completed" )
249
+ return redirect ('haps:register_success' , registration_id = registration .id )
250
+
251
+ # Log critical payment data before reset
252
+ critical_logger .critical (
253
+ f"Payment retry initiated for registration { registration .id } . "
254
+ f"Previous payment data: order_id={ registration .order_id } , "
255
+ f"client_txn_id={ registration .client_txn_id } , "
256
+ f"payment_status={ registration .payment_status } , "
257
+ f"payment_data={ registration .payment_data } "
29
258
)
30
259
31
- context = {"event" : event , "user" : request .user , "reg" : registration }
260
+ # Reset payment fields for retry
261
+ registration .order_id = None
262
+ registration .client_txn_id = None
263
+ registration .payment_status = 'pending'
264
+ registration .save (update_fields = ['order_id' , 'client_txn_id' , 'payment_status' ])
265
+
266
+ return redirect ('haps:initiate_payment' , registration_id = registration .id )
267
+
268
+
269
+ def register_success (request : HttpRequest , registration_id : int ):
270
+ """View for displaying registration success page."""
271
+ try :
272
+ registration = EventRegistration .objects .select_related ('event' , 'user' ).get (id = registration_id )
273
+ except EventRegistration .DoesNotExist :
274
+ raise Http404 ("Registration not found" )
275
+
276
+ context = {
277
+ "registration" : registration ,
278
+ "event" : registration .event ,
279
+ }
32
280
return render (request , "haps/register_success.html" , context = context )
0 commit comments