- {% if complaint.metadata.ai_analysis.extracted_staff_names %}
-
-
{% trans "AI Extracted Names" %}:
-
- {% for name in complaint.metadata.ai_analysis.extracted_staff_names %}
-
{{ name }}
+
+
+
+
+ {% if complaint.metadata.ai_analysis.extracted_staff_names %}
+
+
+
+ {% trans "Extracted from Complaint" %}
+
+
+ {% for name in complaint.metadata.ai_analysis.extracted_staff_names %}
+ {{ name }}
+ {% endfor %}
+
+ {% if complaint.metadata.ai_analysis.primary_staff_name %}
+
+
+ {% trans "Primary" %}: "{{ complaint.metadata.ai_analysis.primary_staff_name }}"
+
+ {% endif %}
+
+ {% endif %}
+
+
+
+ {% for staff_match in complaint.metadata.ai_analysis.staff_matches|slice:":5" %}
+
{% endfor %}
-
- {% if complaint.metadata.ai_analysis.primary_staff_name %}
- {% trans "Primary" %}: "{{ complaint.metadata.ai_analysis.primary_staff_name }}"
- {% endif %}
-
-
- {% endif %}
-
- {% for staff_match in complaint.metadata.ai_analysis.staff_matches|slice:":3" %}
-
-
-
-
+ {% endif %}
@@ -948,6 +991,29 @@
{% trans "Request Explanation" %}
+
+ {% if complaint.complaint_type == 'appreciation' and not complaint.metadata.appreciation_id %}
+
+
+
+
+
+
+
+ {% elif complaint.metadata.appreciation_id %}
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+ {% trans "Create an Appreciation record from this positive feedback. The appreciation will be linked to this complaint." %}
+
+
+
+
+
+
+
+
+ {% trans "Default: Assigned staff member if available" %}
+
+
+
+
+
+
+
+
+ {% trans "Default: Patient Feedback Appreciation" %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{% endblock %}
diff --git a/templates/organizations/staff_detail.html b/templates/organizations/staff_detail.html
index 9d3086e..39cde36 100644
--- a/templates/organizations/staff_detail.html
+++ b/templates/organizations/staff_detail.html
@@ -398,7 +398,7 @@ function confirmCreateUser() {
btn.disabled = true;
btn.innerHTML = '
Creating...';
- fetch(`/api/organizations/staff/{{ staff.id }}/create_user_account/`, {
+ fetch(`/organizations/api/staff/{{ staff.id }}/create_user_account/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -430,7 +430,7 @@ function confirmSendInvitation() {
btn.disabled = true;
btn.innerHTML = '
Sending...';
- fetch(`/api/organizations/staff/{{ staff.id }}/send_invitation/`, {
+ fetch(`/organizations/api/staff/{{ staff.id }}/send_invitation/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -462,7 +462,7 @@ function confirmUnlinkUser() {
btn.disabled = true;
btn.innerHTML = '
Unlinking...';
- fetch(`/api/organizations/staff/{{ staff.id }}/unlink_user/`, {
+ fetch(`/organizations/api/staff/{{ staff.id }}/unlink_user/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
diff --git a/test_appreciation_conversion.py b/test_appreciation_conversion.py
new file mode 100644
index 0000000..29afd54
--- /dev/null
+++ b/test_appreciation_conversion.py
@@ -0,0 +1,460 @@
+#!/usr/bin/env python
+"""
+Test script for Complaint to Appreciation Conversion Feature
+
+This script tests the conversion of appreciation-type complaints to Appreciation records.
+"""
+
+import os
+import sys
+import django
+
+# Setup Django
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'PX360.settings')
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+django.setup()
+
+from django.contrib.auth import get_user_model
+from apps.complaints.models import Complaint, ComplaintUpdate
+from apps.organizations.models import Hospital, Department, Staff
+from app.models import Patient
+from apps.appreciation.models import Appreciation, AppreciationCategory
+from apps.accounts.models import User
+from django.utils import timezone
+from django.urls import reverse
+from django.test import TestCase, Client
+from rest_framework.test import APIClient
+import json
+
+User = get_user_model()
+
+
+def print_section(title):
+ """Print a formatted section header"""
+ print(f"\n{'='*60}")
+ print(f" {title}")
+ print(f"{'='*60}\n")
+
+
+def print_success(message):
+ """Print success message"""
+ print(f"✓ {message}")
+
+
+def print_error(message):
+ """Print error message"""
+ print(f"✗ {message}")
+
+
+def print_info(message):
+ """Print info message"""
+ print(f"ℹ {message}")
+
+
+def test_default_category():
+ """Test that default category exists"""
+ print_section("Test 1: Default Category Check")
+
+ try:
+ category = AppreciationCategory.objects.get(code='patient_feedback')
+ print_success(f"Default category exists: {category.name_en}")
+ print_info(f"Category ID: {category.id}")
+ print_info(f"Name (AR): {category.name_ar}")
+ return True
+ except AppreciationCategory.DoesNotExist:
+ print_error("Default category 'patient_feedback' not found!")
+ print_info("Run: python manage.py create_patient_feedback_category")
+ return False
+
+
+def create_test_data():
+ """Create test data for conversion tests"""
+ print_section("Test 2: Create Test Data")
+
+ # Create PX Admin user
+ try:
+ px_admin = User.objects.get(email='test_px_admin@example.com')
+ except User.DoesNotExist:
+ px_admin = User.objects.create_user(
+ email='test_px_admin@example.com',
+ password='testpass123',
+ first_name='Test',
+ last_name='PX Admin',
+ is_px_admin=True
+ )
+ print_success("Created PX Admin user")
+
+ # Create Hospital
+ try:
+ hospital = Hospital.objects.get(code='TEST_HOSPITAL')
+ except Hospital.DoesNotExist:
+ hospital = Hospital.objects.create(
+ code='TEST_HOSPITAL',
+ name_en='Test Hospital',
+ name_ar='مستشفى تجريبي',
+ city='Riyadh'
+ )
+ print_success("Created Hospital")
+
+ # Create Department
+ try:
+ department = Department.objects.get(code='TEST_DEPT')
+ except Department.DoesNotExist:
+ department = Department.objects.create(
+ code='TEST_DEPT',
+ hospital=hospital,
+ name_en='Test Department',
+ name_ar='قسم تجريبي'
+ )
+ print_success("Created Department")
+
+ # Create Staff
+ try:
+ staff = Staff.objects.get(email='test_staff@example.com')
+ except Staff.DoesNotExist:
+ staff = Staff.objects.create(
+ email='test_staff@example.com',
+ hospital=hospital,
+ department=department,
+ first_name='Test',
+ last_name='Staff',
+ first_name_ar='تجريبي',
+ last_name_ar='موظف',
+ job_title='Test Employee',
+ job_title_ar='موظف تجريبي'
+ )
+ # Create user account for staff
+ staff.user = User.objects.create_user(
+ email='test_staff@example.com',
+ password='staffpass123',
+ first_name='Test',
+ last_name='Staff'
+ )
+ staff.save()
+ print_success("Created Staff with user account")
+
+ # Create Patient
+ try:
+ patient = Patient.objects.get(mrn='TEST_PATIENT_001')
+ except Patient.DoesNotExist:
+ patient = Patient.objects.create(
+ mrn='TEST_PATIENT_001',
+ hospital=hospital,
+ first_name='Test',
+ last_name='Patient',
+ first_name_ar='تجريبي',
+ last_name_ar='مريض'
+ )
+ print_success("Created Patient")
+
+ return {
+ 'px_admin': px_admin,
+ 'hospital': hospital,
+ 'department': department,
+ 'staff': staff,
+ 'patient': patient
+ }
+
+
+def test_appreciation_type_complaint(test_data):
+ """Test creating an appreciation-type complaint"""
+ print_section("Test 3: Create Appreciation-Type Complaint")
+
+ complaint = Complaint.objects.create(
+ patient=test_data['patient'],
+ hospital=test_data['hospital'],
+ department=test_data['department'],
+ staff=test_data['staff'],
+ complaint_type='appreciation',
+ category='quality_of_care',
+ subcategory='Positive Feedback',
+ severity='low',
+ priority='medium',
+ source='web',
+ title='Excellent Service by Test Staff',
+ description='I want to appreciate the excellent service provided by Test Staff. They were very helpful and professional.',
+ short_description='Positive feedback about excellent service',
+ short_description_ar='تغذية راجعة إيجابية عن خدمة ممتازة',
+ status='open',
+ created_by=test_data['px_admin']
+ )
+
+ print_success(f"Created appreciation-type complaint: {complaint.id}")
+ print_info(f"Complaint type: {complaint.complaint_type}")
+ print_info(f"Title: {complaint.title}")
+
+ return complaint
+
+
+def test_api_endpoint(test_data, complaint):
+ """Test the conversion API endpoint"""
+ print_section("Test 4: Test Conversion API Endpoint")
+
+ # Get default category
+ category = AppreciationCategory.objects.get(code='patient_feedback')
+
+ # Prepare request data
+ data = {
+ 'recipient_type': 'user',
+ 'recipient_id': str(test_data['staff'].user.id),
+ 'category_id': str(category.id),
+ 'message_en': complaint.description,
+ 'message_ar': complaint.short_description_ar,
+ 'visibility': 'department',
+ 'is_anonymous': True,
+ 'close_complaint': True
+ }
+
+ # Create API client
+ client = APIClient()
+ client.force_authenticate(user=test_data['px_admin'])
+
+ # Make API request
+ url = reverse('complaints:convert_to_appreciation', kwargs={'pk': complaint.id})
+ print_info(f"API URL: {url}")
+ print_info(f"Request data: {json.dumps(data, indent=2)}")
+
+ response = client.post(url, data, format='json')
+
+ print_info(f"Response status: {response.status_code}")
+
+ if response.status_code == 201:
+ print_success("Conversion API call successful!")
+ result = response.json()
+ print_info(f"Response: {json.dumps(result, indent=2)}")
+
+ # Verify appreciation was created
+ appreciation_id = result.get('appreciation_id')
+ if appreciation_id:
+ try:
+ appreciation = Appreciation.objects.get(id=appreciation_id)
+ print_success(f"Appreciation record created: {appreciation.id}")
+ print_info(f"Appreciation message: {appreciation.message_en[:50]}...")
+
+ # Verify complaint metadata
+ complaint.refresh_from_db()
+ if complaint.metadata.get('appreciation_id'):
+ print_success("Complaint metadata updated with appreciation link")
+ else:
+ print_error("Complaint metadata not updated!")
+
+ # Verify complaint status changed
+ if complaint.status == 'closed':
+ print_success("Complaint status changed to 'closed'")
+ else:
+ print_error(f"Complaint status is '{complaint.status}', expected 'closed'")
+
+ # Verify timeline entry
+ timeline_entries = ComplaintUpdate.objects.filter(
+ complaint=complaint,
+ update_type='note'
+ ).count()
+ if timeline_entries > 0:
+ print_success(f"Timeline entry created ({timeline_entries} entries)")
+ else:
+ print_error("No timeline entry created!")
+
+ return appreciation
+ except Appreciation.DoesNotExist:
+ print_error("Appreciation record not found in database!")
+ else:
+ print_error("No appreciation_id in response!")
+ else:
+ print_error(f"API call failed with status {response.status_code}")
+ print_info(f"Response: {response.json()}")
+
+ return None
+
+
+def test_prevention_of_duplicate_conversion(test_data, complaint):
+ """Test that duplicate conversions are prevented"""
+ print_section("Test 5: Prevent Duplicate Conversion")
+
+ # Create API client
+ client = APIClient()
+ client.force_authenticate(user=test_data['px_admin'])
+
+ # Get default category
+ category = AppreciationCategory.objects.get(code='patient_feedback')
+
+ # Prepare request data
+ data = {
+ 'recipient_type': 'user',
+ 'recipient_id': str(test_data['staff'].user.id),
+ 'category_id': str(category.id),
+ 'message_en': 'Duplicate test',
+ 'message_ar': 'اختبار مكرر',
+ 'visibility': 'private',
+ 'is_anonymous': True,
+ 'close_complaint': False
+ }
+
+ # Make API request (should fail)
+ url = reverse('complaints:convert_to_appreciation', kwargs={'pk': complaint.id})
+ response = client.post(url, data, format='json')
+
+ print_info(f"Response status: {response.status_code}")
+
+ if response.status_code == 400:
+ print_success("Duplicate conversion prevented as expected!")
+ result = response.json()
+ print_info(f"Error message: {result.get('error')}")
+ return True
+ else:
+ print_error("Duplicate conversion was not prevented!")
+ print_info(f"Response: {response.json()}")
+ return False
+
+
+def test_non_appreciation_type(test_data):
+ """Test that non-appreciation complaints cannot be converted"""
+ print_section("Test 6: Non-Appreciation Type Prevention")
+
+ # Create regular complaint type
+ complaint = Complaint.objects.create(
+ patient=test_data['patient'],
+ hospital=test_data['hospital'],
+ department=test_data['department'],
+ staff=test_data['staff'],
+ complaint_type='complaint', # Not appreciation
+ category='quality_of_care',
+ subcategory='Wait Time',
+ severity='medium',
+ priority='high',
+ source='web',
+ title='Long Wait Time',
+ description='I waited too long for my appointment.',
+ status='open',
+ created_by=test_data['px_admin']
+ )
+
+ print_success("Created regular complaint-type complaint")
+
+ # Try to convert
+ client = APIClient()
+ client.force_authenticate(user=test_data['px_admin'])
+
+ category = AppreciationCategory.objects.get(code='patient_feedback')
+
+ data = {
+ 'recipient_type': 'user',
+ 'recipient_id': str(test_data['staff'].user.id),
+ 'category_id': str(category.id),
+ 'message_en': 'Test',
+ 'message_ar': 'اختبار',
+ 'visibility': 'private',
+ 'is_anonymous': True,
+ 'close_complaint': False
+ }
+
+ url = reverse('complaints:convert_to_appreciation', kwargs={'pk': complaint.id})
+ response = client.post(url, data, format='json')
+
+ print_info(f"Response status: {response.status_code}")
+
+ if response.status_code == 400:
+ print_success("Non-appreciation conversion prevented as expected!")
+ result = response.json()
+ print_info(f"Error message: {result.get('error')}")
+ return True
+ else:
+ print_error("Non-appreciation conversion was not prevented!")
+ return False
+
+
+def cleanup_test_data():
+ """Clean up test data"""
+ print_section("Cleanup: Remove Test Data")
+
+ # Delete test appreciations
+ Appreciation.objects.filter(
+ recipient=test_data['staff']
+ ).delete()
+ print_success("Deleted test appreciations")
+
+ # Delete test complaints
+ Complaint.objects.filter(
+ patient=test_data['patient']
+ ).delete()
+ print_success("Deleted test complaints")
+
+ # Delete test patient
+ test_data['patient'].delete()
+ print_success("Deleted test patient")
+
+ # Delete test staff user
+ if test_data['staff'].user:
+ test_data['staff'].user.delete()
+ test_data['staff'].delete()
+ print_success("Deleted test staff")
+
+ # Delete test department
+ test_data['department'].delete()
+ print_success("Deleted test department")
+
+ # Delete test hospital
+ test_data['hospital'].delete()
+ print_success("Deleted test hospital")
+
+ # Delete test px admin
+ test_data['px_admin'].delete()
+ print_success("Deleted test PX admin")
+
+
+def main():
+ """Main test runner"""
+ print_section("Complaint to Appreciation Conversion - Test Suite")
+ print_info("This test suite validates the conversion feature functionality\n")
+
+ all_passed = True
+
+ # Test 1: Check default category
+ if not test_default_category():
+ print_error("Cannot proceed without default category!")
+ return False
+
+ # Test 2: Create test data
+ global test_data
+ test_data = create_test_data()
+
+ # Test 3: Create appreciation-type complaint
+ complaint = test_appreciation_type_complaint(test_data)
+
+ # Test 4: Test API endpoint
+ appreciation = test_api_endpoint(test_data, complaint)
+ if not appreciation:
+ all_passed = False
+
+ # Test 5: Prevent duplicate conversion
+ if complaint.metadata.get('appreciation_id'):
+ if not test_prevention_of_duplicate_conversion(test_data, complaint):
+ all_passed = False
+
+ # Test 6: Prevent non-appreciation conversion
+ if not test_non_appreciation_type(test_data):
+ all_passed = False
+
+ # Cleanup
+ cleanup_test_data()
+
+ # Summary
+ print_section("Test Summary")
+ if all_passed:
+ print_success("All tests passed! ✓")
+ print_info("\nThe Complaint to Appreciation Conversion feature is working correctly.")
+ else:
+ print_error("Some tests failed! ✗")
+ print_info("\nPlease review the error messages above and fix any issues.")
+
+ return all_passed
+
+
+if __name__ == '__main__':
+ try:
+ success = main()
+ sys.exit(0 if success else 1)
+ except Exception as e:
+ print_error(f"Unexpected error: {e}")
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/test_complaint_type_classification.py b/test_complaint_type_classification.py
new file mode 100644
index 0000000..b357a8c
--- /dev/null
+++ b/test_complaint_type_classification.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+"""
+Test script to verify complaint vs appreciation classification.
+
+This script tests:
+1. AI service complaint type detection
+2. Appreciation skipping SLA/PX Actions
+3. Classification with bilingual keywords
+"""
+import os
+import sys
+
+# Add project root to path
+sys.path.insert(0, '/home/ismail/projects/HH')
+
+# Setup Django
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.dev')
+import django
+django.setup()
+
+from apps.core.ai_service import AIService
+from apps.organizations.models import Hospital, Department
+
+def test_complaint_detection():
+ """Test AI detection of complaints vs appreciations"""
+ print("\n" + "="*80)
+ print("TESTING COMPLAINT vs APPRECIATION DETECTION")
+ print("="*80)
+
+ test_cases = [
+ {
+ 'type': 'complaint',
+ 'description': "I am very disappointed with the service. The staff was rude and ignored me. I had to wait for 3 hours and nobody helped.",
+ 'expected': 'complaint'
+ },
+ {
+ 'type': 'complaint',
+ 'description': "The doctor was terrible. He didn't listen to my concerns and dismissed my symptoms. This is unacceptable.",
+ 'expected': 'complaint'
+ },
+ {
+ 'type': 'complaint',
+ 'description': "هناك مشكلة كبيرة في العيادة. الطبيب لم يستمع لي وتجاهل شكواي. خدمة سيئة جدا",
+ 'expected': 'complaint'
+ },
+ {
+ 'type': 'appreciation',
+ 'description': "I would like to thank Dr. Ahmed for the excellent care he provided. He was very professional and caring. The nurses were also wonderful.",
+ 'expected': 'appreciation'
+ },
+ {
+ 'type': 'appreciation',
+ 'description': "Great service! The staff was friendly and helpful. I appreciate the wonderful care I received. Thank you so much!",
+ 'expected': 'appreciation'
+ },
+ {
+ 'type': 'appreciation',
+ 'description': "أريد أن أشكر الطبيب محمد على الرعاية الممتازة. كان مهنيا جدا ومتعاطفا. شكرا جزيلا لكم",
+ 'expected': 'appreciation'
+ },
+ {
+ 'type': 'mixed',
+ 'description': "The doctor was good but the wait time was terrible. I appreciate the care but disappointed with the delay.",
+ 'expected': 'complaint' # Should default to complaint if mixed
+ },
+ ]
+
+ correct = 0
+ incorrect = 0
+
+ for i, test_case in enumerate(test_cases, 1):
+ print(f"\nTest Case {i}: {test_case['type'].upper()}")
+ print(f"Description: {test_case['description'][:100]}...")
+
+ # Detect type
+ detected_type = AIService._detect_complaint_type(test_case['description'])
+
+ # Check result
+ is_correct = detected_type == test_case['expected']
+ status = "✓ CORRECT" if is_correct else "✗ INCORRECT"
+
+ if is_correct:
+ correct += 1
+ else:
+ incorrect += 1
+
+ print(f"Expected: {test_case['expected']}")
+ print(f"Detected: {detected_type}")
+ print(f"Status: {status}")
+
+ # Summary
+ print("\n" + "="*80)
+ print("CLASSIFICATION SUMMARY")
+ print("="*80)
+ print(f"Total Tests: {len(test_cases)}")
+ print(f"Correct: {correct}")
+ print(f"Incorrect: {incorrect}")
+ print(f"Accuracy: {correct/len(test_cases)*100:.1f}%")
+ print("="*80)
+
+ return correct == len(test_cases)
+
+
+def test_appreciation_workflow():
+ """Test that appreciations skip SLA/PX Actions"""
+ print("\n" + "="*80)
+ print("TESTING APPRECIATION WORKFLOW (Skip SLA/PX Actions)")
+ print("="*80)
+
+ # Get a hospital
+ try:
+ hospital = Hospital.objects.first()
+ if not hospital:
+ print("✗ No hospital found in database")
+ return False
+
+ print(f"Using hospital: {hospital.name}")
+ except Exception as e:
+ print(f"✗ Error getting hospital: {e}")
+ return False
+
+ # Test appreciation analysis
+ appreciation_text = "I want to thank the staff for the excellent care provided. Dr. Ahmed was wonderful and very professional."
+
+ print(f"\nAnalyzing appreciation text:")
+ print(f"Text: {appreciation_text}")
+
+ analysis = AIService.analyze_complaint(
+ title="Appreciation for excellent care",
+ description=appreciation_text,
+ hospital_id=hospital.id
+ )
+
+ print(f"\nAI Analysis Results:")
+ print(f"Complaint Type: {analysis.get('complaint_type', 'N/A')}")
+ print(f"Severity: {analysis.get('severity', 'N/A')}")
+ print(f"Priority: {analysis.get('priority', 'N/A')}")
+ print(f"Category: {analysis.get('category', 'N/A')}")
+
+ # Check if detected as appreciation
+ complaint_type = analysis.get('complaint_type', 'complaint')
+ if complaint_type == 'appreciation':
+ print(f"\n✓ Correctly identified as APPRECIATION")
+ print(f"✓ SLA tracking and PX Actions should be SKIPPED")
+ return True
+ else:
+ print(f"\n✗ Incorrectly identified as COMPLAINT")
+ print(f"✗ This would incorrectly trigger SLA/PX Actions")
+ return False
+
+
+def test_complaint_workflow():
+ """Test that complaints still work normally"""
+ print("\n" + "="*80)
+ print("TESTING COMPLAINT WORKFLOW (Normal SLA/PX Actions)")
+ print("="*80)
+
+ # Get a hospital
+ try:
+ hospital = Hospital.objects.first()
+ if not hospital:
+ print("✗ No hospital found in database")
+ return False
+ except Exception as e:
+ print(f"✗ Error getting hospital: {e}")
+ return False
+
+ # Test complaint analysis
+ complaint_text = "The service was terrible. The staff was rude and ignored me for 2 hours."
+
+ print(f"\nAnalyzing complaint text:")
+ print(f"Text: {complaint_text}")
+
+ analysis = AIService.analyze_complaint(
+ title="Terrible service and rude staff",
+ description=complaint_text,
+ hospital_id=hospital.id
+ )
+
+ print(f"\nAI Analysis Results:")
+ print(f"Complaint Type: {analysis.get('complaint_type', 'N/A')}")
+ print(f"Severity: {analysis.get('severity', 'N/A')}")
+ print(f"Priority: {analysis.get('priority', 'N/A')}")
+ print(f"Category: {analysis.get('category', 'N/A')}")
+
+ # Check if detected as complaint
+ complaint_type = analysis.get('complaint_type', 'complaint')
+ if complaint_type == 'complaint':
+ print(f"\n✓ Correctly identified as COMPLAINT")
+ print(f"✓ SLA tracking and PX Actions should be TRIGGERED")
+ return True
+ else:
+ print(f"\n✗ Incorrectly identified as APPRECIATION")
+ print(f"✗ This would incorrectly skip SLA/PX Actions")
+ return False
+
+
+if __name__ == '__main__':
+ print("\n" + "="*80)
+ print("COMPLAINT TYPE CLASSIFICATION TEST SUITE")
+ print("="*80)
+
+ # Run all tests
+ test1_passed = test_complaint_detection()
+ test2_passed = test_appreciation_workflow()
+ test3_passed = test_complaint_workflow()
+
+ # Final summary
+ print("\n" + "="*80)
+ print("FINAL TEST RESULTS")
+ print("="*80)
+ print(f"1. Classification Detection: {'✓ PASSED' if test1_passed else '✗ FAILED'}")
+ print(f"2. Appreciation Workflow: {'✓ PASSED' if test2_passed else '✗ FAILED'}")
+ print(f"3. Complaint Workflow: {'✓ PASSED' if test3_passed else '✗ FAILED'}")
+
+ all_passed = test1_passed and test2_passed and test3_passed
+ print(f"\nOverall: {'✓ ALL TESTS PASSED' if all_passed else '✗ SOME TESTS FAILED'}")
+ print("="*80 + "\n")
+
+ exit(0 if all_passed else 1)