From 867f60fed7d0f2de2d0b2c8ec6e3adf7bb3d9b86 Mon Sep 17 00:00:00 2001 From: Marwan Alwali Date: Thu, 8 Jan 2026 20:56:18 +0300 Subject: [PATCH] update --- PHYSICIAN_REFERENCE_FIXES.md | 84 +++++++ apps/appreciation/serializers.py | 20 +- apps/appreciation/views.py | 64 +++--- apps/complaints/signals.py | 51 +++-- apps/journeys/serializers.py | 12 +- apps/journeys/ui_views.py | 4 +- dump.rdb | Bin 88 -> 88 bytes locale/ar/LC_MESSAGES/django.mo | Bin 101826 -> 104792 bytes locale/ar/LC_MESSAGES/django.po | 212 +++++++++++++++++- templates/complaints/complaint_detail.html | 114 +++++----- templates/dashboard/command_center.html | 12 +- templates/journeys/instance_detail.html | 4 +- templates/physicians/department_overview.html | 10 +- templates/physicians/ratings_list.html | 16 +- .../physicians/specialization_overview.html | 14 +- 15 files changed, 459 insertions(+), 158 deletions(-) create mode 100644 PHYSICIAN_REFERENCE_FIXES.md diff --git a/PHYSICIAN_REFERENCE_FIXES.md b/PHYSICIAN_REFERENCE_FIXES.md new file mode 100644 index 0000000..b2036e1 --- /dev/null +++ b/PHYSICIAN_REFERENCE_FIXES.md @@ -0,0 +1,84 @@ +# Physician Reference Fixes + +## Summary +Fixed all references to use the correct model (`organizations.Staff`) instead of incorrect `Physician` model references. + +## Root Cause +The system uses `organizations.Staff` model for physicians, not a separate `Physician` model. Several templates and code were incorrectly trying to access a `physician` attribute on `PhysicianMonthlyRating` and `PatientJourneyStageInstance` objects, when the actual field is `staff`. + +## Files Fixed + +### 1. Journeys Module +**File:** `apps/journeys/ui_views.py` +- Changed `prefetch_related()` parameter from `'stage_instances__physician'` to `'stage_instances__staff'` in two places +- Line 40 (journey_instance_list view) and Line 149 (journey_instance_detail view) +- This was the source of the original AttributeError: "Cannot find 'physician' on PatientJourneyStageInstance object" + +**File:** `apps/journeys/serializers.py` +- Changed `PatientJourneyStageInstanceSerializer` field from `physician` to `staff` +- Changed `physician_name` method to `staff_name` +- Updated fields list to use `staff` and `staff_name` instead of `physician` and `physician_name` +- The `PatientJourneyStageInstance` model has a `staff` field, not `physician` + +### 2. Appreciation Module +**File:** `apps/appreciation/views.py` +- Changed all `Physician.objects` references to `Staff.objects` +- Updated queryset filters and filters context to use Staff model + +**File:** `apps/appreciation/serializers.py` +- Changed model reference from `Physician` to `Staff` +- Updated all field references from `physician` to `staff` + +### 3. Dashboard Module +**File:** `templates/dashboard/command_center.html` +- Changed `rating.physician.*` references to `rating.staff.*` +- The `PhysicianMonthlyRating` model has a `staff` field, not `physician` + +### 4. Physicians Templates +**File:** `templates/physicians/ratings_list.html` +- Changed all `rating.physician.*` references to `rating.staff.*` + +**File:** `templates/physicians/specialization_overview.html` +- Changed all `rating.physician.*` references to `rating.staff.*` + +**File:** `templates/physicians/department_overview.html` +- Changed all `rating.physician.*` references to `rating.staff.*` + +### 5. Physicians App (Verified - No Changes Needed) +The physicians app is already correctly implemented: +- `apps/physicians/models.py` - `PhysicianMonthlyRating.staff` field correctly points to `organizations.Staff` +- `apps/physicians/views.py` - All code correctly uses `staff` field when querying `PhysicianMonthlyRating` +- `apps/physicians/serializers.py` - All serializers correctly reference `staff` field +- `apps/physicians/ui_views.py` - All views correctly use `staff` field +- `templates/physicians/*.html` - All templates correctly access physician attributes through `physician.*` where `physician` is a Staff object + +The variable name `physician` is used correctly in templates as it represents a `Staff` object passed from views, not a separate `Physician` model. + +## Model Structure + +### organizations.Staff +- This is the actual physician model +- Contains fields like: `first_name`, `last_name`, `license_number`, `specialization`, `department`, `hospital` + +### physicians.PhysicianMonthlyRating +- Contains monthly aggregated ratings for physicians +- Has a `staff` field (ForeignKey to `organizations.Staff`), NOT `physician` +- This was the source of most template errors + +### journeys.PatientJourneyStageInstance +- Contains stage instances in patient journeys +- Has a `staff` field (ForeignKey to `organizations.Staff`), NOT `physician` +- This was the source of the serializer error + +## Verification + +All imports were verified to be correct: +- `PhysicianMonthlyRating` imports are all correct +- No old `Physician` model imports exist +- Only one `physician_profile` reference found, which is a commented line + +## Testing +The application should now work correctly without the following errors: +1. `AttributeError: Cannot find 'physician' on PatientJourneyStageInstance object` +2. Template rendering errors due to `rating.physician` not existing +3. All physician-related views should display correctly diff --git a/apps/appreciation/serializers.py b/apps/appreciation/serializers.py index ee17241..fd1ee9c 100644 --- a/apps/appreciation/serializers.py +++ b/apps/appreciation/serializers.py @@ -107,7 +107,7 @@ class AppreciationSerializer(serializers.ModelSerializer): return "Unknown" def get_recipient_type(self, obj): - """Get recipient type (user or physician)""" + """Get recipient type (user or staff)""" if obj.recipient_content_type: return obj.recipient_content_type.model return None @@ -133,9 +133,9 @@ class AppreciationCreateSerializer(serializers.Serializer): """Serializer for creating Appreciation""" recipient_type = serializers.ChoiceField( - choices=['user', 'physician'], + choices=['user', 'staff'], write_only=True, - help_text="Type of recipient: 'user' or 'physician'" + help_text="Type of recipient: 'user' or 'staff'" ) recipient_id = serializers.UUIDField(write_only=True) category_id = serializers.UUIDField(required=False, allow_null=True) @@ -176,17 +176,17 @@ class AppreciationCreateSerializer(serializers.Serializer): raise serializers.ValidationError({ 'recipient_id': 'User not found' }) - elif recipient_type == 'physician': - from apps.organizations.models import Physician + elif recipient_type == 'staff': + from apps.organizations.models import Staff try: - physician = Physician.objects.get(id=recipient_id) - if physician.hospital_id != hospital_id: + staff = Staff.objects.get(id=recipient_id) + if staff.hospital_id != hospital_id: raise serializers.ValidationError({ - 'recipient_id': 'Physician does not belong to specified hospital' + 'recipient_id': 'Staff does not belong to specified hospital' }) - except Physician.DoesNotExist: + except Staff.DoesNotExist: raise serializers.ValidationError({ - 'recipient_id': 'Physician not found' + 'recipient_id': 'Staff not found' }) # Validate category if provided diff --git a/apps/appreciation/views.py b/apps/appreciation/views.py index 4136701..fb5d3cd 100644 --- a/apps/appreciation/views.py +++ b/apps/appreciation/views.py @@ -86,11 +86,11 @@ class AppreciationViewSet(viewsets.ModelViewSet): # Get user's content type user_content_type = ContentType.objects.get_for_model(user) - # Get physician if user has a physician profile - physician = None - if hasattr(user, 'physician_profile'): - physician = user.phician_profile - physician_content_type = ContentType.objects.get_for_model(type(physician)) + # Get staff if user has a staff profile + staff = None + if hasattr(user, 'staff_profile'): + staff = user.staff_profile + staff_content_type = ContentType.objects.get_for_model(type(staff)) # Build visibility filter visibility_filter = ( @@ -101,11 +101,11 @@ class AppreciationViewSet(viewsets.ModelViewSet): ) # Received by user ) - if physician: + if staff: visibility_filter |= Q( - recipient_content_type=physician_content_type, - recipient_object_id=physician.id - ) # Received by physician + recipient_content_type=staff_content_type, + recipient_object_id=staff.id + ) # Received by staff if user.department: visibility_filter |= Q( @@ -135,9 +135,9 @@ class AppreciationViewSet(viewsets.ModelViewSet): recipient_content_type=content_type, recipient_object_id=recipient_id ) - elif recipient_type == 'physician': - from apps.organizations.models import Physician - content_type = ContentType.objects.get_for_model(Physician) + elif recipient_type == 'staff': + from apps.organizations.models import Staff + content_type = ContentType.objects.get_for_model(Staff) queryset = queryset.filter( recipient_content_type=content_type, recipient_object_id=recipient_id @@ -173,10 +173,10 @@ class AppreciationViewSet(viewsets.ModelViewSet): from apps.accounts.models import User recipient = User.objects.get(id=recipient_id) content_type = ContentType.objects.get_for_model(User) - else: # physician - from apps.organizations.models import Physician - recipient = Physician.objects.get(id=recipient_id) - content_type = ContentType.objects.get_for_model(Physician) + else: # staff + from apps.organizations.models import Staff + recipient = Staff.objects.get(id=recipient_id) + content_type = ContentType.objects.get_for_model(Staff) # Get hospital from apps.organizations.models import Hospital @@ -243,10 +243,10 @@ class AppreciationViewSet(viewsets.ModelViewSet): # Get user's appreciations user_content_type = ContentType.objects.get_for_model(request.user) - # Check if user has physician profile - physician = None - if hasattr(request.user, 'physician_profile'): - physician = request.user.physician_profile + # Check if user has staff profile + staff = None + if hasattr(request.user, 'staff_profile'): + staff = request.user.staff_profile # Build query queryset = self.get_queryset().filter( @@ -256,11 +256,11 @@ class AppreciationViewSet(viewsets.ModelViewSet): ) ) - if physician: - physician_content_type = ContentType.objects.get_for_model(type(physician)) + if staff: + staff_content_type = ContentType.objects.get_for_model(type(staff)) queryset |= self.get_queryset().filter( - recipient_content_type=physician_content_type, - recipient_object_id=physician.id + recipient_content_type=staff_content_type, + recipient_object_id=staff.id ) # Paginate @@ -440,11 +440,11 @@ class UserBadgeViewSet(viewsets.ReadOnlyModelViewSet): # Get user's content type user_content_type = ContentType.objects.get_for_model(user) - # Filter by user or user's physician profile - physician = None - if hasattr(user, 'physician_profile'): - physician = user.physician_profile - physician_content_type = ContentType.objects.get_for_model(type(physician)) + # Filter by user or user's staff profile + staff = None + if hasattr(user, 'staff_profile'): + staff = user.staff_profile + staff_content_type = ContentType.objects.get_for_model(type(staff)) queryset = queryset.filter( Q( @@ -453,10 +453,10 @@ class UserBadgeViewSet(viewsets.ReadOnlyModelViewSet): ) ) - if physician: + if staff: queryset |= queryset.filter( - recipient_content_type=physician_content_type, - recipient_object_id=physician.id + recipient_content_type=staff_content_type, + recipient_object_id=staff.id ) return queryset.select_related('badge') diff --git a/apps/complaints/signals.py b/apps/complaints/signals.py index 8fbdfa2..e302bad 100644 --- a/apps/complaints/signals.py +++ b/apps/complaints/signals.py @@ -32,19 +32,27 @@ def handle_complaint_created(sender, instance, created, **kwargs): send_complaint_notification, ) - # Trigger AI analysis (determines severity and priority) - analyze_complaint_with_ai.delay(str(instance.id)) + # Try to trigger async tasks, but don't fail if Redis/Celery is unavailable + try: + # Trigger AI analysis (determines severity and priority) + analyze_complaint_with_ai.delay(str(instance.id)) - # Trigger PX Action creation (if configured) - create_action_from_complaint.delay(str(instance.id)) + # Trigger PX Action creation (if configured) + create_action_from_complaint.delay(str(instance.id)) - # Send notification - send_complaint_notification.delay( - complaint_id=str(instance.id), - event_type='created' - ) + # Send notification + send_complaint_notification.delay( + complaint_id=str(instance.id), + event_type='created' + ) - logger.info(f"Complaint created: {instance.id} - {instance.title}") + logger.info(f"Complaint created: {instance.id} - {instance.title} - Async tasks queued") + except Exception as e: + # Log the error but don't prevent complaint creation + logger.warning( + f"Complaint created: {instance.id} - {instance.title} - " + f"Async tasks could not be queued (Celery/Redis unavailable): {e}" + ) @receiver(post_save, sender=SurveyInstance) @@ -60,12 +68,19 @@ def handle_survey_completed(sender, instance, created, **kwargs): if instance.metadata.get('complaint_id'): from apps.complaints.tasks import check_resolution_survey_threshold - check_resolution_survey_threshold.delay( - survey_instance_id=str(instance.id), - complaint_id=instance.metadata['complaint_id'] - ) + try: + check_resolution_survey_threshold.delay( + survey_instance_id=str(instance.id), + complaint_id=instance.metadata['complaint_id'] + ) - logger.info( - f"Resolution survey completed for complaint {instance.metadata['complaint_id']}: " - f"Score = {instance.total_score}" - ) + logger.info( + f"Resolution survey completed for complaint {instance.metadata['complaint_id']}: " + f"Score = {instance.total_score} - Async task queued" + ) + except Exception as e: + # Log the error but don't prevent survey completion + logger.warning( + f"Resolution survey completed for complaint {instance.metadata['complaint_id']}: " + f"Score = {instance.total_score} - Async task could not be queued (Celery/Redis unavailable): {e}" + ) diff --git a/apps/journeys/serializers.py b/apps/journeys/serializers.py index 9dfbea5..88d0676 100644 --- a/apps/journeys/serializers.py +++ b/apps/journeys/serializers.py @@ -53,7 +53,7 @@ class PatientJourneyStageInstanceSerializer(serializers.ModelSerializer): """Journey stage instance serializer""" stage_name = serializers.CharField(source='stage_template.name', read_only=True) stage_order = serializers.IntegerField(source='stage_template.order', read_only=True) - physician_name = serializers.SerializerMethodField() + staff_name = serializers.SerializerMethodField() department_name = serializers.CharField(source='department.name', read_only=True) survey_status = serializers.CharField(source='survey_instance.status', read_only=True) @@ -62,7 +62,7 @@ class PatientJourneyStageInstanceSerializer(serializers.ModelSerializer): fields = [ 'id', 'journey_instance', 'stage_template', 'stage_name', 'stage_order', 'status', 'completed_at', 'completed_by_event', - 'physician', 'physician_name', 'department', 'department_name', + 'staff', 'staff_name', 'department', 'department_name', 'survey_instance', 'survey_status', 'survey_sent_at', 'metadata', 'created_at', 'updated_at' ] @@ -72,10 +72,10 @@ class PatientJourneyStageInstanceSerializer(serializers.ModelSerializer): 'created_at', 'updated_at' ] - def get_physician_name(self, obj): - """Get physician full name""" - if obj.physician: - return obj.physician.get_full_name() + def get_staff_name(self, obj): + """Get staff full name""" + if obj.staff: + return obj.staff.get_full_name() return None diff --git a/apps/journeys/ui_views.py b/apps/journeys/ui_views.py index a6efd86..d85d121 100644 --- a/apps/journeys/ui_views.py +++ b/apps/journeys/ui_views.py @@ -36,7 +36,7 @@ def journey_instance_list(request): 'department' ).prefetch_related( 'stage_instances__stage_template', - 'stage_instances__physician', + 'stage_instances__staff', 'stage_instances__survey_instance' ) @@ -146,7 +146,7 @@ def journey_instance_detail(request, pk): 'department' ).prefetch_related( 'stage_instances__stage_template', - 'stage_instances__physician', + 'stage_instances__staff', 'stage_instances__department', 'stage_instances__survey_instance', 'stage_instances__completed_by_event' diff --git a/dump.rdb b/dump.rdb index 399b7de68ff5d7b57691ba028e505748098b31fa..1aaef6fa1d182d47e9521f2f8080d3af760342e4 100644 GIT binary patch delta 45 zcma!um|&oxUK5}Bi=(tSHAOc!HTTd16CQ?N9Etg9x=D$}sRtPTPr0otowiRd7yy&J B5)c3Y delta 45 zcma!um|&nGofDS%i=(tSHAOc!HTTd16CQ?N9Etg9x=D$}sRtPTAKa9`LO1Ko69AIA B6L0_k diff --git a/locale/ar/LC_MESSAGES/django.mo b/locale/ar/LC_MESSAGES/django.mo index fd56e6717f30374666b9dc5e9a93af29720222fe..7b19972d2ae40bbcd8a73a4ebb7d9b3e9e953ec4 100644 GIT binary patch delta 29975 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⪙JXR_0&KiFvQM>suGKg}t%AkB(7WmiTA) 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 E50o&gLI3~& diff --git a/locale/ar/LC_MESSAGES/django.po b/locale/ar/LC_MESSAGES/django.po index 15e83df..bf1cab8 100644 --- a/locale/ar/LC_MESSAGES/django.po +++ b/locale/ar/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PX360 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-01-08 10:47+0300\n" +"POT-Creation-Date: 2026-01-08 15:08+0300\n" "PO-Revision-Date: 2025-12-15 12:30+0300\n" "Last-Translator: PX360 Team\n" "Language-Team: Arabic\n" @@ -983,6 +983,8 @@ msgstr "اسم العائلة" #: templates/callcenter/complaint_form.html:274 #: templates/callcenter/inquiry_form.html:233 #: templates/complaints/complaint_detail.html:847 +#: templates/complaints/complaint_detail.html:904 +#: templates/complaints/complaint_detail.html:1060 #: templates/complaints/complaint_form.html:266 #: templates/complaints/inquiry_form.html:237 #: templates/observations/category_form.html:91 @@ -1626,6 +1628,7 @@ msgstr "النتيجة" #: templates/ai_engine/sentiment_detail.html:68 #: templates/ai_engine/sentiment_list.html:125 #: templates/ai_engine/tags/sentiment_card.html:22 +#: templates/complaints/complaint_detail.html:410 msgid "Confidence" msgstr "الثقة" @@ -1891,6 +1894,7 @@ msgid "PX Command Center" msgstr "مركز قيادة تجربة المرضى" #: templates/analytics/command_center.html:99 +#: templates/complaints/complaint_detail.html:942 msgid "Loading..." msgstr "جارٍ التحميل..." @@ -1970,6 +1974,7 @@ msgid "All Hospitals" msgstr "جميع المستشفيات" #: templates/analytics/command_center.html:188 +#: templates/complaints/complaint_detail.html:929 #: templates/complaints/complaint_list.html:258 #: templates/observations/observation_list.html:234 #: templates/physicians/leaderboard.html:94 @@ -2348,6 +2353,7 @@ msgstr "نوع المستلم" #: templates/appreciation/appreciation_send_form.html:57 #: templates/appreciation/leaderboard.html:95 +#: templates/complaints/complaint_detail.html:986 msgid "Recipient" msgstr "المستلم" @@ -3695,10 +3701,88 @@ msgstr "المرفقات" msgid "PX Actions" msgstr "إجراءات تجربة المريض" +#: templates/complaints/complaint_detail.html:264 +msgid "AI Mapped" +msgstr "تم التعيين بواسطة الذكاء الاصطناعي" + #: templates/complaints/complaint_detail.html:276 msgid "Staff Member" msgstr "موظف" +#: templates/complaints/complaint_detail.html:290 +msgid "AI Matched" +msgstr "مطابق بالذكاء الاصطناعي" + +#: templates/complaints/complaint_detail.html:296 +msgid "Extracted from complaint" +msgstr "مستخرج من الشكوى" + +#: templates/complaints/complaint_detail.html:298 +#: templates/complaints/complaint_detail.html:350 +msgid "confidence" +msgstr "مستوى الثقة" + +#: templates/complaints/complaint_detail.html:313 +msgid "Staff Suggestions" +msgstr "اقتراحات الموظفين" + +#: templates/complaints/complaint_detail.html:315 +msgid "Needs Review" +msgstr "بحاجة إلى مراجعة" + +#: templates/complaints/complaint_detail.html:321 +msgid "AI extracted name" +msgstr "اسم مستخرج بالذكاء الاصطناعي" + +#: templates/complaints/complaint_detail.html:322 +msgid "potential match" +msgstr "تطابق محتمل" + +#: templates/complaints/complaint_detail.html:322 +msgid "No matches found" +msgstr "لم يتم العثور على تطابقات" + +#: templates/complaints/complaint_detail.html:354 +msgid "Currently assigned" +msgstr "مُعيّن حاليًا" + +#: templates/complaints/complaint_detail.html:358 +msgid "Select" +msgstr "اختيار" + +#: templates/complaints/complaint_detail.html:369 +msgid "Search All Staff" +msgstr "البحث في جميع الموظفين" + +#: templates/complaints/complaint_detail.html:392 +msgid "AI Analysis" +msgstr "تحليل الذكاء الاصطناعي" + +#: templates/complaints/complaint_detail.html:394 +msgid "AI Generated" +msgstr "تم إنشاؤه بالذكاء الاصطناعي" + +#: templates/complaints/complaint_detail.html:400 +msgid "Emotion Analysis" +msgstr "تحليل المشاعر" + +#: templates/complaints/complaint_detail.html:415 +msgid "Intensity" +msgstr "الشدة" + +#: templates/complaints/complaint_detail.html:439 +msgid "Summary" +msgstr "ملخص" + +#: templates/complaints/complaint_detail.html:449 +msgid "Suggested Action" +msgstr "الإجراء المقترح" + +#: templates/complaints/complaint_detail.html:455 +#: templates/observations/convert_to_action.html:94 +msgid "Create PX Action" +msgstr "إنشاء إجراء PX" + #: templates/complaints/complaint_detail.html:465 msgid "Resolution" msgstr "الحل" @@ -3810,10 +3894,132 @@ msgstr "تصعيد الشكوى" msgid "This will escalate" msgstr "سيتم التصعيد" +#: templates/complaints/complaint_detail.html:838 +#, fuzzy +#| msgid "Checklist Items Management" +msgid "complaint to higher management" +msgstr "إدارة عناصر قائمة التحقق" + #: templates/complaints/complaint_detail.html:843 msgid "Explain why this complaint needs escalation..." msgstr "اشرح سبب حاجة هذه الشكوى إلى التصعيد..." +#: templates/complaints/complaint_detail.html:863 +#, fuzzy +#| msgid "Create PX Action" +msgid "Create PX Action from AI Suggestion" +msgstr "إنشاء إجراء PX" + +#: templates/complaints/complaint_detail.html:870 +msgid "This will create a PX Action based on the AI-suggested action for this complaint" +msgstr "سيؤدي هذا إلى إنشاء إجراء PX بناءً على الإجراء المقترح بالذكاء الاصطناعي لهذه الشكوى" + +msgid "Auto-mapped Category" +msgstr "فئة معينة تلقائيًا" + +msgid "Category automatically mapped from complaint category" +msgstr "تم تعيين الفئة تلقائيًا من فئة الشكوى" + +#: templates/complaints/complaint_detail.html:886 +#, fuzzy +#| msgid "Rating (Optional)" +msgid "Assign To (Optional)" +msgstr "التقييم (اختياري)" + +#: templates/complaints/complaint_detail.html:888 +#, fuzzy +#| msgid "Unassigned" +msgid "Leave unassigned" +msgstr "غير معين" + +#: templates/complaints/complaint_detail.html:893 +msgid "If left unassigned, you can assign the action later" +msgstr "إذا تُرك بدون تعيين، يمكنك تعيين الإجراء لاحقًا" + +#: templates/complaints/complaint_detail.html:897 +#, fuzzy +#| msgid "Description" +msgid "Action Description" +msgstr "الوصف" + +#: templates/complaints/complaint_detail.html:906 +#, fuzzy +#| msgid "Create PX Action" +msgid "Create Action" +msgstr "إنشاء إجراء PX" + +#: templates/complaints/complaint_detail.html:919 +#, fuzzy +#| msgid "Staff Member" +msgid "Select Staff Member" +msgstr "موظف" + +#: templates/complaints/complaint_detail.html:927 +#, fuzzy +#| msgid "Compliance by Department" +msgid "Filter by Department" +msgstr "الامتثال حسب القسم" + +#: templates/complaints/complaint_detail.html:933 +#, fuzzy +#| msgid "Search All Staff" +msgid "Search Staff" +msgstr "البحث في جميع الموظفين" + +#: templates/complaints/complaint_detail.html:963 +#, fuzzy +#| msgid "Send Notification" +msgid "Send Complaint Notification" +msgstr "إرسال إشعار" + +#: templates/complaints/complaint_detail.html:972 +#, fuzzy +#| msgid "Summary" +msgid "AI Summary" +msgstr "ملخص" + +#: templates/complaints/complaint_detail.html:973 +msgid "you can edit this before sending" +msgstr "يمكنك تعديل هذا قبل الإرسال" + +msgid "This is AI-generated summary. You can edit it before sending" +msgstr "هذا ملخص تم إنشاؤه بالذكاء الاصطناعي. يمكنك تعديله قبل الإرسال" + +msgid "Staff Member Assigned" +msgstr "تم تعيين الموظف" + +msgid "This staff member has no user account in the system" +msgstr "هذا الموظف لا يملك حساب مستخدم في النظام" + +#: templates/complaints/complaint_detail.html:1019 +#, fuzzy +#| msgid "Department View" +msgid "Department Head of" +msgstr "عرض الأقسام" + +#: templates/complaints/complaint_detail.html:1025 +#: templates/complaints/complaint_detail.html:1042 +#, fuzzy +#| msgid "No rating history available" +msgid "No recipient available" +msgstr "لا يوجد سجل تقييمات" + +#: templates/complaints/complaint_detail.html:1026 +msgid "The assigned staff has no user account and no department manager is set" +msgstr "الموظف المعيّن لا يملك حساب مستخدم ولا يوجد مدير قسم محدد" + +msgid "Manager of" +msgstr "مدير" + +msgid "No staff or department manager assigned to this complaint" +msgstr "لم يتم تعيين موظف أو مدير قسم لهذه الشكوى" + +msgid "Additional Message (Optional)" +msgstr "رسالة إضافية (اختياري)" + +msgid "Send Email" +msgstr "إرسال البريد الإلكتروني" + #: templates/complaints/complaint_form.html:5 #: templates/complaints/complaint_list.html:94 msgid "New Complaint" @@ -5005,10 +5211,6 @@ msgstr "تعيين إلى القسم" msgid "Assign to User" msgstr "تعيين إلى المستخدم" -#: templates/observations/convert_to_action.html:94 -msgid "Create PX Action" -msgstr "إنشاء إجراء PX" - #: templates/observations/observation_detail.html:5 msgid "Observation Detail" msgstr "تفاصيل الملاحظة" diff --git a/templates/complaints/complaint_detail.html b/templates/complaints/complaint_detail.html index d80eaf3..92c8ac3 100644 --- a/templates/complaints/complaint_detail.html +++ b/templates/complaints/complaint_detail.html @@ -261,7 +261,7 @@ {% if complaint.metadata.ai_analysis.old_department %} - AI Mapped + {{ _("AI Mapped")}} {% endif %} @@ -287,15 +287,15 @@ {% endif %} - AI Matched + {{ _("AI Matched")}} {% if complaint.metadata.ai_analysis.extracted_staff_name %} - Extracted from complaint: "{{ complaint.metadata.ai_analysis.extracted_staff_name }}" + {{ _("Extracted from complaint")}}: "{{ complaint.metadata.ai_analysis.extracted_staff_name }}" {% if complaint.metadata.ai_analysis.staff_confidence %} - (confidence: {{ complaint.metadata.ai_analysis.staff_confidence|floatformat:0 }}%) + ({{ _("confidence") }}: {{ complaint.metadata.ai_analysis.staff_confidence|floatformat:0 }}%) {% endif %} {% endif %} @@ -310,16 +310,16 @@
- Staff Suggestions + {{ _("Staff Suggestions")}} {% if complaint.metadata.ai_analysis.needs_staff_review %} - Needs Review + {{ _("Needs Review")}} {% endif %}
{% if complaint.metadata.ai_analysis.extracted_staff_name %}

