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 399b7de..1aaef6f 100644 Binary files a/dump.rdb and b/dump.rdb differ diff --git a/locale/ar/LC_MESSAGES/django.mo b/locale/ar/LC_MESSAGES/django.mo index fd56e67..7b19972 100644 Binary files a/locale/ar/LC_MESSAGES/django.mo and b/locale/ar/LC_MESSAGES/django.mo differ 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 @@
- 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 @@