diff --git a/app/signals.py b/app/signals.py index 8142477..1b588e4 100644 --- a/app/signals.py +++ b/app/signals.py @@ -103,59 +103,58 @@ def create_course_tracking(sender, instance, created, **kwargs): Signal handler to create CourseTracking when a new student is created or when a course is assigned to an existing student """ - + # Skip if signal is triggered due to our own update + if getattr(instance, '_skip_course_tracking_signal', False): + return + # Check if student has a course assigned - if instance.course: - try: - # Check if course tracking already exists - existing_tracking = CourseTracking.objects.filter( - student=instance, course=instance.course - ).first() + if not instance.course: + return + + # Check if course tracking already exists (outside of any transaction) + existing_tracking = CourseTracking.objects.filter( + student=instance, course=instance.course + ).first() + + if existing_tracking: + return # Skip if already exists + + try: + # Calculate dates based on course duration + start_date = instance.joining_date or date.today() - if existing_tracking: - print(f"Course tracking already exists for {instance.name}") - return - - # Calculate dates based on course duration - start_date = instance.joining_date or date.today() - - # Calculate expected end date based on course duration type - if instance.course.duration_type == "Year": - # For year-based courses, each year is 365 days - years = instance.course.duration - duration_days = years * 365 - else: # Semester based - # For semester-based courses: - # - Each year has 2 semesters - # - Total years is the same as course duration - years = instance.course.duration - duration_days = years * 365 # Use full years for total duration - - expected_end_date = start_date + timedelta(days=duration_days) - - # Create course tracking without nested transaction - course_tracking = CourseTracking.objects.create( - student=instance, - course=instance.course, - start_date=start_date, - expected_end_date=expected_end_date, - current_period=instance.current_period, - period_start_date=start_date, - period_end_date=start_date - + timedelta(days=180), # 6 months for first semester - ) - - # The model's save() method will handle the percentage calculation automatically - # No need to manually call update_completion_percentage() - - except Exception as e: - print( - f"Error creating course tracking for student {instance.name}: {str(e)}" - ) - # Log the error but don't prevent student creation - # You might want to add proper logging here instead of print statements - else: - print(f"No course assigned to student {instance.name}") + # Calculate expected end date based on course duration type + years = instance.course.duration + duration_days = years * 365 # Use full years for total duration + expected_end_date = start_date + timedelta(days=duration_days) + + # Set period dates based on duration type + period_start_date = start_date + if instance.course.duration_type == "Semester": + period_end_date = start_date + timedelta(days=180) # 6 months + else: + period_end_date = start_date + timedelta(days=365) # 1 year + + # Create a new CourseTracking instance + CourseTracking.objects.create( + student=instance, + course=instance.course, + start_date=start_date, + expected_end_date=expected_end_date, + current_period=instance.current_period, + period_start_date=period_start_date, + period_end_date=period_end_date, + progress_status="In Progress" + ) + + # Log success but don't trigger any more signals + logger.info(f"Created course tracking for student: {instance.name}") + + except Exception as e: + # Log the error properly + error_msg = f"Error creating course tracking for student {instance.name}: {str(e)}" + logger.error(error_msg) + # Do not raise the exception - let the student save proceed @receiver(post_save, sender=Student)