- AI extracted name: "{{ complaint.metadata.ai_analysis.extracted_staff_name }}" - ({% if complaint.metadata.ai_analysis.staff_match_count %}{{ complaint.metadata.ai_analysis.staff_match_count }} potential match{{ complaint.metadata.ai_analysis.staff_match_count|pluralize }}{% else %}No matches found{% endif %}) + {{ _("AI extracted name")}}: "{{ complaint.metadata.ai_analysis.extracted_staff_name }}" + ({% if complaint.metadata.ai_analysis.staff_match_count %}{{ complaint.metadata.ai_analysis.staff_match_count }}{{ _("potential match")}}{{ complaint.metadata.ai_analysis.staff_match_count|pluralize }}{% else %}{{ _("No matches found")}}{% endif %})

{% endif %} @@ -347,15 +347,15 @@
- {{ staff_match.confidence|mul:100|floatformat:0 }}% confidence + {{ staff_match.confidence|mul:100|floatformat:0 }}% {{ _("confidence") }} {% if complaint.staff and staff_match.id == complaint.staff.id|stringformat:"s" %}
- Currently assigned + {{ _("Currently assigned")}}
{% elif not complaint.staff %} {% endif %}
@@ -366,7 +366,7 @@
@@ -384,20 +384,20 @@ - {% if complaint.short_description or complaint.suggested_action %} + {% if complaint.short_description_ar or complaint.suggested_action_ar %}
- AI Analysis + {{ _("AI Analysis")}}
- AI Generated + {{ _("AI Generated")}}
{% if complaint.emotion %}
-
Emotion Analysis
+
{{ _("Emotion Analysis")}}
@@ -407,12 +407,12 @@
- Confidence: {{ complaint.emotion_confidence|mul:100|floatformat:0 }}% + {{ _("Confidence") }}: {{ complaint.emotion_confidence|mul:100|floatformat:0 }}%
- Intensity + {{ _("Intensity") }} {{ complaint.emotion_intensity|floatformat:2 }} / 1.0
@@ -434,25 +434,25 @@
{% endif %} - {% if complaint.short_description %} + {% if complaint.short_description_ar %}
-
Summary
+
{{ _("Summary") }}
- {{ complaint.short_description }} + {{ complaint.short_description_ar }}
{% endif %} - {% if complaint.suggested_action %} + {% if complaint.suggested_action_ar %}
-
Suggested Action
+
{{ _("Suggested Action")}}
- {{ complaint.suggested_action }} + {{ complaint.suggested_action_ar }}
{% endif %} @@ -835,7 +835,7 @@