export
This commit is contained in:
parent
b3d9bd17cb
commit
d787d41bc9
1
.~lock.Doctor_Rating.csv#
Normal file
1
.~lock.Doctor_Rating.csv#
Normal file
@ -0,0 +1 @@
|
||||
,ismail,ismail-Latitude-5500,25.02.2026 04:28,/home/ismail/.local/share/onlyoffice;
|
||||
131
apps/core/management/commands/export_data.py
Normal file
131
apps/core/management/commands/export_data.py
Normal file
@ -0,0 +1,131 @@
|
||||
"""
|
||||
Management command to export database data to JSON files.
|
||||
|
||||
Usage:
|
||||
python manage.py export_data --output-dir=./exported_data
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.apps import apps
|
||||
from django.core.serializers import serialize
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Export database data to JSON files'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--output-dir',
|
||||
type=str,
|
||||
default='./exported_data',
|
||||
help='Directory to export JSON files to'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--apps',
|
||||
type=str,
|
||||
nargs='+',
|
||||
help='Specific apps to export (e.g., complaints organizations accounts)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--exclude-apps',
|
||||
type=str,
|
||||
nargs='+',
|
||||
default=['contenttypes', 'auth', 'admin', 'sessions', 'django_celery_beat'],
|
||||
help='Apps to exclude from export'
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
output_dir = options['output_dir']
|
||||
include_apps = options['apps']
|
||||
exclude_apps = options['exclude_apps']
|
||||
|
||||
# Create output directory
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# Get all models
|
||||
all_models = apps.get_models()
|
||||
|
||||
# Group models by app
|
||||
models_by_app = {}
|
||||
for model in all_models:
|
||||
app_label = model._meta.app_label
|
||||
|
||||
# Skip excluded apps
|
||||
if app_label in exclude_apps:
|
||||
continue
|
||||
|
||||
# Skip if specific apps requested and this isn't one of them
|
||||
if include_apps and app_label not in include_apps:
|
||||
continue
|
||||
|
||||
if app_label not in models_by_app:
|
||||
models_by_app[app_label] = []
|
||||
models_by_app[app_label].append(model)
|
||||
|
||||
# Export data
|
||||
total_exported = 0
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f'Exporting data to: {output_dir}'))
|
||||
self.stdout.write(f'Found {len(models_by_app)} apps to export\n')
|
||||
|
||||
for app_label, models in models_by_app.items():
|
||||
app_dir = os.path.join(output_dir, app_label)
|
||||
os.makedirs(app_dir, exist_ok=True)
|
||||
|
||||
app_data = {}
|
||||
app_count = 0
|
||||
|
||||
for model in models:
|
||||
model_name = model._meta.model_name
|
||||
|
||||
# Skip models with no records
|
||||
count = model.objects.count()
|
||||
if count == 0:
|
||||
continue
|
||||
|
||||
try:
|
||||
# Serialize to JSON
|
||||
data = serialize('json', model.objects.all())
|
||||
app_data[model_name] = {
|
||||
'count': count,
|
||||
'data': json.loads(data)
|
||||
}
|
||||
app_count += count
|
||||
total_exported += count
|
||||
|
||||
self.stdout.write(f' ✓ {app_label}.{model_name}: {count} records')
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.WARNING(f' ⊘ {app_label}.{model_name}: Error - {str(e)}'))
|
||||
|
||||
# Write app data to file
|
||||
if app_data:
|
||||
output_file = os.path.join(app_dir, f'{app_label}_data.json')
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
json.dump({
|
||||
'app': app_label,
|
||||
'exported_at': timestamp,
|
||||
'total_records': app_count,
|
||||
'models': app_data
|
||||
}, f, indent=2, ensure_ascii=False)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f' → Exported to: {output_file}\n'))
|
||||
|
||||
# Create summary file
|
||||
summary_file = os.path.join(output_dir, 'export_summary.json')
|
||||
with open(summary_file, 'w', encoding='utf-8') as f:
|
||||
json.dump({
|
||||
'exported_at': timestamp,
|
||||
'total_records': total_exported,
|
||||
'apps_exported': list(models_by_app.keys()),
|
||||
'output_directory': output_dir
|
||||
}, f, indent=2)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('\n' + '=' * 60))
|
||||
self.stdout.write(self.style.SUCCESS(f'EXPORT COMPLETE'))
|
||||
self.stdout.write(self.style.SUCCESS(f'Total records exported: {total_exported}'))
|
||||
self.stdout.write(self.style.SUCCESS(f'Output directory: {output_dir}'))
|
||||
self.stdout.write(self.style.SUCCESS(f'Summary file: {summary_file}'))
|
||||
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||||
@ -61,7 +61,7 @@ class Command(BaseCommand):
|
||||
|
||||
survey = SurveyTemplate.objects.create(
|
||||
name=name,
|
||||
description=f'{name} for patient feedback collection',
|
||||
name_ar=name,
|
||||
hospital=hospital,
|
||||
survey_type='general',
|
||||
is_active=True
|
||||
|
||||
@ -212,8 +212,11 @@ class Command(BaseCommand):
|
||||
|
||||
subsections_to_create = []
|
||||
|
||||
# Clear existing data to prevent old ID conflicts
|
||||
SubSection.objects.all().delete()
|
||||
# Clear existing data to prevent old ID conflicts (skip if referenced)
|
||||
try:
|
||||
SubSection.objects.all().delete()
|
||||
except Exception:
|
||||
self.stdout.write(self.style.WARNING('Skipping SubSection deletion - some are referenced by complaints'))
|
||||
|
||||
for item in subsections_data:
|
||||
subsections_to_create.append(
|
||||
|
||||
@ -322,9 +322,18 @@ def doctor_rating_job_status(request, job_id):
|
||||
messages.error(request, "You don't have permission to view this job.")
|
||||
return redirect('physicians:physician_list')
|
||||
|
||||
# Calculate progress circle stroke-dashoffset
|
||||
# Circle circumference is 326.73 (2 * pi * r, where r=52)
|
||||
# When progress is 0%, offset should be 326.73 (empty)
|
||||
# When progress is 100%, offset should be 0 (full)
|
||||
circumference = 2 * 3.14159 * 52 # ~326.73
|
||||
progress = job.progress_percentage
|
||||
stroke_dashoffset = circumference * (1 - progress / 100)
|
||||
|
||||
context = {
|
||||
'job': job,
|
||||
'progress': job.progress_percentage,
|
||||
'progress': progress,
|
||||
'stroke_dashoffset': stroke_dashoffset,
|
||||
'is_complete': job.is_complete,
|
||||
'results': job.results,
|
||||
}
|
||||
|
||||
205
database_export/accounts/accounts_data.json
Normal file
205
database_export/accounts/accounts_data.json
Normal file
@ -0,0 +1,205 @@
|
||||
{
|
||||
"app": "accounts",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 5,
|
||||
"models": {
|
||||
"user": {
|
||||
"count": 5,
|
||||
"data": [
|
||||
{
|
||||
"model": "accounts.user",
|
||||
"pk": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$1200000$jlJ1yPpFCioF510zF41nvd$LZeZlcG2wHPippD8ugCE6D00UbvwtlWniIfRFwY6gd8=",
|
||||
"last_login": "2026-02-25T03:59:57.279Z",
|
||||
"is_superuser": false,
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_staff": false,
|
||||
"date_joined": "2026-02-25T03:58:30.702Z",
|
||||
"created_at": "2026-02-25T03:58:31.405Z",
|
||||
"updated_at": "2026-02-25T03:59:32.986Z",
|
||||
"email": "admin@hh.sa",
|
||||
"username": "",
|
||||
"phone": "",
|
||||
"employee_id": "",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"department": null,
|
||||
"avatar": "",
|
||||
"bio": "",
|
||||
"language": "en",
|
||||
"notification_email_enabled": true,
|
||||
"notification_sms_enabled": false,
|
||||
"preferred_notification_channel": "email",
|
||||
"explanation_notification_channel": "email",
|
||||
"is_active": true,
|
||||
"is_provisional": false,
|
||||
"invitation_token": null,
|
||||
"invitation_expires_at": null,
|
||||
"acknowledgement_completed": false,
|
||||
"acknowledgement_completed_at": null,
|
||||
"current_wizard_step": 0,
|
||||
"wizard_completed_steps": [],
|
||||
"groups": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"user_permissions": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "accounts.user",
|
||||
"pk": "f6d00141-47c6-4c96-863e-e91c39e2da87",
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$1200000$bDscjx2gPBbHeAPFwRIi8b$Hgj8Ce+H5TeCquyweT9MA7WlyJOCtwYdN26NmMJ3EEM=",
|
||||
"last_login": "2026-02-25T04:12:09.315Z",
|
||||
"is_superuser": true,
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_staff": true,
|
||||
"date_joined": "2026-02-25T03:57:07.977Z",
|
||||
"created_at": "2026-02-25T03:57:08.653Z",
|
||||
"updated_at": "2026-02-25T03:57:08.653Z",
|
||||
"email": "ismail@tenhal.sa",
|
||||
"username": "",
|
||||
"phone": "",
|
||||
"employee_id": "",
|
||||
"hospital": null,
|
||||
"department": null,
|
||||
"avatar": "",
|
||||
"bio": "",
|
||||
"language": "en",
|
||||
"notification_email_enabled": true,
|
||||
"notification_sms_enabled": false,
|
||||
"preferred_notification_channel": "email",
|
||||
"explanation_notification_channel": "email",
|
||||
"is_active": true,
|
||||
"is_provisional": false,
|
||||
"invitation_token": null,
|
||||
"invitation_expires_at": null,
|
||||
"acknowledgement_completed": false,
|
||||
"acknowledgement_completed_at": null,
|
||||
"current_wizard_step": 0,
|
||||
"wizard_completed_steps": [],
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "accounts.user",
|
||||
"pk": "a5d0077d-f2a7-4069-93fd-d35bdc20d314",
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$1200000$aTXoF4T51QdQgp1QCw9apP$h5sEYLfp3Re9H2dWEc4aHjLPHwnlKgG9PFol0oE18Us=",
|
||||
"last_login": null,
|
||||
"is_superuser": false,
|
||||
"first_name": "Amaal",
|
||||
"last_name": "Al Otaibi",
|
||||
"is_staff": true,
|
||||
"date_joined": "2026-02-25T03:54:37.064Z",
|
||||
"created_at": "2026-02-25T03:54:37.065Z",
|
||||
"updated_at": "2026-02-25T03:54:37.742Z",
|
||||
"email": "amaal@example.com",
|
||||
"username": "amaal",
|
||||
"phone": "",
|
||||
"employee_id": "",
|
||||
"hospital": null,
|
||||
"department": null,
|
||||
"avatar": "",
|
||||
"bio": "",
|
||||
"language": "en",
|
||||
"notification_email_enabled": true,
|
||||
"notification_sms_enabled": false,
|
||||
"preferred_notification_channel": "email",
|
||||
"explanation_notification_channel": "email",
|
||||
"is_active": true,
|
||||
"is_provisional": false,
|
||||
"invitation_token": null,
|
||||
"invitation_expires_at": null,
|
||||
"acknowledgement_completed": false,
|
||||
"acknowledgement_completed_at": null,
|
||||
"current_wizard_step": 0,
|
||||
"wizard_completed_steps": [],
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "accounts.user",
|
||||
"pk": "d3919bb3-37a2-4cfb-9efa-5ca2b67ba91d",
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$1200000$Sv7iDXpGVYzXw4BpFqXqjE$Ioq0F6Y2nly/eFwBI22KAk44qZqbhjkwSaN3hIhhxMQ=",
|
||||
"last_login": null,
|
||||
"is_superuser": false,
|
||||
"first_name": "Abrar",
|
||||
"last_name": "Al Qahtani",
|
||||
"is_staff": true,
|
||||
"date_joined": "2026-02-25T03:54:36.403Z",
|
||||
"created_at": "2026-02-25T03:54:36.403Z",
|
||||
"updated_at": "2026-02-25T03:54:37.056Z",
|
||||
"email": "abrar@example.com",
|
||||
"username": "abrar",
|
||||
"phone": "",
|
||||
"employee_id": "",
|
||||
"hospital": null,
|
||||
"department": null,
|
||||
"avatar": "",
|
||||
"bio": "",
|
||||
"language": "en",
|
||||
"notification_email_enabled": true,
|
||||
"notification_sms_enabled": false,
|
||||
"preferred_notification_channel": "email",
|
||||
"explanation_notification_channel": "email",
|
||||
"is_active": true,
|
||||
"is_provisional": false,
|
||||
"invitation_token": null,
|
||||
"invitation_expires_at": null,
|
||||
"acknowledgement_completed": false,
|
||||
"acknowledgement_completed_at": null,
|
||||
"current_wizard_step": 0,
|
||||
"wizard_completed_steps": [],
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "accounts.user",
|
||||
"pk": "09a84636-411a-4cd2-aa26-80abd29b1dfd",
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$1200000$B6QHfxbMf2KC4kwdU4sVTf$3CLPDxTIhk6HujEaBJqTA9XdUWjqiywnrqXSsoi+ZJI=",
|
||||
"last_login": null,
|
||||
"is_superuser": false,
|
||||
"first_name": "Rahaf",
|
||||
"last_name": "Al Saud",
|
||||
"is_staff": true,
|
||||
"date_joined": "2026-02-25T03:54:35.738Z",
|
||||
"created_at": "2026-02-25T03:54:35.738Z",
|
||||
"updated_at": "2026-02-25T03:54:36.382Z",
|
||||
"email": "rahaf@example.com",
|
||||
"username": "rahaf",
|
||||
"phone": "",
|
||||
"employee_id": "",
|
||||
"hospital": null,
|
||||
"department": null,
|
||||
"avatar": "",
|
||||
"bio": "",
|
||||
"language": "en",
|
||||
"notification_email_enabled": true,
|
||||
"notification_sms_enabled": false,
|
||||
"preferred_notification_channel": "email",
|
||||
"explanation_notification_channel": "email",
|
||||
"is_active": true,
|
||||
"is_provisional": false,
|
||||
"invitation_token": null,
|
||||
"invitation_expires_at": null,
|
||||
"acknowledgement_completed": false,
|
||||
"acknowledgement_completed_at": null,
|
||||
"current_wizard_step": 0,
|
||||
"wizard_completed_steps": [],
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
786
database_export/ai_engine/ai_engine_data.json
Normal file
786
database_export/ai_engine/ai_engine_data.json
Normal file
@ -0,0 +1,786 @@
|
||||
{
|
||||
"app": "ai_engine",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 26,
|
||||
"models": {
|
||||
"sentimentresult": {
|
||||
"count": 26,
|
||||
"data": [
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "ea4d89ac-33ee-4101-8f83-611c493ee679",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:09:40.733Z",
|
||||
"updated_at": "2026-02-25T05:09:40.733Z",
|
||||
"content_type": 57,
|
||||
"object_id": "44e5ce09-a956-474a-a46e-9b79508c6633",
|
||||
"text": "Complaint activated and assigned to ",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "fa5878fb-afc3-4ea0-9027-fd26bf53f9fd",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:09:40.722Z",
|
||||
"updated_at": "2026-02-25T05:09:40.722Z",
|
||||
"content_type": 42,
|
||||
"object_id": "8bbf4733-34c8-4dc0-a440-50ac4ab90a22",
|
||||
"text": "Despite pressing the call button multiple times, nurse Fahd Al-Shehri did not respond for over 30 minutes. When she finally arrived, she was annoyed and unhelpful. This level of neglect is unacceptable in a healthcare setting.",
|
||||
"language": "en",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 1,
|
||||
"keywords": [
|
||||
"helpful"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "72c5e3cc-fd0f-4c6b-b78a-2a7685cba595",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.061Z",
|
||||
"updated_at": "2026-02-25T03:55:42.061Z",
|
||||
"content_type": 57,
|
||||
"object_id": "cfdae30f-9ce2-4484-9363-b98cc19a1418",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "95322885-d654-4b2b-96b8-bebd006b6eda",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.059Z",
|
||||
"updated_at": "2026-02-25T03:55:42.059Z",
|
||||
"content_type": 42,
|
||||
"object_id": "8bbf4733-34c8-4dc0-a440-50ac4ab90a22",
|
||||
"text": "Despite pressing the call button multiple times, nurse Fahd Al-Shehri did not respond for over 30 minutes. When she finally arrived, she was annoyed and unhelpful. This level of neglect is unacceptable in a healthcare setting.",
|
||||
"language": "en",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"helpful"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "d84a5a6c-f657-4d18-8e26-b77cda67284d",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.045Z",
|
||||
"updated_at": "2026-02-25T03:55:42.045Z",
|
||||
"content_type": 57,
|
||||
"object_id": "7295f18f-83c8-4542-94ad-39efca68d7fe",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "382d0da3-1fd3-40b7-8b6d-7265f71795ec",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.042Z",
|
||||
"updated_at": "2026-02-25T03:55:42.042Z",
|
||||
"content_type": 42,
|
||||
"object_id": "1f76952f-4fb6-4eaf-9fd8-2cc441e4ca07",
|
||||
"text": "Dr. Noura Al-Harbi misdiagnosed my condition and prescribed wrong medication. I had to suffer for 3 more days before another doctor caught the error. This negligence is unacceptable and needs to be addressed immediately.",
|
||||
"language": "en",
|
||||
"sentiment": "neutral",
|
||||
"sentiment_score": "0.0000",
|
||||
"confidence": "0.5000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "b3ed5f77-0be3-437a-ac22-72c96a40a346",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.017Z",
|
||||
"updated_at": "2026-02-25T03:55:42.017Z",
|
||||
"content_type": 57,
|
||||
"object_id": "56287023-2c03-4eda-b168-788a1a079cea",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "8337d5c0-5e53-4f51-86c0-f0a7954139ea",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.009Z",
|
||||
"updated_at": "2026-02-25T03:55:42.009Z",
|
||||
"content_type": 42,
|
||||
"object_id": "f4096f2b-81ba-4eee-8ac8-3ad0bded1797",
|
||||
"text": "Dr. Mishari Al-Fahad provided exceptional care and took the time to thoroughly explain my condition and treatment options. His expertise and bedside manner were outstanding.",
|
||||
"language": "en",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"outstanding"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "71863e9f-5168-44e6-bc11-f2880645a301",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.006Z",
|
||||
"updated_at": "2026-02-25T03:55:42.006Z",
|
||||
"content_type": 57,
|
||||
"object_id": "482902ef-7711-43a3-9ed9-a3b56369e591",
|
||||
"text": "SMS notification sent to complainant: Your complaint has been received",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "f5ab6f53-6075-42c4-a08f-0274d33b8cb6",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.962Z",
|
||||
"updated_at": "2026-02-25T03:55:36.962Z",
|
||||
"content_type": 57,
|
||||
"object_id": "0db0aac0-bbfb-4aaa-b648-e0aff5b3479d",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "adb28a27-56df-4ee2-a12b-01208399fb5d",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.957Z",
|
||||
"updated_at": "2026-02-25T03:55:36.957Z",
|
||||
"content_type": 42,
|
||||
"object_id": "1fec51ec-ab1c-4c04-9cc4-7d3cf371940d",
|
||||
"text": "هناك مواقف سيارات محدودة جداً للزوار. اضطررت للدوران عدة مرات لإيجاد مكان وتأخرت عن موعدي. هذا يجب معالجته.",
|
||||
"language": "ar",
|
||||
"sentiment": "neutral",
|
||||
"sentiment_score": "0.0000",
|
||||
"confidence": "0.5000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "4151d62a-1de3-47f7-bf32-e8bd29293853",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.941Z",
|
||||
"updated_at": "2026-02-25T03:55:36.941Z",
|
||||
"content_type": 57,
|
||||
"object_id": "4fd1fc88-7e8e-4602-ae4c-bd7a6778438a",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "b0848bb7-2868-4706-b308-f6147ebba138",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.938Z",
|
||||
"updated_at": "2026-02-25T03:55:36.938Z",
|
||||
"content_type": 42,
|
||||
"object_id": "9da3b845-c425-4bf1-b413-1d10fc1a150d",
|
||||
"text": "أريد أن أعبر عن تقديري للممرضة جواهر الحربي التي بذلت ما هو أبعد من المتوقع لجعلي مرتاحاً خلال إقامتي. كلمتها اللطيفة والراعية جعلت الموقف الصعب أكثر قابلية للتحمل.",
|
||||
"language": "ar",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"لطيف"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "88b78567-89a1-4513-a792-4796b892dde2",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.937Z",
|
||||
"updated_at": "2026-02-25T03:55:36.937Z",
|
||||
"content_type": 57,
|
||||
"object_id": "7a094b69-80bf-4779-8dea-a0164186df14",
|
||||
"text": "SMS notification sent to complainant: Your complaint has been received",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "4e4b9d1c-b790-4b44-9f2f-3b072f0495a9",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.892Z",
|
||||
"updated_at": "2026-02-25T03:55:31.893Z",
|
||||
"content_type": 57,
|
||||
"object_id": "4512b975-e55c-4a6b-9d97-710e855ba791",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "19883722-8435-4e3a-9edf-b36eb65455a3",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.883Z",
|
||||
"updated_at": "2026-02-25T03:55:31.883Z",
|
||||
"content_type": 42,
|
||||
"object_id": "c674b99c-06b3-40c2-9812-0fec40d43ea5",
|
||||
"text": "جودة طعام المستشفى انخفضت بشكل كبير. الوجبات غالباً باردة وغير شهية ولا تلبي المتطلبات الغذائية. هذا يؤثر على رضا المرضى.",
|
||||
"language": "ar",
|
||||
"sentiment": "neutral",
|
||||
"sentiment_score": "0.0000",
|
||||
"confidence": "0.5000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "f47bbd0f-3f0b-400f-8b56-b8fb3bbb83e0",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.867Z",
|
||||
"updated_at": "2026-02-25T03:55:31.867Z",
|
||||
"content_type": 57,
|
||||
"object_id": "7237e1e7-0a25-4057-98ec-b1ac5e218c4f",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "0f6095d8-0db3-4782-ab0e-50fb6da57077",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.863Z",
|
||||
"updated_at": "2026-02-25T03:55:31.863Z",
|
||||
"content_type": 42,
|
||||
"object_id": "c020e66f-0f9a-42ac-9b86-a740d340cd2d",
|
||||
"text": "عندما تم قبولي في غرفتي، لم تكن نظيفة بشكل صحيح. كان هناك غبار على الأسطح وحمام غير صحي. هذا مصدر قلق لسلامة المرضى.",
|
||||
"language": "ar",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"نظيف"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.2,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "726b916a-7804-4d32-9fef-6cfcb9518599",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.851Z",
|
||||
"updated_at": "2026-02-25T03:55:31.852Z",
|
||||
"content_type": 57,
|
||||
"object_id": "09cd1726-8993-4ae4-bae9-40702333d800",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "c5e1627d-825b-4ea0-b0b7-26bb0008c721",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.848Z",
|
||||
"updated_at": "2026-02-25T03:55:31.848Z",
|
||||
"content_type": 42,
|
||||
"object_id": "312155d3-b384-4e6f-b2e7-f8bd21e7817b",
|
||||
"text": "عندما تم قبولي في غرفتي، لم تكن نظيفة بشكل صحيح. كان هناك غبار على الأسطح وحمام غير صحي. هذا مصدر قلق لسلامة المرضى.",
|
||||
"language": "ar",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"نظيف"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.2,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "f0c8d663-8f7b-40d4-8429-deb6b88e0556",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.846Z",
|
||||
"updated_at": "2026-02-25T03:55:31.846Z",
|
||||
"content_type": 57,
|
||||
"object_id": "f226476d-c5e0-4726-8ece-1cfab6bfa0ff",
|
||||
"text": "SMS notification sent to complainant: Your complaint has been received",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "cef2911a-be2c-46a7-9d2a-67d524e6d880",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:26.807Z",
|
||||
"updated_at": "2026-02-25T03:55:26.807Z",
|
||||
"content_type": 57,
|
||||
"object_id": "d5fb457f-7d7b-4485-b0fe-e0b6ce52880c",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "66e6d7dd-0dbc-4467-8c41-bda4e6a20563",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:26.796Z",
|
||||
"updated_at": "2026-02-25T03:55:26.796Z",
|
||||
"content_type": 42,
|
||||
"object_id": "4f11f759-8061-427d-899b-e0c360d11a20",
|
||||
"text": "على الرغم من الضغط على زر الاستدعاء عدة مرات، لم تستجب الممرضة نورة الفالح لأكثر من 30 دقيقة. عندما وصلت أخيراً، كانت منزعجة وغير مفيدة. هذا مستوى من الإهمال غير مقبول في بيئة الرعاية الصحية.",
|
||||
"language": "ar",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"مفيد"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "9a213f8f-02c7-4ad3-9b29-2fe35d09b40d",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:26.790Z",
|
||||
"updated_at": "2026-02-25T03:55:26.791Z",
|
||||
"content_type": 57,
|
||||
"object_id": "51ec2c79-a504-437c-97a3-ddce7f1d65d8",
|
||||
"text": "SMS notification sent to complainant: Your complaint has been received",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 2,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "603917ee-a90b-4cd1-a8b6-06ee32e9f8ab",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.596Z",
|
||||
"updated_at": "2026-02-25T03:55:21.596Z",
|
||||
"content_type": 57,
|
||||
"object_id": "dbb70f16-8f80-4a63-8207-cd55bf2e8226",
|
||||
"text": "Complaint created and registered",
|
||||
"language": "en",
|
||||
"sentiment": "negative",
|
||||
"sentiment_score": "-1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"complaint"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "ai_engine.sentimentresult",
|
||||
"pk": "7b7440ee-5de5-46b3-81b4-37ac9d5d0680",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.592Z",
|
||||
"updated_at": "2026-02-25T03:55:21.592Z",
|
||||
"content_type": 42,
|
||||
"object_id": "75699d55-58b8-42d2-94c3-ff479a005dad",
|
||||
"text": "أريد أن أعبر عن تقديري للممرضة علي العنزي التي بذلت ما هو أبعد من المتوقع لجعلي مرتاحاً خلال إقامتي. كلمتها اللطيفة والراعية جعلت الموقف الصعب أكثر قابلية للتحمل.",
|
||||
"language": "ar",
|
||||
"sentiment": "positive",
|
||||
"sentiment_score": "1.0000",
|
||||
"confidence": "0.3000",
|
||||
"ai_service": "stub",
|
||||
"ai_model": "keyword_matching_v1",
|
||||
"processing_time_ms": 0,
|
||||
"keywords": [
|
||||
"لطيف"
|
||||
],
|
||||
"entities": [],
|
||||
"emotions": {
|
||||
"joy": 0.0,
|
||||
"anger": 0.0,
|
||||
"sadness": 0.0,
|
||||
"fear": 0.0,
|
||||
"surprise": 0.0
|
||||
},
|
||||
"metadata": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
914
database_export/analytics/analytics_data.json
Normal file
914
database_export/analytics/analytics_data.json
Normal file
@ -0,0 +1,914 @@
|
||||
{
|
||||
"app": "analytics",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 47,
|
||||
"models": {
|
||||
"kpireport": {
|
||||
"count": 3,
|
||||
"data": [
|
||||
{
|
||||
"model": "analytics.kpireport",
|
||||
"pk": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:53.918Z",
|
||||
"updated_at": "2026-02-25T05:06:54.114Z",
|
||||
"report_type": "activation_2h",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"year": 2026,
|
||||
"month": 2,
|
||||
"report_date": "2026-02-25",
|
||||
"status": "completed",
|
||||
"generated_by": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"generated_at": "2026-02-25T05:06:54.114Z",
|
||||
"target_percentage": "95.00",
|
||||
"category": "Organizational",
|
||||
"kpi_type": "Outcome",
|
||||
"risk_level": "High",
|
||||
"data_collection_method": "Retrospective",
|
||||
"data_collection_frequency": "Monthly",
|
||||
"reporting_frequency": "Monthly",
|
||||
"dimension": "Efficiency",
|
||||
"collector_name": "",
|
||||
"analyzer_name": "",
|
||||
"total_numerator": 0,
|
||||
"total_denominator": 10,
|
||||
"overall_result": "0.00",
|
||||
"error_message": "",
|
||||
"ai_analysis": null,
|
||||
"ai_analysis_generated_at": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireport",
|
||||
"pk": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.626Z",
|
||||
"updated_at": "2026-02-25T05:05:17.892Z",
|
||||
"report_type": "resolution_72h",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"year": 2026,
|
||||
"month": 2,
|
||||
"report_date": "2026-02-25",
|
||||
"status": "completed",
|
||||
"generated_by": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"generated_at": "2026-02-25T05:05:17.892Z",
|
||||
"target_percentage": "95.00",
|
||||
"category": "Organizational",
|
||||
"kpi_type": "Outcome",
|
||||
"risk_level": "High",
|
||||
"data_collection_method": "Retrospective",
|
||||
"data_collection_frequency": "Monthly",
|
||||
"reporting_frequency": "Monthly",
|
||||
"dimension": "Efficiency",
|
||||
"collector_name": "",
|
||||
"analyzer_name": "",
|
||||
"total_numerator": 0,
|
||||
"total_denominator": 10,
|
||||
"overall_result": "0.00",
|
||||
"error_message": "",
|
||||
"ai_analysis": {
|
||||
"executive_summary": "The 72-Hour Complaint Resolution KPI for Olaya Hospital in February 2026 shows a complete failure to meet targets, with a 0.00% resolution rate against a 95.00% target (0 out of 10 complaints resolved within 72 hours). All 10 complaints (from sources including Social Media 40%, Call Center 30%, Family Member 20%, and Staff 10%) remain unresolved, with no resolution times recorded in the breakdown (0 in Within 24h, Within 48h, Within 72h, or After 72h). This indicates a systemic issue in complaint handling, likely due to process gaps, lack of escalation, or resource constraints. Immediate intervention is required to address the backlog and prevent further deterioration.",
|
||||
"performance_analysis": {
|
||||
"overall_resolution_rate": "0.00%",
|
||||
"target_resolution_rate": "95.00%",
|
||||
"variance": "-95.00%",
|
||||
"status": "below target",
|
||||
"total_complaints": 10,
|
||||
"resolved_within_72h": 0,
|
||||
"performance_trend": {
|
||||
"current_month": "0.00% (0/10)",
|
||||
"previous_months_data": "Not provided, but current month shows no improvement from baseline",
|
||||
"improvement_needed": "100% resolution rate required to meet target next month"
|
||||
}
|
||||
},
|
||||
"key_findings": [
|
||||
"Zero resolutions: No complaints (0 out of 10) were closed within or after 72 hours, indicating a complete process breakdown.",
|
||||
"Uniform delay: All resolution time buckets (Within 24h, 48h, 72h, After 72h) show 0.00%, with no partial progress.",
|
||||
"Source distribution: Top sources are Social Media (4 complaints, 40%) and Call Center (3 complaints, 30%), suggesting high visibility complaints are piling up.",
|
||||
"Department ambiguity: Despite categories, all departments show 0 complaints, 0 resolved; no 'slow departments' flagged, implying no active tracking or misclassification.",
|
||||
"Escalation and closure gaps: 0 escalated and 0 closed cases highlight lack of follow-up mechanisms.",
|
||||
"Month-over-month stagnation: February 2026 mirrors the 0.00% rate, with no resolved cases from prior periods shown."
|
||||
],
|
||||
"reasons_for_delays": [
|
||||
"Process failure: No recorded resolutions suggest absent or ineffective complaint intake, assignment, or tracking workflows, potentially due to unclear ownership.",
|
||||
"Resource constraints: With 10 total complaints and zero actions, likely understaffing or lack of dedicated complaint resolution teams across departments.",
|
||||
"Escalation inaction: 0 escalated cases indicate no escalation protocols are being followed, leading to indefinite hold on complaints.",
|
||||
"Source-specific challenges: High Social Media (40%) complaints may require PR/Communication involvement, which appears unaddressed; Call Center (30%) might overload front-line staff without backend support.",
|
||||
"Departmental silos: Zero counts in all departments (Medical, Nursing, Admin, Support) suggest complaints are not routed correctly or are being ignored at the department level.",
|
||||
"External factors: No data on holidays/overload, but the uniform 0% resolution points to internal inefficiencies rather than volume spikes."
|
||||
],
|
||||
"resolution_time_analysis": {
|
||||
"within_24h": {
|
||||
"count": 0,
|
||||
"percentage": "0.00%"
|
||||
},
|
||||
"within_48h": {
|
||||
"count": 0,
|
||||
"percentage": "0.00%"
|
||||
},
|
||||
"within_72h": {
|
||||
"count": 0,
|
||||
"percentage": "0.00%"
|
||||
},
|
||||
"after_72h": {
|
||||
"count": 0,
|
||||
"percentage": "0.00%"
|
||||
},
|
||||
"insights": "No complaints have progressed through any time stage, resulting in a frozen backlog. Without interventions, this will lead to increasing complaint ages and potential regulatory non-compliance."
|
||||
},
|
||||
"department_analysis": {
|
||||
"non_medical_admin": {
|
||||
"complaints": 0,
|
||||
"resolved": 0,
|
||||
"status": "No activity"
|
||||
},
|
||||
"medical_department": {
|
||||
"complaints": 0,
|
||||
"resolved": 0,
|
||||
"status": "No activity"
|
||||
},
|
||||
"nursing_department": {
|
||||
"complaints": 0,
|
||||
"resolved": 0,
|
||||
"status": "No activity"
|
||||
},
|
||||
"support_services": {
|
||||
"complaints": 0,
|
||||
"resolved": 0,
|
||||
"status": "No activity"
|
||||
},
|
||||
"slow_departments": "None identified, but all departments show zero complaints, suggesting underreporting or lack of integration with complaint system.",
|
||||
"overall_department_insight": "Cross-departmental inaction indicates a hospital-wide issue in complaint capture and resolution, rather than isolated inefficiencies."
|
||||
},
|
||||
"source_analysis": {
|
||||
"social_media": {
|
||||
"count": 4,
|
||||
"percentage": "40.00%",
|
||||
"insight": "Highest volume; requires immediate social media monitoring and response team to mitigate reputational risk."
|
||||
},
|
||||
"call_center": {
|
||||
"count": 3,
|
||||
"percentage": "30.00%",
|
||||
"insight": "Significant portion; likely tied to patient access or service issues, needing better call center-to-department handoffs."
|
||||
},
|
||||
"family_member": {
|
||||
"count": 2,
|
||||
"percentage": "20.00%",
|
||||
"insight": "Indirect complaints; may involve communication breakdowns with families, suggesting needs for family liaison protocols."
|
||||
},
|
||||
"staff": {
|
||||
"count": 1,
|
||||
"percentage": "10.00%",
|
||||
"insight": "Internal complaints; points to potential employee satisfaction issues, which could impact morale if unresolved."
|
||||
},
|
||||
"source_summary": "Social Media and Call Center dominate (70% combined), highlighting external visibility of unresolved issues. No sources resolved, indicating universal process gap."
|
||||
},
|
||||
"recommendations": [
|
||||
"Immediate backlog clearance: Assign a dedicated cross-functional team to triage and resolve all 10 pending complaints within 7 days, starting with high-visibility Social Media (4) and Call Center (3) cases.",
|
||||
"Process enhancement: Implement automated complaint tracking with clear SLA alerts (e.g., alerts at 24h/48h) and mandatory escalation after 48 hours; train staff on intake protocols to ensure 100% capture and routing.",
|
||||
"Resource allocation: Audit staffing levels in complaint handling; add temporary resources or redistribute admin/Nursing staff to handle peak volumes, aiming for at least 50% resolution within 48h next month.",
|
||||
"Department accountability: Assign complaint owners per department (e.g., Medical for clinical complaints, Admin for non-medical); integrate complaint data into department KPIs to ensure visibility and drive accountability.",
|
||||
"Source-specific actions: For Social Media, establish a 24/7 monitoring team; for Call Center, improve handoff checklists; for Family Member/Staff, introduce feedback loops and response templates.",
|
||||
"Monitoring and review: Conduct weekly reviews of resolution rates; set interim target of 50% for March 2026, with root cause analysis for any complaints exceeding 72h.",
|
||||
"Technology upgrade: If not in place, deploy a centralized CRM system to consolidate sources and automate resolution tracking, reducing manual errors."
|
||||
],
|
||||
"_metadata": {
|
||||
"generated_at": "2026-02-25T05:05:39.218450+00:00",
|
||||
"report_id": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"report_type": "resolution_72h",
|
||||
"hospital": "Olaya",
|
||||
"year": 2026,
|
||||
"month": 2
|
||||
}
|
||||
},
|
||||
"ai_analysis_generated_at": "2026-02-25T05:05:39.218Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireport",
|
||||
"pk": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.229Z",
|
||||
"updated_at": "2026-02-25T05:06:34.442Z",
|
||||
"report_type": "satisfaction_resolution",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"year": 2026,
|
||||
"month": 2,
|
||||
"report_date": "2026-02-25",
|
||||
"status": "completed",
|
||||
"generated_by": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"generated_at": "2026-02-25T05:06:34.442Z",
|
||||
"target_percentage": "95.00",
|
||||
"category": "Organizational",
|
||||
"kpi_type": "Outcome",
|
||||
"risk_level": "High",
|
||||
"data_collection_method": "Retrospective",
|
||||
"data_collection_frequency": "Monthly",
|
||||
"reporting_frequency": "Monthly",
|
||||
"dimension": "Efficiency",
|
||||
"collector_name": "",
|
||||
"analyzer_name": "",
|
||||
"total_numerator": 0,
|
||||
"total_denominator": 0,
|
||||
"overall_result": "0.00",
|
||||
"error_message": "",
|
||||
"ai_analysis": null,
|
||||
"ai_analysis_generated_at": null
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"kpireportmonthlydata": {
|
||||
"count": 36,
|
||||
"data": [
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "4d9202e0-cc4c-47ff-9014-ac36d6e761ca",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.640Z",
|
||||
"updated_at": "2026-02-25T05:05:17.644Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 1,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "7cce81c6-a7a9-4004-becf-c3b830ecbacf",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.243Z",
|
||||
"updated_at": "2026-02-25T05:06:34.246Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 1,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "394c89ab-56e3-4220-bfe8-5f7f070145c4",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:53.931Z",
|
||||
"updated_at": "2026-02-25T05:06:53.934Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 1,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "ec879001-3daf-4147-b1b8-98d2302309a2",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.659Z",
|
||||
"updated_at": "2026-02-25T05:05:17.680Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 2,
|
||||
"numerator": 0,
|
||||
"denominator": 10,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {
|
||||
"Social Media": 4,
|
||||
"Call Center": 3,
|
||||
"Staff": 1,
|
||||
"Family Member": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "156e3c95-9211-4d10-a4e1-725333e9576d",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.258Z",
|
||||
"updated_at": "2026-02-25T05:06:34.265Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 2,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "4b5c87df-1245-477f-99c1-6f1ad450460f",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:53.949Z",
|
||||
"updated_at": "2026-02-25T05:06:53.954Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 2,
|
||||
"numerator": 0,
|
||||
"denominator": 10,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "34706e2e-01ae-4ae9-94ee-c91a2ffede86",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.694Z",
|
||||
"updated_at": "2026-02-25T05:05:17.697Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 3,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "5a30b9a3-4a02-4762-b0bc-b16a6fbe9308",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.278Z",
|
||||
"updated_at": "2026-02-25T05:06:34.281Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 3,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "7ebc65a9-7688-4bde-af71-da45eea94bf0",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:53.970Z",
|
||||
"updated_at": "2026-02-25T05:06:53.974Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 3,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "483dec68-8f6c-4ccb-9bb4-793daf28026f",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.711Z",
|
||||
"updated_at": "2026-02-25T05:05:17.714Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 4,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "18e69243-abfb-4800-a7b4-18a09b44b188",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.293Z",
|
||||
"updated_at": "2026-02-25T05:06:34.296Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 4,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "76edc093-a757-4da3-b083-dfd52c5f6f45",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:53.984Z",
|
||||
"updated_at": "2026-02-25T05:06:53.990Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 4,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "f18b64c2-40ea-4ee9-aef0-74af82cb4402",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.726Z",
|
||||
"updated_at": "2026-02-25T05:05:17.730Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 5,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "48ad553d-bc29-48da-9f9d-ae6946724c28",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.308Z",
|
||||
"updated_at": "2026-02-25T05:06:34.313Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 5,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "411a6f5f-dd61-4a98-88f2-b5908d666d22",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:53.998Z",
|
||||
"updated_at": "2026-02-25T05:06:54.000Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 5,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "dff20507-54c1-4f83-acf9-d81914de7a59",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.743Z",
|
||||
"updated_at": "2026-02-25T05:05:17.745Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 6,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "5b010a15-818c-4183-b1a1-4fa39ed3ac8d",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.328Z",
|
||||
"updated_at": "2026-02-25T05:06:34.339Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 6,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "776c9665-80b2-4091-b84f-49eebc577862",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:54.012Z",
|
||||
"updated_at": "2026-02-25T05:06:54.015Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 6,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "0a26b2d2-0270-474c-9e07-120cc330c7af",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.755Z",
|
||||
"updated_at": "2026-02-25T05:05:17.761Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 7,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "4a14e2da-d727-49f2-a6e9-8d5e3ffb5f03",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.356Z",
|
||||
"updated_at": "2026-02-25T05:06:34.362Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 7,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "4d623492-b260-4ee4-a478-5a43599a1b18",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:54.032Z",
|
||||
"updated_at": "2026-02-25T05:06:54.035Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 7,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "c35b57c4-43ba-482f-8000-44ac099435df",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.774Z",
|
||||
"updated_at": "2026-02-25T05:05:17.778Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 8,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "0a1d71e1-758b-4f88-849b-32e6d73d079b",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.376Z",
|
||||
"updated_at": "2026-02-25T05:06:34.380Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 8,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "32a42d17-8ac6-40d7-9285-bca7dded9faa",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:54.047Z",
|
||||
"updated_at": "2026-02-25T05:06:54.050Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 8,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "a24ca72c-6399-4e3a-9e78-a89cfc324411",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.789Z",
|
||||
"updated_at": "2026-02-25T05:05:17.792Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 9,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "3963f4fc-6fdd-4a20-9be6-9d2da2bd8af1",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.394Z",
|
||||
"updated_at": "2026-02-25T05:06:34.398Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 9,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "3f77f04e-7477-4328-9054-84b135b016f3",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:54.063Z",
|
||||
"updated_at": "2026-02-25T05:06:54.065Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 9,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "4f12ec3b-29ec-4664-99b1-44a9418bcbd1",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.798Z",
|
||||
"updated_at": "2026-02-25T05:05:17.801Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 10,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "a4c33859-5031-4410-be37-340115739fc1",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.407Z",
|
||||
"updated_at": "2026-02-25T05:06:34.411Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 10,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "b7fb063c-0f9f-4d4f-9948-ed77b0ddd486",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:54.077Z",
|
||||
"updated_at": "2026-02-25T05:06:54.081Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 10,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "0102b319-57e9-485e-9dd4-6a4b3e8aa01b",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.807Z",
|
||||
"updated_at": "2026-02-25T05:05:17.810Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 11,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "98bb11e1-32d1-4fd1-bf0c-7c0bb1906488",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.418Z",
|
||||
"updated_at": "2026-02-25T05:06:34.422Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 11,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "6435a7b2-1c24-4b75-9d92-44f7eb28e273",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:54.094Z",
|
||||
"updated_at": "2026-02-25T05:06:54.096Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 11,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "a616bf00-880d-4839-ad2c-db841c3196cb",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.816Z",
|
||||
"updated_at": "2026-02-25T05:05:17.818Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"month": 12,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {
|
||||
"source_breakdown": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "7488dc68-b2ae-42a6-a962-0cfe40346444",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:34.429Z",
|
||||
"updated_at": "2026-02-25T05:06:34.434Z",
|
||||
"kpi_report": "3f450a3f-036b-4be6-b368-fc1c3d2dc2ff",
|
||||
"month": 12,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportmonthlydata",
|
||||
"pk": "ddc6ad75-756a-4935-b335-55b86646b15f",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:06:54.106Z",
|
||||
"updated_at": "2026-02-25T05:06:54.109Z",
|
||||
"kpi_report": "56af32e0-a5b2-4d38-8b18-bd0a06805237",
|
||||
"month": 12,
|
||||
"numerator": 0,
|
||||
"denominator": 0,
|
||||
"percentage": "0.00",
|
||||
"is_below_target": true,
|
||||
"details": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"kpireportdepartmentbreakdown": {
|
||||
"count": 4,
|
||||
"data": [
|
||||
{
|
||||
"model": "analytics.kpireportdepartmentbreakdown",
|
||||
"pk": "9137144c-1b44-4d6e-be4d-0430f154f718",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.876Z",
|
||||
"updated_at": "2026-02-25T05:05:17.876Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"department_category": "admin",
|
||||
"complaint_count": 0,
|
||||
"resolved_count": 0,
|
||||
"avg_resolution_days": null,
|
||||
"top_areas": "",
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportdepartmentbreakdown",
|
||||
"pk": "4d5eb559-6036-4185-9acd-6d3625922483",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.858Z",
|
||||
"updated_at": "2026-02-25T05:05:17.858Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"department_category": "medical",
|
||||
"complaint_count": 0,
|
||||
"resolved_count": 0,
|
||||
"avg_resolution_days": null,
|
||||
"top_areas": "",
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportdepartmentbreakdown",
|
||||
"pk": "456bf2ad-1c56-41ef-80f1-d719b70e53d2",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.868Z",
|
||||
"updated_at": "2026-02-25T05:05:17.868Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"department_category": "nursing",
|
||||
"complaint_count": 0,
|
||||
"resolved_count": 0,
|
||||
"avg_resolution_days": null,
|
||||
"top_areas": "",
|
||||
"details": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportdepartmentbreakdown",
|
||||
"pk": "cc391455-444a-4d92-92d9-4c9cb39763d4",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.890Z",
|
||||
"updated_at": "2026-02-25T05:05:17.890Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"department_category": "support",
|
||||
"complaint_count": 0,
|
||||
"resolved_count": 0,
|
||||
"avg_resolution_days": null,
|
||||
"top_areas": "",
|
||||
"details": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"kpireportsourcebreakdown": {
|
||||
"count": 4,
|
||||
"data": [
|
||||
{
|
||||
"model": "analytics.kpireportsourcebreakdown",
|
||||
"pk": "02d33996-ba97-4efe-b6d3-37c6b2e818ff",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.835Z",
|
||||
"updated_at": "2026-02-25T05:05:17.835Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"source_name": "Social Media",
|
||||
"complaint_count": 4,
|
||||
"percentage": "40.00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportsourcebreakdown",
|
||||
"pk": "fc458559-803f-47bf-af84-d7a4ca922bb0",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.838Z",
|
||||
"updated_at": "2026-02-25T05:05:17.838Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"source_name": "Call Center",
|
||||
"complaint_count": 3,
|
||||
"percentage": "30.00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportsourcebreakdown",
|
||||
"pk": "00b2b0dc-1652-4eed-bd47-f954106345ca",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.842Z",
|
||||
"updated_at": "2026-02-25T05:05:17.842Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"source_name": "Family Member",
|
||||
"complaint_count": 2,
|
||||
"percentage": "20.00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "analytics.kpireportsourcebreakdown",
|
||||
"pk": "48a31227-46f2-4274-98bd-a112dc068682",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:05:17.840Z",
|
||||
"updated_at": "2026-02-25T05:05:17.840Z",
|
||||
"kpi_report": "88795c74-4a05-4030-bd81-24b844564b3c",
|
||||
"source_name": "Staff",
|
||||
"complaint_count": 1,
|
||||
"percentage": "10.00"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
2879
database_export/complaints/complaints_data.json
Normal file
2879
database_export/complaints/complaints_data.json
Normal file
File diff suppressed because it is too large
Load Diff
73
database_export/core/core_data.json
Normal file
73
database_export/core/core_data.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"app": "core",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 3,
|
||||
"models": {
|
||||
"auditevent": {
|
||||
"count": 3,
|
||||
"data": [
|
||||
{
|
||||
"model": "core.auditevent",
|
||||
"pk": "cb0145b5-839a-4d42-b8b7-15d7c5a5f92b",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T05:09:40.739Z",
|
||||
"updated_at": "2026-02-25T05:09:40.739Z",
|
||||
"event_type": "activation",
|
||||
"user": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"description": "Complaint activated and assigned to ",
|
||||
"content_type": 42,
|
||||
"object_id": "8bbf4733-34c8-4dc0-a440-50ac4ab90a22",
|
||||
"metadata": {
|
||||
"assigned_to_user_id": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"assigned_to_user_name": "",
|
||||
"previous_assignee_id": null,
|
||||
"previous_assignee_name": null
|
||||
},
|
||||
"ip_address": null,
|
||||
"user_agent": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "core.auditevent",
|
||||
"pk": "5a4f4bf3-9447-46cf-b886-966ea694f297",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:17:40.060Z",
|
||||
"updated_at": "2026-02-25T04:17:40.060Z",
|
||||
"event_type": "doctor_rating_import_queued",
|
||||
"user": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"description": "Queued 38082 doctor ratings for import",
|
||||
"content_type": null,
|
||||
"object_id": null,
|
||||
"metadata": {
|
||||
"job_id": "ac3ebc22-da1a-486a-96cc-c4146b6d3d25",
|
||||
"hospital": "Olaya",
|
||||
"total_records": 38082
|
||||
},
|
||||
"ip_address": null,
|
||||
"user_agent": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "core.auditevent",
|
||||
"pk": "e44a60aa-2c8c-4b21-868f-9c609fabd7bf",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:14:05.305Z",
|
||||
"updated_at": "2026-02-25T04:14:05.305Z",
|
||||
"event_type": "doctor_rating_csv_import",
|
||||
"user": "e4a79042-cd54-45ff-9bf5-d775bcb9fb92",
|
||||
"description": "Parsed 38082 doctor ratings from CSV by ",
|
||||
"content_type": null,
|
||||
"object_id": null,
|
||||
"metadata": {
|
||||
"hospital": "Olaya",
|
||||
"total_count": 38082,
|
||||
"error_count": 0
|
||||
},
|
||||
"ip_address": null,
|
||||
"user_agent": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
29
database_export/export_summary.json
Normal file
29
database_export/export_summary.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 58175,
|
||||
"apps_exported": [
|
||||
"core",
|
||||
"accounts",
|
||||
"organizations",
|
||||
"journeys",
|
||||
"surveys",
|
||||
"complaints",
|
||||
"feedback",
|
||||
"callcenter",
|
||||
"social",
|
||||
"px_action_center",
|
||||
"analytics",
|
||||
"physicians",
|
||||
"projects",
|
||||
"integrations",
|
||||
"notifications",
|
||||
"ai_engine",
|
||||
"appreciation",
|
||||
"observations",
|
||||
"px_sources",
|
||||
"references",
|
||||
"standards",
|
||||
"simulator"
|
||||
],
|
||||
"output_directory": "./database_export"
|
||||
}
|
||||
48
database_export/integrations/integrations_data.json
Normal file
48
database_export/integrations/integrations_data.json
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"app": "integrations",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 3,
|
||||
"models": {
|
||||
"surveytemplatemapping": {
|
||||
"count": 3,
|
||||
"data": [
|
||||
{
|
||||
"model": "integrations.surveytemplatemapping",
|
||||
"pk": "6e7f6f8c-bd68-490b-b67f-0756e610c787",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:01:58.060Z",
|
||||
"updated_at": "2026-02-25T04:01:58.060Z",
|
||||
"patient_type": "APPOINTMENT",
|
||||
"survey_template": "5e8f95fd-2e84-4640-8d67-e549507684a5",
|
||||
"hospital": null,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "integrations.surveytemplatemapping",
|
||||
"pk": "81074873-2bdd-44c6-ad41-4fb71a5c2058",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:01:58.052Z",
|
||||
"updated_at": "2026-02-25T04:01:58.052Z",
|
||||
"patient_type": "INPATIENT",
|
||||
"survey_template": "6104fa70-0768-45b7-9f12-6816d91c0e18",
|
||||
"hospital": null,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "integrations.surveytemplatemapping",
|
||||
"pk": "032cc742-98e8-47de-b4aa-48506342665b",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:01:58.057Z",
|
||||
"updated_at": "2026-02-25T04:01:58.057Z",
|
||||
"patient_type": "OUTPATIENT",
|
||||
"survey_template": "0e175a49-a502-4d46-9c5f-c98894e316cf",
|
||||
"hospital": null,
|
||||
"is_active": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
289
database_export/journeys/journeys_data.json
Normal file
289
database_export/journeys/journeys_data.json
Normal file
@ -0,0 +1,289 @@
|
||||
{
|
||||
"app": "journeys",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 16,
|
||||
"models": {
|
||||
"patientjourneytemplate": {
|
||||
"count": 3,
|
||||
"data": [
|
||||
{
|
||||
"model": "journeys.patientjourneytemplate",
|
||||
"pk": "2b243c19-d7de-4313-917e-de33bea24031",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.509Z",
|
||||
"updated_at": "2026-02-25T04:00:58.509Z",
|
||||
"name": "EMS Patient Journey",
|
||||
"name_ar": "رحلة المريض للطوارئ",
|
||||
"journey_type": "ems",
|
||||
"description": "Emergency medical services patient journey",
|
||||
"hospital": "d7221fdb-a0f7-4460-8d69-14a3bfe627fb",
|
||||
"is_active": true,
|
||||
"is_default": true,
|
||||
"send_post_discharge_survey": true,
|
||||
"post_discharge_survey_delay_hours": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneytemplate",
|
||||
"pk": "63f8256b-c463-4d63-b56e-90b585703b7d",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.535Z",
|
||||
"updated_at": "2026-02-25T04:00:58.535Z",
|
||||
"name": "Inpatient Patient Journey",
|
||||
"name_ar": "رحلة المريض الداخلي",
|
||||
"journey_type": "inpatient",
|
||||
"description": "Inpatient journey from admission to discharge",
|
||||
"hospital": "d7221fdb-a0f7-4460-8d69-14a3bfe627fb",
|
||||
"is_active": true,
|
||||
"is_default": true,
|
||||
"send_post_discharge_survey": true,
|
||||
"post_discharge_survey_delay_hours": 24
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneytemplate",
|
||||
"pk": "953c1fe5-1bb4-4583-a3b9-b2eeec1d278f",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.563Z",
|
||||
"updated_at": "2026-02-25T04:00:58.563Z",
|
||||
"name": "OPD Patient Journey",
|
||||
"name_ar": "رحلة المريض للعيادات الخارجية",
|
||||
"journey_type": "opd",
|
||||
"description": "Outpatient department patient journey",
|
||||
"hospital": "d7221fdb-a0f7-4460-8d69-14a3bfe627fb",
|
||||
"is_active": true,
|
||||
"is_default": true,
|
||||
"send_post_discharge_survey": true,
|
||||
"post_discharge_survey_delay_hours": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"patientjourneystagetemplate": {
|
||||
"count": 13,
|
||||
"data": [
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "dacb47c5-fbeb-4239-96e7-8103827ed6d8",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.511Z",
|
||||
"updated_at": "2026-02-25T04:00:58.511Z",
|
||||
"journey_template": "2b243c19-d7de-4313-917e-de33bea24031",
|
||||
"name": "Ambulance Dispatch",
|
||||
"name_ar": "إرسال الإسعاف",
|
||||
"code": "EMS_STAGE_1_DISPATCHED",
|
||||
"order": 1,
|
||||
"trigger_event_code": "EMS_STAGE_1_DISPATCHED",
|
||||
"survey_template": "733b4d11-2a88-4875-bb33-fb3d7efc3734",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "9128dcaa-ea20-4d1c-953f-08180e12e1d6",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.513Z",
|
||||
"updated_at": "2026-02-25T04:00:58.513Z",
|
||||
"journey_template": "2b243c19-d7de-4313-917e-de33bea24031",
|
||||
"name": "On Scene Care",
|
||||
"name_ar": "الرعاية في الموقع",
|
||||
"code": "EMS_STAGE_2_ON_SCENE",
|
||||
"order": 2,
|
||||
"trigger_event_code": "EMS_STAGE_2_ON_SCENE",
|
||||
"survey_template": "733b4d11-2a88-4875-bb33-fb3d7efc3734",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "e59b6e21-caf9-4e20-9925-30693232bfb7",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.514Z",
|
||||
"updated_at": "2026-02-25T04:00:58.514Z",
|
||||
"journey_template": "2b243c19-d7de-4313-917e-de33bea24031",
|
||||
"name": "Patient Transport",
|
||||
"name_ar": "نقل المريض",
|
||||
"code": "EMS_STAGE_3_TRANSPORT",
|
||||
"order": 3,
|
||||
"trigger_event_code": "EMS_STAGE_3_TRANSPORT",
|
||||
"survey_template": "733b4d11-2a88-4875-bb33-fb3d7efc3734",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "c86143de-01a4-4503-8c43-33bde911d2da",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.537Z",
|
||||
"updated_at": "2026-02-25T04:00:58.537Z",
|
||||
"journey_template": "63f8256b-c463-4d63-b56e-90b585703b7d",
|
||||
"name": "Admission",
|
||||
"name_ar": "القبول",
|
||||
"code": "INPATIENT_STAGE_1_ADMISSION",
|
||||
"order": 1,
|
||||
"trigger_event_code": "INPATIENT_STAGE_1_ADMISSION",
|
||||
"survey_template": "d5d337e2-c2ba-44f5-8f35-6aa7f7e89c02",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "eabc55aa-9ece-4755-ae2b-abd75765dad0",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.539Z",
|
||||
"updated_at": "2026-02-25T04:00:58.539Z",
|
||||
"journey_template": "63f8256b-c463-4d63-b56e-90b585703b7d",
|
||||
"name": "Treatment",
|
||||
"name_ar": "العلاج",
|
||||
"code": "INPATIENT_STAGE_2_TREATMENT",
|
||||
"order": 2,
|
||||
"trigger_event_code": "INPATIENT_STAGE_2_TREATMENT",
|
||||
"survey_template": "d5d337e2-c2ba-44f5-8f35-6aa7f7e89c02",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "372dd6df-7667-4a4a-be26-13dc8957ae52",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.541Z",
|
||||
"updated_at": "2026-02-25T04:00:58.541Z",
|
||||
"journey_template": "63f8256b-c463-4d63-b56e-90b585703b7d",
|
||||
"name": "Nursing Care",
|
||||
"name_ar": "الرعاية التمريضية",
|
||||
"code": "INPATIENT_STAGE_3_NURSING",
|
||||
"order": 3,
|
||||
"trigger_event_code": "INPATIENT_STAGE_3_NURSING",
|
||||
"survey_template": "d5d337e2-c2ba-44f5-8f35-6aa7f7e89c02",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "94fd0498-ad0d-4452-a954-622d232a174a",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.543Z",
|
||||
"updated_at": "2026-02-25T04:00:58.543Z",
|
||||
"journey_template": "63f8256b-c463-4d63-b56e-90b585703b7d",
|
||||
"name": "Lab Tests",
|
||||
"name_ar": "الفحوصات المخبرية",
|
||||
"code": "INPATIENT_STAGE_4_LAB",
|
||||
"order": 4,
|
||||
"trigger_event_code": "INPATIENT_STAGE_4_LAB",
|
||||
"survey_template": "d5d337e2-c2ba-44f5-8f35-6aa7f7e89c02",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "fc7b3fe7-8e47-4947-b082-8f9c384b7137",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.545Z",
|
||||
"updated_at": "2026-02-25T04:00:58.545Z",
|
||||
"journey_template": "63f8256b-c463-4d63-b56e-90b585703b7d",
|
||||
"name": "Radiology",
|
||||
"name_ar": "الأشعة",
|
||||
"code": "INPATIENT_STAGE_5_RADIOLOGY",
|
||||
"order": 5,
|
||||
"trigger_event_code": "INPATIENT_STAGE_5_RADIOLOGY",
|
||||
"survey_template": "d5d337e2-c2ba-44f5-8f35-6aa7f7e89c02",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "eb293246-9d84-46f2-abda-461a21c7c60d",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.565Z",
|
||||
"updated_at": "2026-02-25T04:00:58.565Z",
|
||||
"journey_template": "953c1fe5-1bb4-4583-a3b9-b2eeec1d278f",
|
||||
"name": "Registration",
|
||||
"name_ar": "التسجيل",
|
||||
"code": "OPD_STAGE_1_REGISTRATION",
|
||||
"order": 1,
|
||||
"trigger_event_code": "OPD_STAGE_1_REGISTRATION",
|
||||
"survey_template": "4ac2ae6b-87bc-4519-85d5-afc27d7685f6",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "2014d3dc-c38c-401e-a5ec-12312de05c1e",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.571Z",
|
||||
"updated_at": "2026-02-25T04:00:58.571Z",
|
||||
"journey_template": "953c1fe5-1bb4-4583-a3b9-b2eeec1d278f",
|
||||
"name": "Consultation",
|
||||
"name_ar": "الاستشارة",
|
||||
"code": "OPD_STAGE_2_CONSULTATION",
|
||||
"order": 2,
|
||||
"trigger_event_code": "OPD_STAGE_2_CONSULTATION",
|
||||
"survey_template": "4ac2ae6b-87bc-4519-85d5-afc27d7685f6",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "3e0f67ea-18a9-460b-872a-6d47e0b2906c",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.574Z",
|
||||
"updated_at": "2026-02-25T04:00:58.574Z",
|
||||
"journey_template": "953c1fe5-1bb4-4583-a3b9-b2eeec1d278f",
|
||||
"name": "Lab Tests",
|
||||
"name_ar": "الفحوصات المخبرية",
|
||||
"code": "OPD_STAGE_3_LAB",
|
||||
"order": 3,
|
||||
"trigger_event_code": "OPD_STAGE_3_LAB",
|
||||
"survey_template": "4ac2ae6b-87bc-4519-85d5-afc27d7685f6",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "75860c85-ab25-4bf1-aa88-442a8b520144",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.577Z",
|
||||
"updated_at": "2026-02-25T04:00:58.577Z",
|
||||
"journey_template": "953c1fe5-1bb4-4583-a3b9-b2eeec1d278f",
|
||||
"name": "Radiology",
|
||||
"name_ar": "الأشعة",
|
||||
"code": "OPD_STAGE_4_RADIOLOGY",
|
||||
"order": 4,
|
||||
"trigger_event_code": "OPD_STAGE_4_RADIOLOGY",
|
||||
"survey_template": "4ac2ae6b-87bc-4519-85d5-afc27d7685f6",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "journeys.patientjourneystagetemplate",
|
||||
"pk": "5546f87f-85ab-441a-9898-cbc9e8bb46f9",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T04:00:58.580Z",
|
||||
"updated_at": "2026-02-25T04:00:58.580Z",
|
||||
"journey_template": "953c1fe5-1bb4-4583-a3b9-b2eeec1d278f",
|
||||
"name": "Pharmacy",
|
||||
"name_ar": "الصيدلية",
|
||||
"code": "OPD_STAGE_5_PHARMACY",
|
||||
"order": 5,
|
||||
"trigger_event_code": "OPD_STAGE_5_PHARMACY",
|
||||
"survey_template": "4ac2ae6b-87bc-4519-85d5-afc27d7685f6",
|
||||
"is_optional": false,
|
||||
"is_active": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
132
database_export/notifications/notifications_data.json
Normal file
132
database_export/notifications/notifications_data.json
Normal file
@ -0,0 +1,132 @@
|
||||
{
|
||||
"app": "notifications",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 4,
|
||||
"models": {
|
||||
"notificationlog": {
|
||||
"count": 4,
|
||||
"data": [
|
||||
{
|
||||
"model": "notifications.notificationlog",
|
||||
"pk": "60ff0efd-53d5-443f-b799-3ca311e3fd62",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.978Z",
|
||||
"updated_at": "2026-02-25T03:55:36.978Z",
|
||||
"channel": "sms",
|
||||
"recipient": "+966537702040",
|
||||
"subject": "",
|
||||
"message": "PX360: Your complaint #CMP-HAM-RIY-2026-787134BD has been received. Track: https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-787134BD",
|
||||
"content_type": 42,
|
||||
"object_id": "f4096f2b-81ba-4eee-8ac8-3ad0bded1797",
|
||||
"status": "sent",
|
||||
"sent_at": "2026-02-25T03:55:42.002Z",
|
||||
"delivered_at": null,
|
||||
"provider": "api",
|
||||
"provider_message_id": "",
|
||||
"provider_response": {},
|
||||
"error": "",
|
||||
"retry_count": 0,
|
||||
"metadata": {
|
||||
"api_url": "http://localhost:8000/api/simulator/send-sms/",
|
||||
"auth_method": "bearer",
|
||||
"notification_type": "complaint_created",
|
||||
"reference_number": "CMP-HAM-RIY-2026-787134BD",
|
||||
"tracking_url": "https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-787134BD",
|
||||
"language": "en"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "notifications.notificationlog",
|
||||
"pk": "eff41c4f-b6e7-4691-9faa-f1b707e517a4",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.907Z",
|
||||
"updated_at": "2026-02-25T03:55:31.907Z",
|
||||
"channel": "sms",
|
||||
"recipient": "+966541424622",
|
||||
"subject": "",
|
||||
"message": "PX360: Your complaint #CMP-HAM-RIY-2026-C2897964 has been received. Track: https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-C2897964",
|
||||
"content_type": 42,
|
||||
"object_id": "9da3b845-c425-4bf1-b413-1d10fc1a150d",
|
||||
"status": "sent",
|
||||
"sent_at": "2026-02-25T03:55:36.935Z",
|
||||
"delivered_at": null,
|
||||
"provider": "api",
|
||||
"provider_message_id": "",
|
||||
"provider_response": {},
|
||||
"error": "",
|
||||
"retry_count": 0,
|
||||
"metadata": {
|
||||
"api_url": "http://localhost:8000/api/simulator/send-sms/",
|
||||
"auth_method": "bearer",
|
||||
"notification_type": "complaint_created",
|
||||
"reference_number": "CMP-HAM-RIY-2026-C2897964",
|
||||
"tracking_url": "https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-C2897964",
|
||||
"language": "en"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "notifications.notificationlog",
|
||||
"pk": "de39ff56-dd07-400b-ac8f-717d4e9aa8cf",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:26.817Z",
|
||||
"updated_at": "2026-02-25T03:55:26.817Z",
|
||||
"channel": "sms",
|
||||
"recipient": "+966526753309",
|
||||
"subject": "",
|
||||
"message": "PX360: Your complaint #CMP-HAM-RIY-2026-50004505 has been received. Track: https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-50004505",
|
||||
"content_type": 42,
|
||||
"object_id": "312155d3-b384-4e6f-b2e7-f8bd21e7817b",
|
||||
"status": "sent",
|
||||
"sent_at": "2026-02-25T03:55:31.844Z",
|
||||
"delivered_at": null,
|
||||
"provider": "api",
|
||||
"provider_message_id": "",
|
||||
"provider_response": {},
|
||||
"error": "",
|
||||
"retry_count": 0,
|
||||
"metadata": {
|
||||
"api_url": "http://localhost:8000/api/simulator/send-sms/",
|
||||
"auth_method": "bearer",
|
||||
"notification_type": "complaint_created",
|
||||
"reference_number": "CMP-HAM-RIY-2026-50004505",
|
||||
"tracking_url": "https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-50004505",
|
||||
"language": "en"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "notifications.notificationlog",
|
||||
"pk": "1704e6bc-8c19-4d1b-9538-4091189495dd",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.759Z",
|
||||
"updated_at": "2026-02-25T03:55:21.759Z",
|
||||
"channel": "sms",
|
||||
"recipient": "+966592722909",
|
||||
"subject": "",
|
||||
"message": "PX360: Your complaint #CMP-HAM-RIY-2026-5420F582 has been received. Track: https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-5420F582",
|
||||
"content_type": 42,
|
||||
"object_id": "4f11f759-8061-427d-899b-e0c360d11a20",
|
||||
"status": "sent",
|
||||
"sent_at": "2026-02-25T03:55:26.781Z",
|
||||
"delivered_at": null,
|
||||
"provider": "api",
|
||||
"provider_message_id": "",
|
||||
"provider_response": {},
|
||||
"error": "",
|
||||
"retry_count": 0,
|
||||
"metadata": {
|
||||
"api_url": "http://localhost:8000/api/simulator/send-sms/",
|
||||
"auth_method": "bearer",
|
||||
"notification_type": "complaint_created",
|
||||
"reference_number": "CMP-HAM-RIY-2026-5420F582",
|
||||
"tracking_url": "https://localhost:8000/complaints/public/track/?reference=CMP-HAM-RIY-2026-5420F582",
|
||||
"language": "en"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
515440
database_export/organizations/organizations_data.json
Normal file
515440
database_export/organizations/organizations_data.json
Normal file
File diff suppressed because it is too large
Load Diff
2027027
database_export/physicians/physicians_data.json
Normal file
2027027
database_export/physicians/physicians_data.json
Normal file
File diff suppressed because it is too large
Load Diff
299
database_export/px_sources/px_sources_data.json
Normal file
299
database_export/px_sources/px_sources_data.json
Normal file
@ -0,0 +1,299 @@
|
||||
{
|
||||
"app": "px_sources",
|
||||
"exported_at": "20260225_081256",
|
||||
"total_records": 18,
|
||||
"models": {
|
||||
"pxsource": {
|
||||
"count": 8,
|
||||
"data": [
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "9affe720-438b-43dd-b570-25a7f6e8a5aa",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.561Z",
|
||||
"updated_at": "2026-02-25T03:55:21.561Z",
|
||||
"code": "CALL-CENT",
|
||||
"name_en": "Call Center",
|
||||
"name_ar": "مركز الاتصال",
|
||||
"description": "Call Center source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 3,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "88060ad8-c771-48a6-ae9d-31fdb993e2f9",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.557Z",
|
||||
"updated_at": "2026-02-25T03:55:21.558Z",
|
||||
"code": "FAMI-MEMB",
|
||||
"name_en": "Family Member",
|
||||
"name_ar": "عضو العائلة",
|
||||
"description": "Family Member source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 2,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "642825ce-5e1f-4900-875d-6bb3c67e9f16",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.564Z",
|
||||
"updated_at": "2026-02-25T03:55:21.564Z",
|
||||
"code": "IN-PERS",
|
||||
"name_en": "In Person",
|
||||
"name_ar": "شخصياً",
|
||||
"description": "In Person source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 0,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "e4b6d570-5166-42b5-be13-04774a65a0dc",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.563Z",
|
||||
"updated_at": "2026-02-25T03:55:21.563Z",
|
||||
"code": "ONLI-FORM",
|
||||
"name_en": "Online Form",
|
||||
"name_ar": "نموذج عبر الإنترنت",
|
||||
"description": "Online Form source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 0,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "db13b2e7-5169-40b9-a588-f8570d390af6",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.551Z",
|
||||
"updated_at": "2026-02-25T03:55:21.551Z",
|
||||
"code": "PATIENT",
|
||||
"name_en": "Patient",
|
||||
"name_ar": "مريض",
|
||||
"description": "Patient source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 0,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "31ff949d-4e1b-419d-a0de-f988c41fcc3a",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.569Z",
|
||||
"updated_at": "2026-02-25T03:55:21.569Z",
|
||||
"code": "SOCI-MEDI",
|
||||
"name_en": "Social Media",
|
||||
"name_ar": "وسائل التواصل الاجتماعي",
|
||||
"description": "Social Media source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 4,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "0aacdcd8-7aa7-4351-ad52-73a394c0848e",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.559Z",
|
||||
"updated_at": "2026-02-25T03:55:21.559Z",
|
||||
"code": "STAFF",
|
||||
"name_en": "Staff",
|
||||
"name_ar": "موظف",
|
||||
"description": "Staff source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 1,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.pxsource",
|
||||
"pk": "83f23608-2288-4d86-ae43-4db31a91c1bf",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.566Z",
|
||||
"updated_at": "2026-02-25T03:55:21.567Z",
|
||||
"code": "SURVEY",
|
||||
"name_en": "Survey",
|
||||
"name_ar": "استبيان",
|
||||
"description": "Survey source for complaints and inquiries",
|
||||
"source_type": "internal",
|
||||
"contact_email": "",
|
||||
"contact_phone": "",
|
||||
"is_active": true,
|
||||
"metadata": {},
|
||||
"total_complaints": 0,
|
||||
"total_inquiries": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"sourceusage": {
|
||||
"count": 10,
|
||||
"data": [
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "6ea35b90-42eb-4b5b-aab4-3ae29579feac",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.060Z",
|
||||
"updated_at": "2026-02-25T03:55:42.060Z",
|
||||
"source": "31ff949d-4e1b-419d-a0de-f988c41fcc3a",
|
||||
"content_type": 42,
|
||||
"object_id": "8bbf4733-34c8-4dc0-a440-50ac4ab90a22",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "9f01a1f8-7a07-4f4e-9309-8eb8b3655336",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.044Z",
|
||||
"updated_at": "2026-02-25T03:55:42.044Z",
|
||||
"source": "9affe720-438b-43dd-b570-25a7f6e8a5aa",
|
||||
"content_type": 42,
|
||||
"object_id": "1f76952f-4fb6-4eaf-9fd8-2cc441e4ca07",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "860a79b2-f7db-40ba-85d2-ebdc6bc92c9b",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:42.014Z",
|
||||
"updated_at": "2026-02-25T03:55:42.014Z",
|
||||
"source": "0aacdcd8-7aa7-4351-ad52-73a394c0848e",
|
||||
"content_type": 42,
|
||||
"object_id": "f4096f2b-81ba-4eee-8ac8-3ad0bded1797",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "9b253aae-b0ed-4d7c-bbb4-107529e8fa9a",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.960Z",
|
||||
"updated_at": "2026-02-25T03:55:36.960Z",
|
||||
"source": "88060ad8-c771-48a6-ae9d-31fdb993e2f9",
|
||||
"content_type": 42,
|
||||
"object_id": "1fec51ec-ab1c-4c04-9cc4-7d3cf371940d",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "0fba819d-6316-43b5-a9db-1e164bddff79",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:36.940Z",
|
||||
"updated_at": "2026-02-25T03:55:36.940Z",
|
||||
"source": "31ff949d-4e1b-419d-a0de-f988c41fcc3a",
|
||||
"content_type": 42,
|
||||
"object_id": "9da3b845-c425-4bf1-b413-1d10fc1a150d",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "35e36159-d08f-4af4-bc25-8672ba4e40dc",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.890Z",
|
||||
"updated_at": "2026-02-25T03:55:31.890Z",
|
||||
"source": "9affe720-438b-43dd-b570-25a7f6e8a5aa",
|
||||
"content_type": 42,
|
||||
"object_id": "c674b99c-06b3-40c2-9812-0fec40d43ea5",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "c0c9d0a9-a754-4500-8985-f487b7c8811c",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.865Z",
|
||||
"updated_at": "2026-02-25T03:55:31.865Z",
|
||||
"source": "9affe720-438b-43dd-b570-25a7f6e8a5aa",
|
||||
"content_type": 42,
|
||||
"object_id": "c020e66f-0f9a-42ac-9b86-a740d340cd2d",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "ed5a581f-3d4e-4500-a332-1f816bffaa43",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:31.850Z",
|
||||
"updated_at": "2026-02-25T03:55:31.850Z",
|
||||
"source": "31ff949d-4e1b-419d-a0de-f988c41fcc3a",
|
||||
"content_type": 42,
|
||||
"object_id": "312155d3-b384-4e6f-b2e7-f8bd21e7817b",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "0062eefc-e55c-40ff-8ab3-6ea56ca170d7",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:26.805Z",
|
||||
"updated_at": "2026-02-25T03:55:26.805Z",
|
||||
"source": "31ff949d-4e1b-419d-a0de-f988c41fcc3a",
|
||||
"content_type": 42,
|
||||
"object_id": "4f11f759-8061-427d-899b-e0c360d11a20",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "px_sources.sourceusage",
|
||||
"pk": "a6b5e484-28ef-4c65-8fd4-50505042ede7",
|
||||
"fields": {
|
||||
"created_at": "2026-02-25T03:55:21.594Z",
|
||||
"updated_at": "2026-02-25T03:55:21.594Z",
|
||||
"source": "88060ad8-c771-48a6-ae9d-31fdb993e2f9",
|
||||
"content_type": 42,
|
||||
"object_id": "75699d55-58b8-42d2-94c3-ff479a005dad",
|
||||
"hospital": "4ed13883-9632-4534-a007-4942258a5943",
|
||||
"user": null
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
1918
database_export/surveys/surveys_data.json
Normal file
1918
database_export/surveys/surveys_data.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,220 +4,231 @@
|
||||
{% block title %}{% trans "Generate KPI Report" %} - PX360{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<!-- Header -->
|
||||
<header class="mb-6">
|
||||
<a href="{% url 'analytics:kpi_report_list' %}"
|
||||
class="inline-flex items-center gap-2 text-sm font-bold text-blue hover:text-navy mb-3 transition">
|
||||
<i data-lucide="arrow-left" class="w-4 h-4"></i>
|
||||
{% trans "Back to Reports" %}
|
||||
</a>
|
||||
<div class="flex items-center gap-2 text-sm text-slate mb-3">
|
||||
<a href="{% url 'analytics:kpi_report_list' %}" class="hover:text-navy">{% trans "KPI Reports" %}</a>
|
||||
<i data-lucide="chevron-right" class="w-4 h-4"></i>
|
||||
<span class="font-bold text-navy">{% trans "Generate Report" %}</span>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold text-navy flex items-center gap-3">
|
||||
<i data-lucide="file-plus" class="w-7 h-7"></i>
|
||||
<div class="w-10 h-10 bg-blue-50 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="file-plus" class="w-5 h-5 text-blue"></i>
|
||||
</div>
|
||||
{% trans "Generate KPI Report" %}
|
||||
</h1>
|
||||
<p class="text-sm text-slate mt-1">{% trans "Create a new monthly KPI report for a specific hospital and period." %}</p>
|
||||
<p class="text-slate text-sm mt-1">{% trans "Create a new monthly KPI report for a specific hospital and period." %}</p>
|
||||
</header>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Main Form -->
|
||||
<div class="lg:col-span-2">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title flex items-center gap-2">
|
||||
<i data-lucide="settings-2" class="w-4 h-4"></i>
|
||||
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-slate-100 bg-slate-50">
|
||||
<h2 class="font-bold text-navy flex items-center gap-2">
|
||||
<i data-lucide="settings" class="w-5 h-5 text-blue"></i>
|
||||
{% trans "Report Configuration" %}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<form method="post" action="{% url 'analytics:kpi_report_generate_submit' %}"
|
||||
hx-post="{% url 'analytics:kpi_report_generate_submit' %}"
|
||||
hx-target="#form-result"
|
||||
hx-swap="innerHTML">
|
||||
{% csrf_token %}
|
||||
<div class="p-6">
|
||||
<form method="post" action="{% url 'analytics:kpi_report_generate_submit' %}"
|
||||
hx-post="{% url 'analytics:kpi_report_generate_submit' %}"
|
||||
hx-target="#form-result"
|
||||
hx-swap="innerHTML">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="space-y-6">
|
||||
<!-- Report Type -->
|
||||
<div>
|
||||
<label for="report_type" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Report Type" %} <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="report_type" id="report_type" required
|
||||
class="w-full px-4 py-2.5 bg-slate-100 border border-transparent rounded-lg text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Report Type" %}</option>
|
||||
{% for type_value, type_label in report_types %}
|
||||
<option value="{{ type_value }}">{{ type_label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<p class="text-xs text-slate mt-1.5 flex items-center gap-1">
|
||||
<i data-lucide="info" class="w-3 h-3"></i>
|
||||
{% trans "Choose the type of KPI report to generate." %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Hospital -->
|
||||
<div>
|
||||
<label for="hospital" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Hospital" %} <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="hospital" id="hospital" required
|
||||
class="w-full px-4 py-2.5 bg-slate-100 border border-transparent rounded-lg text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Hospital" %}</option>
|
||||
{% for hospital in hospitals %}
|
||||
<option value="{{ hospital.id }}">{{ hospital.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Year and Month -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-6">
|
||||
<!-- Report Type -->
|
||||
<div>
|
||||
<label for="year" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Year" %} <span class="text-red-500">*</span>
|
||||
<label for="report_type" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Report Type" %} <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="year" id="year" required
|
||||
class="w-full px-4 py-2.5 bg-slate-100 border border-transparent rounded-lg text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Year" %}</option>
|
||||
{% for y in years %}
|
||||
<option value="{{ y }}" {% if y == current_year %}selected{% endif %}>{{ y }}</option>
|
||||
<select name="report_type" id="report_type" required
|
||||
class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Report Type" %}</option>
|
||||
{% for type_value, type_label in report_types %}
|
||||
<option value="{{ type_value }}">{{ type_label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<p class="text-xs text-slate mt-1.5 flex items-center gap-1">
|
||||
<i data-lucide="info" class="w-3 h-3"></i>
|
||||
{% trans "Choose the type of KPI report to generate." %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Hospital -->
|
||||
<div>
|
||||
<label for="hospital" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Hospital" %} <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="hospital" id="hospital" required
|
||||
class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Hospital" %}</option>
|
||||
{% for hospital in hospitals %}
|
||||
<option value="{{ hospital.id }}">{{ hospital.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="month" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Month" %} <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="month" id="month" required
|
||||
class="w-full px-4 py-2.5 bg-slate-100 border border-transparent rounded-lg text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Month" %}</option>
|
||||
{% for m, m_label in months %}
|
||||
<option value="{{ m }}" {% if m == current_month %}selected{% endif %}>{{ m_label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info Box -->
|
||||
<div class="bg-blue-50 border border-blue-100 rounded-xl p-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="p-2 bg-blue-100 rounded-lg flex-shrink-0">
|
||||
<i data-lucide="info" class="w-4 h-4 text-blue"></i>
|
||||
</div>
|
||||
<!-- Year and Month -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="text-sm font-bold text-navy">{% trans "Report Generation Information" %}</p>
|
||||
<p class="text-sm text-slate mt-1 leading-relaxed">
|
||||
{% trans "The report will be generated based on data from the selected month. This may take a few moments depending on the amount of data. If a report already exists for this period, it will be regenerated with the latest data." %}
|
||||
</p>
|
||||
<label for="year" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Year" %} <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="year" id="year" required
|
||||
class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Year" %}</option>
|
||||
{% for y in years %}
|
||||
<option value="{{ y }}" {% if y == current_year %}selected{% endif %}>{{ y }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="month" class="block text-xs font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Month" %} <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="month" id="month" required
|
||||
class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:bg-white focus:border-navy focus:ring-2 focus:ring-navy/10 outline-none transition">
|
||||
<option value="">{% trans "Select Month" %}</option>
|
||||
{% for m, m_label in months %}
|
||||
<option value="{{ m }}" {% if m == current_month %}selected{% endif %}>{{ m_label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Result Container -->
|
||||
<div id="form-result"></div>
|
||||
<!-- Info Box -->
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-2xl p-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-10 h-10 bg-blue-100 rounded-xl flex items-center justify-center flex-shrink-0">
|
||||
<i data-lucide="info" class="w-5 h-5 text-blue-600"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-bold text-blue-800">{% trans "Report Generation Information" %}</p>
|
||||
<p class="text-sm text-blue-700 mt-1 leading-relaxed">
|
||||
{% trans "The report will be generated based on data from the selected month. This may take a few moments depending on the amount of data. If a report already exists for this period, it will be regenerated with the latest data." %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons -->
|
||||
<div class="flex gap-3 pt-4 border-t">
|
||||
<button type="submit" class="btn-primary flex-1 flex items-center justify-center gap-2 py-3">
|
||||
<i data-lucide="play" class="w-4 h-4"></i>
|
||||
{% trans "Generate Report" %}
|
||||
</button>
|
||||
<a href="{% url 'analytics:kpi_report_list' %}" class="btn-secondary px-6 py-3">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
<!-- Result Container -->
|
||||
<div id="form-result"></div>
|
||||
|
||||
<!-- Buttons -->
|
||||
<div class="flex gap-3 pt-4 border-t border-slate-100">
|
||||
<button type="submit" class="flex-1 px-6 py-3 bg-navy text-white rounded-xl font-semibold hover:bg-blue transition flex items-center justify-center gap-2 shadow-lg shadow-navy/20">
|
||||
<i data-lucide="play" class="w-5 h-5"></i>
|
||||
{% trans "Generate Report" %}
|
||||
</button>
|
||||
<a href="{% url 'analytics:kpi_report_list' %}" class="px-6 py-3 border border-slate-200 text-slate rounded-xl font-semibold hover:bg-light transition">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar - Available Reports -->
|
||||
<div class="lg:col-span-1">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="text-sm font-bold text-navy flex items-center gap-2">
|
||||
<i data-lucide="list" class="w-4 h-4"></i>
|
||||
<div class="lg:col-span-1 space-y-6">
|
||||
<!-- Report Types Card -->
|
||||
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-slate-100 bg-slate-50">
|
||||
<h3 class="font-bold text-navy flex items-center gap-2">
|
||||
<i data-lucide="list" class="w-5 h-5 text-blue"></i>
|
||||
{% trans "Available KPI Reports" %}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<div class="p-6 space-y-4">
|
||||
<!-- MOH Reports -->
|
||||
<div class="p-2.5 bg-light rounded-lg">
|
||||
<p class="text-[10px] font-bold text-slate uppercase tracking-wider mb-2">
|
||||
<div>
|
||||
<p class="text-[10px] font-bold text-slate uppercase tracking-wider mb-3 flex items-center gap-2">
|
||||
<span class="w-2 h-2 bg-navy rounded-full"></span>
|
||||
{% trans "Ministry of Health" %}
|
||||
</p>
|
||||
<div class="space-y-1.5">
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="px-1.5 py-0.5 text-xs font-bold bg-navy text-white rounded flex-shrink-0">MOH-2</span>
|
||||
<span class="text-slate truncate">{% trans "72-Hour Resolution" %}</span>
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center gap-3 p-2.5 bg-slate-50 rounded-xl hover:bg-blue-50 transition">
|
||||
<span class="px-2.5 py-1 text-xs font-bold bg-navy text-white rounded-lg flex-shrink-0">MOH-2</span>
|
||||
<span class="text-sm text-slate flex-1">{% trans "72-Hour Resolution" %}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="px-1.5 py-0.5 text-xs font-bold bg-navy text-white rounded flex-shrink-0">MOH-1</span>
|
||||
<span class="text-slate truncate">{% trans "Patient Experience" %}</span>
|
||||
<div class="flex items-center gap-3 p-2.5 bg-slate-50 rounded-xl hover:bg-blue-50 transition">
|
||||
<span class="px-2.5 py-1 text-xs font-bold bg-navy text-white rounded-lg flex-shrink-0">MOH-1</span>
|
||||
<span class="text-sm text-slate flex-1">{% trans "Patient Experience" %}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="px-1.5 py-0.5 text-xs font-bold bg-navy text-white rounded flex-shrink-0">MOH-3</span>
|
||||
<span class="text-slate truncate">{% trans "Resolution Satisfaction" %}</span>
|
||||
<div class="flex items-center gap-3 p-2.5 bg-slate-50 rounded-xl hover:bg-blue-50 transition">
|
||||
<span class="px-2.5 py-1 text-xs font-bold bg-navy text-white rounded-lg flex-shrink-0">MOH-3</span>
|
||||
<span class="text-sm text-slate flex-1">{% trans "Resolution Satisfaction" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Department Reports -->
|
||||
<div class="p-2.5 bg-light rounded-lg">
|
||||
<p class="text-[10px] font-bold text-slate uppercase tracking-wider mb-2">
|
||||
<div>
|
||||
<p class="text-[10px] font-bold text-slate uppercase tracking-wider mb-3 flex items-center gap-2">
|
||||
<span class="w-2 h-2 bg-blue rounded-full"></span>
|
||||
{% trans "Departmental" %}
|
||||
</p>
|
||||
<div class="space-y-1.5">
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="px-1.5 py-0.5 text-xs font-bold bg-blue text-white rounded flex-shrink-0">Dep-KPI-4</span>
|
||||
<span class="text-slate truncate">{% trans "Response Rate" %}</span>
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center gap-3 p-2.5 bg-slate-50 rounded-xl hover:bg-blue-50 transition">
|
||||
<span class="px-2.5 py-1 text-xs font-bold bg-blue text-white rounded-lg flex-shrink-0">Dep-KPI-4</span>
|
||||
<span class="text-sm text-slate flex-1">{% trans "Response Rate" %}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="px-1.5 py-0.5 text-xs font-bold bg-blue text-white rounded flex-shrink-0">KPI-6</span>
|
||||
<span class="text-slate truncate">{% trans "Activation (2h)" %}</span>
|
||||
<div class="flex items-center gap-3 p-2.5 bg-slate-50 rounded-xl hover:bg-blue-50 transition">
|
||||
<span class="px-2.5 py-1 text-xs font-bold bg-blue text-white rounded-lg flex-shrink-0">KPI-6</span>
|
||||
<span class="text-sm text-slate flex-1">{% trans "Activation (2h)" %}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="px-1.5 py-0.5 text-xs font-bold bg-blue text-white rounded flex-shrink-0">KPI-7</span>
|
||||
<span class="text-slate truncate">{% trans "Unactivated" %}</span>
|
||||
<div class="flex items-center gap-3 p-2.5 bg-slate-50 rounded-xl hover:bg-blue-50 transition">
|
||||
<span class="px-2.5 py-1 text-xs font-bold bg-blue text-white rounded-lg flex-shrink-0">KPI-7</span>
|
||||
<span class="text-sm text-slate flex-1">{% trans "Unactivated" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- N-PAD Reports -->
|
||||
<div class="p-2.5 bg-light rounded-lg">
|
||||
<p class="text-[10px] font-bold text-slate uppercase tracking-wider mb-2">
|
||||
<div>
|
||||
<p class="text-[10px] font-bold text-slate uppercase tracking-wider mb-3 flex items-center gap-2">
|
||||
<span class="w-2 h-2 bg-navy rounded-full"></span>
|
||||
{% trans "N-PAD Standards" %}
|
||||
</p>
|
||||
<div class="space-y-1.5">
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="px-1.5 py-0.5 text-xs font-bold bg-navy text-white rounded flex-shrink-0">N-PAD-001</span>
|
||||
<span class="text-slate truncate">{% trans "Resolution" %}</span>
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center gap-3 p-2.5 bg-slate-50 rounded-xl hover:bg-blue-50 transition">
|
||||
<span class="px-2.5 py-1 text-xs font-bold bg-navy text-white rounded-lg flex-shrink-0">N-PAD-001</span>
|
||||
<span class="text-sm text-slate flex-1">{% trans "Resolution" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Tips -->
|
||||
<div class="mt-4 pt-4 border-t">
|
||||
<p class="text-[10px] font-bold text-slate uppercase tracking-wider mb-2">
|
||||
{% trans "Quick Tips" %}
|
||||
</p>
|
||||
<ul class="space-y-2 text-sm text-slate">
|
||||
<li class="flex items-start gap-2">
|
||||
<i data-lucide="check-circle" class="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5"></i>
|
||||
<span>{% trans "Reports are generated automatically every month" %}</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-2">
|
||||
<i data-lucide="check-circle" class="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5"></i>
|
||||
<span>{% trans "You can regenerate any report with latest data" %}</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-2">
|
||||
<i data-lucide="check-circle" class="w-4 h-4 text-green-500 flex-shrink-0 mt-0.5"></i>
|
||||
<span>{% trans "PDF export is available for all reports" %}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Quick Tips Card -->
|
||||
<div class="bg-gradient-to-br from-green-50 to-emerald-50 rounded-2xl border border-green-200 p-6">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<div class="w-8 h-8 bg-green-100 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="lightbulb" class="w-4 h-4 text-green-600"></i>
|
||||
</div>
|
||||
<h4 class="font-bold text-green-800">{% trans "Quick Tips" %}</h4>
|
||||
</div>
|
||||
<ul class="space-y-3">
|
||||
<li class="flex items-start gap-3">
|
||||
<i data-lucide="check-circle-2" class="w-5 h-5 text-green-600 flex-shrink-0 mt-0.5"></i>
|
||||
<span class="text-sm text-green-700">{% trans "Reports are generated automatically every month" %}</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<i data-lucide="check-circle-2" class="w-5 h-5 text-green-600 flex-shrink-0 mt-0.5"></i>
|
||||
<span class="text-sm text-green-700">{% trans "You can regenerate any report with latest data" %}</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<i data-lucide="check-circle-2" class="w-5 h-5 text-green-600 flex-shrink-0 mt-0.5"></i>
|
||||
<span class="text-sm text-green-700">{% trans "PDF export is available for all reports" %}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -226,6 +237,8 @@
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
lucide.createIcons();
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
lucide.createIcons();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@ -5,118 +5,162 @@
|
||||
{% block title %}{% trans "Doctor Rating Import Jobs" %} - PX360{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<!-- Header -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="mb-1">
|
||||
<i class="bi bi-clock-history text-primary me-2"></i>
|
||||
{% trans "Import History" %}
|
||||
</h2>
|
||||
<p class="text-muted mb-0">{% trans "Track doctor rating import jobs" %}</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{% url 'physicians:doctor_rating_import' %}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle me-2"></i>{% trans "New Import" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Jobs Table -->
|
||||
<div class="card">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>{% trans "Job Name" %}</th>
|
||||
<th>{% trans "Hospital" %}</th>
|
||||
<th>{% trans "Source" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "Progress" %}</th>
|
||||
<th>{% trans "Results" %}</th>
|
||||
<th>{% trans "Created" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for job in jobs %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ job.name|truncatechars:40 }}</strong>
|
||||
</td>
|
||||
<td>{{ job.hospital.name }}</td>
|
||||
<td>
|
||||
{% if job.source == 'his_api' %}
|
||||
<span class="badge bg-info">{% trans "HIS API" %}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{% trans "CSV Upload" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if job.status == 'pending' %}
|
||||
<span class="badge bg-secondary">{% trans "Pending" %}</span>
|
||||
{% elif job.status == 'processing' %}
|
||||
<span class="badge bg-primary">
|
||||
<span class="spinner-border spinner-border-sm me-1"></span>
|
||||
{% trans "Processing" %}
|
||||
</span>
|
||||
{% elif job.status == 'completed' %}
|
||||
<span class="badge bg-success">{% trans "Completed" %}</span>
|
||||
{% elif job.status == 'failed' %}
|
||||
<span class="badge bg-danger">{% trans "Failed" %}</span>
|
||||
{% elif job.status == 'partial' %}
|
||||
<span class="badge bg-warning text-dark">{% trans "Partial" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="progress flex-grow-1 me-2" style="height: 8px; width: 80px;">
|
||||
<div class="progress-bar {% if job.status == 'failed' %}bg-danger{% elif job.status == 'completed' %}bg-success{% else %}bg-primary{% endif %}"
|
||||
role="progressbar"
|
||||
style="width: {{ job.progress_percentage }}%">
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted">{{ job.progress_percentage }}%</small>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if job.is_complete %}
|
||||
<small>
|
||||
<span class="text-success">{{ job.success_count }} <i class="bi bi-check"></i></span>
|
||||
{% if job.failed_count > 0 %}
|
||||
<span class="text-danger ms-2">{{ job.failed_count }} <i class="bi bi-x"></i></span>
|
||||
{% endif %}
|
||||
</small>
|
||||
{% else %}
|
||||
<small class="text-muted">{{ job.processed_count }} / {{ job.total_records }}</small>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<small class="text-muted">{{ job.created_at|date:"Y-m-d H:i" }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'physicians:doctor_rating_job_status' job.id %}"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="8" class="text-center py-5">
|
||||
<i class="bi bi-inbox" style="font-size: 3rem; color: #ccc;"></i>
|
||||
<p class="text-muted mt-3">{% trans "No import jobs found" %}</p>
|
||||
<a href="{% url 'physicians:doctor_rating_import' %}" class="btn btn-primary mt-2">
|
||||
<i class="bi bi-plus-circle me-2"></i>{% trans "Import Ratings" %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="flex items-center gap-2 text-sm text-slate mb-2">
|
||||
<a href="{% url 'physicians:individual_ratings_list' %}" class="hover:text-navy">{% trans "Physician Ratings" %}</a>
|
||||
<i data-lucide="chevron-right" class="w-4 h-4"></i>
|
||||
<span class="font-bold text-navy">{% trans "Import History" %}</span>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold text-navy flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-blue-50 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="clock" class="w-5 h-5 text-blue"></i>
|
||||
</div>
|
||||
{% trans "Import History" %}
|
||||
</h1>
|
||||
<p class="text-slate text-sm mt-1">{% trans "Track doctor rating import jobs" %}</p>
|
||||
</div>
|
||||
<a href="{% url 'physicians:doctor_rating_import' %}"
|
||||
class="px-6 py-3 bg-navy text-white rounded-xl font-semibold hover:bg-blue transition flex items-center gap-2 shadow-lg shadow-navy/20">
|
||||
<i data-lucide="plus-circle" class="w-5 h-5"></i>
|
||||
{% trans "New Import" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Jobs Table -->
|
||||
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
|
||||
{% if jobs %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead class="bg-slate-50 border-b border-slate-200">
|
||||
<tr>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Job Name" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Hospital" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Source" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Status" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Progress" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Results" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Created" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-4 px-6">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
{% for job in jobs %}
|
||||
<tr class="hover:bg-light/30 transition">
|
||||
<td class="py-4 px-6">
|
||||
<p class="text-sm font-semibold text-navy">{{ job.name|truncatechars:40 }}</p>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<p class="text-sm text-slate">{{ job.hospital.name }}</p>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
{% if job.source == 'his_api' %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-blue-100 text-blue-700">
|
||||
<i data-lucide="database" class="w-3 h-3 mr-1"></i>
|
||||
{% trans "HIS API" %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-slate-100 text-slate-700">
|
||||
<i data-lucide="upload" class="w-3 h-3 mr-1"></i>
|
||||
{% trans "CSV Upload" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
{% if job.status == 'pending' %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-slate-100 text-slate-700">
|
||||
<i data-lucide="clock" class="w-3 h-3 mr-1"></i>
|
||||
{% trans "Pending" %}
|
||||
</span>
|
||||
{% elif job.status == 'processing' %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-blue-100 text-blue-700">
|
||||
<i data-lucide="loader-2" class="w-3 h-3 mr-1 animate-spin"></i>
|
||||
{% trans "Processing" %}
|
||||
</span>
|
||||
{% elif job.status == 'completed' %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-green-100 text-green-700">
|
||||
<i data-lucide="check-circle" class="w-3 h-3 mr-1"></i>
|
||||
{% trans "Completed" %}
|
||||
</span>
|
||||
{% elif job.status == 'failed' %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-red-100 text-red-700">
|
||||
<i data-lucide="x-circle" class="w-3 h-3 mr-1"></i>
|
||||
{% trans "Failed" %}
|
||||
</span>
|
||||
{% elif job.status == 'partial' %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-lg text-xs font-bold bg-amber-100 text-amber-700">
|
||||
<i data-lucide="alert-circle" class="w-3 h-3 mr-1"></i>
|
||||
{% trans "Partial" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex-1 h-2 bg-slate-100 rounded-full overflow-hidden" style="min-width: 80px;">
|
||||
<div class="h-full {% if job.status == 'failed' %}bg-red-500{% elif job.status == 'completed' %}bg-green-500{% else %}bg-blue-500{% endif %} rounded-full transition-all"
|
||||
style="width: {{ job.progress_percentage }}%"></div>
|
||||
</div>
|
||||
<span class="text-xs font-semibold text-slate w-10">{{ job.progress_percentage }}%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
{% if job.is_complete %}
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="inline-flex items-center gap-1 text-xs font-semibold text-green-600">
|
||||
<i data-lucide="check" class="w-3 h-3"></i>
|
||||
{{ job.success_count }}
|
||||
</span>
|
||||
{% if job.failed_count > 0 %}
|
||||
<span class="inline-flex items-center gap-1 text-xs font-semibold text-red-600">
|
||||
<i data-lucide="x" class="w-3 h-3"></i>
|
||||
{{ job.failed_count }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-xs text-slate">{{ job.processed_count }} / {{ job.total_records }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<p class="text-sm text-slate">{{ job.created_at|date:"Y-m-d H:i" }}</p>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<a href="{% url 'physicians:doctor_rating_job_status' job.id %}"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 border border-blue-200 text-blue rounded-lg text-xs font-semibold hover:bg-blue-50 transition">
|
||||
<i data-lucide="eye" class="w-3.5 h-3.5"></i>
|
||||
{% trans "View" %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<!-- Empty State -->
|
||||
<div class="py-16 text-center">
|
||||
<div class="inline-flex items-center justify-center w-20 h-20 bg-slate-100 rounded-full mb-4">
|
||||
<i data-lucide="inbox" class="w-10 h-10 text-slate-400"></i>
|
||||
</div>
|
||||
<h3 class="text-lg font-bold text-navy mb-2">{% trans "No Import Jobs" %}</h3>
|
||||
<p class="text-slate text-sm mb-6">{% trans "No import jobs found. Start by importing doctor ratings." %}</p>
|
||||
<a href="{% url 'physicians:doctor_rating_import' %}"
|
||||
class="inline-flex items-center gap-2 px-6 py-3 bg-navy text-white rounded-xl font-semibold hover:bg-blue transition shadow-lg shadow-navy/20">
|
||||
<i data-lucide="upload" class="w-5 h-5"></i>
|
||||
{% trans "Import Ratings" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
lucide.createIcons();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@ -7,46 +7,69 @@
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.progress-ring {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
.progress-ring-circle {
|
||||
transition: stroke-dashoffset 0.35s;
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
.stat-card {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<!-- Header -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="mb-1">
|
||||
<i class="bi bi-activity text-primary me-2"></i>
|
||||
<div class="flex items-center gap-2 text-sm text-slate mb-2">
|
||||
<a href="{% url 'physicians:doctor_rating_job_list' %}" class="hover:text-navy">{% trans "Import Jobs" %}</a>
|
||||
<i data-lucide="chevron-right" class="w-4 h-4"></i>
|
||||
<span class="font-bold text-navy">{% trans "Job Details" %}</span>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold text-navy flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-blue-50 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="activity" class="w-5 h-5 text-blue"></i>
|
||||
</div>
|
||||
{% trans "Import Job Status" %}
|
||||
</h2>
|
||||
<p class="text-muted mb-0">{{ job.name }}</p>
|
||||
</h1>
|
||||
<p class="text-slate text-sm mt-1">{{ job.name }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{% url 'physicians:doctor_rating_job_list' %}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-list me-2"></i>{% trans "All Jobs" %}
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="{% url 'physicians:doctor_rating_job_list' %}"
|
||||
class="px-4 py-2 border border-slate-200 text-slate rounded-xl font-semibold hover:bg-light transition flex items-center gap-2">
|
||||
<i data-lucide="list" class="w-4 h-4"></i>
|
||||
{% trans "All Jobs" %}
|
||||
</a>
|
||||
<a href="{% url 'physicians:doctor_rating_import' %}"
|
||||
class="px-4 py-2 bg-navy text-white rounded-xl font-semibold hover:bg-blue transition flex items-center gap-2">
|
||||
<i data-lucide="upload" class="w-4 h-4"></i>
|
||||
{% trans "Import More" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Status Card -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card text-center">
|
||||
<div class="card-body">
|
||||
<!-- Progress Circle -->
|
||||
<div class="position-relative d-inline-block mb-3">
|
||||
<div class="lg:col-span-1">
|
||||
<div class="bg-white rounded-2xl p-6 shadow-sm border border-slate-100">
|
||||
<div class="text-center">
|
||||
<!-- Progress Circle -->
|
||||
<div class="inline-flex items-center justify-center mb-4">
|
||||
<div class="relative">
|
||||
<svg class="progress-ring" viewBox="0 0 120 120">
|
||||
<circle
|
||||
class="progress-ring-circle"
|
||||
stroke="#e9ecef"
|
||||
stroke="#f1f5f9"
|
||||
stroke-width="8"
|
||||
fill="transparent"
|
||||
r="52"
|
||||
@ -55,205 +78,261 @@
|
||||
/>
|
||||
<circle
|
||||
class="progress-ring-circle"
|
||||
stroke="{% if job.status == 'completed' %}#28a745{% elif job.status == 'failed' %}#dc3545{% elif job.status == 'partial' %}#ffc107{% else %}#007bbd{% endif %}"
|
||||
stroke="{% if job.status == 'completed' %}#22c55e{% elif job.status == 'failed' %}#ef4444{% elif job.status == 'partial' %}#f59e0b{% else %}#007bbd{% endif %}"
|
||||
stroke-width="8"
|
||||
fill="transparent"
|
||||
r="52"
|
||||
cx="60"
|
||||
cy="60"
|
||||
stroke-dasharray="326.73"
|
||||
stroke-dashoffset="{{ 326.73|add:-progress|div:100|mul:326.73 }}"
|
||||
stroke-dashoffset="{{ stroke_dashoffset }}"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
<div class="position-absolute top-50 start-50 translate-middle">
|
||||
<h3 class="mb-0">{{ progress }}%</h3>
|
||||
<div class="absolute inset-0 flex items-center justify-center">
|
||||
<div class="text-center">
|
||||
<h3 class="text-2xl font-bold text-navy mb-0">{{ progress }}%</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mb-2">
|
||||
{% if job.status == 'pending' %}
|
||||
<span class="badge bg-secondary">{% trans "Pending" %}</span>
|
||||
{% elif job.status == 'processing' %}
|
||||
<span class="badge bg-primary">{% trans "Processing" %}</span>
|
||||
{% elif job.status == 'completed' %}
|
||||
<span class="badge bg-success">{% trans "Completed" %}</span>
|
||||
{% elif job.status == 'failed' %}
|
||||
<span class="badge bg-danger">{% trans "Failed" %}</span>
|
||||
{% elif job.status == 'partial' %}
|
||||
<span class="badge bg-warning text-dark">{% trans "Partial Success" %}</span>
|
||||
{% endif %}
|
||||
</h5>
|
||||
|
||||
{% if not is_complete %}
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">{% trans "Processing..." %}</span>
|
||||
</div>
|
||||
<!-- Status Badge -->
|
||||
<div class="mb-4">
|
||||
{% if job.status == 'pending' %}
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-xl text-sm font-bold bg-slate-100 text-slate-700">
|
||||
<i data-lucide="clock" class="w-4 h-4 mr-2"></i>
|
||||
{% trans "Pending" %}
|
||||
</span>
|
||||
{% elif job.status == 'processing' %}
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-xl text-sm font-bold bg-blue-100 text-blue-700">
|
||||
<i data-lucide="loader-2" class="w-4 h-4 mr-2 animate-spin"></i>
|
||||
{% trans "Processing" %}
|
||||
</span>
|
||||
{% elif job.status == 'completed' %}
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-xl text-sm font-bold bg-green-100 text-green-700">
|
||||
<i data-lucide="check-circle" class="w-4 h-4 mr-2"></i>
|
||||
{% trans "Completed" %}
|
||||
</span>
|
||||
{% elif job.status == 'failed' %}
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-xl text-sm font-bold bg-red-100 text-red-700">
|
||||
<i data-lucide="x-circle" class="w-4 h-4 mr-2"></i>
|
||||
{% trans "Failed" %}
|
||||
</span>
|
||||
{% elif job.status == 'partial' %}
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-xl text-sm font-bold bg-amber-100 text-amber-700">
|
||||
<i data-lucide="alert-circle" class="w-4 h-4 mr-2"></i>
|
||||
{% trans "Partial Success" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if not is_complete %}
|
||||
<div class="flex items-center justify-center gap-2 text-blue">
|
||||
<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i>
|
||||
<span class="text-sm font-semibold">{% trans "Processing..." %}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-sm text-slate">
|
||||
<i data-lucide="check" class="w-4 h-4 inline mr-1"></i>
|
||||
{% trans "Job completed" %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="mb-0">{% trans "Job Details" %}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<table class="table table-borderless table-sm">
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Hospital:" %}</td>
|
||||
<td><strong>{{ job.hospital.name }}</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Source:" %}</td>
|
||||
<td>{{ job.get_source_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Total Records:" %}</td>
|
||||
<td><strong>{{ job.total_records }}</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Created By:" %}</td>
|
||||
<td>{{ job.created_by.get_full_name|default:job.created_by.email }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!-- Job Details -->
|
||||
<div class="lg:col-span-2">
|
||||
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-slate-100 bg-slate-50">
|
||||
<h3 class="font-bold text-navy flex items-center gap-2">
|
||||
<i data-lucide="file-text" class="w-5 h-5 text-blue"></i>
|
||||
{% trans "Job Details" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Hospital" %}</p>
|
||||
<p class="text-sm font-semibold text-navy">{{ job.hospital.name }}</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<table class="table table-borderless table-sm">
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Created:" %}</td>
|
||||
<td>{{ job.created_at|date:"Y-m-d H:i" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Started:" %}</td>
|
||||
<td>{{ job.started_at|date:"Y-m-d H:i"|default:"-" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Completed:" %}</td>
|
||||
<td>{{ job.completed_at|date:"Y-m-d H:i"|default:"-" }}</td>
|
||||
</tr>
|
||||
{% if job.duration_seconds %}
|
||||
<tr>
|
||||
<td class="text-muted">{% trans "Duration:" %}</td>
|
||||
<td>{{ job.duration_seconds }} {% trans "seconds" %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Source" %}</p>
|
||||
<p class="text-sm text-slate">{{ job.get_source_display }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Total Records" %}</p>
|
||||
<p class="text-lg font-bold text-navy">{{ job.total_records }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Created By" %}</p>
|
||||
<p class="text-sm text-slate">{{ job.created_by.get_full_name|default:job.created_by.email }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Created" %}</p>
|
||||
<p class="text-sm text-slate">{{ job.created_at|date:"Y-m-d H:i" }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Started" %}</p>
|
||||
<p class="text-sm text-slate">{{ job.started_at|date:"Y-m-d H:i"|default:"-" }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Completed" %}</p>
|
||||
<p class="text-sm text-slate">{{ job.completed_at|date:"Y-m-d H:i"|default:"-" }}</p>
|
||||
</div>
|
||||
{% if job.duration_seconds %}
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate uppercase mb-1">{% trans "Duration" %}</p>
|
||||
<p class="text-sm font-semibold text-blue">{{ job.duration_seconds }} {% trans "seconds" %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Results Summary -->
|
||||
{% if is_complete %}
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card border-left-success">
|
||||
<div class="card-body text-center">
|
||||
<h2 class="text-success mb-1">{{ job.success_count }}</h2>
|
||||
<span class="text-muted">{% trans "Successful" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card border-left-danger">
|
||||
<div class="card-body text-center">
|
||||
<h2 class="text-danger mb-1">{{ job.failed_count }}</h2>
|
||||
<span class="text-muted">{% trans "Failed" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card border-left-warning">
|
||||
<div class="card-body text-center">
|
||||
<h2 class="text-warning mb-1">{{ job.skipped_count }}</h2>
|
||||
<span class="text-muted">{% trans "Skipped" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card border-left-info">
|
||||
<div class="card-body text-center">
|
||||
<h2 class="text-info mb-1">{{ job.processed_count }}</h2>
|
||||
<span class="text-muted">{% trans "Processed" %}</span>
|
||||
</div>
|
||||
<!-- Results Summary -->
|
||||
{% if is_complete %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mt-6">
|
||||
<div class="stat-card bg-white rounded-2xl p-6 shadow-sm border border-l-4 border-green-500">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="w-12 h-12 bg-green-50 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="check-circle" class="w-6 h-6 text-green-600"></i>
|
||||
</div>
|
||||
<span class="text-xs font-bold text-slate uppercase">{% trans "Successful" %}</span>
|
||||
</div>
|
||||
<p class="text-3xl font-bold text-green-600">{{ job.success_count }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Error Message -->
|
||||
{% if job.error_message %}
|
||||
<div class="alert alert-danger mb-4">
|
||||
<h6 class="alert-heading">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>{% trans "Error" %}
|
||||
</h6>
|
||||
<p class="mb-0">{{ job.error_message }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Detailed Results -->
|
||||
{% if results and results.errors %}
|
||||
<div class="card">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-list-ul me-2"></i>{% trans "Error Details" %}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive" style="max-height: 400px;">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Row" %}</th>
|
||||
<th>{% trans "Error" %}</th>
|
||||
<th>{% trans "Data" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for error in results.errors|slice:":50" %}
|
||||
<tr>
|
||||
<td>{{ error.row }}</td>
|
||||
<td class="text-danger">{{ error.message }}</td>
|
||||
<td><code class="small">{{ error.data|truncatechars:50 }}</code></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="stat-card bg-white rounded-2xl p-6 shadow-sm border border-l-4 border-red-500">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="w-12 h-12 bg-red-50 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="x-circle" class="w-6 h-6 text-red-600"></i>
|
||||
</div>
|
||||
{% if results.errors|length > 50 %}
|
||||
<p class="text-muted small mt-2">
|
||||
{% trans "Showing first 50 errors of" %} {{ results.errors|length }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<span class="text-xs font-bold text-slate uppercase">{% trans "Failed" %}</span>
|
||||
</div>
|
||||
<p class="text-3xl font-bold text-red-600">{{ job.failed_count }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Navigation -->
|
||||
<div class="mt-4">
|
||||
<a href="{% url 'physicians:doctor_rating_import' %}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle me-2"></i>{% trans "Import More Ratings" %}
|
||||
</a>
|
||||
<a href="{% url 'physicians:individual_ratings_list' %}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-list me-2"></i>{% trans "View Imported Ratings" %}
|
||||
</a>
|
||||
<div class="stat-card bg-white rounded-2xl p-6 shadow-sm border border-l-4 border-amber-500">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="w-12 h-12 bg-amber-50 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="skip-forward" class="w-6 h-6 text-amber-600"></i>
|
||||
</div>
|
||||
<span class="text-xs font-bold text-slate uppercase">{% trans "Skipped" %}</span>
|
||||
</div>
|
||||
<p class="text-3xl font-bold text-amber-600">{{ job.skipped_count }}</p>
|
||||
</div>
|
||||
|
||||
<div class="stat-card bg-white rounded-2xl p-6 shadow-sm border border-l-4 border-blue-500">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center">
|
||||
<i data-lucide="layers" class="w-6 h-6 text-blue-600"></i>
|
||||
</div>
|
||||
<span class="text-xs font-bold text-slate uppercase">{% trans "Processed" %}</span>
|
||||
</div>
|
||||
<p class="text-3xl font-bold text-blue-600">{{ job.processed_count }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Error Message -->
|
||||
{% if job.error_message %}
|
||||
<div class="bg-red-50 border border-red-200 rounded-2xl p-6 mt-6">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="w-10 h-10 bg-red-100 rounded-xl flex items-center justify-center flex-shrink-0">
|
||||
<i data-lucide="alert-triangle" class="w-5 h-5 text-red-600"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h4 class="font-bold text-red-800 mb-2 flex items-center gap-2">
|
||||
<i data-lucide="circle-alert" class="w-4 h-4"></i>
|
||||
{% trans "Error" %}
|
||||
</h4>
|
||||
<p class="text-sm text-red-700">{{ job.error_message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Error Details -->
|
||||
{% if results and results.errors %}
|
||||
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 mt-6 overflow-hidden">
|
||||
<div class="px-6 py-4 border-b border-slate-100 bg-slate-50">
|
||||
<h3 class="font-bold text-navy flex items-center gap-2">
|
||||
<i data-lucide="list" class="w-5 h-5 text-blue"></i>
|
||||
{% trans "Error Details" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead class="bg-slate-50 border-b border-slate-200">
|
||||
<tr>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-3 px-4">{% trans "Row" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-3 px-4">{% trans "Error" %}</th>
|
||||
<th class="text-left text-xs font-bold text-slate uppercase tracking-wider py-3 px-4">{% trans "Data" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
{% for error in results.errors|slice:":50" %}
|
||||
<tr class="hover:bg-light/30 transition">
|
||||
<td class="py-3 px-4">
|
||||
<span class="text-sm font-mono text-slate">{{ error.row }}</span>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
<span class="text-sm text-red-600">{{ error.message }}</span>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
<code class="text-xs bg-slate-100 px-2 py-1 rounded">{{ error.data|truncatechars:50 }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if results.errors|length > 50 %}
|
||||
<div class="px-6 py-4 bg-slate-50 border-t border-slate-200">
|
||||
<p class="text-sm text-slate">
|
||||
{% trans "Showing first 50 errors of" %} <strong>{{ results.errors|length }}</strong>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Action Buttons -->
|
||||
{% if is_complete %}
|
||||
<div class="flex items-center gap-4 mt-6">
|
||||
<a href="{% url 'physicians:individual_ratings_list' %}"
|
||||
class="px-6 py-3 bg-navy text-white rounded-xl font-semibold hover:bg-blue transition flex items-center gap-2 shadow-lg shadow-navy/20">
|
||||
<i data-lucide="list" class="w-5 h-5"></i>
|
||||
{% trans "View Imported Ratings" %}
|
||||
</a>
|
||||
<a href="{% url 'physicians:doctor_rating_import' %}"
|
||||
class="px-6 py-3 border border-slate-200 text-slate rounded-xl font-semibold hover:bg-light transition flex items-center gap-2">
|
||||
<i data-lucide="upload" class="w-5 h-5"></i>
|
||||
{% trans "Import More Ratings" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{% if not is_complete %}
|
||||
<script>
|
||||
// Auto-refresh page every 3 seconds while job is processing
|
||||
setTimeout(function() {
|
||||
window.location.reload();
|
||||
}, 3000);
|
||||
</script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
lucide.createIcons();
|
||||
});
|
||||
|
||||
{% if not is_complete %}
|
||||
// Auto-refresh page every 3 seconds while job is processing
|
||||
setTimeout(function() {
|
||||
window.location.reload();
|
||||
}, 3000);
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user