diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 950f75f..cd00605 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 5cd178a..8462839 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/management/commands/cleanup_requests.py b/core/management/commands/cleanup_requests.py index b307ced..3221ec5 100644 --- a/core/management/commands/cleanup_requests.py +++ b/core/management/commands/cleanup_requests.py @@ -1,5 +1,6 @@ from django.core.management.base import BaseCommand from django.utils import timezone +from django.db.models import Q from core.models import BloodRequest from datetime import timedelta @@ -31,15 +32,29 @@ class Command(BaseCommand): self.stdout.write(self.style.SUCCESS(f'Deleted {count} {urgency} requests older than {days} days.')) deleted_count += count - # 2. Delete non-Active requests older than 7 days + # 2. Delete non-Active and non-Accepted requests older than 7 days cutoff_inactive = now - timedelta(days=7) - inactive_requests = BloodRequest.objects.exclude(status='Active').filter(created_at__lt=cutoff_inactive) + inactive_requests = BloodRequest.objects.exclude( + Q(status='Active') | Q(status='Accepted') + ).filter(created_at__lt=cutoff_inactive) count_inactive = inactive_requests.count() if count_inactive > 0: inactive_requests.delete() - self.stdout.write(self.style.SUCCESS(f'Deleted {count_inactive} non-active requests older than 7 days.')) + self.stdout.write(self.style.SUCCESS(f'Deleted {count_inactive} non-active/non-accepted requests older than 7 days.')) deleted_count += count_inactive + # 3. For Accepted requests, we keep them for 30 days after acceptance for history + cutoff_accepted = now - timedelta(days=30) + old_accepted = BloodRequest.objects.filter( + status='Accepted', + accepted_at__lt=cutoff_accepted + ) + count_accepted = old_accepted.count() + if count_accepted > 0: + old_accepted.delete() + self.stdout.write(self.style.SUCCESS(f'Deleted {count_accepted} accepted requests older than 30 days.')) + deleted_count += count_accepted + if deleted_count == 0: self.stdout.write(self.style.SUCCESS('No old requests to delete.')) else: diff --git a/core/migrations/0021_bloodrequest_accepted_at.py b/core/migrations/0021_bloodrequest_accepted_at.py new file mode 100644 index 0000000..9d522e4 --- /dev/null +++ b/core/migrations/0021_bloodrequest_accepted_at.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-02-27 13:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0020_vaccinerecord_photo'), + ] + + operations = [ + migrations.AddField( + model_name='bloodrequest', + name='accepted_at', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/core/migrations/__pycache__/0021_bloodrequest_accepted_at.cpython-311.pyc b/core/migrations/__pycache__/0021_bloodrequest_accepted_at.cpython-311.pyc new file mode 100644 index 0000000..f83dd3d Binary files /dev/null and b/core/migrations/__pycache__/0021_bloodrequest_accepted_at.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 2f76e18..d03c633 100644 --- a/core/models.py +++ b/core/models.py @@ -137,6 +137,7 @@ class BloodRequest(models.Model): image = models.ImageField(upload_to='blood_requests/', null=True, blank=True) required_date = models.DateField(default=timezone.now) status = models.CharField(max_length=20, default='Active') + accepted_at = models.DateTimeField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): diff --git a/core/templates/core/profile.html b/core/templates/core/profile.html index 5888c72..1ee9c72 100644 --- a/core/templates/core/profile.html +++ b/core/templates/core/profile.html @@ -80,6 +80,94 @@ +
+ Transaction & Operation History +
+ +
+
Donor Record (People You've Helped)
+
+
+
+
{{ donations_made.count }}
+
Total Volunteers
+
+
+
{{ completed_donations_count }}
+
Successful Donations
+
+
+
+ + {% if donations_made %} +
+ {% for donation in donations_made %} +
+
+
+ Helped {{ donation.request.patient_name }} +
{{ donation.request.hospital }} | {{ donation.date|date:"M d, Y" }}
+
+
+ {% if donation.is_completed %} + Completed + {% else %} + Pending + {% endif %} +
+
+
+ {% endfor %} +
+ {% else %} +
+

You haven't volunteered for any requests yet.

+
+ {% endif %} +
+ +
+
Request History (Who Helped You)
+ {% if requests_made %} +
+ {% for br in requests_made %} +
+
+
+ {{ br.blood_group }} for {{ br.patient_name }} +
{{ br.created_at|date:"M d, Y" }} | Status: {{ br.status }}
+ +
+

Volunteers:

+ {% with br.donations.all as donations %} + {% if donations %} +
+ {% for d in donations %} + + {{ d.donor_user.username }} + + {% endfor %} +
+ {% else %} + No volunteers yet + {% endif %} + {% endwith %} +
+
+ + {{ br.status }} + +
+
+ {% endfor %} +
+ {% else %} +
+

You haven't made any blood requests yet.

+
+ {% endif %} +
+
Danger Zone diff --git a/core/templates/core/public_profile.html b/core/templates/core/public_profile.html index c04758e..7087ed5 100644 --- a/core/templates/core/public_profile.html +++ b/core/templates/core/public_profile.html @@ -55,6 +55,47 @@
+
+
Impact & Reliability
+
+
+
+
{{ donations_made.count }}
+
Volunteered
+
+
+
+
+
{{ completed_donations_count }}
+
Successful
+
+
+
+
+ + {% if donations_made %} +
+
Recent Donations
+
+ {% for donation in donations_made|slice:":5" %} +
+
+
+
Donated to {{ donation.request.patient_name }}
+
{{ donation.request.hospital }} | {{ donation.date|date:"M d, Y" }}
+
+ {% if donation.is_completed %} + Verified + {% else %} + Pending + {% endif %} +
+
+ {% endfor %} +
+
+ {% endif %} +
{% if user.is_authenticated and user != profile_user %} diff --git a/core/views.py b/core/views.py index 0f7cba8..a5a995e 100644 --- a/core/views.py +++ b/core/views.py @@ -140,9 +140,16 @@ def profile(request): u_form = UserUpdateForm(instance=request.user) p_form = ProfileUpdateForm(instance=profile) + # Fetch History + requests_made = BloodRequest.objects.filter(user=request.user).order_by('-created_at') + donations_made = DonationEvent.objects.filter(donor_user=request.user).select_related('request').order_by('-date') + context = { 'u_form': u_form, - 'p_form': p_form + 'p_form': p_form, + 'requests_made': requests_made, + 'donations_made': donations_made, + 'completed_donations_count': donations_made.filter(is_completed=True).count() } return render(request, 'core/profile.html', context) @@ -263,7 +270,12 @@ def home(request): else: donor_list_data.sort(key=lambda x: (-x.is_available, x.name)) - blood_requests = BloodRequest.objects.filter(status='Active').order_by('-urgency', '-created_at') + three_days_ago = timezone.now() - timezone.timedelta(days=3) + blood_requests = BloodRequest.objects.filter( + Q(status='Active') | + Q(status='Accepted', accepted_at__gte=three_days_ago) + ).order_by('-urgency', '-created_at') + blood_banks = BloodBank.objects.all() # Stats for Dashboard @@ -275,7 +287,9 @@ def home(request): stats = { "total_donors": Donor.objects.count() + demo_donors, - "active_requests": BloodRequest.objects.filter(status='Active').count(), + "active_requests": BloodRequest.objects.filter( + Q(status='Active') | Q(status='Accepted', accepted_at__gte=three_days_ago) + ).count(), "total_stock": sum([ bb.stock_a_plus + bb.stock_a_minus + bb.stock_b_plus + bb.stock_b_minus + bb.stock_o_plus + bb.stock_o_minus + bb.stock_ab_plus + bb.stock_ab_minus @@ -412,7 +426,11 @@ def vaccination_info(request): def live_map(request): """View to display live alerts/requests on a map.""" - active_requests = BloodRequest.objects.filter(status='Active').order_by('-created_at') + three_days_ago = timezone.now() - timezone.timedelta(days=3) + active_requests = BloodRequest.objects.filter( + Q(status='Active') | + Q(status='Accepted', accepted_at__gte=three_days_ago) + ).order_by('-created_at') # Also include blood banks and donors optionally if we want a full map # But focusing on alerts as requested. @@ -524,6 +542,11 @@ def volunteer_for_request(request, request_id): request=blood_request, donor_user=request.user ) + # Update request status and timestamp + blood_request.status = 'Accepted' + blood_request.accepted_at = timezone.now() + blood_request.save() + messages.success(request, "Thank you for volunteering! The requester has been notified.") # Notify the requester @@ -618,10 +641,16 @@ def public_profile(request, username): profile = user.profile donor_profile = getattr(user, 'donor_profile', None) + # Fetch History + donations_made = DonationEvent.objects.filter(donor_user=user).select_related('request').order_by('-date') + completed_donations_count = donations_made.filter(is_completed=True).count() + context = { 'profile_user': user, 'profile': profile, 'donor': donor_profile, + 'donations_made': donations_made, + 'completed_donations_count': completed_donations_count } return render(request, 'core/public_profile.html', context)