From 34ef272e25da3d98311399205e4371f15724154c Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 27 Feb 2026 13:32:25 +0000 Subject: [PATCH] Autosave: 20260227-133224 --- core/__pycache__/models.cpython-311.pyc | Bin 16032 -> 16109 bytes core/__pycache__/views.cpython-311.pyc | Bin 40752 -> 42575 bytes core/management/commands/cleanup_requests.py | 21 ++++- .../0021_bloodrequest_accepted_at.py | 18 ++++ ...1_bloodrequest_accepted_at.cpython-311.pyc | Bin 0 -> 828 bytes core/models.py | 1 + core/templates/core/profile.html | 88 ++++++++++++++++++ core/templates/core/public_profile.html | 41 ++++++++ core/views.py | 37 +++++++- 9 files changed, 199 insertions(+), 7 deletions(-) create mode 100644 core/migrations/0021_bloodrequest_accepted_at.py create mode 100644 core/migrations/__pycache__/0021_bloodrequest_accepted_at.cpython-311.pyc diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 950f75fdd142eca7561ea330b98b748258ec60a0..cd00605f2bf4d5124458ee0f59c8b42b315a9d4d 100644 GIT binary patch delta 519 zcmZ2b`?i*EIWI340}wFJSeVJ7zL76qo>6aeo%}~erxfNjV#}Bq7*+!@1VqU&F{H9& zNyGR+72?YnfhvF)szNqJqJ<$!E=4k!K~rjSui_&{^U2vt6Bzp^|54Irl%K4jyq)(J zcVcpKYC%bAN_=9;#O+c%PK*XfYIhu8hjGH#U*80cDxOVa@op{D0lf87qxDJ4nfQV(2 zSLyCz1+kJR3W{#7)0@S}xNWkeK_=sw$;}1^Tql7tMId6sAiCdLbs zlZ~G;o|^1wa)|pbNL?R@I6L{FvIN(85EDe~+-zaW&&Ud5f^A4NTfoS8doq*7QN|mS zPgul?z68qL;?2k}F32oN%!$uS%uOwNFxkqop8qMx3=nY^h>L$rUMV6w`Kjd-#;21{ zS#2=}`|rZ`An5wGn7e5r~+$d8cL_Bjd)+7TW(98P`lU*Nta9JbAiq7}tJ~5)iR; z@^{@`tRPnML_yKbr}btrGH#umW{}Bvdh!JW1FjPwg&<=6WG=&QRuBuMaPfLWCdTuV zHyA%_fCmJ(d&Kui#^V{@x1KO-xM3ASOK*#bt!Ta*1Qjxt`K zENU4m`T{6(i#H>`xFEA6F(*DRF*mj7{^WMcdafrRGeE?d%>q_zjEqkvi(79I1^W){ vez4oX7Co8#z*?5^%jSR9I~a9D8Ero>U=kC|rr3N0iGM*z>TP~x%gqP??-z(; diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 5cd178a45e22a4a960edf717002880c22b857fcb..8462839b308896b27f21e240bf2403d7652bfcc1 100644 GIT binary patch delta 5160 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 Lh57LAbK?I33Vl2f delta 4040 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 V0tSw)jxw?`M)K1b2cI2t{U1lM--7@E 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 0000000000000000000000000000000000000000..f83dd3d4c42709cbdc70b9198763feb55372134a GIT binary patch literal 828 zcmZuvy>HV%6u+|_$2N&XEuUJXA~(z<|3jFoAVmN6|NjM4kRRi z?`#~Z{}RG|G~Pr?TB$!-a6w{<7pG9Jbh~%D?6vE8egr9CjI(4r&f~H*2;!Khuvg0bvstM` zU#n#4iaL5+8AQMK!5C|+ljWO}rRx*3v)37$ov-~L%8}XoY4*luuWBl~aZJ#h2vfej5X!eZp +
+ 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)