diff --git a/.DS_Store b/.DS_Store index 6932e4b1..feb9a3ee 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.idea/misc.xml b/.idea/misc.xml index 9027e22a..cfe73808 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -14,4 +14,7 @@ + + \ No newline at end of file diff --git a/accounts/__pycache__/flows.cpython-312.pyc b/accounts/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..b12ee7ba Binary files /dev/null and b/accounts/__pycache__/flows.cpython-312.pyc differ diff --git a/accounts/__pycache__/forms.cpython-312.pyc b/accounts/__pycache__/forms.cpython-312.pyc index 5dca14a0..6708f721 100644 Binary files a/accounts/__pycache__/forms.cpython-312.pyc and b/accounts/__pycache__/forms.cpython-312.pyc differ diff --git a/accounts/__pycache__/views.cpython-312.pyc b/accounts/__pycache__/views.cpython-312.pyc index 46b14088..44e99a6d 100644 Binary files a/accounts/__pycache__/views.cpython-312.pyc and b/accounts/__pycache__/views.cpython-312.pyc differ diff --git a/accounts/flows.py b/accounts/flows.py new file mode 100644 index 00000000..989b74ad --- /dev/null +++ b/accounts/flows.py @@ -0,0 +1,800 @@ +# """ +# Viewflow workflows for accounts app. +# Provides user management, authentication, and security workflows. +# """ +# +# from viewflow import this, jsonstore +# from viewflow.workflow import lock, flow, act +# # from viewflow.base import flow_func +# # from viewflow.workflow.base import Flow +# from viewflow.workflow import celery +# # from viewflow.decorators import flow_view +# from viewflow.jsonstore import CharField +# from viewflow.forms import ModelForm +# from viewflow.fields import ModelField +# from viewflow.workflow.flow.views import CreateProcessView, UpdateProcessView +# from viewflow.workflow.models import Process, Task +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import User, TwoFactorDevice, SocialAccount, UserSession, PasswordHistory +# from .views import * +# +# +# class UserOnboardingProcess(Process): +# """ +# Viewflow process model for user onboarding +# """ +# user = ModelField(User, help_text='Associated user') +# +# # Process status tracking +# registration_submitted = models.BooleanField(default=False) +# account_created = models.BooleanField(default=False) +# email_verified = models.BooleanField(default=False) +# profile_completed = models.BooleanField(default=False) +# permissions_assigned = models.BooleanField(default=False) +# security_setup = models.BooleanField(default=False) +# training_completed = models.BooleanField(default=False) +# onboarding_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'User Onboarding Process' +# verbose_name_plural = 'User Onboarding Processes' +# +# +# class UserOnboardingFlow(flow.Flow): +# """ +# User Onboarding Workflow +# +# This flow manages complete user onboarding from registration +# through account setup, security configuration, and training. +# """ +# +# process_class = UserOnboardingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_user_onboarding) +# .Next(this.register_user) +# ) +# +# register_user = ( +# flow_view(UserRegistrationView) +# .Permission('accounts.can_register_users') +# .Next(this.create_account) +# ) +# +# create_account = ( +# flow_func(this.setup_user_account) +# .Next(this.verify_email) +# ) +# +# verify_email = ( +# flow_view(AccountActivationView) +# .Permission('accounts.can_activate_accounts') +# .Next(this.complete_profile) +# ) +# +# complete_profile = ( +# flow_func(this.setup_user_profile) +# .Next(this.assign_permissions) +# ) +# +# assign_permissions = ( +# flow_view(PermissionManagementView) +# .Permission('accounts.can_manage_permissions') +# .Next(this.setup_security) +# ) +# +# setup_security = ( +# flow_view(TwoFactorSetupView) +# .Permission('accounts.can_setup_security') +# .Next(this.complete_training) +# ) +# +# complete_training = ( +# flow_func(this.assign_training_modules) +# .Next(this.finalize_onboarding) +# ) +# +# finalize_onboarding = ( +# flow_func(this.complete_user_onboarding) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_user_onboarding) +# +# # Flow functions +# def start_user_onboarding(self, activation): +# """Initialize the user onboarding process""" +# process = activation.process +# user = process.user +# +# # Send onboarding notification +# self.notify_onboarding_start(user) +# +# # Create onboarding checklist +# self.create_onboarding_checklist(user) +# +# def setup_user_account(self, activation): +# """Setup user account with initial configuration""" +# process = activation.process +# user = process.user +# +# # Configure account settings +# self.configure_account_settings(user) +# +# # Mark account created +# process.account_created = True +# process.save() +# +# # Send welcome email +# self.send_welcome_email(user) +# +# def setup_user_profile(self, activation): +# """Setup user profile information""" +# process = activation.process +# user = process.user +# +# # Complete profile setup +# self.complete_profile_setup(user) +# +# # Mark profile completed +# process.profile_completed = True +# process.save() +# +# # Generate employee ID if needed +# self.generate_employee_id(user) +# +# def assign_training_modules(self, activation): +# """Assign required training modules""" +# process = activation.process +# user = process.user +# +# # Assign role-based training +# self.assign_role_training(user) +# +# # Mark training assigned +# process.training_completed = True +# process.save() +# +# # Send training notifications +# self.notify_training_assignment(user) +# +# def complete_user_onboarding(self, activation): +# """Complete the user onboarding process""" +# process = activation.process +# user = process.user +# +# # Activate user account +# user.is_active = True +# user.save() +# +# # Mark onboarding completed +# process.onboarding_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_onboarding_completion(user) +# +# # Create initial session +# self.create_initial_session(user) +# +# def end_user_onboarding(self, activation): +# """End the user onboarding workflow""" +# process = activation.process +# +# # Generate onboarding summary +# self.generate_onboarding_summary(process.user) +# +# # Helper methods +# def notify_onboarding_start(self, user): +# """Notify onboarding start""" +# # Notify HR and IT teams +# hr_staff = User.objects.filter(groups__name='HR Staff') +# for staff in hr_staff: +# send_mail( +# subject=f'New User Onboarding: {user.get_full_name()}', +# message=f'User onboarding process started for {user.username}.', +# from_email='accounts@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def create_onboarding_checklist(self, user): +# """Create onboarding checklist""" +# # This would create a checklist for the user +# pass +# +# def configure_account_settings(self, user): +# """Configure initial account settings""" +# # This would set up default account settings +# pass +# +# def send_welcome_email(self, user): +# """Send welcome email to new user""" +# if user.email: +# send_mail( +# subject='Welcome to Hospital Management System', +# message=f'Welcome {user.get_full_name()}! Your account has been created.', +# from_email='accounts@hospital.com', +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# def complete_profile_setup(self, user): +# """Complete user profile setup""" +# # This would complete profile configuration +# pass +# +# def generate_employee_id(self, user): +# """Generate employee ID for user""" +# if not user.employee_id: +# # Generate unique employee ID +# user.employee_id = f"EMP{user.id:06d}" +# user.save() +# +# def assign_role_training(self, user): +# """Assign role-based training modules""" +# # This would assign training based on user role +# pass +# +# def notify_training_assignment(self, user): +# """Notify training assignment""" +# if user.email: +# send_mail( +# subject='Training Modules Assigned', +# message='Training modules have been assigned to your account.', +# from_email='training@hospital.com', +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# def notify_onboarding_completion(self, user): +# """Notify onboarding completion""" +# if user.email: +# send_mail( +# subject='Onboarding Complete', +# message='Your onboarding process has been completed successfully.', +# from_email='accounts@hospital.com', +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# def create_initial_session(self, user): +# """Create initial user session""" +# # This would create the first user session +# pass +# +# def generate_onboarding_summary(self, user): +# """Generate onboarding summary""" +# # This would generate onboarding completion report +# pass +# +# +# class SecurityManagementProcess(Process): +# """ +# Viewflow process model for security management +# """ +# user = ModelField(User, help_text='Associated user') +# +# # Process status tracking +# security_assessment = models.BooleanField(default=False) +# two_factor_setup = models.BooleanField(default=False) +# password_policy_applied = models.BooleanField(default=False) +# session_configured = models.BooleanField(default=False) +# audit_completed = models.BooleanField(default=False) +# compliance_verified = models.BooleanField(default=False) +# security_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Security Management Process' +# verbose_name_plural = 'Security Management Processes' +# +# +# class SecurityManagementFlow(flow.Flow): +# """ +# Security Management Workflow +# +# This flow manages user security setup including two-factor +# authentication, password policies, and compliance verification. +# """ +# +# process_class = SecurityManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_security_management) +# .Next(this.assess_security) +# ) +# +# assess_security = ( +# flow_view(SecurityAuditView) +# .Permission('accounts.can_audit_security') +# .Next(this.setup_two_factor) +# ) +# +# setup_two_factor = ( +# flow_view(TwoFactorSetupView) +# .Permission('accounts.can_setup_two_factor') +# .Next(this.apply_password_policy) +# ) +# +# apply_password_policy = ( +# flow_func(this.enforce_password_policy) +# .Next(this.configure_session) +# ) +# +# configure_session = ( +# flow_view(SessionManagementView) +# .Permission('accounts.can_manage_sessions') +# .Next(this.complete_audit) +# ) +# +# complete_audit = ( +# flow_func(this.perform_security_audit) +# .Next(this.verify_compliance) +# ) +# +# verify_compliance = ( +# flow_view(ComplianceCheckView) +# .Permission('accounts.can_verify_compliance') +# .Next(this.finalize_security) +# ) +# +# finalize_security = ( +# flow_func(this.complete_security_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_security_management) +# +# # Flow functions +# def start_security_management(self, activation): +# """Initialize the security management process""" +# process = activation.process +# user = process.user +# +# # Send security setup notification +# self.notify_security_setup(user) +# +# # Create security checklist +# self.create_security_checklist(user) +# +# def enforce_password_policy(self, activation): +# """Enforce password policy requirements""" +# process = activation.process +# user = process.user +# +# # Apply password policy +# self.apply_password_requirements(user) +# +# # Mark password policy applied +# process.password_policy_applied = True +# process.save() +# +# # Create password history entry +# self.create_password_history(user) +# +# def perform_security_audit(self, activation): +# """Perform comprehensive security audit""" +# process = activation.process +# user = process.user +# +# # Conduct security audit +# audit_results = self.conduct_security_audit(user) +# +# # Mark audit completed +# process.audit_completed = True +# process.save() +# +# # Store audit results +# self.store_audit_results(user, audit_results) +# +# def complete_security_management(self, activation): +# """Complete the security management process""" +# process = activation.process +# user = process.user +# +# # Mark security completed +# process.security_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_security_completion(user) +# +# # Schedule security review +# self.schedule_security_review(user) +# +# def end_security_management(self, activation): +# """End the security management workflow""" +# process = activation.process +# +# # Generate security summary +# self.generate_security_summary(process.user) +# +# # Helper methods +# def notify_security_setup(self, user): +# """Notify security setup start""" +# security_team = User.objects.filter(groups__name='Security Team') +# for staff in security_team: +# send_mail( +# subject=f'Security Setup: {user.get_full_name()}', +# message=f'Security setup process started for {user.username}.', +# from_email='security@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def create_security_checklist(self, user): +# """Create security setup checklist""" +# # This would create security checklist +# pass +# +# def apply_password_requirements(self, user): +# """Apply password policy requirements""" +# # This would enforce password policy +# pass +# +# def create_password_history(self, user): +# """Create password history entry""" +# # This would create password history record +# pass +# +# def conduct_security_audit(self, user): +# """Conduct comprehensive security audit""" +# # This would perform security audit +# return {'status': 'passed', 'issues': []} +# +# def store_audit_results(self, user, results): +# """Store security audit results""" +# # This would store audit results +# pass +# +# def notify_security_completion(self, user): +# """Notify security setup completion""" +# if user.email: +# send_mail( +# subject='Security Setup Complete', +# message='Your security setup has been completed successfully.', +# from_email='security@hospital.com', +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# def schedule_security_review(self, user): +# """Schedule periodic security review""" +# # Schedule security review task +# schedule_security_review.apply_async( +# args=[user.id], +# countdown=86400 * 90 # 90 days +# ) +# +# def generate_security_summary(self, user): +# """Generate security setup summary""" +# # This would generate security summary +# pass +# +# +# class AccountDeactivationProcess(Process): +# """ +# Viewflow process model for account deactivation +# """ +# user = ModelField(User, help_text='Associated user') +# +# # Process status tracking +# deactivation_requested = models.BooleanField(default=False) +# data_backup_completed = models.BooleanField(default=False) +# access_revoked = models.BooleanField(default=False) +# sessions_terminated = models.BooleanField(default=False) +# notifications_sent = models.BooleanField(default=False) +# account_archived = models.BooleanField(default=False) +# deactivation_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Account Deactivation Process' +# verbose_name_plural = 'Account Deactivation Processes' +# +# +# class AccountDeactivationFlow(flow.Flow): +# """ +# Account Deactivation Workflow +# +# This flow manages secure account deactivation including +# data backup, access revocation, and proper archival. +# """ +# +# process_class = AccountDeactivationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_account_deactivation) +# .Next(this.request_deactivation) +# ) +# +# request_deactivation = ( +# flow_view(AccountDeactivationView) +# .Permission('accounts.can_deactivate_accounts') +# .Next(this.backup_data) +# ) +# +# backup_data = ( +# flow_func(this.perform_data_backup) +# .Next(this.revoke_access) +# ) +# +# revoke_access = ( +# flow_func(this.revoke_user_access) +# .Next(this.terminate_sessions) +# ) +# +# terminate_sessions = ( +# flow_func(this.end_user_sessions) +# .Next(this.send_notifications) +# ) +# +# send_notifications = ( +# flow_func(this.notify_deactivation) +# .Next(this.archive_account) +# ) +# +# archive_account = ( +# flow_func(this.archive_user_account) +# .Next(this.complete_deactivation) +# ) +# +# complete_deactivation = ( +# flow_func(this.finalize_account_deactivation) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_account_deactivation) +# +# # Flow functions +# def start_account_deactivation(self, activation): +# """Initialize the account deactivation process""" +# process = activation.process +# user = process.user +# +# # Send deactivation notification +# self.notify_deactivation_start(user) +# +# # Create deactivation checklist +# self.create_deactivation_checklist(user) +# +# def perform_data_backup(self, activation): +# """Perform user data backup""" +# process = activation.process +# user = process.user +# +# # Backup user data +# self.backup_user_data(user) +# +# # Mark backup completed +# process.data_backup_completed = True +# process.save() +# +# # Verify backup integrity +# self.verify_backup_integrity(user) +# +# def revoke_user_access(self, activation): +# """Revoke user access and permissions""" +# process = activation.process +# user = process.user +# +# # Revoke all permissions +# self.revoke_permissions(user) +# +# # Mark access revoked +# process.access_revoked = True +# process.save() +# +# # Log access revocation +# self.log_access_revocation(user) +# +# def end_user_sessions(self, activation): +# """Terminate all user sessions""" +# process = activation.process +# user = process.user +# +# # End all active sessions +# self.terminate_all_sessions(user) +# +# # Mark sessions terminated +# process.sessions_terminated = True +# process.save() +# +# # Log session termination +# self.log_session_termination(user) +# +# def notify_deactivation(self, activation): +# """Send deactivation notifications""" +# process = activation.process +# user = process.user +# +# # Send notifications to relevant parties +# self.send_deactivation_notifications(user) +# +# # Mark notifications sent +# process.notifications_sent = True +# process.save() +# +# def archive_user_account(self, activation): +# """Archive user account""" +# process = activation.process +# user = process.user +# +# # Archive account data +# self.archive_account_data(user) +# +# # Mark account archived +# process.account_archived = True +# process.save() +# +# # Update account status +# self.update_account_status(user) +# +# def finalize_account_deactivation(self, activation): +# """Finalize the account deactivation process""" +# process = activation.process +# user = process.user +# +# # Deactivate user account +# user.is_active = False +# user.save() +# +# # Mark deactivation completed +# process.deactivation_completed = True +# process.save() +# +# # Send final notifications +# self.notify_deactivation_completion(user) +# +# def end_account_deactivation(self, activation): +# """End the account deactivation workflow""" +# process = activation.process +# +# # Generate deactivation summary +# self.generate_deactivation_summary(process.user) +# +# # Helper methods +# def notify_deactivation_start(self, user): +# """Notify deactivation start""" +# hr_staff = User.objects.filter(groups__name='HR Staff') +# for staff in hr_staff: +# send_mail( +# subject=f'Account Deactivation: {user.get_full_name()}', +# message=f'Account deactivation process started for {user.username}.', +# from_email='accounts@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def create_deactivation_checklist(self, user): +# """Create deactivation checklist""" +# # This would create deactivation checklist +# pass +# +# def backup_user_data(self, user): +# """Backup user data""" +# # This would backup all user data +# pass +# +# def verify_backup_integrity(self, user): +# """Verify backup integrity""" +# # This would verify backup completeness +# pass +# +# def revoke_permissions(self, user): +# """Revoke all user permissions""" +# # This would revoke all permissions +# user.groups.clear() +# user.user_permissions.clear() +# +# def log_access_revocation(self, user): +# """Log access revocation""" +# # This would log the access revocation +# pass +# +# def terminate_all_sessions(self, user): +# """Terminate all user sessions""" +# user.user_sessions.filter(is_active=True).update( +# is_active=False, +# ended_at=timezone.now() +# ) +# +# def log_session_termination(self, user): +# """Log session termination""" +# # This would log session termination +# pass +# +# def send_deactivation_notifications(self, user): +# """Send deactivation notifications""" +# # This would send notifications to relevant parties +# pass +# +# def archive_account_data(self, user): +# """Archive account data""" +# # This would archive account data +# pass +# +# def update_account_status(self, user): +# """Update account status""" +# # This would update account status +# pass +# +# def notify_deactivation_completion(self, user): +# """Notify deactivation completion""" +# # This would notify completion +# pass +# +# def generate_deactivation_summary(self, user): +# """Generate deactivation summary""" +# # This would generate deactivation summary +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def schedule_security_review(user_id): +# """Background task to schedule security review""" +# try: +# user = User.objects.get(id=user_id) +# +# # Create security review task +# # This would create a security review task +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def cleanup_expired_sessions(): +# """Background task to cleanup expired sessions""" +# try: +# # Cleanup expired sessions +# expired_sessions = UserSession.objects.filter( +# expires_at__lt=timezone.now(), +# is_active=True +# ) +# +# for session in expired_sessions: +# session.end_session() +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def audit_user_accounts(): +# """Background task to audit user accounts""" +# try: +# # This would perform periodic user account audits +# return True +# except Exception: +# return False +# +# +# @celery.job +# def enforce_password_expiry(): +# """Background task to enforce password expiry""" +# try: +# # This would enforce password expiry policies +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_security_reports(): +# """Background task to generate security reports""" +# try: +# # This would generate periodic security reports +# return True +# except Exception: +# return False +# diff --git a/accounts/forms.py b/accounts/forms.py index e0fcebca..229d940f 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -223,3 +223,721 @@ class PasswordChangeForm(forms.Form): self.user.save() return self.user + +# from django import forms +# from django.contrib.auth.forms import UserCreationForm, PasswordChangeForm +# from django.contrib.auth.models import User, Group +# from django.core.exceptions import ValidationError +# from django.utils import timezone +# from django.contrib.auth.password_validation import validate_password +# from crispy_forms.helper import FormHelper +# from crispy_forms.layout import Layout, Fieldset, Submit, Row, Column, HTML, Div +# from crispy_forms.bootstrap import FormActions +# +# from .models import User, TwoFactorDevice, SocialAccount, UserSession, PasswordHistory +# +# +# class UserRegistrationForm(UserCreationForm): +# """ +# Form for user registration in onboarding workflow +# """ +# first_name = forms.CharField( +# max_length=150, +# required=True, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# last_name = forms.CharField( +# max_length=150, +# required=True, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# email = forms.EmailField( +# required=True, +# widget=forms.EmailInput(attrs={'class': 'form-control'}) +# ) +# employee_id = forms.CharField( +# max_length=50, +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# department = forms.ModelChoiceField( +# queryset=None, # Will be set in __init__ +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# job_title = forms.CharField( +# max_length=200, +# required=True, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# phone_number = forms.CharField( +# max_length=20, +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# start_date = forms.DateField( +# required=True, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# manager = forms.ModelChoiceField( +# queryset=None, # Will be set in __init__ +# required=False, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# +# class Meta: +# model = User +# fields = [ +# 'username', 'first_name', 'last_name', 'email', 'employee_id', +# 'department', 'job_title', 'phone_number', 'start_date', 'manager', +# 'password1', 'password2' +# ] +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# # Set querysets based on tenant +# if tenant: +# from core.models import Department +# self.fields['department'].queryset = Department.objects.filter(tenant=tenant) +# self.fields['manager'].queryset = User.objects.filter( +# tenant=tenant, +# is_active=True, +# groups__name__in=['Managers', 'Department Heads'] +# ) +# +# # Crispy forms helper +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'User Information', +# Row( +# Column('first_name', css_class='form-group col-md-6 mb-0'), +# Column('last_name', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('username', css_class='form-group col-md-6 mb-0'), +# Column('email', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('employee_id', css_class='form-group col-md-6 mb-0'), +# Column('phone_number', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Employment Information', +# Row( +# Column('department', css_class='form-group col-md-6 mb-0'), +# Column('job_title', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('start_date', css_class='form-group col-md-6 mb-0'), +# Column('manager', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Security', +# Row( +# Column('password1', css_class='form-group col-md-6 mb-0'), +# Column('password2', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# FormActions( +# Submit('submit', 'Register User', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean_email(self): +# email = self.cleaned_data.get('email') +# if User.objects.filter(email=email).exists(): +# raise ValidationError('A user with this email already exists.') +# return email +# +# def clean_employee_id(self): +# employee_id = self.cleaned_data.get('employee_id') +# if employee_id and User.objects.filter(employee_id=employee_id).exists(): +# raise ValidationError('A user with this employee ID already exists.') +# return employee_id +# +# +# class AccountActivationForm(forms.Form): +# """ +# Form for account activation in onboarding workflow +# """ +# activation_code = forms.CharField( +# max_length=100, +# required=True, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# terms_accepted = forms.BooleanField( +# required=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# privacy_policy_accepted = forms.BooleanField( +# required=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Account Activation', +# 'activation_code', +# HTML('
'), +# 'terms_accepted', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'privacy_policy_accepted', +# HTML( +# ''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Activate Account', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class TwoFactorSetupForm(forms.ModelForm): +# """ +# Form for two-factor authentication setup +# """ +# device_name = forms.CharField( +# max_length=100, +# required=True, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# device_type = forms.ChoiceField( +# choices=[ +# ('totp', 'Authenticator App (TOTP)'), +# ('sms', 'SMS'), +# ('email', 'Email'), +# ('backup_codes', 'Backup Codes') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# phone_number = forms.CharField( +# max_length=20, +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# verification_code = forms.CharField( +# max_length=10, +# required=True, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# +# class Meta: +# model = TwoFactorDevice +# fields = ['device_name', 'device_type', 'phone_number'] +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Two-Factor Authentication Setup', +# 'device_name', +# 'device_type', +# 'phone_number', +# HTML( +# '
Enter the verification code from your authenticator app or device.
'), +# 'verification_code' +# ), +# FormActions( +# Submit('submit', 'Setup Two-Factor Auth', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean(self): +# cleaned_data = super().clean() +# device_type = cleaned_data.get('device_type') +# phone_number = cleaned_data.get('phone_number') +# +# if device_type == 'sms' and not phone_number: +# raise ValidationError('Phone number is required for SMS two-factor authentication.') +# +# return cleaned_data +# +# +# class PermissionManagementForm(forms.Form): +# """ +# Form for managing user permissions +# """ +# groups = forms.ModelMultipleChoiceField( +# queryset=Group.objects.all(), +# required=False, +# widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'}) +# ) +# is_staff = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# is_superuser = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# access_level = forms.ChoiceField( +# choices=[ +# ('basic', 'Basic Access'), +# ('standard', 'Standard Access'), +# ('advanced', 'Advanced Access'), +# ('admin', 'Administrator Access') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# department_access = forms.ModelMultipleChoiceField( +# queryset=None, # Will be set in __init__ +# required=False, +# widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# from core.models import Department +# self.fields['department_access'].queryset = Department.objects.filter(tenant=tenant) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'User Permissions', +# 'access_level', +# HTML('
'), +# 'is_staff', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'is_superuser', +# HTML(''), +# HTML('
') +# ), +# Fieldset( +# 'Group Memberships', +# 'groups' +# ), +# Fieldset( +# 'Department Access', +# 'department_access' +# ), +# FormActions( +# Submit('submit', 'Update Permissions', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class SecurityAuditForm(forms.Form): +# """ +# Form for security audit configuration +# """ +# audit_type = forms.ChoiceField( +# choices=[ +# ('comprehensive', 'Comprehensive Security Audit'), +# ('password_policy', 'Password Policy Audit'), +# ('access_review', 'Access Rights Review'), +# ('session_audit', 'Session Security Audit'), +# ('two_factor_audit', 'Two-Factor Authentication Audit') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# include_inactive_users = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# check_password_strength = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# review_login_attempts = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# analyze_session_security = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# generate_report = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Security Audit Configuration', +# 'audit_type', +# HTML('
'), +# 'include_inactive_users', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'check_password_strength', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'review_login_attempts', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'analyze_session_security', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'generate_report', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Start Security Audit', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class SessionManagementForm(forms.Form): +# """ +# Form for session management configuration +# """ +# session_timeout = forms.IntegerField( +# min_value=5, +# max_value=1440, +# initial=30, +# widget=forms.NumberInput(attrs={'class': 'form-control'}) +# ) +# max_concurrent_sessions = forms.IntegerField( +# min_value=1, +# max_value=10, +# initial=3, +# widget=forms.NumberInput(attrs={'class': 'form-control'}) +# ) +# require_secure_cookies = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# enable_session_monitoring = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# log_session_events = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# auto_logout_inactive = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Session Configuration', +# Row( +# Column('session_timeout', css_class='form-group col-md-6 mb-0'), +# Column('max_concurrent_sessions', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# HTML('
'), +# 'require_secure_cookies', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'enable_session_monitoring', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'log_session_events', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'auto_logout_inactive', +# HTML( +# ''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Update Session Settings', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class ComplianceCheckForm(forms.Form): +# """ +# Form for compliance verification +# """ +# compliance_standards = forms.MultipleChoiceField( +# choices=[ +# ('hipaa', 'HIPAA Compliance'), +# ('gdpr', 'GDPR Compliance'), +# ('sox', 'SOX Compliance'), +# ('pci_dss', 'PCI DSS Compliance'), +# ('iso27001', 'ISO 27001 Compliance') +# ], +# required=True, +# widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'}) +# ) +# check_password_policies = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# verify_access_controls = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# audit_user_permissions = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# check_data_encryption = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# generate_compliance_report = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Compliance Standards', +# 'compliance_standards' +# ), +# Fieldset( +# 'Compliance Checks', +# HTML('
'), +# 'check_password_policies', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'verify_access_controls', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'audit_user_permissions', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'check_data_encryption', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'generate_compliance_report', +# HTML( +# ''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Start Compliance Check', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class AccountDeactivationForm(forms.Form): +# """ +# Form for account deactivation +# """ +# deactivation_reason = forms.ChoiceField( +# choices=[ +# ('termination', 'Employment Termination'), +# ('resignation', 'Employee Resignation'), +# ('transfer', 'Department Transfer'), +# ('leave', 'Extended Leave'), +# ('security', 'Security Concerns'), +# ('other', 'Other Reason') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# deactivation_date = forms.DateField( +# required=True, +# initial=timezone.now().date(), +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# backup_data = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# transfer_ownership = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# new_owner = forms.ModelChoiceField( +# queryset=None, # Will be set in __init__ +# required=False, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# notify_stakeholders = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# additional_notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}) +# ) +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['new_owner'].queryset = User.objects.filter( +# tenant=tenant, +# is_active=True +# ).exclude(id=self.instance.id if hasattr(self, 'instance') else None) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Deactivation Details', +# Row( +# Column('deactivation_reason', css_class='form-group col-md-6 mb-0'), +# Column('deactivation_date', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'additional_notes' +# ), +# Fieldset( +# 'Data Management', +# HTML('
'), +# 'backup_data', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'transfer_ownership', +# HTML(''), +# HTML('
'), +# 'new_owner' +# ), +# Fieldset( +# 'Notifications', +# HTML('
'), +# 'notify_stakeholders', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Deactivate Account', css_class='btn btn-danger'), +# HTML('Cancel') +# ) +# ) +# +# def clean(self): +# cleaned_data = super().clean() +# transfer_ownership = cleaned_data.get('transfer_ownership') +# new_owner = cleaned_data.get('new_owner') +# +# if transfer_ownership and not new_owner: +# raise ValidationError('New owner must be selected when transferring ownership.') +# +# return cleaned_data +# +# +# class PasswordResetForm(forms.Form): +# """ +# Form for password reset +# """ +# email = forms.EmailField( +# required=True, +# widget=forms.EmailInput(attrs={'class': 'form-control'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Password Reset', +# 'email', +# HTML( +# '
Enter your email address and we will send you a link to reset your password.
') +# ), +# FormActions( +# Submit('submit', 'Send Reset Link', css_class='btn btn-primary'), +# HTML('Back to Login') +# ) +# ) +# +# def clean_email(self): +# email = self.cleaned_data.get('email') +# if not User.objects.filter(email=email, is_active=True).exists(): +# raise ValidationError('No active user found with this email address.') +# return email +# +# +# class PasswordChangeForm(PasswordChangeForm): +# """ +# Enhanced password change form +# """ +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# # Add CSS classes +# for field in self.fields.values(): +# field.widget.attrs['class'] = 'form-control' +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Change Password', +# 'old_password', +# 'new_password1', +# 'new_password2', +# HTML( +# '
Your password must contain at least 8 characters and cannot be too similar to your other personal information.
') +# ), +# FormActions( +# Submit('submit', 'Change Password', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# diff --git a/accounts/views.py b/accounts/views.py index 5a14c533..615079e8 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -2474,3 +2474,650 @@ def upload_avatar(request, pk): # # # +# from django.shortcuts import render, redirect, get_object_or_404 +# from django.contrib.auth import login, logout, authenticate +# from django.contrib.auth.decorators import login_required, permission_required +# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin +# from django.contrib import messages +# from django.views.generic import ( +# CreateView, UpdateView, DeleteView, DetailView, ListView, FormView +# ) +# from django.urls import reverse_lazy, reverse +# from django.http import JsonResponse, HttpResponse +# from django.utils import timezone +# from django.db import transaction, models +# from django.core.mail import send_mail +# from django.conf import settings +# from django.contrib.auth.models import Group +# from viewflow.workflow.flow.views import CreateProcessView, UpdateProcessView +# +# from .models import User, TwoFactorDevice, SocialAccount, UserSession, PasswordHistory +# from .forms import ( +# UserRegistrationForm, AccountActivationForm, TwoFactorSetupForm, +# PermissionManagementForm, SecurityAuditForm, SessionManagementForm, +# ComplianceCheckForm, AccountDeactivationForm, PasswordResetForm, +# PasswordChangeForm +# ) +# from .flows import UserOnboardingFlow, SecurityManagementFlow, AccountDeactivationFlow +# +# +# class UserRegistrationView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for user registration in onboarding workflow +# """ +# model = User +# form_class = UserRegistrationForm +# template_name = 'accounts/user_registration.html' +# permission_required = 'accounts.can_register_users' +# flow_class = UserOnboardingFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create user +# user = form.save(commit=False) +# user.tenant = self.request.user.tenant +# user.is_active = False # Will be activated in workflow +# user.created_by = self.request.user +# user.save() +# +# # Start onboarding workflow +# process = self.flow_class.start.run( +# user=user, +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'User registration initiated for {user.get_full_name()}. ' +# f'Onboarding workflow started.' +# ) +# +# return redirect('accounts:user_detail', pk=user.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Register New User' +# context['breadcrumbs'] = [ +# {'name': 'Home', 'url': reverse('core:dashboard')}, +# {'name': 'Users', 'url': reverse('accounts:user_list')}, +# {'name': 'Register User', 'url': ''} +# ] +# return context +# +# +# class AccountActivationView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for account activation in onboarding workflow +# """ +# form_class = AccountActivationForm +# template_name = 'accounts/account_activation.html' +# permission_required = 'accounts.can_activate_accounts' +# +# def get_success_url(self): +# return reverse('accounts:user_detail', kwargs={'pk': self.kwargs['pk']}) +# +# def form_valid(self, form): +# user = get_object_or_404(User, pk=self.kwargs['pk']) +# activation_code = form.cleaned_data['activation_code'] +# +# # Verify activation code (implement your verification logic) +# if self.verify_activation_code(user, activation_code): +# user.is_active = True +# user.email_verified = True +# user.activated_at = timezone.now() +# user.save() +# +# # Send welcome email +# self.send_welcome_email(user) +# +# messages.success( +# self.request, +# f'Account activated successfully for {user.get_full_name()}.' +# ) +# else: +# messages.error(self.request, 'Invalid activation code.') +# return self.form_invalid(form) +# +# return super().form_valid(form) +# +# def verify_activation_code(self, user, code): +# """Verify activation code (implement your logic)""" +# # This would implement actual verification logic +# return True +# +# def send_welcome_email(self, user): +# """Send welcome email to activated user""" +# if user.email: +# send_mail( +# subject='Welcome to Hospital Management System', +# message=f'Welcome {user.get_full_name()}! Your account has been activated.', +# from_email=settings.DEFAULT_FROM_EMAIL, +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['user'] = get_object_or_404(User, pk=self.kwargs['pk']) +# context['title'] = 'Activate Account' +# return context +# +# +# class TwoFactorSetupView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): +# """ +# View for two-factor authentication setup +# """ +# model = TwoFactorDevice +# form_class = TwoFactorSetupForm +# template_name = 'accounts/two_factor_setup.html' +# permission_required = 'accounts.can_setup_two_factor' +# +# def get_success_url(self): +# return reverse('accounts:security_settings') +# +# def form_valid(self, form): +# device = form.save(commit=False) +# device.user = self.request.user +# device.is_active = True +# device.created_at = timezone.now() +# +# # Generate device-specific configuration +# device.configuration = self.generate_device_config(device.device_type) +# device.save() +# +# messages.success( +# self.request, +# 'Two-factor authentication has been set up successfully.' +# ) +# +# return super().form_valid(form) +# +# def generate_device_config(self, device_type): +# """Generate device-specific configuration""" +# if device_type == 'totp': +# # Generate TOTP secret +# import pyotp +# return {'secret': pyotp.random_base32()} +# elif device_type == 'backup_codes': +# # Generate backup codes +# import secrets +# codes = [secrets.token_hex(4) for _ in range(10)] +# return {'codes': codes} +# return {} +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Setup Two-Factor Authentication' +# return context +# +# +# class PermissionManagementView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for managing user permissions +# """ +# form_class = PermissionManagementForm +# template_name = 'accounts/permission_management.html' +# permission_required = 'accounts.can_manage_permissions' +# +# def get_success_url(self): +# return reverse('accounts:user_detail', kwargs={'pk': self.kwargs['pk']}) +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def get_initial(self): +# user = get_object_or_404(User, pk=self.kwargs['pk']) +# return { +# 'groups': user.groups.all(), +# 'is_staff': user.is_staff, +# 'is_superuser': user.is_superuser, +# 'access_level': getattr(user, 'access_level', 'basic'), +# 'department_access': getattr(user, 'department_access', []) +# } +# +# def form_valid(self, form): +# user = get_object_or_404(User, pk=self.kwargs['pk']) +# +# with transaction.atomic(): +# # Update user permissions +# user.groups.set(form.cleaned_data['groups']) +# user.is_staff = form.cleaned_data['is_staff'] +# user.is_superuser = form.cleaned_data['is_superuser'] +# user.access_level = form.cleaned_data['access_level'] +# user.save() +# +# # Log permission changes +# self.log_permission_changes(user, form.cleaned_data) +# +# messages.success( +# self.request, +# f'Permissions updated successfully for {user.get_full_name()}.' +# ) +# +# return super().form_valid(form) +# +# def log_permission_changes(self, user, changes): +# """Log permission changes for audit""" +# from core.models import AuditLogEntry +# AuditLogEntry.objects.create( +# tenant=user.tenant, +# user=self.request.user, +# event_type='PERMISSION_CHANGE', +# action='UPDATE', +# object_type='User', +# object_id=str(user.id), +# details=changes, +# ip_address=self.request.META.get('REMOTE_ADDR'), +# user_agent=self.request.META.get('HTTP_USER_AGENT', '') +# ) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['user'] = get_object_or_404(User, pk=self.kwargs['pk']) +# context['title'] = 'Manage Permissions' +# return context +# +# +# class SecurityAuditView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for security audit configuration +# """ +# form_class = SecurityAuditForm +# template_name = 'accounts/security_audit.html' +# permission_required = 'accounts.can_audit_security' +# +# def get_success_url(self): +# return reverse('accounts:security_dashboard') +# +# def form_valid(self, form): +# audit_config = form.cleaned_data +# +# # Start security audit workflow +# process = SecurityManagementFlow.start.run( +# user=self.request.user, +# audit_config=audit_config, +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# 'Security audit has been initiated. You will receive a notification when complete.' +# ) +# +# return super().form_valid(form) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Security Audit' +# context['recent_audits'] = self.get_recent_audits() +# return context +# +# def get_recent_audits(self): +# """Get recent security audits""" +# # This would return recent audit records +# return [] +# +# +# class SessionManagementView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for session management configuration +# """ +# form_class = SessionManagementForm +# template_name = 'accounts/session_management.html' +# permission_required = 'accounts.can_manage_sessions' +# +# def get_success_url(self): +# return reverse('accounts:security_settings') +# +# def get_initial(self): +# # Get current session settings +# return { +# 'session_timeout': getattr(settings, 'SESSION_COOKIE_AGE', 1800) // 60, +# 'max_concurrent_sessions': 3, +# 'require_secure_cookies': getattr(settings, 'SESSION_COOKIE_SECURE', True), +# 'enable_session_monitoring': True, +# 'log_session_events': True, +# 'auto_logout_inactive': True +# } +# +# def form_valid(self, form): +# config = form.cleaned_data +# +# # Update session configuration +# self.update_session_config(config) +# +# messages.success( +# self.request, +# 'Session management settings updated successfully.' +# ) +# +# return super().form_valid(form) +# +# def update_session_config(self, config): +# """Update session configuration""" +# # This would update session configuration +# pass +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Session Management' +# context['active_sessions'] = self.get_active_sessions() +# return context +# +# def get_active_sessions(self): +# """Get active user sessions""" +# return UserSession.objects.filter( +# user=self.request.user, +# is_active=True +# ).order_by('-created_at') +# +# +# class ComplianceCheckView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for compliance verification +# """ +# form_class = ComplianceCheckForm +# template_name = 'accounts/compliance_check.html' +# permission_required = 'accounts.can_verify_compliance' +# +# def get_success_url(self): +# return reverse('accounts:compliance_dashboard') +# +# def form_valid(self, form): +# compliance_config = form.cleaned_data +# +# # Start compliance check +# self.start_compliance_check(compliance_config) +# +# messages.success( +# self.request, +# 'Compliance check has been initiated. Results will be available shortly.' +# ) +# +# return super().form_valid(form) +# +# def start_compliance_check(self, config): +# """Start compliance verification process""" +# # This would start compliance checking +# pass +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Compliance Check' +# context['compliance_status'] = self.get_compliance_status() +# return context +# +# def get_compliance_status(self): +# """Get current compliance status""" +# return { +# 'hipaa': 'compliant', +# 'gdpr': 'compliant', +# 'sox': 'pending', +# 'pci_dss': 'non_compliant', +# 'iso27001': 'compliant' +# } +# +# +# class AccountDeactivationView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for account deactivation +# """ +# form_class = AccountDeactivationForm +# template_name = 'accounts/account_deactivation.html' +# permission_required = 'accounts.can_deactivate_accounts' +# +# def get_success_url(self): +# return reverse('accounts:user_list') +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# user = get_object_or_404(User, pk=self.kwargs['pk']) +# deactivation_config = form.cleaned_data +# +# # Start account deactivation workflow +# process = AccountDeactivationFlow.start.run( +# user=user, +# deactivation_config=deactivation_config, +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Account deactivation initiated for {user.get_full_name()}.' +# ) +# +# return super().form_valid(form) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['user'] = get_object_or_404(User, pk=self.kwargs['pk']) +# context['title'] = 'Deactivate Account' +# return context +# +# +# class UserListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): +# """ +# View for listing users +# """ +# model = User +# template_name = 'accounts/user_list.html' +# context_object_name = 'users' +# permission_required = 'accounts.view_user' +# paginate_by = 25 +# +# def get_queryset(self): +# queryset = User.objects.filter(tenant=self.request.user.tenant) +# +# # Apply filters +# search = self.request.GET.get('search') +# if search: +# queryset = queryset.filter( +# models.Q(first_name__icontains=search) | +# models.Q(last_name__icontains=search) | +# models.Q(email__icontains=search) | +# models.Q(username__icontains=search) +# ) +# +# department = self.request.GET.get('department') +# if department: +# queryset = queryset.filter(department_id=department) +# +# status = self.request.GET.get('status') +# if status == 'active': +# queryset = queryset.filter(is_active=True) +# elif status == 'inactive': +# queryset = queryset.filter(is_active=False) +# +# return queryset.order_by('last_name', 'first_name') +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Users' +# context['departments'] = self.get_departments() +# context['search'] = self.request.GET.get('search', '') +# context['selected_department'] = self.request.GET.get('department', '') +# context['selected_status'] = self.request.GET.get('status', '') +# return context +# +# def get_departments(self): +# """Get departments for filter""" +# from core.models import Department +# return Department.objects.filter(tenant=self.request.user.tenant) +# +# +# class UserDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): +# """ +# View for user details +# """ +# model = User +# template_name = 'accounts/user_detail.html' +# context_object_name = 'user' +# permission_required = 'accounts.view_user' +# +# def get_queryset(self): +# return User.objects.filter(tenant=self.request.user.tenant) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# user = self.object +# context['title'] = f'{user.get_full_name()}' +# context['two_factor_devices'] = user.two_factor_devices.filter(is_active=True) +# context['recent_sessions'] = user.user_sessions.order_by('-created_at')[:5] +# context['password_history'] = user.password_history.order_by('-created_at')[:5] +# return context +# +# +# class SecurityDashboardView(LoginRequiredMixin, PermissionRequiredMixin, ListView): +# """ +# View for security dashboard +# """ +# template_name = 'accounts/security_dashboard.html' +# permission_required = 'accounts.view_security_dashboard' +# +# def get_queryset(self): +# return None +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Security Dashboard' +# context['security_metrics'] = self.get_security_metrics() +# context['recent_alerts'] = self.get_recent_security_alerts() +# context['compliance_status'] = self.get_compliance_status() +# return context +# +# def get_security_metrics(self): +# """Get security metrics""" +# tenant = self.request.user.tenant +# return { +# 'total_users': User.objects.filter(tenant=tenant).count(), +# 'active_users': User.objects.filter(tenant=tenant, is_active=True).count(), +# 'users_with_2fa': User.objects.filter( +# tenant=tenant, +# two_factor_devices__is_active=True +# ).distinct().count(), +# 'failed_logins_today': 0, # Would be calculated from audit logs +# 'password_expiring_soon': 0 # Would be calculated from password history +# } +# +# def get_recent_security_alerts(self): +# """Get recent security alerts""" +# # This would return recent security alerts +# return [] +# +# def get_compliance_status(self): +# """Get compliance status""" +# return { +# 'hipaa': 'compliant', +# 'gdpr': 'compliant', +# 'sox': 'pending', +# 'pci_dss': 'non_compliant', +# 'iso27001': 'compliant' +# } +# +# +# # AJAX Views +# @login_required +# @permission_required('accounts.can_manage_sessions') +# def terminate_session_ajax(request, session_id): +# """AJAX view to terminate user session""" +# if request.method == 'POST': +# try: +# session = UserSession.objects.get( +# id=session_id, +# user__tenant=request.user.tenant +# ) +# session.end_session() +# +# return JsonResponse({ +# 'success': True, +# 'message': 'Session terminated successfully.' +# }) +# except UserSession.DoesNotExist: +# return JsonResponse({ +# 'success': False, +# 'message': 'Session not found.' +# }) +# +# return JsonResponse({'success': False, 'message': 'Invalid request.'}) +# +# +# @login_required +# @permission_required('accounts.can_reset_passwords') +# def reset_password_ajax(request, user_id): +# """AJAX view to reset user password""" +# if request.method == 'POST': +# try: +# user = User.objects.get( +# id=user_id, +# tenant=request.user.tenant +# ) +# +# # Generate temporary password +# import secrets +# temp_password = secrets.token_urlsafe(12) +# user.set_password(temp_password) +# user.must_change_password = True +# user.save() +# +# # Send password reset email +# send_mail( +# subject='Password Reset', +# message=f'Your temporary password is: {temp_password}', +# from_email=settings.DEFAULT_FROM_EMAIL, +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# return JsonResponse({ +# 'success': True, +# 'message': 'Password reset successfully. User will receive email with temporary password.' +# }) +# except User.DoesNotExist: +# return JsonResponse({ +# 'success': False, +# 'message': 'User not found.' +# }) +# +# return JsonResponse({'success': False, 'message': 'Invalid request.'}) +# +# +# @login_required +# def user_search_ajax(request): +# """AJAX view for user search""" +# query = request.GET.get('q', '') +# if len(query) < 2: +# return JsonResponse({'users': []}) +# +# users = User.objects.filter( +# tenant=request.user.tenant, +# is_active=True +# ).filter( +# models.Q(first_name__icontains=query) | +# models.Q(last_name__icontains=query) | +# models.Q(email__icontains=query) | +# models.Q(username__icontains=query) +# )[:10] +# +# user_data = [ +# { +# 'id': user.id, +# 'name': user.get_full_name(), +# 'email': user.email, +# 'department': user.department.name if user.department else '' +# } +# for user in users +# ] +# +# return JsonResponse({'users': user_data}) +# diff --git a/analytics/.DS_Store b/analytics/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/analytics/.DS_Store differ diff --git a/analytics/__pycache__/flows.cpython-312.pyc b/analytics/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..7b7b8cbe Binary files /dev/null and b/analytics/__pycache__/flows.cpython-312.pyc differ diff --git a/analytics/__pycache__/forms.cpython-312.pyc b/analytics/__pycache__/forms.cpython-312.pyc index bb5f696e..f0ac9348 100644 Binary files a/analytics/__pycache__/forms.cpython-312.pyc and b/analytics/__pycache__/forms.cpython-312.pyc differ diff --git a/analytics/__pycache__/views.cpython-312.pyc b/analytics/__pycache__/views.cpython-312.pyc index 68873074..671641a4 100644 Binary files a/analytics/__pycache__/views.cpython-312.pyc and b/analytics/__pycache__/views.cpython-312.pyc differ diff --git a/analytics/flows.py b/analytics/flows.py new file mode 100644 index 00000000..136b6467 --- /dev/null +++ b/analytics/flows.py @@ -0,0 +1,845 @@ +# """ +# Viewflow workflows for analytics app. +# Provides report generation, dashboard management, and data analysis workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import Dashboard, DashboardWidget, DataSource, Report, ReportExecution, MetricDefinition, MetricValue +# from .views import ( +# ReportGenerationView, DashboardCreationView, DataSourceConfigurationView, +# MetricCalculationView, AnalysisView, VisualizationView, DistributionView, +# SchedulingView, QualityAssuranceView, PerformanceOptimizationView +# ) +# +# +# class ReportGenerationProcess(Process): +# """ +# Viewflow process model for report generation +# """ +# report = ModelField(Report, help_text='Associated report') +# +# # Process status tracking +# report_requested = models.BooleanField(default=False) +# data_extracted = models.BooleanField(default=False) +# data_processed = models.BooleanField(default=False) +# report_generated = models.BooleanField(default=False) +# quality_checked = models.BooleanField(default=False) +# report_distributed = models.BooleanField(default=False) +# generation_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Report Generation Process' +# verbose_name_plural = 'Report Generation Processes' +# +# +# class ReportGenerationFlow(Flow): +# """ +# Report Generation Workflow +# +# This flow manages automated report generation including +# data extraction, processing, quality checks, and distribution. +# """ +# +# process_class = ReportGenerationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_report_generation) +# .Next(this.request_report) +# ) +# +# request_report = ( +# flow_view(ReportGenerationView) +# .Permission('analytics.can_generate_reports') +# .Next(this.extract_data) +# ) +# +# extract_data = ( +# flow_func(this.perform_data_extraction) +# .Next(this.process_data) +# ) +# +# process_data = ( +# flow_func(this.perform_data_processing) +# .Next(this.generate_report) +# ) +# +# generate_report = ( +# flow_func(this.create_report_output) +# .Next(this.check_quality) +# ) +# +# check_quality = ( +# flow_view(QualityAssuranceView) +# .Permission('analytics.can_check_quality') +# .Next(this.distribute_report) +# ) +# +# distribute_report = ( +# flow_view(DistributionView) +# .Permission('analytics.can_distribute_reports') +# .Next(this.complete_generation) +# ) +# +# complete_generation = ( +# flow_func(this.finalize_report_generation) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_report_generation) +# +# # Flow functions +# def start_report_generation(self, activation): +# """Initialize the report generation process""" +# process = activation.process +# report = process.report +# +# # Create report execution record +# execution = ReportExecution.objects.create( +# report=report, +# execution_type='MANUAL', +# status='PENDING' +# ) +# +# # Send generation notification +# self.notify_generation_start(report, execution) +# +# def perform_data_extraction(self, activation): +# """Extract data from configured sources""" +# process = activation.process +# report = process.report +# +# # Extract data from all configured sources +# extracted_data = self.extract_report_data(report) +# +# # Mark data extracted +# process.data_extracted = True +# process.save() +# +# # Store extracted data +# self.store_extracted_data(report, extracted_data) +# +# def perform_data_processing(self, activation): +# """Process and transform extracted data""" +# process = activation.process +# report = process.report +# +# # Process data according to report configuration +# processed_data = self.process_report_data(report) +# +# # Mark data processed +# process.data_processed = True +# process.save() +# +# # Store processed data +# self.store_processed_data(report, processed_data) +# +# def create_report_output(self, activation): +# """Generate report output in specified format""" +# process = activation.process +# report = process.report +# +# # Generate report in configured format +# report_output = self.generate_report_output(report) +# +# # Mark report generated +# process.report_generated = True +# process.save() +# +# # Store report output +# self.store_report_output(report, report_output) +# +# def finalize_report_generation(self, activation): +# """Finalize the report generation process""" +# process = activation.process +# report = process.report +# +# # Update report execution status +# execution = ReportExecution.objects.filter( +# report=report, +# status='RUNNING' +# ).first() +# +# if execution: +# execution.status = 'COMPLETED' +# execution.completed_at = timezone.now() +# execution.save() +# +# # Mark generation completed +# process.generation_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_generation_completion(report) +# +# # Schedule next execution if recurring +# self.schedule_next_execution(report) +# +# def end_report_generation(self, activation): +# """End the report generation workflow""" +# process = activation.process +# +# # Generate generation summary +# self.generate_generation_summary(process.report) +# +# # Helper methods +# def notify_generation_start(self, report, execution): +# """Notify report generation start""" +# analytics_team = User.objects.filter(groups__name='Analytics Team') +# for staff in analytics_team: +# send_mail( +# subject=f'Report Generation Started: {report.name}', +# message=f'Report generation process started for "{report.name}".', +# from_email='analytics@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def extract_report_data(self, report): +# """Extract data from report sources""" +# # This would implement data extraction logic +# return {'status': 'extracted', 'records': 1000} +# +# def store_extracted_data(self, report, data): +# """Store extracted data""" +# # This would store extracted data +# pass +# +# def process_report_data(self, report): +# """Process and transform report data""" +# # This would implement data processing logic +# return {'status': 'processed', 'records': 1000} +# +# def store_processed_data(self, report, data): +# """Store processed data""" +# # This would store processed data +# pass +# +# def generate_report_output(self, report): +# """Generate report output""" +# # This would generate report in specified format +# return {'status': 'generated', 'file_path': '/reports/output.pdf'} +# +# def store_report_output(self, report, output): +# """Store report output""" +# # This would store report output +# pass +# +# def notify_generation_completion(self, report): +# """Notify report generation completion""" +# # Notify report subscribers +# for subscriber in report.subscribers.all(): +# if subscriber.email: +# send_mail( +# subject=f'Report Ready: {report.name}', +# message=f'Your report "{report.name}" is ready for download.', +# from_email='analytics@hospital.com', +# recipient_list=[subscriber.email], +# fail_silently=True +# ) +# +# def schedule_next_execution(self, report): +# """Schedule next report execution if recurring""" +# if report.is_scheduled and report.schedule_config: +# # Schedule next execution +# schedule_report_execution.apply_async( +# args=[report.report_id], +# countdown=report.schedule_config.get('interval', 86400) +# ) +# +# def generate_generation_summary(self, report): +# """Generate report generation summary""" +# # This would generate generation summary +# pass +# +# +# class DashboardManagementProcess(Process): +# """ +# Viewflow process model for dashboard management +# """ +# dashboard = ModelField(Dashboard, help_text='Associated dashboard') +# +# # Process status tracking +# dashboard_requested = models.BooleanField(default=False) +# data_sources_configured = models.BooleanField(default=False) +# widgets_created = models.BooleanField(default=False) +# layout_configured = models.BooleanField(default=False) +# permissions_set = models.BooleanField(default=False) +# dashboard_tested = models.BooleanField(default=False) +# dashboard_deployed = models.BooleanField(default=False) +# management_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Dashboard Management Process' +# verbose_name_plural = 'Dashboard Management Processes' +# +# +# class DashboardManagementFlow(Flow): +# """ +# Dashboard Management Workflow +# +# This flow manages dashboard creation, configuration, +# and deployment including widgets and data sources. +# """ +# +# process_class = DashboardManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_dashboard_management) +# .Next(this.request_dashboard) +# ) +# +# request_dashboard = ( +# flow_view(DashboardCreationView) +# .Permission('analytics.can_create_dashboards') +# .Next(this.configure_data_sources) +# ) +# +# configure_data_sources = ( +# flow_view(DataSourceConfigurationView) +# .Permission('analytics.can_configure_data_sources') +# .Next(this.create_widgets) +# ) +# +# create_widgets = ( +# flow_func(this.setup_dashboard_widgets) +# .Next(this.configure_layout) +# ) +# +# configure_layout = ( +# flow_func(this.setup_dashboard_layout) +# .Next(this.set_permissions) +# ) +# +# set_permissions = ( +# flow_func(this.configure_dashboard_permissions) +# .Next(this.test_dashboard) +# ) +# +# test_dashboard = ( +# flow_func(this.perform_dashboard_testing) +# .Next(this.deploy_dashboard) +# ) +# +# deploy_dashboard = ( +# flow_func(this.deploy_dashboard_to_production) +# .Next(this.complete_management) +# ) +# +# complete_management = ( +# flow_func(this.finalize_dashboard_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_dashboard_management) +# +# # Flow functions +# def start_dashboard_management(self, activation): +# """Initialize the dashboard management process""" +# process = activation.process +# dashboard = process.dashboard +# +# # Send dashboard creation notification +# self.notify_dashboard_creation(dashboard) +# +# def setup_dashboard_widgets(self, activation): +# """Setup dashboard widgets""" +# process = activation.process +# dashboard = process.dashboard +# +# # Create default widgets based on dashboard type +# self.create_default_widgets(dashboard) +# +# # Mark widgets created +# process.widgets_created = True +# process.save() +# +# def setup_dashboard_layout(self, activation): +# """Setup dashboard layout""" +# process = activation.process +# dashboard = process.dashboard +# +# # Configure dashboard layout +# self.configure_layout_settings(dashboard) +# +# # Mark layout configured +# process.layout_configured = True +# process.save() +# +# def configure_dashboard_permissions(self, activation): +# """Configure dashboard permissions""" +# process = activation.process +# dashboard = process.dashboard +# +# # Set up access permissions +# self.setup_access_permissions(dashboard) +# +# # Mark permissions set +# process.permissions_set = True +# process.save() +# +# def perform_dashboard_testing(self, activation): +# """Perform dashboard testing""" +# process = activation.process +# dashboard = process.dashboard +# +# # Test dashboard functionality +# test_results = self.test_dashboard_functionality(dashboard) +# +# # Mark dashboard tested +# process.dashboard_tested = True +# process.save() +# +# # Store test results +# self.store_test_results(dashboard, test_results) +# +# def deploy_dashboard_to_production(self, activation): +# """Deploy dashboard to production""" +# process = activation.process +# dashboard = process.dashboard +# +# # Deploy dashboard +# self.deploy_dashboard(dashboard) +# +# # Mark dashboard deployed +# process.dashboard_deployed = True +# process.save() +# +# # Activate dashboard +# dashboard.is_active = True +# dashboard.save() +# +# def finalize_dashboard_management(self, activation): +# """Finalize the dashboard management process""" +# process = activation.process +# dashboard = process.dashboard +# +# # Mark management completed +# process.management_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_dashboard_completion(dashboard) +# +# # Schedule dashboard refresh +# self.schedule_dashboard_refresh(dashboard) +# +# def end_dashboard_management(self, activation): +# """End the dashboard management workflow""" +# process = activation.process +# +# # Generate dashboard summary +# self.generate_dashboard_summary(process.dashboard) +# +# # Helper methods +# def notify_dashboard_creation(self, dashboard): +# """Notify dashboard creation""" +# analytics_team = User.objects.filter(groups__name='Analytics Team') +# for staff in analytics_team: +# send_mail( +# subject=f'Dashboard Creation: {dashboard.name}', +# message=f'Dashboard creation process started for "{dashboard.name}".', +# from_email='analytics@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def create_default_widgets(self, dashboard): +# """Create default widgets for dashboard""" +# # This would create default widgets based on dashboard type +# pass +# +# def configure_layout_settings(self, dashboard): +# """Configure dashboard layout settings""" +# # This would configure layout settings +# pass +# +# def setup_access_permissions(self, dashboard): +# """Setup dashboard access permissions""" +# # This would configure access permissions +# pass +# +# def test_dashboard_functionality(self, dashboard): +# """Test dashboard functionality""" +# # This would test dashboard functionality +# return {'status': 'passed', 'issues': []} +# +# def store_test_results(self, dashboard, results): +# """Store dashboard test results""" +# # This would store test results +# pass +# +# def deploy_dashboard(self, dashboard): +# """Deploy dashboard to production""" +# # This would deploy dashboard +# pass +# +# def notify_dashboard_completion(self, dashboard): +# """Notify dashboard completion""" +# # Notify dashboard users +# for user in dashboard.allowed_users.all(): +# if user.email: +# send_mail( +# subject=f'Dashboard Available: {dashboard.name}', +# message=f'Dashboard "{dashboard.name}" is now available.', +# from_email='analytics@hospital.com', +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# def schedule_dashboard_refresh(self, dashboard): +# """Schedule dashboard refresh""" +# # Schedule dashboard refresh task +# refresh_dashboard.apply_async( +# args=[dashboard.dashboard_id], +# countdown=dashboard.refresh_interval +# ) +# +# def generate_dashboard_summary(self, dashboard): +# """Generate dashboard summary""" +# # This would generate dashboard summary +# pass +# +# +# class MetricCalculationProcess(Process): +# """ +# Viewflow process model for metric calculation +# """ +# metric_definition = ModelField(MetricDefinition, help_text='Associated metric definition') +# +# # Process status tracking +# calculation_triggered = models.BooleanField(default=False) +# data_collected = models.BooleanField(default=False) +# metrics_calculated = models.BooleanField(default=False) +# quality_validated = models.BooleanField(default=False) +# thresholds_checked = models.BooleanField(default=False) +# alerts_sent = models.BooleanField(default=False) +# calculation_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Metric Calculation Process' +# verbose_name_plural = 'Metric Calculation Processes' +# +# +# class MetricCalculationFlow(Flow): +# """ +# Metric Calculation Workflow +# +# This flow manages automated metric calculation including +# data collection, calculation, validation, and alerting. +# """ +# +# process_class = MetricCalculationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_metric_calculation) +# .Next(this.trigger_calculation) +# ) +# +# trigger_calculation = ( +# flow_func(this.initiate_calculation) +# .Next(this.collect_data) +# ) +# +# collect_data = ( +# flow_func(this.gather_metric_data) +# .Next(this.calculate_metrics) +# ) +# +# calculate_metrics = ( +# flow_view(MetricCalculationView) +# .Permission('analytics.can_calculate_metrics') +# .Next(this.validate_quality) +# ) +# +# validate_quality = ( +# flow_func(this.perform_quality_validation) +# .Next(this.check_thresholds) +# ) +# +# check_thresholds = ( +# flow_func(this.evaluate_thresholds) +# .Next(this.send_alerts) +# ) +# +# send_alerts = ( +# flow_func(this.dispatch_threshold_alerts) +# .Next(this.complete_calculation) +# ) +# +# complete_calculation = ( +# flow_func(this.finalize_metric_calculation) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_metric_calculation) +# +# # Flow functions +# def start_metric_calculation(self, activation): +# """Initialize the metric calculation process""" +# process = activation.process +# metric = process.metric_definition +# +# # Send calculation notification +# self.notify_calculation_start(metric) +# +# def initiate_calculation(self, activation): +# """Initiate metric calculation""" +# process = activation.process +# metric = process.metric_definition +# +# # Mark calculation triggered +# process.calculation_triggered = True +# process.save() +# +# # Prepare calculation environment +# self.prepare_calculation_environment(metric) +# +# def gather_metric_data(self, activation): +# """Gather data for metric calculation""" +# process = activation.process +# metric = process.metric_definition +# +# # Collect data from configured sources +# collected_data = self.collect_calculation_data(metric) +# +# # Mark data collected +# process.data_collected = True +# process.save() +# +# # Store collected data +# self.store_calculation_data(metric, collected_data) +# +# def perform_quality_validation(self, activation): +# """Perform data quality validation""" +# process = activation.process +# metric = process.metric_definition +# +# # Validate data quality +# quality_results = self.validate_data_quality(metric) +# +# # Mark quality validated +# process.quality_validated = True +# process.save() +# +# # Store quality results +# self.store_quality_results(metric, quality_results) +# +# def evaluate_thresholds(self, activation): +# """Evaluate metric thresholds""" +# process = activation.process +# metric = process.metric_definition +# +# # Check threshold violations +# threshold_results = self.check_metric_thresholds(metric) +# +# # Mark thresholds checked +# process.thresholds_checked = True +# process.save() +# +# # Store threshold results +# self.store_threshold_results(metric, threshold_results) +# +# def dispatch_threshold_alerts(self, activation): +# """Dispatch threshold alerts""" +# process = activation.process +# metric = process.metric_definition +# +# # Send threshold alerts if needed +# self.send_threshold_alerts(metric) +# +# # Mark alerts sent +# process.alerts_sent = True +# process.save() +# +# def finalize_metric_calculation(self, activation): +# """Finalize the metric calculation process""" +# process = activation.process +# metric = process.metric_definition +# +# # Mark calculation completed +# process.calculation_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_calculation_completion(metric) +# +# # Schedule next calculation +# self.schedule_next_calculation(metric) +# +# def end_metric_calculation(self, activation): +# """End the metric calculation workflow""" +# process = activation.process +# +# # Generate calculation summary +# self.generate_calculation_summary(process.metric_definition) +# +# # Helper methods +# def notify_calculation_start(self, metric): +# """Notify metric calculation start""" +# # This would notify relevant parties +# pass +# +# def prepare_calculation_environment(self, metric): +# """Prepare calculation environment""" +# # This would prepare calculation environment +# pass +# +# def collect_calculation_data(self, metric): +# """Collect data for calculation""" +# # This would collect data from configured sources +# return {'status': 'collected', 'records': 1000} +# +# def store_calculation_data(self, metric, data): +# """Store calculation data""" +# # This would store calculation data +# pass +# +# def validate_data_quality(self, metric): +# """Validate data quality""" +# # This would validate data quality +# return {'quality_score': 95, 'issues': []} +# +# def store_quality_results(self, metric, results): +# """Store quality validation results""" +# # This would store quality results +# pass +# +# def check_metric_thresholds(self, metric): +# """Check metric thresholds""" +# # This would check threshold violations +# return {'violations': [], 'status': 'normal'} +# +# def store_threshold_results(self, metric, results): +# """Store threshold check results""" +# # This would store threshold results +# pass +# +# def send_threshold_alerts(self, metric): +# """Send threshold violation alerts""" +# # This would send alerts for threshold violations +# pass +# +# def notify_calculation_completion(self, metric): +# """Notify calculation completion""" +# # This would notify completion +# pass +# +# def schedule_next_calculation(self, metric): +# """Schedule next metric calculation""" +# # Schedule next calculation based on aggregation period +# if metric.aggregation_period == 'HOURLY': +# countdown = 3600 +# elif metric.aggregation_period == 'DAILY': +# countdown = 86400 +# else: +# countdown = 3600 # Default to hourly +# +# calculate_metric.apply_async( +# args=[metric.metric_id], +# countdown=countdown +# ) +# +# def generate_calculation_summary(self, metric): +# """Generate calculation summary""" +# # This would generate calculation summary +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def schedule_report_execution(report_id): +# """Background task to schedule report execution""" +# try: +# report = Report.objects.get(report_id=report_id) +# +# # Create report execution +# execution = ReportExecution.objects.create( +# report=report, +# execution_type='SCHEDULED', +# status='PENDING' +# ) +# +# # Start report generation workflow +# # This would start the report generation workflow +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def refresh_dashboard(dashboard_id): +# """Background task to refresh dashboard data""" +# try: +# dashboard = Dashboard.objects.get(dashboard_id=dashboard_id) +# +# # Refresh all dashboard widgets +# for widget in dashboard.widgets.all(): +# refresh_widget_data(widget) +# +# # Schedule next refresh +# refresh_dashboard.apply_async( +# args=[dashboard_id], +# countdown=dashboard.refresh_interval +# ) +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def calculate_metric(metric_id): +# """Background task to calculate metric values""" +# try: +# metric = MetricDefinition.objects.get(metric_id=metric_id) +# +# # Start metric calculation workflow +# # This would start the metric calculation workflow +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def cleanup_old_reports(): +# """Background task to cleanup old report files""" +# try: +# # This would cleanup old report files +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_analytics_summary(): +# """Background task to generate analytics summary""" +# try: +# # This would generate periodic analytics summary +# return True +# except Exception: +# return False +# +# +# def refresh_widget_data(widget): +# """Helper function to refresh widget data""" +# # This would refresh widget data +# pass +# diff --git a/analytics/forms.py b/analytics/forms.py index f4b71d15..e4ca6158 100644 --- a/analytics/forms.py +++ b/analytics/forms.py @@ -396,3 +396,724 @@ class MetricDefinitionForm(forms.ModelForm): return cleaned_data + +# from django import forms +# from django.core.exceptions import ValidationError +# from django.utils import timezone +# from crispy_forms.helper import FormHelper +# from crispy_forms.layout import Layout, Fieldset, Submit, Row, Column, HTML, Div +# from crispy_forms.bootstrap import FormActions +# import json +# +# from .models import Dashboard, DashboardWidget, DataSource, Report, MetricDefinition +# from core.models import Tenant +# +# +# class ReportGenerationForm(forms.ModelForm): +# """ +# Form for report generation configuration +# """ +# parameters = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}) +# ) +# output_format = forms.ChoiceField( +# choices=[ +# ('pdf', 'PDF'), +# ('excel', 'Excel'), +# ('csv', 'CSV'), +# ('json', 'JSON') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# schedule_execution = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# execution_time = forms.DateTimeField( +# required=False, +# widget=forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}) +# ) +# email_recipients = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# +# class Meta: +# model = Report +# fields = [ +# 'name', 'description', 'report_type', 'data_sources', +# 'parameters', 'output_format', 'schedule_execution', +# 'execution_time', 'email_recipients' +# ] +# widgets = { +# 'name': forms.TextInput(attrs={'class': 'form-control'}), +# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), +# 'report_type': forms.Select(attrs={'class': 'form-control'}), +# 'data_sources': forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['data_sources'].queryset = DataSource.objects.filter(tenant=tenant) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Report Configuration', +# Row( +# Column('name', css_class='form-group col-md-6 mb-0'), +# Column('report_type', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'description', +# 'data_sources', +# 'parameters' +# ), +# Fieldset( +# 'Output Settings', +# Row( +# Column('output_format', css_class='form-group col-md-6 mb-0'), +# Column('email_recipients', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Scheduling', +# HTML('
'), +# 'schedule_execution', +# HTML( +# ''), +# HTML('
'), +# 'execution_time' +# ), +# FormActions( +# Submit('submit', 'Generate Report', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean_parameters(self): +# parameters = self.cleaned_data.get('parameters') +# if parameters: +# try: +# json.loads(parameters) +# except json.JSONDecodeError: +# raise ValidationError('Parameters must be valid JSON.') +# return parameters +# +# def clean(self): +# cleaned_data = super().clean() +# schedule_execution = cleaned_data.get('schedule_execution') +# execution_time = cleaned_data.get('execution_time') +# +# if schedule_execution and not execution_time: +# raise ValidationError('Execution time is required when scheduling execution.') +# +# return cleaned_data +# +# +# class DashboardCreationForm(forms.ModelForm): +# """ +# Form for dashboard creation +# """ +# layout_template = forms.ChoiceField( +# choices=[ +# ('grid_2x2', '2x2 Grid'), +# ('grid_3x3', '3x3 Grid'), +# ('sidebar_main', 'Sidebar + Main'), +# ('top_bottom', 'Top + Bottom'), +# ('custom', 'Custom Layout') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# copy_from_dashboard = forms.ModelChoiceField( +# queryset=None, +# required=False, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# +# class Meta: +# model = Dashboard +# fields = [ +# 'name', 'description', 'dashboard_type', 'layout_template', +# 'refresh_interval', 'is_public', 'allowed_roles', +# 'copy_from_dashboard' +# ] +# widgets = { +# 'name': forms.TextInput(attrs={'class': 'form-control'}), +# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), +# 'dashboard_type': forms.Select(attrs={'class': 'form-control'}), +# 'refresh_interval': forms.NumberInput(attrs={'class': 'form-control'}), +# 'is_public': forms.CheckboxInput(attrs={'class': 'form-check-input'}), +# 'allowed_roles': forms.Textarea(attrs={'class': 'form-control', 'rows': 2}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['copy_from_dashboard'].queryset = Dashboard.objects.filter( +# tenant=tenant, +# is_active=True +# ) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Dashboard Information', +# Row( +# Column('name', css_class='form-group col-md-6 mb-0'), +# Column('dashboard_type', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'description' +# ), +# Fieldset( +# 'Layout Configuration', +# Row( +# Column('layout_template', css_class='form-group col-md-6 mb-0'), +# Column('refresh_interval', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'copy_from_dashboard' +# ), +# Fieldset( +# 'Access Control', +# HTML('
'), +# 'is_public', +# HTML(''), +# HTML('
'), +# 'allowed_roles' +# ), +# FormActions( +# Submit('submit', 'Create Dashboard', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class DataSourceConfigurationForm(forms.ModelForm): +# """ +# Form for data source configuration +# """ +# test_connection = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = DataSource +# fields = [ +# 'name', 'description', 'source_type', 'connection_config', +# 'query_config', 'refresh_interval', 'is_active', +# 'test_connection' +# ] +# widgets = { +# 'name': forms.TextInput(attrs={'class': 'form-control'}), +# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), +# 'source_type': forms.Select(attrs={'class': 'form-control'}), +# 'connection_config': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}), +# 'query_config': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}), +# 'refresh_interval': forms.NumberInput(attrs={'class': 'form-control'}), +# 'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# } +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Data Source Information', +# Row( +# Column('name', css_class='form-group col-md-6 mb-0'), +# Column('source_type', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'description' +# ), +# Fieldset( +# 'Connection Configuration', +# 'connection_config', +# HTML('Enter connection details in JSON format') +# ), +# Fieldset( +# 'Query Configuration', +# 'query_config', +# HTML('Enter query configuration in JSON format') +# ), +# Fieldset( +# 'Settings', +# Row( +# Column('refresh_interval', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# HTML('
'), +# 'is_active', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'test_connection', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Save Data Source', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean_connection_config(self): +# config = self.cleaned_data.get('connection_config') +# if config: +# try: +# json.loads(config) +# except json.JSONDecodeError: +# raise ValidationError('Connection configuration must be valid JSON.') +# return config +# +# def clean_query_config(self): +# config = self.cleaned_data.get('query_config') +# if config: +# try: +# json.loads(config) +# except json.JSONDecodeError: +# raise ValidationError('Query configuration must be valid JSON.') +# return config +# +# +# class MetricCalculationForm(forms.ModelForm): +# """ +# Form for metric calculation configuration +# """ +# calculate_now = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# date_range_start = forms.DateField( +# required=False, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# date_range_end = forms.DateField( +# required=False, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# +# class Meta: +# model = MetricDefinition +# fields = [ +# 'name', 'description', 'metric_type', 'data_source', +# 'calculation_config', 'aggregation_period', 'target_value', +# 'warning_threshold', 'critical_threshold', 'unit_of_measure', +# 'calculate_now', 'date_range_start', 'date_range_end' +# ] +# widgets = { +# 'name': forms.TextInput(attrs={'class': 'form-control'}), +# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), +# 'metric_type': forms.Select(attrs={'class': 'form-control'}), +# 'data_source': forms.Select(attrs={'class': 'form-control'}), +# 'calculation_config': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}), +# 'aggregation_period': forms.Select(attrs={'class': 'form-control'}), +# 'target_value': forms.NumberInput(attrs={'class': 'form-control'}), +# 'warning_threshold': forms.NumberInput(attrs={'class': 'form-control'}), +# 'critical_threshold': forms.NumberInput(attrs={'class': 'form-control'}), +# 'unit_of_measure': forms.TextInput(attrs={'class': 'form-control'}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['data_source'].queryset = DataSource.objects.filter(tenant=tenant) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Metric Definition', +# Row( +# Column('name', css_class='form-group col-md-6 mb-0'), +# Column('metric_type', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'description', +# Row( +# Column('data_source', css_class='form-group col-md-6 mb-0'), +# Column('aggregation_period', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'calculation_config' +# ), +# Fieldset( +# 'Thresholds and Targets', +# Row( +# Column('target_value', css_class='form-group col-md-4 mb-0'), +# Column('warning_threshold', css_class='form-group col-md-4 mb-0'), +# Column('critical_threshold', css_class='form-group col-md-4 mb-0'), +# css_class='form-row' +# ), +# 'unit_of_measure' +# ), +# Fieldset( +# 'Calculation Options', +# HTML('
'), +# 'calculate_now', +# HTML(''), +# HTML('
'), +# Row( +# Column('date_range_start', css_class='form-group col-md-6 mb-0'), +# Column('date_range_end', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# FormActions( +# Submit('submit', 'Save Metric', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean_calculation_config(self): +# config = self.cleaned_data.get('calculation_config') +# if config: +# try: +# json.loads(config) +# except json.JSONDecodeError: +# raise ValidationError('Calculation configuration must be valid JSON.') +# return config +# +# +# class QualityAssuranceForm(forms.Form): +# """ +# Form for quality assurance configuration +# """ +# check_data_accuracy = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# validate_calculations = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# verify_data_sources = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# check_performance = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# generate_qa_report = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# qa_threshold = forms.DecimalField( +# max_digits=5, +# decimal_places=2, +# initial=95.0, +# widget=forms.NumberInput(attrs={'class': 'form-control'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Quality Assurance Checks', +# HTML('
'), +# 'check_data_accuracy', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'validate_calculations', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'verify_data_sources', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'check_performance', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'generate_qa_report', +# HTML(''), +# HTML('
') +# ), +# Fieldset( +# 'Quality Threshold', +# 'qa_threshold', +# HTML('Minimum quality score percentage (0-100)') +# ), +# FormActions( +# Submit('submit', 'Start Quality Check', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class DistributionForm(forms.Form): +# """ +# Form for report distribution configuration +# """ +# distribution_method = forms.ChoiceField( +# choices=[ +# ('email', 'Email'), +# ('download', 'Download Link'), +# ('ftp', 'FTP Upload'), +# ('api', 'API Endpoint'), +# ('dashboard', 'Dashboard Publication') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# recipients = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}) +# ) +# subject = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# message = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}) +# ) +# schedule_distribution = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# distribution_time = forms.DateTimeField( +# required=False, +# widget=forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Distribution Method', +# 'distribution_method', +# 'recipients', +# HTML('Enter email addresses separated by commas') +# ), +# Fieldset( +# 'Message Content', +# 'subject', +# 'message' +# ), +# Fieldset( +# 'Scheduling', +# HTML('
'), +# 'schedule_distribution', +# HTML(''), +# HTML('
'), +# 'distribution_time' +# ), +# FormActions( +# Submit('submit', 'Distribute Report', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean(self): +# cleaned_data = super().clean() +# distribution_method = cleaned_data.get('distribution_method') +# recipients = cleaned_data.get('recipients') +# schedule_distribution = cleaned_data.get('schedule_distribution') +# distribution_time = cleaned_data.get('distribution_time') +# +# if distribution_method == 'email' and not recipients: +# raise ValidationError('Recipients are required for email distribution.') +# +# if schedule_distribution and not distribution_time: +# raise ValidationError('Distribution time is required when scheduling distribution.') +# +# return cleaned_data +# +# +# class VisualizationForm(forms.Form): +# """ +# Form for visualization configuration +# """ +# chart_type = forms.ChoiceField( +# choices=[ +# ('line', 'Line Chart'), +# ('bar', 'Bar Chart'), +# ('pie', 'Pie Chart'), +# ('scatter', 'Scatter Plot'), +# ('heatmap', 'Heat Map'), +# ('gauge', 'Gauge'), +# ('table', 'Data Table') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# title = forms.CharField( +# required=True, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# x_axis_label = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# y_axis_label = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# color_scheme = forms.ChoiceField( +# choices=[ +# ('default', 'Default'), +# ('blue', 'Blue Theme'), +# ('green', 'Green Theme'), +# ('red', 'Red Theme'), +# ('purple', 'Purple Theme'), +# ('custom', 'Custom Colors') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# show_legend = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# show_grid = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Chart Configuration', +# Row( +# Column('chart_type', css_class='form-group col-md-6 mb-0'), +# Column('color_scheme', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'title' +# ), +# Fieldset( +# 'Axis Labels', +# Row( +# Column('x_axis_label', css_class='form-group col-md-6 mb-0'), +# Column('y_axis_label', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Display Options', +# HTML('
'), +# 'show_legend', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'show_grid', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Create Visualization', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class AnalysisForm(forms.Form): +# """ +# Form for data analysis configuration +# """ +# analysis_type = forms.ChoiceField( +# choices=[ +# ('descriptive', 'Descriptive Analysis'), +# ('trend', 'Trend Analysis'), +# ('correlation', 'Correlation Analysis'), +# ('regression', 'Regression Analysis'), +# ('forecasting', 'Forecasting'), +# ('anomaly', 'Anomaly Detection') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# data_source = forms.ModelChoiceField( +# queryset=None, +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# date_range_start = forms.DateField( +# required=True, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# date_range_end = forms.DateField( +# required=True, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# confidence_level = forms.DecimalField( +# max_digits=5, +# decimal_places=2, +# initial=95.0, +# widget=forms.NumberInput(attrs={'class': 'form-control'}) +# ) +# generate_insights = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['data_source'].queryset = DataSource.objects.filter(tenant=tenant) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Analysis Configuration', +# Row( +# Column('analysis_type', css_class='form-group col-md-6 mb-0'), +# Column('data_source', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('date_range_start', css_class='form-group col-md-6 mb-0'), +# Column('date_range_end', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'confidence_level' +# ), +# Fieldset( +# 'Options', +# HTML('
'), +# 'generate_insights', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Start Analysis', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# diff --git a/analytics/views.py b/analytics/views.py index b95327ea..9f2fa7af 100644 --- a/analytics/views.py +++ b/analytics/views.py @@ -3157,4 +3157,731 @@ def report_list(request): # 'count': len(results) # } # -# return render(request, 'analytics/partials/search_results.html', context) \ No newline at end of file +# return render(request, 'analytics/partials/search_results.html', context) + + +# from django.shortcuts import render, redirect, get_object_or_404 +# from django.contrib.auth.decorators import login_required, permission_required +# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin +# from django.contrib import messages +# from django.views.generic import ( +# CreateView, UpdateView, DeleteView, DetailView, ListView, FormView +# ) +# from django.urls import reverse_lazy, reverse +# from django.http import JsonResponse, HttpResponse +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# from django.conf import settings +# from viewflow.views import CreateProcessView, UpdateProcessView +# import json +# +# from .models import Dashboard, DashboardWidget, DataSource, Report, MetricDefinition, ReportExecution +# from .forms import ( +# ReportGenerationForm, DashboardCreationForm, DataSourceConfigurationForm, +# MetricCalculationForm, QualityAssuranceForm, DistributionForm, +# VisualizationForm, AnalysisForm +# ) +# from .flows import ReportGenerationFlow, DashboardManagementFlow, MetricCalculationFlow +# +# +# class ReportGenerationView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for report generation workflow +# """ +# model = Report +# form_class = ReportGenerationForm +# template_name = 'analytics/report_generation.html' +# permission_required = 'analytics.can_generate_reports' +# flow_class = ReportGenerationFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create report +# report = form.save(commit=False) +# report.tenant = self.request.user.tenant +# report.created_by = self.request.user +# report.save() +# +# # Save many-to-many relationships +# form.save_m2m() +# +# # Start report generation workflow +# process = self.flow_class.start.run( +# report=report, +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Report generation initiated for "{report.name}". ' +# f'You will be notified when the report is ready.' +# ) +# +# return redirect('analytics:report_detail', pk=report.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Generate Report' +# context['breadcrumbs'] = [ +# {'name': 'Home', 'url': reverse('core:dashboard')}, +# {'name': 'Analytics', 'url': reverse('analytics:dashboard')}, +# {'name': 'Reports', 'url': reverse('analytics:report_list')}, +# {'name': 'Generate Report', 'url': ''} +# ] +# return context +# +# +# class DashboardCreationView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for dashboard creation workflow +# """ +# model = Dashboard +# form_class = DashboardCreationForm +# template_name = 'analytics/dashboard_creation.html' +# permission_required = 'analytics.can_create_dashboards' +# flow_class = DashboardManagementFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create dashboard +# dashboard = form.save(commit=False) +# dashboard.tenant = self.request.user.tenant +# dashboard.created_by = self.request.user +# dashboard.save() +# +# # Start dashboard creation workflow +# process = self.flow_class.start.run( +# dashboard=dashboard, +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Dashboard "{dashboard.name}" created successfully. ' +# f'You can now add widgets and configure the layout.' +# ) +# +# return redirect('analytics:dashboard_detail', pk=dashboard.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Create Dashboard' +# context['breadcrumbs'] = [ +# {'name': 'Home', 'url': reverse('core:dashboard')}, +# {'name': 'Analytics', 'url': reverse('analytics:dashboard')}, +# {'name': 'Dashboards', 'url': reverse('analytics:dashboard_list')}, +# {'name': 'Create Dashboard', 'url': ''} +# ] +# return context +# +# +# class DataSourceConfigurationView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): +# """ +# View for data source configuration +# """ +# model = DataSource +# form_class = DataSourceConfigurationForm +# template_name = 'analytics/data_source_configuration.html' +# permission_required = 'analytics.can_configure_data_sources' +# +# def get_success_url(self): +# return reverse('analytics:data_source_detail', kwargs={'pk': self.object.pk}) +# +# def form_valid(self, form): +# data_source = form.save(commit=False) +# data_source.tenant = self.request.user.tenant +# data_source.created_by = self.request.user +# data_source.save() +# +# # Test connection if requested +# if form.cleaned_data.get('test_connection'): +# connection_result = self.test_data_source_connection(data_source) +# if connection_result['success']: +# messages.success( +# self.request, +# f'Data source "{data_source.name}" configured successfully. Connection test passed.' +# ) +# else: +# messages.warning( +# self.request, +# f'Data source "{data_source.name}" configured, but connection test failed: {connection_result["error"]}' +# ) +# else: +# messages.success( +# self.request, +# f'Data source "{data_source.name}" configured successfully.' +# ) +# +# return super().form_valid(form) +# +# def test_data_source_connection(self, data_source): +# """Test data source connection""" +# try: +# # Implement connection testing logic based on source type +# if data_source.source_type == 'database': +# return self.test_database_connection(data_source) +# elif data_source.source_type == 'api': +# return self.test_api_connection(data_source) +# elif data_source.source_type == 'file': +# return self.test_file_connection(data_source) +# else: +# return {'success': True} +# except Exception as e: +# return {'success': False, 'error': str(e)} +# +# def test_database_connection(self, data_source): +# """Test database connection""" +# # Implement database connection testing +# return {'success': True} +# +# def test_api_connection(self, data_source): +# """Test API connection""" +# # Implement API connection testing +# return {'success': True} +# +# def test_file_connection(self, data_source): +# """Test file connection""" +# # Implement file connection testing +# return {'success': True} +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Configure Data Source' +# return context +# +# +# class MetricCalculationView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for metric calculation workflow +# """ +# model = MetricDefinition +# form_class = MetricCalculationForm +# template_name = 'analytics/metric_calculation.html' +# permission_required = 'analytics.can_calculate_metrics' +# flow_class = MetricCalculationFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create metric definition +# metric = form.save(commit=False) +# metric.tenant = self.request.user.tenant +# metric.created_by = self.request.user +# metric.save() +# +# # Start metric calculation workflow +# process = self.flow_class.start.run( +# metric=metric, +# calculate_now=form.cleaned_data.get('calculate_now', False), +# date_range_start=form.cleaned_data.get('date_range_start'), +# date_range_end=form.cleaned_data.get('date_range_end'), +# created_by=self.request.user +# ) +# +# if form.cleaned_data.get('calculate_now'): +# messages.success( +# self.request, +# f'Metric "{metric.name}" created and calculation initiated. ' +# f'Results will be available shortly.' +# ) +# else: +# messages.success( +# self.request, +# f'Metric "{metric.name}" created successfully.' +# ) +# +# return redirect('analytics:metric_detail', pk=metric.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Calculate Metric' +# context['breadcrumbs'] = [ +# {'name': 'Home', 'url': reverse('core:dashboard')}, +# {'name': 'Analytics', 'url': reverse('analytics:dashboard')}, +# {'name': 'Metrics', 'url': reverse('analytics:metric_list')}, +# {'name': 'Calculate Metric', 'url': ''} +# ] +# return context +# +# +# class QualityAssuranceView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for quality assurance configuration +# """ +# form_class = QualityAssuranceForm +# template_name = 'analytics/quality_assurance.html' +# permission_required = 'analytics.can_perform_qa' +# +# def get_success_url(self): +# return reverse('analytics:dashboard') +# +# def form_valid(self, form): +# qa_config = form.cleaned_data +# +# # Start quality assurance process +# self.start_quality_assurance(qa_config) +# +# messages.success( +# self.request, +# 'Quality assurance process initiated. You will receive a notification when complete.' +# ) +# +# return super().form_valid(form) +# +# def start_quality_assurance(self, config): +# """Start quality assurance process""" +# # This would start the QA process +# pass +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Quality Assurance' +# context['qa_metrics'] = self.get_qa_metrics() +# return context +# +# def get_qa_metrics(self): +# """Get quality assurance metrics""" +# return { +# 'data_accuracy': 98.5, +# 'calculation_accuracy': 99.2, +# 'source_reliability': 97.8, +# 'performance_score': 95.6 +# } +# +# +# class DistributionView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for report distribution +# """ +# form_class = DistributionForm +# template_name = 'analytics/distribution.html' +# permission_required = 'analytics.can_distribute_reports' +# +# def get_success_url(self): +# return reverse('analytics:report_detail', kwargs={'pk': self.kwargs['pk']}) +# +# def form_valid(self, form): +# report = get_object_or_404(Report, pk=self.kwargs['pk']) +# distribution_config = form.cleaned_data +# +# # Start distribution process +# self.distribute_report(report, distribution_config) +# +# messages.success( +# self.request, +# f'Report "{report.name}" distribution initiated.' +# ) +# +# return super().form_valid(form) +# +# def distribute_report(self, report, config): +# """Distribute report based on configuration""" +# method = config['distribution_method'] +# +# if method == 'email': +# self.distribute_via_email(report, config) +# elif method == 'download': +# self.create_download_link(report, config) +# elif method == 'ftp': +# self.upload_to_ftp(report, config) +# elif method == 'api': +# self.publish_to_api(report, config) +# elif method == 'dashboard': +# self.publish_to_dashboard(report, config) +# +# def distribute_via_email(self, report, config): +# """Distribute report via email""" +# recipients = [email.strip() for email in config['recipients'].split(',')] +# +# send_mail( +# subject=config.get('subject', f'Report: {report.name}'), +# message=config.get('message', f'Please find the attached report: {report.name}'), +# from_email=settings.DEFAULT_FROM_EMAIL, +# recipient_list=recipients, +# fail_silently=False +# ) +# +# def create_download_link(self, report, config): +# """Create download link for report""" +# # Implement download link creation +# pass +# +# def upload_to_ftp(self, report, config): +# """Upload report to FTP server""" +# # Implement FTP upload +# pass +# +# def publish_to_api(self, report, config): +# """Publish report to API endpoint""" +# # Implement API publication +# pass +# +# def publish_to_dashboard(self, report, config): +# """Publish report to dashboard""" +# # Implement dashboard publication +# pass +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['report'] = get_object_or_404(Report, pk=self.kwargs['pk']) +# context['title'] = 'Distribute Report' +# return context +# +# +# class VisualizationView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for visualization configuration +# """ +# form_class = VisualizationForm +# template_name = 'analytics/visualization.html' +# permission_required = 'analytics.can_create_visualizations' +# +# def get_success_url(self): +# return reverse('analytics:dashboard_detail', kwargs={'pk': self.kwargs['pk']}) +# +# def form_valid(self, form): +# dashboard = get_object_or_404(Dashboard, pk=self.kwargs['pk']) +# visualization_config = form.cleaned_data +# +# # Create visualization widget +# widget = self.create_visualization_widget(dashboard, visualization_config) +# +# messages.success( +# self.request, +# f'Visualization "{visualization_config["title"]}" added to dashboard.' +# ) +# +# return super().form_valid(form) +# +# def create_visualization_widget(self, dashboard, config): +# """Create visualization widget""" +# widget = DashboardWidget.objects.create( +# dashboard=dashboard, +# widget_type='chart', +# title=config['title'], +# configuration=config, +# position_x=0, +# position_y=0, +# width=6, +# height=4, +# created_by=self.request.user +# ) +# return widget +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['dashboard'] = get_object_or_404(Dashboard, pk=self.kwargs['pk']) +# context['title'] = 'Create Visualization' +# return context +# +# +# class AnalysisView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for data analysis +# """ +# form_class = AnalysisForm +# template_name = 'analytics/analysis.html' +# permission_required = 'analytics.can_perform_analysis' +# +# def get_success_url(self): +# return reverse('analytics:dashboard') +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# analysis_config = form.cleaned_data +# +# # Start analysis process +# analysis_result = self.perform_analysis(analysis_config) +# +# messages.success( +# self.request, +# 'Data analysis completed successfully. Results are available in the dashboard.' +# ) +# +# return super().form_valid(form) +# +# def perform_analysis(self, config): +# """Perform data analysis""" +# analysis_type = config['analysis_type'] +# +# if analysis_type == 'descriptive': +# return self.descriptive_analysis(config) +# elif analysis_type == 'trend': +# return self.trend_analysis(config) +# elif analysis_type == 'correlation': +# return self.correlation_analysis(config) +# elif analysis_type == 'regression': +# return self.regression_analysis(config) +# elif analysis_type == 'forecasting': +# return self.forecasting_analysis(config) +# elif analysis_type == 'anomaly': +# return self.anomaly_detection(config) +# +# def descriptive_analysis(self, config): +# """Perform descriptive analysis""" +# # Implement descriptive analysis +# return {} +# +# def trend_analysis(self, config): +# """Perform trend analysis""" +# # Implement trend analysis +# return {} +# +# def correlation_analysis(self, config): +# """Perform correlation analysis""" +# # Implement correlation analysis +# return {} +# +# def regression_analysis(self, config): +# """Perform regression analysis""" +# # Implement regression analysis +# return {} +# +# def forecasting_analysis(self, config): +# """Perform forecasting analysis""" +# # Implement forecasting analysis +# return {} +# +# def anomaly_detection(self, config): +# """Perform anomaly detection""" +# # Implement anomaly detection +# return {} +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Data Analysis' +# return context +# +# +# class DashboardListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): +# """ +# View for listing dashboards +# """ +# model = Dashboard +# template_name = 'analytics/dashboard_list.html' +# context_object_name = 'dashboards' +# permission_required = 'analytics.view_dashboard' +# paginate_by = 20 +# +# def get_queryset(self): +# queryset = Dashboard.objects.filter(tenant=self.request.user.tenant) +# +# # Apply filters +# search = self.request.GET.get('search') +# if search: +# queryset = queryset.filter(name__icontains=search) +# +# dashboard_type = self.request.GET.get('type') +# if dashboard_type: +# queryset = queryset.filter(dashboard_type=dashboard_type) +# +# return queryset.order_by('-created_at') +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Dashboards' +# context['search'] = self.request.GET.get('search', '') +# context['selected_type'] = self.request.GET.get('type', '') +# return context +# +# +# class DashboardDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): +# """ +# View for dashboard details +# """ +# model = Dashboard +# template_name = 'analytics/dashboard_detail.html' +# context_object_name = 'dashboard' +# permission_required = 'analytics.view_dashboard' +# +# def get_queryset(self): +# return Dashboard.objects.filter(tenant=self.request.user.tenant) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# dashboard = self.object +# context['title'] = dashboard.name +# context['widgets'] = dashboard.widgets.filter(is_active=True).order_by('position_y', 'position_x') +# context['can_edit'] = self.request.user.has_perm('analytics.change_dashboard') +# return context +# +# +# class ReportListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): +# """ +# View for listing reports +# """ +# model = Report +# template_name = 'analytics/report_list.html' +# context_object_name = 'reports' +# permission_required = 'analytics.view_report' +# paginate_by = 20 +# +# def get_queryset(self): +# queryset = Report.objects.filter(tenant=self.request.user.tenant) +# +# # Apply filters +# search = self.request.GET.get('search') +# if search: +# queryset = queryset.filter(name__icontains=search) +# +# report_type = self.request.GET.get('type') +# if report_type: +# queryset = queryset.filter(report_type=report_type) +# +# return queryset.order_by('-created_at') +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Reports' +# context['search'] = self.request.GET.get('search', '') +# context['selected_type'] = self.request.GET.get('type', '') +# return context +# +# +# class ReportDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): +# """ +# View for report details +# """ +# model = Report +# template_name = 'analytics/report_detail.html' +# context_object_name = 'report' +# permission_required = 'analytics.view_report' +# +# def get_queryset(self): +# return Report.objects.filter(tenant=self.request.user.tenant) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# report = self.object +# context['title'] = report.name +# context['executions'] = report.executions.order_by('-created_at')[:10] +# context['can_generate'] = self.request.user.has_perm('analytics.can_generate_reports') +# return context +# +# +# # AJAX Views +# @login_required +# @permission_required('analytics.can_test_data_sources') +# def test_data_source_ajax(request, data_source_id): +# """AJAX view to test data source connection""" +# if request.method == 'POST': +# try: +# data_source = DataSource.objects.get( +# id=data_source_id, +# tenant=request.user.tenant +# ) +# +# # Test connection +# result = test_data_source_connection(data_source) +# +# return JsonResponse({ +# 'success': result['success'], +# 'message': 'Connection successful' if result['success'] else result.get('error', 'Connection failed') +# }) +# except DataSource.DoesNotExist: +# return JsonResponse({ +# 'success': False, +# 'message': 'Data source not found.' +# }) +# +# return JsonResponse({'success': False, 'message': 'Invalid request.'}) +# +# +# @login_required +# @permission_required('analytics.can_calculate_metrics') +# def calculate_metric_ajax(request, metric_id): +# """AJAX view to calculate metric""" +# if request.method == 'POST': +# try: +# metric = MetricDefinition.objects.get( +# id=metric_id, +# tenant=request.user.tenant +# ) +# +# # Start metric calculation +# process = MetricCalculationFlow.start.run( +# metric=metric, +# calculate_now=True, +# created_by=request.user +# ) +# +# return JsonResponse({ +# 'success': True, +# 'message': 'Metric calculation initiated.' +# }) +# except MetricDefinition.DoesNotExist: +# return JsonResponse({ +# 'success': False, +# 'message': 'Metric not found.' +# }) +# +# return JsonResponse({'success': False, 'message': 'Invalid request.'}) +# +# +# @login_required +# def dashboard_data_ajax(request, dashboard_id): +# """AJAX view to get dashboard data""" +# try: +# dashboard = Dashboard.objects.get( +# id=dashboard_id, +# tenant=request.user.tenant +# ) +# +# widgets_data = [] +# for widget in dashboard.widgets.filter(is_active=True): +# widget_data = { +# 'id': widget.id, +# 'title': widget.title, +# 'type': widget.widget_type, +# 'position': { +# 'x': widget.position_x, +# 'y': widget.position_y, +# 'width': widget.width, +# 'height': widget.height +# }, +# 'data': widget.get_data() # This would be implemented in the model +# } +# widgets_data.append(widget_data) +# +# return JsonResponse({ +# 'success': True, +# 'dashboard': { +# 'id': dashboard.id, +# 'name': dashboard.name, +# 'widgets': widgets_data +# } +# }) +# except Dashboard.DoesNotExist: +# return JsonResponse({ +# 'success': False, +# 'message': 'Dashboard not found.' +# }) +# +# +# def test_data_source_connection(data_source): +# """Test data source connection""" +# try: +# # Implement connection testing logic +# return {'success': True} +# except Exception as e: +# return {'success': False, 'error': str(e)} +# diff --git a/appointments/__pycache__/flows.cpython-312.pyc b/appointments/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..218b52df Binary files /dev/null and b/appointments/__pycache__/flows.cpython-312.pyc differ diff --git a/appointments/__pycache__/forms.cpython-312.pyc b/appointments/__pycache__/forms.cpython-312.pyc index 18bfe31a..f0c15bd1 100644 Binary files a/appointments/__pycache__/forms.cpython-312.pyc and b/appointments/__pycache__/forms.cpython-312.pyc differ diff --git a/appointments/__pycache__/views.cpython-312.pyc b/appointments/__pycache__/views.cpython-312.pyc index 29ac94d5..8992cf75 100644 Binary files a/appointments/__pycache__/views.cpython-312.pyc and b/appointments/__pycache__/views.cpython-312.pyc differ diff --git a/appointments/flows.py b/appointments/flows.py new file mode 100644 index 00000000..f68bbf2e --- /dev/null +++ b/appointments/flows.py @@ -0,0 +1,871 @@ +# """ +# Viewflow workflows for appointments app. +# Provides appointment scheduling, confirmation, and queue management workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import AppointmentRequest, SlotAvailability, WaitingQueue, QueueEntry +# from .views import ( +# AppointmentRequestView, AvailabilityCheckView, AppointmentSchedulingView, +# AppointmentConfirmationView, ReminderView, CheckInView, QueueManagementView, +# TelemedicineSetupView, AppointmentCompletionView, ReschedulingView, +# CancellationView, NoShowHandlingView +# ) +# +# +# class AppointmentSchedulingProcess(Process): +# """ +# Viewflow process model for appointment scheduling +# """ +# appointment_request = ModelField(AppointmentRequest, help_text='Associated appointment request') +# +# # Process status tracking +# request_submitted = models.BooleanField(default=False) +# availability_checked = models.BooleanField(default=False) +# appointment_scheduled = models.BooleanField(default=False) +# confirmation_sent = models.BooleanField(default=False) +# reminders_scheduled = models.BooleanField(default=False) +# patient_checked_in = models.BooleanField(default=False) +# appointment_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Appointment Scheduling Process' +# verbose_name_plural = 'Appointment Scheduling Processes' +# +# +# class AppointmentSchedulingFlow(Flow): +# """ +# Appointment Scheduling Workflow +# +# This flow manages the complete appointment lifecycle from +# request through scheduling, confirmation, and completion. +# """ +# +# process_class = AppointmentSchedulingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_appointment_scheduling) +# .Next(this.submit_request) +# ) +# +# submit_request = ( +# flow_view(AppointmentRequestView) +# .Permission('appointments.can_submit_requests') +# .Next(this.check_availability) +# ) +# +# check_availability = ( +# flow_view(AvailabilityCheckView) +# .Permission('appointments.can_check_availability') +# .Next(this.schedule_appointment) +# ) +# +# schedule_appointment = ( +# flow_view(AppointmentSchedulingView) +# .Permission('appointments.can_schedule_appointments') +# .Next(this.send_confirmation) +# ) +# +# send_confirmation = ( +# flow_view(AppointmentConfirmationView) +# .Permission('appointments.can_send_confirmations') +# .Next(this.schedule_reminders) +# ) +# +# schedule_reminders = ( +# flow_func(this.setup_reminders) +# .Next(this.check_in_patient) +# ) +# +# check_in_patient = ( +# flow_view(CheckInView) +# .Permission('appointments.can_check_in_patients') +# .Next(this.complete_appointment) +# ) +# +# complete_appointment = ( +# flow_func(this.finalize_appointment) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_appointment_scheduling) +# +# # Flow functions +# def start_appointment_scheduling(self, activation): +# """Initialize the appointment scheduling process""" +# process = activation.process +# appointment = process.appointment_request +# +# # Update appointment status +# appointment.status = 'REQUESTED' +# appointment.save() +# +# # Send notification to scheduling staff +# self.notify_scheduling_staff(appointment) +# +# # Check for urgent appointments +# if appointment.priority in ['HIGH', 'URGENT'] or appointment.urgency_score >= 8: +# self.notify_urgent_appointment(appointment) +# +# def setup_reminders(self, activation): +# """Setup appointment reminders""" +# process = activation.process +# appointment = process.appointment_request +# +# # Mark reminders as scheduled +# process.reminders_scheduled = True +# process.save() +# +# # Schedule reminder tasks +# self.schedule_appointment_reminders(appointment) +# +# # Send immediate confirmation if telemedicine +# if appointment.is_telemedicine: +# self.setup_telemedicine_meeting(appointment) +# +# def finalize_appointment(self, activation): +# """Finalize the appointment process""" +# process = activation.process +# appointment = process.appointment_request +# +# # Update appointment status +# appointment.status = 'COMPLETED' +# appointment.completed_at = timezone.now() +# appointment.save() +# +# # Mark process as completed +# process.appointment_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_appointment_completion(appointment) +# +# # Update provider schedule +# self.update_provider_schedule(appointment) +# +# # Generate follow-up recommendations +# self.generate_follow_up_recommendations(appointment) +# +# def end_appointment_scheduling(self, activation): +# """End the appointment scheduling workflow""" +# process = activation.process +# +# # Generate appointment summary +# self.generate_appointment_summary(process.appointment_request) +# +# # Helper methods +# def notify_scheduling_staff(self, appointment): +# """Notify scheduling staff of new appointment request""" +# from django.contrib.auth.models import Group +# +# scheduling_staff = User.objects.filter( +# groups__name='Scheduling Staff' +# ) +# +# for staff in scheduling_staff: +# send_mail( +# subject=f'New Appointment Request: {appointment.patient.get_full_name()}', +# message=f'New {appointment.get_appointment_type_display()} appointment request for {appointment.specialty}.', +# from_email='scheduling@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_urgent_appointment(self, appointment): +# """Notify of urgent appointment request""" +# scheduling_managers = User.objects.filter( +# groups__name='Scheduling Managers' +# ) +# +# for manager in scheduling_managers: +# send_mail( +# subject=f'URGENT Appointment Request: {appointment.patient.get_full_name()}', +# message=f'{appointment.get_priority_display()} appointment request requires immediate attention.', +# from_email='scheduling@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def schedule_appointment_reminders(self, appointment): +# """Schedule appointment reminder tasks""" +# if appointment.scheduled_datetime: +# # Schedule 24-hour reminder +# reminder_24h = appointment.scheduled_datetime - timedelta(hours=24) +# if reminder_24h > timezone.now(): +# send_appointment_reminder.apply_async( +# args=[appointment.id, '24_hour'], +# eta=reminder_24h +# ) +# +# # Schedule 2-hour reminder +# reminder_2h = appointment.scheduled_datetime - timedelta(hours=2) +# if reminder_2h > timezone.now(): +# send_appointment_reminder.apply_async( +# args=[appointment.id, '2_hour'], +# eta=reminder_2h +# ) +# +# def setup_telemedicine_meeting(self, appointment): +# """Setup telemedicine meeting details""" +# # This would integrate with telemedicine platforms +# pass +# +# def notify_appointment_completion(self, appointment): +# """Notify appointment completion""" +# # Notify patient +# if appointment.patient.email: +# send_mail( +# subject='Appointment Completed', +# message=f'Your appointment with {appointment.provider.get_full_name()} has been completed.', +# from_email='appointments@hospital.com', +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def update_provider_schedule(self, appointment): +# """Update provider schedule after appointment""" +# # This would update provider availability +# pass +# +# def generate_follow_up_recommendations(self, appointment): +# """Generate follow-up appointment recommendations""" +# # This would analyze appointment and suggest follow-ups +# pass +# +# def generate_appointment_summary(self, appointment): +# """Generate appointment summary""" +# # This would generate appointment summary report +# pass +# +# +# class AppointmentConfirmationProcess(Process): +# """ +# Viewflow process model for appointment confirmation +# """ +# appointment_request = ModelField(AppointmentRequest, help_text='Associated appointment request') +# +# # Process status tracking +# confirmation_requested = models.BooleanField(default=False) +# patient_contacted = models.BooleanField(default=False) +# confirmation_received = models.BooleanField(default=False) +# details_updated = models.BooleanField(default=False) +# confirmation_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Appointment Confirmation Process' +# verbose_name_plural = 'Appointment Confirmation Processes' +# +# +# class AppointmentConfirmationFlow(Flow): +# """ +# Appointment Confirmation Workflow +# +# This flow manages appointment confirmation including patient +# contact, confirmation receipt, and detail updates. +# """ +# +# process_class = AppointmentConfirmationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_confirmation) +# .Next(this.request_confirmation) +# ) +# +# request_confirmation = ( +# flow_func(this.send_confirmation_request) +# .Next(this.contact_patient) +# ) +# +# contact_patient = ( +# flow_view(PatientContactView) +# .Permission('appointments.can_contact_patients') +# .Next(this.receive_confirmation) +# ) +# +# receive_confirmation = ( +# flow_view(ConfirmationReceiptView) +# .Permission('appointments.can_receive_confirmations') +# .Next(this.update_details) +# ) +# +# update_details = ( +# flow_view(DetailUpdateView) +# .Permission('appointments.can_update_details') +# .Next(this.complete_confirmation) +# ) +# +# complete_confirmation = ( +# flow_func(this.finalize_confirmation) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_confirmation) +# +# # Flow functions +# def start_confirmation(self, activation): +# """Initialize the confirmation process""" +# process = activation.process +# appointment = process.appointment_request +# +# # Send confirmation request +# self.send_confirmation_request(appointment) +# +# def send_confirmation_request(self, activation): +# """Send confirmation request to patient""" +# process = activation.process +# appointment = process.appointment_request +# +# # Mark confirmation requested +# process.confirmation_requested = True +# process.save() +# +# # Send confirmation request via preferred method +# self.send_confirmation_via_preferred_method(appointment) +# +# def finalize_confirmation(self, activation): +# """Finalize the confirmation process""" +# process = activation.process +# appointment = process.appointment_request +# +# # Update appointment status +# appointment.status = 'CONFIRMED' +# appointment.save() +# +# # Mark process as completed +# process.confirmation_completed = True +# process.save() +# +# # Send confirmation completion notification +# self.notify_confirmation_completion(appointment) +# +# def end_confirmation(self, activation): +# """End the confirmation workflow""" +# process = activation.process +# +# # Log confirmation completion +# self.log_confirmation_completion(process.appointment_request) +# +# # Helper methods +# def send_confirmation_via_preferred_method(self, appointment): +# """Send confirmation via patient's preferred method""" +# preferences = appointment.reminder_preferences +# +# if preferences.get('email', True) and appointment.patient.email: +# self.send_email_confirmation(appointment) +# +# if preferences.get('sms', False) and appointment.patient.phone: +# self.send_sms_confirmation(appointment) +# +# if preferences.get('phone', False): +# self.schedule_phone_confirmation(appointment) +# +# def send_email_confirmation(self, appointment): +# """Send email confirmation""" +# send_mail( +# subject='Appointment Confirmation Required', +# message=f'Please confirm your appointment on {appointment.scheduled_datetime}.', +# from_email='appointments@hospital.com', +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def send_sms_confirmation(self, appointment): +# """Send SMS confirmation""" +# # This would integrate with SMS service +# pass +# +# def schedule_phone_confirmation(self, appointment): +# """Schedule phone confirmation call""" +# # This would schedule a phone call task +# pass +# +# def notify_confirmation_completion(self, appointment): +# """Notify confirmation completion""" +# # Notify scheduling staff +# scheduling_staff = User.objects.filter( +# groups__name='Scheduling Staff' +# ) +# +# for staff in scheduling_staff: +# send_mail( +# subject=f'Appointment Confirmed: {appointment.patient.get_full_name()}', +# message=f'Patient has confirmed appointment for {appointment.scheduled_datetime}.', +# from_email='appointments@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def log_confirmation_completion(self, appointment): +# """Log confirmation completion""" +# # This would log confirmation details +# pass +# +# +# class QueueManagementProcess(Process): +# """ +# Viewflow process model for queue management +# """ +# queue_entry = ModelField(QueueEntry, help_text='Associated queue entry') +# +# # Process status tracking +# patient_queued = models.BooleanField(default=False) +# position_assigned = models.BooleanField(default=False) +# wait_time_estimated = models.BooleanField(default=False) +# patient_called = models.BooleanField(default=False) +# service_started = models.BooleanField(default=False) +# service_completed = models.BooleanField(default=False) +# queue_exited = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Queue Management Process' +# verbose_name_plural = 'Queue Management Processes' +# +# +# class QueueManagementFlow(Flow): +# """ +# Queue Management Workflow +# +# This flow manages patient flow through waiting queues +# including position assignment and service coordination. +# """ +# +# process_class = QueueManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_queue_management) +# .Next(this.queue_patient) +# ) +# +# queue_patient = ( +# flow_view(PatientQueuingView) +# .Permission('appointments.can_queue_patients') +# .Next(this.assign_position) +# ) +# +# assign_position = ( +# flow_func(this.calculate_queue_position) +# .Next(this.estimate_wait_time) +# ) +# +# estimate_wait_time = ( +# flow_func(this.calculate_wait_time) +# .Next(this.call_patient) +# ) +# +# call_patient = ( +# flow_view(PatientCallingView) +# .Permission('appointments.can_call_patients') +# .Next(this.start_service) +# ) +# +# start_service = ( +# flow_view(ServiceStartView) +# .Permission('appointments.can_start_service') +# .Next(this.complete_service) +# ) +# +# complete_service = ( +# flow_view(ServiceCompletionView) +# .Permission('appointments.can_complete_service') +# .Next(this.exit_queue) +# ) +# +# exit_queue = ( +# flow_func(this.finalize_queue_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_queue_management) +# +# # Flow functions +# def start_queue_management(self, activation): +# """Initialize the queue management process""" +# process = activation.process +# entry = process.queue_entry +# +# # Update entry status +# entry.status = 'WAITING' +# entry.save() +# +# # Send queue notification +# self.notify_queue_entry(entry) +# +# def calculate_queue_position(self, activation): +# """Calculate and assign queue position""" +# process = activation.process +# entry = process.queue_entry +# +# # Calculate position based on priority and arrival time +# position = self.determine_queue_position(entry) +# entry.queue_position = position +# entry.save() +# +# # Mark position assigned +# process.position_assigned = True +# process.save() +# +# # Update other queue positions +# self.update_queue_positions(entry.queue) +# +# def calculate_wait_time(self, activation): +# """Calculate estimated wait time""" +# process = activation.process +# entry = process.queue_entry +# +# # Calculate estimated service time +# estimated_time = self.estimate_service_time(entry) +# entry.estimated_service_time = estimated_time +# entry.save() +# +# # Mark wait time estimated +# process.wait_time_estimated = True +# process.save() +# +# # Send wait time notification +# self.notify_wait_time(entry) +# +# def finalize_queue_management(self, activation): +# """Finalize the queue management process""" +# process = activation.process +# entry = process.queue_entry +# +# # Update entry status +# entry.status = 'COMPLETED' +# entry.served_at = timezone.now() +# entry.save() +# +# # Mark process as completed +# process.queue_exited = True +# process.save() +# +# # Update queue metrics +# self.update_queue_metrics(entry) +# +# # Notify next patient +# self.notify_next_patient(entry.queue) +# +# def end_queue_management(self, activation): +# """End the queue management workflow""" +# process = activation.process +# +# # Generate queue summary +# self.generate_queue_summary(process.queue_entry) +# +# # Helper methods +# def notify_queue_entry(self, entry): +# """Notify patient of queue entry""" +# if entry.patient.email: +# send_mail( +# subject='Added to Waiting Queue', +# message=f'You have been added to the {entry.queue.name} queue.', +# from_email='appointments@hospital.com', +# recipient_list=[entry.patient.email], +# fail_silently=True +# ) +# +# def determine_queue_position(self, entry): +# """Determine queue position based on priority""" +# # This would implement priority-based positioning logic +# return entry.queue.current_queue_size + 1 +# +# def update_queue_positions(self, queue): +# """Update positions for all entries in queue""" +# entries = queue.queue_entries.filter(status='WAITING').order_by('priority_score', 'joined_at') +# for i, entry in enumerate(entries, 1): +# entry.queue_position = i +# entry.save() +# +# def estimate_service_time(self, entry): +# """Estimate service time for queue entry""" +# queue = entry.queue +# position = entry.queue_position +# avg_service_time = queue.average_service_time_minutes +# +# estimated_minutes = position * avg_service_time +# return timezone.now() + timedelta(minutes=estimated_minutes) +# +# def notify_wait_time(self, entry): +# """Notify patient of estimated wait time""" +# if entry.patient.email and entry.estimated_service_time: +# wait_minutes = int((entry.estimated_service_time - timezone.now()).total_seconds() / 60) +# send_mail( +# subject='Queue Wait Time Update', +# message=f'Your estimated wait time is {wait_minutes} minutes.', +# from_email='appointments@hospital.com', +# recipient_list=[entry.patient.email], +# fail_silently=True +# ) +# +# def update_queue_metrics(self, entry): +# """Update queue performance metrics""" +# # This would update queue analytics +# pass +# +# def notify_next_patient(self, queue): +# """Notify next patient in queue""" +# next_entry = queue.queue_entries.filter( +# status='WAITING' +# ).order_by('queue_position').first() +# +# if next_entry: +# self.notify_patient_ready(next_entry) +# +# def notify_patient_ready(self, entry): +# """Notify patient they are ready to be called""" +# if entry.patient.email: +# send_mail( +# subject='Ready for Appointment', +# message='You will be called shortly for your appointment.', +# from_email='appointments@hospital.com', +# recipient_list=[entry.patient.email], +# fail_silently=True +# ) +# +# def generate_queue_summary(self, entry): +# """Generate queue management summary""" +# # This would generate queue analytics +# pass +# +# +# class TelemedicineSetupProcess(Process): +# """ +# Viewflow process model for telemedicine setup +# """ +# appointment_request = ModelField(AppointmentRequest, help_text='Associated appointment request') +# +# # Process status tracking +# platform_selected = models.BooleanField(default=False) +# meeting_created = models.BooleanField(default=False) +# credentials_sent = models.BooleanField(default=False) +# technical_check_completed = models.BooleanField(default=False) +# meeting_ready = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Telemedicine Setup Process' +# verbose_name_plural = 'Telemedicine Setup Processes' +# +# +# class TelemedicineSetupFlow(Flow): +# """ +# Telemedicine Setup Workflow +# +# This flow manages telemedicine appointment setup including +# platform selection, meeting creation, and technical verification. +# """ +# +# process_class = TelemedicineSetupProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_telemedicine_setup) +# .Next(this.select_platform) +# ) +# +# select_platform = ( +# flow_view(PlatformSelectionView) +# .Permission('appointments.can_select_platforms') +# .Next(this.create_meeting) +# ) +# +# create_meeting = ( +# flow_view(MeetingCreationView) +# .Permission('appointments.can_create_meetings') +# .Next(this.send_credentials) +# ) +# +# send_credentials = ( +# flow_view(CredentialSendingView) +# .Permission('appointments.can_send_credentials') +# .Next(this.technical_check) +# ) +# +# technical_check = ( +# flow_view(TechnicalCheckView) +# .Permission('appointments.can_perform_technical_checks') +# .Next(this.finalize_setup) +# ) +# +# finalize_setup = ( +# flow_func(this.complete_telemedicine_setup) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_telemedicine_setup) +# +# # Flow functions +# def start_telemedicine_setup(self, activation): +# """Initialize the telemedicine setup process""" +# process = activation.process +# appointment = process.appointment_request +# +# # Mark as telemedicine appointment +# appointment.is_telemedicine = True +# appointment.save() +# +# # Send setup notification +# self.notify_telemedicine_setup(appointment) +# +# def complete_telemedicine_setup(self, activation): +# """Finalize the telemedicine setup process""" +# process = activation.process +# appointment = process.appointment_request +# +# # Mark meeting as ready +# process.meeting_ready = True +# process.save() +# +# # Send final meeting details +# self.send_final_meeting_details(appointment) +# +# # Schedule pre-meeting reminder +# self.schedule_pre_meeting_reminder(appointment) +# +# def end_telemedicine_setup(self, activation): +# """End the telemedicine setup workflow""" +# process = activation.process +# +# # Log setup completion +# self.log_telemedicine_setup(process.appointment_request) +# +# # Helper methods +# def notify_telemedicine_setup(self, appointment): +# """Notify patient of telemedicine setup""" +# if appointment.patient.email: +# send_mail( +# subject='Telemedicine Appointment Setup', +# message='Your telemedicine appointment is being set up. You will receive meeting details shortly.', +# from_email='telemedicine@hospital.com', +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def send_final_meeting_details(self, appointment): +# """Send final meeting details to patient""" +# if appointment.patient.email: +# send_mail( +# subject='Telemedicine Meeting Details', +# message=f'Meeting URL: {appointment.meeting_url}\nMeeting ID: {appointment.meeting_id}', +# from_email='telemedicine@hospital.com', +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def schedule_pre_meeting_reminder(self, appointment): +# """Schedule pre-meeting reminder""" +# if appointment.scheduled_datetime: +# reminder_time = appointment.scheduled_datetime - timedelta(minutes=15) +# if reminder_time > timezone.now(): +# send_telemedicine_reminder.apply_async( +# args=[appointment.id], +# eta=reminder_time +# ) +# +# def log_telemedicine_setup(self, appointment): +# """Log telemedicine setup completion""" +# # This would log setup details +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def send_appointment_reminder(appointment_id, reminder_type): +# """Background task to send appointment reminders""" +# try: +# appointment = AppointmentRequest.objects.get(id=appointment_id) +# +# if reminder_type == '24_hour': +# subject = 'Appointment Reminder - Tomorrow' +# message = f'Reminder: You have an appointment tomorrow at {appointment.scheduled_datetime}.' +# elif reminder_type == '2_hour': +# subject = 'Appointment Reminder - 2 Hours' +# message = f'Reminder: You have an appointment in 2 hours at {appointment.scheduled_datetime}.' +# +# if appointment.patient.email: +# send_mail( +# subject=subject, +# message=message, +# from_email='appointments@hospital.com', +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def send_telemedicine_reminder(appointment_id): +# """Background task to send telemedicine pre-meeting reminder""" +# try: +# appointment = AppointmentRequest.objects.get(id=appointment_id) +# +# if appointment.patient.email: +# send_mail( +# subject='Telemedicine Meeting Starting Soon', +# message=f'Your telemedicine appointment starts in 15 minutes. Meeting URL: {appointment.meeting_url}', +# from_email='telemedicine@hospital.com', +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_confirm_appointments(): +# """Background task to automatically confirm appointments""" +# try: +# # This would implement auto-confirmation logic +# return True +# except Exception: +# return False +# +# +# @celery.job +# def manage_no_shows(): +# """Background task to manage no-show appointments""" +# try: +# # This would identify and handle no-show appointments +# return True +# except Exception: +# return False +# +# +# @celery.job +# def optimize_schedules(): +# """Background task to optimize provider schedules""" +# try: +# # This would implement schedule optimization +# return True +# except Exception: +# return False +# +# +# @celery.job +# def update_queue_positions(): +# """Background task to update queue positions""" +# try: +# # This would update queue positions and wait times +# return True +# except Exception: +# return False +# diff --git a/appointments/forms.py b/appointments/forms.py index 2d353f5c..776859a9 100644 --- a/appointments/forms.py +++ b/appointments/forms.py @@ -439,3 +439,751 @@ class SlotSearchForm(forms.Form): role__in=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT'] ).order_by('last_name', 'first_name') + +# from django import forms +# from django.core.exceptions import ValidationError +# from django.utils import timezone +# from django.contrib.auth.models import User +# from crispy_forms.helper import FormHelper +# from crispy_forms.layout import Layout, Fieldset, Submit, Row, Column, HTML, Div +# from crispy_forms.bootstrap import FormActions +# from datetime import datetime, timedelta +# +# from .models import Appointment, AppointmentConfirmation, Queue, TelemedicineSession +# from patients.models import Patient +# from core.models import Department +# +# +# class AppointmentSchedulingForm(forms.ModelForm): +# """ +# Form for appointment scheduling +# """ +# patient_search = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={ +# 'class': 'form-control', +# 'placeholder': 'Search patient by name, ID, or phone...', +# 'data-toggle': 'patient-search' +# }) +# ) +# preferred_time_1 = forms.TimeField( +# required=False, +# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}) +# ) +# preferred_time_2 = forms.TimeField( +# required=False, +# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}) +# ) +# preferred_time_3 = forms.TimeField( +# required=False, +# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}) +# ) +# special_instructions = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# send_confirmation = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# send_reminder = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = Appointment +# fields = [ +# 'patient', 'provider', 'department', 'appointment_type', +# 'appointment_date', 'appointment_time', 'duration', +# 'urgency', 'reason', 'notes', 'special_instructions', +# 'send_confirmation', 'send_reminder' +# ] +# widgets = { +# 'patient': forms.Select(attrs={'class': 'form-control'}), +# 'provider': forms.Select(attrs={'class': 'form-control'}), +# 'department': forms.Select(attrs={'class': 'form-control'}), +# 'appointment_type': forms.Select(attrs={'class': 'form-control'}), +# 'appointment_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}), +# 'appointment_time': forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}), +# 'duration': forms.NumberInput(attrs={'class': 'form-control'}), +# 'urgency': forms.Select(attrs={'class': 'form-control'}), +# 'reason': forms.TextInput(attrs={'class': 'form-control'}), +# 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['patient'].queryset = Patient.objects.filter(tenant=tenant) +# self.fields['provider'].queryset = User.objects.filter( +# tenant=tenant, +# groups__name__in=['Doctors', 'Nurses', 'Specialists'] +# ) +# self.fields['department'].queryset = Department.objects.filter(tenant=tenant) +# +# # Set minimum date to today +# self.fields['appointment_date'].widget.attrs['min'] = timezone.now().date().isoformat() +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Patient Information', +# 'patient_search', +# 'patient' +# ), +# Fieldset( +# 'Appointment Details', +# Row( +# Column('provider', css_class='form-group col-md-6 mb-0'), +# Column('department', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('appointment_type', css_class='form-group col-md-6 mb-0'), +# Column('urgency', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('appointment_date', css_class='form-group col-md-4 mb-0'), +# Column('appointment_time', css_class='form-group col-md-4 mb-0'), +# Column('duration', css_class='form-group col-md-4 mb-0'), +# css_class='form-row' +# ), +# 'reason', +# 'notes', +# 'special_instructions' +# ), +# Fieldset( +# 'Preferred Times (Alternative Options)', +# Row( +# Column('preferred_time_1', css_class='form-group col-md-4 mb-0'), +# Column('preferred_time_2', css_class='form-group col-md-4 mb-0'), +# Column('preferred_time_3', css_class='form-group col-md-4 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Notifications', +# HTML('
'), +# 'send_confirmation', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'send_reminder', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Schedule Appointment', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean(self): +# cleaned_data = super().clean() +# appointment_date = cleaned_data.get('appointment_date') +# appointment_time = cleaned_data.get('appointment_time') +# provider = cleaned_data.get('provider') +# +# if appointment_date and appointment_time: +# appointment_datetime = datetime.combine(appointment_date, appointment_time) +# +# # Check if appointment is in the past +# if appointment_datetime < timezone.now(): +# raise ValidationError('Appointment cannot be scheduled in the past.') +# +# # Check provider availability +# if provider and self.check_provider_conflict(provider, appointment_datetime): +# raise ValidationError('Provider is not available at the selected time.') +# +# return cleaned_data +# +# def check_provider_conflict(self, provider, appointment_datetime): +# """Check if provider has conflicting appointments""" +# duration = self.cleaned_data.get('duration', 30) +# end_time = appointment_datetime + timedelta(minutes=duration) +# +# conflicts = Appointment.objects.filter( +# provider=provider, +# appointment_date=appointment_datetime.date(), +# status__in=['scheduled', 'confirmed', 'in_progress'] +# ).exclude(id=self.instance.id if self.instance else None) +# +# for conflict in conflicts: +# conflict_start = datetime.combine(conflict.appointment_date, conflict.appointment_time) +# conflict_end = conflict_start + timedelta(minutes=conflict.duration) +# +# if (appointment_datetime < conflict_end and end_time > conflict_start): +# return True +# +# return False +# +# +# class AppointmentConfirmationForm(forms.ModelForm): +# """ +# Form for appointment confirmation +# """ +# confirmation_method = forms.ChoiceField( +# choices=[ +# ('phone', 'Phone Call'), +# ('email', 'Email'), +# ('sms', 'SMS'), +# ('in_person', 'In Person'), +# ('online', 'Online Portal') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# contact_attempts = forms.IntegerField( +# initial=1, +# min_value=1, +# max_value=5, +# widget=forms.NumberInput(attrs={'class': 'form-control'}) +# ) +# confirmation_notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# reschedule_requested = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# new_preferred_date = forms.DateField( +# required=False, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# new_preferred_time = forms.TimeField( +# required=False, +# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}) +# ) +# +# class Meta: +# model = AppointmentConfirmation +# fields = [ +# 'confirmation_method', 'contact_attempts', 'confirmation_notes', +# 'reschedule_requested', 'new_preferred_date', 'new_preferred_time' +# ] +# +# def __init__(self, *args, **kwargs): +# appointment = kwargs.pop('appointment', None) +# super().__init__(*args, **kwargs) +# +# self.appointment = appointment +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Confirmation Details', +# Row( +# Column('confirmation_method', css_class='form-group col-md-6 mb-0'), +# Column('contact_attempts', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'confirmation_notes' +# ), +# Fieldset( +# 'Reschedule Request', +# HTML('
'), +# 'reschedule_requested', +# HTML( +# ''), +# HTML('
'), +# Row( +# Column('new_preferred_date', css_class='form-group col-md-6 mb-0'), +# Column('new_preferred_time', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# FormActions( +# Submit('submit', 'Confirm Appointment', css_class='btn btn-primary'), +# HTML( +# 'Cancel') +# ) +# ) +# +# def clean(self): +# cleaned_data = super().clean() +# reschedule_requested = cleaned_data.get('reschedule_requested') +# new_preferred_date = cleaned_data.get('new_preferred_date') +# new_preferred_time = cleaned_data.get('new_preferred_time') +# +# if reschedule_requested: +# if not new_preferred_date: +# raise ValidationError('New preferred date is required when reschedule is requested.') +# if not new_preferred_time: +# raise ValidationError('New preferred time is required when reschedule is requested.') +# +# return cleaned_data +# +# +# class QueueManagementForm(forms.ModelForm): +# """ +# Form for queue management +# """ +# estimated_wait_time = forms.IntegerField( +# required=False, +# widget=forms.NumberInput(attrs={'class': 'form-control'}) +# ) +# priority_adjustment = forms.ChoiceField( +# choices=[ +# ('none', 'No Change'), +# ('increase', 'Increase Priority'), +# ('decrease', 'Decrease Priority') +# ], +# required=False, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# queue_notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# notify_patient = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = Queue +# fields = [ +# 'queue_type', 'priority', 'estimated_wait_time', +# 'priority_adjustment', 'queue_notes', 'notify_patient' +# ] +# widgets = { +# 'queue_type': forms.Select(attrs={'class': 'form-control'}), +# 'priority': forms.Select(attrs={'class': 'form-control'}) +# } +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Queue Configuration', +# Row( +# Column('queue_type', css_class='form-group col-md-6 mb-0'), +# Column('priority', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('estimated_wait_time', css_class='form-group col-md-6 mb-0'), +# Column('priority_adjustment', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'queue_notes' +# ), +# Fieldset( +# 'Notifications', +# HTML('
'), +# 'notify_patient', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Update Queue', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class TelemedicineSetupForm(forms.ModelForm): +# """ +# Form for telemedicine session setup +# """ +# platform = forms.ChoiceField( +# choices=[ +# ('zoom', 'Zoom'), +# ('teams', 'Microsoft Teams'), +# ('webex', 'Cisco Webex'), +# ('meet', 'Google Meet'), +# ('custom', 'Custom Platform') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# test_connection = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# send_instructions = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# backup_phone = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# technical_support_contact = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# session_recording = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = TelemedicineSession +# fields = [ +# 'platform', 'meeting_url', 'meeting_id', 'meeting_password', +# 'test_connection', 'send_instructions', 'backup_phone', +# 'technical_support_contact', 'session_recording' +# ] +# widgets = { +# 'meeting_url': forms.URLInput(attrs={'class': 'form-control'}), +# 'meeting_id': forms.TextInput(attrs={'class': 'form-control'}), +# 'meeting_password': forms.TextInput(attrs={'class': 'form-control'}) +# } +# +# def __init__(self, *args, **kwargs): +# appointment = kwargs.pop('appointment', None) +# super().__init__(*args, **kwargs) +# +# self.appointment = appointment +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Platform Configuration', +# 'platform', +# 'meeting_url', +# Row( +# Column('meeting_id', css_class='form-group col-md-6 mb-0'), +# Column('meeting_password', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Support Information', +# Row( +# Column('backup_phone', css_class='form-group col-md-6 mb-0'), +# Column('technical_support_contact', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Session Options', +# HTML('
'), +# 'test_connection', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'send_instructions', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'session_recording', +# HTML( +# ''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Setup Telemedicine', css_class='btn btn-primary'), +# HTML( +# 'Cancel') +# ) +# ) +# +# def clean_meeting_url(self): +# meeting_url = self.cleaned_data.get('meeting_url') +# platform = self.cleaned_data.get('platform') +# +# if platform and meeting_url: +# # Validate URL format based on platform +# if platform == 'zoom' and 'zoom.us' not in meeting_url: +# raise ValidationError('Invalid Zoom meeting URL format.') +# elif platform == 'teams' and 'teams.microsoft.com' not in meeting_url: +# raise ValidationError('Invalid Microsoft Teams meeting URL format.') +# elif platform == 'webex' and 'webex.com' not in meeting_url: +# raise ValidationError('Invalid Webex meeting URL format.') +# elif platform == 'meet' and 'meet.google.com' not in meeting_url: +# raise ValidationError('Invalid Google Meet URL format.') +# +# return meeting_url +# +# +# class AppointmentRescheduleForm(forms.Form): +# """ +# Form for appointment rescheduling +# """ +# new_date = forms.DateField( +# required=True, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# new_time = forms.TimeField( +# required=True, +# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}) +# ) +# new_provider = forms.ModelChoiceField( +# queryset=None, +# required=False, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# reschedule_reason = forms.ChoiceField( +# choices=[ +# ('patient_request', 'Patient Request'), +# ('provider_unavailable', 'Provider Unavailable'), +# ('emergency', 'Emergency'), +# ('equipment_issue', 'Equipment Issue'), +# ('other', 'Other') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# notify_patient = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# appointment = kwargs.pop('appointment', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['new_provider'].queryset = User.objects.filter( +# tenant=tenant, +# groups__name__in=['Doctors', 'Nurses', 'Specialists'] +# ) +# +# # Set minimum date to today +# self.fields['new_date'].widget.attrs['min'] = timezone.now().date().isoformat() +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'New Appointment Details', +# Row( +# Column('new_date', css_class='form-group col-md-6 mb-0'), +# Column('new_time', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'new_provider' +# ), +# Fieldset( +# 'Reschedule Information', +# 'reschedule_reason', +# 'notes' +# ), +# Fieldset( +# 'Notifications', +# HTML('
'), +# 'notify_patient', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Reschedule Appointment', css_class='btn btn-primary'), +# HTML( +# 'Cancel') +# ) +# ) +# +# +# class AppointmentCancellationForm(forms.Form): +# """ +# Form for appointment cancellation +# """ +# cancellation_reason = forms.ChoiceField( +# choices=[ +# ('patient_request', 'Patient Request'), +# ('provider_unavailable', 'Provider Unavailable'), +# ('patient_no_show', 'Patient No Show'), +# ('emergency', 'Emergency'), +# ('equipment_failure', 'Equipment Failure'), +# ('other', 'Other') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# cancellation_notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# offer_reschedule = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# notify_patient = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# refund_required = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Cancellation Details', +# 'cancellation_reason', +# 'cancellation_notes' +# ), +# Fieldset( +# 'Follow-up Actions', +# HTML('
'), +# 'offer_reschedule', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'notify_patient', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'refund_required', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Cancel Appointment', css_class='btn btn-danger'), +# HTML( +# 'Back') +# ) +# ) +# +# +# class AppointmentCheckInForm(forms.Form): +# """ +# Form for appointment check-in +# """ +# arrival_time = forms.TimeField( +# initial=timezone.now().time(), +# widget=forms.TimeInput(attrs={'class': 'form-control', 'type': 'time'}) +# ) +# insurance_verified = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# copay_collected = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# forms_completed = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# vitals_required = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# special_needs = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 2}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Check-in Information', +# 'arrival_time', +# 'special_needs' +# ), +# Fieldset( +# 'Pre-visit Tasks', +# HTML('
'), +# 'insurance_verified', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'copay_collected', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'forms_completed', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'vitals_required', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Check In Patient', css_class='btn btn-primary'), +# HTML( +# 'Cancel') +# ) +# ) +# +# +# class BulkAppointmentForm(forms.Form): +# """ +# Form for bulk appointment operations +# """ +# action = forms.ChoiceField( +# choices=[ +# ('confirm', 'Confirm Appointments'), +# ('reschedule', 'Reschedule Appointments'), +# ('cancel', 'Cancel Appointments'), +# ('send_reminders', 'Send Reminders') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# appointment_ids = forms.CharField( +# widget=forms.HiddenInput() +# ) +# bulk_date = forms.DateField( +# required=False, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# bulk_reason = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# notify_patients = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# 'appointment_ids', +# Fieldset( +# 'Bulk Operation', +# 'action', +# 'bulk_date', +# 'bulk_reason' +# ), +# Fieldset( +# 'Notifications', +# HTML('
'), +# 'notify_patients', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Execute Bulk Operation', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# diff --git a/appointments/views.py b/appointments/views.py index eb643ade..d3ed1966 100644 --- a/appointments/views.py +++ b/appointments/views.py @@ -3209,3 +3209,907 @@ def reschedule_appointment(request, appointment_id): # 'appointment': session.appointment # }) # + + +# from django.shortcuts import render, redirect, get_object_or_404 +# from django.contrib.auth.decorators import login_required, permission_required +# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin +# from django.contrib import messages +# from django.views.generic import ( +# CreateView, UpdateView, DeleteView, DetailView, ListView, FormView +# ) +# from django.urls import reverse_lazy, reverse +# from django.http import JsonResponse, HttpResponse +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# from django.conf import settings +# from django.db.models import Q, Count +# from viewflow.views import CreateProcessView, UpdateProcessView +# from datetime import datetime, timedelta +# import json +# +# from .models import Appointment, AppointmentConfirmation, Queue, TelemedicineSession +# from .forms import ( +# AppointmentSchedulingForm, AppointmentConfirmationForm, QueueManagementForm, +# TelemedicineSetupForm, AppointmentRescheduleForm, AppointmentCancellationForm, +# AppointmentCheckInForm, BulkAppointmentForm +# ) +# from .flows import AppointmentSchedulingFlow, AppointmentConfirmationFlow, QueueManagementFlow, TelemedicineSetupFlow +# from patients.models import Patient +# +# +# class AppointmentSchedulingView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for appointment scheduling workflow +# """ +# model = Appointment +# form_class = AppointmentSchedulingForm +# template_name = 'appointments/appointment_scheduling.html' +# permission_required = 'appointments.can_schedule_appointments' +# flow_class = AppointmentSchedulingFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create appointment +# appointment = form.save(commit=False) +# appointment.tenant = self.request.user.tenant +# appointment.scheduled_by = self.request.user +# appointment.status = 'scheduled' +# appointment.save() +# +# # Start appointment scheduling workflow +# process = self.flow_class.start.run( +# appointment=appointment, +# send_confirmation=form.cleaned_data.get('send_confirmation', True), +# send_reminder=form.cleaned_data.get('send_reminder', True), +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Appointment scheduled successfully for {appointment.patient.get_full_name()} ' +# f'on {appointment.appointment_date} at {appointment.appointment_time}.' +# ) +# +# return redirect('appointments:appointment_detail', pk=appointment.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Schedule Appointment' +# context['breadcrumbs'] = [ +# {'name': 'Home', 'url': reverse('core:dashboard')}, +# {'name': 'Appointments', 'url': reverse('appointments:appointment_list')}, +# {'name': 'Schedule Appointment', 'url': ''} +# ] +# context['available_slots'] = self.get_available_slots() +# return context +# +# def get_available_slots(self): +# """Get available appointment slots for the next 7 days""" +# slots = [] +# today = timezone.now().date() +# +# for i in range(7): +# date = today + timedelta(days=i) +# day_slots = self.get_slots_for_date(date) +# if day_slots: +# slots.append({ +# 'date': date, +# 'slots': day_slots +# }) +# +# return slots +# +# def get_slots_for_date(self, date): +# """Get available slots for a specific date""" +# # This would implement slot availability logic +# return [] +# +# +# class AppointmentConfirmationView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for appointment confirmation workflow +# """ +# model = AppointmentConfirmation +# form_class = AppointmentConfirmationForm +# template_name = 'appointments/appointment_confirmation.html' +# permission_required = 'appointments.can_confirm_appointments' +# flow_class = AppointmentConfirmationFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# return kwargs +# +# def form_valid(self, form): +# appointment = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# +# with transaction.atomic(): +# # Create confirmation record +# confirmation = form.save(commit=False) +# confirmation.appointment = appointment +# confirmation.confirmed_by = self.request.user +# confirmation.confirmed_at = timezone.now() +# confirmation.save() +# +# # Update appointment status +# if form.cleaned_data.get('reschedule_requested'): +# appointment.status = 'reschedule_requested' +# appointment.save() +# +# # Start rescheduling process +# messages.info( +# self.request, +# 'Patient requested reschedule. Please process the reschedule request.' +# ) +# return redirect('appointments:appointment_reschedule', pk=appointment.pk) +# else: +# appointment.status = 'confirmed' +# appointment.save() +# +# # Start confirmation workflow +# process = self.flow_class.start.run( +# appointment=appointment, +# confirmation=confirmation, +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Appointment confirmed for {appointment.patient.get_full_name()}.' +# ) +# +# return redirect('appointments:appointment_detail', pk=appointment.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# context['title'] = 'Confirm Appointment' +# return context +# +# +# class QueueManagementView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for queue management workflow +# """ +# model = Queue +# form_class = QueueManagementForm +# template_name = 'appointments/queue_management.html' +# permission_required = 'appointments.can_manage_queue' +# flow_class = QueueManagementFlow +# +# def form_valid(self, form): +# appointment = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# +# with transaction.atomic(): +# # Create or update queue entry +# queue_entry, created = Queue.objects.get_or_create( +# appointment=appointment, +# defaults={ +# 'tenant': self.request.user.tenant, +# 'patient': appointment.patient, +# 'provider': appointment.provider, +# 'department': appointment.department, +# 'created_by': self.request.user +# } +# ) +# +# # Update queue entry with form data +# for field in form.cleaned_data: +# if hasattr(queue_entry, field): +# setattr(queue_entry, field, form.cleaned_data[field]) +# +# queue_entry.save() +# +# # Start queue management workflow +# process = self.flow_class.start.run( +# queue_entry=queue_entry, +# appointment=appointment, +# notify_patient=form.cleaned_data.get('notify_patient', True), +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Queue updated for {appointment.patient.get_full_name()}. ' +# f'Position: {queue_entry.position}, Wait time: {queue_entry.estimated_wait_time} minutes.' +# ) +# +# return redirect('appointments:queue_list') +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# context['title'] = 'Manage Queue' +# context['current_queue'] = self.get_current_queue() +# return context +# +# def get_current_queue(self): +# """Get current queue status""" +# return Queue.objects.filter( +# tenant=self.request.user.tenant, +# status='waiting' +# ).order_by('priority', 'created_at') +# +# +# class TelemedicineSetupView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for telemedicine setup workflow +# """ +# model = TelemedicineSession +# form_class = TelemedicineSetupForm +# template_name = 'appointments/telemedicine_setup.html' +# permission_required = 'appointments.can_setup_telemedicine' +# flow_class = TelemedicineSetupFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# return kwargs +# +# def form_valid(self, form): +# appointment = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# +# with transaction.atomic(): +# # Create telemedicine session +# session = form.save(commit=False) +# session.appointment = appointment +# session.tenant = self.request.user.tenant +# session.created_by = self.request.user +# session.save() +# +# # Update appointment type +# appointment.appointment_type = 'telemedicine' +# appointment.save() +# +# # Start telemedicine setup workflow +# process = self.flow_class.start.run( +# session=session, +# appointment=appointment, +# test_connection=form.cleaned_data.get('test_connection', True), +# send_instructions=form.cleaned_data.get('send_instructions', True), +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Telemedicine session setup completed for {appointment.patient.get_full_name()}. ' +# f'Meeting details have been sent to the patient.' +# ) +# +# return redirect('appointments:appointment_detail', pk=appointment.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['appointment_id']) +# context['title'] = 'Setup Telemedicine' +# return context +# +# +# class AppointmentRescheduleView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for appointment rescheduling +# """ +# form_class = AppointmentRescheduleForm +# template_name = 'appointments/appointment_reschedule.html' +# permission_required = 'appointments.can_reschedule_appointments' +# +# def get_success_url(self): +# return reverse('appointments:appointment_detail', kwargs={'pk': self.kwargs['pk']}) +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# kwargs['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['pk']) +# return kwargs +# +# def form_valid(self, form): +# appointment = get_object_or_404(Appointment, pk=self.kwargs['pk']) +# +# with transaction.atomic(): +# # Store original appointment details +# original_date = appointment.appointment_date +# original_time = appointment.appointment_time +# original_provider = appointment.provider +# +# # Update appointment +# appointment.appointment_date = form.cleaned_data['new_date'] +# appointment.appointment_time = form.cleaned_data['new_time'] +# if form.cleaned_data.get('new_provider'): +# appointment.provider = form.cleaned_data['new_provider'] +# appointment.status = 'rescheduled' +# appointment.save() +# +# # Log reschedule +# self.log_reschedule(appointment, original_date, original_time, original_provider, form.cleaned_data) +# +# # Send notifications +# if form.cleaned_data.get('notify_patient'): +# self.send_reschedule_notification(appointment, form.cleaned_data) +# +# messages.success( +# self.request, +# f'Appointment rescheduled successfully. New date: {appointment.appointment_date}, ' +# f'New time: {appointment.appointment_time}.' +# ) +# +# return super().form_valid(form) +# +# def log_reschedule(self, appointment, original_date, original_time, original_provider, form_data): +# """Log reschedule details""" +# from core.models import AuditLogEntry +# AuditLogEntry.objects.create( +# tenant=appointment.tenant, +# user=self.request.user, +# event_type='APPOINTMENT_RESCHEDULE', +# action='UPDATE', +# object_type='Appointment', +# object_id=str(appointment.id), +# details={ +# 'original_date': original_date.isoformat(), +# 'original_time': original_time.isoformat(), +# 'original_provider': original_provider.get_full_name() if original_provider else None, +# 'new_date': form_data['new_date'].isoformat(), +# 'new_time': form_data['new_time'].isoformat(), +# 'new_provider': form_data['new_provider'].get_full_name() if form_data.get('new_provider') else None, +# 'reason': form_data['reschedule_reason'], +# 'notes': form_data.get('notes', '') +# }, +# ip_address=self.request.META.get('REMOTE_ADDR'), +# user_agent=self.request.META.get('HTTP_USER_AGENT', '') +# ) +# +# def send_reschedule_notification(self, appointment, form_data): +# """Send reschedule notification to patient""" +# if appointment.patient.email: +# send_mail( +# subject='Appointment Rescheduled', +# message=f'Your appointment has been rescheduled to {appointment.appointment_date} at {appointment.appointment_time}.', +# from_email=settings.DEFAULT_FROM_EMAIL, +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['pk']) +# context['title'] = 'Reschedule Appointment' +# return context +# +# +# class AppointmentCancellationView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for appointment cancellation +# """ +# form_class = AppointmentCancellationForm +# template_name = 'appointments/appointment_cancellation.html' +# permission_required = 'appointments.can_cancel_appointments' +# +# def get_success_url(self): +# return reverse('appointments:appointment_list') +# +# def form_valid(self, form): +# appointment = get_object_or_404(Appointment, pk=self.kwargs['pk']) +# +# with transaction.atomic(): +# # Update appointment status +# appointment.status = 'cancelled' +# appointment.cancelled_at = timezone.now() +# appointment.cancelled_by = self.request.user +# appointment.cancellation_reason = form.cleaned_data['cancellation_reason'] +# appointment.cancellation_notes = form.cleaned_data.get('cancellation_notes', '') +# appointment.save() +# +# # Handle follow-up actions +# if form.cleaned_data.get('offer_reschedule'): +# self.offer_reschedule(appointment) +# +# if form.cleaned_data.get('notify_patient'): +# self.send_cancellation_notification(appointment, form.cleaned_data) +# +# if form.cleaned_data.get('refund_required'): +# self.process_refund(appointment) +# +# messages.success( +# self.request, +# f'Appointment cancelled for {appointment.patient.get_full_name()}.' +# ) +# +# return super().form_valid(form) +# +# def offer_reschedule(self, appointment): +# """Offer reschedule options to patient""" +# # This would implement reschedule offering logic +# pass +# +# def send_cancellation_notification(self, appointment, form_data): +# """Send cancellation notification to patient""" +# if appointment.patient.email: +# send_mail( +# subject='Appointment Cancelled', +# message=f'Your appointment on {appointment.appointment_date} has been cancelled. Reason: {form_data["cancellation_reason"]}', +# from_email=settings.DEFAULT_FROM_EMAIL, +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def process_refund(self, appointment): +# """Process refund if required""" +# # This would implement refund processing logic +# pass +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['pk']) +# context['title'] = 'Cancel Appointment' +# return context +# +# +# class AppointmentCheckInView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for appointment check-in +# """ +# form_class = AppointmentCheckInForm +# template_name = 'appointments/appointment_checkin.html' +# permission_required = 'appointments.can_checkin_patients' +# +# def get_success_url(self): +# return reverse('appointments:appointment_detail', kwargs={'pk': self.kwargs['pk']}) +# +# def form_valid(self, form): +# appointment = get_object_or_404(Appointment, pk=self.kwargs['pk']) +# +# with transaction.atomic(): +# # Update appointment status +# appointment.status = 'checked_in' +# appointment.checked_in_at = timezone.now() +# appointment.checked_in_by = self.request.user +# appointment.arrival_time = form.cleaned_data['arrival_time'] +# appointment.save() +# +# # Create queue entry if needed +# if not hasattr(appointment, 'queue_entry'): +# Queue.objects.create( +# appointment=appointment, +# tenant=appointment.tenant, +# patient=appointment.patient, +# provider=appointment.provider, +# department=appointment.department, +# queue_type='check_in', +# priority='normal', +# status='waiting', +# created_by=self.request.user +# ) +# +# # Handle pre-visit tasks +# self.process_checkin_tasks(appointment, form.cleaned_data) +# +# messages.success( +# self.request, +# f'{appointment.patient.get_full_name()} checked in successfully.' +# ) +# +# return super().form_valid(form) +# +# def process_checkin_tasks(self, appointment, form_data): +# """Process check-in tasks""" +# tasks = [] +# +# if form_data.get('insurance_verified'): +# tasks.append('Insurance verified') +# if form_data.get('copay_collected'): +# tasks.append('Copay collected') +# if form_data.get('forms_completed'): +# tasks.append('Forms completed') +# if form_data.get('vitals_required'): +# tasks.append('Vitals required') +# +# # Log completed tasks +# if tasks: +# from core.models import AuditLogEntry +# AuditLogEntry.objects.create( +# tenant=appointment.tenant, +# user=self.request.user, +# event_type='APPOINTMENT_CHECKIN', +# action='UPDATE', +# object_type='Appointment', +# object_id=str(appointment.id), +# details={ +# 'completed_tasks': tasks, +# 'special_needs': form_data.get('special_needs', '') +# }, +# ip_address=self.request.META.get('REMOTE_ADDR'), +# user_agent=self.request.META.get('HTTP_USER_AGENT', '') +# ) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['appointment'] = get_object_or_404(Appointment, pk=self.kwargs['pk']) +# context['title'] = 'Check In Patient' +# return context +# +# +# class BulkAppointmentView(LoginRequiredMixin, PermissionRequiredMixin, FormView): +# """ +# View for bulk appointment operations +# """ +# form_class = BulkAppointmentForm +# template_name = 'appointments/bulk_appointment.html' +# permission_required = 'appointments.can_bulk_manage_appointments' +# +# def get_success_url(self): +# return reverse('appointments:appointment_list') +# +# def form_valid(self, form): +# appointment_ids = form.cleaned_data['appointment_ids'].split(',') +# appointments = Appointment.objects.filter( +# id__in=appointment_ids, +# tenant=self.request.user.tenant +# ) +# +# action = form.cleaned_data['action'] +# +# with transaction.atomic(): +# if action == 'confirm': +# self.bulk_confirm(appointments, form.cleaned_data) +# elif action == 'reschedule': +# self.bulk_reschedule(appointments, form.cleaned_data) +# elif action == 'cancel': +# self.bulk_cancel(appointments, form.cleaned_data) +# elif action == 'send_reminders': +# self.bulk_send_reminders(appointments, form.cleaned_data) +# +# messages.success( +# self.request, +# f'Bulk operation "{action}" completed for {appointments.count()} appointments.' +# ) +# +# return super().form_valid(form) +# +# def bulk_confirm(self, appointments, form_data): +# """Bulk confirm appointments""" +# for appointment in appointments: +# appointment.status = 'confirmed' +# appointment.save() +# +# if form_data.get('notify_patients'): +# self.send_confirmation_notification(appointment) +# +# def bulk_reschedule(self, appointments, form_data): +# """Bulk reschedule appointments""" +# new_date = form_data.get('bulk_date') +# if new_date: +# for appointment in appointments: +# appointment.appointment_date = new_date +# appointment.status = 'rescheduled' +# appointment.save() +# +# if form_data.get('notify_patients'): +# self.send_reschedule_notification(appointment, form_data) +# +# def bulk_cancel(self, appointments, form_data): +# """Bulk cancel appointments""" +# for appointment in appointments: +# appointment.status = 'cancelled' +# appointment.cancelled_at = timezone.now() +# appointment.cancelled_by = self.request.user +# appointment.cancellation_reason = 'bulk_cancellation' +# appointment.cancellation_notes = form_data.get('bulk_reason', '') +# appointment.save() +# +# if form_data.get('notify_patients'): +# self.send_cancellation_notification(appointment, form_data) +# +# def bulk_send_reminders(self, appointments, form_data): +# """Bulk send reminders""" +# for appointment in appointments: +# if form_data.get('notify_patients'): +# self.send_reminder_notification(appointment) +# +# def send_confirmation_notification(self, appointment): +# """Send confirmation notification""" +# if appointment.patient.email: +# send_mail( +# subject='Appointment Confirmed', +# message=f'Your appointment on {appointment.appointment_date} at {appointment.appointment_time} has been confirmed.', +# from_email=settings.DEFAULT_FROM_EMAIL, +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def send_reminder_notification(self, appointment): +# """Send reminder notification""" +# if appointment.patient.email: +# send_mail( +# subject='Appointment Reminder', +# message=f'Reminder: You have an appointment on {appointment.appointment_date} at {appointment.appointment_time}.', +# from_email=settings.DEFAULT_FROM_EMAIL, +# recipient_list=[appointment.patient.email], +# fail_silently=True +# ) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Bulk Appointment Operations' +# return context +# +# +# class AppointmentListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): +# """ +# View for listing appointments +# """ +# model = Appointment +# template_name = 'appointments/appointment_list.html' +# context_object_name = 'appointments' +# permission_required = 'appointments.view_appointment' +# paginate_by = 25 +# +# def get_queryset(self): +# queryset = Appointment.objects.filter(tenant=self.request.user.tenant) +# +# # Apply filters +# search = self.request.GET.get('search') +# if search: +# queryset = queryset.filter( +# Q(patient__first_name__icontains=search) | +# Q(patient__last_name__icontains=search) | +# Q(provider__first_name__icontains=search) | +# Q(provider__last_name__icontains=search) | +# Q(reason__icontains=search) +# ) +# +# status = self.request.GET.get('status') +# if status: +# queryset = queryset.filter(status=status) +# +# date_from = self.request.GET.get('date_from') +# if date_from: +# queryset = queryset.filter(appointment_date__gte=date_from) +# +# date_to = self.request.GET.get('date_to') +# if date_to: +# queryset = queryset.filter(appointment_date__lte=date_to) +# +# provider = self.request.GET.get('provider') +# if provider: +# queryset = queryset.filter(provider_id=provider) +# +# return queryset.order_by('appointment_date', 'appointment_time') +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Appointments' +# context['providers'] = self.get_providers() +# context['search'] = self.request.GET.get('search', '') +# context['selected_status'] = self.request.GET.get('status', '') +# context['selected_provider'] = self.request.GET.get('provider', '') +# context['date_from'] = self.request.GET.get('date_from', '') +# context['date_to'] = self.request.GET.get('date_to', '') +# return context +# +# def get_providers(self): +# """Get providers for filter""" +# from django.contrib.auth.models import User +# return User.objects.filter( +# tenant=self.request.user.tenant, +# groups__name__in=['Doctors', 'Nurses', 'Specialists'] +# ).distinct() +# +# +# class AppointmentDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): +# """ +# View for appointment details +# """ +# model = Appointment +# template_name = 'appointments/appointment_detail.html' +# context_object_name = 'appointment' +# permission_required = 'appointments.view_appointment' +# +# def get_queryset(self): +# return Appointment.objects.filter(tenant=self.request.user.tenant) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# appointment = self.object +# context['title'] = f'Appointment - {appointment.patient.get_full_name()}' +# context['confirmation'] = getattr(appointment, 'confirmation', None) +# context['queue_entry'] = getattr(appointment, 'queue_entry', None) +# context['telemedicine_session'] = getattr(appointment, 'telemedicine_session', None) +# context['can_edit'] = self.request.user.has_perm('appointments.change_appointment') +# context['can_cancel'] = self.request.user.has_perm('appointments.can_cancel_appointments') +# context['can_reschedule'] = self.request.user.has_perm('appointments.can_reschedule_appointments') +# return context +# +# +# class QueueListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): +# """ +# View for listing queue entries +# """ +# model = Queue +# template_name = 'appointments/queue_list.html' +# context_object_name = 'queue_entries' +# permission_required = 'appointments.view_queue' +# +# def get_queryset(self): +# queryset = Queue.objects.filter(tenant=self.request.user.tenant) +# +# # Apply filters +# status = self.request.GET.get('status', 'waiting') +# if status: +# queryset = queryset.filter(status=status) +# +# department = self.request.GET.get('department') +# if department: +# queryset = queryset.filter(department_id=department) +# +# return queryset.order_by('priority', 'created_at') +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Patient Queue' +# context['departments'] = self.get_departments() +# context['selected_status'] = self.request.GET.get('status', 'waiting') +# context['selected_department'] = self.request.GET.get('department', '') +# context['queue_stats'] = self.get_queue_stats() +# return context +# +# def get_departments(self): +# """Get departments for filter""" +# from core.models import Department +# return Department.objects.filter(tenant=self.request.user.tenant) +# +# def get_queue_stats(self): +# """Get queue statistics""" +# return { +# 'total_waiting': Queue.objects.filter( +# tenant=self.request.user.tenant, +# status='waiting' +# ).count(), +# 'average_wait_time': 25, # Would be calculated +# 'longest_wait': 45 # Would be calculated +# } +# +# +# # AJAX Views +# @login_required +# @permission_required('appointments.view_appointment') +# def appointment_availability_ajax(request): +# """AJAX view to check appointment availability""" +# date = request.GET.get('date') +# provider_id = request.GET.get('provider_id') +# +# if not date or not provider_id: +# return JsonResponse({'success': False, 'message': 'Missing parameters'}) +# +# try: +# from django.contrib.auth.models import User +# provider = User.objects.get(id=provider_id, tenant=request.user.tenant) +# appointment_date = datetime.strptime(date, '%Y-%m-%d').date() +# +# # Get existing appointments for the date +# existing_appointments = Appointment.objects.filter( +# provider=provider, +# appointment_date=appointment_date, +# status__in=['scheduled', 'confirmed', 'in_progress'] +# ) +# +# # Generate available slots +# available_slots = generate_available_slots(appointment_date, existing_appointments) +# +# return JsonResponse({ +# 'success': True, +# 'slots': available_slots +# }) +# except Exception as e: +# return JsonResponse({'success': False, 'message': str(e)}) +# +# +# @login_required +# @permission_required('appointments.view_patient') +# def patient_search_ajax(request): +# """AJAX view for patient search""" +# query = request.GET.get('q', '') +# if len(query) < 2: +# return JsonResponse({'patients': []}) +# +# patients = Patient.objects.filter( +# tenant=request.user.tenant +# ).filter( +# Q(first_name__icontains=query) | +# Q(last_name__icontains=query) | +# Q(patient_id__icontains=query) | +# Q(phone_number__icontains=query) +# )[:10] +# +# patient_data = [ +# { +# 'id': patient.id, +# 'name': patient.get_full_name(), +# 'patient_id': patient.patient_id, +# 'phone': patient.phone_number, +# 'email': patient.email +# } +# for patient in patients +# ] +# +# return JsonResponse({'patients': patient_data}) +# +# +# @login_required +# @permission_required('appointments.can_manage_queue') +# def update_queue_position_ajax(request): +# """AJAX view to update queue position""" +# if request.method == 'POST': +# try: +# data = json.loads(request.body) +# queue_id = data.get('queue_id') +# new_position = data.get('new_position') +# +# queue_entry = Queue.objects.get( +# id=queue_id, +# tenant=request.user.tenant +# ) +# +# queue_entry.position = new_position +# queue_entry.save() +# +# return JsonResponse({ +# 'success': True, +# 'message': 'Queue position updated successfully.' +# }) +# except Queue.DoesNotExist: +# return JsonResponse({ +# 'success': False, +# 'message': 'Queue entry not found.' +# }) +# except Exception as e: +# return JsonResponse({ +# 'success': False, +# 'message': str(e) +# }) +# +# return JsonResponse({'success': False, 'message': 'Invalid request.'}) +# +# +# def generate_available_slots(date, existing_appointments): +# """Generate available appointment slots for a date""" +# slots = [] +# start_time = datetime.strptime('09:00', '%H:%M').time() +# end_time = datetime.strptime('17:00', '%H:%M').time() +# slot_duration = 30 # minutes +# +# current_time = datetime.combine(date, start_time) +# end_datetime = datetime.combine(date, end_time) +# +# while current_time < end_datetime: +# slot_time = current_time.time() +# +# # Check if slot is available +# is_available = True +# for appointment in existing_appointments: +# appointment_start = datetime.combine(date, appointment.appointment_time) +# appointment_end = appointment_start + timedelta(minutes=appointment.duration) +# +# slot_start = current_time +# slot_end = current_time + timedelta(minutes=slot_duration) +# +# if slot_start < appointment_end and slot_end > appointment_start: +# is_available = False +# break +# +# if is_available: +# slots.append({ +# 'time': slot_time.strftime('%H:%M'), +# 'available': True +# }) +# +# current_time += timedelta(minutes=slot_duration) +# +# return slots +# diff --git a/billing/__pycache__/flows.cpython-312.pyc b/billing/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..b0341c05 Binary files /dev/null and b/billing/__pycache__/flows.cpython-312.pyc differ diff --git a/billing/__pycache__/forms.cpython-312.pyc b/billing/__pycache__/forms.cpython-312.pyc index dee0ae36..1499c47d 100644 Binary files a/billing/__pycache__/forms.cpython-312.pyc and b/billing/__pycache__/forms.cpython-312.pyc differ diff --git a/billing/__pycache__/urls.cpython-312.pyc b/billing/__pycache__/urls.cpython-312.pyc index 1100ee35..dd846f07 100644 Binary files a/billing/__pycache__/urls.cpython-312.pyc and b/billing/__pycache__/urls.cpython-312.pyc differ diff --git a/billing/__pycache__/views.cpython-312.pyc b/billing/__pycache__/views.cpython-312.pyc index de825d6a..f9e5bcdf 100644 Binary files a/billing/__pycache__/views.cpython-312.pyc and b/billing/__pycache__/views.cpython-312.pyc differ diff --git a/billing/flows.py b/billing/flows.py new file mode 100644 index 00000000..3088bc61 --- /dev/null +++ b/billing/flows.py @@ -0,0 +1,1022 @@ +# """ +# Viewflow workflows for billing app. +# Provides medical billing, insurance claims, and payment processing workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import MedicalBill, InsuranceClaim, Payment, ClaimStatusUpdate +# from .views import ( +# BillGenerationView, ChargeReviewView, InsuranceVerificationView, +# ClaimPreparationView, ClaimSubmissionView, ClaimTrackingView, +# PaymentProcessingView, PaymentReconciliationView, DenialManagementView, +# AppealPreparationView, CollectionsView +# ) +# +# +# class MedicalBillingProcess(Process): +# """ +# Viewflow process model for medical billing +# """ +# medical_bill = ModelField(MedicalBill, help_text='Associated medical bill') +# +# # Process status tracking +# charges_captured = models.BooleanField(default=False) +# charges_reviewed = models.BooleanField(default=False) +# insurance_verified = models.BooleanField(default=False) +# bill_generated = models.BooleanField(default=False) +# claims_submitted = models.BooleanField(default=False) +# payments_processed = models.BooleanField(default=False) +# account_reconciled = models.BooleanField(default=False) +# billing_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Medical Billing Process' +# verbose_name_plural = 'Medical Billing Processes' +# +# +# class MedicalBillingFlow(Flow): +# """ +# Medical Billing Workflow +# +# This flow manages the complete revenue cycle from charge capture +# through payment processing and account reconciliation. +# """ +# +# process_class = MedicalBillingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_billing) +# .Next(this.capture_charges) +# ) +# +# capture_charges = ( +# flow_func(this.collect_service_charges) +# .Next(this.review_charges) +# ) +# +# review_charges = ( +# flow_view(ChargeReviewView) +# .Permission('billing.can_review_charges') +# .Next(this.verify_insurance) +# ) +# +# verify_insurance = ( +# flow_view(InsuranceVerificationView) +# .Permission('billing.can_verify_insurance') +# .Next(this.generate_bill) +# ) +# +# generate_bill = ( +# flow_view(BillGenerationView) +# .Permission('billing.can_generate_bills') +# .Next(this.parallel_claim_processing) +# ) +# +# parallel_claim_processing = ( +# flow_func(this.start_parallel_processing) +# .Next(this.submit_primary_claim) +# .Next(this.submit_secondary_claim) +# .Next(this.patient_billing) +# ) +# +# submit_primary_claim = ( +# flow_view(PrimaryClaimSubmissionView) +# .Permission('billing.can_submit_claims') +# .Next(this.join_claim_processing) +# ) +# +# submit_secondary_claim = ( +# flow_view(SecondaryClaimSubmissionView) +# .Permission('billing.can_submit_claims') +# .Next(this.join_claim_processing) +# ) +# +# patient_billing = ( +# flow_view(PatientBillingView) +# .Permission('billing.can_bill_patients') +# .Next(this.join_claim_processing) +# ) +# +# join_claim_processing = ( +# flow_func(this.join_parallel_processing) +# .Next(this.process_payments) +# ) +# +# process_payments = ( +# flow_view(PaymentProcessingView) +# .Permission('billing.can_process_payments') +# .Next(this.reconcile_account) +# ) +# +# reconcile_account = ( +# flow_view(PaymentReconciliationView) +# .Permission('billing.can_reconcile_accounts') +# .Next(this.finalize_billing) +# ) +# +# finalize_billing = ( +# flow_func(this.complete_billing) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_billing) +# +# # Flow functions +# def start_billing(self, activation): +# """Initialize the billing process""" +# process = activation.process +# bill = process.medical_bill +# +# # Update bill status +# bill.status = 'PROCESSING' +# bill.save() +# +# # Send notification to billing staff +# self.notify_billing_staff(bill) +# +# # Check for priority billing +# if bill.bill_type in ['EMERGENCY', 'SURGERY']: +# self.notify_priority_billing(bill) +# +# def collect_service_charges(self, activation): +# """Collect charges from various service departments""" +# process = activation.process +# bill = process.medical_bill +# +# # Collect charges from different departments +# charges = self.gather_service_charges(bill) +# +# if charges: +# # Update bill with collected charges +# self.update_bill_charges(bill, charges) +# +# process.charges_captured = True +# process.save() +# +# def start_parallel_processing(self, activation): +# """Start parallel claim and billing processing""" +# process = activation.process +# +# # Create parallel processing tasks +# self.create_claim_tasks(process.medical_bill) +# +# def join_parallel_processing(self, activation): +# """Wait for all claim processing to complete""" +# process = activation.process +# +# # Check if all processing is completed +# if self.all_claims_processed(process.medical_bill): +# # Proceed to payment processing +# self.notify_claims_completed(process.medical_bill) +# +# def complete_billing(self, activation): +# """Finalize the billing process""" +# process = activation.process +# bill = process.medical_bill +# +# # Update bill status based on payment status +# if bill.balance_due <= 0: +# bill.status = 'PAID' +# elif bill.total_payments > 0: +# bill.status = 'PARTIALLY_PAID' +# else: +# bill.status = 'OUTSTANDING' +# +# bill.save() +# +# # Mark process as completed +# process.billing_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_billing_completion(bill) +# +# # Update revenue metrics +# self.update_revenue_metrics(bill) +# +# def end_billing(self, activation): +# """End the billing workflow""" +# process = activation.process +# +# # Generate billing summary report +# self.generate_billing_summary(process.medical_bill) +# +# # Helper methods +# def notify_billing_staff(self, bill): +# """Notify billing staff of new bill""" +# from django.contrib.auth.models import Group +# +# billing_staff = User.objects.filter( +# groups__name='Billing Staff' +# ) +# +# for staff in billing_staff: +# send_mail( +# subject=f'New Medical Bill: {bill.bill_number}', +# message=f'New medical bill for {bill.patient.get_full_name()} requires processing.', +# from_email='billing@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_priority_billing(self, bill): +# """Notify of priority billing""" +# billing_managers = User.objects.filter( +# groups__name='Billing Managers' +# ) +# +# for manager in billing_managers: +# send_mail( +# subject=f'PRIORITY Billing: {bill.bill_number}', +# message=f'{bill.get_bill_type_display()} bill requires priority processing.', +# from_email='billing@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def gather_service_charges(self, bill): +# """Gather charges from service departments""" +# # This would collect charges from various departments +# return [] +# +# def update_bill_charges(self, bill, charges): +# """Update bill with collected charges""" +# # This would update the bill with charges +# pass +# +# def create_claim_tasks(self, bill): +# """Create claim processing tasks""" +# # This would create tasks for claim processing +# pass +# +# def all_claims_processed(self, bill): +# """Check if all claims are processed""" +# # This would check claim processing status +# return True +# +# def notify_claims_completed(self, bill): +# """Notify that claims processing is completed""" +# billing_staff = User.objects.filter( +# groups__name='Billing Staff' +# ) +# +# for staff in billing_staff: +# send_mail( +# subject=f'Claims Processed: {bill.bill_number}', +# message=f'All claims have been processed for {bill.patient.get_full_name()}.', +# from_email='billing@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_billing_completion(self, bill): +# """Notify billing completion""" +# # Notify patient if email available +# if bill.patient.email: +# send_mail( +# subject='Medical Bill Processed', +# message=f'Your medical bill {bill.bill_number} has been processed.', +# from_email='billing@hospital.com', +# recipient_list=[bill.patient.email], +# fail_silently=True +# ) +# +# def update_revenue_metrics(self, bill): +# """Update revenue cycle metrics""" +# # This would update revenue metrics +# pass +# +# def generate_billing_summary(self, bill): +# """Generate billing summary report""" +# # This would generate a comprehensive billing report +# pass +# +# +# class InsuranceClaimProcess(Process): +# """ +# Viewflow process model for insurance claims +# """ +# insurance_claim = ModelField(InsuranceClaim, help_text='Associated insurance claim') +# +# # Process status tracking +# claim_prepared = models.BooleanField(default=False) +# eligibility_verified = models.BooleanField(default=False) +# claim_submitted = models.BooleanField(default=False) +# claim_tracked = models.BooleanField(default=False) +# response_received = models.BooleanField(default=False) +# payment_posted = models.BooleanField(default=False) +# denials_managed = models.BooleanField(default=False) +# claim_finalized = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Insurance Claim Process' +# verbose_name_plural = 'Insurance Claim Processes' +# +# +# class InsuranceClaimFlow(Flow): +# """ +# Insurance Claim Processing Workflow +# +# This flow manages insurance claim processing from preparation +# through payment posting and denial management. +# """ +# +# process_class = InsuranceClaimProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_claim) +# .Next(this.prepare_claim) +# ) +# +# prepare_claim = ( +# flow_view(ClaimPreparationView) +# .Permission('billing.can_prepare_claims') +# .Next(this.verify_eligibility) +# ) +# +# verify_eligibility = ( +# flow_view(EligibilityVerificationView) +# .Permission('billing.can_verify_eligibility') +# .Next(this.submit_claim) +# ) +# +# submit_claim = ( +# flow_view(ClaimSubmissionView) +# .Permission('billing.can_submit_claims') +# .Next(this.track_claim) +# ) +# +# track_claim = ( +# flow_view(ClaimTrackingView) +# .Permission('billing.can_track_claims') +# .Next(this.receive_response) +# ) +# +# receive_response = ( +# flow_func(this.process_claim_response) +# .Next(this.post_payment) +# ) +# +# post_payment = ( +# flow_view(PaymentPostingView) +# .Permission('billing.can_post_payments') +# .Next(this.manage_denials) +# ) +# +# manage_denials = ( +# flow_view(DenialManagementView) +# .Permission('billing.can_manage_denials') +# .Next(this.finalize_claim) +# ) +# +# finalize_claim = ( +# flow_func(this.complete_claim) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_claim) +# +# # Flow functions +# def start_claim(self, activation): +# """Initialize the claim process""" +# process = activation.process +# claim = process.insurance_claim +# +# # Update claim status +# claim.status = 'PREPARING' +# claim.save() +# +# # Send notification to claims staff +# self.notify_claims_staff(claim) +# +# def process_claim_response(self, activation): +# """Process insurance claim response""" +# process = activation.process +# claim = process.insurance_claim +# +# # Check for claim response +# response = self.check_claim_response(claim) +# +# if response: +# # Update claim with response +# self.update_claim_response(claim, response) +# +# process.response_received = True +# process.save() +# +# # Handle different response types +# if response.get('status') == 'DENIED': +# self.handle_claim_denial(claim, response) +# elif response.get('status') == 'PAID': +# self.handle_claim_payment(claim, response) +# +# def complete_claim(self, activation): +# """Finalize the claim process""" +# process = activation.process +# claim = process.insurance_claim +# +# # Update claim status based on final outcome +# if claim.paid_amount >= claim.billed_amount: +# claim.status = 'PAID' +# elif claim.paid_amount > 0: +# claim.status = 'PARTIALLY_PAID' +# elif claim.denial_reason: +# claim.status = 'DENIED' +# else: +# claim.status = 'PENDING' +# +# claim.save() +# +# # Mark process as completed +# process.claim_finalized = True +# process.save() +# +# # Send completion notifications +# self.notify_claim_completion(claim) +# +# def end_claim(self, activation): +# """End the claim workflow""" +# process = activation.process +# +# # Generate claim summary report +# self.generate_claim_summary(process.insurance_claim) +# +# # Helper methods +# def notify_claims_staff(self, claim): +# """Notify claims staff""" +# claims_staff = User.objects.filter( +# groups__name='Claims Staff' +# ) +# +# for staff in claims_staff: +# send_mail( +# subject=f'New Insurance Claim: {claim.claim_number}', +# message=f'New insurance claim for {claim.patient.get_full_name()} requires processing.', +# from_email='claims@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def check_claim_response(self, claim): +# """Check for claim response from insurance""" +# # This would check for insurance responses +# return None +# +# def update_claim_response(self, claim, response): +# """Update claim with insurance response""" +# # This would update the claim with response data +# pass +# +# def handle_claim_denial(self, claim, response): +# """Handle claim denial""" +# # Notify claims staff of denial +# claims_staff = User.objects.filter( +# groups__name='Claims Staff' +# ) +# +# for staff in claims_staff: +# send_mail( +# subject=f'Claim Denied: {claim.claim_number}', +# message=f'Insurance claim has been denied. Reason: {response.get("denial_reason", "Unknown")}', +# from_email='claims@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def handle_claim_payment(self, claim, response): +# """Handle claim payment""" +# # This would process claim payment +# pass +# +# def notify_claim_completion(self, claim): +# """Notify claim completion""" +# # This would notify relevant parties +# pass +# +# def generate_claim_summary(self, claim): +# """Generate claim summary report""" +# # This would generate claim summary +# pass +# +# +# class PaymentProcessingProcess(Process): +# """ +# Viewflow process model for payment processing +# """ +# payment = ModelField(Payment, help_text='Associated payment') +# +# # Process status tracking +# payment_received = models.BooleanField(default=False) +# payment_verified = models.BooleanField(default=False) +# payment_processed = models.BooleanField(default=False) +# payment_deposited = models.BooleanField(default=False) +# account_updated = models.BooleanField(default=False) +# receipt_generated = models.BooleanField(default=False) +# payment_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Payment Processing Process' +# verbose_name_plural = 'Payment Processing Processes' +# +# +# class PaymentProcessingFlow(Flow): +# """ +# Payment Processing Workflow +# +# This flow manages payment processing from receipt through +# deposit and account reconciliation. +# """ +# +# process_class = PaymentProcessingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_payment) +# .Next(this.receive_payment) +# ) +# +# receive_payment = ( +# flow_view(PaymentReceiptView) +# .Permission('billing.can_receive_payments') +# .Next(this.verify_payment) +# ) +# +# verify_payment = ( +# flow_view(PaymentVerificationView) +# .Permission('billing.can_verify_payments') +# .Next(this.process_payment) +# ) +# +# process_payment = ( +# flow_view(PaymentProcessingView) +# .Permission('billing.can_process_payments') +# .Next(this.deposit_payment) +# ) +# +# deposit_payment = ( +# flow_view(PaymentDepositView) +# .Permission('billing.can_deposit_payments') +# .Next(this.update_account) +# ) +# +# update_account = ( +# flow_func(this.update_patient_account) +# .Next(this.generate_receipt) +# ) +# +# generate_receipt = ( +# flow_view(ReceiptGenerationView) +# .Permission('billing.can_generate_receipts') +# .Next(this.finalize_payment) +# ) +# +# finalize_payment = ( +# flow_func(this.complete_payment) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_payment) +# +# # Flow functions +# def start_payment(self, activation): +# """Initialize the payment process""" +# process = activation.process +# payment = process.payment +# +# # Update payment status +# payment.status = 'PENDING' +# payment.save() +# +# # Send notification to billing staff +# self.notify_payment_received(payment) +# +# def update_patient_account(self, activation): +# """Update patient account with payment""" +# process = activation.process +# payment = process.payment +# +# # Update medical bill balance +# bill = payment.medical_bill +# bill.total_payments += payment.payment_amount +# bill.balance_due = bill.total_amount - bill.total_payments +# bill.save() +# +# process.account_updated = True +# process.save() +# +# # Check if bill is fully paid +# if bill.balance_due <= 0: +# self.notify_account_paid_in_full(bill) +# +# def complete_payment(self, activation): +# """Finalize the payment process""" +# process = activation.process +# payment = process.payment +# +# # Update payment status +# payment.status = 'PROCESSED' +# payment.save() +# +# # Mark process as completed +# process.payment_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_payment_completion(payment) +# +# def end_payment(self, activation): +# """End the payment workflow""" +# process = activation.process +# +# # Generate payment summary report +# self.generate_payment_summary(process.payment) +# +# # Helper methods +# def notify_payment_received(self, payment): +# """Notify billing staff of payment received""" +# billing_staff = User.objects.filter( +# groups__name='Billing Staff' +# ) +# +# for staff in billing_staff: +# send_mail( +# subject=f'Payment Received: {payment.payment_number}', +# message=f'Payment of ${payment.payment_amount} received for {payment.patient.get_full_name()}.', +# from_email='billing@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_account_paid_in_full(self, bill): +# """Notify that account is paid in full""" +# # Notify patient +# if bill.patient.email: +# send_mail( +# subject='Account Paid in Full', +# message=f'Your account for bill {bill.bill_number} has been paid in full.', +# from_email='billing@hospital.com', +# recipient_list=[bill.patient.email], +# fail_silently=True +# ) +# +# def notify_payment_completion(self, payment): +# """Notify payment completion""" +# # This would notify relevant parties +# pass +# +# def generate_payment_summary(self, payment): +# """Generate payment summary report""" +# # This would generate payment summary +# pass +# +# +# class DenialManagementProcess(Process): +# """ +# Viewflow process model for denial management +# """ +# insurance_claim = ModelField(InsuranceClaim, help_text='Associated denied claim') +# +# # Process status tracking +# denial_analyzed = models.BooleanField(default=False) +# appeal_prepared = models.BooleanField(default=False) +# appeal_submitted = models.BooleanField(default=False) +# appeal_tracked = models.BooleanField(default=False) +# appeal_resolved = models.BooleanField(default=False) +# account_adjusted = models.BooleanField(default=False) +# denial_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Denial Management Process' +# verbose_name_plural = 'Denial Management Processes' +# +# +# class DenialManagementFlow(Flow): +# """ +# Denial Management Workflow +# +# This flow manages insurance claim denials including analysis, +# appeal preparation, submission, and resolution. +# """ +# +# process_class = DenialManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_denial_management) +# .Next(this.analyze_denial) +# ) +# +# analyze_denial = ( +# flow_view(DenialAnalysisView) +# .Permission('billing.can_analyze_denials') +# .Next(this.prepare_appeal) +# ) +# +# prepare_appeal = ( +# flow_view(AppealPreparationView) +# .Permission('billing.can_prepare_appeals') +# .Next(this.submit_appeal) +# ) +# +# submit_appeal = ( +# flow_view(AppealSubmissionView) +# .Permission('billing.can_submit_appeals') +# .Next(this.track_appeal) +# ) +# +# track_appeal = ( +# flow_view(AppealTrackingView) +# .Permission('billing.can_track_appeals') +# .Next(this.resolve_appeal) +# ) +# +# resolve_appeal = ( +# flow_func(this.process_appeal_resolution) +# .Next(this.adjust_account) +# ) +# +# adjust_account = ( +# flow_view(AccountAdjustmentView) +# .Permission('billing.can_adjust_accounts') +# .Next(this.finalize_denial) +# ) +# +# finalize_denial = ( +# flow_func(this.complete_denial_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_denial_management) +# +# # Flow functions +# def start_denial_management(self, activation): +# """Initialize the denial management process""" +# process = activation.process +# claim = process.insurance_claim +# +# # Send notification to denial management staff +# self.notify_denial_staff(claim) +# +# def process_appeal_resolution(self, activation): +# """Process appeal resolution""" +# process = activation.process +# claim = process.insurance_claim +# +# # Check appeal status +# appeal_result = self.check_appeal_status(claim) +# +# if appeal_result: +# # Update claim with appeal result +# self.update_appeal_result(claim, appeal_result) +# +# process.appeal_resolved = True +# process.save() +# +# def complete_denial_management(self, activation): +# """Finalize the denial management process""" +# process = activation.process +# claim = process.insurance_claim +# +# # Mark process as completed +# process.denial_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_denial_completion(claim) +# +# def end_denial_management(self, activation): +# """End the denial management workflow""" +# process = activation.process +# +# # Generate denial management summary +# self.generate_denial_summary(process.insurance_claim) +# +# # Helper methods +# def notify_denial_staff(self, claim): +# """Notify denial management staff""" +# denial_staff = User.objects.filter( +# groups__name='Denial Management' +# ) +# +# for staff in denial_staff: +# send_mail( +# subject=f'Claim Denial: {claim.claim_number}', +# message=f'Insurance claim has been denied and requires review.', +# from_email='denials@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def check_appeal_status(self, claim): +# """Check appeal status""" +# # This would check appeal status +# return None +# +# def update_appeal_result(self, claim, result): +# """Update claim with appeal result""" +# # This would update the claim with appeal result +# pass +# +# def notify_denial_completion(self, claim): +# """Notify denial management completion""" +# # This would notify relevant parties +# pass +# +# def generate_denial_summary(self, claim): +# """Generate denial management summary""" +# # This would generate denial summary +# pass +# +# +# class CollectionsProcess(Process): +# """ +# Viewflow process model for collections +# """ +# medical_bill = ModelField(MedicalBill, help_text='Associated medical bill') +# +# # Process status tracking +# account_reviewed = models.BooleanField(default=False) +# patient_contacted = models.BooleanField(default=False) +# payment_plan_offered = models.BooleanField(default=False) +# collection_actions_taken = models.BooleanField(default=False) +# external_agency_assigned = models.BooleanField(default=False) +# collections_resolved = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Collections Process' +# verbose_name_plural = 'Collections Processes' +# +# +# class CollectionsFlow(Flow): +# """ +# Collections Workflow +# +# This flow manages collections activities for overdue accounts +# including patient contact, payment plans, and external collections. +# """ +# +# process_class = CollectionsProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_collections) +# .Next(this.review_account) +# ) +# +# review_account = ( +# flow_view(AccountReviewView) +# .Permission('billing.can_review_collections') +# .Next(this.contact_patient) +# ) +# +# contact_patient = ( +# flow_view(PatientContactView) +# .Permission('billing.can_contact_patients') +# .Next(this.offer_payment_plan) +# ) +# +# offer_payment_plan = ( +# flow_view(PaymentPlanView) +# .Permission('billing.can_offer_payment_plans') +# .Next(this.collection_actions) +# ) +# +# collection_actions = ( +# flow_view(CollectionActionsView) +# .Permission('billing.can_take_collection_actions') +# .Next(this.external_collections) +# ) +# +# external_collections = ( +# flow_view(ExternalCollectionsView) +# .Permission('billing.can_assign_external_collections') +# .Next(this.resolve_collections) +# ) +# +# resolve_collections = ( +# flow_func(this.complete_collections) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_collections) +# +# # Flow functions +# def start_collections(self, activation): +# """Initialize the collections process""" +# process = activation.process +# bill = process.medical_bill +# +# # Send notification to collections staff +# self.notify_collections_staff(bill) +# +# def complete_collections(self, activation): +# """Finalize the collections process""" +# process = activation.process +# bill = process.medical_bill +# +# # Mark process as completed +# process.collections_resolved = True +# process.save() +# +# # Send completion notifications +# self.notify_collections_completion(bill) +# +# def end_collections(self, activation): +# """End the collections workflow""" +# process = activation.process +# +# # Generate collections summary +# self.generate_collections_summary(process.medical_bill) +# +# # Helper methods +# def notify_collections_staff(self, bill): +# """Notify collections staff""" +# collections_staff = User.objects.filter( +# groups__name='Collections Staff' +# ) +# +# for staff in collections_staff: +# send_mail( +# subject=f'Collections Account: {bill.bill_number}', +# message=f'Account for {bill.patient.get_full_name()} requires collections action.', +# from_email='collections@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_collections_completion(self, bill): +# """Notify collections completion""" +# # This would notify relevant parties +# pass +# +# def generate_collections_summary(self, bill): +# """Generate collections summary""" +# # This would generate collections summary +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_generate_bills(): +# """Background task to automatically generate bills""" +# try: +# # This would generate bills for completed services +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_claim_status(): +# """Background task to monitor insurance claim status""" +# try: +# # This would check claim status with insurance companies +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_billing_reports(): +# """Background task to generate billing reports""" +# try: +# # This would generate daily billing reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_post_insurance_payments(): +# """Background task to automatically post insurance payments""" +# try: +# # This would post insurance payments from EDI files +# return True +# except Exception: +# return False +# +# +# @celery.job +# def identify_collection_accounts(): +# """Background task to identify accounts for collections""" +# try: +# # This would identify overdue accounts +# return True +# except Exception: +# return False +# diff --git a/billing/forms.py b/billing/forms.py index 30aa60b9..44b2bd66 100644 --- a/billing/forms.py +++ b/billing/forms.py @@ -786,3 +786,790 @@ class PaymentSearchForm(forms.Form): }) ) + +# from django import forms +# from django.core.exceptions import ValidationError +# from django.utils import timezone +# from django.contrib.auth.models import User +# from crispy_forms.helper import FormHelper +# from crispy_forms.layout import Layout, Fieldset, Submit, Row, Column, HTML, Div +# from crispy_forms.bootstrap import FormActions +# from decimal import Decimal +# import json +# +# from .models import ( +# Bill, BillItem, InsuranceClaim, Payment, PaymentMethod, +# InsuranceProvider, ClaimDenial, PaymentPlan +# ) +# from patients.models import Patient +# +# +# class MedicalBillingForm(forms.ModelForm): +# """ +# Form for medical billing creation +# """ +# patient_search = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={ +# 'class': 'form-control', +# 'placeholder': 'Search patient by name, ID, or insurance...', +# 'data-toggle': 'patient-search' +# }) +# ) +# insurance_verification = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# auto_submit_primary = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# auto_submit_secondary = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# generate_patient_statement = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = Bill +# fields = [ +# 'patient', 'encounter', 'bill_type', 'service_date', +# 'diagnosis_codes', 'procedure_codes', 'provider', +# 'facility', 'insurance_verification', 'auto_submit_primary', +# 'auto_submit_secondary', 'generate_patient_statement' +# ] +# widgets = { +# 'patient': forms.Select(attrs={'class': 'form-control'}), +# 'encounter': forms.Select(attrs={'class': 'form-control'}), +# 'bill_type': forms.Select(attrs={'class': 'form-control'}), +# 'service_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}), +# 'diagnosis_codes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), +# 'procedure_codes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), +# 'provider': forms.Select(attrs={'class': 'form-control'}), +# 'facility': forms.Select(attrs={'class': 'form-control'}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['patient'].queryset = Patient.objects.filter(tenant=tenant) +# self.fields['provider'].queryset = User.objects.filter( +# tenant=tenant, +# groups__name__in=['Doctors', 'Nurses', 'Specialists'] +# ) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Patient Information', +# 'patient_search', +# 'patient', +# 'encounter' +# ), +# Fieldset( +# 'Service Details', +# Row( +# Column('bill_type', css_class='form-group col-md-6 mb-0'), +# Column('service_date', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('provider', css_class='form-group col-md-6 mb-0'), +# Column('facility', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'diagnosis_codes', +# 'procedure_codes' +# ), +# Fieldset( +# 'Billing Options', +# HTML('
'), +# 'insurance_verification', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'auto_submit_primary', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'auto_submit_secondary', +# HTML( +# ''), +# HTML('
'), +# HTML('
'), +# 'generate_patient_statement', +# HTML( +# ''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Create Bill', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean_diagnosis_codes(self): +# codes = self.cleaned_data.get('diagnosis_codes') +# if codes: +# # Validate ICD-10 codes format +# code_list = [code.strip() for code in codes.split(',')] +# for code in code_list: +# if not self.validate_icd10_code(code): +# raise ValidationError(f'Invalid ICD-10 code format: {code}') +# return codes +# +# def clean_procedure_codes(self): +# codes = self.cleaned_data.get('procedure_codes') +# if codes: +# # Validate CPT codes format +# code_list = [code.strip() for code in codes.split(',')] +# for code in code_list: +# if not self.validate_cpt_code(code): +# raise ValidationError(f'Invalid CPT code format: {code}') +# return codes +# +# def validate_icd10_code(self, code): +# """Validate ICD-10 code format""" +# # Basic ICD-10 validation (simplified) +# return len(code) >= 3 and code[0].isalpha() +# +# def validate_cpt_code(self, code): +# """Validate CPT code format""" +# # Basic CPT validation (simplified) +# return len(code) == 5 and code.isdigit() +# +# +# class BillItemForm(forms.ModelForm): +# """ +# Form for bill item creation/editing +# """ +# quantity = forms.DecimalField( +# max_digits=10, +# decimal_places=2, +# initial=1.00, +# widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# ) +# unit_price = forms.DecimalField( +# max_digits=10, +# decimal_places=2, +# widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# ) +# discount_amount = forms.DecimalField( +# max_digits=10, +# decimal_places=2, +# initial=0.00, +# required=False, +# widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# ) +# +# class Meta: +# model = BillItem +# fields = [ +# 'service_code', 'description', 'quantity', 'unit_price', +# 'discount_amount', 'modifier_codes', 'revenue_code' +# ] +# widgets = { +# 'service_code': forms.TextInput(attrs={'class': 'form-control'}), +# 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 2}), +# 'modifier_codes': forms.TextInput(attrs={'class': 'form-control'}), +# 'revenue_code': forms.TextInput(attrs={'class': 'form-control'}) +# } +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Service Information', +# Row( +# Column('service_code', css_class='form-group col-md-6 mb-0'), +# Column('revenue_code', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'description', +# 'modifier_codes' +# ), +# Fieldset( +# 'Pricing', +# Row( +# Column('quantity', css_class='form-group col-md-4 mb-0'), +# Column('unit_price', css_class='form-group col-md-4 mb-0'), +# Column('discount_amount', css_class='form-group col-md-4 mb-0'), +# css_class='form-row' +# ) +# ), +# FormActions( +# Submit('submit', 'Save Item', css_class='btn btn-primary'), +# HTML('') +# ) +# ) +# +# def clean(self): +# cleaned_data = super().clean() +# quantity = cleaned_data.get('quantity') +# unit_price = cleaned_data.get('unit_price') +# discount_amount = cleaned_data.get('discount_amount', Decimal('0.00')) +# +# if quantity and unit_price: +# total_amount = quantity * unit_price +# if discount_amount > total_amount: +# raise ValidationError('Discount amount cannot exceed total amount.') +# +# return cleaned_data +# +# +# class InsuranceClaimForm(forms.ModelForm): +# """ +# Form for insurance claim submission +# """ +# claim_type = forms.ChoiceField( +# choices=[ +# ('primary', 'Primary Insurance'), +# ('secondary', 'Secondary Insurance'), +# ('tertiary', 'Tertiary Insurance') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# submit_electronically = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# prior_authorization = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# referral_number = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# +# class Meta: +# model = InsuranceClaim +# fields = [ +# 'bill', 'insurance_provider', 'claim_type', 'policy_number', +# 'group_number', 'subscriber_id', 'prior_authorization', +# 'referral_number', 'submit_electronically' +# ] +# widgets = { +# 'bill': forms.Select(attrs={'class': 'form-control'}), +# 'insurance_provider': forms.Select(attrs={'class': 'form-control'}), +# 'policy_number': forms.TextInput(attrs={'class': 'form-control'}), +# 'group_number': forms.TextInput(attrs={'class': 'form-control'}), +# 'subscriber_id': forms.TextInput(attrs={'class': 'form-control'}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['bill'].queryset = Bill.objects.filter(tenant=tenant) +# self.fields['insurance_provider'].queryset = InsuranceProvider.objects.filter(tenant=tenant) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Claim Information', +# Row( +# Column('bill', css_class='form-group col-md-6 mb-0'), +# Column('claim_type', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'insurance_provider' +# ), +# Fieldset( +# 'Insurance Details', +# Row( +# Column('policy_number', css_class='form-group col-md-6 mb-0'), +# Column('group_number', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'subscriber_id' +# ), +# Fieldset( +# 'Authorization', +# Row( +# Column('prior_authorization', css_class='form-group col-md-6 mb-0'), +# Column('referral_number', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ) +# ), +# Fieldset( +# 'Submission Options', +# HTML('
'), +# 'submit_electronically', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Submit Claim', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class PaymentProcessingForm(forms.ModelForm): +# """ +# Form for payment processing +# """ +# payment_amount = forms.DecimalField( +# max_digits=10, +# decimal_places=2, +# widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# ) +# payment_date = forms.DateField( +# initial=timezone.now().date(), +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# reference_number = forms.CharField( +# required=False, +# widget=forms.TextInput(attrs={'class': 'form-control'}) +# ) +# notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# send_receipt = forms.BooleanField( +# required=False, +# initial=True, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = Payment +# fields = [ +# 'bill', 'payment_method', 'payment_source', 'payment_amount', +# 'payment_date', 'reference_number', 'notes', 'send_receipt' +# ] +# widgets = { +# 'bill': forms.Select(attrs={'class': 'form-control'}), +# 'payment_method': forms.Select(attrs={'class': 'form-control'}), +# 'payment_source': forms.Select(attrs={'class': 'form-control'}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# bill = kwargs.pop('bill', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['bill'].queryset = Bill.objects.filter(tenant=tenant) +# self.fields['payment_method'].queryset = PaymentMethod.objects.filter(tenant=tenant) +# +# if bill: +# self.fields['bill'].initial = bill +# self.fields['payment_amount'].initial = bill.balance_due +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Payment Information', +# Row( +# Column('bill', css_class='form-group col-md-6 mb-0'), +# Column('payment_source', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('payment_method', css_class='form-group col-md-6 mb-0'), +# Column('payment_amount', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('payment_date', css_class='form-group col-md-6 mb-0'), +# Column('reference_number', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'notes' +# ), +# Fieldset( +# 'Options', +# HTML('
'), +# 'send_receipt', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Process Payment', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean_payment_amount(self): +# payment_amount = self.cleaned_data.get('payment_amount') +# bill = self.cleaned_data.get('bill') +# +# if payment_amount and bill: +# if payment_amount > bill.balance_due: +# raise ValidationError('Payment amount cannot exceed balance due.') +# if payment_amount <= 0: +# raise ValidationError('Payment amount must be greater than zero.') +# +# return payment_amount +# +# +# class DenialManagementForm(forms.ModelForm): +# """ +# Form for denial management +# """ +# denial_reason = forms.ChoiceField( +# choices=[ +# ('invalid_code', 'Invalid Procedure/Diagnosis Code'), +# ('not_covered', 'Service Not Covered'), +# ('prior_auth', 'Prior Authorization Required'), +# ('duplicate', 'Duplicate Claim'), +# ('incomplete', 'Incomplete Information'), +# ('timely_filing', 'Timely Filing Limit Exceeded'), +# ('other', 'Other') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# appeal_deadline = forms.DateField( +# required=False, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# corrective_action = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}) +# ) +# resubmit_claim = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# file_appeal = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = ClaimDenial +# fields = [ +# 'claim', 'denial_reason', 'denial_description', 'denied_amount', +# 'appeal_deadline', 'corrective_action', 'resubmit_claim', 'file_appeal' +# ] +# widgets = { +# 'claim': forms.Select(attrs={'class': 'form-control'}), +# 'denial_description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), +# 'denied_amount': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['claim'].queryset = InsuranceClaim.objects.filter(tenant=tenant) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Denial Information', +# 'claim', +# Row( +# Column('denial_reason', css_class='form-group col-md-6 mb-0'), +# Column('denied_amount', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'denial_description', +# 'appeal_deadline' +# ), +# Fieldset( +# 'Corrective Actions', +# 'corrective_action', +# HTML('
'), +# 'resubmit_claim', +# HTML(''), +# HTML('
'), +# HTML('
'), +# 'file_appeal', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Process Denial', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class PaymentPlanForm(forms.ModelForm): +# """ +# Form for payment plan setup +# """ +# plan_type = forms.ChoiceField( +# choices=[ +# ('monthly', 'Monthly Payments'), +# ('weekly', 'Weekly Payments'), +# ('biweekly', 'Bi-weekly Payments'), +# ('custom', 'Custom Schedule') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# number_of_payments = forms.IntegerField( +# min_value=2, +# max_value=60, +# widget=forms.NumberInput(attrs={'class': 'form-control'}) +# ) +# payment_amount = forms.DecimalField( +# max_digits=10, +# decimal_places=2, +# widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# ) +# first_payment_date = forms.DateField( +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# auto_payment = forms.BooleanField( +# required=False, +# widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}) +# ) +# +# class Meta: +# model = PaymentPlan +# fields = [ +# 'bill', 'plan_type', 'total_amount', 'number_of_payments', +# 'payment_amount', 'first_payment_date', 'auto_payment' +# ] +# widgets = { +# 'bill': forms.Select(attrs={'class': 'form-control'}), +# 'total_amount': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# } +# +# def __init__(self, *args, **kwargs): +# tenant = kwargs.pop('tenant', None) +# super().__init__(*args, **kwargs) +# +# if tenant: +# self.fields['bill'].queryset = Bill.objects.filter(tenant=tenant, balance_due__gt=0) +# +# # Set minimum date to tomorrow +# tomorrow = timezone.now().date() + timezone.timedelta(days=1) +# self.fields['first_payment_date'].widget.attrs['min'] = tomorrow.isoformat() +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Payment Plan Details', +# 'bill', +# Row( +# Column('plan_type', css_class='form-group col-md-6 mb-0'), +# Column('total_amount', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# Row( +# Column('number_of_payments', css_class='form-group col-md-6 mb-0'), +# Column('payment_amount', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'first_payment_date' +# ), +# Fieldset( +# 'Options', +# HTML('
'), +# 'auto_payment', +# HTML(''), +# HTML('
') +# ), +# FormActions( +# Submit('submit', 'Create Payment Plan', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# def clean(self): +# cleaned_data = super().clean() +# total_amount = cleaned_data.get('total_amount') +# number_of_payments = cleaned_data.get('number_of_payments') +# payment_amount = cleaned_data.get('payment_amount') +# +# if total_amount and number_of_payments and payment_amount: +# calculated_total = payment_amount * number_of_payments +# if abs(calculated_total - total_amount) > Decimal('0.01'): +# raise ValidationError('Payment amount × number of payments must equal total amount.') +# +# return cleaned_data +# +# +# class CollectionsForm(forms.Form): +# """ +# Form for collections management +# """ +# collection_action = forms.ChoiceField( +# choices=[ +# ('letter_1', 'Send First Collection Letter'), +# ('letter_2', 'Send Second Collection Letter'), +# ('letter_3', 'Send Final Collection Letter'), +# ('phone_call', 'Schedule Phone Call'), +# ('external_agency', 'Send to External Agency'), +# ('write_off', 'Write Off Balance') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# collection_notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}) +# ) +# follow_up_date = forms.DateField( +# required=False, +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# write_off_reason = forms.ChoiceField( +# choices=[ +# ('uncollectible', 'Uncollectible'), +# ('patient_deceased', 'Patient Deceased'), +# ('bankruptcy', 'Bankruptcy'), +# ('small_balance', 'Small Balance'), +# ('other', 'Other') +# ], +# required=False, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Collection Action', +# 'collection_action', +# 'collection_notes', +# 'follow_up_date' +# ), +# Fieldset( +# 'Write-off Details', +# 'write_off_reason', +# HTML('Required only for write-off actions') +# ), +# FormActions( +# Submit('submit', 'Execute Collection Action', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class InsuranceVerificationForm(forms.Form): +# """ +# Form for insurance verification +# """ +# verification_type = forms.ChoiceField( +# choices=[ +# ('eligibility', 'Eligibility Verification'), +# ('benefits', 'Benefits Verification'), +# ('authorization', 'Prior Authorization'), +# ('referral', 'Referral Verification') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# service_date = forms.DateField( +# widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}) +# ) +# procedure_codes = forms.CharField( +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# verification_notes = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# Fieldset( +# 'Verification Details', +# Row( +# Column('verification_type', css_class='form-group col-md-6 mb-0'), +# Column('service_date', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'procedure_codes', +# 'verification_notes' +# ), +# FormActions( +# Submit('submit', 'Verify Insurance', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# class BulkBillingForm(forms.Form): +# """ +# Form for bulk billing operations +# """ +# action = forms.ChoiceField( +# choices=[ +# ('submit_claims', 'Submit Claims'), +# ('generate_statements', 'Generate Patient Statements'), +# ('send_reminders', 'Send Payment Reminders'), +# ('update_status', 'Update Status'), +# ('apply_adjustments', 'Apply Adjustments') +# ], +# required=True, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# bill_ids = forms.CharField( +# widget=forms.HiddenInput() +# ) +# new_status = forms.ChoiceField( +# choices=[ +# ('pending', 'Pending'), +# ('submitted', 'Submitted'), +# ('paid', 'Paid'), +# ('denied', 'Denied'), +# ('cancelled', 'Cancelled') +# ], +# required=False, +# widget=forms.Select(attrs={'class': 'form-control'}) +# ) +# adjustment_amount = forms.DecimalField( +# max_digits=10, +# decimal_places=2, +# required=False, +# widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}) +# ) +# adjustment_reason = forms.CharField( +# required=False, +# widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}) +# ) +# +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# +# self.helper = FormHelper() +# self.helper.layout = Layout( +# 'bill_ids', +# Fieldset( +# 'Bulk Operation', +# 'action', +# 'new_status', +# Row( +# Column('adjustment_amount', css_class='form-group col-md-6 mb-0'), +# css_class='form-row' +# ), +# 'adjustment_reason' +# ), +# FormActions( +# Submit('submit', 'Execute Bulk Operation', css_class='btn btn-primary'), +# HTML('Cancel') +# ) +# ) +# +# +# diff --git a/billing/urls.py b/billing/urls.py index a60e0c98..1e5d7bd9 100644 --- a/billing/urls.py +++ b/billing/urls.py @@ -14,6 +14,8 @@ urlpatterns = [ # Medical Bills path('bills/', views.MedicalBillListView.as_view(), name='bill_list'), path('bills//', views.MedicalBillDetailView.as_view(), name='bill_detail'), + path('bills//', views.bill_details_api, name='bill_details_api'), + path('bills//line-items', views.bill_line_items_api, name='bill_line_items_api'), path('bills/create/', views.MedicalBillCreateView.as_view(), name='bill_create'), path('bills//edit/', views.MedicalBillUpdateView.as_view(), name='bill_update'), path('bills//delete/', views.MedicalBillDeleteView.as_view(), name='bill_delete'), @@ -40,14 +42,15 @@ urlpatterns = [ path('bills//payments/create/', views.PaymentCreateView.as_view(), name='bill_payment_create'), # HTMX endpoints - path('htmx/stats/', views.htmx_billing_stats, name='billing_stats'), - path('htmx/bill-search/', views.htmx_bill_search, name='bill_search'), + path('stats/bills/', views.billing_stats, name='billing_stats'), + path('bill-search/', views.bill_search, name='bill_search'), # Action endpoints path('bills//submit/', views.submit_bill, name='submit_bill'), # Export endpoints path('export/bills/', views.export_bills, name='export_bills'), + path('export/claims/', views.export_claims, name='export_claims'), # API endpoints # path('api/', include('billing.api.urls')), diff --git a/billing/views.py b/billing/views.py index 59282afe..f8edfbb2 100644 --- a/billing/views.py +++ b/billing/views.py @@ -393,7 +393,7 @@ class InsuranceClaimDetailView(LoginRequiredMixin, DetailView): claim = self.get_object() # Get related data - context['status_updates'] = claim.claimstatusupdate_set.all().order_by('-update_date') + # context['status_updates'] = claim.claimstatusupdate_set.all().order_by('-update_date') return context @@ -426,8 +426,8 @@ class InsuranceClaimCreateView(LoginRequiredMixin, PermissionRequiredMixin, Crea return kwargs def form_valid(self, form): - # Set medical bill and created_by - bill_id = self.kwargs.get('bill_id') + # Prefer URL bill_id; otherwise read from POST("medical_bill") + bill_id = self.kwargs.get('bill_id') or self.request.POST.get('medical_bill') if bill_id: try: medical_bill = MedicalBill.objects.get( @@ -438,22 +438,25 @@ class InsuranceClaimCreateView(LoginRequiredMixin, PermissionRequiredMixin, Crea except MedicalBill.DoesNotExist: messages.error(self.request, 'Medical bill not found.') return redirect('billing:bill_list') - + else: + messages.error(self.request, 'Please select a medical bill.') + return redirect('billing:claim_create') + form.instance.created_by = self.request.user - - # Generate claim number + if not form.instance.claim_number: form.instance.claim_number = form.instance.generate_claim_number() - + response = super().form_valid(form) - - messages.success( - self.request, - f'Insurance claim {self.object.claim_number} created successfully.' - ) - + messages.success(self.request, f'Insurance claim {self.object.claim_number} created successfully.') return response - + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + tenant = getattr(self.request, 'tenant', None) + ctx['available_bills'] = MedicalBill.objects.filter(tenant=tenant).select_related('patient') + return ctx + def get_success_url(self): return reverse('billing:claim_detail', kwargs={'claim_id': self.object.claim_id}) @@ -631,7 +634,7 @@ class PaymentCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView) # return JsonResponse(stats) @login_required -def htmx_billing_stats(request): +def billing_stats(request): """ HTMX view for billing statistics. """ @@ -690,7 +693,30 @@ def htmx_billing_stats(request): @login_required -def htmx_bill_search(request): +def bill_details_api(request, bill_id): + tenant = getattr(request, 'tenant', None) + if not tenant: + return JsonResponse({'error': 'No tenant found'}, status=400) + + bill = get_object_or_404( + MedicalBill.objects.select_related('patient', 'billing_provider'), + bill_id=bill_id, + tenant=tenant, + ) + + data = { + 'patient_name': bill.patient.get_full_name() if bill.patient else '', + 'bill_number': bill.bill_number or '', + 'bill_date': bill.bill_date.isoformat() if bill.bill_date else '', + 'total_amount': str(bill.total_amount or 0), + 'service_date_from': bill.service_date_from.isoformat() if bill.service_date_from else '', + 'service_date_to': bill.service_date_to.isoformat() if bill.service_date_to else '', + 'billing_provider': bill.billing_provider.get_full_name() if bill.billing_provider else '', + } + return JsonResponse(data) + +@login_required +def bill_search(request): """ HTMX endpoint for bill search. """ @@ -1391,6 +1417,145 @@ def payment_download(request, payment_id): messages.error(request, f'Error generating PDF: {str(e)}') return redirect('billing:payment_receipt', payment_id=payment_id) + +@login_required +def export_claims(request): + """ + Export insurance claims to CSV. + Supports optional filtering by 'claims' GET param: ?claims=ID1,ID2,ID3 + """ + tenant = getattr(request, 'tenant', None) + if not tenant: + return HttpResponse('No tenant found', status=400) + + # Base queryset + qs = InsuranceClaim.objects.filter(tenant=tenant).select_related( + 'medical_bill__patient', + 'insurance_info', + ) + + # Optional selection filter (comma-separated claim_ids) + selected = request.GET.get('claims') + if selected: + claim_ids = [c.strip() for c in selected.split(',') if c.strip()] + if claim_ids: + qs = qs.filter(claim_id__in=claim_ids) + + # Prepare CSV response + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="insurance_claims.csv"' + + writer = csv.writer(response) + writer.writerow([ + 'Claim Number', + 'Bill Number', + 'Patient Name', + 'Insurance Company', + 'Claim Type', + 'Service From', + 'Service To', + 'Billed Amount', + 'Status', + ]) + + for claim in qs: + bill = getattr(claim, 'medical_bill', None) + patient = getattr(bill, 'patient', None) + + # Safely get nice display values + insurance_company = getattr(getattr(claim, 'insurance_info', None), 'company', None) + if not insurance_company: + # Fallback to __str__ of insurance_info or empty + insurance_company = str(getattr(claim, 'insurance_info', '')) or '' + + claim_type = getattr(claim, 'get_claim_type_display', None) + if callable(claim_type): + claim_type = claim.get_claim_type_display() + else: + claim_type = getattr(claim, 'claim_type', '') or '' + + status_val = '' + get_status_display = getattr(claim, 'get_status_display', None) + if callable(get_status_display): + status_val = claim.get_status_display() + else: + # Fallback if no choices helper exists + status_val = getattr(claim, 'status', '') or '' + + writer.writerow([ + getattr(claim, 'claim_number', '') or '', + getattr(bill, 'bill_number', '') if bill else '', + patient.get_full_name() if patient else '', + insurance_company, + claim_type, + claim.service_date_from.strftime('%Y-%m-%d') if getattr(claim, 'service_date_from', None) else '', + claim.service_date_to.strftime('%Y-%m-%d') if getattr(claim, 'service_date_to', None) else '', + str(getattr(claim, 'billed_amount', '')) or '0', + status_val, + ]) + + return response + + +@login_required +def bill_line_items_api(request, bill_id=None): + """ + Return line items for a medical bill as JSON. + Supports: + - /api/bills//line-items/ + - /api/bills/line-items/?bill_id= + """ + tenant = getattr(request, 'tenant', None) + if not tenant: + return JsonResponse({'success': False, 'error': 'No tenant found'}, status=400) + + bill_id = bill_id or request.GET.get('bill_id') + if not bill_id: + return JsonResponse({'success': False, 'error': 'bill_id is required'}, status=400) + + bill = get_object_or_404( + MedicalBill.objects.select_related('patient').prefetch_related('billlineitem_set'), + bill_id=bill_id, + tenant=tenant, + ) + + # Prefer per-item service date if your model has it; otherwise fall back + bill_service_date = ( + bill.service_date_from.isoformat() if getattr(bill, 'service_date_from', None) + else bill.bill_date.isoformat() if getattr(bill, 'bill_date', None) + else '' + ) + + items = [] + for li in bill.billlineitem_set.all(): + qty = getattr(li, 'quantity', 0) or 0 + price = getattr(li, 'unit_price', Decimal('0')) or Decimal('0') + # If your BillLineItem has service_date, use it; otherwise default + li_service_date = getattr(li, 'service_date', None) + if li_service_date: + li_service_date = li_service_date.isoformat() + else: + li_service_date = bill_service_date + + items.append({ + 'id': getattr(li, 'id', None), + 'service_code': getattr(li, 'service_code', '') or '', + 'description': getattr(li, 'description', '') or '', + 'quantity': qty, + 'unit_price': str(price), + 'service_date': li_service_date, + 'total': str(price * Decimal(qty)), + }) + + return JsonResponse({ + 'success': True, + 'bill_id': str(bill.bill_id), + 'patient_name': bill.patient.get_full_name() if bill.patient else '', + 'line_items': items, + }) + + + # # # """ @@ -2159,3 +2324,503 @@ payment_list = PaymentListView.as_view() # # # +# from django.shortcuts import render, redirect, get_object_or_404 +# from django.contrib.auth.decorators import login_required, permission_required +# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin +# from django.contrib import messages +# from django.views.generic import ( +# CreateView, UpdateView, DeleteView, DetailView, ListView, FormView +# ) +# from django.urls import reverse_lazy, reverse +# from django.http import JsonResponse, HttpResponse +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# from django.conf import settings +# from django.db.models import Q, Sum, Count +# from viewflow.views import CreateProcessView, UpdateProcessView +# from decimal import Decimal +# import json +# +# from .models import ( +# Bill, BillItem, InsuranceClaim, Payment, PaymentMethod, +# InsuranceProvider, ClaimDenial, PaymentPlan +# ) +# from .forms import ( +# MedicalBillingForm, BillItemForm, InsuranceClaimForm, PaymentProcessingForm, +# DenialManagementForm, PaymentPlanForm, CollectionsForm, +# InsuranceVerificationForm, BulkBillingForm +# ) +# from .flows import MedicalBillingFlow, InsuranceClaimFlow, PaymentProcessingFlow, DenialManagementFlow, CollectionsFlow +# from patients.models import Patient +# +# +# class MedicalBillingView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for medical billing workflow +# """ +# model = Bill +# form_class = MedicalBillingForm +# template_name = 'billing/medical_billing.html' +# permission_required = 'billing.can_create_bills' +# flow_class = MedicalBillingFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create bill +# bill = form.save(commit=False) +# bill.tenant = self.request.user.tenant +# bill.created_by = self.request.user +# bill.status = 'draft' +# bill.save() +# +# # Start medical billing workflow +# process = self.flow_class.start.run( +# bill=bill, +# insurance_verification=form.cleaned_data.get('insurance_verification', True), +# auto_submit_primary=form.cleaned_data.get('auto_submit_primary', True), +# auto_submit_secondary=form.cleaned_data.get('auto_submit_secondary', False), +# generate_patient_statement=form.cleaned_data.get('generate_patient_statement', True), +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Medical bill created successfully for {bill.patient.get_full_name()}. ' +# f'Billing workflow initiated.' +# ) +# +# return redirect('billing:bill_detail', pk=bill.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Create Medical Bill' +# context['breadcrumbs'] = [ +# {'name': 'Home', 'url': reverse('core:dashboard')}, +# {'name': 'Billing', 'url': reverse('billing:dashboard')}, +# {'name': 'Bills', 'url': reverse('billing:bill_list')}, +# {'name': 'Create Bill', 'url': ''} +# ] +# return context +# +# +# class BillItemView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): +# """ +# View for bill item creation/editing +# """ +# model = BillItem +# form_class = BillItemForm +# template_name = 'billing/bill_item_form.html' +# permission_required = 'billing.can_edit_bill_items' +# +# def get_success_url(self): +# return reverse('billing:bill_detail', kwargs={'pk': self.kwargs['bill_id']}) +# +# def form_valid(self, form): +# bill = get_object_or_404(Bill, pk=self.kwargs['bill_id']) +# +# with transaction.atomic(): +# # Create bill item +# item = form.save(commit=False) +# item.bill = bill +# item.tenant = bill.tenant +# item.save() +# +# # Recalculate bill totals +# self.recalculate_bill_totals(bill) +# +# messages.success( +# self.request, +# f'Bill item "{item.description}" added successfully.' +# ) +# +# return super().form_valid(form) +# +# def recalculate_bill_totals(self, bill): +# """Recalculate bill totals""" +# items = bill.items.all() +# subtotal = sum(item.total_amount for item in items) +# +# bill.subtotal = subtotal +# bill.total_amount = subtotal + bill.tax_amount +# bill.balance_due = bill.total_amount - bill.paid_amount +# bill.save() +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['bill'] = get_object_or_404(Bill, pk=self.kwargs['bill_id']) +# context['title'] = 'Add Bill Item' +# return context +# +# +# class InsuranceClaimView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for insurance claim submission workflow +# """ +# model = InsuranceClaim +# form_class = InsuranceClaimForm +# template_name = 'billing/insurance_claim.html' +# permission_required = 'billing.can_submit_claims' +# flow_class = InsuranceClaimFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create insurance claim +# claim = form.save(commit=False) +# claim.tenant = self.request.user.tenant +# claim.submitted_by = self.request.user +# claim.status = 'pending' +# claim.save() +# +# # Start insurance claim workflow +# process = self.flow_class.start.run( +# claim=claim, +# submit_electronically=form.cleaned_data.get('submit_electronically', True), +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Insurance claim submitted successfully. Claim ID: {claim.claim_number}' +# ) +# +# return redirect('billing:claim_detail', pk=claim.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Submit Insurance Claim' +# context['breadcrumbs'] = [ +# {'name': 'Home', 'url': reverse('core:dashboard')}, +# {'name': 'Billing', 'url': reverse('billing:dashboard')}, +# {'name': 'Claims', 'url': reverse('billing:claim_list')}, +# {'name': 'Submit Claim', 'url': ''} +# ] +# return context +# +# +# class PaymentProcessingView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for payment processing workflow +# """ +# model = Payment +# form_class = PaymentProcessingForm +# template_name = 'billing/payment_processing.html' +# permission_required = 'billing.can_process_payments' +# flow_class = PaymentProcessingFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# +# # Pre-populate bill if provided +# bill_id = self.kwargs.get('bill_id') +# if bill_id: +# kwargs['bill'] = get_object_or_404(Bill, pk=bill_id) +# +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create payment +# payment = form.save(commit=False) +# payment.tenant = self.request.user.tenant +# payment.processed_by = self.request.user +# payment.status = 'pending' +# payment.save() +# +# # Update bill balance +# bill = payment.bill +# bill.paid_amount += payment.payment_amount +# bill.balance_due = bill.total_amount - bill.paid_amount +# +# if bill.balance_due <= 0: +# bill.status = 'paid' +# else: +# bill.status = 'partial_payment' +# +# bill.save() +# +# # Start payment processing workflow +# process = self.flow_class.start.run( +# payment=payment, +# send_receipt=form.cleaned_data.get('send_receipt', True), +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Payment of ${payment.payment_amount} processed successfully. ' +# f'Remaining balance: ${bill.balance_due}' +# ) +# +# return redirect('billing:payment_detail', pk=payment.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Process Payment' +# +# bill_id = self.kwargs.get('bill_id') +# if bill_id: +# context['bill'] = get_object_or_404(Bill, pk=bill_id) +# +# return context +# +# +# class DenialManagementView(LoginRequiredMixin, PermissionRequiredMixin, CreateProcessView): +# """ +# View for denial management workflow +# """ +# model = ClaimDenial +# form_class = DenialManagementForm +# template_name = 'billing/denial_management.html' +# permission_required = 'billing.can_manage_denials' +# flow_class = DenialManagementFlow +# +# def get_form_kwargs(self): +# kwargs = super().get_form_kwargs() +# kwargs['tenant'] = self.request.user.tenant +# return kwargs +# +# def form_valid(self, form): +# with transaction.atomic(): +# # Create denial record +# denial = form.save(commit=False) +# denial.tenant = self.request.user.tenant +# denial.processed_by = self.request.user +# denial.save() +# +# # Update claim status +# claim = denial.claim +# claim.status = 'denied' +# claim.save() +# +# # Start denial management workflow +# process = self.flow_class.start.run( +# denial=denial, +# resubmit_claim=form.cleaned_data.get('resubmit_claim', False), +# file_appeal=form.cleaned_data.get('file_appeal', False), +# created_by=self.request.user +# ) +# +# messages.success( +# self.request, +# f'Denial processed for claim {claim.claim_number}. ' +# f'Workflow initiated for corrective actions.' +# ) +# +# return redirect('billing:denial_detail', pk=denial.pk) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Manage Claim Denial' +# return context +# +# +# class BillListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): +# """ +# View for listing bills +# """ +# model = Bill +# template_name = 'billing/bill_list.html' +# context_object_name = 'bills' +# permission_required = 'billing.view_bill' +# paginate_by = 25 +# +# def get_queryset(self): +# queryset = Bill.objects.filter(tenant=self.request.user.tenant) +# +# # Apply filters +# search = self.request.GET.get('search') +# if search: +# queryset = queryset.filter( +# Q(patient__first_name__icontains=search) | +# Q(patient__last_name__icontains=search) | +# Q(bill_number__icontains=search) +# ) +# +# status = self.request.GET.get('status') +# if status: +# queryset = queryset.filter(status=status) +# +# date_from = self.request.GET.get('date_from') +# if date_from: +# queryset = queryset.filter(service_date__gte=date_from) +# +# date_to = self.request.GET.get('date_to') +# if date_to: +# queryset = queryset.filter(service_date__lte=date_to) +# +# return queryset.order_by('-created_at') +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# context['title'] = 'Bills' +# context['search'] = self.request.GET.get('search', '') +# context['selected_status'] = self.request.GET.get('status', '') +# context['date_from'] = self.request.GET.get('date_from', '') +# context['date_to'] = self.request.GET.get('date_to', '') +# context['billing_stats'] = self.get_billing_stats() +# return context +# +# def get_billing_stats(self): +# """Get billing statistics""" +# bills = Bill.objects.filter(tenant=self.request.user.tenant) +# return { +# 'total_bills': bills.count(), +# 'total_amount': bills.aggregate(Sum('total_amount'))['total_amount__sum'] or 0, +# 'total_paid': bills.aggregate(Sum('paid_amount'))['paid_amount__sum'] or 0, +# 'total_outstanding': bills.aggregate(Sum('balance_due'))['balance_due__sum'] or 0 +# } +# +# +# class BillDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): +# """ +# View for bill details +# """ +# model = Bill +# template_name = 'billing/bill_detail.html' +# context_object_name = 'bill' +# permission_required = 'billing.view_bill' +# +# def get_queryset(self): +# return Bill.objects.filter(tenant=self.request.user.tenant) +# +# def get_context_data(self, **kwargs): +# context = super().get_context_data(**kwargs) +# bill = self.object +# context['title'] = f'Bill {bill.bill_number}' +# context['items'] = bill.items.all() +# context['claims'] = bill.claims.all() +# context['payments'] = bill.payments.all() +# context['payment_plan'] = getattr(bill, 'payment_plan', None) +# context['can_edit'] = self.request.user.has_perm('billing.change_bill') +# context['can_process_payment'] = self.request.user.has_perm('billing.can_process_payments') +# return context +# +# +# # AJAX Views +# @login_required +# @permission_required('billing.view_patient') +# def patient_billing_search_ajax(request): +# """AJAX view for patient billing search""" +# query = request.GET.get('q', '') +# if len(query) < 2: +# return JsonResponse({'patients': []}) +# +# patients = Patient.objects.filter( +# tenant=request.user.tenant +# ).filter( +# Q(first_name__icontains=query) | +# Q(last_name__icontains=query) | +# Q(patient_id__icontains=query) | +# Q(insurance_id__icontains=query) +# )[:10] +# +# patient_data = [ +# { +# 'id': patient.id, +# 'name': patient.get_full_name(), +# 'patient_id': patient.patient_id, +# 'insurance': patient.primary_insurance.name if patient.primary_insurance else 'No Insurance', +# 'outstanding_balance': str(patient.get_outstanding_balance()) +# } +# for patient in patients +# ] +# +# return JsonResponse({'patients': patient_data}) +# +# +# @login_required +# @permission_required('billing.can_calculate_totals') +# def calculate_bill_totals_ajax(request): +# """AJAX view to calculate bill totals""" +# if request.method == 'POST': +# try: +# data = json.loads(request.body) +# items = data.get('items', []) +# +# subtotal = Decimal('0.00') +# for item in items: +# quantity = Decimal(str(item.get('quantity', 1))) +# unit_price = Decimal(str(item.get('unit_price', 0))) +# discount = Decimal(str(item.get('discount', 0))) +# +# item_total = (quantity * unit_price) - discount +# subtotal += item_total +# +# tax_rate = Decimal('0.08') # 8% tax rate (configurable) +# tax_amount = subtotal * tax_rate +# total_amount = subtotal + tax_amount +# +# return JsonResponse({ +# 'success': True, +# 'subtotal': str(subtotal), +# 'tax_amount': str(tax_amount), +# 'total_amount': str(total_amount) +# }) +# except Exception as e: +# return JsonResponse({ +# 'success': False, +# 'error': str(e) +# }) +# +# return JsonResponse({'success': False, 'message': 'Invalid request.'}) +# +# +# @login_required +# @permission_required('billing.can_verify_insurance') +# def verify_insurance_ajax(request, patient_id): +# """AJAX view to verify insurance""" +# if request.method == 'POST': +# try: +# patient = Patient.objects.get( +# id=patient_id, +# tenant=request.user.tenant +# ) +# +# # Perform insurance verification +# verification_result = verify_patient_insurance(patient) +# +# return JsonResponse({ +# 'success': verification_result['success'], +# 'data': verification_result +# }) +# except Patient.DoesNotExist: +# return JsonResponse({ +# 'success': False, +# 'message': 'Patient not found.' +# }) +# +# return JsonResponse({'success': False, 'message': 'Invalid request.'}) +# +# +# def verify_patient_insurance(patient): +# """Verify patient insurance""" +# try: +# # This would implement actual insurance verification +# return { +# 'success': True, +# 'status': 'active', +# 'coverage': 'full', +# 'copay': 25.00, +# 'deductible': 500.00, +# 'deductible_met': 150.00, +# 'out_of_pocket_max': 2000.00, +# 'out_of_pocket_met': 300.00 +# } +# except Exception as e: +# return { +# 'success': False, +# 'error': str(e) +# } +# diff --git a/blood_bank/__pycache__/forms.cpython-312.pyc b/blood_bank/__pycache__/forms.cpython-312.pyc index 9283a135..7690112b 100644 Binary files a/blood_bank/__pycache__/forms.cpython-312.pyc and b/blood_bank/__pycache__/forms.cpython-312.pyc differ diff --git a/blood_bank/__pycache__/models.cpython-312.pyc b/blood_bank/__pycache__/models.cpython-312.pyc index 1adafb18..6daed658 100644 Binary files a/blood_bank/__pycache__/models.cpython-312.pyc and b/blood_bank/__pycache__/models.cpython-312.pyc differ diff --git a/blood_bank/__pycache__/urls.cpython-312.pyc b/blood_bank/__pycache__/urls.cpython-312.pyc index 0d2a88b5..78ba56aa 100644 Binary files a/blood_bank/__pycache__/urls.cpython-312.pyc and b/blood_bank/__pycache__/urls.cpython-312.pyc differ diff --git a/blood_bank/__pycache__/views.cpython-312.pyc b/blood_bank/__pycache__/views.cpython-312.pyc index 6ce82638..c8323144 100644 Binary files a/blood_bank/__pycache__/views.cpython-312.pyc and b/blood_bank/__pycache__/views.cpython-312.pyc differ diff --git a/blood_bank/models.py b/blood_bank/models.py index bc0abfc0..9081ba94 100644 --- a/blood_bank/models.py +++ b/blood_bank/models.py @@ -3,7 +3,7 @@ from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator from django.utils import timezone from datetime import timedelta -from core.models import Department +from hr.models import Department from patients.models import PatientProfile from accounts.models import User diff --git a/blood_bank/urls.py b/blood_bank/urls.py index 98fa7f5f..fa45fd9e 100644 --- a/blood_bank/urls.py +++ b/blood_bank/urls.py @@ -9,25 +9,25 @@ urlpatterns = [ # Donor Management path('donors/', views.DonorListView.as_view(), name='donor_list'), - path('donors//', views.donor_detail, name='donor_detail'), - path('donors/create/', views.donor_create, name='donor_create'), - path('donors//update/', views.donor_update, name='donor_update'), + path('donors//', views.DonorDetailView.as_view(), name='donor_detail'), + path('donors/create/', views.DonorCreateView.as_view(), name='donor_create'), + path('donors//update/', views.DonorUpdateView.as_view(), name='donor_update'), path('donors//eligibility/', views.donor_eligibility_check, name='donor_eligibility'), # Blood Unit Management - path('units/', views.blood_unit_list, name='blood_unit_list'), - path('units//', views.blood_unit_detail, name='blood_unit_detail'), - path('units/create/', views.blood_unit_create, name='blood_unit_create'), - path('units/create//', views.blood_unit_create, name='blood_unit_create_for_donor'), + path('units/', views.BloodUnitListView.as_view(), name='blood_unit_list'), + path('units//', views.BloodUnitDetailView.as_view(), name='blood_unit_detail'), + path('units/create/', views.BloodUnitCreateView.as_view(), name='blood_unit_create'), + path('units/create//', views.BloodUnitCreateView.as_view(), name='blood_unit_create_for_donor'), # Blood Testing path('units//test/', views.blood_test_create, name='blood_test_create'), path('units//crossmatch//', views.crossmatch_create, name='crossmatch_create'), # Blood Requests - path('requests/', views.blood_request_list, name='blood_request_list'), - path('requests//', views.blood_request_detail, name='blood_request_detail'), - path('requests/create/', views.blood_request_create, name='blood_request_create'), + path('requests/', views.BloodRequestListView.as_view(), name='blood_request_list'), + path('requests//', views.BloodRequestDetailView.as_view(), name='blood_request_detail'), + path('requests/create/', views.BloodRequestCreateView.as_view(), name='blood_request_create'), # Blood Issue and Transfusion path('requests//issue/', views.blood_issue_create, name='blood_issue_create'), diff --git a/blood_bank/views.py b/blood_bank/views.py index d40f1ba9..3303210e 100644 --- a/blood_bank/views.py +++ b/blood_bank/views.py @@ -1,4 +1,4 @@ -from django.contrib.auth.mixins import LoginRequiredMixin +from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required, permission_required from django.contrib import messages @@ -11,7 +11,7 @@ from django.contrib.auth.models import User from datetime import timedelta import json -from django.views.generic import ListView +from django.views.generic import ListView, CreateView, DetailView, DeleteView, UpdateView from .models import ( BloodGroup, Donor, BloodComponent, BloodUnit, BloodTest, CrossMatch, @@ -52,9 +52,7 @@ def dashboard(request): context['blood_group_stats'] = blood_group_stats # Recent activities - context['recent_units'] = BloodUnit.objects.select_related( - 'donor', 'component', 'blood_group' - ).order_by('-collection_date')[:10] + context['recent_units'] = BloodUnit.objects.select_related('donor', 'component', 'blood_group').order_by('-collection_date') context['urgent_requests'] = BloodRequest.objects.filter( urgency='emergency', status__in=['pending', 'processing'] @@ -110,62 +108,65 @@ class DonorListView(LoginRequiredMixin, ListView): -@login_required -def donor_detail(request, donor_id): - """Donor detail view with donation history""" - donor = get_object_or_404(Donor, id=donor_id) +class DonorDetailView(LoginRequiredMixin, DetailView): + model = Donor + template_name = 'blood_bank/donors/donor_detail.html' + context_object_name = 'donor' + pk_url_kwarg = 'donor_id' - # Get donation history - blood_units = BloodUnit.objects.filter(donor=donor).select_related( - 'component', 'blood_group' - ).order_by('-collection_date') - - context = { - 'donor': donor, - 'blood_units': blood_units, - 'total_donations': blood_units.count(), - 'last_donation': blood_units.first(), - } - - return render(request, 'blood_bank/donors/donor_detail.html', context) + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + donor = self.object + blood_units = ( + BloodUnit.objects + .filter(donor=donor) + .select_related('component', 'blood_group') + .order_by('-collection_date') + ) + ctx.update({ + 'blood_units': blood_units, + 'total_donations': blood_units.count(), + 'last_donation': blood_units.first(), + }) + return ctx -@login_required -@permission_required('blood_bank.add_donor') -def donor_create(request): - """Create new donor""" - if request.method == 'POST': - form = DonorForm(request.POST) - if form.is_valid(): - donor = form.save(commit=False) - donor.created_by = request.user - donor.save() - messages.success(request, f'Donor {donor.donor_id} created successfully.') - return redirect('blood_bank:donor_detail', donor_id=donor.id) - else: - form = DonorForm() +class DonorCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): + model = Donor + form_class = DonorForm + template_name = 'blood_bank/donors/donor_form.html' + permission_required = 'blood_bank.add_donor' - return render(request, 'blood_bank/donors/donor_form.html', {'form': form, 'title': 'Add New Donor'}) + def form_valid(self, form): + donor = form.save(commit=False) + donor.created_by = self.request.user + donor.save() + messages.success(self.request, f'Donor {donor.donor_id} created successfully.') + return redirect('blood_bank:donor_detail', donor_id=donor.id) + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + ctx['title'] = 'Add New Donor' + return ctx -@login_required -@permission_required('blood_bank.change_donor') -def donor_update(request, donor_id): - """Update donor information""" - donor = get_object_or_404(Donor, id=donor_id) +class DonorUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): + model = Donor + form_class = DonorForm + template_name = 'blood_bank/donors/donor_form.html' + permission_required = 'blood_bank.change_donor' + pk_url_kwarg = 'donor_id' + context_object_name = 'donor' - if request.method == 'POST': - form = DonorForm(request.POST, instance=donor) - if form.is_valid(): - form.save() - messages.success(request, f'Donor {donor.donor_id} updated successfully.') - return redirect('blood_bank:donor_detail', donor_id=donor.id) - else: - form = DonorForm(instance=donor) + def form_valid(self, form): + donor = form.save() + messages.success(self.request, f'Donor {donor.donor_id} updated successfully.') + return redirect('blood_bank:donor_detail', donor_id=donor.id) - return render(request, 'blood_bank/donors/donor_form.html', { - 'form': form, 'donor': donor, 'title': 'Update Donor' - }) + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + ctx['title'] = 'Update Donor' + return ctx @login_required @@ -192,167 +193,163 @@ def donor_eligibility_check(request, donor_id): return render(request, 'blood_bank/donors/donor_eligibility.html', context) -# Blood Unit Management Views -@login_required -def blood_unit_list(request): - """List all blood units with filtering""" - form = BloodInventorySearchForm(request.GET) - blood_units = BloodUnit.objects.select_related( - 'donor', 'component', 'blood_group' - ).order_by('-collection_date') +class BloodUnitListView(LoginRequiredMixin, ListView): + model = BloodUnit + template_name = 'blood_bank/units/blood_unit_list.html' + context_object_name = 'blood_units' # you'll still get page_obj automatically + paginate_by = 25 - if form.is_valid(): - if form.cleaned_data['blood_group']: - blood_units = blood_units.filter(blood_group=form.cleaned_data['blood_group']) + def get_queryset(self): + # base queryset + qs = BloodUnit.objects.select_related('donor', 'component', 'blood_group') \ + .order_by('-collection_date') - if form.cleaned_data['component']: - blood_units = blood_units.filter(component=form.cleaned_data['component']) + # bind/validate the filter form + self.form = BloodInventorySearchForm(self.request.GET) + if self.form.is_valid(): + cd = self.form.cleaned_data - if form.cleaned_data['status']: - blood_units = blood_units.filter(status=form.cleaned_data['status']) + if cd.get('blood_group'): + qs = qs.filter(blood_group=cd['blood_group']) - if form.cleaned_data['expiry_days']: - expiry_date = timezone.now() + timedelta(days=form.cleaned_data['expiry_days']) - blood_units = blood_units.filter(expiry_date__lte=expiry_date) + if cd.get('component'): + qs = qs.filter(component=cd['component']) - paginator = Paginator(blood_units, 25) - page_number = request.GET.get('page') - page_obj = paginator.get_page(page_number) + if cd.get('status'): + qs = qs.filter(status=cd['status']) - context = { - 'page_obj': page_obj, - 'form': form, - } + if cd.get('expiry_days') is not None: + expiry_date = timezone.now() + timedelta(days=cd['expiry_days']) + qs = qs.filter(expiry_date__lte=expiry_date) - return render(request, 'blood_bank/units/blood_unit_list.html', context) + return qs + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + # expose the (bound) form to the template + ctx['form'] = getattr(self, 'form', BloodInventorySearchForm(self.request.GET)) + return ctx -@login_required -def blood_unit_detail(request, unit_id): - """Blood unit detail view with test results""" - blood_unit = get_object_or_404(BloodUnit, id=unit_id) +class BloodUnitDetailView(LoginRequiredMixin, DetailView): + model = BloodUnit + template_name = 'blood_bank/units/blood_unit_detail.html' + context_object_name = 'blood_unit' + pk_url_kwarg = 'unit_id' - # Get test results - tests = BloodTest.objects.filter(blood_unit=blood_unit).select_related('tested_by') - crossmatches = CrossMatch.objects.filter(blood_unit=blood_unit).select_related( - 'recipient', 'tested_by' - ) + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + blood_unit = self.object - context = { - 'blood_unit': blood_unit, - 'tests': tests, - 'crossmatches': crossmatches, - } - - return render(request, 'blood_bank/units/blood_unit_detail.html', context) + # related objects + ctx['tests'] = BloodTest.objects.filter(blood_unit=blood_unit) \ + .select_related('tested_by') + ctx['crossmatches'] = CrossMatch.objects.filter(blood_unit=blood_unit) \ + .select_related('recipient', 'tested_by') + return ctx -@login_required -@permission_required('blood_bank.add_bloodunit') -def blood_unit_create(request, donor_id=None): - """Create new blood unit""" - donor = None - if donor_id: - donor = get_object_or_404(Donor, id=donor_id) +class BloodUnitCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): + model = BloodUnit + form_class = BloodUnitForm + template_name = 'blood_bank/units/blood_unit_form.html' + permission_required = 'blood_bank.add_bloodunit' - if request.method == 'POST': - form = BloodUnitForm(request.POST) - if form.is_valid(): - blood_unit = form.save(commit=False) - blood_unit.collected_by = request.user - blood_unit.save() + def get_initial(self): + initial = super().get_initial() + donor_id = self.kwargs.get('donor_id') + if donor_id: + donor = get_object_or_404(Donor, id=donor_id) + initial['donor'] = donor + initial['blood_group'] = donor.blood_group + self.donor = donor # store for use in context + return initial - # Update donor's last donation date and total donations - if blood_unit.donor: - blood_unit.donor.last_donation_date = blood_unit.collection_date - blood_unit.donor.total_donations += 1 - blood_unit.donor.save() + def form_valid(self, form): + blood_unit = form.save(commit=False) + blood_unit.collected_by = self.request.user + blood_unit.save() - messages.success(request, f'Blood unit {blood_unit.unit_number} created successfully.') - return redirect('blood_bank:blood_unit_detail', unit_id=blood_unit.id) - else: - initial_data = {} - if donor: - initial_data['donor'] = donor - initial_data['blood_group'] = donor.blood_group - form = BloodUnitForm(initial=initial_data) + # Update donor’s donation stats + if blood_unit.donor: + blood_unit.donor.last_donation_date = blood_unit.collection_date + blood_unit.donor.total_donations += 1 + blood_unit.donor.save() - return render(request, 'blood_bank/units/blood_unit_form.html', { - 'form': form, 'donor': donor, 'title': 'Register Blood Unit' - }) + messages.success(self.request, f'Blood unit {blood_unit.unit_number} created successfully.') + return redirect('blood_bank:blood_unit_detail', unit_id=blood_unit.id) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['donor'] = getattr(self, 'donor', None) + context['title'] = 'Register Blood Unit' + return context -# Blood Request Management Views -@login_required -def blood_request_list(request): - """List all blood requests""" - requests = BloodRequest.objects.select_related( - 'patient', 'requesting_department', 'requesting_physician', 'component_requested' - ).order_by('-request_date') +class BloodRequestListView(LoginRequiredMixin, ListView): + model = BloodRequest + template_name = 'blood_bank/requests/blood_request_list.html' + context_object_name = 'page_obj' + paginate_by = 25 - # Filter by status - status_filter = request.GET.get('status') - if status_filter: - requests = requests.filter(status=status_filter) + def get_queryset(self): + qs = BloodRequest.objects.select_related( + 'patient', 'requesting_department', 'requesting_physician', 'component_requested' + ).order_by('-request_date') - # Filter by urgency - urgency_filter = request.GET.get('urgency') - if urgency_filter: - requests = requests.filter(urgency=urgency_filter) + status_filter = self.request.GET.get('status') + urgency_filter = self.request.GET.get('urgency') - paginator = Paginator(requests, 25) - page_number = request.GET.get('page') - page_obj = paginator.get_page(page_number) + if status_filter: + qs = qs.filter(status=status_filter) + if urgency_filter: + qs = qs.filter(urgency=urgency_filter) - context = { - 'page_obj': page_obj, - 'status_choices': BloodRequest.STATUS_CHOICES, - 'urgency_choices': BloodRequest.URGENCY_CHOICES, - 'status_filter': status_filter, - 'urgency_filter': urgency_filter, - } + return qs - return render(request, 'blood_bank/requests/blood_request_list.html', context) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['status_choices'] = BloodRequest.STATUS_CHOICES + context['urgency_choices'] = BloodRequest.URGENCY_CHOICES + context['status_filter'] = self.request.GET.get('status') + context['urgency_filter'] = self.request.GET.get('urgency') + return context -@login_required -def blood_request_detail(request, request_id): - """Blood request detail view""" - blood_request = get_object_or_404(BloodRequest, id=request_id) +class BloodRequestDetailView(LoginRequiredMixin, DetailView): + model = BloodRequest + pk_url_kwarg = 'request_id' + template_name = 'blood_bank/requests/blood_request_detail.html' + context_object_name = 'blood_request' - # Get issued units for this request - issues = BloodIssue.objects.filter(blood_request=blood_request).select_related( - 'blood_unit', 'issued_by', 'issued_to' - ) - - context = { - 'blood_request': blood_request, - 'issues': issues, - } - - return render(request, 'blood_bank/requests/blood_request_detail.html', context) + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['issues'] = BloodIssue.objects.filter( + blood_request=self.object + ).select_related('blood_unit', 'issued_by', 'issued_to') + return context -@login_required -@permission_required('blood_bank.add_bloodrequest') -def blood_request_create(request): - """Create new blood request""" - if request.method == 'POST': - form = BloodRequestForm(request.POST) - if form.is_valid(): - blood_request = form.save(commit=False) - blood_request.requesting_physician = request.user - # Generate request number - blood_request.request_number = f"BR{timezone.now().strftime('%Y%m%d')}{BloodRequest.objects.count() + 1:04d}" - blood_request.save() - messages.success(request, f'Blood request {blood_request.request_number} created successfully.') - return redirect('blood_bank:blood_request_detail', request_id=blood_request.id) - else: - form = BloodRequestForm() +class BloodRequestCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): + model = BloodRequest + form_class = BloodRequestForm + template_name = 'blood_bank/requests/blood_request_form.html' + permission_required = 'blood_bank.add_bloodrequest' - return render(request, 'blood_bank/requests/blood_request_form.html', { - 'form': form, 'title': 'Create Blood Request' - }) + def form_valid(self, form): + blood_request = form.save(commit=False) + blood_request.requesting_physician = self.request.user + # Generate request number + blood_request.request_number = f"BR{timezone.now().strftime('%Y%m%d')}{BloodRequest.objects.count() + 1:04d}" + blood_request.save() + + messages.success(self.request, f'Blood request {blood_request.request_number} created successfully.') + return redirect('blood_bank:blood_request_detail', request_id=blood_request.id) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = 'Create Blood Request' + return context # Blood Issue and Transfusion Views diff --git a/communications/__pycache__/flows.cpython-312.pyc b/communications/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..620ed170 Binary files /dev/null and b/communications/__pycache__/flows.cpython-312.pyc differ diff --git a/communications/flows.py b/communications/flows.py new file mode 100644 index 00000000..fc077c27 --- /dev/null +++ b/communications/flows.py @@ -0,0 +1,1046 @@ +# """ +# Viewflow workflows for communications app. +# Provides message routing, notification delivery, and alert management workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import Message, MessageRecipient, NotificationTemplate, AlertRule, AlertInstance +# from .views import ( +# MessageCompositionView, RecipientSelectionView, MessageDeliveryView, +# NotificationCreationView, TemplateSelectionView, AlertConfigurationView, +# AlertEvaluationView, EscalationView, AcknowledgmentView, ResolutionView +# ) +# +# +# class MessageDeliveryProcess(Process): +# """ +# Viewflow process model for message delivery +# """ +# message = ModelField(Message, help_text='Associated message') +# +# # Process status tracking +# message_composed = models.BooleanField(default=False) +# recipients_selected = models.BooleanField(default=False) +# content_validated = models.BooleanField(default=False) +# delivery_scheduled = models.BooleanField(default=False) +# message_sent = models.BooleanField(default=False) +# delivery_confirmed = models.BooleanField(default=False) +# acknowledgments_received = models.BooleanField(default=False) +# delivery_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Message Delivery Process' +# verbose_name_plural = 'Message Delivery Processes' +# +# +# class MessageDeliveryFlow(Flow): +# """ +# Message Delivery Workflow +# +# This flow manages message composition, recipient selection, +# delivery, and acknowledgment tracking. +# """ +# +# process_class = MessageDeliveryProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_message_delivery) +# .Next(this.compose_message) +# ) +# +# compose_message = ( +# flow_view(MessageCompositionView) +# .Permission('communications.can_compose_messages') +# .Next(this.select_recipients) +# ) +# +# select_recipients = ( +# flow_view(RecipientSelectionView) +# .Permission('communications.can_select_recipients') +# .Next(this.validate_content) +# ) +# +# validate_content = ( +# flow_func(this.perform_content_validation) +# .Next(this.schedule_delivery) +# ) +# +# schedule_delivery = ( +# flow_func(this.setup_delivery_schedule) +# .Next(this.send_message) +# ) +# +# send_message = ( +# flow_view(MessageDeliveryView) +# .Permission('communications.can_send_messages') +# .Next(this.confirm_delivery) +# ) +# +# confirm_delivery = ( +# flow_func(this.track_delivery_status) +# .Next(this.collect_acknowledgments) +# ) +# +# collect_acknowledgments = ( +# flow_func(this.monitor_acknowledgments) +# .Next(this.complete_delivery) +# ) +# +# complete_delivery = ( +# flow_func(this.finalize_message_delivery) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_message_delivery) +# +# # Flow functions +# def start_message_delivery(self, activation): +# """Initialize the message delivery process""" +# process = activation.process +# message = process.message +# +# # Update message status +# message.status = 'DRAFT' +# message.save() +# +# # Send notification to communications staff +# self.notify_message_creation(message) +# +# # Check for urgent messages +# if message.priority in ['URGENT', 'CRITICAL'] or message.is_urgent: +# self.notify_urgent_message(message) +# +# def perform_content_validation(self, activation): +# """Validate message content and compliance""" +# process = activation.process +# message = process.message +# +# # Perform content validation +# validation_results = self.validate_message_content(message) +# +# if validation_results['is_valid']: +# process.content_validated = True +# process.save() +# else: +# # Handle validation failures +# self.handle_validation_failure(message, validation_results) +# +# def setup_delivery_schedule(self, activation): +# """Setup message delivery schedule""" +# process = activation.process +# message = process.message +# +# # Set delivery schedule +# if message.scheduled_at: +# # Message is scheduled for future delivery +# self.schedule_future_delivery(message) +# else: +# # Immediate delivery +# message.scheduled_at = timezone.now() +# message.save() +# +# # Mark delivery scheduled +# process.delivery_scheduled = True +# process.save() +# +# def track_delivery_status(self, activation): +# """Track message delivery status""" +# process = activation.process +# message = process.message +# +# # Update message status +# message.status = 'SENT' +# message.sent_at = timezone.now() +# message.save() +# +# # Mark message sent +# process.message_sent = True +# process.save() +# +# # Start delivery tracking +# self.start_delivery_tracking(message) +# +# def monitor_acknowledgments(self, activation): +# """Monitor message acknowledgments""" +# process = activation.process +# message = process.message +# +# if message.requires_acknowledgment: +# # Check acknowledgment status +# acknowledgment_status = self.check_acknowledgment_status(message) +# +# if acknowledgment_status['all_acknowledged']: +# process.acknowledgments_received = True +# process.save() +# else: +# # Send reminders for unacknowledged messages +# self.send_acknowledgment_reminders(message) +# else: +# # No acknowledgment required +# process.acknowledgments_received = True +# process.save() +# +# def finalize_message_delivery(self, activation): +# """Finalize the message delivery process""" +# process = activation.process +# message = process.message +# +# # Update message status +# message.status = 'DELIVERED' +# message.save() +# +# # Mark process as completed +# process.delivery_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_delivery_completion(message) +# +# # Update delivery metrics +# self.update_delivery_metrics(message) +# +# def end_message_delivery(self, activation): +# """End the message delivery workflow""" +# process = activation.process +# +# # Generate delivery summary report +# self.generate_delivery_summary(process.message) +# +# # Helper methods +# def notify_message_creation(self, message): +# """Notify communications staff of new message""" +# from django.contrib.auth.models import Group +# +# communications_staff = User.objects.filter( +# groups__name='Communications Staff' +# ) +# +# for staff in communications_staff: +# send_mail( +# subject=f'New Message Created: {message.subject}', +# message=f'New {message.get_message_type_display()} message created by {message.sender.get_full_name()}.', +# from_email='communications@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_urgent_message(self, message): +# """Notify of urgent message""" +# communications_managers = User.objects.filter( +# groups__name='Communications Managers' +# ) +# +# for manager in communications_managers: +# send_mail( +# subject=f'URGENT Message: {message.subject}', +# message=f'{message.get_priority_display()} message requires immediate attention.', +# from_email='communications@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def validate_message_content(self, message): +# """Validate message content for compliance and quality""" +# validation_results = { +# 'is_valid': True, +# 'errors': [], +# 'warnings': [] +# } +# +# # Content validation logic would go here +# # Check for compliance, appropriate language, etc. +# +# return validation_results +# +# def handle_validation_failure(self, message, validation_results): +# """Handle message validation failures""" +# # This would handle validation failures +# pass +# +# def schedule_future_delivery(self, message): +# """Schedule message for future delivery""" +# # Schedule delivery task +# send_scheduled_message.apply_async( +# args=[message.message_id], +# eta=message.scheduled_at +# ) +# +# def start_delivery_tracking(self, message): +# """Start tracking message delivery""" +# # This would start delivery tracking for all recipients +# pass +# +# def check_acknowledgment_status(self, message): +# """Check acknowledgment status for all recipients""" +# recipients = message.recipients.all() +# total_recipients = recipients.count() +# acknowledged_recipients = recipients.filter(status='ACKNOWLEDGED').count() +# +# return { +# 'all_acknowledged': acknowledged_recipients == total_recipients, +# 'acknowledgment_rate': acknowledged_recipients / total_recipients if total_recipients > 0 else 0 +# } +# +# def send_acknowledgment_reminders(self, message): +# """Send reminders for unacknowledged messages""" +# unacknowledged_recipients = message.recipients.filter( +# status__in=['DELIVERED', 'READ'] +# ) +# +# for recipient in unacknowledged_recipients: +# self.send_acknowledgment_reminder(recipient) +# +# def send_acknowledgment_reminder(self, recipient): +# """Send acknowledgment reminder to specific recipient""" +# # This would send reminder to recipient +# pass +# +# def notify_delivery_completion(self, message): +# """Notify delivery completion""" +# # Notify sender +# if message.sender and message.sender.email: +# send_mail( +# subject=f'Message Delivered: {message.subject}', +# message=f'Your message has been successfully delivered to all recipients.', +# from_email='communications@hospital.com', +# recipient_list=[message.sender.email], +# fail_silently=True +# ) +# +# def update_delivery_metrics(self, message): +# """Update message delivery metrics""" +# # This would update delivery performance metrics +# pass +# +# def generate_delivery_summary(self, message): +# """Generate message delivery summary""" +# # This would generate comprehensive delivery report +# pass +# +# +# class NotificationManagementProcess(Process): +# """ +# Viewflow process model for notification management +# """ +# notification_template = ModelField(NotificationTemplate, help_text='Associated notification template') +# +# # Process status tracking +# template_selected = models.BooleanField(default=False) +# content_generated = models.BooleanField(default=False) +# recipients_determined = models.BooleanField(default=False) +# notifications_created = models.BooleanField(default=False) +# delivery_initiated = models.BooleanField(default=False) +# delivery_monitored = models.BooleanField(default=False) +# notifications_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Notification Management Process' +# verbose_name_plural = 'Notification Management Processes' +# +# +# class NotificationManagementFlow(Flow): +# """ +# Notification Management Workflow +# +# This flow manages automated notification generation, +# delivery, and tracking using templates. +# """ +# +# process_class = NotificationManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_notification_management) +# .Next(this.select_template) +# ) +# +# select_template = ( +# flow_view(TemplateSelectionView) +# .Permission('communications.can_select_templates') +# .Next(this.generate_content) +# ) +# +# generate_content = ( +# flow_func(this.create_notification_content) +# .Next(this.determine_recipients) +# ) +# +# determine_recipients = ( +# flow_func(this.identify_notification_recipients) +# .Next(this.create_notifications) +# ) +# +# create_notifications = ( +# flow_view(NotificationCreationView) +# .Permission('communications.can_create_notifications') +# .Next(this.initiate_delivery) +# ) +# +# initiate_delivery = ( +# flow_func(this.start_notification_delivery) +# .Next(this.monitor_delivery) +# ) +# +# monitor_delivery = ( +# flow_func(this.track_notification_delivery) +# .Next(this.complete_notifications) +# ) +# +# complete_notifications = ( +# flow_func(this.finalize_notification_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_notification_management) +# +# # Flow functions +# def start_notification_management(self, activation): +# """Initialize the notification management process""" +# process = activation.process +# template = process.notification_template +# +# # Send notification to communications staff +# self.notify_notification_triggered(template) +# +# def create_notification_content(self, activation): +# """Generate notification content from template""" +# process = activation.process +# template = process.notification_template +# +# # Generate content using template +# content = self.generate_template_content(template) +# +# # Mark content generated +# process.content_generated = True +# process.save() +# +# # Store generated content +# self.store_generated_content(template, content) +# +# def identify_notification_recipients(self, activation): +# """Identify notification recipients""" +# process = activation.process +# template = process.notification_template +# +# # Determine recipients based on template configuration +# recipients = self.determine_template_recipients(template) +# +# # Mark recipients determined +# process.recipients_determined = True +# process.save() +# +# # Store recipient list +# self.store_recipient_list(template, recipients) +# +# def start_notification_delivery(self, activation): +# """Start notification delivery""" +# process = activation.process +# template = process.notification_template +# +# # Initiate delivery for all notifications +# self.initiate_template_delivery(template) +# +# # Mark delivery initiated +# process.delivery_initiated = True +# process.save() +# +# def track_notification_delivery(self, activation): +# """Track notification delivery progress""" +# process = activation.process +# template = process.notification_template +# +# # Monitor delivery status +# delivery_status = self.monitor_template_delivery(template) +# +# if delivery_status['all_delivered']: +# process.delivery_monitored = True +# process.save() +# else: +# # Continue monitoring +# self.schedule_delivery_monitoring(template) +# +# def finalize_notification_management(self, activation): +# """Finalize the notification management process""" +# process = activation.process +# template = process.notification_template +# +# # Mark process as completed +# process.notifications_completed = True +# process.save() +# +# # Update template usage statistics +# self.update_template_usage(template) +# +# # Send completion notifications +# self.notify_notification_completion(template) +# +# def end_notification_management(self, activation): +# """End the notification management workflow""" +# process = activation.process +# +# # Generate notification summary +# self.generate_notification_summary(process.notification_template) +# +# # Helper methods +# def notify_notification_triggered(self, template): +# """Notify communications staff of triggered notification""" +# communications_staff = User.objects.filter( +# groups__name='Communications Staff' +# ) +# +# for staff in communications_staff: +# send_mail( +# subject=f'Notification Triggered: {template.name}', +# message=f'Automated notification "{template.name}" has been triggered.', +# from_email='notifications@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def generate_template_content(self, template): +# """Generate content from notification template""" +# # This would implement template rendering logic +# return { +# 'subject': template.subject_template, +# 'content': template.content_template +# } +# +# def store_generated_content(self, template, content): +# """Store generated notification content""" +# # This would store the generated content +# pass +# +# def determine_template_recipients(self, template): +# """Determine recipients for template notifications""" +# # This would implement recipient determination logic +# return [] +# +# def store_recipient_list(self, template, recipients): +# """Store recipient list for template""" +# # This would store the recipient list +# pass +# +# def initiate_template_delivery(self, template): +# """Initiate delivery for template notifications""" +# # This would start delivery for all notifications +# pass +# +# def monitor_template_delivery(self, template): +# """Monitor template notification delivery""" +# # This would monitor delivery progress +# return {'all_delivered': True} +# +# def schedule_delivery_monitoring(self, template): +# """Schedule continued delivery monitoring""" +# # This would schedule monitoring tasks +# pass +# +# def update_template_usage(self, template): +# """Update template usage statistics""" +# template.usage_count += 1 +# template.last_used_at = timezone.now() +# template.save() +# +# def notify_notification_completion(self, template): +# """Notify notification completion""" +# # This would notify relevant parties +# pass +# +# def generate_notification_summary(self, template): +# """Generate notification summary""" +# # This would generate notification summary +# pass +# +# +# class AlertManagementProcess(Process): +# """ +# Viewflow process model for alert management +# """ +# alert_instance = ModelField(AlertInstance, help_text='Associated alert instance') +# +# # Process status tracking +# alert_triggered = models.BooleanField(default=False) +# alert_evaluated = models.BooleanField(default=False) +# notifications_sent = models.BooleanField(default=False) +# acknowledgment_received = models.BooleanField(default=False) +# escalation_processed = models.BooleanField(default=False) +# resolution_completed = models.BooleanField(default=False) +# alert_closed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Alert Management Process' +# verbose_name_plural = 'Alert Management Processes' +# +# +# class AlertManagementFlow(Flow): +# """ +# Alert Management Workflow +# +# This flow manages alert lifecycle from trigger through +# acknowledgment, escalation, and resolution. +# """ +# +# process_class = AlertManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_alert_management) +# .Next(this.trigger_alert) +# ) +# +# trigger_alert = ( +# flow_func(this.process_alert_trigger) +# .Next(this.evaluate_alert) +# ) +# +# evaluate_alert = ( +# flow_view(AlertEvaluationView) +# .Permission('communications.can_evaluate_alerts') +# .Next(this.send_notifications) +# ) +# +# send_notifications = ( +# flow_func(this.dispatch_alert_notifications) +# .Next(this.await_acknowledgment) +# ) +# +# await_acknowledgment = ( +# flow_view(AcknowledgmentView) +# .Permission('communications.can_acknowledge_alerts') +# .Next(this.process_escalation) +# ) +# +# process_escalation = ( +# flow_view(EscalationView) +# .Permission('communications.can_escalate_alerts') +# .Next(this.resolve_alert) +# ) +# +# resolve_alert = ( +# flow_view(ResolutionView) +# .Permission('communications.can_resolve_alerts') +# .Next(this.close_alert) +# ) +# +# close_alert = ( +# flow_func(this.finalize_alert_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_alert_management) +# +# # Flow functions +# def start_alert_management(self, activation): +# """Initialize the alert management process""" +# process = activation.process +# alert = process.alert_instance +# +# # Update alert status +# alert.status = 'ACTIVE' +# alert.save() +# +# # Send immediate notifications for critical alerts +# if alert.severity in ['CRITICAL', 'EMERGENCY']: +# self.send_immediate_notifications(alert) +# +# def process_alert_trigger(self, activation): +# """Process alert trigger conditions""" +# process = activation.process +# alert = process.alert_instance +# +# # Mark alert as triggered +# process.alert_triggered = True +# process.save() +# +# # Log alert trigger +# self.log_alert_trigger(alert) +# +# # Check for duplicate alerts +# self.check_duplicate_alerts(alert) +# +# def dispatch_alert_notifications(self, activation): +# """Dispatch alert notifications""" +# process = activation.process +# alert = process.alert_instance +# +# # Send notifications to configured recipients +# self.send_alert_notifications(alert) +# +# # Mark notifications sent +# process.notifications_sent = True +# process.save() +# +# # Schedule escalation if no acknowledgment +# self.schedule_escalation(alert) +# +# def finalize_alert_management(self, activation): +# """Finalize the alert management process""" +# process = activation.process +# alert = process.alert_instance +# +# # Update alert status +# alert.status = 'RESOLVED' +# alert.resolved_at = timezone.now() +# alert.save() +# +# # Mark process as completed +# process.alert_closed = True +# process.save() +# +# # Send resolution notifications +# self.notify_alert_resolution(alert) +# +# # Update alert metrics +# self.update_alert_metrics(alert) +# +# def end_alert_management(self, activation): +# """End the alert management workflow""" +# process = activation.process +# +# # Generate alert summary +# self.generate_alert_summary(process.alert_instance) +# +# # Helper methods +# def send_immediate_notifications(self, alert): +# """Send immediate notifications for critical alerts""" +# # This would send immediate notifications +# pass +# +# def log_alert_trigger(self, alert): +# """Log alert trigger event""" +# # This would log the alert trigger +# pass +# +# def check_duplicate_alerts(self, alert): +# """Check for duplicate alerts""" +# # This would check for and handle duplicate alerts +# pass +# +# def send_alert_notifications(self, alert): +# """Send alert notifications to recipients""" +# rule = alert.alert_rule +# +# # Send to default recipients +# for recipient in rule.default_recipients.all(): +# self.send_alert_to_recipient(alert, recipient) +# +# # Send to role-based recipients +# for role in rule.recipient_roles: +# role_recipients = User.objects.filter(groups__name=role) +# for recipient in role_recipients: +# self.send_alert_to_recipient(alert, recipient) +# +# def send_alert_to_recipient(self, alert, recipient): +# """Send alert to specific recipient""" +# if recipient.email: +# send_mail( +# subject=f'ALERT: {alert.title}', +# message=f'Alert: {alert.description}\nSeverity: {alert.severity}', +# from_email='alerts@hospital.com', +# recipient_list=[recipient.email], +# fail_silently=True +# ) +# +# def schedule_escalation(self, alert): +# """Schedule alert escalation""" +# rule = alert.alert_rule +# escalation_rules = rule.escalation_rules +# +# if escalation_rules: +# # Schedule escalation task +# escalate_alert.apply_async( +# args=[alert.alert_id], +# countdown=escalation_rules.get('escalation_delay', 3600) # 1 hour default +# ) +# +# def notify_alert_resolution(self, alert): +# """Notify alert resolution""" +# # Notify all recipients of resolution +# rule = alert.alert_rule +# +# for recipient in rule.default_recipients.all(): +# if recipient.email: +# send_mail( +# subject=f'RESOLVED: {alert.title}', +# message=f'Alert has been resolved: {alert.description}', +# from_email='alerts@hospital.com', +# recipient_list=[recipient.email], +# fail_silently=True +# ) +# +# def update_alert_metrics(self, alert): +# """Update alert performance metrics""" +# # This would update alert metrics +# pass +# +# def generate_alert_summary(self, alert): +# """Generate alert summary""" +# # This would generate alert summary +# pass +# +# +# class CommunicationAuditProcess(Process): +# """ +# Viewflow process model for communication audit +# """ +# audit_period_start = models.DateTimeField(help_text='Audit period start') +# audit_period_end = models.DateTimeField(help_text='Audit period end') +# +# # Process status tracking +# audit_initiated = models.BooleanField(default=False) +# data_collected = models.BooleanField(default=False) +# analysis_completed = models.BooleanField(default=False) +# report_generated = models.BooleanField(default=False) +# audit_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Communication Audit Process' +# verbose_name_plural = 'Communication Audit Processes' +# +# +# class CommunicationAuditFlow(Flow): +# """ +# Communication Audit Workflow +# +# This flow manages communication auditing including +# data collection, analysis, and reporting. +# """ +# +# process_class = CommunicationAuditProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_communication_audit) +# .Next(this.initiate_audit) +# ) +# +# initiate_audit = ( +# flow_func(this.setup_audit_parameters) +# .Next(this.collect_data) +# ) +# +# collect_data = ( +# flow_func(this.gather_communication_data) +# .Next(this.analyze_data) +# ) +# +# analyze_data = ( +# flow_func(this.perform_communication_analysis) +# .Next(this.generate_report) +# ) +# +# generate_report = ( +# flow_func(this.create_audit_report) +# .Next(this.complete_audit) +# ) +# +# complete_audit = ( +# flow_func(this.finalize_communication_audit) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_communication_audit) +# +# # Flow functions +# def start_communication_audit(self, activation): +# """Initialize the communication audit process""" +# process = activation.process +# +# # Send audit notification +# self.notify_audit_start(process.audit_period_start, process.audit_period_end) +# +# def setup_audit_parameters(self, activation): +# """Setup audit parameters and scope""" +# process = activation.process +# +# # Mark audit initiated +# process.audit_initiated = True +# process.save() +# +# # Configure audit parameters +# self.configure_audit_scope(process.audit_period_start, process.audit_period_end) +# +# def gather_communication_data(self, activation): +# """Gather communication data for audit""" +# process = activation.process +# +# # Collect communication data +# self.collect_audit_data(process.audit_period_start, process.audit_period_end) +# +# # Mark data collected +# process.data_collected = True +# process.save() +# +# def perform_communication_analysis(self, activation): +# """Perform communication analysis""" +# process = activation.process +# +# # Analyze communication patterns and compliance +# self.analyze_communication_patterns(process.audit_period_start, process.audit_period_end) +# +# # Mark analysis completed +# process.analysis_completed = True +# process.save() +# +# def create_audit_report(self, activation): +# """Create audit report""" +# process = activation.process +# +# # Generate comprehensive audit report +# self.generate_audit_report(process.audit_period_start, process.audit_period_end) +# +# # Mark report generated +# process.report_generated = True +# process.save() +# +# def finalize_communication_audit(self, activation): +# """Finalize the communication audit process""" +# process = activation.process +# +# # Mark audit completed +# process.audit_completed = True +# process.save() +# +# # Send audit completion notification +# self.notify_audit_completion(process.audit_period_start, process.audit_period_end) +# +# def end_communication_audit(self, activation): +# """End the communication audit workflow""" +# process = activation.process +# +# # Archive audit results +# self.archive_audit_results(process.audit_period_start, process.audit_period_end) +# +# # Helper methods +# def notify_audit_start(self, start_date, end_date): +# """Notify audit start""" +# # This would notify relevant parties of audit start +# pass +# +# def configure_audit_scope(self, start_date, end_date): +# """Configure audit scope and parameters""" +# # This would configure audit parameters +# pass +# +# def collect_audit_data(self, start_date, end_date): +# """Collect communication data for audit""" +# # This would collect all relevant communication data +# pass +# +# def analyze_communication_patterns(self, start_date, end_date): +# """Analyze communication patterns""" +# # This would analyze communication effectiveness and compliance +# pass +# +# def generate_audit_report(self, start_date, end_date): +# """Generate comprehensive audit report""" +# # This would generate detailed audit report +# pass +# +# def notify_audit_completion(self, start_date, end_date): +# """Notify audit completion""" +# # This would notify audit completion +# pass +# +# def archive_audit_results(self, start_date, end_date): +# """Archive audit results""" +# # This would archive audit results for future reference +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def send_scheduled_message(message_id): +# """Background task to send scheduled messages""" +# try: +# message = Message.objects.get(message_id=message_id) +# +# # Send message to all recipients +# for recipient in message.recipients.all(): +# send_message_to_recipient(message, recipient) +# +# # Update message status +# message.status = 'SENT' +# message.sent_at = timezone.now() +# message.save() +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def escalate_alert(alert_id): +# """Background task to escalate alerts""" +# try: +# alert = AlertInstance.objects.get(alert_id=alert_id) +# +# if alert.status == 'ACTIVE': +# # Escalate alert +# alert.escalation_level += 1 +# alert.escalated_at = timezone.now() +# alert.save() +# +# # Send escalation notifications +# send_escalation_notifications(alert) +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def process_notification_queue(): +# """Background task to process notification queue""" +# try: +# # This would process pending notifications +# return True +# except Exception: +# return False +# +# +# @celery.job +# def cleanup_expired_messages(): +# """Background task to cleanup expired messages""" +# try: +# # This would cleanup expired messages +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_communication_reports(): +# """Background task to generate communication reports""" +# try: +# # This would generate periodic communication reports +# return True +# except Exception: +# return False +# +# +# def send_message_to_recipient(message, recipient): +# """Helper function to send message to specific recipient""" +# # This would implement actual message sending logic +# pass +# +# +# def send_escalation_notifications(alert): +# """Helper function to send escalation notifications""" +# # This would send escalation notifications +# pass +# diff --git a/core/__pycache__/admin.cpython-312.pyc b/core/__pycache__/admin.cpython-312.pyc index cf8a7ffc..00b2aa28 100644 Binary files a/core/__pycache__/admin.cpython-312.pyc and b/core/__pycache__/admin.cpython-312.pyc differ diff --git a/core/__pycache__/flows.cpython-312.pyc b/core/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..aadce5c4 Binary files /dev/null and b/core/__pycache__/flows.cpython-312.pyc differ diff --git a/core/__pycache__/forms.cpython-312.pyc b/core/__pycache__/forms.cpython-312.pyc index 13ebdd6d..2b335ed8 100644 Binary files a/core/__pycache__/forms.cpython-312.pyc and b/core/__pycache__/forms.cpython-312.pyc differ diff --git a/core/__pycache__/models.cpython-312.pyc b/core/__pycache__/models.cpython-312.pyc index a41f847e..01ccffd0 100644 Binary files a/core/__pycache__/models.cpython-312.pyc and b/core/__pycache__/models.cpython-312.pyc differ diff --git a/core/__pycache__/views.cpython-312.pyc b/core/__pycache__/views.cpython-312.pyc index aff523a8..c4cf615b 100644 Binary files a/core/__pycache__/views.cpython-312.pyc and b/core/__pycache__/views.cpython-312.pyc differ diff --git a/core/flows.py b/core/flows.py new file mode 100644 index 00000000..4e05b8d3 --- /dev/null +++ b/core/flows.py @@ -0,0 +1,849 @@ +# """ +# Viewflow workflows for core app. +# Provides system administration, tenant management, and configuration workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import Tenant, Department, AuditLogEntry, SystemConfiguration, SystemNotification, IntegrationLog +# from .views import ( +# TenantSetupView, DepartmentManagementView, ConfigurationView, +# AuditReviewView, NotificationManagementView, IntegrationMonitoringView, +# SystemMaintenanceView, BackupView, SecurityAuditView, ComplianceCheckView +# ) +# +# +# class TenantOnboardingProcess(Process): +# """ +# Viewflow process model for tenant onboarding +# """ +# tenant = ModelField(Tenant, help_text='Associated tenant') +# +# # Process status tracking +# tenant_created = models.BooleanField(default=False) +# configuration_setup = models.BooleanField(default=False) +# departments_created = models.BooleanField(default=False) +# users_configured = models.BooleanField(default=False) +# integrations_setup = models.BooleanField(default=False) +# testing_completed = models.BooleanField(default=False) +# training_provided = models.BooleanField(default=False) +# onboarding_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Tenant Onboarding Process' +# verbose_name_plural = 'Tenant Onboarding Processes' +# +# +# class TenantOnboardingFlow(Flow): +# """ +# Tenant Onboarding Workflow +# +# This flow manages complete tenant onboarding from initial +# setup through configuration, testing, and go-live. +# """ +# +# process_class = TenantOnboardingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_tenant_onboarding) +# .Next(this.setup_tenant) +# ) +# +# setup_tenant = ( +# flow_view(TenantSetupView) +# .Permission('core.can_setup_tenants') +# .Next(this.configure_system) +# ) +# +# configure_system = ( +# flow_view(ConfigurationView) +# .Permission('core.can_configure_system') +# .Next(this.create_departments) +# ) +# +# create_departments = ( +# flow_view(DepartmentManagementView) +# .Permission('core.can_manage_departments') +# .Next(this.configure_users) +# ) +# +# configure_users = ( +# flow_func(this.setup_initial_users) +# .Next(this.setup_integrations) +# ) +# +# setup_integrations = ( +# flow_func(this.configure_integrations) +# .Next(this.complete_testing) +# ) +# +# complete_testing = ( +# flow_func(this.perform_system_testing) +# .Next(this.provide_training) +# ) +# +# provide_training = ( +# flow_func(this.deliver_user_training) +# .Next(this.finalize_onboarding) +# ) +# +# finalize_onboarding = ( +# flow_func(this.complete_tenant_onboarding) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_tenant_onboarding) +# +# # Flow functions +# def start_tenant_onboarding(self, activation): +# """Initialize the tenant onboarding process""" +# process = activation.process +# tenant = process.tenant +# +# # Send onboarding notification +# self.notify_onboarding_start(tenant) +# +# # Create onboarding checklist +# self.create_onboarding_checklist(tenant) +# +# # Set up audit logging +# self.setup_audit_logging(tenant) +# +# def setup_initial_users(self, activation): +# """Setup initial users for tenant""" +# process = activation.process +# tenant = process.tenant +# +# # Create initial admin users +# self.create_admin_users(tenant) +# +# # Mark users configured +# process.users_configured = True +# process.save() +# +# # Send user credentials +# self.send_user_credentials(tenant) +# +# def configure_integrations(self, activation): +# """Configure system integrations""" +# process = activation.process +# tenant = process.tenant +# +# # Setup default integrations +# self.setup_default_integrations(tenant) +# +# # Mark integrations setup +# process.integrations_setup = True +# process.save() +# +# # Test integration connectivity +# self.test_integration_connectivity(tenant) +# +# def perform_system_testing(self, activation): +# """Perform comprehensive system testing""" +# process = activation.process +# tenant = process.tenant +# +# # Execute system tests +# test_results = self.execute_system_tests(tenant) +# +# # Mark testing completed +# process.testing_completed = True +# process.save() +# +# # Store test results +# self.store_test_results(tenant, test_results) +# +# def deliver_user_training(self, activation): +# """Deliver user training""" +# process = activation.process +# tenant = process.tenant +# +# # Schedule training sessions +# self.schedule_training_sessions(tenant) +# +# # Mark training provided +# process.training_provided = True +# process.save() +# +# # Send training materials +# self.send_training_materials(tenant) +# +# def complete_tenant_onboarding(self, activation): +# """Complete the tenant onboarding process""" +# process = activation.process +# tenant = process.tenant +# +# # Activate tenant +# tenant.is_active = True +# tenant.save() +# +# # Mark onboarding completed +# process.onboarding_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_onboarding_completion(tenant) +# +# # Schedule post-onboarding follow-up +# self.schedule_followup(tenant) +# +# def end_tenant_onboarding(self, activation): +# """End the tenant onboarding workflow""" +# process = activation.process +# +# # Generate onboarding summary +# self.generate_onboarding_summary(process.tenant) +# +# # Helper methods +# def notify_onboarding_start(self, tenant): +# """Notify onboarding start""" +# admin_team = User.objects.filter(groups__name='System Administrators') +# for admin in admin_team: +# send_mail( +# subject=f'Tenant Onboarding Started: {tenant.name}', +# message=f'Onboarding process started for tenant "{tenant.name}".', +# from_email='admin@hospital.com', +# recipient_list=[admin.email], +# fail_silently=True +# ) +# +# def create_onboarding_checklist(self, tenant): +# """Create onboarding checklist""" +# # This would create a comprehensive onboarding checklist +# pass +# +# def setup_audit_logging(self, tenant): +# """Setup audit logging for tenant""" +# # This would configure audit logging +# pass +# +# def create_admin_users(self, tenant): +# """Create initial admin users""" +# # This would create initial admin users +# pass +# +# def send_user_credentials(self, tenant): +# """Send user credentials""" +# # This would send initial user credentials +# pass +# +# def setup_default_integrations(self, tenant): +# """Setup default integrations""" +# # This would configure default integrations +# pass +# +# def test_integration_connectivity(self, tenant): +# """Test integration connectivity""" +# # This would test all integrations +# pass +# +# def execute_system_tests(self, tenant): +# """Execute comprehensive system tests""" +# # This would run system tests +# return {'status': 'passed', 'issues': []} +# +# def store_test_results(self, tenant, results): +# """Store test results""" +# # This would store test results +# pass +# +# def schedule_training_sessions(self, tenant): +# """Schedule training sessions""" +# # This would schedule training +# pass +# +# def send_training_materials(self, tenant): +# """Send training materials""" +# # This would send training materials +# pass +# +# def notify_onboarding_completion(self, tenant): +# """Notify onboarding completion""" +# send_mail( +# subject=f'Tenant Onboarding Complete: {tenant.name}', +# message=f'Onboarding completed successfully for "{tenant.name}".', +# from_email='admin@hospital.com', +# recipient_list=[tenant.email], +# fail_silently=True +# ) +# +# def schedule_followup(self, tenant): +# """Schedule post-onboarding follow-up""" +# # Schedule follow-up task +# tenant_followup.apply_async( +# args=[tenant.tenant_id], +# countdown=86400 * 7 # 7 days +# ) +# +# def generate_onboarding_summary(self, tenant): +# """Generate onboarding summary""" +# # This would generate onboarding summary +# pass +# +# +# class SystemMaintenanceProcess(Process): +# """ +# Viewflow process model for system maintenance +# """ +# maintenance_type = models.CharField(max_length=50, help_text='Type of maintenance') +# +# # Process status tracking +# maintenance_scheduled = models.BooleanField(default=False) +# notifications_sent = models.BooleanField(default=False) +# backup_completed = models.BooleanField(default=False) +# maintenance_executed = models.BooleanField(default=False) +# testing_completed = models.BooleanField(default=False) +# system_restored = models.BooleanField(default=False) +# maintenance_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'System Maintenance Process' +# verbose_name_plural = 'System Maintenance Processes' +# +# +# class SystemMaintenanceFlow(Flow): +# """ +# System Maintenance Workflow +# +# This flow manages scheduled system maintenance including +# notifications, backups, execution, and restoration. +# """ +# +# process_class = SystemMaintenanceProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_system_maintenance) +# .Next(this.schedule_maintenance) +# ) +# +# schedule_maintenance = ( +# flow_view(SystemMaintenanceView) +# .Permission('core.can_schedule_maintenance') +# .Next(this.send_notifications) +# ) +# +# send_notifications = ( +# flow_func(this.notify_maintenance_window) +# .Next(this.create_backup) +# ) +# +# create_backup = ( +# flow_view(BackupView) +# .Permission('core.can_create_backups') +# .Next(this.execute_maintenance) +# ) +# +# execute_maintenance = ( +# flow_func(this.perform_maintenance_tasks) +# .Next(this.test_system) +# ) +# +# test_system = ( +# flow_func(this.perform_post_maintenance_testing) +# .Next(this.restore_system) +# ) +# +# restore_system = ( +# flow_func(this.restore_system_services) +# .Next(this.complete_maintenance) +# ) +# +# complete_maintenance = ( +# flow_func(this.finalize_system_maintenance) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_system_maintenance) +# +# # Flow functions +# def start_system_maintenance(self, activation): +# """Initialize the system maintenance process""" +# process = activation.process +# +# # Send maintenance start notification +# self.notify_maintenance_start(process.maintenance_type) +# +# # Create maintenance checklist +# self.create_maintenance_checklist(process.maintenance_type) +# +# def notify_maintenance_window(self, activation): +# """Send maintenance window notifications""" +# process = activation.process +# +# # Send notifications to all users +# self.send_maintenance_notifications(process.maintenance_type) +# +# # Mark notifications sent +# process.notifications_sent = True +# process.save() +# +# # Create system notification +# self.create_system_notification(process.maintenance_type) +# +# def perform_maintenance_tasks(self, activation): +# """Perform maintenance tasks""" +# process = activation.process +# +# # Execute maintenance tasks +# self.execute_maintenance_procedures(process.maintenance_type) +# +# # Mark maintenance executed +# process.maintenance_executed = True +# process.save() +# +# # Log maintenance activities +# self.log_maintenance_activities(process.maintenance_type) +# +# def perform_post_maintenance_testing(self, activation): +# """Perform post-maintenance testing""" +# process = activation.process +# +# # Execute post-maintenance tests +# test_results = self.execute_post_maintenance_tests() +# +# # Mark testing completed +# process.testing_completed = True +# process.save() +# +# # Store test results +# self.store_maintenance_test_results(test_results) +# +# def restore_system_services(self, activation): +# """Restore system services""" +# process = activation.process +# +# # Restore all system services +# self.restore_services() +# +# # Mark system restored +# process.system_restored = True +# process.save() +# +# # Verify service restoration +# self.verify_service_restoration() +# +# def finalize_system_maintenance(self, activation): +# """Finalize the system maintenance process""" +# process = activation.process +# +# # Mark maintenance completed +# process.maintenance_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_maintenance_completion(process.maintenance_type) +# +# # Generate maintenance report +# self.generate_maintenance_report(process.maintenance_type) +# +# def end_system_maintenance(self, activation): +# """End the system maintenance workflow""" +# process = activation.process +# +# # Archive maintenance records +# self.archive_maintenance_records(process.maintenance_type) +# +# # Helper methods +# def notify_maintenance_start(self, maintenance_type): +# """Notify maintenance start""" +# admin_team = User.objects.filter(groups__name='System Administrators') +# for admin in admin_team: +# send_mail( +# subject=f'System Maintenance Started: {maintenance_type}', +# message=f'System maintenance process started for {maintenance_type}.', +# from_email='admin@hospital.com', +# recipient_list=[admin.email], +# fail_silently=True +# ) +# +# def create_maintenance_checklist(self, maintenance_type): +# """Create maintenance checklist""" +# # This would create maintenance checklist +# pass +# +# def send_maintenance_notifications(self, maintenance_type): +# """Send maintenance notifications to all users""" +# # This would send notifications to all users +# pass +# +# def create_system_notification(self, maintenance_type): +# """Create system-wide notification""" +# SystemNotification.objects.create( +# title='Scheduled System Maintenance', +# message=f'System maintenance is scheduled for {maintenance_type}.', +# notification_type='MAINTENANCE', +# priority='HIGH', +# target_audience='ALL_USERS', +# is_active=True +# ) +# +# def execute_maintenance_procedures(self, maintenance_type): +# """Execute maintenance procedures""" +# # This would execute maintenance procedures +# pass +# +# def log_maintenance_activities(self, maintenance_type): +# """Log maintenance activities""" +# # This would log all maintenance activities +# pass +# +# def execute_post_maintenance_tests(self): +# """Execute post-maintenance tests""" +# # This would run post-maintenance tests +# return {'status': 'passed', 'issues': []} +# +# def store_maintenance_test_results(self, results): +# """Store maintenance test results""" +# # This would store test results +# pass +# +# def restore_services(self): +# """Restore all system services""" +# # This would restore system services +# pass +# +# def verify_service_restoration(self): +# """Verify service restoration""" +# # This would verify all services are restored +# pass +# +# def notify_maintenance_completion(self, maintenance_type): +# """Notify maintenance completion""" +# all_users = User.objects.filter(is_active=True) +# for user in all_users: +# if user.email: +# send_mail( +# subject='System Maintenance Complete', +# message=f'System maintenance for {maintenance_type} has been completed.', +# from_email='admin@hospital.com', +# recipient_list=[user.email], +# fail_silently=True +# ) +# +# def generate_maintenance_report(self, maintenance_type): +# """Generate maintenance report""" +# # This would generate comprehensive maintenance report +# pass +# +# def archive_maintenance_records(self, maintenance_type): +# """Archive maintenance records""" +# # This would archive maintenance records +# pass +# +# +# class AuditManagementProcess(Process): +# """ +# Viewflow process model for audit management +# """ +# audit_type = models.CharField(max_length=50, help_text='Type of audit') +# +# # Process status tracking +# audit_initiated = models.BooleanField(default=False) +# scope_defined = models.BooleanField(default=False) +# data_collected = models.BooleanField(default=False) +# analysis_completed = models.BooleanField(default=False) +# findings_documented = models.BooleanField(default=False) +# report_generated = models.BooleanField(default=False) +# audit_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Audit Management Process' +# verbose_name_plural = 'Audit Management Processes' +# +# +# class AuditManagementFlow(Flow): +# """ +# Audit Management Workflow +# +# This flow manages system audits including security, +# compliance, and operational audits. +# """ +# +# process_class = AuditManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_audit_management) +# .Next(this.initiate_audit) +# ) +# +# initiate_audit = ( +# flow_func(this.setup_audit_scope) +# .Next(this.define_scope) +# ) +# +# define_scope = ( +# flow_func(this.define_audit_scope) +# .Next(this.collect_data) +# ) +# +# collect_data = ( +# flow_func(this.gather_audit_data) +# .Next(this.analyze_data) +# ) +# +# analyze_data = ( +# flow_view(AuditReviewView) +# .Permission('core.can_review_audits') +# .Next(this.document_findings) +# ) +# +# document_findings = ( +# flow_func(this.document_audit_findings) +# .Next(this.generate_report) +# ) +# +# generate_report = ( +# flow_func(this.create_audit_report) +# .Next(this.complete_audit) +# ) +# +# complete_audit = ( +# flow_func(this.finalize_audit_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_audit_management) +# +# # Flow functions +# def start_audit_management(self, activation): +# """Initialize the audit management process""" +# process = activation.process +# +# # Send audit start notification +# self.notify_audit_start(process.audit_type) +# +# # Create audit checklist +# self.create_audit_checklist(process.audit_type) +# +# def setup_audit_scope(self, activation): +# """Setup audit scope""" +# process = activation.process +# +# # Mark audit initiated +# process.audit_initiated = True +# process.save() +# +# # Configure audit parameters +# self.configure_audit_parameters(process.audit_type) +# +# def define_audit_scope(self, activation): +# """Define audit scope and criteria""" +# process = activation.process +# +# # Define audit scope +# self.establish_audit_scope(process.audit_type) +# +# # Mark scope defined +# process.scope_defined = True +# process.save() +# +# def gather_audit_data(self, activation): +# """Gather audit data""" +# process = activation.process +# +# # Collect audit data +# audit_data = self.collect_audit_data(process.audit_type) +# +# # Mark data collected +# process.data_collected = True +# process.save() +# +# # Store audit data +# self.store_audit_data(process.audit_type, audit_data) +# +# def document_audit_findings(self, activation): +# """Document audit findings""" +# process = activation.process +# +# # Document findings +# findings = self.create_audit_findings(process.audit_type) +# +# # Mark findings documented +# process.findings_documented = True +# process.save() +# +# # Store findings +# self.store_audit_findings(process.audit_type, findings) +# +# def create_audit_report(self, activation): +# """Create audit report""" +# process = activation.process +# +# # Generate audit report +# report = self.generate_audit_report(process.audit_type) +# +# # Mark report generated +# process.report_generated = True +# process.save() +# +# # Store report +# self.store_audit_report(process.audit_type, report) +# +# def finalize_audit_management(self, activation): +# """Finalize the audit management process""" +# process = activation.process +# +# # Mark audit completed +# process.audit_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_audit_completion(process.audit_type) +# +# # Schedule follow-up actions +# self.schedule_audit_followup(process.audit_type) +# +# def end_audit_management(self, activation): +# """End the audit management workflow""" +# process = activation.process +# +# # Archive audit records +# self.archive_audit_records(process.audit_type) +# +# # Helper methods +# def notify_audit_start(self, audit_type): +# """Notify audit start""" +# audit_team = User.objects.filter(groups__name='Audit Team') +# for auditor in audit_team: +# send_mail( +# subject=f'Audit Started: {audit_type}', +# message=f'Audit process started for {audit_type}.', +# from_email='audit@hospital.com', +# recipient_list=[auditor.email], +# fail_silently=True +# ) +# +# def create_audit_checklist(self, audit_type): +# """Create audit checklist""" +# # This would create audit checklist +# pass +# +# def configure_audit_parameters(self, audit_type): +# """Configure audit parameters""" +# # This would configure audit parameters +# pass +# +# def establish_audit_scope(self, audit_type): +# """Establish audit scope""" +# # This would define audit scope +# pass +# +# def collect_audit_data(self, audit_type): +# """Collect audit data""" +# # This would collect audit data +# return {'status': 'collected', 'records': 1000} +# +# def store_audit_data(self, audit_type, data): +# """Store audit data""" +# # This would store audit data +# pass +# +# def create_audit_findings(self, audit_type): +# """Create audit findings""" +# # This would create audit findings +# return {'findings': [], 'recommendations': []} +# +# def store_audit_findings(self, audit_type, findings): +# """Store audit findings""" +# # This would store findings +# pass +# +# def generate_audit_report(self, audit_type): +# """Generate audit report""" +# # This would generate comprehensive audit report +# return {'report_path': '/audits/report.pdf'} +# +# def store_audit_report(self, audit_type, report): +# """Store audit report""" +# # This would store audit report +# pass +# +# def notify_audit_completion(self, audit_type): +# """Notify audit completion""" +# # This would notify relevant parties +# pass +# +# def schedule_audit_followup(self, audit_type): +# """Schedule audit follow-up""" +# # Schedule follow-up task +# audit_followup.apply_async( +# args=[audit_type], +# countdown=86400 * 30 # 30 days +# ) +# +# def archive_audit_records(self, audit_type): +# """Archive audit records""" +# # This would archive audit records +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def tenant_followup(tenant_id): +# """Background task for tenant follow-up""" +# try: +# tenant = Tenant.objects.get(tenant_id=tenant_id) +# +# # Perform follow-up activities +# # This would perform post-onboarding follow-up +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def system_health_check(): +# """Background task for system health monitoring""" +# try: +# # This would perform system health checks +# return True +# except Exception: +# return False +# +# +# @celery.job +# def audit_followup(audit_type): +# """Background task for audit follow-up""" +# try: +# # This would perform audit follow-up activities +# return True +# except Exception: +# return False +# +# +# @celery.job +# def cleanup_audit_logs(): +# """Background task to cleanup old audit logs""" +# try: +# # This would cleanup old audit logs +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_system_reports(): +# """Background task to generate system reports""" +# try: +# # This would generate periodic system reports +# return True +# except Exception: +# return False +# diff --git a/core/models.py b/core/models.py index a0074036..459657b1 100644 --- a/core/models.py +++ b/core/models.py @@ -90,7 +90,7 @@ class Tenant(models.Model): ) country = models.CharField( max_length=100, - default='United States', + default='Saudi Arabia', help_text='Country' ) @@ -150,7 +150,7 @@ class Tenant(models.Model): ) currency = models.CharField( max_length=3, - default='USD', + default='SAR', help_text='Organization currency code' ) @@ -854,7 +854,6 @@ class IntegrationLog(models.Model): - class Department(models.Model): """ Hospital department model for organizational structure. @@ -890,10 +889,10 @@ class Department(models.Model): tenant = models.ForeignKey( Tenant, on_delete=models.CASCADE, - related_name='departments', + related_name='core_departments', help_text='Organization tenant' ) - + # Department Information department_id = models.UUIDField( default=uuid.uuid4, @@ -914,14 +913,14 @@ class Department(models.Model): null=True, help_text='Department description' ) - + # Department Classification department_type = models.CharField( max_length=30, choices=DEPARTMENT_TYPE_CHOICES, help_text='Type of department' ) - + # Organizational Structure parent_department = models.ForeignKey( 'self', @@ -931,7 +930,7 @@ class Department(models.Model): related_name='sub_departments', help_text='Parent department (for hierarchical structure)' ) - + # Management department_head = models.ForeignKey( settings.AUTH_USER_MODEL, @@ -941,7 +940,7 @@ class Department(models.Model): related_name='headed_departments', help_text='Department head/manager' ) - + # Contact Information phone = models.CharField( max_length=20, @@ -960,7 +959,7 @@ class Department(models.Model): null=True, help_text='Department email' ) - + # Location building = models.CharField( max_length=50, @@ -986,7 +985,7 @@ class Department(models.Model): null=True, help_text='Room numbers (e.g., 101-110, 201A-205C)' ) - + # Operational Information is_active = models.BooleanField( default=True, @@ -1001,7 +1000,7 @@ class Department(models.Model): blank=True, help_text='Operating hours by day of week' ) - + # Budget and Cost Center cost_center_code = models.CharField( max_length=20, @@ -1015,7 +1014,7 @@ class Department(models.Model): null=True, help_text='Budget code' ) - + # Staffing authorized_positions = models.PositiveIntegerField( default=0, @@ -1025,7 +1024,7 @@ class Department(models.Model): default=0, help_text='Current number of staff members' ) - + # Quality and Compliance accreditation_required = models.BooleanField( default=False, @@ -1047,7 +1046,7 @@ class Department(models.Model): null=True, help_text='Next scheduled inspection date' ) - + # Metadata created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @@ -1059,7 +1058,7 @@ class Department(models.Model): related_name='created_departments', help_text='User who created the department' ) - + class Meta: db_table = 'core_department' verbose_name = 'Department' @@ -1072,24 +1071,24 @@ class Department(models.Model): models.Index(fields=['parent_department']), ] unique_together = ['tenant', 'code'] - + def __str__(self): return f"{self.name} ({self.code})" - + @property def full_name(self): """Return full department name with parent if applicable""" if self.parent_department: return f"{self.parent_department.name} - {self.name}" return self.name - + @property def staffing_percentage(self): """Calculate current staffing percentage""" if self.authorized_positions > 0: return (self.current_staff_count / self.authorized_positions) * 100 return 0 - + def get_all_sub_departments(self): """Get all sub-departments recursively""" sub_departments = [] diff --git a/db.sqlite3 b/db.sqlite3 index e52372a3..80274949 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/emr/__pycache__/flows.cpython-312.pyc b/emr/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..a9dc1af6 Binary files /dev/null and b/emr/__pycache__/flows.cpython-312.pyc differ diff --git a/emr/__pycache__/urls.cpython-312.pyc b/emr/__pycache__/urls.cpython-312.pyc index fe32c7af..cf7bccd7 100644 Binary files a/emr/__pycache__/urls.cpython-312.pyc and b/emr/__pycache__/urls.cpython-312.pyc differ diff --git a/emr/flows.py b/emr/flows.py new file mode 100644 index 00000000..cef76b53 --- /dev/null +++ b/emr/flows.py @@ -0,0 +1,929 @@ +# """ +# Viewflow workflows for EMR app. +# Provides electronic medical record workflows for clinical documentation, care planning, and patient management. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import Encounter, ClinicalNote, ProblemList, CarePlan, NoteTemplate +# from .views import ( +# EncounterInitiationView, PatientAssessmentView, ClinicalDocumentationView, +# ProblemIdentificationView, CarePlanDevelopmentView, TreatmentPlanningView, +# ProgressMonitoringView, DischargePreparationView, QualityReviewView, +# NoteCreationView, NoteReviewView, NoteSigningView +# ) +# +# +# class ClinicalEncounterProcess(Process): +# """ +# Viewflow process model for clinical encounters +# """ +# encounter = ModelField(Encounter, help_text='Associated clinical encounter') +# +# # Process status tracking +# encounter_initiated = models.BooleanField(default=False) +# patient_assessed = models.BooleanField(default=False) +# problems_identified = models.BooleanField(default=False) +# care_plan_developed = models.BooleanField(default=False) +# treatment_planned = models.BooleanField(default=False) +# documentation_completed = models.BooleanField(default=False) +# quality_reviewed = models.BooleanField(default=False) +# encounter_finalized = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Clinical Encounter Process' +# verbose_name_plural = 'Clinical Encounter Processes' +# +# +# class ClinicalEncounterFlow(Flow): +# """ +# Clinical Encounter Workflow +# +# This flow manages the complete clinical encounter process from +# patient assessment through documentation and quality review. +# """ +# +# process_class = ClinicalEncounterProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_encounter) +# .Next(this.initiate_encounter) +# ) +# +# initiate_encounter = ( +# flow_view(EncounterInitiationView) +# .Permission('emr.can_initiate_encounters') +# .Next(this.assess_patient) +# ) +# +# assess_patient = ( +# flow_view(PatientAssessmentView) +# .Permission('emr.can_assess_patients') +# .Next(this.parallel_clinical_work) +# ) +# +# parallel_clinical_work = ( +# flow_func(this.start_parallel_clinical_work) +# .Next(this.identify_problems) +# .Next(this.develop_care_plan) +# .Next(this.plan_treatment) +# ) +# +# identify_problems = ( +# flow_view(ProblemIdentificationView) +# .Permission('emr.can_identify_problems') +# .Next(this.join_clinical_work) +# ) +# +# develop_care_plan = ( +# flow_view(CarePlanDevelopmentView) +# .Permission('emr.can_develop_care_plans') +# .Next(this.join_clinical_work) +# ) +# +# plan_treatment = ( +# flow_view(TreatmentPlanningView) +# .Permission('emr.can_plan_treatment') +# .Next(this.join_clinical_work) +# ) +# +# join_clinical_work = ( +# flow_func(this.join_parallel_clinical_work) +# .Next(this.complete_documentation) +# ) +# +# complete_documentation = ( +# flow_view(ClinicalDocumentationView) +# .Permission('emr.can_complete_documentation') +# .Next(this.review_quality) +# ) +# +# review_quality = ( +# flow_view(QualityReviewView) +# .Permission('emr.can_review_quality') +# .Next(this.finalize_encounter) +# ) +# +# finalize_encounter = ( +# flow_func(this.complete_encounter) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_encounter) +# +# # Flow functions +# def start_encounter(self, activation): +# """Initialize the clinical encounter process""" +# process = activation.process +# encounter = process.encounter +# +# # Update encounter status +# encounter.status = 'IN_PROGRESS' +# encounter.save() +# +# # Send notification to clinical staff +# self.notify_clinical_staff(encounter) +# +# # Check for high-priority encounters +# if encounter.encounter_type in ['EMERGENCY', 'URGENT_CARE']: +# self.notify_priority_encounter(encounter) +# +# def start_parallel_clinical_work(self, activation): +# """Start parallel clinical work tasks""" +# process = activation.process +# +# # Create parallel clinical tasks +# self.create_clinical_tasks(process.encounter) +# +# def join_parallel_clinical_work(self, activation): +# """Wait for all clinical work to complete""" +# process = activation.process +# +# # Check if all clinical work is completed +# if (process.problems_identified and +# process.care_plan_developed and +# process.treatment_planned): +# +# # Proceed to documentation +# self.notify_documentation_ready(process.encounter) +# +# def complete_encounter(self, activation): +# """Finalize the clinical encounter process""" +# process = activation.process +# encounter = process.encounter +# +# # Update encounter status +# encounter.status = 'COMPLETED' +# encounter.end_datetime = timezone.now() +# encounter.save() +# +# # Mark process as completed +# process.encounter_finalized = True +# process.save() +# +# # Send completion notifications +# self.notify_encounter_completion(encounter) +# +# # Update clinical metrics +# self.update_clinical_metrics(encounter) +# +# # Schedule follow-up if needed +# self.schedule_follow_up(encounter) +# +# def end_encounter(self, activation): +# """End the clinical encounter workflow""" +# process = activation.process +# +# # Generate encounter summary report +# self.generate_encounter_summary(process.encounter) +# +# # Helper methods +# def notify_clinical_staff(self, encounter): +# """Notify clinical staff of new encounter""" +# from django.contrib.auth.models import Group +# +# clinical_staff = User.objects.filter( +# groups__name='Clinical Staff' +# ) +# +# for staff in clinical_staff: +# send_mail( +# subject=f'New Clinical Encounter: {encounter.patient.get_full_name()}', +# message=f'New {encounter.get_encounter_type_display()} encounter started.', +# from_email='clinical@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_priority_encounter(self, encounter): +# """Notify of priority encounter""" +# supervisors = User.objects.filter( +# groups__name='Clinical Supervisors' +# ) +# +# for supervisor in supervisors: +# send_mail( +# subject=f'PRIORITY Encounter: {encounter.patient.get_full_name()}', +# message=f'{encounter.get_encounter_type_display()} encounter requires immediate attention.', +# from_email='clinical@hospital.com', +# recipient_list=[supervisor.email], +# fail_silently=True +# ) +# +# def create_clinical_tasks(self, encounter): +# """Create clinical work tasks""" +# # This would create tasks in a task management system +# pass +# +# def notify_documentation_ready(self, encounter): +# """Notify that documentation is ready""" +# if encounter.provider and encounter.provider.email: +# send_mail( +# subject=f'Documentation Ready: {encounter.patient.get_full_name()}', +# message=f'Clinical work completed, ready for documentation.', +# from_email='clinical@hospital.com', +# recipient_list=[encounter.provider.email], +# fail_silently=True +# ) +# +# def notify_encounter_completion(self, encounter): +# """Notify encounter completion""" +# # Notify care team +# care_team = encounter.care_team.all() +# for member in care_team: +# if member.email: +# send_mail( +# subject=f'Encounter Completed: {encounter.patient.get_full_name()}', +# message=f'Clinical encounter has been completed and documented.', +# from_email='clinical@hospital.com', +# recipient_list=[member.email], +# fail_silently=True +# ) +# +# def update_clinical_metrics(self, encounter): +# """Update clinical quality metrics""" +# # This would update clinical performance metrics +# pass +# +# def schedule_follow_up(self, encounter): +# """Schedule follow-up appointments if needed""" +# # This would schedule follow-up appointments +# pass +# +# def generate_encounter_summary(self, encounter): +# """Generate encounter summary report""" +# # This would generate a comprehensive encounter report +# pass +# +# +# class ClinicalDocumentationProcess(Process): +# """ +# Viewflow process model for clinical documentation +# """ +# clinical_note = ModelField(ClinicalNote, help_text='Associated clinical note') +# +# # Process status tracking +# note_initiated = models.BooleanField(default=False) +# content_drafted = models.BooleanField(default=False) +# clinical_review_completed = models.BooleanField(default=False) +# quality_check_completed = models.BooleanField(default=False) +# note_signed = models.BooleanField(default=False) +# note_finalized = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Clinical Documentation Process' +# verbose_name_plural = 'Clinical Documentation Processes' +# +# +# class ClinicalDocumentationFlow(Flow): +# """ +# Clinical Documentation Workflow +# +# This flow manages clinical note creation, review, and finalization +# with quality checks and electronic signatures. +# """ +# +# process_class = ClinicalDocumentationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_documentation) +# .Next(this.create_note) +# ) +# +# create_note = ( +# flow_view(NoteCreationView) +# .Permission('emr.can_create_notes') +# .Next(this.draft_content) +# ) +# +# draft_content = ( +# flow_view(NoteDraftingView) +# .Permission('emr.can_draft_notes') +# .Next(this.review_note) +# ) +# +# review_note = ( +# flow_view(NoteReviewView) +# .Permission('emr.can_review_notes') +# .Next(this.quality_check) +# ) +# +# quality_check = ( +# flow_view(NoteQualityCheckView) +# .Permission('emr.can_quality_check_notes') +# .Next(this.sign_note) +# ) +# +# sign_note = ( +# flow_view(NoteSigningView) +# .Permission('emr.can_sign_notes') +# .Next(this.finalize_note) +# ) +# +# finalize_note = ( +# flow_func(this.complete_documentation) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_documentation) +# +# # Flow functions +# def start_documentation(self, activation): +# """Initialize the documentation process""" +# process = activation.process +# note = process.clinical_note +# +# # Update note status +# note.status = 'DRAFT' +# note.save() +# +# # Send notification to documenting provider +# self.notify_documentation_required(note) +# +# def complete_documentation(self, activation): +# """Finalize the documentation process""" +# process = activation.process +# note = process.clinical_note +# +# # Update note status +# note.status = 'FINAL' +# note.finalized_datetime = timezone.now() +# note.save() +# +# # Mark process as completed +# process.note_finalized = True +# process.save() +# +# # Send completion notifications +# self.notify_documentation_completion(note) +# +# # Update documentation metrics +# self.update_documentation_metrics(note) +# +# def end_documentation(self, activation): +# """End the documentation workflow""" +# process = activation.process +# +# # Generate documentation summary +# self.generate_documentation_summary(process.clinical_note) +# +# # Helper methods +# def notify_documentation_required(self, note): +# """Notify provider that documentation is required""" +# if note.author and note.author.email: +# send_mail( +# subject=f'Documentation Required: {note.patient.get_full_name()}', +# message=f'{note.get_note_type_display()} requires completion.', +# from_email='documentation@hospital.com', +# recipient_list=[note.author.email], +# fail_silently=True +# ) +# +# def notify_documentation_completion(self, note): +# """Notify documentation completion""" +# # Notify care team +# if note.encounter: +# care_team = note.encounter.care_team.all() +# for member in care_team: +# if member.email: +# send_mail( +# subject=f'Documentation Complete: {note.patient.get_full_name()}', +# message=f'{note.get_note_type_display()} has been completed and signed.', +# from_email='documentation@hospital.com', +# recipient_list=[member.email], +# fail_silently=True +# ) +# +# def update_documentation_metrics(self, note): +# """Update documentation quality metrics""" +# # This would update documentation performance metrics +# pass +# +# def generate_documentation_summary(self, note): +# """Generate documentation summary""" +# # This would generate documentation summary +# pass +# +# +# class CarePlanManagementProcess(Process): +# """ +# Viewflow process model for care plan management +# """ +# care_plan = ModelField(CarePlan, help_text='Associated care plan') +# +# # Process status tracking +# plan_initiated = models.BooleanField(default=False) +# assessment_completed = models.BooleanField(default=False) +# goals_established = models.BooleanField(default=False) +# interventions_planned = models.BooleanField(default=False) +# team_assigned = models.BooleanField(default=False) +# plan_approved = models.BooleanField(default=False) +# implementation_started = models.BooleanField(default=False) +# progress_monitored = models.BooleanField(default=False) +# plan_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Care Plan Management Process' +# verbose_name_plural = 'Care Plan Management Processes' +# +# +# class CarePlanManagementFlow(Flow): +# """ +# Care Plan Management Workflow +# +# This flow manages care plan development, approval, implementation, +# and monitoring with multidisciplinary team coordination. +# """ +# +# process_class = CarePlanManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_care_planning) +# .Next(this.initiate_plan) +# ) +# +# initiate_plan = ( +# flow_view(CarePlanInitiationView) +# .Permission('emr.can_initiate_care_plans') +# .Next(this.complete_assessment) +# ) +# +# complete_assessment = ( +# flow_view(CarePlanAssessmentView) +# .Permission('emr.can_assess_care_plans') +# .Next(this.establish_goals) +# ) +# +# establish_goals = ( +# flow_view(GoalEstablishmentView) +# .Permission('emr.can_establish_goals') +# .Next(this.plan_interventions) +# ) +# +# plan_interventions = ( +# flow_view(InterventionPlanningView) +# .Permission('emr.can_plan_interventions') +# .Next(this.assign_care_team) +# ) +# +# assign_care_team = ( +# flow_view(CareTeamAssignmentView) +# .Permission('emr.can_assign_care_team') +# .Next(this.approve_plan) +# ) +# +# approve_plan = ( +# flow_view(CarePlanApprovalView) +# .Permission('emr.can_approve_care_plans') +# .Next(this.implement_plan) +# ) +# +# implement_plan = ( +# flow_func(this.start_implementation) +# .Next(this.monitor_progress) +# ) +# +# monitor_progress = ( +# flow_view(ProgressMonitoringView) +# .Permission('emr.can_monitor_progress') +# .Next(this.complete_plan) +# ) +# +# complete_plan = ( +# flow_func(this.finalize_care_plan) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_care_planning) +# +# # Flow functions +# def start_care_planning(self, activation): +# """Initialize the care planning process""" +# process = activation.process +# plan = process.care_plan +# +# # Update plan status +# plan.status = 'DRAFT' +# plan.save() +# +# # Send notification to care team +# self.notify_care_planning_start(plan) +# +# def start_implementation(self, activation): +# """Start care plan implementation""" +# process = activation.process +# plan = process.care_plan +# +# # Update plan status +# plan.status = 'ACTIVE' +# plan.save() +# +# # Mark implementation started +# process.implementation_started = True +# process.save() +# +# # Notify care team of implementation +# self.notify_implementation_start(plan) +# +# # Schedule monitoring activities +# self.schedule_monitoring(plan) +# +# def finalize_care_plan(self, activation): +# """Finalize the care plan process""" +# process = activation.process +# plan = process.care_plan +# +# # Update plan status based on completion +# if plan.completion_percentage >= 100: +# plan.status = 'COMPLETED' +# else: +# plan.status = 'ON_HOLD' +# +# plan.save() +# +# # Mark process as completed +# process.plan_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_care_plan_completion(plan) +# +# # Generate outcomes report +# self.generate_outcomes_report(plan) +# +# def end_care_planning(self, activation): +# """End the care planning workflow""" +# process = activation.process +# +# # Generate care plan summary +# self.generate_care_plan_summary(process.care_plan) +# +# # Helper methods +# def notify_care_planning_start(self, plan): +# """Notify care team of care planning start""" +# care_team = plan.care_team.all() +# for member in care_team: +# if member.email: +# send_mail( +# subject=f'Care Plan Development: {plan.patient.get_full_name()}', +# message=f'Care plan development has started for {plan.title}.', +# from_email='careplanning@hospital.com', +# recipient_list=[member.email], +# fail_silently=True +# ) +# +# def notify_implementation_start(self, plan): +# """Notify care team of implementation start""" +# care_team = plan.care_team.all() +# for member in care_team: +# if member.email: +# send_mail( +# subject=f'Care Plan Implementation: {plan.patient.get_full_name()}', +# message=f'Care plan implementation has started for {plan.title}.', +# from_email='careplanning@hospital.com', +# recipient_list=[member.email], +# fail_silently=True +# ) +# +# def schedule_monitoring(self, plan): +# """Schedule monitoring activities""" +# # This would schedule monitoring tasks +# pass +# +# def notify_care_plan_completion(self, plan): +# """Notify care plan completion""" +# # Notify patient if email available +# if plan.patient.email: +# send_mail( +# subject='Care Plan Completed', +# message=f'Your care plan "{plan.title}" has been completed.', +# from_email='careplanning@hospital.com', +# recipient_list=[plan.patient.email], +# fail_silently=True +# ) +# +# def generate_outcomes_report(self, plan): +# """Generate care plan outcomes report""" +# # This would generate outcomes report +# pass +# +# def generate_care_plan_summary(self, plan): +# """Generate care plan summary""" +# # This would generate care plan summary +# pass +# +# +# class ProblemManagementProcess(Process): +# """ +# Viewflow process model for problem management +# """ +# problem = ModelField(ProblemList, help_text='Associated problem') +# +# # Process status tracking +# problem_identified = models.BooleanField(default=False) +# problem_assessed = models.BooleanField(default=False) +# treatment_planned = models.BooleanField(default=False) +# interventions_implemented = models.BooleanField(default=False) +# progress_monitored = models.BooleanField(default=False) +# problem_resolved = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Problem Management Process' +# verbose_name_plural = 'Problem Management Processes' +# +# +# class ProblemManagementFlow(Flow): +# """ +# Problem Management Workflow +# +# This flow manages clinical problem identification, assessment, +# treatment planning, and resolution tracking. +# """ +# +# process_class = ProblemManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_problem_management) +# .Next(this.identify_problem) +# ) +# +# identify_problem = ( +# flow_view(ProblemIdentificationView) +# .Permission('emr.can_identify_problems') +# .Next(this.assess_problem) +# ) +# +# assess_problem = ( +# flow_view(ProblemAssessmentView) +# .Permission('emr.can_assess_problems') +# .Next(this.plan_treatment) +# ) +# +# plan_treatment = ( +# flow_view(TreatmentPlanningView) +# .Permission('emr.can_plan_treatment') +# .Next(this.implement_interventions) +# ) +# +# implement_interventions = ( +# flow_view(InterventionImplementationView) +# .Permission('emr.can_implement_interventions') +# .Next(this.monitor_progress) +# ) +# +# monitor_progress = ( +# flow_view(ProgressMonitoringView) +# .Permission('emr.can_monitor_progress') +# .Next(this.resolve_problem) +# ) +# +# resolve_problem = ( +# flow_func(this.complete_problem_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_problem_management) +# +# # Flow functions +# def start_problem_management(self, activation): +# """Initialize the problem management process""" +# process = activation.process +# problem = process.problem +# +# # Update problem status +# problem.status = 'ACTIVE' +# problem.save() +# +# # Send notification to care team +# self.notify_problem_identified(problem) +# +# def complete_problem_management(self, activation): +# """Finalize the problem management process""" +# process = activation.process +# problem = process.problem +# +# # Update problem status +# if problem.resolution_date: +# problem.status = 'RESOLVED' +# else: +# problem.status = 'ONGOING' +# +# problem.save() +# +# # Mark process as completed +# process.problem_resolved = True +# process.save() +# +# # Send completion notifications +# self.notify_problem_resolution(problem) +# +# def end_problem_management(self, activation): +# """End the problem management workflow""" +# process = activation.process +# +# # Generate problem summary +# self.generate_problem_summary(process.problem) +# +# # Helper methods +# def notify_problem_identified(self, problem): +# """Notify care team of problem identification""" +# # This would notify the care team +# pass +# +# def notify_problem_resolution(self, problem): +# """Notify problem resolution""" +# # This would notify relevant parties +# pass +# +# def generate_problem_summary(self, problem): +# """Generate problem management summary""" +# # This would generate problem summary +# pass +# +# +# class QualityAssuranceProcess(Process): +# """ +# Viewflow process model for clinical quality assurance +# """ +# encounter_id = CharField(max_length=50, help_text='Encounter identifier') +# review_type = CharField(max_length=20, help_text='Type of quality review') +# +# # Process status tracking +# review_initiated = models.BooleanField(default=False) +# documentation_reviewed = models.BooleanField(default=False) +# clinical_indicators_checked = models.BooleanField(default=False) +# compliance_verified = models.BooleanField(default=False) +# feedback_provided = models.BooleanField(default=False) +# quality_review_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Quality Assurance Process' +# verbose_name_plural = 'Quality Assurance Processes' +# +# +# class QualityAssuranceFlow(Flow): +# """ +# Clinical Quality Assurance Workflow +# +# This flow manages clinical quality reviews including documentation +# quality, clinical indicators, and compliance verification. +# """ +# +# process_class = QualityAssuranceProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_quality_review) +# .Next(this.review_documentation) +# ) +# +# review_documentation = ( +# flow_view(DocumentationReviewView) +# .Permission('emr.can_review_documentation') +# .Next(this.check_clinical_indicators) +# ) +# +# check_clinical_indicators = ( +# flow_view(ClinicalIndicatorCheckView) +# .Permission('emr.can_check_clinical_indicators') +# .Next(this.verify_compliance) +# ) +# +# verify_compliance = ( +# flow_view(ComplianceVerificationView) +# .Permission('emr.can_verify_compliance') +# .Next(this.provide_feedback) +# ) +# +# provide_feedback = ( +# flow_view(QualityFeedbackView) +# .Permission('emr.can_provide_quality_feedback') +# .Next(this.complete_review) +# ) +# +# complete_review = ( +# flow_func(this.finalize_quality_review) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_quality_review) +# +# # Flow functions +# def start_quality_review(self, activation): +# """Initialize the quality review process""" +# process = activation.process +# +# # Notify quality staff +# self.notify_quality_staff(process.encounter_id, process.review_type) +# +# def finalize_quality_review(self, activation): +# """Finalize the quality review process""" +# process = activation.process +# +# # Mark review as completed +# process.quality_review_completed = True +# process.save() +# +# # Generate quality report +# self.generate_quality_report(process.encounter_id, process.review_type) +# +# def end_quality_review(self, activation): +# """End the quality review workflow""" +# process = activation.process +# +# # Update quality metrics +# self.update_quality_metrics(process.encounter_id, process.review_type) +# +# # Helper methods +# def notify_quality_staff(self, encounter_id, review_type): +# """Notify quality staff""" +# quality_staff = User.objects.filter( +# groups__name='Quality Assurance' +# ) +# +# for staff in quality_staff: +# send_mail( +# subject=f'Quality Review Required: {encounter_id}', +# message=f'{review_type} quality review required for encounter {encounter_id}.', +# from_email='quality@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def generate_quality_report(self, encounter_id, review_type): +# """Generate quality report""" +# # This would generate quality report +# pass +# +# def update_quality_metrics(self, encounter_id, review_type): +# """Update quality metrics""" +# # This would update quality metrics +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_generate_care_plans(): +# """Background task to automatically generate care plans""" +# try: +# # This would generate care plans based on problems +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_documentation_compliance(): +# """Background task to monitor documentation compliance""" +# try: +# # This would monitor documentation timeliness +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_clinical_reports(): +# """Background task to generate clinical reports""" +# try: +# # This would generate clinical quality reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_schedule_care_plan_reviews(): +# """Background task to schedule care plan reviews""" +# try: +# # This would schedule care plan reviews +# return True +# except Exception: +# return False +# +# +# @celery.job +# def identify_quality_indicators(): +# """Background task to identify quality indicators""" +# try: +# # This would identify quality improvement opportunities +# return True +# except Exception: +# return False +# diff --git a/emr/urls.py b/emr/urls.py index 71c27d78..3ca745f7 100644 --- a/emr/urls.py +++ b/emr/urls.py @@ -11,7 +11,7 @@ urlpatterns = [ # Main views path('', views.EMRDashboardView.as_view(), name='dashboard'), path('encounters/', views.EncounterListView.as_view(), name='encounter_list'), - path('encounters//', views.EncounterDetailView.as_view(), name='encounter_detail'), + path('encounters//', views.EncounterDetailView.as_view(), name='encounter_detail'), # path('encounters//update/', views.EncounterUpdateView.as_view(), name='encounter_update'), # path('encounters//delete/', views.EncounterDeleteView.as_view(), name='encounter_delete'), path('encounters/create/', views.EncounterCreateView.as_view(), name='encounter_create'), diff --git a/hospital_management/__pycache__/settings.cpython-312.pyc b/hospital_management/__pycache__/settings.cpython-312.pyc index dbcf00eb..fad854ec 100644 Binary files a/hospital_management/__pycache__/settings.cpython-312.pyc and b/hospital_management/__pycache__/settings.cpython-312.pyc differ diff --git a/hospital_management/settings.py b/hospital_management/settings.py index d5b04d12..41bce3d5 100644 --- a/hospital_management/settings.py +++ b/hospital_management/settings.py @@ -46,6 +46,8 @@ THIRD_PARTY_APPS = [ 'corsheaders', 'django_extensions', 'allauth', + 'viewflow', + 'viewflow.workflow', # 'allauth.socialaccount', ] diff --git a/hr/__pycache__/flows.cpython-312.pyc b/hr/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..58e95d4f Binary files /dev/null and b/hr/__pycache__/flows.cpython-312.pyc differ diff --git a/hr/__pycache__/models.cpython-312.pyc b/hr/__pycache__/models.cpython-312.pyc index ccfa36e3..21574f34 100644 Binary files a/hr/__pycache__/models.cpython-312.pyc and b/hr/__pycache__/models.cpython-312.pyc differ diff --git a/hr/__pycache__/urls.cpython-312.pyc b/hr/__pycache__/urls.cpython-312.pyc index 0ae99261..8ff4cc55 100644 Binary files a/hr/__pycache__/urls.cpython-312.pyc and b/hr/__pycache__/urls.cpython-312.pyc differ diff --git a/hr/__pycache__/views.cpython-312.pyc b/hr/__pycache__/views.cpython-312.pyc index 65d387e8..cedb4c60 100644 Binary files a/hr/__pycache__/views.cpython-312.pyc and b/hr/__pycache__/views.cpython-312.pyc differ diff --git a/hr/flows.py b/hr/flows.py new file mode 100644 index 00000000..4aefd4c2 --- /dev/null +++ b/hr/flows.py @@ -0,0 +1,846 @@ +# """ +# Viewflow workflows for HR app. +# Provides employee onboarding, performance review, and training workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import Employee, PerformanceReview, TrainingRecord +# from .views import ( +# EmployeeOnboardingView, DocumentCollectionView, SystemAccessSetupView, +# OrientationSchedulingView, PerformanceReviewInitiationView, +# SelfAssessmentView, ManagerReviewView, ReviewMeetingView, +# TrainingNeedsAssessmentView, TrainingSchedulingView, TrainingDeliveryView, +# TrainingEvaluationView +# ) +# +# +# class EmployeeOnboardingProcess(Process): +# """ +# Viewflow process model for employee onboarding +# """ +# employee = ModelField(Employee, help_text='Associated employee') +# +# # Process status tracking +# employee_created = models.BooleanField(default=False) +# documents_collected = models.BooleanField(default=False) +# system_access_setup = models.BooleanField(default=False) +# orientation_scheduled = models.BooleanField(default=False) +# orientation_completed = models.BooleanField(default=False) +# probationary_review_scheduled = models.BooleanField(default=False) +# onboarding_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Employee Onboarding Process' +# verbose_name_plural = 'Employee Onboarding Processes' +# +# +# class EmployeeOnboardingFlow(Flow): +# """ +# Employee Onboarding Workflow +# +# This flow manages the complete employee onboarding process from +# initial setup through orientation and probationary period setup. +# """ +# +# process_class = EmployeeOnboardingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_onboarding) +# .Next(this.create_employee_record) +# ) +# +# create_employee_record = ( +# flow_view(EmployeeOnboardingView) +# .Permission('hr.can_create_employees') +# .Next(this.collect_documents) +# ) +# +# collect_documents = ( +# flow_view(DocumentCollectionView) +# .Permission('hr.can_collect_documents') +# .Next(this.setup_system_access) +# ) +# +# setup_system_access = ( +# flow_view(SystemAccessSetupView) +# .Permission('hr.can_setup_system_access') +# .Next(this.schedule_orientation) +# ) +# +# schedule_orientation = ( +# flow_view(OrientationSchedulingView) +# .Permission('hr.can_schedule_orientation') +# .Next(this.conduct_orientation) +# ) +# +# conduct_orientation = ( +# flow_view(OrientationDeliveryView) +# .Permission('hr.can_conduct_orientation') +# .Next(this.schedule_probationary_review) +# ) +# +# schedule_probationary_review = ( +# flow_func(this.setup_probationary_review) +# .Next(this.finalize_onboarding) +# ) +# +# finalize_onboarding = ( +# flow_func(this.complete_onboarding) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_onboarding) +# +# # Flow functions +# def start_onboarding(self, activation): +# """Initialize the onboarding process""" +# process = activation.process +# employee = process.employee +# +# # Send welcome notification +# self.send_welcome_notification(employee) +# +# # Notify HR staff +# self.notify_hr_staff(employee) +# +# def setup_probationary_review(self, activation): +# """Setup probationary review""" +# process = activation.process +# employee = process.employee +# +# # Schedule probationary review (typically 90 days) +# review_date = timezone.now().date() + timezone.timedelta(days=90) +# +# # Create probationary review record +# PerformanceReview.objects.create( +# employee=employee, +# review_period_start=employee.hire_date, +# review_period_end=review_date, +# review_date=review_date, +# review_type='PROBATIONARY', +# status='DRAFT' +# ) +# +# process.probationary_review_scheduled = True +# process.save() +# +# # Notify manager +# self.notify_manager_probationary_review(employee, review_date) +# +# def complete_onboarding(self, activation): +# """Finalize the onboarding process""" +# process = activation.process +# employee = process.employee +# +# # Update employee status +# employee.employment_status = 'ACTIVE' +# employee.save() +# +# # Mark process as completed +# process.onboarding_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_onboarding_completion(employee) +# +# def end_onboarding(self, activation): +# """End the onboarding workflow""" +# process = activation.process +# +# # Generate onboarding summary report +# self.generate_onboarding_summary(process.employee) +# +# # Helper methods +# def send_welcome_notification(self, employee): +# """Send welcome notification to new employee""" +# if employee.email: +# send_mail( +# subject=f'Welcome to {employee.tenant.name}!', +# message=f'Welcome {employee.first_name}! Your onboarding process has begun.', +# from_email='hr@hospital.com', +# recipient_list=[employee.email], +# fail_silently=True +# ) +# +# def notify_hr_staff(self, employee): +# """Notify HR staff of new employee onboarding""" +# from django.contrib.auth.models import Group +# +# hr_staff = User.objects.filter( +# groups__name='HR Staff' +# ) +# +# for staff in hr_staff: +# send_mail( +# subject=f'New Employee Onboarding: {employee.get_full_name()}', +# message=f'New employee {employee.get_full_name()} onboarding has started.', +# from_email='hr@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_manager_probationary_review(self, employee, review_date): +# """Notify manager of upcoming probationary review""" +# if employee.manager and employee.manager.email: +# send_mail( +# subject=f'Probationary Review Scheduled: {employee.get_full_name()}', +# message=f'Probationary review scheduled for {review_date}.', +# from_email='hr@hospital.com', +# recipient_list=[employee.manager.email], +# fail_silently=True +# ) +# +# def notify_onboarding_completion(self, employee): +# """Notify relevant parties of onboarding completion""" +# # Notify employee +# if employee.email: +# send_mail( +# subject='Onboarding Complete', +# message=f'Congratulations {employee.first_name}! Your onboarding is complete.', +# from_email='hr@hospital.com', +# recipient_list=[employee.email], +# fail_silently=True +# ) +# +# # Notify manager +# if employee.manager and employee.manager.email: +# send_mail( +# subject=f'Employee Onboarding Complete: {employee.get_full_name()}', +# message=f'{employee.get_full_name()} has completed onboarding.', +# from_email='hr@hospital.com', +# recipient_list=[employee.manager.email], +# fail_silently=True +# ) +# +# def generate_onboarding_summary(self, employee): +# """Generate onboarding summary report""" +# # This would generate a comprehensive onboarding report +# pass +# +# +# class PerformanceReviewProcess(Process): +# """ +# Viewflow process model for performance reviews +# """ +# performance_review = ModelField(PerformanceReview, help_text='Associated performance review') +# +# # Process status tracking +# review_initiated = models.BooleanField(default=False) +# self_assessment_completed = models.BooleanField(default=False) +# manager_review_completed = models.BooleanField(default=False) +# review_meeting_held = models.BooleanField(default=False) +# employee_acknowledged = models.BooleanField(default=False) +# development_plan_created = models.BooleanField(default=False) +# review_finalized = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Performance Review Process' +# verbose_name_plural = 'Performance Review Processes' +# +# +# class PerformanceReviewFlow(Flow): +# """ +# Performance Review Workflow +# +# This flow manages the complete performance review process including +# self-assessment, manager review, meeting, and development planning. +# """ +# +# process_class = PerformanceReviewProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_performance_review) +# .Next(this.initiate_review) +# ) +# +# initiate_review = ( +# flow_view(PerformanceReviewInitiationView) +# .Permission('hr.can_initiate_reviews') +# .Next(this.employee_self_assessment) +# ) +# +# employee_self_assessment = ( +# flow_view(SelfAssessmentView) +# .Permission('hr.can_complete_self_assessment') +# .Next(this.manager_review) +# ) +# +# manager_review = ( +# flow_view(ManagerReviewView) +# .Permission('hr.can_conduct_manager_review') +# .Next(this.review_meeting) +# ) +# +# review_meeting = ( +# flow_view(ReviewMeetingView) +# .Permission('hr.can_conduct_review_meeting') +# .Next(this.employee_acknowledgment) +# ) +# +# employee_acknowledgment = ( +# flow_view(EmployeeAcknowledgmentView) +# .Permission('hr.can_acknowledge_review') +# .Next(this.create_development_plan) +# ) +# +# create_development_plan = ( +# flow_view(DevelopmentPlanView) +# .Permission('hr.can_create_development_plan') +# .Next(this.finalize_review) +# ) +# +# finalize_review = ( +# flow_func(this.complete_performance_review) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_performance_review) +# +# # Flow functions +# def start_performance_review(self, activation): +# """Initialize the performance review process""" +# process = activation.process +# review = process.performance_review +# +# # Update review status +# review.status = 'IN_PROGRESS' +# review.save() +# +# # Notify employee and manager +# self.notify_review_start(review) +# +# def complete_performance_review(self, activation): +# """Finalize the performance review process""" +# process = activation.process +# review = process.performance_review +# +# # Update review status +# review.status = 'COMPLETED' +# review.save() +# +# # Mark process as completed +# process.review_finalized = True +# process.save() +# +# # Schedule next review +# self.schedule_next_review(review) +# +# # Send completion notifications +# self.notify_review_completion(review) +# +# def end_performance_review(self, activation): +# """End the performance review workflow""" +# process = activation.process +# +# # Generate review summary report +# self.generate_review_summary(process.performance_review) +# +# # Helper methods +# def notify_review_start(self, review): +# """Notify employee and manager of review start""" +# # Notify employee +# if review.employee.email: +# send_mail( +# subject='Performance Review Started', +# message=f'Your {review.get_review_type_display()} has been initiated.', +# from_email='hr@hospital.com', +# recipient_list=[review.employee.email], +# fail_silently=True +# ) +# +# # Notify manager +# if review.employee.manager and review.employee.manager.email: +# send_mail( +# subject=f'Performance Review: {review.employee.get_full_name()}', +# message=f'Performance review for {review.employee.get_full_name()} has started.', +# from_email='hr@hospital.com', +# recipient_list=[review.employee.manager.email], +# fail_silently=True +# ) +# +# def schedule_next_review(self, review): +# """Schedule next performance review""" +# if review.review_type == 'ANNUAL': +# # Schedule next annual review +# next_review_date = review.review_date + timezone.timedelta(days=365) +# +# PerformanceReview.objects.create( +# employee=review.employee, +# review_period_start=review.review_period_end + timezone.timedelta(days=1), +# review_period_end=next_review_date, +# review_date=next_review_date, +# review_type='ANNUAL', +# status='DRAFT' +# ) +# +# def notify_review_completion(self, review): +# """Notify relevant parties of review completion""" +# # Notify employee +# if review.employee.email: +# send_mail( +# subject='Performance Review Complete', +# message=f'Your {review.get_review_type_display()} has been completed.', +# from_email='hr@hospital.com', +# recipient_list=[review.employee.email], +# fail_silently=True +# ) +# +# # Notify HR +# hr_staff = User.objects.filter(groups__name='HR Staff') +# for staff in hr_staff: +# send_mail( +# subject=f'Performance Review Complete: {review.employee.get_full_name()}', +# message=f'Performance review for {review.employee.get_full_name()} has been completed.', +# from_email='hr@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def generate_review_summary(self, review): +# """Generate performance review summary report""" +# # This would generate a comprehensive review report +# pass +# +# +# class TrainingProcess(Process): +# """ +# Viewflow process model for training programs +# """ +# training_record = ModelField(TrainingRecord, help_text='Associated training record') +# +# # Process status tracking +# training_needs_assessed = models.BooleanField(default=False) +# training_scheduled = models.BooleanField(default=False) +# training_delivered = models.BooleanField(default=False) +# training_evaluated = models.BooleanField(default=False) +# certification_issued = models.BooleanField(default=False) +# follow_up_scheduled = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Training Process' +# verbose_name_plural = 'Training Processes' +# +# +# class TrainingFlow(Flow): +# """ +# Training Workflow +# +# This flow manages training programs including needs assessment, +# scheduling, delivery, evaluation, and certification. +# """ +# +# process_class = TrainingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_training) +# .Next(this.assess_training_needs) +# ) +# +# assess_training_needs = ( +# flow_view(TrainingNeedsAssessmentView) +# .Permission('hr.can_assess_training_needs') +# .Next(this.schedule_training) +# ) +# +# schedule_training = ( +# flow_view(TrainingSchedulingView) +# .Permission('hr.can_schedule_training') +# .Next(this.deliver_training) +# ) +# +# deliver_training = ( +# flow_view(TrainingDeliveryView) +# .Permission('hr.can_deliver_training') +# .Next(this.evaluate_training) +# ) +# +# evaluate_training = ( +# flow_view(TrainingEvaluationView) +# .Permission('hr.can_evaluate_training') +# .Next(this.issue_certification) +# ) +# +# issue_certification = ( +# flow_func(this.process_certification) +# .Next(this.schedule_follow_up) +# ) +# +# schedule_follow_up = ( +# flow_func(this.setup_follow_up) +# .Next(this.finalize_training) +# ) +# +# finalize_training = ( +# flow_func(this.complete_training) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_training) +# +# # Flow functions +# def start_training(self, activation): +# """Initialize the training process""" +# process = activation.process +# training = process.training_record +# +# # Update training status +# training.status = 'SCHEDULED' +# training.save() +# +# # Notify employee and manager +# self.notify_training_start(training) +# +# def process_certification(self, activation): +# """Process certification if training passed""" +# process = activation.process +# training = process.training_record +# +# if training.passed and training.training_type == 'CERTIFICATION': +# # Generate certificate number +# training.certificate_number = self.generate_certificate_number() +# training.save() +# +# process.certification_issued = True +# process.save() +# +# # Notify employee of certification +# self.notify_certification_issued(training) +# +# def setup_follow_up(self, activation): +# """Setup follow-up training if needed""" +# process = activation.process +# training = process.training_record +# +# # Schedule follow-up based on training type +# if training.training_type in ['CERTIFICATION', 'MANDATORY']: +# if training.expiry_date: +# # Schedule renewal training +# renewal_date = training.expiry_date - timezone.timedelta(days=30) +# self.schedule_renewal_training(training, renewal_date) +# +# process.follow_up_scheduled = True +# process.save() +# +# def complete_training(self, activation): +# """Finalize the training process""" +# process = activation.process +# training = process.training_record +# +# # Update training status +# if training.passed: +# training.status = 'COMPLETED' +# else: +# training.status = 'FAILED' +# +# training.completion_date = timezone.now().date() +# training.save() +# +# # Send completion notifications +# self.notify_training_completion(training) +# +# def end_training(self, activation): +# """End the training workflow""" +# process = activation.process +# +# # Generate training summary report +# self.generate_training_summary(process.training_record) +# +# # Helper methods +# def notify_training_start(self, training): +# """Notify employee and manager of training start""" +# # Notify employee +# if training.employee.email: +# send_mail( +# subject=f'Training Scheduled: {training.training_name}', +# message=f'Your training "{training.training_name}" has been scheduled for {training.training_date}.', +# from_email='hr@hospital.com', +# recipient_list=[training.employee.email], +# fail_silently=True +# ) +# +# # Notify manager +# if training.employee.manager and training.employee.manager.email: +# send_mail( +# subject=f'Employee Training: {training.employee.get_full_name()}', +# message=f'{training.employee.get_full_name()} has training scheduled: {training.training_name}.', +# from_email='hr@hospital.com', +# recipient_list=[training.employee.manager.email], +# fail_silently=True +# ) +# +# def generate_certificate_number(self): +# """Generate unique certificate number""" +# from django.utils.crypto import get_random_string +# return f"CERT{timezone.now().strftime('%Y%m%d')}{get_random_string(4, '0123456789')}" +# +# def notify_certification_issued(self, training): +# """Notify employee of certification""" +# if training.employee.email: +# send_mail( +# subject=f'Certification Issued: {training.training_name}', +# message=f'Congratulations! You have been certified in {training.training_name}. Certificate #: {training.certificate_number}', +# from_email='hr@hospital.com', +# recipient_list=[training.employee.email], +# fail_silently=True +# ) +# +# def schedule_renewal_training(self, training, renewal_date): +# """Schedule renewal training""" +# TrainingRecord.objects.create( +# employee=training.employee, +# training_name=f"{training.training_name} - Renewal", +# training_type=training.training_type, +# training_date=renewal_date, +# status='SCHEDULED' +# ) +# +# def notify_training_completion(self, training): +# """Notify relevant parties of training completion""" +# # Notify employee +# if training.employee.email: +# status_text = "completed successfully" if training.passed else "not passed" +# send_mail( +# subject=f'Training {status_text.title()}: {training.training_name}', +# message=f'Your training "{training.training_name}" has been {status_text}.', +# from_email='hr@hospital.com', +# recipient_list=[training.employee.email], +# fail_silently=True +# ) +# +# def generate_training_summary(self, training): +# """Generate training summary report""" +# # This would generate a comprehensive training report +# pass +# +# +# class ComplianceTrackingProcess(Process): +# """ +# Viewflow process model for compliance tracking +# """ +# employee_id = CharField(max_length=50, help_text='Employee identifier') +# compliance_type = CharField(max_length=20, help_text='Type of compliance') +# +# # Process status tracking +# compliance_checked = models.BooleanField(default=False) +# deficiencies_identified = models.BooleanField(default=False) +# corrective_actions_planned = models.BooleanField(default=False) +# actions_implemented = models.BooleanField(default=False) +# compliance_verified = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Compliance Tracking Process' +# verbose_name_plural = 'Compliance Tracking Processes' +# +# +# class ComplianceTrackingFlow(Flow): +# """ +# Compliance Tracking Workflow +# +# This flow manages compliance tracking including monitoring, +# deficiency identification, and corrective actions. +# """ +# +# process_class = ComplianceTrackingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_compliance_tracking) +# .Next(this.check_compliance) +# ) +# +# check_compliance = ( +# flow_func(this.monitor_compliance) +# .Next(this.identify_deficiencies) +# ) +# +# identify_deficiencies = ( +# flow_func(this.assess_deficiencies) +# .Next(this.plan_corrective_actions) +# ) +# +# plan_corrective_actions = ( +# flow_view(CorrectiveActionPlanningView) +# .Permission('hr.can_plan_corrective_actions') +# .Next(this.implement_actions) +# ) +# +# implement_actions = ( +# flow_view(CorrectiveActionImplementationView) +# .Permission('hr.can_implement_corrective_actions') +# .Next(this.verify_compliance) +# ) +# +# verify_compliance = ( +# flow_func(this.validate_compliance) +# .Next(this.finalize_compliance) +# ) +# +# finalize_compliance = ( +# flow_func(this.complete_compliance_tracking) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_compliance_tracking) +# +# # Flow functions +# def start_compliance_tracking(self, activation): +# """Initialize the compliance tracking process""" +# process = activation.process +# +# # Log compliance check initiation +# self.log_compliance_check(process.employee_id, process.compliance_type) +# +# def monitor_compliance(self, activation): +# """Monitor employee compliance""" +# process = activation.process +# +# # Check compliance status +# compliance_status = self.check_employee_compliance(process.employee_id, process.compliance_type) +# +# process.compliance_checked = True +# process.save() +# +# if not compliance_status: +# # Alert of compliance issues +# self.alert_compliance_issues(process.employee_id, process.compliance_type) +# +# def assess_deficiencies(self, activation): +# """Assess compliance deficiencies""" +# process = activation.process +# +# # Identify specific deficiencies +# deficiencies = self.identify_compliance_deficiencies(process.employee_id, process.compliance_type) +# +# if deficiencies: +# process.deficiencies_identified = True +# process.save() +# +# # Notify relevant parties +# self.notify_compliance_deficiencies(process.employee_id, deficiencies) +# +# def validate_compliance(self, activation): +# """Validate compliance after corrective actions""" +# process = activation.process +# +# # Re-check compliance +# compliance_status = self.check_employee_compliance(process.employee_id, process.compliance_type) +# +# if compliance_status: +# process.compliance_verified = True +# process.save() +# else: +# # Escalate if still non-compliant +# self.escalate_compliance_issue(process.employee_id, process.compliance_type) +# +# def complete_compliance_tracking(self, activation): +# """Finalize the compliance tracking process""" +# process = activation.process +# +# # Generate compliance report +# self.generate_compliance_report(process.employee_id, process.compliance_type) +# +# def end_compliance_tracking(self, activation): +# """End the compliance tracking workflow""" +# process = activation.process +# +# # Archive compliance tracking +# self.archive_compliance_tracking(process.employee_id, process.compliance_type) +# +# # Helper methods +# def log_compliance_check(self, employee_id, compliance_type): +# """Log compliance check""" +# # This would log the compliance check +# pass +# +# def check_employee_compliance(self, employee_id, compliance_type): +# """Check employee compliance status""" +# # This would check compliance status +# return True +# +# def alert_compliance_issues(self, employee_id, compliance_type): +# """Alert of compliance issues""" +# # This would send compliance alerts +# pass +# +# def identify_compliance_deficiencies(self, employee_id, compliance_type): +# """Identify specific compliance deficiencies""" +# # This would identify deficiencies +# return [] +# +# def notify_compliance_deficiencies(self, employee_id, deficiencies): +# """Notify of compliance deficiencies""" +# # This would send deficiency notifications +# pass +# +# def escalate_compliance_issue(self, employee_id, compliance_type): +# """Escalate compliance issue""" +# # This would escalate the issue +# pass +# +# def generate_compliance_report(self, employee_id, compliance_type): +# """Generate compliance report""" +# # This would generate compliance report +# pass +# +# def archive_compliance_tracking(self, employee_id, compliance_type): +# """Archive compliance tracking""" +# # This would archive the tracking +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_schedule_performance_reviews(): +# """Background task to automatically schedule performance reviews""" +# try: +# # This would schedule upcoming reviews +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_training_expiry(): +# """Background task to monitor training and certification expiry""" +# try: +# # This would monitor expiring certifications +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_hr_compliance_report(): +# """Background task to generate HR compliance reports""" +# try: +# # This would generate compliance reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_assign_mandatory_training(): +# """Background task to automatically assign mandatory training""" +# try: +# # This would assign mandatory training +# return True +# except Exception: +# return False +# diff --git a/hr/migrations/0002_trainingrecord_is_certified.py b/hr/migrations/0002_trainingrecord_is_certified.py new file mode 100644 index 00000000..e80a416d --- /dev/null +++ b/hr/migrations/0002_trainingrecord_is_certified.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.4 on 2025-09-07 14:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("hr", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="trainingrecord", + name="is_certified", + field=models.BooleanField(default=False, help_text="Training is certified"), + ), + ] diff --git a/hr/migrations/__pycache__/0002_trainingrecord_is_certified.cpython-312.pyc b/hr/migrations/__pycache__/0002_trainingrecord_is_certified.cpython-312.pyc new file mode 100644 index 00000000..5d772d29 Binary files /dev/null and b/hr/migrations/__pycache__/0002_trainingrecord_is_certified.cpython-312.pyc differ diff --git a/hr/models.py b/hr/models.py index f0a1c9df..a1240a65 100644 --- a/hr/models.py +++ b/hr/models.py @@ -11,6 +11,8 @@ from django.conf import settings from datetime import timedelta, datetime, date, time from decimal import Decimal import json +from django.core.exceptions import ValidationError + class Employee(models.Model): @@ -157,7 +159,13 @@ class Employee(models.Model): null=True, help_text='Country' ) - + national_id = models.CharField( + max_length=10, + blank=True, + null=True, + unique=True, + help_text='National ID' + ) # Personal Details date_of_birth = models.DateField( blank=True, @@ -391,12 +399,19 @@ class Department(models.Model): """ Department model for organizational structure. """ - + DEPARTMENT_TYPE_CHOICES = [ + ('CLINICAL', 'Clinical'), + ('ADMINISTRATIVE', 'Administrative'), + ('SUPPORT', 'Support'), + ('ANCILLARY', 'Ancillary'), + ('EXECUTIVE', 'Executive'), + ] + # Tenant relationship tenant = models.ForeignKey( 'core.Tenant', on_delete=models.CASCADE, - related_name='hr_departments', + related_name='departments', help_text='Organization tenant' ) @@ -409,7 +424,7 @@ class Department(models.Model): ) department_code = models.CharField( max_length=20, - help_text='Department code' + help_text='Department code (e.g., CARD, EMER, SURG)' ) name = models.CharField( max_length=100, @@ -424,13 +439,7 @@ class Department(models.Model): # Department Type department_type = models.CharField( max_length=20, - choices=[ - ('CLINICAL', 'Clinical'), - ('ADMINISTRATIVE', 'Administrative'), - ('SUPPORT', 'Support'), - ('ANCILLARY', 'Ancillary'), - ('EXECUTIVE', 'Executive'), - ], + choices=DEPARTMENT_TYPE_CHOICES, help_text='Department type' ) @@ -440,7 +449,7 @@ class Department(models.Model): on_delete=models.CASCADE, null=True, blank=True, - related_name='child_departments', + related_name='sub_departments', help_text='Parent department' ) @@ -453,6 +462,24 @@ class Department(models.Model): related_name='headed_departments', help_text='Department head' ) + # Contact Information + phone = models.CharField( + max_length=20, + blank=True, + null=True, + help_text='Department phone number' + ) + extension = models.CharField( + max_length=10, + blank=True, + null=True, + help_text='Phone extension' + ) + email = models.EmailField( + blank=True, + null=True, + help_text='Department email' + ) # Budget Information annual_budget = models.DecimalField( @@ -468,7 +495,10 @@ class Department(models.Model): null=True, help_text='Cost center code' ) - + authorized_positions = models.PositiveIntegerField( + default=0, + help_text='Number of authorized positions' + ) # Location Information location = models.CharField( max_length=100, @@ -477,11 +507,42 @@ class Department(models.Model): help_text='Department location' ) - # Department Status + # Operational Information is_active = models.BooleanField( default=True, help_text='Department is active' ) + is_24_hour = models.BooleanField( + default=False, + help_text='Department operates 24 hours' + ) + operating_hours = models.JSONField( + default=dict, + blank=True, + help_text='Operating hours by day of week' + ) + + # Quality and Compliance + accreditation_required = models.BooleanField( + default=False, + help_text='Department requires special accreditation' + ) + accreditation_body = models.CharField( + max_length=100, + blank=True, + null=True, + help_text='Accrediting body (e.g., Joint Commission, CAP)' + ) + last_inspection_date = models.DateField( + blank=True, + null=True, + help_text='Last inspection date' + ) + next_inspection_date = models.DateField( + blank=True, + null=True, + help_text='Next scheduled inspection date' + ) # Notes notes = models.TextField( @@ -517,7 +578,14 @@ class Department(models.Model): def __str__(self): return f"{self.department_code} - {self.name}" - + + @property + def full_name(self): + """Return full department name with parent if applicable""" + if self.parent_department: + return f"{self.parent_department.name} - {self.name}" + return self.name + @property def employee_count(self): """ @@ -532,12 +600,33 @@ class Department(models.Model): """ return sum(emp.fte_percentage for emp in self.employees.filter(employment_status='ACTIVE')) / 100 + @property + def staffing_percentage(self): + """Calculate current staffing percentage""" + if self.authorized_positions > 0: + return (self.employee_count / self.authorized_positions) * 100 + return 0 + + def get_all_sub_departments(self): + """Get all sub-departments recursively""" + sub_departments = [] + for sub_dept in self.sub_departments.all(): + sub_departments.append(sub_dept) + sub_departments.extend(sub_dept.get_all_sub_departments()) + return sub_departments + class Schedule(models.Model): """ Schedule model for employee work schedules. """ - + SCHEDULE_TYPE_CHOICES = [ + ('REGULAR', 'Regular Schedule'), + ('ROTATING', 'Rotating Schedule'), + ('FLEXIBLE', 'Flexible Schedule'), + ('ON_CALL', 'On-Call Schedule'), + ('TEMPORARY', 'Temporary Schedule'), + ] # Employee relationship employee = models.ForeignKey( Employee, @@ -566,13 +655,7 @@ class Schedule(models.Model): # Schedule Type schedule_type = models.CharField( max_length=20, - choices=[ - ('REGULAR', 'Regular Schedule'), - ('ROTATING', 'Rotating Schedule'), - ('FLEXIBLE', 'Flexible Schedule'), - ('ON_CALL', 'On-Call Schedule'), - ('TEMPORARY', 'Temporary Schedule'), - ], + choices=SCHEDULE_TYPE_CHOICES, help_text='Schedule type' ) @@ -668,7 +751,23 @@ class ScheduleAssignment(models.Model): """ Schedule assignment model for specific shift assignments. """ - + SHIFT_TYPE_CHOICES = [ + ('DAY', 'Day Shift'), + ('EVENING', 'Evening Shift'), + ('NIGHT', 'Night Shift'), + ('WEEKEND', 'Weekend Shift'), + ('HOLIDAY', 'Holiday Shift'), + ('ON_CALL', 'On-Call'), + ('OVERTIME', 'Overtime'), + ] + STATUS_CHOICES = [ + ('SCHEDULED', 'Scheduled'), + ('CONFIRMED', 'Confirmed'), + ('COMPLETED', 'Completed'), + ('CANCELLED', 'Cancelled'), + ('NO_SHOW', 'No Show'), + ] + # Schedule relationship schedule = models.ForeignKey( Schedule, @@ -699,15 +798,7 @@ class ScheduleAssignment(models.Model): # Shift Information shift_type = models.CharField( max_length=20, - choices=[ - ('DAY', 'Day Shift'), - ('EVENING', 'Evening Shift'), - ('NIGHT', 'Night Shift'), - ('WEEKEND', 'Weekend Shift'), - ('HOLIDAY', 'Holiday Shift'), - ('ON_CALL', 'On-Call'), - ('OVERTIME', 'Overtime'), - ], + choices=SHIFT_TYPE_CHOICES, help_text='Shift type' ) @@ -730,13 +821,7 @@ class ScheduleAssignment(models.Model): # Assignment Status status = models.CharField( max_length=20, - choices=[ - ('SCHEDULED', 'Scheduled'), - ('CONFIRMED', 'Confirmed'), - ('COMPLETED', 'Completed'), - ('CANCELLED', 'Cancelled'), - ('NO_SHOW', 'No Show'), - ], + choices=STATUS_CHOICES, default='SCHEDULED', help_text='Assignment status' ) @@ -812,7 +897,25 @@ class TimeEntry(models.Model): """ Time entry model for tracking actual work hours. """ - + ENTRY_TYPE_CHOICES = [ + ('REGULAR', 'Regular Time'), + ('OVERTIME', 'Overtime'), + ('HOLIDAY', 'Holiday'), + ('VACATION', 'Vacation'), + ('SICK', 'Sick Leave'), + ('PERSONAL', 'Personal Time'), + ('BEREAVEMENT', 'Bereavement'), + ('JURY_DUTY', 'Jury Duty'), + ('TRAINING', 'Training'), + ] + STATUS_CHOICES = [ + ('DRAFT', 'Draft'), + ('SUBMITTED', 'Submitted'), + ('APPROVED', 'Approved'), + ('REJECTED', 'Rejected'), + ('PAID', 'Paid'), + ] + # Employee relationship employee = models.ForeignKey( Employee, @@ -889,17 +992,7 @@ class TimeEntry(models.Model): # Entry Type entry_type = models.CharField( max_length=20, - choices=[ - ('REGULAR', 'Regular Time'), - ('OVERTIME', 'Overtime'), - ('HOLIDAY', 'Holiday'), - ('VACATION', 'Vacation'), - ('SICK', 'Sick Leave'), - ('PERSONAL', 'Personal Time'), - ('BEREAVEMENT', 'Bereavement'), - ('JURY_DUTY', 'Jury Duty'), - ('TRAINING', 'Training'), - ], + choices=ENTRY_TYPE_CHOICES, default='REGULAR', help_text='Entry type' ) @@ -938,13 +1031,7 @@ class TimeEntry(models.Model): # Entry Status status = models.CharField( max_length=20, - choices=[ - ('DRAFT', 'Draft'), - ('SUBMITTED', 'Submitted'), - ('APPROVED', 'Approved'), - ('REJECTED', 'Rejected'), - ('PAID', 'Paid'), - ], + choices=STATUS_CHOICES, default='DRAFT', help_text='Entry status' ) @@ -1024,7 +1111,21 @@ class PerformanceReview(models.Model): """ Performance review model for employee evaluations. """ - + REVIEW_TYPE_CHOICES = [ + ('ANNUAL', 'Annual Review'), + ('PROBATIONARY', 'Probationary Review'), + ('MID_YEAR', 'Mid-Year Review'), + ('PROJECT', 'Project Review'), + ('DISCIPLINARY', 'Disciplinary Review'), + ('PROMOTION', 'Promotion Review'), + ] + STATUS_CHOICES = [ + ('DRAFT', 'Draft'), + ('IN_PROGRESS', 'In Progress'), + ('COMPLETED', 'Completed'), + ('ACKNOWLEDGED', 'Acknowledged by Employee'), + ('DISPUTED', 'Disputed'), + ] # Employee relationship employee = models.ForeignKey( Employee, @@ -1055,14 +1156,7 @@ class PerformanceReview(models.Model): # Review Type review_type = models.CharField( max_length=20, - choices=[ - ('ANNUAL', 'Annual Review'), - ('PROBATIONARY', 'Probationary Review'), - ('MID_YEAR', 'Mid-Year Review'), - ('PROJECT', 'Project Review'), - ('DISCIPLINARY', 'Disciplinary Review'), - ('PROMOTION', 'Promotion Review'), - ], + choices=REVIEW_TYPE_CHOICES, help_text='Review type' ) @@ -1146,13 +1240,7 @@ class PerformanceReview(models.Model): # Review Status status = models.CharField( max_length=20, - choices=[ - ('DRAFT', 'Draft'), - ('IN_PROGRESS', 'In Progress'), - ('COMPLETED', 'Completed'), - ('ACKNOWLEDGED', 'Acknowledged by Employee'), - ('DISPUTED', 'Disputed'), - ], + choices=STATUS_CHOICES, default='DRAFT', help_text='Review status' ) @@ -1204,7 +1292,26 @@ class TrainingRecord(models.Model): """ Training record model for employee training and certifications. """ - + TRAINING_TYPE_CHOICES = [ + ('ORIENTATION', 'Orientation'), + ('MANDATORY', 'Mandatory Training'), + ('CONTINUING_ED', 'Continuing Education'), + ('CERTIFICATION', 'Certification'), + ('SKILLS', 'Skills Training'), + ('SAFETY', 'Safety Training'), + ('COMPLIANCE', 'Compliance Training'), + ('LEADERSHIP', 'Leadership Development'), + ('TECHNICAL', 'Technical Training'), + ('OTHER', 'Other'), + ] + STATUS_CHOICES = [ + ('SCHEDULED', 'Scheduled'), + ('IN_PROGRESS', 'In Progress'), + ('COMPLETED', 'Completed'), + ('CANCELLED', 'Cancelled'), + ('NO_SHOW', 'No Show'), + ('FAILED', 'Failed'), + ] # Employee relationship employee = models.ForeignKey( Employee, @@ -1229,25 +1336,14 @@ class TrainingRecord(models.Model): null=True, help_text='Training description' ) - + # Training Type training_type = models.CharField( max_length=20, - choices=[ - ('ORIENTATION', 'Orientation'), - ('MANDATORY', 'Mandatory Training'), - ('CONTINUING_ED', 'Continuing Education'), - ('CERTIFICATION', 'Certification'), - ('SKILLS', 'Skills Training'), - ('SAFETY', 'Safety Training'), - ('COMPLIANCE', 'Compliance Training'), - ('LEADERSHIP', 'Leadership Development'), - ('TECHNICAL', 'Technical Training'), - ('OTHER', 'Other'), - ], + choices=TRAINING_TYPE_CHOICES, help_text='Training type' ) - + # Training Provider training_provider = models.CharField( max_length=200, @@ -1261,7 +1357,7 @@ class TrainingRecord(models.Model): null=True, help_text='Instructor name' ) - + # Training Dates training_date = models.DateField( help_text='Training date' @@ -1294,14 +1390,7 @@ class TrainingRecord(models.Model): # Training Status status = models.CharField( max_length=20, - choices=[ - ('SCHEDULED', 'Scheduled'), - ('IN_PROGRESS', 'In Progress'), - ('COMPLETED', 'Completed'), - ('CANCELLED', 'Cancelled'), - ('NO_SHOW', 'No Show'), - ('FAILED', 'Failed'), - ], + choices=STATUS_CHOICES, default='SCHEDULED', help_text='Training status' ) @@ -1318,7 +1407,10 @@ class TrainingRecord(models.Model): default=False, help_text='Training passed' ) - + is_certified = models.BooleanField( + default=False, + help_text='Training is certified' + ) # Certification Information certificate_number = models.CharField( max_length=50, @@ -1409,3 +1501,411 @@ class TrainingRecord(models.Model): return (self.expiry_date - date.today()).days <= 30 return False + +# class TrainingPrograms(models.Model): +# PROGRAM_TYPE_CHOICES = [ +# ('ORIENTATION', 'Orientation'), +# ('MANDATORY', 'Mandatory Training'), +# ('CONTINUING_ED', 'Continuing Education'), +# ('CERTIFICATION', 'Certification'), +# ('SKILLS', 'Skills Training'), +# ('SAFETY', 'Safety Training'), +# ('COMPLIANCE', 'Compliance Training'), +# ('LEADERSHIP', 'Leadership Development'), +# ('TECHNICAL', 'Technical Training'), +# ('OTHER', 'Other'), +# ] +# +# # Multi-tenancy +# tenant = models.ForeignKey( +# 'core.Tenant', on_delete=models.CASCADE, related_name='training_programs' +# ) +# +# program_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) +# name = models.CharField(max_length=200) +# description = models.TextField(blank=True, null=True) +# program_type = models.CharField(max_length=20, choices=PROGRAM_TYPE_CHOICES) +# +# # Provider/Instructor at the program (defaults; sessions can override) +# program_provider = models.CharField(max_length=200, blank=True, null=True) +# default_instructor = models.ForeignKey( +# Employee, on_delete=models.SET_NULL, null=True, blank=True, +# related_name='default_instructor_programs', +# help_text='Default instructor; sessions may override' +# ) +# +# # Optional “program window” (e.g., for long initiatives) +# start_date = models.DateField(help_text='Program start date', blank=True, null=True) +# end_date = models.DateField(help_text='Program end date', blank=True, null=True) +# +# duration_hours = models.DecimalField(max_digits=5, decimal_places=2, +# default=Decimal('0.00')) +# cost = models.DecimalField(max_digits=10, decimal_places=2, +# default=Decimal('0.00')) +# is_certified = models.BooleanField(default=False) +# +# # Renewal/expiry policy (applies if is_certified) +# validity_days = models.PositiveIntegerField( +# blank=True, null=True, +# help_text='Days certificate is valid from completion (e.g., 365).' +# ) +# notify_before_days = models.PositiveIntegerField( +# blank=True, null=True, +# help_text='Days before expiry to flag for renewal.' +# ) +# +# # Metadata +# created_at = models.DateTimeField(auto_now_add=True) +# updated_at = models.DateTimeField(auto_now=True) +# created_by = models.ForeignKey( +# settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, +# null=True, blank=True, related_name='created_training_programs' +# ) +# +# class Meta: +# db_table = 'hr_training_program' +# ordering = ['name'] +# unique_together = [('tenant', 'name')] +# indexes = [ +# models.Index(fields=['tenant', 'program_type']), +# models.Index(fields=['tenant', 'is_certified']), +# ] +# +# def clean(self): +# if self.start_date and self.end_date and self.end_date < self.start_date: +# raise ValidationError(_('Program end_date cannot be before start_date.')) +# if self.is_certified and not self.validity_days: +# # Not hard error—could be open-ended—but warn as best practice. +# pass +# +# def __str__(self): +# return f'{self.name} ({self.get_program_type_display()})' +# +# +# class ProgramModule(models.Model): +# """Optional content structure for a program.""" +# program = models.ForeignKey( +# TrainingPrograms, on_delete=models.CASCADE, related_name='modules' +# ) +# title = models.CharField(max_length=200) +# order = models.PositiveIntegerField(default=1) +# hours = models.DecimalField(max_digits=5, decimal_places=2, +# default=Decimal('0.00')) +# +# class Meta: +# db_table = 'hr_training_program_module' +# ordering = ['program', 'order'] +# unique_together = [('program', 'order')] +# indexes = [models.Index(fields=['program', 'order'])] +# +# def __str__(self): +# return f'{self.program.name} · {self.order}. {self.title}' +# +# +# class ProgramPrerequisite(models.Model): +# """A program may require completion of other program(s).""" +# program = models.ForeignKey( +# TrainingPrograms, on_delete=models.CASCADE, related_name='prerequisites' +# ) +# required_program = models.ForeignKey( +# TrainingPrograms, on_delete=models.CASCADE, related_name='unlocking_programs' +# ) +# +# class Meta: +# db_table = 'hr_training_program_prerequisite' +# unique_together = [('program', 'required_program')] +# +# def clean(self): +# if self.program_id == self.required_program_id: +# raise ValidationError(_('Program cannot require itself.')) +# +# +# class TrainingSession(models.Model): +# """ +# A scheduled run of a program (cohort/class). +# """ +# DELIVERY_CHOICES = [ +# ('IN_PERSON', 'In-person'), +# ('VIRTUAL', 'Virtual'), +# ('HYBRID', 'Hybrid'), +# ('SELF_PACED', 'Self-paced'), +# ] +# +# tenant = models.ForeignKey( +# Tenant, on_delete=models.CASCADE, related_name='training_sessions' +# ) +# session_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) +# program = models.ForeignKey( +# TrainingPrograms, on_delete=models.CASCADE, related_name='sessions' +# ) +# title = models.CharField( +# max_length=200, blank=True, null=True, +# help_text='Optional run title; falls back to program name' +# ) +# instructor = models.ForeignKey( +# Employee, on_delete=models.SET_NULL, null=True, blank=True, +# related_name='instructed_sessions' +# ) +# delivery_method = models.CharField(max_length=12, choices=DELIVERY_CHOICES, default='IN_PERSON') +# +# # Schedule +# start_at = models.DateTimeField() +# end_at = models.DateTimeField() +# location = models.CharField(max_length=200, blank=True, null=True) +# capacity = models.PositiveIntegerField(default=0) +# +# # Overrides +# cost_override = models.DecimalField(max_digits=10, decimal_places=2, +# blank=True, null=True) +# hours_override = models.DecimalField(max_digits=5, decimal_places=2, +# blank=True, null=True) +# +# # Metadata +# created_at = models.DateTimeField(auto_now_add=True) +# created_by = models.ForeignKey( +# settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, +# null=True, blank=True, related_name='created_training_sessions' +# ) +# +# class Meta: +# db_table = 'hr_training_session' +# ordering = ['-start_at'] +# indexes = [ +# models.Index(fields=['tenant', 'start_at']), +# models.Index(fields=['tenant', 'program']), +# ] +# constraints = [ +# models.CheckConstraint( +# check=models.Q(end_at__gt=models.F('start_at')), +# name='session_end_after_start' +# ), +# ] +# +# def __str__(self): +# return self.title or f'{self.program.name} @ {self.start_at:%Y-%m-%d}' +# +# +# class TrainingRecord(models.Model): +# """ +# Enrollment/participation record (renamed semantic, kept class name). +# Each row = an employee participating in a specific session of a program. +# """ +# STATUS_CHOICES = [ +# ('SCHEDULED', 'Scheduled'), +# ('IN_PROGRESS', 'In Progress'), +# ('COMPLETED', 'Completed'), +# ('CANCELLED', 'Cancelled'), +# ('NO_SHOW', 'No Show'), +# ('FAILED', 'Failed'), +# ('WAITLISTED', 'Waitlisted'), +# ] +# +# tenant = models.ForeignKey( +# Tenant, on_delete=models.CASCADE, related_name='training_records' +# ) +# record_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) +# +# # Core links +# employee = models.ForeignKey( +# Employee, on_delete=models.CASCADE, related_name='training_records' +# ) +# program = models.ForeignKey( +# TrainingPrograms, on_delete=models.PROTECT, related_name='training_records' +# ) +# session = models.ForeignKey( +# TrainingSession, on_delete=models.PROTECT, related_name='enrollments', +# help_text='The specific run the employee is enrolled in.' +# ) +# +# # Timeline +# enrolled_at = models.DateTimeField(auto_now_add=True) +# started_at = models.DateTimeField(blank=True, null=True) +# completion_date = models.DateField(blank=True, null=True) +# +# # Outcomes +# status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='SCHEDULED') +# credits_earned = models.DecimalField(max_digits=5, decimal_places=2, +# default=Decimal('0.00')) +# score = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True) +# passed = models.BooleanField(default=False) +# +# # Notes/Cost +# notes = models.TextField(blank=True, null=True) +# cost_paid = models.DecimalField(max_digits=10, decimal_places=2, +# blank=True, null=True) +# +# created_at = models.DateTimeField(auto_now_add=True) +# updated_at = models.DateTimeField(auto_now=True) +# created_by = models.ForeignKey( +# settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, +# null=True, blank=True, related_name='created_training_records' +# ) +# +# class Meta: +# db_table = 'hr_training_record' +# verbose_name = 'Training Enrollment' +# verbose_name_plural = 'Training Enrollments' +# ordering = ['-enrolled_at'] +# unique_together = [('employee', 'session')] +# indexes = [ +# models.Index(fields=['tenant', 'employee']), +# models.Index(fields=['tenant', 'program']), +# models.Index(fields=['tenant', 'session']), +# models.Index(fields=['tenant', 'status']), +# models.Index(fields=['tenant', 'completion_date']), +# ] +# +# def clean(self): +# # Tenancy alignment +# if self.program and self.tenant_id != self.program.tenant_id: +# raise ValidationError(_('Tenant mismatch between record and program.')) +# if self.session and self.tenant_id != self.session.tenant_id: +# raise ValidationError(_('Tenant mismatch between record and session.')) +# if self.employee and self.tenant_id != self.employee.tenant_id: +# raise ValidationError(_('Tenant mismatch between record and employee.')) +# +# # Prevent enrolling into sessions of a different program (shouldn’t happen) +# if self.session and self.program and self.session.program_id != self.program_id: +# raise ValidationError(_('Session does not belong to the selected program.')) +# +# if self.completion_date and self.status not in ('COMPLETED', 'FAILED'): +# raise ValidationError(_('Completion date requires status COMPLETED or FAILED.')) +# +# def __str__(self): +# return f'{self.employee} → {self.program.name} ({self.get_status_display()})' +# +# # Helper properties +# @property +# def hours(self): +# return self.session.hours_override or self.program.duration_hours +# +# @property +# def effective_cost(self): +# return self.cost_paid if self.cost_paid is not None else \ +# (self.session.cost_override if self.session.cost_override is not None +# else self.program.cost) +# +# @property +# def eligible_for_certificate(self): +# return self.status == 'COMPLETED' and self.passed and self.program.is_certified +# +# +# class SessionAttendance(models.Model): +# """ +# Optional check-in/out per participant per session (or per day if multi-day). +# If you want per-day granularity, add a "session_day" field. +# """ +# ATTENDANCE_STATUS = [ +# ('PRESENT', 'Present'), +# ('LATE', 'Late'), +# ('ABSENT', 'Absent'), +# ('EXCUSED', 'Excused'), +# ] +# +# enrollment = models.ForeignKey( +# TrainingRecord, on_delete=models.CASCADE, related_name='attendance' +# ) +# checked_in_at = models.DateTimeField(blank=True, null=True) +# checked_out_at = models.DateTimeField(blank=True, null=True) +# status = models.CharField(max_length=10, choices=ATTENDANCE_STATUS, default='PRESENT') +# notes = models.CharField(max_length=255, blank=True, null=True) +# +# class Meta: +# db_table = 'hr_training_attendance' +# ordering = ['enrollment_id', 'checked_in_at'] +# indexes = [models.Index(fields=['enrollment'])] +# +# +# class SessionAssessment(models.Model): +# """ +# Optional evaluation (quiz/exam) tied to an enrollment. +# """ +# enrollment = models.ForeignKey( +# TrainingRecord, on_delete=models.CASCADE, related_name='assessments' +# ) +# name = models.CharField(max_length=200) +# max_score = models.DecimalField(max_digits=7, decimal_places=2, default=100) +# score = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True) +# passed = models.BooleanField(default=False) +# taken_at = models.DateTimeField(blank=True, null=True) +# +# class Meta: +# db_table = 'hr_training_assessment' +# ordering = ['-taken_at'] +# indexes = [models.Index(fields=['enrollment'])] +# +# +# class TrainingCertificates(models.Model): +# """ +# Issued certificates on completion. +# Usually tied to a program and the enrollment that produced it. +# """ +# tenant = models.ForeignKey( +# Tenant, on_delete=models.CASCADE, related_name='training_certificates' +# ) +# certificate_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False) +# +# program = models.ForeignKey( +# TrainingPrograms, on_delete=models.PROTECT, related_name='certificates' +# ) +# employee = models.ForeignKey( +# Employee, on_delete=models.CASCADE, related_name='training_certificates' +# ) +# enrollment = models.OneToOneField( +# TrainingRecord, on_delete=models.CASCADE, related_name='certificate', +# help_text='The enrollment that generated this certificate.' +# ) +# +# certificate_name = models.CharField(max_length=200) +# certificate_number = models.CharField(max_length=50, blank=True, null=True) +# certification_body = models.CharField(max_length=200, blank=True, null=True) +# issued_date = models.DateField(auto_now_add=True) +# expiry_date = models.DateField(blank=True, null=True) +# file = models.FileField(upload_to='certificates/', blank=True, null=True) +# +# created_at = models.DateTimeField(auto_now_add=True) +# created_by = models.ForeignKey( +# settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, +# null=True, blank=True, related_name='created_training_certificates' +# ) +# +# class Meta: +# db_table = 'hr_training_certificate' +# ordering = ['-issued_date'] +# unique_together = [('employee', 'program', 'enrollment')] +# indexes = [ +# models.Index(fields=['tenant', 'employee']), +# models.Index(fields=['tenant', 'program']), +# models.Index(fields=['tenant', 'expiry_date']), +# models.Index(fields=['certificate_number']), +# ] +# +# def clean(self): +# # tenancy alignment +# if self.program and self.tenant_id != self.program.tenant_id: +# raise ValidationError(_('Tenant mismatch between certificate and program.')) +# if self.employee and self.tenant_id != self.employee.tenant_id: +# raise ValidationError(_('Tenant mismatch between certificate and employee.')) +# if self.enrollment and self.tenant_id != self.enrollment.tenant_id: +# raise ValidationError(_('Tenant mismatch between certificate and enrollment.')) +# if self.enrollment and self.enrollment.program_id != self.program_id: +# raise ValidationError(_('Enrollment does not belong to this program.')) +# +# def __str__(self): +# return f'{self.certificate_name} - {self.employee}' +# +# @property +# def is_expired(self): +# return bool(self.expiry_date and self.expiry_date < date.today()) +# +# @property +# def days_to_expiry(self): +# return (self.expiry_date - date.today()).days if self.expiry_date else None +# +# @classmethod +# def compute_expiry(cls, program: TrainingPrograms, issued_on: date) -> date | None: +# if program.is_certified and program.validity_days: +# return issued_on + timedelta(days=program.validity_days) +# return None + + diff --git a/hr/urls.py b/hr/urls.py index 28f18a0d..f1b272b4 100644 --- a/hr/urls.py +++ b/hr/urls.py @@ -65,10 +65,12 @@ urlpatterns = [ path('reviews//', views.PerformanceReviewDetailView.as_view(), name='performance_review_detail'), path('reviews//update/', views.PerformanceReviewUpdateView.as_view(), name='performance_review_update'), path('reviews//delete/', views.PerformanceReviewDeleteView.as_view(), name='performance_review_delete'), + path('reviews//complete/', views.complete_performance_review, name='complete_performance_review'), # ============================================================================ # TRAINING RECORD URLS (FULL CRUD - Operational Data) # ============================================================================ + path('training-management', views.TrainingManagementView.as_view(), name='training_management'), path('training/', views.TrainingRecordListView.as_view(), name='training_record_list'), path('training/create/', views.TrainingRecordCreateView.as_view(), name='training_record_create'), path('training//', views.TrainingRecordDetailView.as_view(), name='training_record_detail'), @@ -88,6 +90,7 @@ urlpatterns = [ path('clock-out/', views.clock_out, name='clock_out'), path('time-entries//approve/', views.approve_time_entry, name='approve_time_entry'), path('schedules//publish/', views.publish_schedule, name='publish_schedule'), + # ============================================================================ # API ENDPOINTS diff --git a/hr/views.py b/hr/views.py index ae42ae33..f09cf856 100644 --- a/hr/views.py +++ b/hr/views.py @@ -28,10 +28,6 @@ from .forms import ( ) -# ============================================================================ -# DASHBOARD AND OVERVIEW VIEWS -# ============================================================================ - class HRDashboardView(LoginRequiredMixin, TemplateView): """ Main HR dashboard with comprehensive statistics and recent activity. @@ -92,10 +88,6 @@ class HRDashboardView(LoginRequiredMixin, TemplateView): return context -# ============================================================================ -# EMPLOYEE VIEWS (FULL CRUD - Master Data) -# ============================================================================ - class EmployeeListView(LoginRequiredMixin, ListView): """ List all employees with filtering and search capabilities. @@ -236,7 +228,7 @@ class EmployeeDeleteView(LoginRequiredMixin, DeleteView): Soft delete an employee record (healthcare compliance). """ model = Employee - template_name = 'hr/employee_confirm_delete.html' + template_name = 'hr/employees/employee_confirm_delete.html' success_url = reverse_lazy('hr:employee_list') def get_queryset(self): @@ -253,16 +245,12 @@ class EmployeeDeleteView(LoginRequiredMixin, DeleteView): return redirect(self.success_url) -# ============================================================================ -# DEPARTMENT VIEWS (FULL CRUD - Master Data) -# ============================================================================ - class DepartmentListView(LoginRequiredMixin, ListView): """ List all departments with employee counts. """ model = Department - template_name = 'hr/department_list.html' + template_name = 'hr/departments/department_list.html' context_object_name = 'departments' paginate_by = 20 @@ -286,7 +274,7 @@ class DepartmentDetailView(LoginRequiredMixin, DetailView): Display detailed information about a specific department. """ model = Department - template_name = 'hr/department_detail.html' + template_name = 'hr/departments/department_detail.html' context_object_name = 'department' def get_queryset(self): @@ -316,7 +304,7 @@ class DepartmentCreateView(LoginRequiredMixin, CreateView): """ model = Department form_class = DepartmentForm - template_name = 'hr/department_form.html' + template_name = 'hr/departments/department_form.html' success_url = reverse_lazy('hr:department_list') def form_valid(self, form): @@ -336,7 +324,7 @@ class DepartmentUpdateView(LoginRequiredMixin, UpdateView): """ model = Department form_class = DepartmentForm - template_name = 'hr/department_form.html' + template_name = 'hr/departments/department_form.html' def get_queryset(self): return Department.objects.filter(tenant=self.request.user.tenant) @@ -359,7 +347,7 @@ class DepartmentDeleteView(LoginRequiredMixin, DeleteView): Delete a department (only if no employees assigned). """ model = Department - template_name = 'hr/department_confirm_delete.html' + template_name = 'hr/departments/department_confirm_delete.html' success_url = reverse_lazy('hr:department_list') def get_queryset(self): @@ -377,16 +365,12 @@ class DepartmentDeleteView(LoginRequiredMixin, DeleteView): return super().delete(request, *args, **kwargs) -# ============================================================================ -# SCHEDULE VIEWS (LIMITED CRUD - Operational Data) -# ============================================================================ - class ScheduleListView(LoginRequiredMixin, ListView): """ List all schedules with filtering capabilities. """ model = Schedule - template_name = 'hr/schedule_list.html' + template_name = 'hr/schedules/schedule_list.html' context_object_name = 'schedules' paginate_by = 20 @@ -414,7 +398,7 @@ class ScheduleDetailView(LoginRequiredMixin, DetailView): Display detailed information about a specific schedule. """ model = Schedule - template_name = 'hr/schedule_detail.html' + template_name = 'hr/schedules/schedule_detail.html' context_object_name = 'schedule' def get_queryset(self): @@ -438,7 +422,7 @@ class ScheduleCreateView(LoginRequiredMixin, CreateView): """ model = Schedule form_class = ScheduleForm - template_name = 'hr/schedule_form.html' + template_name = 'hr/schedules/schedule_form.html' success_url = reverse_lazy('hr:schedule_list') def form_valid(self, form): @@ -458,7 +442,7 @@ class ScheduleUpdateView(LoginRequiredMixin, UpdateView): """ model = Schedule form_class = ScheduleForm - template_name = 'hr/schedule_form.html' + template_name = 'hr/schedules/schedule_form.html' def get_queryset(self): return Schedule.objects.filter(employee__tenant=self.request.user.tenant) @@ -476,16 +460,12 @@ class ScheduleUpdateView(LoginRequiredMixin, UpdateView): return kwargs -# ============================================================================ -# SCHEDULE ASSIGNMENT VIEWS (LIMITED CRUD - Operational Data) -# ============================================================================ - class ScheduleAssignmentListView(LoginRequiredMixin, ListView): """ List all schedule assignments with filtering capabilities. """ model = ScheduleAssignment - template_name = 'hr/schedule_assignment_list.html' + template_name = 'hr/assignments/schedule_assignment_list.html' context_object_name = 'assignments' paginate_by = 20 @@ -521,7 +501,7 @@ class ScheduleAssignmentCreateView(LoginRequiredMixin, CreateView): """ model = ScheduleAssignment form_class = ScheduleAssignmentForm - template_name = 'hr/schedule_assignment_form.html' + template_name = 'hr/assignments/schedule_assignment_form.html' success_url = reverse_lazy('hr:schedule_assignment_list') def form_valid(self, form): @@ -540,7 +520,7 @@ class ScheduleAssignmentUpdateView(LoginRequiredMixin, UpdateView): """ model = ScheduleAssignment form_class = ScheduleAssignmentForm - template_name = 'hr/schedule_assignment_form.html' + template_name = 'hr/assignments/schedule_assignment_form.html' success_url = reverse_lazy('hr:schedule_assignment_list') def get_queryset(self): @@ -556,16 +536,12 @@ class ScheduleAssignmentUpdateView(LoginRequiredMixin, UpdateView): return kwargs -# ============================================================================ -# TIME ENTRY VIEWS (RESTRICTED CRUD - Operational Data) -# ============================================================================ - class TimeEntryListView(LoginRequiredMixin, ListView): """ List time entries with filtering capabilities. """ model = TimeEntry - template_name = 'hr/time_entry_list.html' + template_name = 'hr/time_entries/time_entry_list.html' context_object_name = 'time_entries' paginate_by = 20 @@ -600,7 +576,7 @@ class TimeEntryDetailView(LoginRequiredMixin, DetailView): Display detailed information about a specific time entry. """ model = TimeEntry - template_name = 'hr/time_entry_detail.html' + template_name = 'hr/time_entries/time_entry_detail.html' context_object_name = 'time_entry' def get_queryset(self): @@ -613,7 +589,7 @@ class TimeEntryCreateView(LoginRequiredMixin, CreateView): """ model = TimeEntry form_class = TimeEntryForm - template_name = 'hr/time_entry_form.html' + template_name = 'hr/time_entries/time_entry_form.html' success_url = reverse_lazy('hr:time_entry_list') def form_valid(self, form): @@ -632,7 +608,7 @@ class TimeEntryUpdateView(LoginRequiredMixin, UpdateView): """ model = TimeEntry form_class = TimeEntryForm - template_name = 'hr/time_entry_form.html' + template_name = 'hr/time_entries/time_entry_form.html' success_url = reverse_lazy('hr:time_entry_list') def get_queryset(self): @@ -653,16 +629,12 @@ class TimeEntryUpdateView(LoginRequiredMixin, UpdateView): return kwargs -# ============================================================================ -# PERFORMANCE REVIEW VIEWS (FULL CRUD - Operational Data) -# ============================================================================ - class PerformanceReviewListView(LoginRequiredMixin, ListView): """ List performance reviews with filtering capabilities. """ model = PerformanceReview - template_name = 'hr/performance_review_list.html' + template_name = 'hr/reviews/performance_review_list.html' context_object_name = 'reviews' paginate_by = 20 @@ -694,11 +666,80 @@ class PerformanceReviewDetailView(LoginRequiredMixin, DetailView): Display detailed information about a specific performance review. """ model = PerformanceReview - template_name = 'hr/performance_review_detail.html' + template_name = 'hr/reviews/performance_review_detail.html' context_object_name = 'review' - + def get_queryset(self): - return PerformanceReview.objects.filter(employee__tenant=self.request.user.tenant) + # Eager load employee + department + supervisor to reduce queries + return (PerformanceReview.objects + .select_related('employee', 'employee__department', 'employee__supervisor', 'reviewer') + .filter(employee__tenant=self.request.user.tenant)) + + def get_object(self, queryset=None): + queryset = queryset or self.get_queryset() + return get_object_or_404(queryset, pk=self.kwargs.get('pk') or self.kwargs.get('id')) + + @staticmethod + def _split_lines(text): + if not text: + return [] + parts = [] + for line in str(text).replace('\r', '').split('\n'): + for piece in line.split(';'): + piece = piece.strip() + if piece: + parts.append(piece) + return parts + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + review = ctx['review'] + + # Build categories from competency_ratings JSON: { "Teamwork": 4.0, ... } + # Make a list of dicts the template can iterate through. + categories = [] + ratings = review.competency_ratings or {} + # Keep a stable order (by key) to avoid chart jitter + for name in sorted(ratings.keys()): + try: + score = float(ratings[name]) + except (TypeError, ValueError): + score = 0.0 + categories.append({'name': name, 'score': score, 'comments': ''}) + + # Previous reviews (same employee, exclude current) + previous_reviews = ( + PerformanceReview.objects + .filter(employee=review.employee) + .exclude(pk=review.pk) + .order_by('-review_date')[:5] + .select_related('employee') + ) + + # Strengths / AFI lists for bullet rendering + strengths_list = self._split_lines(review.strengths) + afi_list = self._split_lines(review.areas_for_improvement) + + # Goals blocks as lists for nicer display + goals_achieved_list = self._split_lines(review.goals_achieved) + goals_not_achieved_list = self._split_lines(review.goals_not_achieved) + future_goals_list = self._split_lines(review.future_goals) + + ctx.update({ + 'categories': categories, + 'previous_reviews': previous_reviews, + 'review_strengths_list': strengths_list, + 'review_afi_list': afi_list, + 'goals_achieved_list': goals_achieved_list, + 'goals_not_achieved_list': goals_not_achieved_list, + 'future_goals_list': future_goals_list, + }) + + # convenience on the review object (template already expects these list props sometimes) + setattr(review, 'strengths_list', strengths_list) + setattr(review, 'areas_for_improvement_list', afi_list) + + return ctx class PerformanceReviewCreateView(LoginRequiredMixin, CreateView): @@ -707,7 +748,7 @@ class PerformanceReviewCreateView(LoginRequiredMixin, CreateView): """ model = PerformanceReview form_class = PerformanceReviewForm - template_name = 'hr/performance_review_form.html' + template_name = 'hr/reviews/performance_review_form.html' success_url = reverse_lazy('hr:performance_review_list') def form_valid(self, form): @@ -727,7 +768,7 @@ class PerformanceReviewUpdateView(LoginRequiredMixin, UpdateView): """ model = PerformanceReview form_class = PerformanceReviewForm - template_name = 'hr/performance_review_form.html' + template_name = 'hr/reviews/performance_review_form.html' def get_queryset(self): return PerformanceReview.objects.filter(employee__tenant=self.request.user.tenant) @@ -750,7 +791,7 @@ class PerformanceReviewDeleteView(LoginRequiredMixin, DeleteView): Delete a performance review (only if not finalized). """ model = PerformanceReview - template_name = 'hr/performance_review_confirm_delete.html' + template_name = 'hr/reviews/performance_review_confirm_delete.html' success_url = reverse_lazy('hr:performance_review_list') def get_queryset(self): @@ -768,39 +809,128 @@ class PerformanceReviewDeleteView(LoginRequiredMixin, DeleteView): return super().delete(request, *args, **kwargs) -# ============================================================================ -# TRAINING RECORD VIEWS (FULL CRUD - Operational Data) -# ============================================================================ +class TrainingManagementView(LoginRequiredMixin, ListView): + model = TrainingRecord + template_name = 'hr/training/training_management.html' + context_object_name = 'training_records' + paginate_by = 20 + + def get_queryset(self): + qs = (TrainingRecord.objects + .filter(employee__tenant=self.request.user.tenant) + .select_related('employee', 'employee__department') + .order_by('-training_date', '-completion_date')) + # optional GET filters (works with the template’s inputs) + if emp := self.request.GET.get('employee'): + qs = qs.filter(employee_id=emp) + if ttype := self.request.GET.get('training_type'): + qs = qs.filter(training_type=ttype) + if status := self.request.GET.get('status'): + qs = qs.filter(status=status) + return qs + + def get_context_data(self, **kwargs): + ctx = super().get_context_data(**kwargs) + tenant = self.request.user.tenant + today = timezone.now().date() + + base = TrainingRecord.objects.filter(employee__tenant=tenant) + + total_records = base.count() + completed_trainings = base.filter(status='COMPLETED').count() + pending_trainings = base.filter(status__in=['SCHEDULED', 'IN_PROGRESS']).count() + overdue_trainings = base.filter(expiry_date__lt=today, expiry_date__isnull=False).exclude( + status='COMPLETED').count() + + # compliance rate = “not expired” among trainings that have an expiry_date + with_expiry = base.filter(expiry_date__isnull=False) + valid_now = with_expiry.filter(expiry_date__gte=today).count() + compliance_rate = round((valid_now / with_expiry.count()) * 100, 1) if with_expiry.exists() else 100.0 + + # expiring soon = within 30 days + expiring_soon_count = with_expiry.filter(expiry_date__gte=today, + expiry_date__lte=today + timedelta(days=30)).count() + + # department compliance (simple example: percent of non-expired per dept among those with expiry) + dept_rows = [] + departments = Department.objects.filter(tenant=tenant).order_by('name') + for d in departments: + d_qs = with_expiry.filter(employee__department=d) + if not d_qs.exists(): + rate = 100 + else: + ok = d_qs.filter(expiry_date__gte=today).count() + rate = round((ok / d_qs.count()) * 100) + color = 'success' if rate >= 90 else 'warning' if rate >= 70 else 'danger' + dept_rows.append({'name': d.name, 'compliance_rate': rate, 'compliance_color': color}) + + # “compliance alerts” demo (overdue/expiring soon) + alerts = [] + for tr in base.select_related('employee'): + if tr.expiry_date: + if tr.expiry_date < today: + alerts.append({ + 'id': tr.id, + 'employee': tr.employee, + 'requirement': tr.training_name, + 'due_date': tr.expiry_date, + 'priority_color': 'danger', + 'urgency_color': 'danger', + 'get_priority_display': 'Overdue', + }) + elif today <= tr.expiry_date <= today + timedelta(days=30): + alerts.append({ + 'id': tr.id, + 'employee': tr.employee, + 'requirement': tr.training_name, + 'due_date': tr.expiry_date, + 'priority_color': 'warning', + 'urgency_color': 'warning', + 'get_priority_display': 'Expiring Soon', + }) + + ctx.update({ + 'total_records': total_records, + 'completed_trainings': completed_trainings, + 'pending_trainings': pending_trainings, + 'overdue_trainings': overdue_trainings, + 'departments': departments, + 'compliance_rate': compliance_rate, + 'expiring_soon_count': expiring_soon_count, + 'department_compliance': dept_rows, + 'compliance_alerts': alerts, + }) + return ctx class TrainingRecordListView(LoginRequiredMixin, ListView): """ - List training records with filtering capabilities. - """ + List training records with filtering capabilities. + """ model = TrainingRecord - template_name = 'hr/training_record_list.html' + template_name = 'hr/training/training_record_list.html' context_object_name = 'training_records' paginate_by = 20 - + def get_queryset(self): queryset = TrainingRecord.objects.filter( employee__tenant=self.request.user.tenant ).select_related('employee') - + # Filter by employee employee = self.request.GET.get('employee') if employee: queryset = queryset.filter(employee_id=employee) - + # Filter by training type training_type = self.request.GET.get('training_type') if training_type: queryset = queryset.filter(training_type=training_type) - + # Filter by completion status status = self.request.GET.get('status') if status: queryset = queryset.filter(status=status) - + return queryset.order_by('-completion_date') @@ -809,8 +939,8 @@ class TrainingRecordDetailView(LoginRequiredMixin, DetailView): Display detailed information about a specific training record. """ model = TrainingRecord - template_name = 'hr/training_record_detail.html' - context_object_name = 'training_record' + template_name = 'hr/training/training_record_detail.html' + context_object_name = 'record' def get_queryset(self): return TrainingRecord.objects.filter(employee__tenant=self.request.user.tenant) @@ -822,7 +952,7 @@ class TrainingRecordCreateView(LoginRequiredMixin, CreateView): """ model = TrainingRecord form_class = TrainingRecordForm - template_name = 'hr/training_record_form.html' + template_name = 'hr/training/training_record_form.html' success_url = reverse_lazy('hr:training_record_list') def form_valid(self, form): @@ -842,7 +972,7 @@ class TrainingRecordUpdateView(LoginRequiredMixin, UpdateView): """ model = TrainingRecord form_class = TrainingRecordForm - template_name = 'hr/training_record_form.html' + template_name = 'hr/training/training_record_form.html' def get_queryset(self): return TrainingRecord.objects.filter(employee__tenant=self.request.user.tenant) @@ -865,7 +995,7 @@ class TrainingRecordDeleteView(LoginRequiredMixin, DeleteView): Delete a training record. """ model = TrainingRecord - template_name = 'hr/training_record_confirm_delete.html' + template_name = 'hr/training/training_record_confirm_delete.html' success_url = reverse_lazy('hr:training_record_list') def get_queryset(self): @@ -876,9 +1006,15 @@ class TrainingRecordDeleteView(LoginRequiredMixin, DeleteView): return super().delete(request, *args, **kwargs) -# ============================================================================ -# HTMX VIEWS FOR REAL-TIME UPDATES -# ============================================================================ +@login_required +def complete_performance_review(request, review_id): + review = get_object_or_404(PerformanceReview, pk=review_id) + review.status = 'COMPLETED' + review.completed_by = request.user + review.save() + + messages.success(request, 'Performance review completed successfully.') + return redirect('hr:performance_review_detail', pk=review.pk) @login_required def hr_stats(request): @@ -961,10 +1097,6 @@ def attendance_summary(request): return render(request, 'hr/partials/attendance_summary.html', context) -# ============================================================================ -# ACTION VIEWS FOR WORKFLOW OPERATIONS -# ============================================================================ - @login_required def clock_in(request): """ @@ -1093,7 +1225,7 @@ def approve_time_entry(request, entry_id): next_url = request.POST.get('next', reverse('hr:time_entry_detail', kwargs={'pk': time_entry.id})) return redirect(next_url) - return render(request, 'hr/time_entry_approve.html', { + return render(request, 'hr/time_entries/time_entry_approve.html', { 'time_entry': time_entry }) @@ -1123,15 +1255,11 @@ def publish_schedule(request, schedule_id): messages.success(request, 'Schedule published successfully.') return redirect('hr:schedule_detail', pk=schedule.id) - return render(request, 'hr/schedule_publish.html', { + return render(request, 'hr/schedules/schedule_publish.html', { 'schedule': schedule }) -# ============================================================================ -# API ENDPOINTS -# ============================================================================ - @login_required def api_employee_list(request): """ @@ -1155,6 +1283,40 @@ def api_department_list(request): return JsonResponse({'departments': list(departments)}) + +# Query patterns to use if needed +# # All upcoming sessions for a tenant (next 30 days) +# TrainingSession.objects.filter( +# tenant=request.user.tenant, start_at__gte=timezone.now(), +# start_at__lte=timezone.now() + timedelta(days=30) +# ).select_related('program', 'instructor') +# +# # Employees due for renewal in 30 days +# TrainingCertificates.objects.filter( +# tenant=request.user.tenant, +# expiry_date__lte=date.today() + timedelta(days=30), +# expiry_date__gte=date.today() +# ).select_related('employee', 'program') +# +# # Enroll an employee, respecting capacity +# session = TrainingSession.objects.select_for_update().get(pk=session_pk, tenant=tenant) +# if session.capacity and session.enrollments.count() >= session.capacity: +# status = 'WAITLISTED' +# else: +# status = 'SCHEDULED' +# enrollment = TrainingRecord.objects.create( +# tenant=tenant, employee=emp, program=session.program, session=session, +# status=status, created_by=request.user +# ) +# +# # Mark completion + pass (auto-certificate will fire via signal) +# enrollment.status = 'COMPLETED' +# enrollment.passed = True +# enrollment.completion_date = date.today() +# enrollment.credits_earned = enrollment.hours +# enrollment.save() + + # # from django.shortcuts import render, redirect, get_object_or_404 # from django.views.generic import ( diff --git a/inpatients/__pycache__/flows.cpython-312.pyc b/inpatients/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..6cd8ebb6 Binary files /dev/null and b/inpatients/__pycache__/flows.cpython-312.pyc differ diff --git a/inpatients/flows.py b/inpatients/flows.py new file mode 100644 index 00000000..0d7ed355 --- /dev/null +++ b/inpatients/flows.py @@ -0,0 +1,757 @@ +# """ +# Viewflow workflows for inpatients app. +# Provides admission, transfer, and discharge workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import Admission, Transfer, DischargeSummary, Ward, Bed +# from .views import ( +# AdmissionRegistrationView, BedAssignmentView, MedicalAssessmentView, +# NursingAssessmentView, AdmissionOrdersView, TransferRequestView, +# TransferApprovalView, TransferExecutionView, DischargeInitiationView, +# DischargePlanningView, DischargeExecutionView +# ) +# +# +# class AdmissionProcess(Process): +# """ +# Viewflow process model for patient admissions +# """ +# admission = ModelField(Admission, help_text='Associated admission record') +# +# # Process status tracking +# registration_completed = models.BooleanField(default=False) +# bed_assigned = models.BooleanField(default=False) +# medical_assessment_completed = models.BooleanField(default=False) +# nursing_assessment_completed = models.BooleanField(default=False) +# orders_written = models.BooleanField(default=False) +# admission_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Admission Process' +# verbose_name_plural = 'Admission Processes' +# +# +# class AdmissionFlow(Flow): +# """ +# Hospital Patient Admission Workflow +# +# This flow manages the complete patient admission process from +# initial registration through final admission completion. +# """ +# +# process_class = AdmissionProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_admission) +# .Next(this.patient_registration) +# ) +# +# patient_registration = ( +# flow_view(AdmissionRegistrationView) +# .Permission('inpatients.can_register_admissions') +# .Next(this.check_bed_availability) +# ) +# +# check_bed_availability = ( +# flow_func(this.check_beds) +# .Next(this.bed_assignment) +# ) +# +# bed_assignment = ( +# flow_view(BedAssignmentView) +# .Permission('inpatients.can_assign_beds') +# .Next(this.parallel_assessments) +# ) +# +# parallel_assessments = ( +# flow_func(this.start_parallel_assessments) +# .Next(this.medical_assessment) +# .Next(this.nursing_assessment) +# ) +# +# medical_assessment = ( +# flow_view(MedicalAssessmentView) +# .Permission('inpatients.can_perform_medical_assessment') +# .Next(this.join_assessments) +# ) +# +# nursing_assessment = ( +# flow_view(NursingAssessmentView) +# .Permission('inpatients.can_perform_nursing_assessment') +# .Next(this.join_assessments) +# ) +# +# join_assessments = ( +# flow_func(this.join_parallel_assessments) +# .Next(this.write_admission_orders) +# ) +# +# write_admission_orders = ( +# flow_view(AdmissionOrdersView) +# .Permission('inpatients.can_write_orders') +# .Next(this.finalize_admission) +# ) +# +# finalize_admission = ( +# flow_func(this.complete_admission) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_admission) +# +# # Flow functions +# def start_admission(self, activation): +# """Initialize the admission process""" +# process = activation.process +# admission = process.admission +# +# # Update admission status +# admission.status = 'PENDING' +# admission.save() +# +# # Send notification to registration staff +# self.notify_registration_staff(admission) +# +# def check_beds(self, activation): +# """Check bed availability for the patient""" +# process = activation.process +# admission = process.admission +# +# # Check if beds are available in the requested ward +# available_beds = Bed.objects.filter( +# ward=admission.current_ward, +# status='AVAILABLE' +# ).count() +# +# if available_beds == 0: +# # Handle no beds available - could trigger waiting list +# admission.admission_notes += f"\nNo beds available in {admission.current_ward.name} at {timezone.now()}" +# admission.save() +# +# # Notify bed management +# self.notify_bed_shortage(admission) +# +# def start_parallel_assessments(self, activation): +# """Start parallel medical and nursing assessments""" +# process = activation.process +# +# # Create assessment tasks +# self.create_assessment_tasks(process) +# +# def join_parallel_assessments(self, activation): +# """Wait for both assessments to complete""" +# process = activation.process +# +# # Check if both assessments are completed +# if (process.medical_assessment_completed and +# process.nursing_assessment_completed): +# +# # Notify physician to write orders +# self.notify_physician_for_orders(process.admission) +# +# def complete_admission(self, activation): +# """Finalize the admission process""" +# process = activation.process +# admission = process.admission +# +# # Update admission status +# admission.status = 'ADMITTED' +# admission.save() +# +# # Update bed status +# if admission.current_bed: +# admission.current_bed.status = 'OCCUPIED' +# admission.current_bed.current_patient = admission.patient +# admission.current_bed.current_admission = admission +# admission.current_bed.occupied_since = timezone.now() +# admission.current_bed.save() +# +# # Mark process as completed +# process.admission_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_admission_complete(admission) +# +# def end_admission(self, activation): +# """End the admission workflow""" +# process = activation.process +# +# # Generate admission summary report +# self.generate_admission_summary(process.admission) +# +# # Helper methods +# def notify_registration_staff(self, admission): +# """Notify registration staff of new admission""" +# from django.contrib.auth.models import Group +# +# registration_staff = User.objects.filter( +# groups__name='Registration Staff' +# ) +# +# for staff in registration_staff: +# send_mail( +# subject=f'New Admission: {admission.patient.get_full_name()}', +# message=f'A new {admission.get_admission_type_display()} admission has been initiated.', +# from_email='admissions@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_bed_shortage(self, admission): +# """Notify bed management of shortage""" +# from django.contrib.auth.models import Group +# +# bed_managers = User.objects.filter( +# groups__name='Bed Management' +# ) +# +# for manager in bed_managers: +# send_mail( +# subject=f'Bed Shortage Alert - {admission.current_ward.name}', +# message=f'No beds available for admission of {admission.patient.get_full_name()}.', +# from_email='admissions@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def create_assessment_tasks(self, process): +# """Create assessment tasks for medical and nursing staff""" +# # This would create tasks in a task management system +# pass +# +# def notify_physician_for_orders(self, admission): +# """Notify attending physician to write orders""" +# if admission.attending_physician and admission.attending_physician.email: +# send_mail( +# subject=f'Admission Orders Required: {admission.patient.get_full_name()}', +# message=f'Please write admission orders. Both assessments are complete.', +# from_email='admissions@hospital.com', +# recipient_list=[admission.attending_physician.email], +# fail_silently=True +# ) +# +# def notify_admission_complete(self, admission): +# """Notify relevant staff that admission is complete""" +# # Notify nursing staff +# nursing_staff = User.objects.filter( +# groups__name='Nursing Staff', +# profile__department=admission.current_ward +# ) +# +# for nurse in nursing_staff: +# send_mail( +# subject=f'New Patient Admitted: {admission.patient.get_full_name()}', +# message=f'Patient has been admitted to {admission.current_bed.room_number if admission.current_bed else "TBD"}.', +# from_email='admissions@hospital.com', +# recipient_list=[nurse.email], +# fail_silently=True +# ) +# +# def generate_admission_summary(self, admission): +# """Generate admission summary report""" +# # This would generate a comprehensive admission report +# pass +# +# +# class TransferProcess(Process): +# """ +# Viewflow process model for patient transfers +# """ +# transfer = ModelField(Transfer, help_text='Associated transfer record') +# +# # Process status tracking +# request_approved = models.BooleanField(default=False) +# bed_prepared = models.BooleanField(default=False) +# transport_arranged = models.BooleanField(default=False) +# handoff_completed = models.BooleanField(default=False) +# transfer_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Transfer Process' +# verbose_name_plural = 'Transfer Processes' +# +# +# class TransferFlow(Flow): +# """ +# Hospital Patient Transfer Workflow +# +# This flow manages patient transfers between wards, beds, or units. +# """ +# +# process_class = TransferProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_transfer) +# .Next(this.transfer_request) +# ) +# +# transfer_request = ( +# flow_view(TransferRequestView) +# .Permission('inpatients.can_request_transfers') +# .Next(this.transfer_approval) +# ) +# +# transfer_approval = ( +# flow_view(TransferApprovalView) +# .Permission('inpatients.can_approve_transfers') +# .Next(this.prepare_destination) +# ) +# +# prepare_destination = ( +# flow_func(this.prepare_bed) +# .Next(this.arrange_transport) +# ) +# +# arrange_transport = ( +# flow_func(this.schedule_transport) +# .Next(this.execute_transfer) +# ) +# +# execute_transfer = ( +# flow_view(TransferExecutionView) +# .Permission('inpatients.can_execute_transfers') +# .Next(this.complete_transfer) +# ) +# +# complete_transfer = ( +# flow_func(this.finalize_transfer) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_transfer) +# +# # Flow functions +# def start_transfer(self, activation): +# """Initialize the transfer process""" +# process = activation.process +# transfer = process.transfer +# +# # Update transfer status +# transfer.status = 'REQUESTED' +# transfer.save() +# +# # Notify receiving ward +# self.notify_receiving_ward(transfer) +# +# def prepare_bed(self, activation): +# """Prepare destination bed""" +# process = activation.process +# transfer = process.transfer +# +# if transfer.to_bed: +# # Reserve the destination bed +# transfer.to_bed.status = 'RESERVED' +# transfer.to_bed.reserved_until = timezone.now() + timezone.timedelta(hours=2) +# transfer.to_bed.save() +# +# process.bed_prepared = True +# process.save() +# +# def schedule_transport(self, activation): +# """Schedule patient transport""" +# process = activation.process +# transfer = process.transfer +# +# # Auto-schedule transport based on priority +# if transfer.priority in ['EMERGENT', 'STAT']: +# transfer.scheduled_datetime = timezone.now() + timezone.timedelta(minutes=15) +# elif transfer.priority == 'URGENT': +# transfer.scheduled_datetime = timezone.now() + timezone.timedelta(hours=1) +# else: +# transfer.scheduled_datetime = timezone.now() + timezone.timedelta(hours=4) +# +# transfer.save() +# +# process.transport_arranged = True +# process.save() +# +# # Notify transport team +# self.notify_transport_team(transfer) +# +# def finalize_transfer(self, activation): +# """Finalize the transfer process""" +# process = activation.process +# transfer = process.transfer +# admission = transfer.admission +# +# # Update admission location +# admission.current_ward = transfer.to_ward +# admission.current_bed = transfer.to_bed +# admission.save() +# +# # Update bed statuses +# if transfer.from_bed: +# transfer.from_bed.status = 'AVAILABLE' +# transfer.from_bed.current_patient = None +# transfer.from_bed.current_admission = None +# transfer.from_bed.occupied_since = None +# transfer.from_bed.save() +# +# if transfer.to_bed: +# transfer.to_bed.status = 'OCCUPIED' +# transfer.to_bed.current_patient = transfer.patient +# transfer.to_bed.current_admission = admission +# transfer.to_bed.occupied_since = timezone.now() +# transfer.to_bed.save() +# +# # Update transfer status +# transfer.status = 'COMPLETED' +# transfer.actual_datetime = timezone.now() +# transfer.save() +# +# process.transfer_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_transfer_complete(transfer) +# +# def end_transfer(self, activation): +# """End the transfer workflow""" +# process = activation.process +# +# # Generate transfer summary +# self.generate_transfer_summary(process.transfer) +# +# # Helper methods +# def notify_receiving_ward(self, transfer): +# """Notify receiving ward of incoming transfer""" +# receiving_staff = User.objects.filter( +# groups__name='Nursing Staff', +# profile__department=transfer.to_ward +# ) +# +# for staff in receiving_staff: +# send_mail( +# subject=f'Incoming Transfer: {transfer.patient.get_full_name()}', +# message=f'Patient transfer requested from {transfer.from_ward.name}.', +# from_email='transfers@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_transport_team(self, transfer): +# """Notify transport team of scheduled transfer""" +# transport_staff = User.objects.filter( +# groups__name='Transport Team' +# ) +# +# for staff in transport_staff: +# send_mail( +# subject=f'Transport Scheduled: {transfer.patient.get_full_name()}', +# message=f'Transfer scheduled for {transfer.scheduled_datetime}.', +# from_email='transport@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_transfer_complete(self, transfer): +# """Notify relevant staff that transfer is complete""" +# # Notify both sending and receiving wards +# all_staff = User.objects.filter( +# groups__name='Nursing Staff', +# profile__department__in=[transfer.from_ward, transfer.to_ward] +# ) +# +# for staff in all_staff: +# send_mail( +# subject=f'Transfer Complete: {transfer.patient.get_full_name()}', +# message=f'Patient transfer from {transfer.from_ward.name} to {transfer.to_ward.name} completed.', +# from_email='transfers@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def generate_transfer_summary(self, transfer): +# """Generate transfer summary report""" +# # This would generate a comprehensive transfer report +# pass +# +# +# class DischargeProcess(Process): +# """ +# Viewflow process model for patient discharges +# """ +# admission = ModelField(Admission, help_text='Associated admission record') +# discharge_summary = ModelField(DischargeSummary, null=True, blank=True, +# help_text='Associated discharge summary') +# +# # Process status tracking +# discharge_planning_started = models.BooleanField(default=False) +# discharge_orders_written = models.BooleanField(default=False) +# discharge_summary_completed = models.BooleanField(default=False) +# patient_education_completed = models.BooleanField(default=False) +# medications_reconciled = models.BooleanField(default=False) +# follow_up_scheduled = models.BooleanField(default=False) +# discharge_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Discharge Process' +# verbose_name_plural = 'Discharge Processes' +# +# +# class DischargeFlow(Flow): +# """ +# Hospital Patient Discharge Workflow +# +# This flow manages the complete patient discharge process from +# discharge planning through final discharge completion. +# """ +# +# process_class = DischargeProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_discharge) +# .Next(this.discharge_planning) +# ) +# +# discharge_planning = ( +# flow_view(DischargePlanningView) +# .Permission('inpatients.can_plan_discharges') +# .Next(this.write_discharge_orders) +# ) +# +# write_discharge_orders = ( +# flow_view(DischargeOrdersView) +# .Permission('inpatients.can_write_discharge_orders') +# .Next(this.parallel_discharge_tasks) +# ) +# +# parallel_discharge_tasks = ( +# flow_func(this.start_parallel_discharge_tasks) +# .Next(this.complete_discharge_summary) +# .Next(this.patient_education) +# .Next(this.medication_reconciliation) +# .Next(this.schedule_follow_up) +# ) +# +# complete_discharge_summary = ( +# flow_view(DischargeDocumentationView) +# .Permission('inpatients.can_complete_discharge_summary') +# .Next(this.join_discharge_tasks) +# ) +# +# patient_education = ( +# flow_view(PatientEducationView) +# .Permission('inpatients.can_provide_patient_education') +# .Next(this.join_discharge_tasks) +# ) +# +# medication_reconciliation = ( +# flow_view(MedicationReconciliationView) +# .Permission('inpatients.can_reconcile_medications') +# .Next(this.join_discharge_tasks) +# ) +# +# schedule_follow_up = ( +# flow_view(FollowUpSchedulingView) +# .Permission('inpatients.can_schedule_follow_up') +# .Next(this.join_discharge_tasks) +# ) +# +# join_discharge_tasks = ( +# flow_func(this.join_parallel_discharge_tasks) +# .Next(this.execute_discharge) +# ) +# +# execute_discharge = ( +# flow_view(DischargeExecutionView) +# .Permission('inpatients.can_execute_discharges') +# .Next(this.finalize_discharge) +# ) +# +# finalize_discharge = ( +# flow_func(this.complete_discharge) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_discharge) +# +# # Flow functions +# def start_discharge(self, activation): +# """Initialize the discharge process""" +# process = activation.process +# admission = process.admission +# +# # Update admission discharge planning status +# admission.discharge_planning_started = True +# admission.save() +# +# # Notify discharge planning team +# self.notify_discharge_planning_team(admission) +# +# def start_parallel_discharge_tasks(self, activation): +# """Start parallel discharge preparation tasks""" +# process = activation.process +# +# # Create discharge preparation tasks +# self.create_discharge_tasks(process) +# +# def join_parallel_discharge_tasks(self, activation): +# """Wait for all discharge tasks to complete""" +# process = activation.process +# +# # Check if all discharge tasks are completed +# if (process.discharge_summary_completed and +# process.patient_education_completed and +# process.medications_reconciled and +# process.follow_up_scheduled): +# +# # Notify that patient is ready for discharge +# self.notify_ready_for_discharge(process.admission) +# +# def complete_discharge(self, activation): +# """Finalize the discharge process""" +# process = activation.process +# admission = process.admission +# +# # Update admission status +# admission.status = 'DISCHARGED' +# admission.discharge_datetime = timezone.now() +# admission.save() +# +# # Update bed status +# if admission.current_bed: +# admission.current_bed.status = 'CLEANING' +# admission.current_bed.current_patient = None +# admission.current_bed.current_admission = None +# admission.current_bed.occupied_since = None +# admission.current_bed.save() +# +# # Mark process as completed +# process.discharge_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_discharge_complete(admission) +# +# def end_discharge(self, activation): +# """End the discharge workflow""" +# process = activation.process +# +# # Generate discharge summary report +# self.generate_final_discharge_report(process.admission) +# +# # Helper methods +# def notify_discharge_planning_team(self, admission): +# """Notify discharge planning team""" +# discharge_planners = User.objects.filter( +# groups__name='Discharge Planning' +# ) +# +# for planner in discharge_planners: +# send_mail( +# subject=f'Discharge Planning Required: {admission.patient.get_full_name()}', +# message=f'Discharge planning has been initiated.', +# from_email='discharge@hospital.com', +# recipient_list=[planner.email], +# fail_silently=True +# ) +# +# def create_discharge_tasks(self, process): +# """Create discharge preparation tasks""" +# # This would create tasks in a task management system +# pass +# +# def notify_ready_for_discharge(self, admission): +# """Notify that patient is ready for discharge""" +# if admission.attending_physician and admission.attending_physician.email: +# send_mail( +# subject=f'Patient Ready for Discharge: {admission.patient.get_full_name()}', +# message=f'All discharge preparations are complete.', +# from_email='discharge@hospital.com', +# recipient_list=[admission.attending_physician.email], +# fail_silently=True +# ) +# +# def notify_discharge_complete(self, admission): +# """Notify relevant staff that discharge is complete""" +# # Notify nursing staff and housekeeping +# relevant_staff = User.objects.filter( +# groups__name__in=['Nursing Staff', 'Housekeeping'], +# profile__department=admission.current_ward +# ) +# +# for staff in relevant_staff: +# send_mail( +# subject=f'Patient Discharged: {admission.patient.get_full_name()}', +# message=f'Patient has been discharged from {admission.current_bed.room_number if admission.current_bed else "ward"}.', +# from_email='discharge@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def generate_final_discharge_report(self, admission): +# """Generate final discharge report""" +# # This would generate a comprehensive discharge report +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_assign_bed(admission_id, ward_id): +# """Background task to automatically assign available bed""" +# try: +# admission = Admission.objects.get(id=admission_id) +# ward = Ward.objects.get(id=ward_id) +# +# available_bed = Bed.objects.filter( +# ward=ward, +# status='AVAILABLE' +# ).first() +# +# if available_bed: +# admission.current_bed = available_bed +# available_bed.status = 'RESERVED' +# available_bed.save() +# admission.save() +# return True +# +# return False +# except (Admission.DoesNotExist, Ward.DoesNotExist): +# return False +# +# +# @celery.job +# def schedule_discharge_planning(admission_id, days_before_discharge=2): +# """Background task to schedule discharge planning""" +# try: +# admission = Admission.objects.get(id=admission_id) +# +# if admission.estimated_length_of_stay: +# planning_date = admission.admission_datetime + timezone.timedelta( +# days=admission.estimated_length_of_stay - days_before_discharge +# ) +# +# # Schedule discharge planning +# # This would integrate with a scheduling system +# return True +# +# return False +# except Admission.DoesNotExist: +# return False +# +# +# @celery.job +# def generate_encounter_number(): +# """Generate unique encounter number""" +# from django.utils.crypto import get_random_string +# return f"ENC{timezone.now().strftime('%Y%m%d')}{get_random_string(4, '0123456789')}" +# diff --git a/integration/__pycache__/flows.cpython-312.pyc b/integration/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..2b3c2434 Binary files /dev/null and b/integration/__pycache__/flows.cpython-312.pyc differ diff --git a/integration/flows.py b/integration/flows.py new file mode 100644 index 00000000..23834ca0 --- /dev/null +++ b/integration/flows.py @@ -0,0 +1,781 @@ +# """ +# Viewflow workflows for integration app. +# Provides external system integration, data synchronization, and API management workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import ( +# ExternalSystem, IntegrationEndpoint, DataMapping, SyncConfiguration, +# IntegrationExecution, WebhookEndpoint, WebhookExecution, IntegrationLog +# ) +# from .views import ( +# SystemSetupView, EndpointConfigurationView, DataMappingView, +# SyncConfigurationView, TestConnectionView, MonitoringView, +# WebhookManagementView, SecurityConfigurationView, PerformanceOptimizationView +# ) +# +# +# class SystemIntegrationProcess(Process): +# """ +# Viewflow process model for system integration +# """ +# external_system = ModelField(ExternalSystem, help_text='Associated external system') +# +# # Process status tracking +# system_registered = models.BooleanField(default=False) +# connection_tested = models.BooleanField(default=False) +# endpoints_configured = models.BooleanField(default=False) +# data_mapping_created = models.BooleanField(default=False) +# security_configured = models.BooleanField(default=False) +# testing_completed = models.BooleanField(default=False) +# monitoring_setup = models.BooleanField(default=False) +# integration_activated = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'System Integration Process' +# verbose_name_plural = 'System Integration Processes' +# +# +# class SystemIntegrationFlow(Flow): +# """ +# System Integration Workflow +# +# This flow manages complete external system integration including +# setup, configuration, testing, and activation. +# """ +# +# process_class = SystemIntegrationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_system_integration) +# .Next(this.register_system) +# ) +# +# register_system = ( +# flow_view(SystemSetupView) +# .Permission('integration.can_setup_systems') +# .Next(this.test_connection) +# ) +# +# test_connection = ( +# flow_view(TestConnectionView) +# .Permission('integration.can_test_connections') +# .Next(this.configure_endpoints) +# ) +# +# configure_endpoints = ( +# flow_view(EndpointConfigurationView) +# .Permission('integration.can_configure_endpoints') +# .Next(this.create_data_mapping) +# ) +# +# create_data_mapping = ( +# flow_view(DataMappingView) +# .Permission('integration.can_create_mappings') +# .Next(this.configure_security) +# ) +# +# configure_security = ( +# flow_view(SecurityConfigurationView) +# .Permission('integration.can_configure_security') +# .Next(this.complete_testing) +# ) +# +# complete_testing = ( +# flow_func(this.perform_integration_testing) +# .Next(this.setup_monitoring) +# ) +# +# setup_monitoring = ( +# flow_view(MonitoringView) +# .Permission('integration.can_setup_monitoring') +# .Next(this.activate_integration) +# ) +# +# activate_integration = ( +# flow_func(this.activate_system_integration) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_system_integration) +# +# # Flow functions +# def start_system_integration(self, activation): +# """Initialize the system integration process""" +# process = activation.process +# system = process.external_system +# +# # Send integration notification +# self.notify_integration_start(system) +# +# # Create integration checklist +# self.create_integration_checklist(system) +# +# # Initialize integration logging +# self.setup_integration_logging(system) +# +# def perform_integration_testing(self, activation): +# """Perform comprehensive integration testing""" +# process = activation.process +# system = process.external_system +# +# # Execute integration tests +# test_results = self.execute_integration_tests(system) +# +# # Mark testing completed +# process.testing_completed = True +# process.save() +# +# # Store test results +# self.store_integration_test_results(system, test_results) +# +# # Validate test results +# self.validate_test_results(system, test_results) +# +# def activate_system_integration(self, activation): +# """Activate the system integration""" +# process = activation.process +# system = process.external_system +# +# # Activate system +# system.is_active = True +# system.save() +# +# # Mark integration activated +# process.integration_activated = True +# process.save() +# +# # Send activation notifications +# self.notify_integration_activation(system) +# +# # Schedule health checks +# self.schedule_health_checks(system) +# +# # Start monitoring +# self.start_integration_monitoring(system) +# +# def end_system_integration(self, activation): +# """End the system integration workflow""" +# process = activation.process +# +# # Generate integration summary +# self.generate_integration_summary(process.external_system) +# +# # Helper methods +# def notify_integration_start(self, system): +# """Notify integration start""" +# integration_team = User.objects.filter(groups__name='Integration Team') +# for staff in integration_team: +# send_mail( +# subject=f'System Integration Started: {system.name}', +# message=f'Integration process started for "{system.name}".', +# from_email='integration@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def create_integration_checklist(self, system): +# """Create integration checklist""" +# # This would create integration checklist +# pass +# +# def setup_integration_logging(self, system): +# """Setup integration logging""" +# IntegrationLog.objects.create( +# external_system=system, +# level='info', +# category='system', +# message=f'Integration process started for {system.name}' +# ) +# +# def execute_integration_tests(self, system): +# """Execute comprehensive integration tests""" +# # This would run integration tests +# return {'status': 'passed', 'tests_run': 10, 'failures': 0} +# +# def store_integration_test_results(self, system, results): +# """Store integration test results""" +# # This would store test results +# pass +# +# def validate_test_results(self, system, results): +# """Validate integration test results""" +# # This would validate test results +# if results.get('failures', 0) > 0: +# raise Exception('Integration tests failed') +# +# def notify_integration_activation(self, system): +# """Notify integration activation""" +# # Notify relevant teams +# integration_team = User.objects.filter(groups__name='Integration Team') +# for staff in integration_team: +# send_mail( +# subject=f'System Integration Activated: {system.name}', +# message=f'Integration for "{system.name}" has been activated.', +# from_email='integration@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def schedule_health_checks(self, system): +# """Schedule periodic health checks""" +# # Schedule health check task +# system_health_check.apply_async( +# args=[system.system_id], +# countdown=300 # 5 minutes +# ) +# +# def start_integration_monitoring(self, system): +# """Start integration monitoring""" +# # This would start monitoring +# pass +# +# def generate_integration_summary(self, system): +# """Generate integration summary""" +# # This would generate integration summary +# pass +# +# +# class DataSynchronizationProcess(Process): +# """ +# Viewflow process model for data synchronization +# """ +# sync_configuration = ModelField(SyncConfiguration, help_text='Associated sync configuration') +# +# # Process status tracking +# sync_initiated = models.BooleanField(default=False) +# data_extracted = models.BooleanField(default=False) +# data_transformed = models.BooleanField(default=False) +# data_validated = models.BooleanField(default=False) +# data_loaded = models.BooleanField(default=False) +# conflicts_resolved = models.BooleanField(default=False) +# sync_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Data Synchronization Process' +# verbose_name_plural = 'Data Synchronization Processes' +# +# +# class DataSynchronizationFlow(Flow): +# """ +# Data Synchronization Workflow +# +# This flow manages automated data synchronization between +# external systems and the hospital management system. +# """ +# +# process_class = DataSynchronizationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_data_synchronization) +# .Next(this.initiate_sync) +# ) +# +# initiate_sync = ( +# flow_func(this.setup_sync_process) +# .Next(this.extract_data) +# ) +# +# extract_data = ( +# flow_func(this.perform_data_extraction) +# .Next(this.transform_data) +# ) +# +# transform_data = ( +# flow_func(this.perform_data_transformation) +# .Next(this.validate_data) +# ) +# +# validate_data = ( +# flow_func(this.perform_data_validation) +# .Next(this.load_data) +# ) +# +# load_data = ( +# flow_func(this.perform_data_loading) +# .Next(this.resolve_conflicts) +# ) +# +# resolve_conflicts = ( +# flow_func(this.handle_data_conflicts) +# .Next(this.complete_sync) +# ) +# +# complete_sync = ( +# flow_func(this.finalize_data_synchronization) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_data_synchronization) +# +# # Flow functions +# def start_data_synchronization(self, activation): +# """Initialize the data synchronization process""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Send sync notification +# self.notify_sync_start(sync_config) +# +# # Create sync execution record +# self.create_sync_execution(sync_config) +# +# def setup_sync_process(self, activation): +# """Setup synchronization process""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Mark sync initiated +# process.sync_initiated = True +# process.save() +# +# # Prepare sync environment +# self.prepare_sync_environment(sync_config) +# +# def perform_data_extraction(self, activation): +# """Extract data from source system""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Extract data +# extracted_data = self.extract_source_data(sync_config) +# +# # Mark data extracted +# process.data_extracted = True +# process.save() +# +# # Store extracted data +# self.store_extracted_data(sync_config, extracted_data) +# +# def perform_data_transformation(self, activation): +# """Transform data according to mapping rules""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Transform data +# transformed_data = self.transform_sync_data(sync_config) +# +# # Mark data transformed +# process.data_transformed = True +# process.save() +# +# # Store transformed data +# self.store_transformed_data(sync_config, transformed_data) +# +# def perform_data_validation(self, activation): +# """Validate transformed data""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Validate data +# validation_results = self.validate_sync_data(sync_config) +# +# # Mark data validated +# process.data_validated = True +# process.save() +# +# # Store validation results +# self.store_validation_results(sync_config, validation_results) +# +# def perform_data_loading(self, activation): +# """Load data into target system""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Load data +# loading_results = self.load_sync_data(sync_config) +# +# # Mark data loaded +# process.data_loaded = True +# process.save() +# +# # Store loading results +# self.store_loading_results(sync_config, loading_results) +# +# def handle_data_conflicts(self, activation): +# """Handle data conflicts and duplicates""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Resolve conflicts +# conflict_results = self.resolve_data_conflicts(sync_config) +# +# # Mark conflicts resolved +# process.conflicts_resolved = True +# process.save() +# +# # Store conflict resolution results +# self.store_conflict_results(sync_config, conflict_results) +# +# def finalize_data_synchronization(self, activation): +# """Finalize the data synchronization process""" +# process = activation.process +# sync_config = process.sync_configuration +# +# # Mark sync completed +# process.sync_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_sync_completion(sync_config) +# +# # Update sync statistics +# self.update_sync_statistics(sync_config) +# +# # Schedule next sync if recurring +# self.schedule_next_sync(sync_config) +# +# def end_data_synchronization(self, activation): +# """End the data synchronization workflow""" +# process = activation.process +# +# # Generate sync summary +# self.generate_sync_summary(process.sync_configuration) +# +# # Helper methods +# def notify_sync_start(self, sync_config): +# """Notify sync start""" +# # This would notify relevant parties +# pass +# +# def create_sync_execution(self, sync_config): +# """Create sync execution record""" +# # This would create execution record +# pass +# +# def prepare_sync_environment(self, sync_config): +# """Prepare synchronization environment""" +# # This would prepare sync environment +# pass +# +# def extract_source_data(self, sync_config): +# """Extract data from source system""" +# # This would extract data from source +# return {'status': 'extracted', 'records': 1000} +# +# def store_extracted_data(self, sync_config, data): +# """Store extracted data""" +# # This would store extracted data +# pass +# +# def transform_sync_data(self, sync_config): +# """Transform data according to mapping""" +# # This would transform data +# return {'status': 'transformed', 'records': 1000} +# +# def store_transformed_data(self, sync_config, data): +# """Store transformed data""" +# # This would store transformed data +# pass +# +# def validate_sync_data(self, sync_config): +# """Validate transformed data""" +# # This would validate data +# return {'status': 'valid', 'errors': []} +# +# def store_validation_results(self, sync_config, results): +# """Store validation results""" +# # This would store validation results +# pass +# +# def load_sync_data(self, sync_config): +# """Load data into target system""" +# # This would load data +# return {'status': 'loaded', 'records': 1000} +# +# def store_loading_results(self, sync_config, results): +# """Store loading results""" +# # This would store loading results +# pass +# +# def resolve_data_conflicts(self, sync_config): +# """Resolve data conflicts""" +# # This would resolve conflicts +# return {'status': 'resolved', 'conflicts': 0} +# +# def store_conflict_results(self, sync_config, results): +# """Store conflict resolution results""" +# # This would store conflict results +# pass +# +# def notify_sync_completion(self, sync_config): +# """Notify sync completion""" +# # This would notify completion +# pass +# +# def update_sync_statistics(self, sync_config): +# """Update synchronization statistics""" +# # This would update sync stats +# pass +# +# def schedule_next_sync(self, sync_config): +# """Schedule next synchronization""" +# if sync_config.is_recurring: +# # Schedule next sync +# data_sync.apply_async( +# args=[sync_config.sync_id], +# countdown=sync_config.sync_interval_seconds +# ) +# +# def generate_sync_summary(self, sync_config): +# """Generate synchronization summary""" +# # This would generate sync summary +# pass +# +# +# class WebhookManagementProcess(Process): +# """ +# Viewflow process model for webhook management +# """ +# webhook_endpoint = ModelField(WebhookEndpoint, help_text='Associated webhook endpoint') +# +# # Process status tracking +# webhook_created = models.BooleanField(default=False) +# security_configured = models.BooleanField(default=False) +# testing_completed = models.BooleanField(default=False) +# monitoring_setup = models.BooleanField(default=False) +# webhook_activated = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Webhook Management Process' +# verbose_name_plural = 'Webhook Management Processes' +# +# +# class WebhookManagementFlow(Flow): +# """ +# Webhook Management Workflow +# +# This flow manages webhook endpoint creation, configuration, +# testing, and activation for receiving external data. +# """ +# +# process_class = WebhookManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_webhook_management) +# .Next(this.create_webhook) +# ) +# +# create_webhook = ( +# flow_view(WebhookManagementView) +# .Permission('integration.can_manage_webhooks') +# .Next(this.configure_security) +# ) +# +# configure_security = ( +# flow_func(this.setup_webhook_security) +# .Next(this.test_webhook) +# ) +# +# test_webhook = ( +# flow_func(this.perform_webhook_testing) +# .Next(this.setup_monitoring) +# ) +# +# setup_monitoring = ( +# flow_func(this.configure_webhook_monitoring) +# .Next(this.activate_webhook) +# ) +# +# activate_webhook = ( +# flow_func(this.activate_webhook_endpoint) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_webhook_management) +# +# # Flow functions +# def start_webhook_management(self, activation): +# """Initialize the webhook management process""" +# process = activation.process +# webhook = process.webhook_endpoint +# +# # Send webhook creation notification +# self.notify_webhook_creation(webhook) +# +# def setup_webhook_security(self, activation): +# """Setup webhook security configuration""" +# process = activation.process +# webhook = process.webhook_endpoint +# +# # Configure security settings +# self.configure_webhook_security(webhook) +# +# # Mark security configured +# process.security_configured = True +# process.save() +# +# def perform_webhook_testing(self, activation): +# """Perform webhook testing""" +# process = activation.process +# webhook = process.webhook_endpoint +# +# # Test webhook functionality +# test_results = self.test_webhook_functionality(webhook) +# +# # Mark testing completed +# process.testing_completed = True +# process.save() +# +# # Store test results +# self.store_webhook_test_results(webhook, test_results) +# +# def configure_webhook_monitoring(self, activation): +# """Configure webhook monitoring""" +# process = activation.process +# webhook = process.webhook_endpoint +# +# # Setup monitoring +# self.setup_webhook_monitoring(webhook) +# +# # Mark monitoring setup +# process.monitoring_setup = True +# process.save() +# +# def activate_webhook_endpoint(self, activation): +# """Activate webhook endpoint""" +# process = activation.process +# webhook = process.webhook_endpoint +# +# # Activate webhook +# webhook.is_active = True +# webhook.save() +# +# # Mark webhook activated +# process.webhook_activated = True +# process.save() +# +# # Send activation notifications +# self.notify_webhook_activation(webhook) +# +# def end_webhook_management(self, activation): +# """End the webhook management workflow""" +# process = activation.process +# +# # Generate webhook summary +# self.generate_webhook_summary(process.webhook_endpoint) +# +# # Helper methods +# def notify_webhook_creation(self, webhook): +# """Notify webhook creation""" +# integration_team = User.objects.filter(groups__name='Integration Team') +# for staff in integration_team: +# send_mail( +# subject=f'Webhook Created: {webhook.name}', +# message=f'Webhook endpoint "{webhook.name}" has been created.', +# from_email='integration@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def configure_webhook_security(self, webhook): +# """Configure webhook security""" +# # This would configure security settings +# pass +# +# def test_webhook_functionality(self, webhook): +# """Test webhook functionality""" +# # This would test webhook +# return {'status': 'passed', 'tests': 5} +# +# def store_webhook_test_results(self, webhook, results): +# """Store webhook test results""" +# # This would store test results +# pass +# +# def setup_webhook_monitoring(self, webhook): +# """Setup webhook monitoring""" +# # This would setup monitoring +# pass +# +# def notify_webhook_activation(self, webhook): +# """Notify webhook activation""" +# # This would notify activation +# pass +# +# def generate_webhook_summary(self, webhook): +# """Generate webhook summary""" +# # This would generate webhook summary +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def system_health_check(system_id): +# """Background task for system health monitoring""" +# try: +# system = ExternalSystem.objects.get(system_id=system_id) +# +# # Perform health check +# # This would perform system health check +# +# # Schedule next health check +# system_health_check.apply_async( +# args=[system_id], +# countdown=300 # 5 minutes +# ) +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def data_sync(sync_id): +# """Background task for data synchronization""" +# try: +# sync_config = SyncConfiguration.objects.get(sync_id=sync_id) +# +# # Start data synchronization workflow +# # This would start the data sync workflow +# +# return True +# except Exception: +# return False +# +# +# @celery.job +# def webhook_health_check(): +# """Background task for webhook health monitoring""" +# try: +# # This would monitor webhook health +# return True +# except Exception: +# return False +# +# +# @celery.job +# def integration_performance_monitoring(): +# """Background task for integration performance monitoring""" +# try: +# # This would monitor integration performance +# return True +# except Exception: +# return False +# +# +# @celery.job +# def cleanup_integration_logs(): +# """Background task to cleanup old integration logs""" +# try: +# # This would cleanup old logs +# return True +# except Exception: +# return False +# diff --git a/inventory/__pycache__/flows.cpython-312.pyc b/inventory/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..98e4ebf1 Binary files /dev/null and b/inventory/__pycache__/flows.cpython-312.pyc differ diff --git a/inventory/flows.py b/inventory/flows.py new file mode 100644 index 00000000..845c5d5e --- /dev/null +++ b/inventory/flows.py @@ -0,0 +1,905 @@ +# """ +# Viewflow workflows for inventory app. +# Provides inventory management, procurement, and supply chain workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import InventoryItem, PurchaseOrder, PurchaseOrderItem, Supplier, InventoryStock, InventoryLocation +# from .views import ( +# PurchaseRequestView, VendorSelectionView, PurchaseOrderCreationView, +# ApprovalView, OrderSubmissionView, ReceivingView, InspectionView, +# StockUpdateView, InvoiceMatchingView, PaymentProcessingView, +# StockReplenishmentView, StockTransferView, StockAdjustmentView, +# CycleCountView, InventoryAuditView +# ) +# +# +# class ProcurementProcess(Process): +# """ +# Viewflow process model for procurement +# """ +# purchase_order = ModelField(PurchaseOrder, help_text='Associated purchase order') +# +# # Process status tracking +# request_submitted = models.BooleanField(default=False) +# vendor_selected = models.BooleanField(default=False) +# order_created = models.BooleanField(default=False) +# order_approved = models.BooleanField(default=False) +# order_sent = models.BooleanField(default=False) +# goods_received = models.BooleanField(default=False) +# invoice_processed = models.BooleanField(default=False) +# payment_completed = models.BooleanField(default=False) +# procurement_closed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Procurement Process' +# verbose_name_plural = 'Procurement Processes' +# +# +# class ProcurementFlow(Flow): +# """ +# Procurement Workflow +# +# This flow manages the complete procurement process from purchase +# request through payment and order closure. +# """ +# +# process_class = ProcurementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_procurement) +# .Next(this.submit_request) +# ) +# +# submit_request = ( +# flow_view(PurchaseRequestView) +# .Permission('inventory.can_submit_purchase_requests') +# .Next(this.select_vendor) +# ) +# +# select_vendor = ( +# flow_view(VendorSelectionView) +# .Permission('inventory.can_select_vendors') +# .Next(this.create_order) +# ) +# +# create_order = ( +# flow_view(PurchaseOrderCreationView) +# .Permission('inventory.can_create_purchase_orders') +# .Next(this.approve_order) +# ) +# +# approve_order = ( +# flow_view(ApprovalView) +# .Permission('inventory.can_approve_purchase_orders') +# .Next(this.send_order) +# ) +# +# send_order = ( +# flow_view(OrderSubmissionView) +# .Permission('inventory.can_send_purchase_orders') +# .Next(this.receive_goods) +# ) +# +# receive_goods = ( +# flow_view(ReceivingView) +# .Permission('inventory.can_receive_goods') +# .Next(this.inspect_goods) +# ) +# +# inspect_goods = ( +# flow_view(InspectionView) +# .Permission('inventory.can_inspect_goods') +# .Next(this.update_stock) +# ) +# +# update_stock = ( +# flow_view(StockUpdateView) +# .Permission('inventory.can_update_stock') +# .Next(this.process_invoice) +# ) +# +# process_invoice = ( +# flow_view(InvoiceMatchingView) +# .Permission('inventory.can_process_invoices') +# .Next(this.process_payment) +# ) +# +# process_payment = ( +# flow_view(PaymentProcessingView) +# .Permission('inventory.can_process_payments') +# .Next(this.close_order) +# ) +# +# close_order = ( +# flow_func(this.complete_procurement) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_procurement) +# +# # Flow functions +# def start_procurement(self, activation): +# """Initialize the procurement process""" +# process = activation.process +# order = process.purchase_order +# +# # Update order status +# order.status = 'DRAFT' +# order.save() +# +# # Send notification to procurement staff +# self.notify_procurement_staff(order) +# +# # Check for urgent orders +# if order.priority in ['HIGH', 'URGENT']: +# self.notify_urgent_procurement(order) +# +# def complete_procurement(self, activation): +# """Finalize the procurement process""" +# process = activation.process +# order = process.purchase_order +# +# # Update order status +# order.status = 'CLOSED' +# order.save() +# +# # Mark process as completed +# process.procurement_closed = True +# process.save() +# +# # Send completion notifications +# self.notify_procurement_completion(order) +# +# # Update supplier performance metrics +# self.update_supplier_performance(order) +# +# # Update procurement metrics +# self.update_procurement_metrics(order) +# +# def end_procurement(self, activation): +# """End the procurement workflow""" +# process = activation.process +# +# # Generate procurement summary report +# self.generate_procurement_summary(process.purchase_order) +# +# # Helper methods +# def notify_procurement_staff(self, order): +# """Notify procurement staff of new order""" +# from django.contrib.auth.models import Group +# +# procurement_staff = User.objects.filter( +# groups__name='Procurement Staff' +# ) +# +# for staff in procurement_staff: +# send_mail( +# subject=f'New Purchase Order: {order.po_number}', +# message=f'New purchase order for {order.supplier.name} requires processing.', +# from_email='procurement@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_urgent_procurement(self, order): +# """Notify of urgent procurement""" +# procurement_managers = User.objects.filter( +# groups__name='Procurement Managers' +# ) +# +# for manager in procurement_managers: +# send_mail( +# subject=f'URGENT Purchase Order: {order.po_number}', +# message=f'{order.get_priority_display()} purchase order requires immediate attention.', +# from_email='procurement@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def notify_procurement_completion(self, order): +# """Notify procurement completion""" +# # Notify requestor +# if order.requested_by and order.requested_by.email: +# send_mail( +# subject=f'Purchase Order Complete: {order.po_number}', +# message=f'Your purchase order has been completed and goods received.', +# from_email='procurement@hospital.com', +# recipient_list=[order.requested_by.email], +# fail_silently=True +# ) +# +# def update_supplier_performance(self, order): +# """Update supplier performance metrics""" +# supplier = order.supplier +# +# # Calculate on-time delivery +# if order.actual_delivery_date and order.promised_delivery_date: +# if order.actual_delivery_date <= order.promised_delivery_date: +# # Update on-time delivery rate +# pass +# +# # This would update comprehensive supplier metrics +# pass +# +# def update_procurement_metrics(self, order): +# """Update procurement performance metrics""" +# # This would update procurement cycle time and other metrics +# pass +# +# def generate_procurement_summary(self, order): +# """Generate procurement summary report""" +# # This would generate a comprehensive procurement report +# pass +# +# +# class InventoryReplenishmentProcess(Process): +# """ +# Viewflow process model for inventory replenishment +# """ +# inventory_item = ModelField(InventoryItem, help_text='Associated inventory item') +# +# # Process status tracking +# reorder_triggered = models.BooleanField(default=False) +# demand_analyzed = models.BooleanField(default=False) +# quantity_calculated = models.BooleanField(default=False) +# supplier_contacted = models.BooleanField(default=False) +# order_placed = models.BooleanField(default=False) +# delivery_scheduled = models.BooleanField(default=False) +# stock_replenished = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Inventory Replenishment Process' +# verbose_name_plural = 'Inventory Replenishment Processes' +# +# +# class InventoryReplenishmentFlow(Flow): +# """ +# Inventory Replenishment Workflow +# +# This flow manages automatic and manual inventory replenishment +# including demand analysis and supplier coordination. +# """ +# +# process_class = InventoryReplenishmentProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_replenishment) +# .Next(this.trigger_reorder) +# ) +# +# trigger_reorder = ( +# flow_func(this.check_reorder_point) +# .Next(this.analyze_demand) +# ) +# +# analyze_demand = ( +# flow_view(DemandAnalysisView) +# .Permission('inventory.can_analyze_demand') +# .Next(this.calculate_quantity) +# ) +# +# calculate_quantity = ( +# flow_view(QuantityCalculationView) +# .Permission('inventory.can_calculate_quantities') +# .Next(this.contact_supplier) +# ) +# +# contact_supplier = ( +# flow_view(SupplierContactView) +# .Permission('inventory.can_contact_suppliers') +# .Next(this.place_order) +# ) +# +# place_order = ( +# flow_view(OrderPlacementView) +# .Permission('inventory.can_place_orders') +# .Next(this.schedule_delivery) +# ) +# +# schedule_delivery = ( +# flow_view(DeliverySchedulingView) +# .Permission('inventory.can_schedule_deliveries') +# .Next(this.replenish_stock) +# ) +# +# replenish_stock = ( +# flow_func(this.complete_replenishment) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_replenishment) +# +# # Flow functions +# def start_replenishment(self, activation): +# """Initialize the replenishment process""" +# process = activation.process +# item = process.inventory_item +# +# # Send notification to inventory staff +# self.notify_replenishment_needed(item) +# +# def check_reorder_point(self, activation): +# """Check if item has reached reorder point""" +# process = activation.process +# item = process.inventory_item +# +# # Check current stock levels +# current_stock = item.total_stock +# +# if current_stock <= item.reorder_point: +# process.reorder_triggered = True +# process.save() +# +# # Send urgent notification if below safety stock +# if current_stock <= item.safety_stock: +# self.notify_critical_stock(item) +# +# def complete_replenishment(self, activation): +# """Finalize the replenishment process""" +# process = activation.process +# item = process.inventory_item +# +# # Mark process as completed +# process.stock_replenished = True +# process.save() +# +# # Send completion notifications +# self.notify_replenishment_completion(item) +# +# # Update inventory metrics +# self.update_inventory_metrics(item) +# +# def end_replenishment(self, activation): +# """End the replenishment workflow""" +# process = activation.process +# +# # Generate replenishment summary +# self.generate_replenishment_summary(process.inventory_item) +# +# # Helper methods +# def notify_replenishment_needed(self, item): +# """Notify inventory staff of replenishment need""" +# inventory_staff = User.objects.filter( +# groups__name='Inventory Staff' +# ) +# +# for staff in inventory_staff: +# send_mail( +# subject=f'Replenishment Needed: {item.item_name}', +# message=f'Item {item.item_code} has reached reorder point.', +# from_email='inventory@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_critical_stock(self, item): +# """Notify of critical stock levels""" +# inventory_managers = User.objects.filter( +# groups__name='Inventory Managers' +# ) +# +# for manager in inventory_managers: +# send_mail( +# subject=f'CRITICAL STOCK: {item.item_name}', +# message=f'Item {item.item_code} is below safety stock level.', +# from_email='inventory@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def notify_replenishment_completion(self, item): +# """Notify replenishment completion""" +# # This would notify relevant staff +# pass +# +# def update_inventory_metrics(self, item): +# """Update inventory performance metrics""" +# # This would update inventory turnover and other metrics +# pass +# +# def generate_replenishment_summary(self, item): +# """Generate replenishment summary""" +# # This would generate replenishment summary +# pass +# +# +# class StockMovementProcess(Process): +# """ +# Viewflow process model for stock movements +# """ +# movement_type = CharField(max_length=20, help_text='Type of stock movement') +# item_id = CharField(max_length=50, help_text='Item identifier') +# +# # Process status tracking +# movement_initiated = models.BooleanField(default=False) +# authorization_verified = models.BooleanField(default=False) +# stock_reserved = models.BooleanField(default=False) +# movement_executed = models.BooleanField(default=False) +# documentation_completed = models.BooleanField(default=False) +# movement_verified = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Stock Movement Process' +# verbose_name_plural = 'Stock Movement Processes' +# +# +# class StockMovementFlow(Flow): +# """ +# Stock Movement Workflow +# +# This flow manages stock transfers, adjustments, and other +# inventory movements with proper authorization and tracking. +# """ +# +# process_class = StockMovementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_movement) +# .Next(this.initiate_movement) +# ) +# +# initiate_movement = ( +# flow_view(MovementInitiationView) +# .Permission('inventory.can_initiate_movements') +# .Next(this.verify_authorization) +# ) +# +# verify_authorization = ( +# flow_view(AuthorizationVerificationView) +# .Permission('inventory.can_verify_authorization') +# .Next(this.reserve_stock) +# ) +# +# reserve_stock = ( +# flow_view(StockReservationView) +# .Permission('inventory.can_reserve_stock') +# .Next(this.execute_movement) +# ) +# +# execute_movement = ( +# flow_view(MovementExecutionView) +# .Permission('inventory.can_execute_movements') +# .Next(this.complete_documentation) +# ) +# +# complete_documentation = ( +# flow_view(DocumentationView) +# .Permission('inventory.can_complete_documentation') +# .Next(this.verify_movement) +# ) +# +# verify_movement = ( +# flow_view(MovementVerificationView) +# .Permission('inventory.can_verify_movements') +# .Next(this.finalize_movement) +# ) +# +# finalize_movement = ( +# flow_func(this.complete_movement) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_movement) +# +# # Flow functions +# def start_movement(self, activation): +# """Initialize the stock movement process""" +# process = activation.process +# +# # Send notification to inventory staff +# self.notify_movement_initiated(process.movement_type, process.item_id) +# +# def complete_movement(self, activation): +# """Finalize the stock movement process""" +# process = activation.process +# +# # Mark process as completed +# process.movement_verified = True +# process.save() +# +# # Send completion notifications +# self.notify_movement_completion(process.movement_type, process.item_id) +# +# # Update inventory records +# self.update_inventory_records(process.movement_type, process.item_id) +# +# def end_movement(self, activation): +# """End the stock movement workflow""" +# process = activation.process +# +# # Generate movement summary +# self.generate_movement_summary(process.movement_type, process.item_id) +# +# # Helper methods +# def notify_movement_initiated(self, movement_type, item_id): +# """Notify inventory staff of movement initiation""" +# inventory_staff = User.objects.filter( +# groups__name='Inventory Staff' +# ) +# +# for staff in inventory_staff: +# send_mail( +# subject=f'Stock Movement Initiated: {item_id}', +# message=f'{movement_type} movement initiated for item {item_id}.', +# from_email='inventory@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_movement_completion(self, movement_type, item_id): +# """Notify movement completion""" +# # This would notify relevant staff +# pass +# +# def update_inventory_records(self, movement_type, item_id): +# """Update inventory records""" +# # This would update inventory records +# pass +# +# def generate_movement_summary(self, movement_type, item_id): +# """Generate movement summary""" +# # This would generate movement summary +# pass +# +# +# class InventoryAuditProcess(Process): +# """ +# Viewflow process model for inventory audits +# """ +# audit_type = CharField(max_length=20, help_text='Type of audit') +# location_id = CharField(max_length=50, help_text='Location identifier') +# +# # Process status tracking +# audit_scheduled = models.BooleanField(default=False) +# audit_team_assigned = models.BooleanField(default=False) +# physical_count_completed = models.BooleanField(default=False) +# discrepancies_identified = models.BooleanField(default=False) +# adjustments_made = models.BooleanField(default=False) +# audit_report_generated = models.BooleanField(default=False) +# audit_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Inventory Audit Process' +# verbose_name_plural = 'Inventory Audit Processes' +# +# +# class InventoryAuditFlow(Flow): +# """ +# Inventory Audit Workflow +# +# This flow manages inventory audits including cycle counts, +# physical inventories, and discrepancy resolution. +# """ +# +# process_class = InventoryAuditProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_audit) +# .Next(this.schedule_audit) +# ) +# +# schedule_audit = ( +# flow_view(AuditSchedulingView) +# .Permission('inventory.can_schedule_audits') +# .Next(this.assign_team) +# ) +# +# assign_team = ( +# flow_view(TeamAssignmentView) +# .Permission('inventory.can_assign_audit_teams') +# .Next(this.conduct_count) +# ) +# +# conduct_count = ( +# flow_view(CycleCountView) +# .Permission('inventory.can_conduct_counts') +# .Next(this.identify_discrepancies) +# ) +# +# identify_discrepancies = ( +# flow_func(this.analyze_discrepancies) +# .Next(this.make_adjustments) +# ) +# +# make_adjustments = ( +# flow_view(InventoryAdjustmentView) +# .Permission('inventory.can_make_adjustments') +# .Next(this.generate_report) +# ) +# +# generate_report = ( +# flow_view(AuditReportView) +# .Permission('inventory.can_generate_audit_reports') +# .Next(this.complete_audit) +# ) +# +# complete_audit = ( +# flow_func(this.finalize_audit) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_audit) +# +# # Flow functions +# def start_audit(self, activation): +# """Initialize the audit process""" +# process = activation.process +# +# # Send notification to audit team +# self.notify_audit_scheduled(process.audit_type, process.location_id) +# +# def analyze_discrepancies(self, activation): +# """Analyze inventory discrepancies""" +# process = activation.process +# +# # Check for discrepancies +# discrepancies = self.check_discrepancies(process.location_id) +# +# if discrepancies: +# process.discrepancies_identified = True +# process.save() +# +# # Alert audit supervisor +# self.alert_audit_supervisor(process.location_id, discrepancies) +# +# def finalize_audit(self, activation): +# """Finalize the audit process""" +# process = activation.process +# +# # Mark audit as completed +# process.audit_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_audit_completion(process.audit_type, process.location_id) +# +# # Update audit metrics +# self.update_audit_metrics(process.audit_type, process.location_id) +# +# def end_audit(self, activation): +# """End the audit workflow""" +# process = activation.process +# +# # Generate audit summary +# self.generate_audit_summary(process.audit_type, process.location_id) +# +# # Helper methods +# def notify_audit_scheduled(self, audit_type, location_id): +# """Notify audit team of scheduled audit""" +# audit_staff = User.objects.filter( +# groups__name='Audit Staff' +# ) +# +# for staff in audit_staff: +# send_mail( +# subject=f'Audit Scheduled: {location_id}', +# message=f'{audit_type} audit scheduled for location {location_id}.', +# from_email='audit@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def check_discrepancies(self, location_id): +# """Check for inventory discrepancies""" +# # This would implement discrepancy checking logic +# return [] +# +# def alert_audit_supervisor(self, location_id, discrepancies): +# """Alert audit supervisor of discrepancies""" +# supervisors = User.objects.filter( +# groups__name='Audit Supervisors' +# ) +# +# for supervisor in supervisors: +# send_mail( +# subject=f'Audit Discrepancies Found: {location_id}', +# message=f'Inventory discrepancies identified during audit.', +# from_email='audit@hospital.com', +# recipient_list=[supervisor.email], +# fail_silently=True +# ) +# +# def notify_audit_completion(self, audit_type, location_id): +# """Notify audit completion""" +# # This would notify relevant parties +# pass +# +# def update_audit_metrics(self, audit_type, location_id): +# """Update audit metrics""" +# # This would update audit performance metrics +# pass +# +# def generate_audit_summary(self, audit_type, location_id): +# """Generate audit summary""" +# # This would generate audit summary +# pass +# +# +# class SupplierManagementProcess(Process): +# """ +# Viewflow process model for supplier management +# """ +# supplier = ModelField(Supplier, help_text='Associated supplier') +# +# # Process status tracking +# supplier_onboarded = models.BooleanField(default=False) +# qualifications_verified = models.BooleanField(default=False) +# contracts_negotiated = models.BooleanField(default=False) +# performance_monitored = models.BooleanField(default=False) +# relationship_maintained = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Supplier Management Process' +# verbose_name_plural = 'Supplier Management Processes' +# +# +# class SupplierManagementFlow(Flow): +# """ +# Supplier Management Workflow +# +# This flow manages supplier onboarding, qualification, +# performance monitoring, and relationship management. +# """ +# +# process_class = SupplierManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_supplier_management) +# .Next(this.onboard_supplier) +# ) +# +# onboard_supplier = ( +# flow_view(SupplierOnboardingView) +# .Permission('inventory.can_onboard_suppliers') +# .Next(this.verify_qualifications) +# ) +# +# verify_qualifications = ( +# flow_view(QualificationVerificationView) +# .Permission('inventory.can_verify_qualifications') +# .Next(this.negotiate_contracts) +# ) +# +# negotiate_contracts = ( +# flow_view(ContractNegotiationView) +# .Permission('inventory.can_negotiate_contracts') +# .Next(this.monitor_performance) +# ) +# +# monitor_performance = ( +# flow_view(PerformanceMonitoringView) +# .Permission('inventory.can_monitor_performance') +# .Next(this.maintain_relationship) +# ) +# +# maintain_relationship = ( +# flow_func(this.complete_supplier_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_supplier_management) +# +# # Flow functions +# def start_supplier_management(self, activation): +# """Initialize the supplier management process""" +# process = activation.process +# supplier = process.supplier +# +# # Send notification to procurement team +# self.notify_supplier_onboarding(supplier) +# +# def complete_supplier_management(self, activation): +# """Finalize the supplier management process""" +# process = activation.process +# supplier = process.supplier +# +# # Mark process as completed +# process.relationship_maintained = True +# process.save() +# +# # Send completion notifications +# self.notify_supplier_management_completion(supplier) +# +# def end_supplier_management(self, activation): +# """End the supplier management workflow""" +# process = activation.process +# +# # Generate supplier management summary +# self.generate_supplier_summary(process.supplier) +# +# # Helper methods +# def notify_supplier_onboarding(self, supplier): +# """Notify procurement team of supplier onboarding""" +# procurement_staff = User.objects.filter( +# groups__name='Procurement Staff' +# ) +# +# for staff in procurement_staff: +# send_mail( +# subject=f'Supplier Onboarding: {supplier.name}', +# message=f'New supplier {supplier.name} requires onboarding.', +# from_email='procurement@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_supplier_management_completion(self, supplier): +# """Notify supplier management completion""" +# # This would notify relevant parties +# pass +# +# def generate_supplier_summary(self, supplier): +# """Generate supplier management summary""" +# # This would generate supplier summary +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_reorder_items(): +# """Background task to automatically reorder items""" +# try: +# # This would check reorder points and create orders +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_expiring_items(): +# """Background task to monitor expiring inventory items""" +# try: +# # This would identify items nearing expiration +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_inventory_reports(): +# """Background task to generate inventory reports""" +# try: +# # This would generate daily inventory reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def update_supplier_performance(): +# """Background task to update supplier performance metrics""" +# try: +# # This would calculate supplier performance metrics +# return True +# except Exception: +# return False +# +# +# @celery.job +# def schedule_cycle_counts(): +# """Background task to schedule cycle counts""" +# try: +# # This would schedule regular cycle counts +# return True +# except Exception: +# return False +# diff --git a/laboratory/__pycache__/flows.cpython-312.pyc b/laboratory/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..55c792fd Binary files /dev/null and b/laboratory/__pycache__/flows.cpython-312.pyc differ diff --git a/laboratory/flows.py b/laboratory/flows.py new file mode 100644 index 00000000..855bc531 --- /dev/null +++ b/laboratory/flows.py @@ -0,0 +1,523 @@ +# """ +# Viewflow workflows for laboratory app. +# Provides lab test ordering, specimen processing, and result reporting workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import LabOrder, Specimen, LabResult, LabTest +# from .views import ( +# LabOrderCreationView, SpecimenCollectionView, SpecimenReceiptView, +# TestProcessingView, ResultEntryView, ResultVerificationView, +# ResultReportingView +# ) +# +# +# class LabOrderProcess(Process): +# """ +# Viewflow process model for laboratory test orders +# """ +# lab_order = ModelField(LabOrder, help_text='Associated lab order') +# +# # Process status tracking +# order_created = models.BooleanField(default=False) +# specimen_collected = models.BooleanField(default=False) +# specimen_received = models.BooleanField(default=False) +# tests_processed = models.BooleanField(default=False) +# results_verified = models.BooleanField(default=False) +# results_reported = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Lab Order Process' +# verbose_name_plural = 'Lab Order Processes' +# +# +# class LabOrderFlow(Flow): +# """ +# Laboratory Test Order Workflow +# +# This flow manages the complete laboratory testing process from +# order creation through result reporting. +# """ +# +# process_class = LabOrderProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_lab_order) +# .Next(this.create_order) +# ) +# +# create_order = ( +# flow_view(LabOrderCreationView) +# .Permission('laboratory.can_create_orders') +# .Next(this.schedule_collection) +# ) +# +# schedule_collection = ( +# flow_func(this.schedule_specimen_collection) +# .Next(this.collect_specimen) +# ) +# +# collect_specimen = ( +# flow_view(SpecimenCollectionView) +# .Permission('laboratory.can_collect_specimens') +# .Next(this.transport_specimen) +# ) +# +# transport_specimen = ( +# flow_func(this.handle_specimen_transport) +# .Next(this.receive_specimen) +# ) +# +# receive_specimen = ( +# flow_view(SpecimenReceiptView) +# .Permission('laboratory.can_receive_specimens') +# .Next(this.check_specimen_quality) +# ) +# +# check_specimen_quality = ( +# flow_func(this.validate_specimen_quality) +# .Next(this.process_tests) +# ) +# +# process_tests = ( +# flow_view(TestProcessingView) +# .Permission('laboratory.can_process_tests') +# .Next(this.enter_results) +# ) +# +# enter_results = ( +# flow_view(ResultEntryView) +# .Permission('laboratory.can_enter_results') +# .Next(this.verify_results) +# ) +# +# verify_results = ( +# flow_view(ResultVerificationView) +# .Permission('laboratory.can_verify_results') +# .Next(this.check_critical_values) +# ) +# +# check_critical_values = ( +# flow_func(this.check_for_critical_values) +# .Next(this.report_results) +# ) +# +# report_results = ( +# flow_view(ResultReportingView) +# .Permission('laboratory.can_report_results') +# .Next(this.finalize_order) +# ) +# +# finalize_order = ( +# flow_func(this.complete_lab_order) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_lab_order) +# +# # Flow functions +# def start_lab_order(self, activation): +# """Initialize the lab order process""" +# process = activation.process +# lab_order = process.lab_order +# +# # Update order status +# lab_order.status = 'PENDING' +# lab_order.save() +# +# # Send notification to lab staff +# self.notify_lab_staff(lab_order) +# +# def schedule_specimen_collection(self, activation): +# """Schedule specimen collection based on order priority""" +# process = activation.process +# lab_order = process.lab_order +# +# # Calculate collection time based on priority +# if lab_order.priority == 'STAT': +# collection_time = timezone.now() + timezone.timedelta(minutes=15) +# elif lab_order.priority == 'URGENT': +# collection_time = timezone.now() + timezone.timedelta(hours=1) +# else: +# collection_time = timezone.now() + timezone.timedelta(hours=4) +# +# # Update order with scheduled collection time +# lab_order.collection_datetime = collection_time +# lab_order.save() +# +# # Notify collection staff +# self.notify_collection_staff(lab_order) +# +# def handle_specimen_transport(self, activation): +# """Handle specimen transport to laboratory""" +# process = activation.process +# lab_order = process.lab_order +# +# # Update specimen status to in transit +# for specimen in lab_order.specimens.all(): +# specimen.status = 'IN_TRANSIT' +# specimen.save() +# +# # Schedule transport based on priority +# if lab_order.priority in ['STAT', 'URGENT']: +# # Immediate transport +# self.notify_transport_team(lab_order, urgent=True) +# else: +# # Regular transport schedule +# self.schedule_regular_transport(lab_order) +# +# def validate_specimen_quality(self, activation): +# """Validate specimen quality and reject if necessary""" +# process = activation.process +# lab_order = process.lab_order +# +# rejected_specimens = [] +# +# for specimen in lab_order.specimens.all(): +# if specimen.quality == 'REJECTED': +# rejected_specimens.append(specimen) +# +# # Notify ordering physician of rejection +# self.notify_specimen_rejection(specimen) +# +# # Request new specimen collection +# self.request_recollection(specimen) +# +# if rejected_specimens: +# # Update order status if specimens rejected +# lab_order.status = 'SPECIMEN_REJECTED' +# lab_order.save() +# else: +# # Proceed with processing +# lab_order.status = 'PROCESSING' +# lab_order.save() +# +# process.specimen_received = True +# process.save() +# +# def check_for_critical_values(self, activation): +# """Check for critical values and alert if found""" +# process = activation.process +# lab_order = process.lab_order +# +# critical_results = [] +# +# for result in lab_order.results.all(): +# if self.is_critical_value(result): +# critical_results.append(result) +# +# if critical_results: +# # Immediate notification for critical values +# self.notify_critical_values(lab_order, critical_results) +# +# # Mark as critical in order +# lab_order.has_critical_values = True +# lab_order.save() +# +# def complete_lab_order(self, activation): +# """Finalize the lab order process""" +# process = activation.process +# lab_order = process.lab_order +# +# # Update order status +# lab_order.status = 'COMPLETED' +# lab_order.completed_datetime = timezone.now() +# lab_order.save() +# +# # Mark process as completed +# process.results_reported = True +# process.save() +# +# # Send completion notifications +# self.notify_order_completion(lab_order) +# +# def end_lab_order(self, activation): +# """End the lab order workflow""" +# process = activation.process +# +# # Generate order summary report +# self.generate_order_summary(process.lab_order) +# +# # Helper methods +# def notify_lab_staff(self, lab_order): +# """Notify laboratory staff of new order""" +# from django.contrib.auth.models import Group +# +# lab_staff = User.objects.filter( +# groups__name='Laboratory Staff' +# ) +# +# for staff in lab_staff: +# send_mail( +# subject=f'New Lab Order: {lab_order.order_number}', +# message=f'New {lab_order.get_priority_display()} lab order for {lab_order.patient.get_full_name()}.', +# from_email='laboratory@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_collection_staff(self, lab_order): +# """Notify specimen collection staff""" +# collection_staff = User.objects.filter( +# groups__name='Specimen Collection' +# ) +# +# for staff in collection_staff: +# send_mail( +# subject=f'Specimen Collection Required: {lab_order.order_number}', +# message=f'Specimen collection scheduled for {lab_order.collection_datetime}.', +# from_email='laboratory@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_transport_team(self, lab_order, urgent=False): +# """Notify transport team for specimen pickup""" +# transport_staff = User.objects.filter( +# groups__name='Transport Team' +# ) +# +# priority_text = "URGENT" if urgent else "ROUTINE" +# +# for staff in transport_staff: +# send_mail( +# subject=f'{priority_text} Transport: {lab_order.order_number}', +# message=f'Specimen transport required for lab order {lab_order.order_number}.', +# from_email='transport@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def schedule_regular_transport(self, lab_order): +# """Schedule regular transport pickup""" +# # This would integrate with transport scheduling system +# pass +# +# def notify_specimen_rejection(self, specimen): +# """Notify ordering physician of specimen rejection""" +# if specimen.order.ordering_physician and specimen.order.ordering_physician.email: +# send_mail( +# subject=f'Specimen Rejected: {specimen.specimen_number}', +# message=f'Specimen rejected due to: {specimen.rejection_reason}. Please reorder.', +# from_email='laboratory@hospital.com', +# recipient_list=[specimen.order.ordering_physician.email], +# fail_silently=True +# ) +# +# def request_recollection(self, specimen): +# """Request new specimen collection""" +# # This would trigger a new collection workflow +# pass +# +# def is_critical_value(self, result): +# """Check if result value is critical""" +# # This would implement critical value checking logic +# # based on test-specific critical ranges +# return False # Placeholder +# +# def notify_critical_values(self, lab_order, critical_results): +# """Notify physicians of critical values immediately""" +# if lab_order.ordering_physician and lab_order.ordering_physician.email: +# result_details = "\n".join([ +# f"{result.test.test_name}: {result.result_value} {result.result_unit}" +# for result in critical_results +# ]) +# +# send_mail( +# subject=f'CRITICAL VALUES: {lab_order.order_number}', +# message=f'Critical values detected:\n{result_details}', +# from_email='laboratory@hospital.com', +# recipient_list=[lab_order.ordering_physician.email], +# fail_silently=True +# ) +# +# def notify_order_completion(self, lab_order): +# """Notify ordering physician of completed results""" +# if lab_order.ordering_physician and lab_order.ordering_physician.email: +# send_mail( +# subject=f'Lab Results Available: {lab_order.order_number}', +# message=f'Laboratory results are now available for {lab_order.patient.get_full_name()}.', +# from_email='laboratory@hospital.com', +# recipient_list=[lab_order.ordering_physician.email], +# fail_silently=True +# ) +# +# def generate_order_summary(self, lab_order): +# """Generate lab order summary report""" +# # This would generate a comprehensive lab order report +# pass +# +# +# class QualityControlProcess(Process): +# """ +# Viewflow process model for quality control procedures +# """ +# qc_batch = CharField(max_length=50, help_text='QC batch identifier') +# +# # Process status tracking +# qc_samples_prepared = models.BooleanField(default=False) +# qc_tests_run = models.BooleanField(default=False) +# qc_results_reviewed = models.BooleanField(default=False) +# qc_approved = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Quality Control Process' +# verbose_name_plural = 'Quality Control Processes' +# +# +# class QualityControlFlow(Flow): +# """ +# Laboratory Quality Control Workflow +# +# This flow manages quality control procedures for laboratory testing. +# """ +# +# process_class = QualityControlProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_qc_process) +# .Next(this.prepare_qc_samples) +# ) +# +# prepare_qc_samples = ( +# flow_view(QCSamplePreparationView) +# .Permission('laboratory.can_prepare_qc_samples') +# .Next(this.run_qc_tests) +# ) +# +# run_qc_tests = ( +# flow_view(QCTestExecutionView) +# .Permission('laboratory.can_run_qc_tests') +# .Next(this.review_qc_results) +# ) +# +# review_qc_results = ( +# flow_view(QCResultReviewView) +# .Permission('laboratory.can_review_qc_results') +# .Next(this.approve_qc) +# ) +# +# approve_qc = ( +# flow_view(QCApprovalView) +# .Permission('laboratory.can_approve_qc') +# .Next(this.finalize_qc) +# ) +# +# finalize_qc = ( +# flow_func(this.complete_qc_process) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_qc_process) +# +# # Flow functions +# def start_qc_process(self, activation): +# """Initialize the QC process""" +# process = activation.process +# +# # Notify QC staff +# self.notify_qc_staff(process.qc_batch) +# +# def complete_qc_process(self, activation): +# """Finalize the QC process""" +# process = activation.process +# +# # Mark QC as approved +# process.qc_approved = True +# process.save() +# +# # Release patient results if QC passed +# self.release_patient_results(process.qc_batch) +# +# def end_qc_process(self, activation): +# """End the QC workflow""" +# process = activation.process +# +# # Generate QC summary report +# self.generate_qc_summary(process.qc_batch) +# +# # Helper methods +# def notify_qc_staff(self, qc_batch): +# """Notify QC staff of new QC batch""" +# qc_staff = User.objects.filter( +# groups__name='Quality Control' +# ) +# +# for staff in qc_staff: +# send_mail( +# subject=f'QC Batch Ready: {qc_batch}', +# message=f'Quality control batch {qc_batch} is ready for processing.', +# from_email='laboratory@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def release_patient_results(self, qc_batch): +# """Release patient results after QC approval""" +# # This would release held patient results +# pass +# +# def generate_qc_summary(self, qc_batch): +# """Generate QC summary report""" +# # This would generate a comprehensive QC report +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_schedule_collection(order_id): +# """Background task to automatically schedule specimen collection""" +# try: +# lab_order = LabOrder.objects.get(id=order_id) +# +# # Auto-assign collection staff based on location and availability +# collection_staff = User.objects.filter( +# groups__name='Specimen Collection', +# is_active=True +# ).first() +# +# if collection_staff: +# # Create collection task +# # This would integrate with task management system +# return True +# +# return False +# except LabOrder.DoesNotExist: +# return False +# +# +# @celery.job +# def process_batch_results(batch_id): +# """Background task to process batch of test results""" +# try: +# # This would process a batch of results +# # and perform automated quality checks +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_daily_qc_report(): +# """Background task to generate daily QC report""" +# try: +# # This would generate daily QC summary +# return True +# except Exception: +# return False +# diff --git a/logs/hospital_management.log b/logs/hospital_management.log index a86f851d..30ff10a4 100644 --- a/logs/hospital_management.log +++ b/logs/hospital_management.log @@ -182694,3 +182694,6911 @@ INFO 2025-09-06 19:06:33,154 basehttp 33886 6203437056 "GET /en/blood-bank/donor WARNING 2025-09-06 19:06:33,179 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json WARNING 2025-09-06 19:06:33,181 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 INFO 2025-09-06 19:06:33,226 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:07:33,242 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:08:33,254 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:09:33,261 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:09:59,880 log 33886 6220263424 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-06 19:09:59,887 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:09:59,888 basehttp 33886 6220263424 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:09:59,899 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:09:59,899 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:10:01,883 basehttp 33886 6203437056 "GET /en/blood-bank/donors/34/eligibility/ HTTP/1.1" 200 34004 +WARNING 2025-09-06 19:10:01,906 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:10:01,907 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:10:01,947 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:10:12,338 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:10:12,338 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:10:12,351 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:10:12,353 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:10:18,495 basehttp 33886 6203437056 "GET /en/blood-bank/donors/create/ HTTP/1.1" 200 33924 +WARNING 2025-09-06 19:10:18,514 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:10:18,514 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:10:18,564 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:11:18,590 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:11:31,467 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:11:31,480 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:11:31,480 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:11:31,503 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:11:31,503 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:11:41,047 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:11:41,048 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:11:45,501 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95494 +WARNING 2025-09-06 19:11:45,523 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:11:45,523 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:11:45,576 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:11:56,062 basehttp 33886 6203437056 "GET /en/blood-bank/requests/21/ HTTP/1.1" 200 32303 +WARNING 2025-09-06 19:11:56,083 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:11:56,083 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:11:56,125 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:11:59,419 basehttp 33886 6203437056 "GET /en/blood-bank/requests/21/issue/ HTTP/1.1" 200 44297 +WARNING 2025-09-06 19:11:59,445 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:11:59,446 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:11:59,488 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:12:59,502 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:13:11,618 log 33886 6220263424 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-06 19:13:11,618 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:13:11,619 basehttp 33886 6220263424 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:13:11,629 log 33886 6220263424 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:13:11,629 basehttp 33886 6220263424 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:13:26,553 basehttp 33886 6220263424 "GET /blood-bank/api/blood-availability/?blood_group=2&component=1 HTTP/1.1" 302 0 +INFO 2025-09-06 19:13:26,565 basehttp 33886 6203437056 "GET /en/blood-bank/api/blood-availability/?blood_group=2&component=1 HTTP/1.1" 200 22 +INFO 2025-09-06 19:13:36,486 basehttp 33886 6203437056 "GET /en/blood-bank/requests/21/issue/ HTTP/1.1" 200 44297 +WARNING 2025-09-06 19:13:36,502 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:13:36,502 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:13:36,548 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:13:38,899 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:13:38,899 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:13:38,909 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:13:38,909 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:14:11,624 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:15:11,630 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:15:38,062 basehttp 33886 6203437056 "GET /blood-bank/api/blood-availability/?blood_group=2&component=1 HTTP/1.1" 302 0 +INFO 2025-09-06 19:15:38,074 basehttp 33886 6203437056 "GET /en/blood-bank/api/blood-availability/?blood_group=2&component=1 HTTP/1.1" 200 22 +INFO 2025-09-06 19:15:41,784 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:15:41,786 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:15:41,786 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:15:41,807 basehttp 33886 6220263424 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95494 +WARNING 2025-09-06 19:15:41,820 log 33886 6220263424 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:15:41,820 basehttp 33886 6220263424 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:15:41,825 log 33886 6220263424 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:15:41,825 basehttp 33886 6220263424 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:15:41,853 basehttp 33886 6220263424 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:16:41,864 basehttp 33886 6220263424 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:16:41,956 basehttp 33886 6220263424 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95494 +WARNING 2025-09-06 19:16:41,971 log 33886 6220263424 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:16:41,971 basehttp 33886 6220263424 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:16:42,040 basehttp 33886 6220263424 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:16:57,789 basehttp 33886 6220263424 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95494 +INFO 2025-09-06 19:16:57,799 basehttp 33886 6203437056 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-06 19:16:57,801 basehttp 33886 6270742528 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-06 19:16:57,801 basehttp 33886 6287568896 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +WARNING 2025-09-06 19:16:57,807 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:16:57,807 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:16:57,809 basehttp 33886 6220263424 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-06 19:16:57,810 basehttp 33886 6270742528 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-06 19:16:57,810 basehttp 33886 6203437056 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-06 19:16:57,813 basehttp 33886 6203437056 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-06 19:16:57,815 basehttp 33886 6220263424 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-06 19:16:57,815 basehttp 33886 6203437056 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-06 19:16:57,818 basehttp 33886 6237089792 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-06 19:16:57,818 basehttp 33886 6270742528 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-06 19:16:57,820 basehttp 33886 6287568896 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-06 19:16:57,820 basehttp 33886 6253916160 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-06 19:16:58,663 basehttp 33886 6287568896 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-06 19:16:58,772 basehttp 33886 6287568896 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-06 19:16:58,772 basehttp 33886 6270742528 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-06 19:16:58,773 basehttp 33886 6253916160 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-06 19:16:58,773 basehttp 33886 6203437056 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-06 19:16:58,773 basehttp 33886 6237089792 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-06 19:16:58,774 basehttp 33886 6220263424 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-06 19:16:58,779 basehttp 33886 6237089792 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-06 19:16:58,780 basehttp 33886 6270742528 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-06 19:16:58,781 basehttp 33886 6287568896 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-06 19:16:58,781 basehttp 33886 6220263424 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-06 19:16:58,781 basehttp 33886 6203437056 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-06 19:16:58,783 basehttp 33886 6203437056 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-06 19:16:58,784 basehttp 33886 6270742528 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-06 19:16:58,784 basehttp 33886 6220263424 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-06 19:16:58,785 basehttp 33886 6253916160 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-06 19:16:58,785 basehttp 33886 6287568896 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-06 19:16:58,786 basehttp 33886 6237089792 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-06 19:16:58,788 basehttp 33886 6237089792 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-06 19:16:58,789 basehttp 33886 6270742528 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-06 19:16:58,789 basehttp 33886 6220263424 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-06 19:16:58,789 basehttp 33886 6253916160 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-06 19:16:58,790 basehttp 33886 6287568896 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-06 19:16:58,791 basehttp 33886 6237089792 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-06 19:16:58,793 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:16:59,723 log 33886 6203437056 Not Found: /favicon.ico +WARNING 2025-09-06 19:16:59,724 basehttp 33886 6203437056 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-06 19:17:37,138 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95494 +WARNING 2025-09-06 19:17:37,154 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:17:37,154 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:17:37,243 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:18:37,263 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:18:37,321 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:18:37,335 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:18:37,335 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:18:37,388 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:19:37,405 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:19:37,469 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:19:37,484 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:19:37,484 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:19:37,539 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:20:33,296 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:20:33,311 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:20:33,311 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:20:33,370 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:21:33,375 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:21:33,443 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:21:33,455 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:21:33,455 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:21:33,507 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:21:39,147 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:21:39,161 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:21:39,162 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:21:39,213 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:22:39,221 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:22:39,288 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:22:39,308 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:22:39,308 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:22:39,362 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:23:39,371 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:23:39,446 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:23:39,464 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:23:39,464 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:23:39,517 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:24:39,535 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:24:39,590 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:24:39,608 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:24:39,608 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:24:39,669 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:25:16,406 basehttp 33886 6203437056 "GET /en/blood-bank/requests/31/issue/ HTTP/1.1" 200 44569 +INFO 2025-09-06 19:25:16,420 basehttp 33886 6220263424 "GET /static/plugins/select2/dist/css/select2.min.css HTTP/1.1" 200 14966 +INFO 2025-09-06 19:25:16,422 basehttp 33886 6220263424 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +WARNING 2025-09-06 19:25:16,424 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:25:16,424 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:25:16,476 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:25:29,649 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:25:29,650 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:25:29,676 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:25:29,676 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:25:39,675 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:25:39,747 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:25:39,767 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:25:39,767 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:25:39,816 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:26:39,831 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:26:39,887 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:26:39,901 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:26:39,901 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:26:39,973 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:27:04,018 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:27:04,039 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:27:04,039 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:27:04,088 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:27:20,045 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:27:20,067 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:27:20,067 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:27:20,120 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:27:45,754 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:27:45,772 log 33886 6203437056 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:27:45,772 basehttp 33886 6203437056 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:27:45,827 basehttp 33886 6203437056 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:27:53,028 basehttp 33886 6203437056 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +INFO 2025-09-06 19:27:53,037 basehttp 33886 6203437056 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-06 19:27:53,042 basehttp 33886 6237089792 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-06 19:27:53,043 basehttp 33886 6270742528 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-06 19:27:53,044 basehttp 33886 6287568896 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +INFO 2025-09-06 19:27:53,044 basehttp 33886 6203437056 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-06 19:27:53,045 basehttp 33886 6237089792 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-06 19:27:53,047 basehttp 33886 6237089792 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +WARNING 2025-09-06 19:27:53,052 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:27:53,053 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:27:53,054 basehttp 33886 6203437056 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-06 19:27:53,055 basehttp 33886 6237089792 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-06 19:27:53,056 basehttp 33886 6287568896 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-06 19:27:53,057 basehttp 33886 6253916160 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-06 19:27:53,059 basehttp 33886 6220263424 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-06 19:27:53,059 basehttp 33886 6270742528 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-06 19:27:53,900 basehttp 33886 6270742528 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-06 19:27:53,925 basehttp 33886 6253916160 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-06 19:27:53,926 basehttp 33886 6220263424 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-06 19:27:53,926 basehttp 33886 6237089792 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-06 19:27:53,927 basehttp 33886 6270742528 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-06 19:27:53,928 basehttp 33886 6287568896 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-06 19:27:53,929 basehttp 33886 6237089792 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-06 19:27:53,930 basehttp 33886 6203437056 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-06 19:27:53,930 basehttp 33886 6220263424 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-06 19:27:53,932 basehttp 33886 6237089792 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-06 19:27:53,932 basehttp 33886 6287568896 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-06 19:27:53,932 basehttp 33886 6203437056 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-06 19:27:53,933 basehttp 33886 6270742528 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-06 19:27:53,934 basehttp 33886 6220263424 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-06 19:27:53,936 basehttp 33886 6203437056 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-06 19:27:53,936 basehttp 33886 6287568896 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-06 19:27:53,937 basehttp 33886 6270742528 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-06 19:27:53,937 basehttp 33886 6253916160 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-06 19:27:53,938 basehttp 33886 6237089792 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-06 19:27:53,938 basehttp 33886 6220263424 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-06 19:27:53,945 basehttp 33886 6270742528 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-06 19:27:53,956 basehttp 33886 6287568896 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-06 19:27:53,956 basehttp 33886 6203437056 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-06 19:27:53,957 basehttp 33886 6253916160 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-06 19:27:53,962 basehttp 33886 6220263424 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:27:54,851 log 33886 6220263424 Not Found: /favicon.ico +WARNING 2025-09-06 19:27:54,851 basehttp 33886 6220263424 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-06 19:28:36,420 basehttp 33886 6220263424 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:28:36,438 log 33886 6220263424 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:36,438 basehttp 33886 6220263424 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:36,519 basehttp 33886 6220263424 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:28:41,333 basehttp 33886 6220263424 "GET /en/blood-bank/requests/ HTTP/1.1" 200 95604 +INFO 2025-09-06 19:28:41,340 basehttp 33886 6220263424 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-06 19:28:41,346 basehttp 33886 6270742528 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +INFO 2025-09-06 19:28:41,347 basehttp 33886 6203437056 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-06 19:28:41,347 basehttp 33886 6220263424 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-06 19:28:41,350 basehttp 33886 6237089792 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-06 19:28:41,350 basehttp 33886 6203437056 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-06 19:28:41,355 basehttp 33886 6203437056 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-06 19:28:41,357 basehttp 33886 6220263424 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-06 19:28:41,358 basehttp 33886 6203437056 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +WARNING 2025-09-06 19:28:41,359 log 33886 6287568896 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:41,359 basehttp 33886 6287568896 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:41,360 basehttp 33886 6220263424 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-06 19:28:41,360 basehttp 33886 6237089792 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-06 19:28:41,363 basehttp 33886 6253916160 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-06 19:28:41,363 basehttp 33886 6270742528 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-06 19:28:41,553 basehttp 33886 6270742528 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-06 19:28:41,578 basehttp 33886 6253916160 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-06 19:28:41,579 basehttp 33886 6237089792 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-06 19:28:41,579 basehttp 33886 6270742528 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-06 19:28:41,579 basehttp 33886 6220263424 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-06 19:28:41,579 basehttp 33886 6287568896 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-06 19:28:41,580 basehttp 33886 6203437056 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-06 19:28:41,583 basehttp 33886 6220263424 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-06 19:28:41,584 basehttp 33886 6270742528 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-06 19:28:41,584 basehttp 33886 6237089792 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-06 19:28:41,585 basehttp 33886 6253916160 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-06 19:28:41,586 basehttp 33886 6203437056 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-06 19:28:41,588 basehttp 33886 6270742528 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-06 19:28:41,597 basehttp 33886 6270742528 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-06 19:28:41,598 basehttp 33886 6237089792 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-06 19:28:41,592 basehttp 33886 6253916160 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-06 19:28:41,595 basehttp 33886 6220263424 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-06 19:28:41,604 basehttp 33886 6287568896 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-06 19:28:41,596 basehttp 33886 6203437056 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-06 19:28:41,608 basehttp 33886 6287568896 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-06 19:28:41,608 basehttp 33886 6220263424 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-06 19:28:41,608 basehttp 33886 6270742528 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-06 19:28:41,609 basehttp 33886 6237089792 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-06 19:28:41,609 basehttp 33886 6203437056 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-06 19:28:41,612 basehttp 33886 6253916160 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:28:41,707 log 33886 6253916160 Not Found: /favicon.ico +WARNING 2025-09-06 19:28:41,707 basehttp 33886 6253916160 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-06 19:28:43,985 basehttp 33886 6253916160 "GET /en/blood-bank/requests/39/ HTTP/1.1" 200 32942 +WARNING 2025-09-06 19:28:44,003 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:44,004 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:44,073 basehttp 33886 6253916160 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:28:46,841 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:46,842 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:28:46,858 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:46,859 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:48,647 basehttp 33886 6253916160 "GET /en/blood-bank/requests/39/ HTTP/1.1" 200 32942 +WARNING 2025-09-06 19:28:48,669 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:48,669 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:48,709 basehttp 33886 6253916160 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:28:50,535 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:50,535 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:28:50,547 log 33886 6253916160 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:50,547 basehttp 33886 6253916160 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:52,138 basehttp 33886 6253916160 "GET /en/blood-bank/requests/38/issue/ HTTP/1.1" 200 44569 +INFO 2025-09-06 19:28:52,150 basehttp 33886 6253916160 "GET /static/plugins/select2/dist/css/select2.min.css HTTP/1.1" 200 14966 +INFO 2025-09-06 19:28:52,150 basehttp 33886 6203437056 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +WARNING 2025-09-06 19:28:52,155 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:52,155 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:52,206 basehttp 33886 6237089792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:28:54,000 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:54,000 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:28:54,010 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:54,010 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:56,856 basehttp 33886 6237089792 "GET /en/blood-bank/requests/37/issue/ HTTP/1.1" 200 44297 +WARNING 2025-09-06 19:28:56,876 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:28:56,877 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:28:56,923 basehttp 33886 6237089792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:29:04,827 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:29:04,828 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 19:29:04,841 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:29:04,841 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:29:09,836 basehttp 33886 6237089792 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 70207 +WARNING 2025-09-06 19:29:09,853 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:29:09,853 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:29:09,881 basehttp 33886 6237089792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:29:12,237 basehttp 33886 6237089792 "GET /en/blood-bank/requests/?page=1 HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:29:12,259 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:29:12,259 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:29:12,305 basehttp 33886 6237089792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:30:12,315 basehttp 33886 6237089792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:30:12,389 basehttp 33886 6237089792 "GET /en/blood-bank/requests/?page=1 HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:30:12,402 log 33886 6237089792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:30:12,402 basehttp 33886 6237089792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:30:12,449 basehttp 33886 6237089792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:31:05,224 autoreload 33886 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/views.py changed, reloading. +INFO 2025-09-06 19:31:05,721 autoreload 58836 8747049152 Watching for file changes with StatReloader +INFO 2025-09-06 19:31:12,538 basehttp 58836 6157119488 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:31:12,555 basehttp 58836 6173945856 "GET /en/blood-bank/requests/?page=1 HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:31:12,568 log 58836 6173945856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:31:12,568 basehttp 58836 6173945856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:31:12,623 basehttp 58836 6173945856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:32:12,642 basehttp 58836 6173945856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:32:12,696 basehttp 58836 6173945856 "GET /en/blood-bank/requests/?page=1 HTTP/1.1" 200 95604 +WARNING 2025-09-06 19:32:12,710 log 58836 6173945856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:32:12,710 basehttp 58836 6173945856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:32:12,762 basehttp 58836 6173945856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:32:49,006 autoreload 58836 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/views.py changed, reloading. +INFO 2025-09-06 19:32:49,342 autoreload 59644 8747049152 Watching for file changes with StatReloader +INFO 2025-09-06 19:33:26,538 autoreload 59644 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/views.py changed, reloading. +INFO 2025-09-06 19:33:26,855 autoreload 59959 8747049152 Watching for file changes with StatReloader +INFO 2025-09-06 19:34:36,707 autoreload 59959 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/views.py changed, reloading. +INFO 2025-09-06 19:34:37,017 autoreload 60430 8747049152 Watching for file changes with StatReloader +INFO 2025-09-06 19:37:51,202 autoreload 60430 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/views.py changed, reloading. +INFO 2025-09-06 19:37:51,504 autoreload 61907 8747049152 Watching for file changes with StatReloader +INFO 2025-09-06 19:40:12,981 autoreload 61907 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/urls.py changed, reloading. +INFO 2025-09-06 19:40:13,258 autoreload 62923 8747049152 Watching for file changes with StatReloader +WARNING 2025-09-06 19:40:24,226 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:40:24,226 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:40:24,350 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:40:25,120 basehttp 62923 6159593472 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69125 +WARNING 2025-09-06 19:40:25,140 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:40:25,140 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:40:25,221 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:41:10,879 basehttp 62923 6159593472 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69125 +WARNING 2025-09-06 19:41:10,895 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:41:10,895 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:41:10,947 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:41:41,734 basehttp 62923 6159593472 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69125 +INFO 2025-09-06 19:41:41,749 basehttp 62923 6226898944 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +INFO 2025-09-06 19:41:41,750 basehttp 62923 6193246208 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-06 19:41:41,752 basehttp 62923 6210072576 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-06 19:41:41,753 basehttp 62923 6193246208 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-06 19:41:41,756 basehttp 62923 6243725312 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-06 19:41:41,758 basehttp 62923 6159593472 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +WARNING 2025-09-06 19:41:41,760 log 62923 6226898944 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:41:41,761 basehttp 62923 6226898944 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:41:41,761 basehttp 62923 6159593472 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-06 19:41:41,765 basehttp 62923 6159593472 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-06 19:41:41,766 basehttp 62923 6226898944 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-06 19:41:41,775 basehttp 62923 6193246208 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-06 19:41:41,786 basehttp 62923 6243725312 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-06 19:41:41,787 basehttp 62923 6176419840 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-06 19:41:41,788 basehttp 62923 6210072576 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-06 19:41:42,607 basehttp 62923 6210072576 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-06 19:41:42,627 basehttp 62923 6210072576 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-06 19:41:42,629 basehttp 62923 6193246208 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-06 19:41:42,629 basehttp 62923 6176419840 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-06 19:41:42,629 basehttp 62923 6243725312 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-06 19:41:42,629 basehttp 62923 6226898944 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-06 19:41:42,637 basehttp 62923 6193246208 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-06 19:41:42,653 basehttp 62923 6226898944 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-06 19:41:42,654 basehttp 62923 6243725312 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-06 19:41:42,654 basehttp 62923 6159593472 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-06 19:41:42,655 basehttp 62923 6193246208 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-06 19:41:42,655 basehttp 62923 6176419840 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-06 19:41:42,656 basehttp 62923 6159593472 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-06 19:41:42,658 basehttp 62923 6226898944 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-06 19:41:42,658 basehttp 62923 6176419840 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-06 19:41:42,658 basehttp 62923 6243725312 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-06 19:41:42,658 basehttp 62923 6193246208 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-06 19:41:42,660 basehttp 62923 6159593472 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-06 19:41:42,660 basehttp 62923 6210072576 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-06 19:41:42,662 basehttp 62923 6226898944 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-06 19:41:42,663 basehttp 62923 6176419840 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-06 19:41:42,664 basehttp 62923 6243725312 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-06 19:41:42,665 basehttp 62923 6193246208 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-06 19:41:42,665 basehttp 62923 6159593472 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-06 19:41:42,684 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:41:43,610 log 62923 6159593472 Not Found: /favicon.ico +WARNING 2025-09-06 19:41:43,610 basehttp 62923 6159593472 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-06 19:42:07,122 basehttp 62923 6159593472 "GET /en/blood-bank/requests/15/issue/ HTTP/1.1" 200 44297 +INFO 2025-09-06 19:42:07,134 basehttp 62923 6159593472 "GET /static/plugins/select2/dist/css/select2.min.css HTTP/1.1" 200 14966 +INFO 2025-09-06 19:42:07,134 basehttp 62923 6193246208 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +WARNING 2025-09-06 19:42:07,138 log 62923 6243725312 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:42:07,138 basehttp 62923 6243725312 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:42:07,204 basehttp 62923 6243725312 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:43:02,125 basehttp 62923 6243725312 "GET /en/blood-bank/requests/15/issue/ HTTP/1.1" 200 44298 +WARNING 2025-09-06 19:43:02,152 log 62923 6243725312 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:43:02,152 basehttp 62923 6243725312 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:43:02,191 basehttp 62923 6243725312 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:43:14,691 basehttp 62923 6243725312 "GET /en/blood-bank/requests/15/issue/ HTTP/1.1" 200 44298 +INFO 2025-09-06 19:43:14,701 basehttp 62923 6159593472 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-06 19:43:14,702 basehttp 62923 6210072576 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-06 19:43:14,703 basehttp 62923 6176419840 "GET /static/plugins/select2/dist/css/select2.min.css HTTP/1.1" 200 14966 +INFO 2025-09-06 19:43:14,708 basehttp 62923 6226898944 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-06 19:43:14,710 basehttp 62923 6243725312 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-06 19:43:14,711 basehttp 62923 6176419840 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +WARNING 2025-09-06 19:43:14,715 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:43:14,715 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:43:14,715 basehttp 62923 6226898944 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +INFO 2025-09-06 19:43:14,718 basehttp 62923 6193246208 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-06 19:43:14,719 basehttp 62923 6210072576 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-06 19:43:14,856 basehttp 62923 6210072576 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-06 19:43:14,878 basehttp 62923 6210072576 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-06 19:43:14,879 basehttp 62923 6176419840 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-06 19:43:14,879 basehttp 62923 6193246208 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-06 19:43:14,880 basehttp 62923 6159593472 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-06 19:43:14,880 basehttp 62923 6226898944 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-06 19:43:14,882 basehttp 62923 6226898944 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-06 19:43:14,882 basehttp 62923 6243725312 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-06 19:43:14,882 basehttp 62923 6176419840 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-06 19:43:14,883 basehttp 62923 6159593472 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-06 19:43:14,883 basehttp 62923 6193246208 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-06 19:43:14,886 basehttp 62923 6243725312 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-06 19:43:14,886 basehttp 62923 6176419840 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-06 19:43:14,886 basehttp 62923 6193246208 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-06 19:43:14,887 basehttp 62923 6226898944 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-06 19:43:14,887 basehttp 62923 6210072576 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-06 19:43:14,887 basehttp 62923 6159593472 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-06 19:43:14,888 basehttp 62923 6226898944 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-06 19:43:14,889 basehttp 62923 6159593472 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-06 19:43:14,889 basehttp 62923 6210072576 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-06 19:43:14,890 basehttp 62923 6226898944 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-06 19:43:14,891 basehttp 62923 6176419840 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-06 19:43:14,891 basehttp 62923 6210072576 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-06 19:43:14,892 basehttp 62923 6193246208 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-06 19:43:14,894 basehttp 62923 6243725312 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 19:43:14,998 log 62923 6243725312 Not Found: /favicon.ico +WARNING 2025-09-06 19:43:14,998 basehttp 62923 6243725312 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-06 19:43:26,976 basehttp 62923 6243725312 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69125 +INFO 2025-09-06 19:43:26,992 basehttp 62923 6193246208 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +INFO 2025-09-06 19:43:26,992 basehttp 62923 6226898944 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-06 19:43:26,993 basehttp 62923 6243725312 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-06 19:43:26,993 basehttp 62923 6176419840 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +WARNING 2025-09-06 19:43:26,998 log 62923 6210072576 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:43:26,998 basehttp 62923 6210072576 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:43:26,998 basehttp 62923 6176419840 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-06 19:43:26,998 basehttp 62923 6243725312 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-06 19:44:27,096 basehttp 62923 6176419840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:44:27,147 basehttp 62923 6176419840 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69125 +WARNING 2025-09-06 19:44:27,161 log 62923 6176419840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:44:27,162 basehttp 62923 6176419840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:44:27,214 basehttp 62923 6176419840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:45:27,226 basehttp 62923 6176419840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:45:27,281 basehttp 62923 6176419840 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69125 +WARNING 2025-09-06 19:45:27,296 log 62923 6176419840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:45:27,296 basehttp 62923 6176419840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:45:27,348 basehttp 62923 6176419840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:46:13,992 basehttp 62923 6176419840 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69127 +WARNING 2025-09-06 19:46:14,008 log 62923 6176419840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:46:14,008 basehttp 62923 6176419840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:46:14,061 basehttp 62923 6176419840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:47:04,387 basehttp 62923 6176419840 "GET /en/admin/blood_bank/bloodrequest/ HTTP/1.1" 200 113405 +INFO 2025-09-06 19:47:04,399 basehttp 62923 6226898944 "GET /static/admin/css/nav_sidebar.css HTTP/1.1" 200 2810 +INFO 2025-09-06 19:47:04,399 basehttp 62923 6243725312 "GET /static/admin/css/dark_mode.css HTTP/1.1" 200 2808 +INFO 2025-09-06 19:47:04,399 basehttp 62923 6193246208 "GET /static/admin/css/changelists.css HTTP/1.1" 200 6878 +INFO 2025-09-06 19:47:04,399 basehttp 62923 6176419840 "GET /static/admin/css/base.css HTTP/1.1" 200 22120 +INFO 2025-09-06 19:47:04,399 basehttp 62923 6210072576 "GET /static/admin/js/theme.js HTTP/1.1" 200 1653 +INFO 2025-09-06 19:47:04,401 basehttp 62923 6243725312 "GET /static/admin/css/responsive.css HTTP/1.1" 200 16565 +INFO 2025-09-06 19:47:04,402 basehttp 62923 6210072576 "GET /static/admin/js/jquery.init.js HTTP/1.1" 200 347 +INFO 2025-09-06 19:47:04,402 basehttp 62923 6193246208 "GET /static/admin/js/admin/RelatedObjectLookups.js HTTP/1.1" 200 9777 +INFO 2025-09-06 19:47:04,403 basehttp 62923 6176419840 "GET /static/admin/js/core.js HTTP/1.1" 200 6208 +INFO 2025-09-06 19:47:04,405 basehttp 62923 6243725312 "GET /static/admin/js/actions.js HTTP/1.1" 200 8076 +INFO 2025-09-06 19:47:04,405 basehttp 62923 6193246208 "GET /static/admin/js/prepopulate.js HTTP/1.1" 200 1531 +INFO 2025-09-06 19:47:04,406 basehttp 62923 6210072576 "GET /static/admin/js/urlify.js HTTP/1.1" 200 7887 +INFO 2025-09-06 19:47:04,407 basehttp 62923 6159593472 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-06 19:47:04,407 basehttp 62923 6193246208 "GET /static/admin/img/search.svg HTTP/1.1" 200 458 +INFO 2025-09-06 19:47:04,408 basehttp 62923 6226898944 "GET /static/admin/js/vendor/jquery/jquery.js HTTP/1.1" 200 285314 +INFO 2025-09-06 19:47:04,409 basehttp 62923 6176419840 "GET /static/admin/js/vendor/xregexp/xregexp.js HTTP/1.1" 200 325171 +INFO 2025-09-06 19:47:04,412 basehttp 62923 6226898944 "GET /static/admin/js/nav_sidebar.js HTTP/1.1" 200 3063 +INFO 2025-09-06 19:47:04,414 basehttp 62923 6176419840 "GET /static/admin/js/filters.js HTTP/1.1" 200 978 +INFO 2025-09-06 19:47:04,422 basehttp 62923 6176419840 "GET /static/admin/img/icon-addlink.svg HTTP/1.1" 200 331 +INFO 2025-09-06 19:47:04,422 basehttp 62923 6176419840 "GET /static/admin/img/sorting-icons.svg HTTP/1.1" 200 1097 +INFO 2025-09-06 19:47:04,422 basehttp 62923 6226898944 "GET /static/admin/img/tooltag-add.svg HTTP/1.1" 200 331 +INFO 2025-09-06 19:47:04,423 basehttp 62923 6193246208 "GET /static/admin/img/icon-viewlink.svg HTTP/1.1" 200 581 +INFO 2025-09-06 19:47:06,558 basehttp 62923 6193246208 "GET /en/admin/blood_bank/bloodrequest/40/change/ HTTP/1.1" 200 128128 +INFO 2025-09-06 19:47:06,577 basehttp 62923 6193246208 "GET /static/admin/css/forms.css HTTP/1.1" 200 8525 +INFO 2025-09-06 19:47:06,577 basehttp 62923 6243725312 "GET /static/admin/js/prepopulate_init.js HTTP/1.1" 200 586 +INFO 2025-09-06 19:47:06,578 basehttp 62923 6176419840 "GET /static/admin/js/calendar.js HTTP/1.1" 200 9141 +INFO 2025-09-06 19:47:06,578 basehttp 62923 6210072576 "GET /static/admin/js/inlines.js HTTP/1.1" 200 15628 +INFO 2025-09-06 19:47:06,578 basehttp 62923 6159593472 "GET /static/admin/js/admin/DateTimeShortcuts.js HTTP/1.1" 200 19319 +INFO 2025-09-06 19:47:06,578 basehttp 62923 6210072576 "GET /static/admin/css/widgets.css HTTP/1.1" 200 11991 +INFO 2025-09-06 19:47:06,580 basehttp 62923 6210072576 "GET /static/admin/img/icon-changelink.svg HTTP/1.1" 200 380 +INFO 2025-09-06 19:47:06,581 basehttp 62923 6210072576 "GET /static/admin/img/icon-deletelink.svg HTTP/1.1" 200 392 +INFO 2025-09-06 19:47:06,582 basehttp 62923 6226898944 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-06 19:47:06,583 basehttp 62923 6210072576 "GET /static/admin/js/change_form.js HTTP/1.1" 200 606 +INFO 2025-09-06 19:47:06,609 basehttp 62923 6226898944 "GET /static/admin/img/icon-clock.svg HTTP/1.1" 200 677 +INFO 2025-09-06 19:47:06,609 basehttp 62923 6210072576 "GET /static/admin/img/icon-calendar.svg HTTP/1.1" 200 1086 +INFO 2025-09-06 19:47:11,976 basehttp 62923 6210072576 "POST /en/admin/blood_bank/bloodrequest/40/change/ HTTP/1.1" 302 0 +INFO 2025-09-06 19:47:12,013 basehttp 62923 6210072576 "GET /en/admin/blood_bank/bloodrequest/ HTTP/1.1" 200 113680 +INFO 2025-09-06 19:47:12,028 basehttp 62923 6210072576 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-06 19:47:12,036 basehttp 62923 6210072576 "GET /static/admin/img/icon-yes.svg HTTP/1.1" 200 436 +INFO 2025-09-06 19:47:14,103 basehttp 62923 6210072576 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:47:14,114 basehttp 62923 6226898944 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69127 +WARNING 2025-09-06 19:47:14,125 log 62923 6226898944 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:47:14,125 basehttp 62923 6226898944 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:47:14,175 basehttp 62923 6226898944 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:48:15,133 basehttp 62923 6226898944 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:48:15,144 basehttp 62923 6210072576 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69127 +WARNING 2025-09-06 19:48:15,156 log 62923 6210072576 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:48:15,157 basehttp 62923 6210072576 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:48:15,218 basehttp 62923 6210072576 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:48:37,932 basehttp 62923 6210072576 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69123 +WARNING 2025-09-06 19:48:37,948 log 62923 6210072576 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:48:37,948 basehttp 62923 6210072576 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:48:38,001 basehttp 62923 6210072576 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:49:23,812 basehttp 62923 6210072576 "GET /en/blood-bank/requests/?page=2 HTTP/1.1" 200 69119 +WARNING 2025-09-06 19:49:23,831 log 62923 6210072576 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:49:23,831 basehttp 62923 6210072576 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:49:23,874 basehttp 62923 6210072576 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:49:37,620 basehttp 62923 6210072576 "GET /en/blood-bank/requests/ HTTP/1.1" 200 94515 +WARNING 2025-09-06 19:49:37,637 log 62923 6210072576 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:49:37,637 basehttp 62923 6210072576 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:49:38,885 basehttp 62923 6210072576 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +WARNING 2025-09-06 19:49:38,905 log 62923 6210072576 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:49:38,905 basehttp 62923 6210072576 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:49:45,653 basehttp 62923 6210072576 "GET /en/blood-bank/units/ HTTP/1.1" 200 88820 +WARNING 2025-09-06 19:49:45,673 log 62923 6210072576 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 19:49:45,673 basehttp 62923 6210072576 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 19:49:45,735 basehttp 62923 6210072576 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:50:53,650 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:51:54,644 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:52:55,646 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:54:25,871 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:57:18,309 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 19:58:19,303 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:32:39,307 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 20:43:02,490 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-06 20:43:02,491 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 20:43:02,492 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:02,506 basehttp 62923 6176419840 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +WARNING 2025-09-06 20:43:02,517 log 62923 6176419840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:02,518 basehttp 62923 6176419840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 20:43:02,524 log 62923 6176419840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:02,524 basehttp 62923 6176419840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:02,594 basehttp 62923 6176419840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:43:03,304 basehttp 62923 6176419840 "GET /en/inventory/stock/ HTTP/1.1" 200 134411 +INFO 2025-09-06 20:43:03,318 basehttp 62923 6176419840 "GET /static/plugins/dropzone/src/options.js HTTP/1.1" 200 23721 +WARNING 2025-09-06 20:43:03,321 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:03,321 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:04,834 basehttp 62923 6159593472 "GET / HTTP/1.1" 302 0 +INFO 2025-09-06 20:43:04,854 basehttp 62923 6176419840 "GET /en/ HTTP/1.1" 200 49790 +WARNING 2025-09-06 20:43:04,870 log 62923 6176419840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:04,871 basehttp 62923 6176419840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:04,922 basehttp 62923 6176419840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:43:04,932 basehttp 62923 6210072576 "GET /en/htmx/tenant-info/ HTTP/1.1" 200 1043 +INFO 2025-09-06 20:43:04,935 basehttp 62923 6193246208 "GET /en/htmx/system-health/ HTTP/1.1" 200 1356 +INFO 2025-09-06 20:43:04,948 basehttp 62923 6159593472 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +INFO 2025-09-06 20:43:20,053 basehttp 62923 6159593472 "GET /en/patients/register/ HTTP/1.1" 200 27711 +WARNING 2025-09-06 20:43:20,075 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:20,075 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:20,113 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 20:43:35,146 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-06 20:43:35,146 basehttp 62923 6159593472 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +WARNING 2025-09-06 20:43:35,146 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 20:43:35,177 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:35,182 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:36,812 basehttp 62923 6159593472 "GET /en/appointments/create/ HTTP/1.1" 200 36462 +WARNING 2025-09-06 20:43:36,833 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:36,833 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:36,869 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 20:43:44,391 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:44,391 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 20:43:44,403 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:44,404 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:45,956 basehttp 62923 6159593472 "GET /en/ HTTP/1.1" 200 49790 +WARNING 2025-09-06 20:43:45,970 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:45,970 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:46,043 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:43:46,047 basehttp 62923 6210072576 "GET /en/htmx/system-health/ HTTP/1.1" 200 1356 +INFO 2025-09-06 20:43:46,047 basehttp 62923 6176419840 "GET /en/htmx/tenant-info/ HTTP/1.1" 200 1043 +INFO 2025-09-06 20:43:46,049 basehttp 62923 6193246208 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +INFO 2025-09-06 20:43:51,723 basehttp 62923 6193246208 "GET /en/billing/bills/create/ HTTP/1.1" 200 109266 +WARNING 2025-09-06 20:43:51,746 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:43:51,746 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:43:51,798 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:44:51,815 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:45:51,819 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:46:51,820 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:47:51,813 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:48:12,511 basehttp 62923 6193246208 "GET /en/billing/bills/create/ HTTP/1.1" 200 110464 +WARNING 2025-09-06 20:48:12,528 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:48:12,529 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:48:12,588 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:48:33,842 basehttp 62923 6193246208 "GET /en/billing/bills/create/ HTTP/1.1" 200 110432 +WARNING 2025-09-06 20:48:33,859 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:48:33,859 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:48:33,912 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:49:22,973 basehttp 62923 6193246208 "GET /en/billing/bills/ HTTP/1.1" 200 135104 +WARNING 2025-09-06 20:49:22,996 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:49:22,996 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:49:23,028 basehttp 62923 6193246208 "GET /static/css/saudiriyalsymbol.woff2 HTTP/1.1" 200 720 +INFO 2025-09-06 20:49:23,071 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:49:23,076 basehttp 62923 6159593472 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 20:50:23,072 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:50:23,075 basehttp 62923 6193246208 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 20:51:23,085 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:51:23,088 basehttp 62923 6159593472 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 20:51:33,802 basehttp 62923 6159593472 "GET /en/billing/bills/ HTTP/1.1" 200 101540 +WARNING 2025-09-06 20:51:33,820 log 62923 6159593472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:51:33,820 basehttp 62923 6159593472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:51:33,880 basehttp 62923 6159593472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:51:33,884 basehttp 62923 6193246208 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +ERROR 2025-09-06 20:51:54,500 log 62923 6193246208 Internal Server Error: /en/billing/bills/a668a9c6-ab05-40eb-96f3-5c56e1efc6d9/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 327, in render + return nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'encounter_detail' with arguments '(UUID('23e89bd9-30d2-4da2-accd-8579ce105ca3'),)' not found. 1 pattern(s) tried: ['en/emr/encounters/(?P[0-9]+)/\\Z'] +ERROR 2025-09-06 20:51:54,501 basehttp 62923 6193246208 "GET /en/billing/bills/a668a9c6-ab05-40eb-96f3-5c56e1efc6d9/ HTTP/1.1" 500 201537 +WARNING 2025-09-06 20:51:54,519 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:51:54,519 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:52:38,832 basehttp 62923 6193246208 "GET /en/billing/bills/a668a9c6-ab05-40eb-96f3-5c56e1efc6d9/ HTTP/1.1" 200 40744 +WARNING 2025-09-06 20:52:38,849 log 62923 6193246208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:52:38,849 basehttp 62923 6193246208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:52:38,891 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:53:38,899 basehttp 62923 6193246208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:53:44,589 autoreload 62923 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/emr/urls.py changed, reloading. +INFO 2025-09-06 20:53:45,035 autoreload 75155 8747049152 Watching for file changes with StatReloader +INFO 2025-09-06 20:53:45,500 basehttp 75155 6163345408 "GET /en/billing/bills/a668a9c6-ab05-40eb-96f3-5c56e1efc6d9/ HTTP/1.1" 200 40777 +WARNING 2025-09-06 20:53:45,518 log 75155 6163345408 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:45,519 basehttp 75155 6163345408 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:53:45,565 basehttp 75155 6163345408 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 20:53:48,154 log 75155 6196998144 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:48,155 basehttp 75155 6196998144 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:53:48,160 basehttp 75155 6163345408 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:53:48,164 basehttp 75155 6180171776 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +WARNING 2025-09-06 20:53:48,190 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:48,190 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:53:48,846 basehttp 75155 6180171776 "GET /en/billing/bills/ HTTP/1.1" 200 101540 +WARNING 2025-09-06 20:53:48,861 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:48,861 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:53:48,924 basehttp 75155 6180171776 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:53:48,927 basehttp 75155 6163345408 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 20:53:50,969 basehttp 75155 6163345408 "GET /en/billing/bills/a668a9c6-ab05-40eb-96f3-5c56e1efc6d9/ HTTP/1.1" 200 40777 +WARNING 2025-09-06 20:53:50,995 log 75155 6163345408 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:50,995 basehttp 75155 6163345408 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:53:51,034 basehttp 75155 6163345408 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 20:53:55,492 log 75155 6163345408 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:55,493 basehttp 75155 6163345408 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 20:53:55,504 log 75155 6163345408 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:55,504 basehttp 75155 6163345408 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:53:59,272 basehttp 75155 6163345408 "GET /en/billing/bills/ HTTP/1.1" 200 101540 +WARNING 2025-09-06 20:53:59,288 log 75155 6163345408 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:53:59,288 basehttp 75155 6163345408 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:53:59,349 basehttp 75155 6163345408 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 20:53:59,351 basehttp 75155 6180171776 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 20:54:03,209 basehttp 75155 6180171776 "GET /en/billing/bills/a668a9c6-ab05-40eb-96f3-5c56e1efc6d9/edit/ HTTP/1.1" 200 110457 +WARNING 2025-09-06 20:54:03,231 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:54:03,231 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:54:03,275 basehttp 75155 6180171776 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 20:54:08,801 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:54:08,801 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 20:54:08,833 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:54:08,833 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 20:54:14,430 log 75155 6180171776 Internal Server Error: /en/billing/bills/49ecf1c4-8024-4107-ad14-0d46cf66fe79/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 243, in render + nodelist.append(node.render_annotated(context)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_print' not found. 'claim_print' is not a valid view function or pattern name. +ERROR 2025-09-06 20:54:14,431 basehttp 75155 6180171776 "GET /en/billing/bills/49ecf1c4-8024-4107-ad14-0d46cf66fe79/ HTTP/1.1" 500 194361 +WARNING 2025-09-06 20:54:14,448 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:54:14,448 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:55:26,412 basehttp 75155 6180171776 "GET /en/billing/bills/49ecf1c4-8024-4107-ad14-0d46cf66fe79/ HTTP/1.1" 200 38565 +WARNING 2025-09-06 20:55:26,428 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:55:26,428 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:55:26,471 basehttp 75155 6180171776 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-06 20:55:32,484 log 75155 6180171776 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/detail.py", line 113, in get + context = self.get_context_data(object=self.object) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py", line 396, in get_context_data + context['status_updates'] = claim.claimstatusupdate_set.all().order_by('-update_date') + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +AttributeError: 'InsuranceClaim' object has no attribute 'claimstatusupdate_set' +ERROR 2025-09-06 20:55:32,488 basehttp 75155 6180171776 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 87057 +WARNING 2025-09-06 20:55:32,505 log 75155 6180171776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:55:32,505 basehttp 75155 6180171776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 20:58:35,611 autoreload 75155 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-06 20:58:36,030 autoreload 77344 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-06 20:58:37,142 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_print' not found. 'claim_print' is not a valid view function or pattern name. +ERROR 2025-09-06 20:58:37,144 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 176843 +WARNING 2025-09-06 20:58:37,155 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:58:37,155 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 20:58:38,805 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_print' not found. 'claim_print' is not a valid view function or pattern name. +ERROR 2025-09-06 20:58:38,806 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 176843 +WARNING 2025-09-06 20:58:38,822 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:58:38,822 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 20:59:09,893 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_download' not found. 'claim_download' is not a valid view function or pattern name. +ERROR 2025-09-06 20:59:09,894 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 176762 +WARNING 2025-09-06 20:59:09,908 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:59:09,908 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 20:59:38,455 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_download' not found. 'claim_download' is not a valid view function or pattern name. +ERROR 2025-09-06 20:59:38,456 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 176671 +WARNING 2025-09-06 20:59:38,469 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:59:38,469 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 20:59:50,130 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 327, in render + return nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_status_check' not found. 'claim_status_check' is not a valid view function or pattern name. +ERROR 2025-09-06 20:59:50,131 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 190725 +WARNING 2025-09-06 20:59:50,143 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 20:59:50,143 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 21:00:01,988 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 327, in render + return nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_status_check' not found. 'claim_status_check' is not a valid view function or pattern name. +ERROR 2025-09-06 21:00:01,989 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 191087 +WARNING 2025-09-06 21:00:02,004 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:00:02,004 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 21:00:16,339 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_print' not found. 'claim_print' is not a valid view function or pattern name. +ERROR 2025-09-06 21:00:16,340 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 176728 +WARNING 2025-09-06 21:00:16,353 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:00:16,353 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 21:00:27,731 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_download' not found. 'claim_download' is not a valid view function or pattern name. +ERROR 2025-09-06 21:00:27,732 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 176265 +WARNING 2025-09-06 21:00:27,745 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:00:27,745 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-06 21:00:39,384 log 77344 6157611008 Internal Server Error: /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 327, in render + return nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1075, in render + output = self.filter_expression.resolve(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 749, in resolve + new_obj = func(obj, *arg_vals) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaultfilters.py", line 784, in date + return formats.date_format(value, arg) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/utils/formats.py", line 155, in date_format + return dateformat.format( + ^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/utils/dateformat.py", line 325, in format + return df.format(format_string) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/utils/dateformat.py", line 45, in format + raise TypeError( +TypeError: The format for date objects may not contain time-related format specifiers (found 'g'). +ERROR 2025-09-06 21:00:39,385 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 500 198633 +WARNING 2025-09-06 21:00:39,399 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:00:39,399 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:01:06,361 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 200 37484 +WARNING 2025-09-06 21:01:06,378 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:01:06,378 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:01:06,451 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:01:27,610 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 21:01:27,612 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:01:27,612 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 21:01:27,627 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:01:27,627 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:01:31,347 basehttp 77344 6174437376 "GET /en/billing/payments/create/?bill=49ecf1c4-8024-4107-ad14-0d46cf66fe79 HTTP/1.1" 200 42101 +WARNING 2025-09-06 21:01:31,368 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:01:31,368 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:01:31,438 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:02:31,455 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:03:31,438 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:04:31,453 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:05:20,613 basehttp 77344 6174437376 "GET /en/billing/payments/create/?bill=49ecf1c4-8024-4107-ad14-0d46cf66fe79 HTTP/1.1" 200 42101 +WARNING 2025-09-06 21:05:20,633 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:05:20,633 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:05:20,698 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:05:22,185 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 21:05:22,187 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:05:22,187 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 21:05:22,200 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:05:22,200 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:05:22,728 basehttp 77344 6157611008 "GET /en/billing/bills/49ecf1c4-8024-4107-ad14-0d46cf66fe79/ HTTP/1.1" 200 38565 +WARNING 2025-09-06 21:05:22,744 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:05:22,744 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:05:22,787 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:06:22,791 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:07:22,802 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:07:53,414 basehttp 77344 6157611008 "GET /en/billing/payments/create/?bill=49ecf1c4-8024-4107-ad14-0d46cf66fe79 HTTP/1.1" 200 42101 +WARNING 2025-09-06 21:07:53,429 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:07:53,430 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:07:53,475 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 21:07:59,928 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:07:59,928 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 21:07:59,941 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:07:59,941 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:08:22,808 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:08:23,620 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 200 37650 +WARNING 2025-09-06 21:08:23,640 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:08:23,640 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:08:23,683 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:08:27,797 basehttp 77344 6157611008 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 200 37650 +WARNING 2025-09-06 21:08:27,815 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:08:27,816 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:08:27,853 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-06 21:08:35,506 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:08:35,506 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 21:08:35,518 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:08:35,518 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-06 21:08:35,894 log 77344 6157611008 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-06 21:08:35,894 basehttp 77344 6157611008 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-06 21:09:35,940 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:09:35,945 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:10:35,950 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:10:35,952 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:11:35,955 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:11:35,958 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:12:35,949 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:12:35,952 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:13:35,952 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:13:35,955 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:14:35,958 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:14:35,961 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:15:35,955 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:15:35,958 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:16:35,958 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:16:35,961 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:17:35,967 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:17:35,970 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:18:35,945 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:18:35,948 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:19:36,239 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:19:36,243 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:20:38,239 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:20:38,242 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:23:50,004 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:23:50,007 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:25:50,011 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:25:50,015 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:28:17,699 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:28:17,702 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:30:17,696 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:30:17,699 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:32:41,898 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:32:41,901 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:39:08,829 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:39:08,832 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:41:08,820 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:41:08,823 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:43:08,820 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:43:08,823 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:45:08,818 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:45:08,821 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:47:08,816 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:47:08,818 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:49:08,818 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:49:08,821 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:51:08,825 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:51:08,826 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:53:08,800 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:53:08,803 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:55:08,848 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:55:08,851 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:57:08,855 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:57:08,858 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 21:59:08,851 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 21:59:08,854 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:01:08,861 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:01:08,863 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:03:08,853 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:03:08,856 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:05:08,854 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:05:08,858 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:07:08,851 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:07:08,854 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:09:08,854 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:09:08,856 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:11:08,846 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:11:08,849 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:13:08,851 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:13:08,853 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:15:08,843 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:15:08,846 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:17:08,843 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:17:08,846 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:19:08,841 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:19:08,844 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:21:08,834 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:21:08,837 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:23:08,836 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:23:08,841 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:25:08,841 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:25:08,844 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:27:08,813 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:27:08,815 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:29:08,814 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:29:08,817 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:31:08,811 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:31:08,814 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:33:08,813 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:33:08,815 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:35:08,814 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:35:08,816 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:37:08,809 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:37:08,813 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:39:08,809 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:39:08,812 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:42:34,941 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:42:34,943 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:49:25,788 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:49:25,791 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:51:25,783 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:51:25,786 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:53:25,764 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:53:25,765 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:55:25,774 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:55:25,777 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:57:25,908 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:57:25,911 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 22:58:25,919 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 22:58:25,923 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:00:25,913 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:00:25,915 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:01:25,923 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:01:25,927 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:03:25,907 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:03:25,910 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:05:25,897 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:05:25,899 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:07:25,909 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:07:25,913 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:09:25,909 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:09:25,912 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:11:25,910 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:11:25,914 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:13:25,903 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:13:25,907 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:15:25,904 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:15:25,907 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:17:25,926 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:17:25,929 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:19:25,904 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:19:25,908 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:21:25,922 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:21:25,925 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:23:25,908 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:23:25,911 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:25:25,916 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:25:25,919 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:27:25,908 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:27:25,913 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:29:25,892 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:29:25,895 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:31:25,898 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:31:25,901 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:33:25,895 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:33:25,898 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:35:25,875 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:35:25,878 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:37:25,891 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:37:25,895 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:39:25,895 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:39:25,898 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:41:25,896 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:41:25,899 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:43:25,900 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:43:25,903 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:45:25,898 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:45:25,901 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:47:25,900 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:47:25,903 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:49:25,909 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:49:25,912 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-06 23:54:06,595 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-06 23:54:06,598 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:05:11,486 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:05:11,489 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:07:31,248 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:07:31,251 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:18:38,689 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:18:38,693 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:23:25,721 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:23:25,724 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:35:15,078 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:35:15,082 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:37:15,065 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:37:15,068 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:39:15,064 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:39:15,067 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:41:15,061 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:41:15,064 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:43:15,064 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:43:15,066 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:45:15,057 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:45:15,060 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:47:15,054 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:47:15,057 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:49:15,100 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:49:15,103 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:51:15,085 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:51:15,087 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:53:15,096 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:53:15,098 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:55:15,098 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:55:15,102 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:57:15,098 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:57:15,100 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 00:59:15,096 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 00:59:15,099 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:01:15,094 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:01:15,098 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:03:15,116 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:03:15,120 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:05:15,126 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:05:15,129 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:07:15,124 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:07:15,127 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:09:15,127 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:09:15,129 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:11:15,110 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:11:15,112 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:13:15,117 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:13:15,119 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:15:15,120 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:15:15,122 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:17:15,119 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:17:15,121 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:19:15,107 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:19:15,110 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:21:15,118 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:21:15,121 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:23:15,117 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:23:15,120 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:25:15,125 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:25:15,128 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:27:15,113 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:27:15,116 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:29:15,122 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:29:15,124 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:31:15,115 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:31:15,118 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:33:15,196 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:33:15,199 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:35:15,204 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:35:15,207 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:47:32,334 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:47:32,337 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 01:57:14,127 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 01:57:14,130 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:04:09,538 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:04:09,542 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:06:09,532 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:06:09,535 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:08:09,538 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:08:09,540 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:10:09,524 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:10:09,526 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:12:09,536 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:12:09,539 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:14:09,539 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:14:09,543 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:16:09,546 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:16:09,549 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:18:09,560 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:18:09,563 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:20:09,576 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:20:09,578 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:22:09,565 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:22:09,568 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:23:09,591 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:23:09,594 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:25:09,570 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:25:09,572 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:27:09,581 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:27:09,585 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:29:09,599 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:29:09,602 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:31:09,604 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:31:09,607 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:33:09,580 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:33:09,583 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:35:09,577 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:35:09,580 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:37:09,572 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:37:09,574 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:39:09,562 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:39:09,564 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:41:09,587 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:41:09,590 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:43:09,585 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:43:09,589 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:45:09,593 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:45:09,596 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:47:09,580 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:47:09,583 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:49:09,582 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:49:09,590 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:51:09,589 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:51:09,592 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:53:09,587 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:53:09,590 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:55:09,578 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:55:09,581 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:57:09,596 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:57:09,600 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 02:59:09,587 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 02:59:09,590 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4938 +INFO 2025-09-07 03:01:09,592 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:01:09,596 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:03:09,609 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:03:09,612 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:18:53,235 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:18:53,238 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:20:53,003 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:20:53,007 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:22:52,994 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:22:52,997 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:24:52,996 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:24:52,999 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:26:52,998 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:26:53,001 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:28:52,999 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:28:53,002 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:30:53,015 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:30:53,018 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:32:53,011 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:32:53,015 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:34:52,851 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:34:52,854 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:36:52,849 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:36:52,852 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:38:52,848 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:38:52,851 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:40:52,845 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:40:52,848 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:42:52,858 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:42:52,861 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:44:52,844 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:44:52,847 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:46:52,845 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:46:52,847 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:48:52,841 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:48:52,844 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:50:52,847 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:50:52,850 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:52:52,839 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:52:52,845 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:54:52,845 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:54:52,848 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:56:52,852 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:56:52,855 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 03:58:52,844 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 03:58:52,847 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:00:52,843 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:00:52,845 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:02:52,842 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:02:52,845 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:04:52,855 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:04:52,858 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:06:52,858 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:06:52,861 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:08:52,847 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:08:52,850 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:10:52,846 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:10:52,849 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:12:52,845 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:12:52,849 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:14:52,844 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:14:52,847 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:16:52,851 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:16:52,854 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:18:52,841 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:18:52,843 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:27:01,087 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:27:01,090 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:30:06,007 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:30:06,010 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:45:08,671 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:45:08,674 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:46:08,658 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:47:08,668 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:48:08,647 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:49:08,665 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:50:08,655 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:51:08,672 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:52:08,658 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:53:08,660 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:54:08,641 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:55:08,659 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:56:08,659 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:57:08,646 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 04:58:08,641 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 04:59:08,640 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:00:08,644 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:01:08,639 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:02:08,674 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:03:08,634 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:04:08,637 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:05:08,632 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:06:08,645 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:07:08,641 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:08:08,627 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:09:08,643 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:10:08,646 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:11:08,624 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:12:08,627 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:13:08,645 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:14:08,627 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:15:08,630 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:16:08,632 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:17:08,663 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:18:08,638 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:19:08,628 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:20:08,638 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:21:08,649 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:22:08,631 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:23:08,635 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:24:08,637 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:25:08,624 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:26:08,621 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:27:08,627 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:28:08,661 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:28:08,664 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:30:08,620 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:30:08,622 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:31:08,737 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:32:08,740 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:33:08,735 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:34:08,753 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:35:08,751 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:36:08,739 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:37:08,741 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:38:08,756 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:39:08,748 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:40:08,756 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:41:08,739 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:42:08,746 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:43:08,753 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:44:08,741 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:45:08,754 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:48:49,254 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:51:47,792 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:56:57,168 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:57:57,160 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 05:58:57,173 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 05:59:57,161 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:00:57,166 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:01:57,162 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:02:57,164 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:03:57,148 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:04:57,152 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:05:57,149 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:06:57,148 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:07:57,147 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:08:57,151 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:09:57,151 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:10:57,151 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:11:57,147 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:12:57,150 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:13:57,149 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:14:57,149 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:15:57,139 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:16:57,153 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:17:57,147 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:18:57,160 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:19:57,165 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:20:57,163 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:21:57,158 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:22:57,161 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:23:57,160 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:24:57,170 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:25:57,158 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:26:57,162 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:27:57,160 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:28:57,152 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:29:57,168 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:30:57,148 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:31:57,158 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:32:57,162 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:33:57,170 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:34:57,172 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:35:57,172 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:36:57,172 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:37:57,172 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:38:57,171 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:39:57,179 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:40:57,175 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:41:57,172 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:42:57,175 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:43:57,163 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:44:57,171 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:45:57,172 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:46:57,177 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:47:57,174 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:48:57,302 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:49:57,308 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:50:57,305 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:51:57,303 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:52:57,307 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:53:57,308 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 06:54:57,308 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 06:55:57,308 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:00:31,574 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:04:05,986 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:07:02,629 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:10:49,009 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:11:48,997 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:12:49,000 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:13:49,030 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:13:49,030 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:15:48,889 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:15:48,893 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:17:48,887 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:17:48,889 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:19:48,882 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:19:48,884 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:20:48,897 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:20:48,900 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:22:48,882 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:22:48,884 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:24:48,877 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:24:48,879 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:26:48,890 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:26:48,893 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:28:48,885 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:28:48,889 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:30:48,884 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:30:48,888 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:32:48,916 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:32:48,918 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:34:48,892 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:34:48,894 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:36:48,888 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:36:48,891 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:38:48,891 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:38:48,895 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:40:48,889 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:40:48,892 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:42:48,882 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:42:48,885 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:44:48,900 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:44:48,903 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:46:48,771 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:46:48,774 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:48:48,772 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:48:48,773 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:50:48,784 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:50:48,785 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:52:48,777 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:52:48,780 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:53:48,801 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:53:48,803 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:55:48,784 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:55:48,787 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:57:48,761 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:57:48,764 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 07:59:48,762 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 07:59:48,765 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:01:48,761 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:01:48,764 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:03:48,754 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:03:48,756 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:05:48,760 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:05:48,763 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:07:48,749 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:07:48,751 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:08:48,741 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:08:48,743 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:10:48,745 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:10:48,747 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:14:35,707 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:14:35,710 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:22:57,062 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:22:57,065 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:24:57,051 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:24:57,055 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:26:57,052 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:26:57,055 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:28:57,050 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:28:57,053 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:30:57,047 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:30:57,050 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:36:20,741 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:36:20,744 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:38:20,730 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:38:20,733 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:40:20,727 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:40:20,730 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:42:20,735 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:42:20,738 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:44:20,723 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:44:20,726 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:46:20,729 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:46:20,733 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:48:20,725 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:48:20,729 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:50:20,833 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:50:20,836 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:52:20,836 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:52:20,839 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:54:20,821 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:54:20,823 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:56:20,846 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:56:20,848 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 08:58:20,838 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 08:58:20,843 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:00:20,836 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:00:20,838 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:02:20,836 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:02:20,839 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:04:20,836 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:04:20,838 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:06:20,831 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:06:20,834 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:08:20,841 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:08:20,845 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:10:20,835 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:10:20,838 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:12:20,835 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:12:20,838 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:14:20,871 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:14:20,873 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:16:20,815 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:16:20,817 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:18:20,843 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:18:20,846 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:20:20,933 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:20:20,935 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:22:20,970 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:22:20,972 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:24:20,938 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:24:20,941 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:26:20,941 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:26:20,944 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:28:20,955 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:28:20,959 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:30:20,943 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:30:20,945 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:32:20,947 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:32:20,950 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:34:20,950 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:34:20,952 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:43:12,980 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:43:12,985 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:44:12,941 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:44:12,943 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:45:12,948 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:45:12,951 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:46:12,953 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:46:12,956 basehttp 77344 6174437376 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:47:13,815 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:47:13,817 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:52:52,859 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:52:52,861 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:57:54,394 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:57:54,397 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 09:59:54,393 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 09:59:54,396 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:08:09,558 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:08:09,561 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:10:09,559 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:10:09,562 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:12:09,559 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:12:09,562 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:14:09,566 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:14:09,569 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:16:09,571 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:16:09,573 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:18:09,578 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:18:09,582 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:20:09,568 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:20:09,570 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:22:09,571 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:22:09,574 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:24:09,572 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:24:09,574 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:26:09,567 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:26:09,569 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:28:09,574 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:28:09,577 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:30:09,584 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:30:09,587 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:32:09,578 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:32:09,581 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:34:09,563 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:34:09,574 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:36:09,576 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:36:09,580 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:38:09,576 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:38:09,579 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:40:09,628 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:40:09,631 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:42:09,622 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:42:09,624 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:44:09,630 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:44:09,633 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:46:09,633 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:46:09,636 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:48:09,629 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:48:09,632 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:50:09,638 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:50:09,640 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:52:09,641 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:52:09,644 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:54:09,638 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:54:09,640 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:56:09,641 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:56:09,643 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 10:58:09,649 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 10:58:09,652 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:00:09,659 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:00:09,662 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:02:09,646 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:02:09,650 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:04:09,654 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:04:09,657 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:06:09,661 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:06:09,664 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:08:09,654 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:08:09,657 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:18:47,301 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:18:47,303 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:26:17,718 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:26:17,721 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:33:46,852 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:33:46,854 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:46:00,804 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:46:00,806 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:48:00,816 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:48:00,818 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:50:00,816 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:50:00,818 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:52:00,817 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:52:00,819 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:54:00,814 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:54:00,817 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:56:00,825 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:56:00,827 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 11:58:00,832 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 11:58:00,835 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:00:00,834 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:00:00,837 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:02:00,850 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:02:00,853 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:04:00,853 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:04:00,856 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:06:00,860 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:06:00,863 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:08:00,856 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:08:00,859 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:10:00,855 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:10:00,858 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:29:03,105 basehttp 77344 6157611008 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +INFO 2025-09-07 12:29:03,107 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 12:29:05,278 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:29:05,278 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 12:29:06,347 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:29:06,347 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 12:29:07,590 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:29:07,591 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 12:29:07,602 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:29:07,602 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:30:05,385 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:31:05,382 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:32:05,383 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:33:05,384 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:34:05,402 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:34:22,538 basehttp 77344 6174437376 "GET /en/billing/bills/create/ HTTP/1.1" 200 126347 +WARNING 2025-09-07 12:34:22,558 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:34:22,558 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:34:22,607 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:35:22,623 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 12:35:40,628 log 77344 6208090112 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:35:40,629 basehttp 77344 6208090112 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:35:40,632 basehttp 77344 6157611008 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:35:40,635 basehttp 77344 6191263744 "GET /en/htmx/system-health/ HTTP/1.1" 200 1356 +INFO 2025-09-07 12:35:40,638 basehttp 77344 6174437376 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +WARNING 2025-09-07 12:35:40,641 log 77344 6208090112 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:35:40,641 basehttp 77344 6208090112 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:35:46,410 basehttp 77344 6208090112 "GET /en/billing HTTP/1.1" 301 0 +INFO 2025-09-07 12:35:46,434 basehttp 77344 6174437376 "GET /en/billing/ HTTP/1.1" 200 47086 +WARNING 2025-09-07 12:35:46,448 log 77344 6174437376 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:35:46,449 basehttp 77344 6174437376 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:35:46,477 basehttp 77344 6174437376 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:35:46,480 basehttp 77344 6191263744 "GET /en/billing/htmx/stats/ HTTP/1.1" 200 4943 +ERROR 2025-09-07 12:35:53,457 log 77344 6191263744 Internal Server Error: /en/billing/claims/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'export_claims' not found. 'export_claims' is not a valid view function or pattern name. +ERROR 2025-09-07 12:35:53,458 basehttp 77344 6191263744 "GET /en/billing/claims/ HTTP/1.1" 500 207751 +WARNING 2025-09-07 12:35:53,477 log 77344 6191263744 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:35:53,477 basehttp 77344 6191263744 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:39:36,305 autoreload 77344 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 12:39:36,788 autoreload 97928 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 12:40:53,033 autoreload 97928 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 12:40:53,426 autoreload 98481 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 12:40:54,795 log 98481 6134345728 Internal Server Error: /en/billing/claims/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'export_claims' not found. 'export_claims' is not a valid view function or pattern name. +ERROR 2025-09-07 12:40:54,797 basehttp 98481 6134345728 "GET /en/billing/claims/ HTTP/1.1" 500 207888 +WARNING 2025-09-07 12:40:54,809 log 98481 6134345728 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:40:54,809 basehttp 98481 6134345728 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:44:58,267 autoreload 98481 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 12:44:58,602 autoreload 826 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 12:45:22,581 autoreload 826 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/urls.py changed, reloading. +INFO 2025-09-07 12:45:22,898 autoreload 1126 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 12:45:24,934 log 1126 6129577984 Internal Server Error: /en/billing/claims/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'batch_submit_claims' not found. 'batch_submit_claims' is not a valid view function or pattern name. +ERROR 2025-09-07 12:45:24,936 basehttp 1126 6129577984 "GET /en/billing/claims/ HTTP/1.1" 500 207934 +WARNING 2025-09-07 12:45:24,952 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:45:24,952 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 12:45:46,751 log 1126 6129577984 Internal Server Error: /en/billing/claims/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_stats' not found. 'claim_stats' is not a valid view function or pattern name. +ERROR 2025-09-07 12:45:46,753 basehttp 1126 6129577984 "GET /en/billing/claims/ HTTP/1.1" 500 207076 +WARNING 2025-09-07 12:45:46,769 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:45:46,770 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 12:46:13,557 log 1126 6129577984 Internal Server Error: /en/billing/claims/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 243, in render + nodelist.append(node.render_annotated(context)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_print' not found. 'claim_print' is not a valid view function or pattern name. +ERROR 2025-09-07 12:46:13,558 basehttp 1126 6129577984 "GET /en/billing/claims/ HTTP/1.1" 500 236107 +WARNING 2025-09-07 12:46:13,574 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:46:13,574 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 12:46:55,322 log 1126 6129577984 Internal Server Error: /en/billing/claims/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bulk_submit_claims' not found. 'bulk_submit_claims' is not a valid view function or pattern name. +ERROR 2025-09-07 12:46:55,324 basehttp 1126 6129577984 "GET /en/billing/claims/ HTTP/1.1" 500 211156 +WARNING 2025-09-07 12:46:55,339 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:46:55,339 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:47:18,798 basehttp 1126 6129577984 "GET /en/billing/claims/ HTTP/1.1" 200 144975 +WARNING 2025-09-07 12:47:18,815 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:47:18,815 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:47:18,892 basehttp 1126 6129577984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:48:05,593 basehttp 1126 6129577984 "GET /en/billing/claims/ HTTP/1.1" 200 145155 +WARNING 2025-09-07 12:48:05,607 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:48:05,608 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:48:05,660 basehttp 1126 6129577984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:48:17,864 basehttp 1126 6129577984 "GET /en/billing/claims/172084ad-de1a-44f4-b67d-f89f27dca7dc/ HTTP/1.1" 200 37650 +WARNING 2025-09-07 12:48:17,881 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:48:17,882 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:48:17,924 basehttp 1126 6129577984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 12:48:28,251 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:48:28,251 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 12:48:28,285 log 1126 6129577984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:48:28,286 basehttp 1126 6129577984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:49:05,672 basehttp 1126 6129577984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 12:49:20,467 autoreload 1126 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 12:49:20,872 autoreload 2864 8747049152 Watching for file changes with StatReloader +WARNING 2025-09-07 12:49:21,914 log 2864 6203011072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:49:21,914 basehttp 2864 6203011072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 12:49:21,927 log 2864 6203011072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:49:21,927 basehttp 2864 6203011072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:49:22,778 basehttp 2864 6203011072 "GET /en/billing/claims/ HTTP/1.1" 200 145155 +WARNING 2025-09-07 12:49:22,799 log 2864 6203011072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:49:22,799 basehttp 2864 6203011072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 12:49:22,857 basehttp 2864 6203011072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 12:49:24,049 log 2864 6203011072 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_details_api' not found. 'bill_details_api' is not a valid view function or pattern name. +ERROR 2025-09-07 12:49:24,051 basehttp 2864 6203011072 "GET /en/billing/claims/create/ HTTP/1.1" 500 194122 +WARNING 2025-09-07 12:49:24,068 log 2864 6203011072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 12:49:24,068 basehttp 2864 6203011072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:02:57,501 autoreload 2864 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/urls.py changed, reloading. +INFO 2025-09-07 14:02:58,023 autoreload 5063 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 14:07:44,147 autoreload 5063 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/urls.py changed, reloading. +INFO 2025-09-07 14:07:44,460 autoreload 7139 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 14:07:46,904 log 7139 6202322944 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_details_api' with no arguments not found. 1 pattern(s) tried: ['en/billing/bills/(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z'] +ERROR 2025-09-07 14:07:46,906 basehttp 7139 6202322944 "GET /en/billing/claims/create/ HTTP/1.1" 500 196668 +WARNING 2025-09-07 14:07:46,924 log 7139 6202322944 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:07:46,924 basehttp 7139 6202322944 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 14:09:34,737 log 7139 6202322944 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_details_api' with arguments '('',)' not found. 1 pattern(s) tried: ['en/billing/bills/(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z'] +ERROR 2025-09-07 14:09:34,739 basehttp 7139 6202322944 "GET /en/billing/claims/create/ HTTP/1.1" 500 198113 +WARNING 2025-09-07 14:09:34,753 log 7139 6202322944 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:09:34,753 basehttp 7139 6202322944 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 14:10:56,880 log 7139 6202322944 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_details_api' with arguments '(0,)' not found. 1 pattern(s) tried: ['en/billing/bills/(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z'] +ERROR 2025-09-07 14:10:56,881 basehttp 7139 6202322944 "GET /en/billing/claims/create/ HTTP/1.1" 500 198003 +WARNING 2025-09-07 14:10:56,895 log 7139 6202322944 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:10:56,895 basehttp 7139 6202322944 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:11:45,306 autoreload 7139 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 14:11:45,662 autoreload 8942 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 14:11:47,998 log 8942 6157873152 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_details_api' with arguments '(0,)' not found. 1 pattern(s) tried: ['en/billing/bills/(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z'] +ERROR 2025-09-07 14:11:48,000 basehttp 8942 6157873152 "GET /en/billing/claims/create/ HTTP/1.1" 500 198003 +WARNING 2025-09-07 14:11:48,016 log 8942 6157873152 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:11:48,016 basehttp 8942 6157873152 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 14:13:51,092 log 8942 6157873152 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_details_api' with arguments '(0,)' not found. 1 pattern(s) tried: ['en/billing/bills/(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/\\Z'] +ERROR 2025-09-07 14:13:51,093 basehttp 8942 6157873152 "GET /en/billing/claims/create/ HTTP/1.1" 500 198021 +WARNING 2025-09-07 14:13:51,107 log 8942 6157873152 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:13:51,107 basehttp 8942 6157873152 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:17:09,213 autoreload 8942 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 14:17:09,525 autoreload 11319 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 14:17:35,604 autoreload 11319 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/urls.py changed, reloading. +INFO 2025-09-07 14:17:35,925 autoreload 11481 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 14:18:02,757 log 11481 6171029504 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'insurance_details_api' not found. 'insurance_details_api' is not a valid view function or pattern name. +ERROR 2025-09-07 14:18:02,758 basehttp 11481 6171029504 "GET /en/billing/claims/create/ HTTP/1.1" 500 194751 +WARNING 2025-09-07 14:18:02,776 log 11481 6171029504 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:18:02,776 basehttp 11481 6171029504 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:21:36,134 autoreload 11481 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 14:21:36,450 autoreload 13311 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 14:30:21,471 autoreload 13311 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/patients/views.py changed, reloading. +INFO 2025-09-07 14:30:21,814 autoreload 17159 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 14:30:22,942 log 17159 6201470976 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_line_items_api' not found. 'bill_line_items_api' is not a valid view function or pattern name. +ERROR 2025-09-07 14:30:22,944 basehttp 17159 6201470976 "GET /en/billing/claims/create/ HTTP/1.1" 500 194905 +WARNING 2025-09-07 14:30:22,954 log 17159 6201470976 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:30:22,954 basehttp 17159 6201470976 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:32:17,361 autoreload 17159 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/urls.py changed, reloading. +INFO 2025-09-07 14:32:17,711 autoreload 18042 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 14:33:39,885 autoreload 18042 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/billing/views.py changed, reloading. +INFO 2025-09-07 14:33:40,189 autoreload 18669 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 14:33:48,303 log 18669 6198521856 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'bill_line_items_api' with no arguments not found. 1 pattern(s) tried: ['en/billing/bills/(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/line\\-items\\Z'] +ERROR 2025-09-07 14:33:48,304 basehttp 18669 6198521856 "GET /en/billing/claims/create/ HTTP/1.1" 500 197447 +WARNING 2025-09-07 14:33:48,321 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:33:48,321 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 14:35:02,948 log 18669 6198521856 Internal Server Error: /en/billing/claims/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_preview' not found. 'claim_preview' is not a valid view function or pattern name. +ERROR 2025-09-07 14:35:02,949 basehttp 18669 6198521856 "GET /en/billing/claims/create/ HTTP/1.1" 500 194951 +WARNING 2025-09-07 14:35:02,965 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:35:02,965 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:35:25,061 basehttp 18669 6198521856 "GET /en/billing/claims/create/ HTTP/1.1" 200 66340 +WARNING 2025-09-07 14:35:25,077 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:35:25,077 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:35:25,140 basehttp 18669 6198521856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:36:20,079 basehttp 18669 6198521856 "GET /en/billing/bills/49ecf1c4-8024-4107-ad14-0d46cf66fe79/ HTTP/1.1" 200 38565 +INFO 2025-09-07 14:36:25,152 basehttp 18669 6198521856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:37:08,113 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:37:08,113 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:37:30,410 basehttp 18669 6198521856 "GET /en/billing/claims/ HTTP/1.1" 200 147205 +WARNING 2025-09-07 14:37:30,426 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:37:30,426 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:37:30,474 basehttp 18669 6198521856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:37:39,286 basehttp 18669 6198521856 "GET /en/billing/claims/ HTTP/1.1" 200 147205 +WARNING 2025-09-07 14:37:39,304 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:37:39,305 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:37:39,357 basehttp 18669 6198521856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 14:37:40,782 log 18669 6198521856 Internal Server Error: /en/billing/claims/5237a09c-9179-4f06-a247-65ce91213492/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 327, in render + return nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'claim_appeal' not found. 'claim_appeal' is not a valid view function or pattern name. +ERROR 2025-09-07 14:37:40,784 basehttp 18669 6198521856 "GET /en/billing/claims/5237a09c-9179-4f06-a247-65ce91213492/ HTTP/1.1" 500 191204 +WARNING 2025-09-07 14:37:40,802 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:37:40,802 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:41:07,375 basehttp 18669 6198521856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:41:07,377 log 18669 6215348224 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:41:07,377 basehttp 18669 6215348224 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:41:07,390 log 18669 6215348224 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:41:07,391 basehttp 18669 6215348224 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:41:11,966 basehttp 18669 6215348224 "GET /en/hr HTTP/1.1" 301 0 +INFO 2025-09-07 14:41:12,005 basehttp 18669 6198521856 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 14:41:12,022 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:41:12,022 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:41:12,038 basehttp 18669 6198521856 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 14:41:32,945 log 18669 6198521856 Internal Server Error: /en/hr/departments/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 47, in select_template + raise TemplateDoesNotExist(", ".join(template_name_list), chain=chain) +django.template.exceptions.TemplateDoesNotExist: hr/department_list.html, hr/department_list.html +ERROR 2025-09-07 14:41:32,946 basehttp 18669 6198521856 "GET /en/hr/departments/ HTTP/1.1" 500 86314 +WARNING 2025-09-07 14:41:32,965 log 18669 6198521856 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:41:32,966 basehttp 18669 6198521856 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:44:30,725 autoreload 18669 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 14:44:31,100 autoreload 23535 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 14:48:28,470 basehttp 23535 6201683968 "GET /en/hr/departments/ HTTP/1.1" 200 125426 +INFO 2025-09-07 14:48:28,486 basehttp 23535 6218510336 "GET /static/plugins/datatables.net-buttons-bs5/css/buttons.bootstrap5.min.css HTTP/1.1" 200 8136 +WARNING 2025-09-07 14:48:28,488 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:48:28,488 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:48:28,490 basehttp 23535 6218510336 "GET /static/plugins/datatables.net-buttons-bs5/js/buttons.bootstrap5.min.js HTTP/1.1" 200 1627 +INFO 2025-09-07 14:48:28,492 basehttp 23535 6201683968 "GET /static/plugins/datatables.net-buttons/js/dataTables.buttons.min.js HTTP/1.1" 200 27926 +INFO 2025-09-07 14:48:28,492 basehttp 23535 6252163072 "GET /static/plugins/datatables.net-buttons/js/buttons.print.min.js HTTP/1.1" 200 3073 +INFO 2025-09-07 14:48:28,492 basehttp 23535 6235336704 "GET /static/plugins/datatables.net-buttons/js/buttons.html5.min.js HTTP/1.1" 200 26043 +INFO 2025-09-07 14:48:28,498 basehttp 23535 6268989440 "GET /static/plugins/jszip/dist/jszip.min.js HTTP/1.1" 200 97630 +INFO 2025-09-07 14:48:28,504 basehttp 23535 6218510336 "GET /static/plugins/pdfmake/build/vfs_fonts.js HTTP/1.1" 200 828866 +INFO 2025-09-07 14:48:28,505 basehttp 23535 6285815808 "GET /static/plugins/pdfmake/build/pdfmake.min.js HTTP/1.1" 200 1400771 +INFO 2025-09-07 14:48:28,604 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:48:28,606 basehttp 23535 6285815808 "GET /static/plugins/pdfmake/build/pdfmake.min.js.map HTTP/1.1" 200 4214503 +INFO 2025-09-07 14:48:47,353 basehttp 23535 6285815808 "GET /en/hr/departments/create/ HTTP/1.1" 200 41288 +WARNING 2025-09-07 14:48:47,364 basehttp 23535 6285815808 "GET /static/plugins/select2-bootstrap5-theme/select2-bootstrap5.min.css HTTP/1.1" 404 2104 +WARNING 2025-09-07 14:48:47,373 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:48:47,373 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:48:47,444 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:49:02,684 basehttp 23535 6218510336 "GET /en/hr/departments/ HTTP/1.1" 200 125426 +WARNING 2025-09-07 14:49:02,703 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:49:02,703 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:49:02,798 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:49:04,753 basehttp 23535 6218510336 "GET /en/hr/departments/12/ HTTP/1.1" 200 35129 +WARNING 2025-09-07 14:49:04,775 basehttp 23535 6218510336 "GET /static/plugins/chart.js/dist/Chart.min.css HTTP/1.1" 404 2032 +WARNING 2025-09-07 14:49:04,775 basehttp 23535 6268989440 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 14:49:04,775 basehttp 23535 6235336704 "GET /static/plugins/chart.js/dist/Chart.min.js HTTP/1.1" 404 2029 +WARNING 2025-09-07 14:49:04,781 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:49:04,781 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:49:04,825 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:49:56,931 basehttp 23535 6252163072 "GET /en/hr/departments/12/update/ HTTP/1.1" 200 41458 +WARNING 2025-09-07 14:49:56,950 basehttp 23535 6201683968 "GET /static/plugins/select2-bootstrap5-theme/select2-bootstrap5.min.css HTTP/1.1" 404 2104 +WARNING 2025-09-07 14:49:56,954 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:49:56,954 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:49:57,005 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:50:03,717 basehttp 23535 6201683968 "GET /static/plugins/chart.js/dist/Chart.min.css HTTP/1.1" 404 2032 +WARNING 2025-09-07 14:50:03,721 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:03,721 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:03,732 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:03,732 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:04,847 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:50:10,725 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-07 14:50:10,725 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:50:10,725 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:10,741 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:10,741 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:13,335 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:50:13,338 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:13,340 basehttp 23535 6252163072 "GET /static/plugins/select2-bootstrap5-theme/select2-bootstrap5.min.css HTTP/1.1" 404 2104 +WARNING 2025-09-07 14:50:13,340 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:13,352 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:13,352 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:14,669 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:14,669 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:14,671 basehttp 23535 6201683968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:50:14,684 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:14,684 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:17,041 log 23535 6235336704 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:17,042 basehttp 23535 6235336704 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:17,044 basehttp 23535 6201683968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:50:17,051 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:17,051 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:17,057 basehttp 23535 6218510336 "GET /en/hr/htmx/stats/ HTTP/1.1" 200 4459 +INFO 2025-09-07 14:50:18,074 basehttp 23535 6218510336 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 14:50:18,091 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:18,091 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:18,143 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:50:19,416 basehttp 23535 6218510336 "GET /en/hr/employees/ HTTP/1.1" 200 130495 +WARNING 2025-09-07 14:50:19,439 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:19,439 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:19,483 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:50:32,151 basehttp 23535 6218510336 "GET /en/hr/employees/56/ HTTP/1.1" 200 34482 +WARNING 2025-09-07 14:50:32,175 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:32,175 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:32,215 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:50:39,307 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:39,307 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:39,323 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:39,323 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:40,377 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:40,377 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:40,389 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:40,389 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:41,063 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:41,063 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:41,949 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:41,949 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 14:50:42,797 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:42,797 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:55,783 basehttp 23535 6218510336 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 14:50:55,805 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:55,805 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:55,822 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:50:59,805 basehttp 23535 6218510336 "GET /en/hr/schedules/ HTTP/1.1" 200 121762 +WARNING 2025-09-07 14:50:59,829 basehttp 23535 6201683968 "GET /static/plugins/fullcalendar/main.min.css HTTP/1.1" 404 2026 +WARNING 2025-09-07 14:50:59,831 basehttp 23535 6252163072 "GET /static/plugins/fullcalendar/main.min.js HTTP/1.1" 404 2023 +WARNING 2025-09-07 14:50:59,831 basehttp 23535 6235336704 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 14:50:59,840 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:50:59,840 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:50:59,883 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:51:59,904 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:52:59,891 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:53:19,615 basehttp 23535 6218510336 "GET /en/hr/schedules/ HTTP/1.1" 200 121575 +WARNING 2025-09-07 14:53:19,625 basehttp 23535 6218510336 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 14:53:19,625 basehttp 23535 6201683968 "GET /static/plugins/fullcalendar/main.min.js HTTP/1.1" 404 2023 +WARNING 2025-09-07 14:53:19,631 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:53:19,631 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:53:19,688 basehttp 23535 6201683968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:53:21,928 basehttp 23535 6201683968 "GET /en/hr/schedules/ HTTP/1.1" 200 121575 +WARNING 2025-09-07 14:53:21,939 basehttp 23535 6201683968 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 14:53:21,939 basehttp 23535 6218510336 "GET /static/plugins/fullcalendar/main.min.js HTTP/1.1" 404 2023 +WARNING 2025-09-07 14:53:21,945 log 23535 6235336704 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:53:21,945 basehttp 23535 6235336704 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:53:21,997 basehttp 23535 6235336704 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:53:31,828 basehttp 23535 6235336704 "GET /en/hr/schedules/?page=2 HTTP/1.1" 200 122790 +WARNING 2025-09-07 14:53:31,847 basehttp 23535 6235336704 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 14:53:31,848 basehttp 23535 6201683968 "GET /static/plugins/fullcalendar/main.min.js HTTP/1.1" 404 2023 +WARNING 2025-09-07 14:53:31,854 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:53:31,854 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:53:31,896 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:54:32,350 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:55:33,351 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:56:34,352 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:57:35,360 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:58:07,336 basehttp 23535 6218510336 "GET /en/hr/schedules/?page=2 HTTP/1.1" 200 123284 +INFO 2025-09-07 14:58:07,344 basehttp 23535 6218510336 "GET /static/plugins/moment/min/moment.min.js HTTP/1.1" 200 58890 +INFO 2025-09-07 14:58:07,356 basehttp 23535 6285815808 "GET /static/plugins/%40fullcalendar/bootstrap/index.global.js HTTP/1.1" 200 2075 +INFO 2025-09-07 14:58:07,356 basehttp 23535 6235336704 "GET /static/plugins/%40fullcalendar/timegrid/index.global.js HTTP/1.1" 200 68582 +INFO 2025-09-07 14:58:07,357 basehttp 23535 6268989440 "GET /static/plugins/%40fullcalendar/list/index.global.js HTTP/1.1" 200 18635 +INFO 2025-09-07 14:58:07,357 basehttp 23535 6201683968 "GET /static/plugins/%40fullcalendar/daygrid/index.global.js HTTP/1.1" 200 58461 +INFO 2025-09-07 14:58:07,358 basehttp 23535 6252163072 "GET /static/plugins/%40fullcalendar/interaction/index.global.js HTTP/1.1" 200 99452 +INFO 2025-09-07 14:58:07,362 basehttp 23535 6218510336 "GET /static/plugins/%40fullcalendar/core/index.global.js HTTP/1.1" 200 444856 +WARNING 2025-09-07 14:58:07,366 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 14:58:07,366 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:58:07,428 basehttp 23535 6252163072 "GET /static/plugins/moment/min/moment.min.js.map HTTP/1.1" 200 98730 +INFO 2025-09-07 14:58:07,467 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 14:58:10,732 basehttp 23535 6252163072 "GET /en/hr/schedules/?page=2 HTTP/1.1" 200 123284 +INFO 2025-09-07 14:58:10,740 basehttp 23535 6201683968 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-07 14:58:10,742 basehttp 23535 6235336704 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-07 14:58:10,743 basehttp 23535 6268989440 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +WARNING 2025-09-07 14:58:10,748 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-07 14:58:10,748 basehttp 23535 6285815808 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +WARNING 2025-09-07 14:58:10,749 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 14:58:10,749 basehttp 23535 6235336704 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-07 14:58:10,753 basehttp 23535 6201683968 "GET /static/plugins/moment/min/moment.min.js HTTP/1.1" 200 58890 +INFO 2025-09-07 14:58:10,755 basehttp 23535 6252163072 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-07 14:58:10,756 basehttp 23535 6201683968 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-07 14:58:10,759 basehttp 23535 6285815808 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-07 14:58:10,760 basehttp 23535 6235336704 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-07 14:58:10,760 basehttp 23535 6201683968 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-07 14:58:10,762 basehttp 23535 6252163072 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-07 14:58:10,765 basehttp 23535 6235336704 "GET /static/plugins/%40fullcalendar/timegrid/index.global.js HTTP/1.1" 200 68582 +INFO 2025-09-07 14:58:10,766 basehttp 23535 6201683968 "GET /static/plugins/%40fullcalendar/daygrid/index.global.js HTTP/1.1" 200 58461 +INFO 2025-09-07 14:58:10,768 basehttp 23535 6252163072 "GET /static/plugins/%40fullcalendar/interaction/index.global.js HTTP/1.1" 200 99452 +INFO 2025-09-07 14:58:10,769 basehttp 23535 6235336704 "GET /static/plugins/%40fullcalendar/bootstrap/index.global.js HTTP/1.1" 200 2075 +INFO 2025-09-07 14:58:10,769 basehttp 23535 6201683968 "GET /static/plugins/%40fullcalendar/list/index.global.js HTTP/1.1" 200 18635 +INFO 2025-09-07 14:58:10,770 basehttp 23535 6218510336 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-07 14:58:10,770 basehttp 23535 6285815808 "GET /static/plugins/%40fullcalendar/core/index.global.js HTTP/1.1" 200 444856 +INFO 2025-09-07 14:58:10,770 basehttp 23535 6268989440 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-07 14:58:11,753 basehttp 23535 6285815808 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-07 14:58:11,774 basehttp 23535 6268989440 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-07 14:58:11,774 basehttp 23535 6285815808 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-07 14:58:11,774 basehttp 23535 6252163072 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-07 14:58:11,775 basehttp 23535 6218510336 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-07 14:58:11,776 basehttp 23535 6201683968 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-07 14:58:11,779 basehttp 23535 6285815808 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-07 14:58:11,779 basehttp 23535 6235336704 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-07 14:58:11,780 basehttp 23535 6218510336 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-07 14:58:11,780 basehttp 23535 6252163072 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-07 14:58:11,780 basehttp 23535 6201683968 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-07 14:58:11,782 basehttp 23535 6235336704 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-07 14:58:11,782 basehttp 23535 6285815808 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-07 14:58:11,782 basehttp 23535 6252163072 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-07 14:58:11,783 basehttp 23535 6201683968 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-07 14:58:11,783 basehttp 23535 6218510336 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-07 14:58:11,785 basehttp 23535 6235336704 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-07 14:58:11,785 basehttp 23535 6268989440 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-07 14:58:11,786 basehttp 23535 6252163072 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-07 14:58:11,787 basehttp 23535 6235336704 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-07 14:58:11,787 basehttp 23535 6201683968 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-07 14:58:11,787 basehttp 23535 6218510336 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-07 14:58:11,788 basehttp 23535 6268989440 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-07 14:58:11,788 basehttp 23535 6285815808 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-07 14:58:11,790 basehttp 23535 6285815808 "GET /static/plugins/moment/min/moment.min.js.map HTTP/1.1" 200 98730 +INFO 2025-09-07 14:58:11,812 basehttp 23535 6285815808 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 14:58:11,937 log 23535 6285815808 Not Found: /favicon.ico +WARNING 2025-09-07 14:58:11,943 basehttp 23535 6285815808 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-07 14:59:11,824 basehttp 23535 6285815808 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:00:12,344 basehttp 23535 6285815808 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 15:01:02,531 log 23535 6285815808 Internal Server Error: /en/hr/schedules/21/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 243, in render + nodelist.append(node.render_annotated(context)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'schedule_assignment_delete' not found. 'schedule_assignment_delete' is not a valid view function or pattern name. +ERROR 2025-09-07 15:01:02,532 basehttp 23535 6285815808 "GET /en/hr/schedules/21/ HTTP/1.1" 500 224610 +WARNING 2025-09-07 15:01:02,554 log 23535 6285815808 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:01:02,554 basehttp 23535 6285815808 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 15:02:26,622 log 23535 6285815808 Internal Server Error: /en/hr/schedules/21/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'export_schedule' not found. 'export_schedule' is not a valid view function or pattern name. +ERROR 2025-09-07 15:02:26,623 basehttp 23535 6285815808 "GET /en/hr/schedules/21/ HTTP/1.1" 500 204110 +WARNING 2025-09-07 15:02:26,639 log 23535 6285815808 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:02:26,640 basehttp 23535 6285815808 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:03:24,515 basehttp 23535 6285815808 "GET /en/hr/schedules/21/ HTTP/1.1" 200 173472 +WARNING 2025-09-07 15:03:24,526 basehttp 23535 6285815808 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:03:24,527 basehttp 23535 6201683968 "GET /static/plugins/chart.js/dist/chart.umd.js HTTP/1.1" 200 206279 +WARNING 2025-09-07 15:03:24,532 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:03:24,532 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:03:24,566 basehttp 23535 6218510336 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:03:24,638 basehttp 23535 6201683968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:03:24,643 basehttp 23535 6201683968 "GET /static/plugins/chart.js/dist/chart.umd.js.map HTTP/1.1" 200 958364 +WARNING 2025-09-07 15:03:24,656 basehttp 23535 6201683968 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:03:49,585 basehttp 23535 6201683968 "GET /en/hr/schedules/21/ HTTP/1.1" 200 173472 +INFO 2025-09-07 15:03:49,597 basehttp 23535 6252163072 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-07 15:03:49,598 basehttp 23535 6285815808 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +INFO 2025-09-07 15:03:49,599 basehttp 23535 6268989440 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-07 15:03:49,601 basehttp 23535 6252163072 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +WARNING 2025-09-07 15:03:49,602 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:03:49,602 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:03:49,603 basehttp 23535 6218510336 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-07 15:03:49,604 basehttp 23535 6235336704 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +WARNING 2025-09-07 15:03:49,685 basehttp 23535 6218510336 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:03:49,685 basehttp 23535 6235336704 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-07 15:03:49,687 basehttp 23535 6201683968 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-07 15:03:49,689 basehttp 23535 6201683968 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-07 15:03:49,690 basehttp 23535 6235336704 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-07 15:03:49,690 basehttp 23535 6201683968 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-07 15:03:49,691 basehttp 23535 6201683968 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-07 15:03:49,692 basehttp 23535 6235336704 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-07 15:03:49,693 basehttp 23535 6235336704 "GET /static/plugins/%40fullcalendar/daygrid/index.global.js HTTP/1.1" 200 58461 +INFO 2025-09-07 15:03:49,694 basehttp 23535 6201683968 "GET /static/plugins/%40fullcalendar/core/index.global.js HTTP/1.1" 200 444856 +INFO 2025-09-07 15:03:49,695 basehttp 23535 6235336704 "GET /static/plugins/%40fullcalendar/timegrid/index.global.js HTTP/1.1" 200 68582 +INFO 2025-09-07 15:03:49,695 basehttp 23535 6201683968 "GET /static/plugins/%40fullcalendar/interaction/index.global.js HTTP/1.1" 200 99452 +INFO 2025-09-07 15:03:49,696 basehttp 23535 6235336704 "GET /static/plugins/%40fullcalendar/list/index.global.js HTTP/1.1" 200 18635 +INFO 2025-09-07 15:03:49,696 basehttp 23535 6201683968 "GET /static/plugins/%40fullcalendar/bootstrap/index.global.js HTTP/1.1" 200 2075 +INFO 2025-09-07 15:03:49,697 basehttp 23535 6235336704 "GET /static/plugins/chart.js/dist/chart.umd.js HTTP/1.1" 200 206279 +WARNING 2025-09-07 15:03:50,486 basehttp 23535 6201683968 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:03:50,487 basehttp 23535 6235336704 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-07 15:03:50,509 basehttp 23535 6252163072 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-07 15:03:50,510 basehttp 23535 6235336704 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-07 15:03:50,511 basehttp 23535 6201683968 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-07 15:03:50,512 basehttp 23535 6268989440 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-07 15:03:50,512 basehttp 23535 6285815808 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-07 15:03:50,514 basehttp 23535 6201683968 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-07 15:03:50,514 basehttp 23535 6218510336 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-07 15:03:50,515 basehttp 23535 6268989440 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-07 15:03:50,515 basehttp 23535 6285815808 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-07 15:03:50,517 basehttp 23535 6268989440 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-07 15:03:50,518 basehttp 23535 6218510336 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-07 15:03:50,518 basehttp 23535 6285815808 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-07 15:03:50,518 basehttp 23535 6252163072 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-07 15:03:50,518 basehttp 23535 6201683968 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-07 15:03:50,520 basehttp 23535 6285815808 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-07 15:03:50,521 basehttp 23535 6252163072 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-07 15:03:50,522 basehttp 23535 6201683968 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-07 15:03:50,523 basehttp 23535 6235336704 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-07 15:03:50,523 basehttp 23535 6268989440 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-07 15:03:50,523 basehttp 23535 6218510336 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-07 15:03:50,523 basehttp 23535 6285815808 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-07 15:03:50,524 basehttp 23535 6252163072 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-07 15:03:50,524 basehttp 23535 6201683968 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-07 15:03:50,538 basehttp 23535 6201683968 "GET /static/plugins/chart.js/dist/chart.umd.js.map HTTP/1.1" 200 958364 +INFO 2025-09-07 15:03:50,548 basehttp 23535 6201683968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:03:50,569 basehttp 23535 6201683968 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:03:50,625 log 23535 6285815808 Not Found: /favicon.ico +WARNING 2025-09-07 15:03:50,625 basehttp 23535 6285815808 "GET /favicon.ico HTTP/1.1" 404 2557 +WARNING 2025-09-07 15:03:59,502 basehttp 23535 6285815808 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:04:07,948 basehttp 23535 6252163072 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:04:15,855 basehttp 23535 6268989440 "GET /en/hr/employees/27/ HTTP/1.1" 200 34730 +WARNING 2025-09-07 15:04:15,880 log 23535 6268989440 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:04:15,880 basehttp 23535 6268989440 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:04:15,943 basehttp 23535 6268989440 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:04:22,166 log 23535 6268989440 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:04:22,166 basehttp 23535 6268989440 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:04:22,204 log 23535 6268989440 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:04:22,204 basehttp 23535 6268989440 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:04:50,563 basehttp 23535 6268989440 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:05:15,546 basehttp 23535 6268989440 "GET /en/hr/schedules/21/ HTTP/1.1" 200 173472 +WARNING 2025-09-07 15:05:15,555 basehttp 23535 6268989440 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:05:15,567 basehttp 23535 6218510336 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:05:15,571 log 23535 6235336704 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:05:15,571 basehttp 23535 6235336704 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:05:15,643 basehttp 23535 6235336704 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:05:15,665 basehttp 23535 6235336704 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:05:44,464 basehttp 23535 6201683968 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:06:02,782 basehttp 23535 6201683968 "GET /en/hr/schedules/?page=2 HTTP/1.1" 200 123257 +INFO 2025-09-07 15:06:02,791 basehttp 23535 6201683968 "GET /static/plugins/moment/min/moment.min.js HTTP/1.1" 200 58890 +WARNING 2025-09-07 15:06:02,812 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:06:02,812 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:06:02,819 basehttp 23535 6201683968 "GET /static/plugins/moment/min/moment.min.js.map HTTP/1.1" 200 98730 +INFO 2025-09-07 15:06:18,524 basehttp 23535 6201683968 "GET /en/hr/schedules/ HTTP/1.1" 200 122042 +WARNING 2025-09-07 15:06:18,548 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:06:18,548 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:06:18,986 basehttp 23535 6201683968 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 15:06:19,008 log 23535 6201683968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:06:19,008 basehttp 23535 6201683968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:06:21,734 basehttp 23535 6201683968 "GET /en/hr/departments/ HTTP/1.1" 200 125426 +INFO 2025-09-07 15:06:21,750 basehttp 23535 6201683968 "GET /static/plugins/datatables.net-buttons-bs5/css/buttons.bootstrap5.min.css HTTP/1.1" 200 8136 +INFO 2025-09-07 15:06:21,750 basehttp 23535 6252163072 "GET /static/plugins/datatables.net-buttons-bs5/js/buttons.bootstrap5.min.js HTTP/1.1" 200 1627 +INFO 2025-09-07 15:06:21,751 basehttp 23535 6218510336 "GET /static/plugins/select2/dist/css/select2.min.css HTTP/1.1" 200 14966 +INFO 2025-09-07 15:06:21,751 basehttp 23535 6235336704 "GET /static/plugins/datatables.net-buttons/js/dataTables.buttons.min.js HTTP/1.1" 200 27926 +WARNING 2025-09-07 15:06:21,755 log 23535 6268989440 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:06:21,756 basehttp 23535 6268989440 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:06:21,758 basehttp 23535 6235336704 "GET /static/plugins/datatables.net-buttons/js/buttons.print.min.js HTTP/1.1" 200 3073 +INFO 2025-09-07 15:06:21,758 basehttp 23535 6218510336 "GET /static/plugins/datatables.net-buttons/js/buttons.html5.min.js HTTP/1.1" 200 26043 +INFO 2025-09-07 15:06:21,760 basehttp 23535 6201683968 "GET /static/plugins/jszip/dist/jszip.min.js HTTP/1.1" 200 97630 +INFO 2025-09-07 15:06:21,763 basehttp 23535 6268989440 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +INFO 2025-09-07 15:06:21,768 basehttp 23535 6285815808 "GET /static/plugins/pdfmake/build/vfs_fonts.js HTTP/1.1" 200 828866 +INFO 2025-09-07 15:06:21,769 basehttp 23535 6252163072 "GET /static/plugins/pdfmake/build/pdfmake.min.js HTTP/1.1" 200 1400771 +INFO 2025-09-07 15:06:21,851 basehttp 23535 6252163072 "GET /static/plugins/pdfmake/build/pdfmake.min.js.map HTTP/1.1" 200 4214503 +INFO 2025-09-07 15:06:21,853 basehttp 23535 6285815808 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:06:24,044 log 23535 6285815808 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:06:24,044 basehttp 23535 6285815808 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:06:24,058 log 23535 6285815808 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:06:24,058 basehttp 23535 6285815808 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 15:06:25,465 log 23535 6285815808 Internal Server Error: /en/hr/time-entries/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'export_time_entries' not found. 'export_time_entries' is not a valid view function or pattern name. +ERROR 2025-09-07 15:06:25,466 basehttp 23535 6285815808 "GET /en/hr/time-entries/ HTTP/1.1" 500 202728 +WARNING 2025-09-07 15:06:25,492 log 23535 6285815808 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:06:25,492 basehttp 23535 6285815808 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:07:32,068 basehttp 23535 6285815808 "GET /en/hr/time-entries/ HTTP/1.1" 200 143885 +WARNING 2025-09-07 15:07:32,077 basehttp 23535 6268989440 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:07:32,078 basehttp 23535 6252163072 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.css HTTP/1.1" 200 8069 +INFO 2025-09-07 15:07:32,079 basehttp 23535 6201683968 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.js HTTP/1.1" 200 67842 +WARNING 2025-09-07 15:07:32,081 log 23535 6285815808 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:07:32,081 basehttp 23535 6285815808 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:07:32,106 basehttp 23535 6285815808 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:07:32,138 basehttp 23535 6201683968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:07:32,182 basehttp 23535 6201683968 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:07:50,766 basehttp 23535 6252163072 "GET /en/hr/time-entries/ HTTP/1.1" 200 143725 +WARNING 2025-09-07 15:07:50,774 basehttp 23535 6252163072 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:07:50,775 basehttp 23535 6218510336 "GET /static/img/user/user-1.jpg HTTP/1.1" 200 3528 +WARNING 2025-09-07 15:07:50,780 log 23535 6235336704 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:07:50,780 basehttp 23535 6235336704 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:07:50,837 basehttp 23535 6235336704 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:07:50,870 basehttp 23535 6235336704 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:07:52,889 basehttp 23535 6218510336 "GET /en/hr/time-entries/ HTTP/1.1" 200 143725 +INFO 2025-09-07 15:07:52,899 basehttp 23535 6235336704 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-07 15:07:52,899 basehttp 23535 6252163072 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-07 15:07:52,900 basehttp 23535 6268989440 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +INFO 2025-09-07 15:07:52,902 basehttp 23535 6285815808 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.css HTTP/1.1" 200 8069 +INFO 2025-09-07 15:07:52,904 basehttp 23535 6268989440 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +WARNING 2025-09-07 15:07:52,906 basehttp 23535 6285815808 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:07:52,908 basehttp 23535 6218510336 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-07 15:07:52,909 basehttp 23535 6235336704 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-07 15:07:52,911 basehttp 23535 6235336704 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +WARNING 2025-09-07 15:07:52,913 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:07:52,913 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:07:52,915 basehttp 23535 6235336704 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-07 15:07:52,916 basehttp 23535 6285815808 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-07 15:07:52,917 basehttp 23535 6252163072 - Broken pipe from ('127.0.0.1', 58254) +INFO 2025-09-07 15:07:52,918 basehttp 23535 6218510336 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-07 15:07:52,919 basehttp 23535 6302642176 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-07 15:07:52,922 basehttp 23535 6302642176 "GET /static/img/user/user-1.jpg HTTP/1.1" 200 3528 +INFO 2025-09-07 15:07:52,922 basehttp 23535 6235336704 "GET /static/plugins/moment/min/moment.min.js HTTP/1.1" 200 58890 +INFO 2025-09-07 15:07:52,922 basehttp 23535 6285815808 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.js HTTP/1.1" 200 67842 +INFO 2025-09-07 15:07:52,923 basehttp 23535 6218510336 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +INFO 2025-09-07 15:07:52,928 basehttp 23535 6201683968 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-07 15:07:52,929 basehttp 23535 6268989440 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +WARNING 2025-09-07 15:07:53,743 basehttp 23535 6268989440 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:07:53,773 basehttp 23535 6285815808 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-07 15:07:53,773 basehttp 23535 6201683968 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-07 15:07:53,773 basehttp 23535 6302642176 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-07 15:07:53,774 basehttp 23535 6235336704 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-07 15:07:53,774 basehttp 23535 6218510336 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-07 15:07:53,777 basehttp 23535 6235336704 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-07 15:07:53,778 basehttp 23535 6252163072 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-07 15:07:53,778 basehttp 23535 6218510336 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-07 15:07:53,778 basehttp 23535 6302642176 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-07 15:07:53,779 basehttp 23535 6201683968 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-07 15:07:53,781 basehttp 23535 6235336704 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-07 15:07:53,781 basehttp 23535 6252163072 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-07 15:07:53,782 basehttp 23535 6302642176 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-07 15:07:53,782 basehttp 23535 6218510336 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-07 15:07:53,782 basehttp 23535 6201683968 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-07 15:07:53,782 basehttp 23535 6285815808 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-07 15:07:53,785 basehttp 23535 6201683968 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-07 15:07:53,785 basehttp 23535 6235336704 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-07 15:07:53,785 basehttp 23535 6218510336 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-07 15:07:53,785 basehttp 23535 6302642176 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-07 15:07:53,785 basehttp 23535 6252163072 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-07 15:07:53,786 basehttp 23535 6285815808 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-07 15:07:53,786 basehttp 23535 6201683968 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-07 15:07:53,796 basehttp 23535 6201683968 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-07 15:07:53,806 basehttp 23535 6201683968 "GET /static/plugins/moment/min/moment.min.js.map HTTP/1.1" 200 98730 +INFO 2025-09-07 15:07:53,819 basehttp 23535 6201683968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:07:53,855 basehttp 23535 6201683968 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:07:54,101 log 23535 6302642176 Not Found: /favicon.ico +WARNING 2025-09-07 15:07:54,101 basehttp 23535 6302642176 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-07 15:08:41,055 basehttp 23535 6302642176 "GET /en/hr/time-entries/ HTTP/1.1" 200 138936 +WARNING 2025-09-07 15:08:41,068 log 23535 6302642176 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:08:41,068 basehttp 23535 6302642176 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:08:41,164 basehttp 23535 6302642176 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:08:54,359 basehttp 23535 6302642176 "GET /en/hr/time-entries/ HTTP/1.1" 200 138956 +INFO 2025-09-07 15:08:54,366 basehttp 23535 6302642176 "GET /static/img/user/user-10.jpg HTTP/1.1" 200 6490 +WARNING 2025-09-07 15:08:54,374 log 23535 6302642176 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:08:54,374 basehttp 23535 6302642176 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:08:54,431 basehttp 23535 6302642176 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:09:16,424 basehttp 23535 6302642176 "GET /en/hr/time-entries/ HTTP/1.1" 200 137743 +WARNING 2025-09-07 15:09:16,439 log 23535 6302642176 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:09:16,439 basehttp 23535 6302642176 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:09:16,498 basehttp 23535 6302642176 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:09:31,143 basehttp 23535 6302642176 "GET /en/hr/time-entries/ HTTP/1.1" 200 137863 +WARNING 2025-09-07 15:09:31,156 log 23535 6302642176 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:09:31,156 basehttp 23535 6302642176 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:09:31,207 basehttp 23535 6302642176 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:10:03,173 basehttp 23535 6302642176 "GET /en/hr/time-entries/ HTTP/1.1" 200 138243 +WARNING 2025-09-07 15:10:03,188 log 23535 6302642176 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:10:03,188 basehttp 23535 6302642176 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:10:03,237 basehttp 23535 6302642176 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:10:43,104 basehttp 23535 6302642176 "GET /en/hr/time-entries/ HTTP/1.1" 200 137710 +WARNING 2025-09-07 15:10:43,121 log 23535 6302642176 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:10:43,121 basehttp 23535 6302642176 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:10:43,175 basehttp 23535 6302642176 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:10:47,796 basehttp 23535 6302642176 "GET /en/hr/time-entries/45/ HTTP/1.1" 200 32196 +WARNING 2025-09-07 15:10:47,807 basehttp 23535 6285815808 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:10:47,812 log 23535 6302642176 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:10:47,812 basehttp 23535 6302642176 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:10:47,857 basehttp 23535 6302642176 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:11:17,487 basehttp 23535 6302642176 "GET /en/hr/time-entries/45/ HTTP/1.1" 200 32165 +WARNING 2025-09-07 15:11:17,500 basehttp 23535 6302642176 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:11:17,508 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:11:17,508 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:11:17,554 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:11:37,340 basehttp 23535 6252163072 "GET /en/hr/time-entries/45/ HTTP/1.1" 200 32158 +WARNING 2025-09-07 15:11:37,359 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:11:37,359 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:11:37,404 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:11:41,289 basehttp 23535 6252163072 "GET /en/hr/employees/2/ HTTP/1.1" 200 34735 +WARNING 2025-09-07 15:11:41,309 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:11:41,309 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:11:41,351 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:11:43,657 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:11:43,657 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:11:43,668 log 23535 6252163072 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:11:43,668 basehttp 23535 6252163072 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:12:25,801 basehttp 23535 6252163072 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:12:25,802 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:12:25,802 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:12:25,816 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:12:25,817 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:12:27,914 basehttp 23535 6218510336 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 15:12:27,929 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:12:27,929 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:12:30,289 basehttp 23535 6218510336 "GET /en/hr/employees/ HTTP/1.1" 200 130495 +WARNING 2025-09-07 15:12:30,308 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:12:30,308 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:12:30,330 basehttp 23535 6218510336 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 15:12:32,887 log 23535 6218510336 Internal Server Error: /en/hr/employees/56/delete/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'employee_deactivate' not found. 'employee_deactivate' is not a valid view function or pattern name. +ERROR 2025-09-07 15:12:32,888 basehttp 23535 6218510336 "GET /en/hr/employees/56/delete/ HTTP/1.1" 500 174783 +WARNING 2025-09-07 15:12:32,907 log 23535 6218510336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:12:32,907 basehttp 23535 6218510336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:14:32,943 autoreload 23535 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:14:33,479 autoreload 36795 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:14:34,155 basehttp 36795 6341865472 "GET /en/hr/employees/56/delete/ HTTP/1.1" 200 34468 +WARNING 2025-09-07 15:14:34,174 log 36795 6341865472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:14:34,174 basehttp 36795 6341865472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:14:34,222 basehttp 36795 6341865472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:15:01,587 basehttp 36795 6341865472 "GET /en/hr/employees/56/ HTTP/1.1" 200 34482 +WARNING 2025-09-07 15:15:01,601 log 36795 6341865472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:15:01,601 basehttp 36795 6341865472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:15:01,638 basehttp 36795 6341865472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:15:43,738 log 36795 6358691840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:15:43,739 basehttp 36795 6358691840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:15:43,741 basehttp 36795 6341865472 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:15:43,746 log 36795 6358691840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:15:43,746 basehttp 36795 6358691840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:15:50,386 basehttp 36795 6358691840 "GET /en/hr/employees/ HTTP/1.1" 200 130495 +WARNING 2025-09-07 15:15:50,398 log 36795 6358691840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:15:50,398 basehttp 36795 6358691840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:15:50,444 basehttp 36795 6358691840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:16:18,096 log 36795 6358691840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:16:18,097 basehttp 36795 6358691840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:16:18,109 log 36795 6358691840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:16:18,109 basehttp 36795 6358691840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:16:20,480 basehttp 36795 6358691840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:16:20,481 log 36795 6341865472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:16:20,481 basehttp 36795 6341865472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:16:20,490 log 36795 6341865472 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:16:20,490 basehttp 36795 6341865472 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:16:22,038 basehttp 36795 6341865472 "GET / HTTP/1.1" 302 0 +INFO 2025-09-07 15:16:22,063 basehttp 36795 6358691840 "GET /en/ HTTP/1.1" 200 49810 +WARNING 2025-09-07 15:16:22,083 log 36795 6358691840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:16:22,083 basehttp 36795 6358691840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:16:22,161 basehttp 36795 6358691840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:16:22,164 basehttp 36795 6392344576 "GET /en/htmx/tenant-info/ HTTP/1.1" 200 1043 +INFO 2025-09-07 15:16:22,165 basehttp 36795 6375518208 "GET /en/htmx/system-health/ HTTP/1.1" 200 1356 +INFO 2025-09-07 15:16:22,168 basehttp 36795 6341865472 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +INFO 2025-09-07 15:16:30,883 basehttp 36795 6341865472 "GET /en/hr HTTP/1.1" 301 0 +INFO 2025-09-07 15:16:30,921 basehttp 36795 6375518208 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 15:16:30,938 log 36795 6375518208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:16:30,938 basehttp 36795 6375518208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:16:30,956 basehttp 36795 6375518208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 15:16:39,629 log 36795 6375518208 Internal Server Error: /en/hr/reviews/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'export_performance_reviews' not found. 'export_performance_reviews' is not a valid view function or pattern name. +ERROR 2025-09-07 15:16:39,630 basehttp 36795 6375518208 "GET /en/hr/reviews/ HTTP/1.1" 500 213690 +WARNING 2025-09-07 15:16:39,650 log 36795 6375518208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:16:39,650 basehttp 36795 6375518208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:17:34,224 basehttp 36795 6375518208 "GET /en/hr/reviews/ HTTP/1.1" 200 37449 +WARNING 2025-09-07 15:17:34,238 log 36795 6375518208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:17:34,239 basehttp 36795 6375518208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:17:34,285 basehttp 36795 6375518208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:18:34,298 basehttp 36795 6375518208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:19:34,301 basehttp 36795 6375518208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:19:34,844 basehttp 36795 6375518208 "GET /en/hr/reviews/ HTTP/1.1" 200 37356 +WARNING 2025-09-07 15:19:34,863 log 36795 6375518208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:19:34,863 basehttp 36795 6375518208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:19:34,913 basehttp 36795 6375518208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:20:00,885 basehttp 36795 6375518208 "GET /en/hr/reviews/ HTTP/1.1" 200 37346 +WARNING 2025-09-07 15:20:00,902 log 36795 6375518208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:20:00,902 basehttp 36795 6375518208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:20:00,951 basehttp 36795 6375518208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:20:15,335 basehttp 36795 6375518208 "GET /en/hr/reviews/ HTTP/1.1" 200 37343 +WARNING 2025-09-07 15:20:15,355 log 36795 6375518208 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:20:15,355 basehttp 36795 6375518208 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:20:15,406 basehttp 36795 6375518208 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:20:18,213 basehttp 36795 6375518208 "GET /en/hr/reviews/ HTTP/1.1" 200 37343 +INFO 2025-09-07 15:20:18,226 basehttp 36795 6425997312 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.css HTTP/1.1" 200 8069 +INFO 2025-09-07 15:20:18,227 basehttp 36795 6409170944 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +INFO 2025-09-07 15:20:18,227 basehttp 36795 6358691840 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-07 15:20:18,228 basehttp 36795 6341865472 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-07 15:20:18,230 basehttp 36795 6425997312 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-07 15:20:18,232 basehttp 36795 6375518208 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +WARNING 2025-09-07 15:20:18,234 log 36795 6409170944 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-07 15:20:18,235 basehttp 36795 6392344576 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +WARNING 2025-09-07 15:20:18,237 basehttp 36795 6409170944 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:20:18,419 basehttp 36795 6392344576 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-07 15:20:18,422 basehttp 36795 6392344576 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-07 15:20:18,425 basehttp 36795 6409170944 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-07 15:20:18,427 basehttp 36795 6409170944 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-07 15:20:18,429 basehttp 36795 6409170944 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-07 15:20:18,430 basehttp 36795 6392344576 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-07 15:20:18,430 basehttp 36795 6409170944 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-07 15:20:18,432 basehttp 36795 6392344576 "GET /static/plugins/moment/min/moment.min.js HTTP/1.1" 200 58890 +INFO 2025-09-07 15:20:18,432 basehttp 36795 6409170944 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.js HTTP/1.1" 200 67842 +INFO 2025-09-07 15:20:18,435 basehttp 36795 6392344576 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +INFO 2025-09-07 15:20:19,239 basehttp 36795 6409170944 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-07 15:20:19,239 basehttp 36795 6341865472 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-07 15:20:19,239 basehttp 36795 6392344576 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-07 15:20:19,239 basehttp 36795 6375518208 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-07 15:20:19,239 basehttp 36795 6425997312 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-07 15:20:19,243 basehttp 36795 6358691840 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-07 15:20:19,243 basehttp 36795 6409170944 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-07 15:20:19,244 basehttp 36795 6341865472 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-07 15:20:19,245 basehttp 36795 6392344576 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-07 15:20:19,245 basehttp 36795 6341865472 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-07 15:20:19,245 basehttp 36795 6375518208 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-07 15:20:19,246 basehttp 36795 6358691840 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-07 15:20:19,246 basehttp 36795 6425997312 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-07 15:20:19,247 basehttp 36795 6409170944 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-07 15:20:19,248 basehttp 36795 6392344576 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-07 15:20:19,249 basehttp 36795 6358691840 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-07 15:20:19,249 basehttp 36795 6375518208 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-07 15:20:19,250 basehttp 36795 6341865472 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-07 15:20:19,250 basehttp 36795 6409170944 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-07 15:20:19,250 basehttp 36795 6425997312 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-07 15:20:19,252 basehttp 36795 6341865472 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-07 15:20:19,252 basehttp 36795 6375518208 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-07 15:20:19,254 basehttp 36795 6392344576 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-07 15:20:19,261 basehttp 36795 6409170944 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-07 15:20:19,295 basehttp 36795 6409170944 "GET /static/plugins/moment/min/moment.min.js.map HTTP/1.1" 200 98730 +INFO 2025-09-07 15:20:19,307 basehttp 36795 6409170944 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:20:19,537 log 36795 6409170944 Not Found: /favicon.ico +WARNING 2025-09-07 15:20:19,537 basehttp 36795 6409170944 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-07 15:20:32,844 basehttp 36795 6409170944 "GET /en/admin/hr/performancereview/ HTTP/1.1" 200 139984 +INFO 2025-09-07 15:20:32,855 basehttp 36795 6392344576 "GET /static/admin/css/dark_mode.css HTTP/1.1" 200 2808 +INFO 2025-09-07 15:20:32,856 basehttp 36795 6341865472 "GET /static/admin/css/nav_sidebar.css HTTP/1.1" 200 2810 +INFO 2025-09-07 15:20:32,856 basehttp 36795 6375518208 "GET /static/admin/js/theme.js HTTP/1.1" 200 1653 +INFO 2025-09-07 15:20:32,856 basehttp 36795 6409170944 "GET /static/admin/css/base.css HTTP/1.1" 200 22120 +INFO 2025-09-07 15:20:32,857 basehttp 36795 6425997312 "GET /static/admin/css/changelists.css HTTP/1.1" 200 6878 +INFO 2025-09-07 15:20:32,859 basehttp 36795 6375518208 "GET /static/admin/js/jquery.init.js HTTP/1.1" 200 347 +INFO 2025-09-07 15:20:32,860 basehttp 36795 6392344576 "GET /static/admin/css/responsive.css HTTP/1.1" 200 16565 +INFO 2025-09-07 15:20:32,860 basehttp 36795 6409170944 "GET /static/admin/js/core.js HTTP/1.1" 200 6208 +INFO 2025-09-07 15:20:32,860 basehttp 36795 6425997312 "GET /static/admin/js/admin/RelatedObjectLookups.js HTTP/1.1" 200 9777 +INFO 2025-09-07 15:20:32,863 basehttp 36795 6375518208 "GET /static/admin/js/actions.js HTTP/1.1" 200 8076 +INFO 2025-09-07 15:20:32,863 basehttp 36795 6409170944 "GET /static/admin/js/urlify.js HTTP/1.1" 200 7887 +INFO 2025-09-07 15:20:32,863 basehttp 36795 6392344576 "GET /static/admin/js/prepopulate.js HTTP/1.1" 200 1531 +INFO 2025-09-07 15:20:32,866 basehttp 36795 6341865472 "GET /static/admin/js/vendor/jquery/jquery.js HTTP/1.1" 200 285314 +INFO 2025-09-07 15:20:32,867 basehttp 36795 6392344576 "GET /static/admin/img/search.svg HTTP/1.1" 200 458 +INFO 2025-09-07 15:20:32,867 basehttp 36795 6358691840 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-07 15:20:32,868 basehttp 36795 6358691840 "GET /static/admin/js/nav_sidebar.js HTTP/1.1" 200 3063 +INFO 2025-09-07 15:20:32,869 basehttp 36795 6425997312 "GET /static/admin/js/vendor/xregexp/xregexp.js HTTP/1.1" 200 325171 +INFO 2025-09-07 15:20:32,872 basehttp 36795 6425997312 "GET /static/admin/js/filters.js HTTP/1.1" 200 978 +INFO 2025-09-07 15:20:32,881 basehttp 36795 6425997312 "GET /static/admin/img/icon-addlink.svg HTTP/1.1" 200 331 +INFO 2025-09-07 15:20:32,881 basehttp 36795 6358691840 "GET /static/admin/img/tooltag-add.svg HTTP/1.1" 200 331 +INFO 2025-09-07 15:20:32,881 basehttp 36795 6392344576 "GET /static/admin/img/sorting-icons.svg HTTP/1.1" 200 1097 +INFO 2025-09-07 15:20:32,882 basehttp 36795 6392344576 "GET /static/admin/img/icon-viewlink.svg HTTP/1.1" 200 581 +INFO 2025-09-07 15:21:19,323 basehttp 36795 6392344576 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:21:56,623 autoreload 36795 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:21:57,093 autoreload 40099 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:21:57,588 basehttp 40099 6170996736 "GET /en/hr/reviews/ HTTP/1.1" 200 87097 +WARNING 2025-09-07 15:21:57,604 log 40099 6170996736 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:21:57,604 basehttp 40099 6170996736 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:21:57,691 basehttp 40099 6170996736 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:22:22,149 basehttp 40099 6170996736 "GET /en/hr/reviews/ HTTP/1.1" 200 149783 +WARNING 2025-09-07 15:22:22,164 log 40099 6170996736 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:22:22,164 basehttp 40099 6170996736 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:22:22,221 basehttp 40099 6170996736 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:22:39,257 basehttp 40099 6170996736 "GET /en/hr/reviews/create/ HTTP/1.1" 200 51757 +INFO 2025-09-07 15:22:39,273 basehttp 40099 6187823104 "GET /static/plugins/select2/dist/css/select2.min.css HTTP/1.1" 200 14966 +WARNING 2025-09-07 15:22:39,275 log 40099 6170996736 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:22:39,276 basehttp 40099 6170996736 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:22:39,276 basehttp 40099 6204649472 "GET /static/plugins/summernote/dist/summernote-lite.css HTTP/1.1" 200 38212 +INFO 2025-09-07 15:22:39,277 basehttp 40099 6221475840 "GET /static/plugins/summernote/dist/summernote-lite.min.js HTTP/1.1" 200 186367 +INFO 2025-09-07 15:22:39,321 basehttp 40099 6221475840 "GET /static/webfonts/fa-regular-400.woff2 HTTP/1.1" 200 25472 +INFO 2025-09-07 15:22:39,329 basehttp 40099 6221475840 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:22:39,331 basehttp 40099 6221475840 "GET /static/plugins/summernote/dist/summernote-lite.css.map HTTP/1.1" 200 52049 +WARNING 2025-09-07 15:22:57,227 log 40099 6221475840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:22:57,227 basehttp 40099 6221475840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:22:57,261 log 40099 6221475840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:22:57,261 basehttp 40099 6221475840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:23:03,538 basehttp 40099 6221475840 "GET /en/hr/reviews/8/ HTTP/1.1" 200 35190 +WARNING 2025-09-07 15:23:03,557 basehttp 40099 6204649472 "GET /static/plugins/chart.js/dist/Chart.min.css HTTP/1.1" 404 2032 +WARNING 2025-09-07 15:23:03,558 basehttp 40099 6170996736 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +WARNING 2025-09-07 15:23:03,559 basehttp 40099 6187823104 "GET /static/plugins/chart.js/dist/Chart.min.js HTTP/1.1" 404 2029 +WARNING 2025-09-07 15:23:03,561 log 40099 6221475840 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:23:03,561 basehttp 40099 6221475840 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 15:23:03,585 basehttp 40099 6221475840 "GET /static/img/user/default-avatar.jpg HTTP/1.1" 404 2008 +INFO 2025-09-07 15:23:03,604 basehttp 40099 6170996736 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:24:03,619 basehttp 40099 6170996736 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:25:03,623 basehttp 40099 6170996736 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:26:03,615 basehttp 40099 6170996736 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:27:03,639 basehttp 40099 6170996736 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:27:19,943 autoreload 40099 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/models.py changed, reloading. +INFO 2025-09-07 15:27:20,378 autoreload 42495 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:28:03,695 basehttp 42495 6169866240 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:29:03,630 basehttp 42495 6169866240 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:29:15,762 autoreload 42495 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/models.py changed, reloading. +INFO 2025-09-07 15:29:16,265 autoreload 43350 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:30:03,693 basehttp 43350 6196097024 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:31:03,637 basehttp 43350 6196097024 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:31:56,553 autoreload 43350 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:31:56,912 autoreload 44551 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:32:03,696 basehttp 44551 6164459520 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:33:03,629 basehttp 44551 6164459520 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:34:03,634 basehttp 44551 6164459520 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:35:03,646 basehttp 44551 6164459520 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:36:03,647 basehttp 44551 6164459520 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:37:03,650 basehttp 44551 6164459520 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 15:37:37,753 log 44551 6164459520 Internal Server Error: /en/hr/reviews/8/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/detail.py", line 112, in get + self.object = self.get_object() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py", line 712, in get_object + return get_object_or_404(queryset, pk=self.kwargs.get(self.pk_url_kwarg, self.kwargs.get('pk'))) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/shortcuts.py", line 90, in get_object_or_404 + return queryset.get(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 629, in get + num = len(clone) + ^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 366, in __len__ + self._fetch_all() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1949, in _fetch_all + self._result_cache = list(self._iterable_class(self)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 91, in __iter__ + results = compiler.execute_sql( + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 1610, in execute_sql + sql, params = self.as_sql() + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 766, in as_sql + extra_select, order_by, group_by = self.pre_sql_setup( + ^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 85, in pre_sql_setup + self.setup_query(with_col_aliases=with_col_aliases) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 74, in setup_query + self.select, self.klass_info, self.annotation_col_map = self.get_select( + ^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 299, in get_select + related_klass_infos = self.get_related_selections(select, select_mask) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 1265, in get_related_selections + next_klass_infos = self.get_related_selections( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 1396, in get_related_selections + raise FieldError( +django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'manager'. Choices are: tenant, user, department, supervisor, created_by +ERROR 2025-09-07 15:37:37,756 basehttp 44551 6164459520 "GET /en/hr/reviews/8/ HTTP/1.1" 500 173140 +WARNING 2025-09-07 15:37:37,772 log 44551 6164459520 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:37:37,772 basehttp 44551 6164459520 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:38:15,889 autoreload 44551 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:38:16,260 autoreload 47337 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 15:38:16,841 log 47337 6194507776 Internal Server Error: /en/hr/reviews/8/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/detail.py", line 112, in get + self.object = self.get_object() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py", line 712, in get_object + return get_object_or_404(queryset, pk=self.kwargs.get(self.pk_url_kwarg, self.kwargs.get('pk'))) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/shortcuts.py", line 90, in get_object_or_404 + return queryset.get(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 629, in get + num = len(clone) + ^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 366, in __len__ + self._fetch_all() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1949, in _fetch_all + self._result_cache = list(self._iterable_class(self)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 91, in __iter__ + results = compiler.execute_sql( + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 1610, in execute_sql + sql, params = self.as_sql() + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 766, in as_sql + extra_select, order_by, group_by = self.pre_sql_setup( + ^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 85, in pre_sql_setup + self.setup_query(with_col_aliases=with_col_aliases) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 74, in setup_query + self.select, self.klass_info, self.annotation_col_map = self.get_select( + ^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 299, in get_select + related_klass_infos = self.get_related_selections(select, select_mask) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 1396, in get_related_selections + raise FieldError( +django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'created_by'. Choices are: employee, reviewer +ERROR 2025-09-07 15:38:16,843 basehttp 47337 6194507776 "GET /en/hr/reviews/8/ HTTP/1.1" 500 161070 +WARNING 2025-09-07 15:38:16,859 log 47337 6194507776 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:38:16,859 basehttp 47337 6194507776 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:38:38,194 autoreload 47337 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:38:38,527 autoreload 47502 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 15:38:38,784 log 47502 6138064896 Internal Server Error: /en/hr/reviews/8/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/detail.py", line 112, in get + self.object = self.get_object() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py", line 712, in get_object + return get_object_or_404(queryset, pk=self.kwargs.get(self.pk_url_kwarg, self.kwargs.get('pk'))) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/shortcuts.py", line 90, in get_object_or_404 + return queryset.get(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 629, in get + num = len(clone) + ^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 366, in __len__ + self._fetch_all() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1951, in _fetch_all + self._prefetch_related_objects() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1328, in _prefetch_related_objects + prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 2372, in prefetch_related_objects + raise AttributeError( +AttributeError: Cannot find 'categories' on PerformanceReview object, 'categories' is an invalid parameter to prefetch_related() +ERROR 2025-09-07 15:38:38,785 basehttp 47502 6138064896 "GET /en/hr/reviews/8/ HTTP/1.1" 500 113875 +WARNING 2025-09-07 15:38:38,798 log 47502 6138064896 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:38:38,798 basehttp 47502 6138064896 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:38:51,266 autoreload 47502 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:38:51,619 autoreload 47588 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:39:40,551 autoreload 47588 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:39:40,898 autoreload 47977 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 15:39:41,445 log 47977 6199848960 Internal Server Error: /en/hr/reviews/8/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/detail.py", line 112, in get + self.object = self.get_object() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py", line 712, in get_object + return get_object_or_404(queryset, pk=self.kwargs.get(self.pk_url_kwarg, self.kwargs.get('pk'))) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/shortcuts.py", line 90, in get_object_or_404 + return queryset.get(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 629, in get + num = len(clone) + ^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 366, in __len__ + self._fetch_all() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1951, in _fetch_all + self._prefetch_related_objects() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1328, in _prefetch_related_objects + prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 2386, in prefetch_related_objects + raise ValueError( +ValueError: 'review_type' does not resolve to an item that supports prefetching - this is an invalid parameter to prefetch_related(). +ERROR 2025-09-07 15:39:41,447 basehttp 47977 6199848960 "GET /en/hr/reviews/8/ HTTP/1.1" 500 113884 +WARNING 2025-09-07 15:39:41,458 log 47977 6199848960 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:39:41,458 basehttp 47977 6199848960 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:40:35,131 autoreload 47977 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:40:35,503 autoreload 48369 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 15:40:36,071 log 48369 6163918848 Internal Server Error: /en/hr/reviews/8/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/detail.py", line 112, in get + self.object = self.get_object() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py", line 712, in get_object + return get_object_or_404(queryset, pk=self.kwargs.get(self.pk_url_kwarg, self.kwargs.get('pk'))) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/shortcuts.py", line 90, in get_object_or_404 + return queryset.get(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 629, in get + num = len(clone) + ^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 366, in __len__ + self._fetch_all() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1951, in _fetch_all + self._prefetch_related_objects() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1328, in _prefetch_related_objects + prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 2372, in prefetch_related_objects + raise AttributeError( +AttributeError: Cannot find 'goals' on PerformanceReview object, 'goals' is an invalid parameter to prefetch_related() +ERROR 2025-09-07 15:40:36,072 basehttp 48369 6163918848 "GET /en/hr/reviews/8/ HTTP/1.1" 500 113687 +WARNING 2025-09-07 15:40:36,088 log 48369 6163918848 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:40:36,088 basehttp 48369 6163918848 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:40:44,031 autoreload 48369 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:40:44,357 autoreload 48481 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 15:40:44,695 log 48481 6130069504 Internal Server Error: /en/hr/reviews/8/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/views/generic/detail.py", line 113, in get + context = self.get_context_data(object=self.object) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py", line 780, in get_context_data + .order_by('-period_end')[:5] + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1722, in order_by + obj.query.add_ordering(*field_names) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/query.py", line 2291, in add_ordering + self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/query.py", line 1805, in names_to_path + raise FieldError( +django.core.exceptions.FieldError: Cannot resolve keyword 'period_end' into field. Choices are: areas_for_improvement, competency_ratings, created_at, development_plan, employee, employee_comments, employee_id, employee_signature_date, future_goals, goals_achieved, goals_not_achieved, id, notes, overall_rating, review_date, review_id, review_period_end, review_period_start, review_type, reviewer, reviewer_id, status, strengths, training_recommendations, updated_at +ERROR 2025-09-07 15:40:44,696 basehttp 48481 6130069504 "GET /en/hr/reviews/8/ HTTP/1.1" 500 104264 +WARNING 2025-09-07 15:40:44,707 log 48481 6130069504 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:40:44,707 basehttp 48481 6130069504 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:41:18,911 autoreload 48481 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:41:19,236 autoreload 48721 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:41:20,478 basehttp 48721 6122270720 "GET /en/hr/reviews/8/ HTTP/1.1" 200 35458 +WARNING 2025-09-07 15:41:20,492 log 48721 6122270720 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:41:20,492 basehttp 48721 6122270720 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:41:20,493 basehttp 48721 6139097088 "GET /static/plugins/chart.js/dist/chart.umd.js HTTP/1.1" 200 206279 +INFO 2025-09-07 15:41:20,573 basehttp 48721 6122270720 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:41:20,574 basehttp 48721 6139097088 "GET /static/plugins/chart.js/dist/chart.umd.js.map HTTP/1.1" 200 958364 +INFO 2025-09-07 15:42:20,568 basehttp 48721 6139097088 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:43:20,570 basehttp 48721 6139097088 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:44:03,623 autoreload 48721 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 15:44:03,983 autoreload 49957 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 15:44:20,650 basehttp 49957 6130266112 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:44:49,174 basehttp 49957 6130266112 "GET /en/hr/reviews/8/ HTTP/1.1" 200 47214 +WARNING 2025-09-07 15:44:49,195 log 49957 6130266112 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:44:49,195 basehttp 49957 6130266112 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 15:44:49,262 basehttp 49957 6130266112 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 15:45:49,267 basehttp 49957 6130266112 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 15:46:24,712 log 49957 6130266112 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:46:24,712 basehttp 49957 6130266112 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 15:46:29,157 log 49957 6130266112 Internal Server Error: /en/hr/reviews/55/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 327, in render + return nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'complete_performance_review' not found. 'complete_performance_review' is not a valid view function or pattern name. +ERROR 2025-09-07 15:46:29,159 basehttp 49957 6130266112 "GET /en/hr/reviews/55/ HTTP/1.1" 500 212138 +WARNING 2025-09-07 15:46:29,174 log 49957 6130266112 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 15:46:29,174 basehttp 49957 6130266112 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:03:50,066 autoreload 49957 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 16:03:50,557 autoreload 58605 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 16:05:14,742 autoreload 58605 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/urls.py changed, reloading. +INFO 2025-09-07 16:05:15,058 autoreload 59264 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 16:05:15,422 basehttp 59264 6191017984 "GET /en/hr/reviews/55/ HTTP/1.1" 200 47768 +WARNING 2025-09-07 16:05:15,435 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:05:15,435 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:05:15,496 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:06:15,511 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:07:15,498 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:07:47,624 basehttp 59264 6191017984 "GET /en/hr/reviews/55/ HTTP/1.1" 200 48316 +WARNING 2025-09-07 16:07:47,639 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:07:47,639 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:07:47,693 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:08:32,659 basehttp 59264 6191017984 "GET /en/hr/reviews/55/ HTTP/1.1" 200 48847 +WARNING 2025-09-07 16:08:32,673 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:08:32,674 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:08:32,728 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:08:58,962 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:08:58,962 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:09:31,141 basehttp 59264 6191017984 "GET /en/hr/reviews/ HTTP/1.1" 200 149783 +INFO 2025-09-07 16:09:31,156 basehttp 59264 6258323456 "GET /static/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css HTTP/1.1" 200 15096 +INFO 2025-09-07 16:09:31,157 basehttp 59264 6224670720 "GET /static/css/custom.css HTTP/1.1" 200 2063 +INFO 2025-09-07 16:09:31,157 basehttp 59264 6275149824 "GET /static/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css HTTP/1.1" 200 6044 +WARNING 2025-09-07 16:09:31,161 log 59264 6241497088 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-07 16:09:31,161 basehttp 59264 6258323456 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.css HTTP/1.1" 200 8069 +WARNING 2025-09-07 16:09:31,161 basehttp 59264 6241497088 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:09:31,163 basehttp 59264 6191017984 "GET /static/css/vendor.min.css HTTP/1.1" 200 177466 +INFO 2025-09-07 16:09:31,164 basehttp 59264 6275149824 "GET /static/img/user/user-4.jpg HTTP/1.1" 200 5916 +INFO 2025-09-07 16:09:31,166 basehttp 59264 6224670720 "GET /static/js/htmx.min.js HTTP/1.1" 200 50917 +INFO 2025-09-07 16:09:31,168 basehttp 59264 6275149824 "GET /static/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js HTTP/1.1" 200 1470 +INFO 2025-09-07 16:09:31,170 basehttp 59264 6207844352 "GET /static/css/default/app.min.css HTTP/1.1" 200 893480 +INFO 2025-09-07 16:09:31,171 basehttp 59264 6275149824 "GET /static/plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js HTTP/1.1" 200 1796 +INFO 2025-09-07 16:09:31,172 basehttp 59264 6258323456 "GET /static/js/app.min.js HTTP/1.1" 200 110394 +INFO 2025-09-07 16:09:31,173 basehttp 59264 6191017984 "GET /static/plugins/datatables.net/js/dataTables.min.js HTTP/1.1" 200 95735 +INFO 2025-09-07 16:09:31,175 basehttp 59264 6224670720 "GET /static/plugins/datatables.net-responsive/js/dataTables.responsive.min.js HTTP/1.1" 200 16086 +INFO 2025-09-07 16:09:31,181 basehttp 59264 6241497088 "GET /static/js/vendor.min.js HTTP/1.1" 200 1091361 +INFO 2025-09-07 16:09:31,184 basehttp 59264 6275149824 "GET /static/plugins/bootstrap-daterangepicker/daterangepicker.js HTTP/1.1" 200 67842 +INFO 2025-09-07 16:09:31,186 basehttp 59264 6258323456 "GET /static/plugins/select2/dist/js/select2.min.js HTTP/1.1" 200 70851 +INFO 2025-09-07 16:09:31,188 basehttp 59264 6207844352 "GET /static/plugins/moment/min/moment.min.js HTTP/1.1" 200 58890 +INFO 2025-09-07 16:09:32,003 basehttp 59264 6207844352 "GET /static/img/theme/default.jpg HTTP/1.1" 200 26964 +INFO 2025-09-07 16:09:32,003 basehttp 59264 6241497088 "GET /static/img/theme/material.jpg HTTP/1.1" 200 28774 +INFO 2025-09-07 16:09:32,003 basehttp 59264 6224670720 "GET /static/img/theme/facebook.jpg HTTP/1.1" 200 27881 +INFO 2025-09-07 16:09:32,003 basehttp 59264 6258323456 "GET /static/img/theme/transparent.jpg HTTP/1.1" 200 32747 +INFO 2025-09-07 16:09:32,004 basehttp 59264 6275149824 "GET /static/img/theme/apple.jpg HTTP/1.1" 200 28822 +INFO 2025-09-07 16:09:32,006 basehttp 59264 6191017984 "GET /static/img/theme/google.jpg HTTP/1.1" 200 86013 +INFO 2025-09-07 16:09:32,008 basehttp 59264 6241497088 "GET /static/img/version/html.jpg HTTP/1.1" 200 17325 +INFO 2025-09-07 16:09:32,008 basehttp 59264 6258323456 "GET /static/img/version/ajax.jpg HTTP/1.1" 200 20223 +INFO 2025-09-07 16:09:32,010 basehttp 59264 6191017984 "GET /static/img/version/svelte.jpg HTTP/1.1" 200 25060 +INFO 2025-09-07 16:09:32,010 basehttp 59264 6224670720 "GET /static/img/version/angular1x.jpg HTTP/1.1" 200 22869 +INFO 2025-09-07 16:09:32,010 basehttp 59264 6275149824 "GET /static/img/version/angular10x.jpg HTTP/1.1" 200 24580 +INFO 2025-09-07 16:09:32,011 basehttp 59264 6241497088 "GET /static/img/version/django.jpg HTTP/1.1" 200 20935 +INFO 2025-09-07 16:09:32,013 basehttp 59264 6191017984 "GET /static/img/version/dotnet.jpg HTTP/1.1" 200 24791 +INFO 2025-09-07 16:09:32,013 basehttp 59264 6258323456 "GET /static/img/version/laravel.jpg HTTP/1.1" 200 26040 +INFO 2025-09-07 16:09:32,013 basehttp 59264 6224670720 "GET /static/img/version/reactjs.jpg HTTP/1.1" 200 26850 +INFO 2025-09-07 16:09:32,013 basehttp 59264 6275149824 "GET /static/img/version/vuejs.jpg HTTP/1.1" 200 22518 +INFO 2025-09-07 16:09:32,015 basehttp 59264 6207844352 "GET /static/webfonts/fa-solid-900.woff2 HTTP/1.1" 200 158220 +INFO 2025-09-07 16:09:32,016 basehttp 59264 6275149824 "GET /static/img/theme/blog.jpg HTTP/1.1" 200 32334 +INFO 2025-09-07 16:09:32,016 basehttp 59264 6241497088 "GET /static/img/version/nextjs.jpg HTTP/1.1" 200 20152 +INFO 2025-09-07 16:09:32,017 basehttp 59264 6224670720 "GET /static/img/theme/e-commerce.jpg HTTP/1.1" 200 37734 +INFO 2025-09-07 16:09:32,017 basehttp 59264 6191017984 "GET /static/img/theme/forum.jpg HTTP/1.1" 200 28744 +INFO 2025-09-07 16:09:32,017 basehttp 59264 6207844352 "GET /static/img/theme/corporate.jpg HTTP/1.1" 200 38911 +INFO 2025-09-07 16:09:32,017 basehttp 59264 6258323456 "GET /static/img/theme/one-page-parallax.jpg HTTP/1.1" 200 22474 +INFO 2025-09-07 16:09:32,030 basehttp 59264 6191017984 "GET /static/css/default/app.min.css.map HTTP/1.1" 200 1957526 +INFO 2025-09-07 16:09:32,034 basehttp 59264 6207844352 "GET /static/plugins/moment/min/moment.min.js.map HTTP/1.1" 200 98730 +INFO 2025-09-07 16:09:32,046 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:09:32,133 log 59264 6207844352 Not Found: /favicon.ico +WARNING 2025-09-07 16:09:32,133 basehttp 59264 6207844352 "GET /favicon.ico HTTP/1.1" 404 2557 +INFO 2025-09-07 16:09:44,724 basehttp 59264 6207844352 "GET /en/hr/reviews/29/ HTTP/1.1" 200 54428 +INFO 2025-09-07 16:09:44,741 basehttp 59264 6191017984 "GET /static/plugins/chart.js/dist/chart.umd.js HTTP/1.1" 200 206279 +WARNING 2025-09-07 16:09:44,745 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:09:44,745 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:09:44,805 basehttp 59264 6207844352 "GET /static/webfonts/fa-regular-400.woff2 HTTP/1.1" 200 25472 +INFO 2025-09-07 16:09:44,820 basehttp 59264 6207844352 "GET /static/plugins/chart.js/dist/chart.umd.js.map HTTP/1.1" 200 958364 +INFO 2025-09-07 16:09:44,827 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:10:14,116 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:10:14,116 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:10:14,126 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:10:14,126 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:10:17,915 basehttp 59264 6207844352 "GET /en/hr/reviews/55/ HTTP/1.1" 200 48847 +WARNING 2025-09-07 16:10:17,932 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:10:17,932 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:10:18,030 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:10:22,113 basehttp 59264 6207844352 "GET /en/hr/reviews/55/complete/ HTTP/1.1" 302 0 +INFO 2025-09-07 16:10:22,127 basehttp 59264 6207844352 "GET /en/hr/reviews/55/ HTTP/1.1" 200 48707 +WARNING 2025-09-07 16:10:22,143 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:10:22,144 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:10:22,191 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:10:39,472 basehttp 59264 6207844352 "GET /en/hr/reviews/ HTTP/1.1" 200 148767 +WARNING 2025-09-07 16:10:39,493 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:10:39,493 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:10:39,562 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:10:45,577 basehttp 59264 6207844352 "GET /en/hr/reviews/86/ HTTP/1.1" 200 54386 +WARNING 2025-09-07 16:10:45,601 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:10:45,601 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:10:45,648 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:11:06,099 basehttp 59264 6207844352 "GET /en/hr/reviews/87/ HTTP/1.1" 200 46425 +WARNING 2025-09-07 16:11:06,121 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:11:06,121 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:11:06,171 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:11:12,234 basehttp 59264 6207844352 "GET /en/hr/reviews/86/ HTTP/1.1" 200 54386 +WARNING 2025-09-07 16:11:12,258 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:11:12,258 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:11:12,312 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:11:20,964 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:11:20,964 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:11:20,977 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:11:20,977 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:11:22,229 basehttp 59264 6207844352 "GET / HTTP/1.1" 302 0 +INFO 2025-09-07 16:11:22,252 basehttp 59264 6191017984 "GET /en/ HTTP/1.1" 200 49810 +WARNING 2025-09-07 16:11:22,273 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:11:22,273 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:11:22,342 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:11:22,346 basehttp 59264 6224670720 "GET /en/htmx/tenant-info/ HTTP/1.1" 200 1043 +INFO 2025-09-07 16:11:22,348 basehttp 59264 6275149824 "GET /en/htmx/system-health/ HTTP/1.1" 200 1356 +INFO 2025-09-07 16:11:22,350 basehttp 59264 6258323456 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +INFO 2025-09-07 16:11:25,239 basehttp 59264 6258323456 "GET /en/hr HTTP/1.1" 301 0 +INFO 2025-09-07 16:11:25,273 basehttp 59264 6275149824 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 16:11:25,294 log 59264 6275149824 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:11:25,294 basehttp 59264 6275149824 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:11:25,309 basehttp 59264 6275149824 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:11:33,103 basehttp 59264 6275149824 "GET /en/hr/departments/ HTTP/1.1" 200 125426 +INFO 2025-09-07 16:11:33,121 basehttp 59264 6275149824 "GET /static/plugins/datatables.net-buttons-bs5/css/buttons.bootstrap5.min.css HTTP/1.1" 200 8136 +INFO 2025-09-07 16:11:33,121 basehttp 59264 6241497088 "GET /static/plugins/datatables.net-buttons-bs5/js/buttons.bootstrap5.min.js HTTP/1.1" 200 1627 +INFO 2025-09-07 16:11:33,121 basehttp 59264 6224670720 "GET /static/plugins/select2/dist/css/select2.min.css HTTP/1.1" 200 14966 +INFO 2025-09-07 16:11:33,122 basehttp 59264 6191017984 "GET /static/plugins/datatables.net-buttons/js/dataTables.buttons.min.js HTTP/1.1" 200 27926 +WARNING 2025-09-07 16:11:33,126 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:11:33,127 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:11:33,128 basehttp 59264 6224670720 "GET /static/plugins/datatables.net-buttons/js/buttons.print.min.js HTTP/1.1" 200 3073 +INFO 2025-09-07 16:11:33,131 basehttp 59264 6241497088 "GET /static/plugins/jszip/dist/jszip.min.js HTTP/1.1" 200 97630 +INFO 2025-09-07 16:11:33,131 basehttp 59264 6191017984 "GET /static/plugins/datatables.net-buttons/js/buttons.html5.min.js HTTP/1.1" 200 26043 +INFO 2025-09-07 16:11:33,138 basehttp 59264 6258323456 "GET /static/plugins/pdfmake/build/vfs_fonts.js HTTP/1.1" 200 828866 +INFO 2025-09-07 16:11:33,144 basehttp 59264 6275149824 "GET /static/plugins/pdfmake/build/pdfmake.min.js HTTP/1.1" 200 1400771 +INFO 2025-09-07 16:11:33,217 basehttp 59264 6258323456 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:11:33,228 basehttp 59264 6275149824 "GET /static/plugins/pdfmake/build/pdfmake.min.js.map HTTP/1.1" 200 4214503 +INFO 2025-09-07 16:12:34,200 basehttp 59264 6275149824 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:13:12,441 basehttp 59264 6275149824 "GET /en/hr/departments/12/delete/ HTTP/1.1" 200 30311 +WARNING 2025-09-07 16:13:12,464 log 59264 6275149824 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:13:12,464 basehttp 59264 6275149824 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:13:12,504 basehttp 59264 6275149824 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:13:21,744 basehttp 59264 6275149824 "GET /en/hr/departments/12/ HTTP/1.1" 200 35129 +WARNING 2025-09-07 16:13:21,762 basehttp 59264 6258323456 "GET /static/plugins/chart.js/dist/Chart.min.css HTTP/1.1" 404 2032 +WARNING 2025-09-07 16:13:21,765 basehttp 59264 6241497088 "GET /static/plugins/chart.js/dist/Chart.min.js HTTP/1.1" 404 2029 +WARNING 2025-09-07 16:13:21,767 basehttp 59264 6191017984 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 16:13:21,769 log 59264 6275149824 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:13:21,769 basehttp 59264 6275149824 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:13:21,800 basehttp 59264 6275149824 "GET /static/css/saudiriyalsymbol.woff2 HTTP/1.1" 200 720 +INFO 2025-09-07 16:13:21,812 basehttp 59264 6275149824 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:13:36,120 basehttp 59264 6275149824 "GET /en/hr/departments/12/update/ HTTP/1.1" 200 41458 +WARNING 2025-09-07 16:13:36,137 basehttp 59264 6275149824 "GET /static/plugins/select2-bootstrap5-theme/select2-bootstrap5.min.css HTTP/1.1" 404 2104 +WARNING 2025-09-07 16:13:36,143 log 59264 6224670720 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:13:36,143 basehttp 59264 6224670720 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:13:36,192 basehttp 59264 6224670720 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:13:51,429 basehttp 59264 6224670720 "GET /en/hr/departments/ HTTP/1.1" 200 125426 +WARNING 2025-09-07 16:13:51,446 log 59264 6224670720 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:13:51,446 basehttp 59264 6224670720 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:13:51,546 basehttp 59264 6224670720 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:14:15,846 basehttp 59264 6224670720 "GET /en/hr/departments/10/ HTTP/1.1" 200 52158 +WARNING 2025-09-07 16:14:15,863 basehttp 59264 6224670720 "GET /static/plugins/chart.js/dist/Chart.min.css HTTP/1.1" 404 2032 +WARNING 2025-09-07 16:14:15,867 basehttp 59264 6207844352 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 16:14:15,867 basehttp 59264 6191017984 "GET /static/plugins/chart.js/dist/Chart.min.js HTTP/1.1" 404 2029 +WARNING 2025-09-07 16:14:15,870 log 59264 6241497088 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:14:15,870 basehttp 59264 6241497088 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:14:15,914 basehttp 59264 6241497088 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:14:51,664 basehttp 59264 6241497088 "GET /en/hr/employees/52/ HTTP/1.1" 200 34483 +WARNING 2025-09-07 16:14:51,686 log 59264 6241497088 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:14:51,687 basehttp 59264 6241497088 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:14:51,729 basehttp 59264 6241497088 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:15:51,745 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:16:51,736 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:17:51,739 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:18:25,132 basehttp 59264 6191017984 "GET /en/hr/employees/52/ HTTP/1.1" 200 36484 +WARNING 2025-09-07 16:18:25,143 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:18:25,143 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:18:25,186 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:18:48,463 basehttp 59264 6191017984 "GET /en/hr/employees/52/ HTTP/1.1" 200 36493 +WARNING 2025-09-07 16:18:48,479 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:18:48,479 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:18:48,517 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:19:48,522 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:20:48,535 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:21:16,667 basehttp 59264 6191017984 "GET /en/hr/employees/52/ HTTP/1.1" 200 35212 +WARNING 2025-09-07 16:21:16,680 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:21:16,681 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:21:16,729 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:22:16,739 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:22:49,183 basehttp 59264 6191017984 "GET /en/hr/employees/52/ HTTP/1.1" 200 35242 +WARNING 2025-09-07 16:22:49,197 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:22:49,197 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:22:49,222 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:23:01,175 basehttp 59264 6191017984 "GET /en/hr/employees/52/ HTTP/1.1" 200 35248 +WARNING 2025-09-07 16:23:01,190 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:23:01,191 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:23:01,252 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:23:57,143 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:23:57,146 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:23:57,146 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:23:57,149 basehttp 59264 6191017984 "GET /static/plugins/chart.js/dist/Chart.min.css HTTP/1.1" 404 2032 +WARNING 2025-09-07 16:23:57,164 log 59264 6207844352 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:23:57,164 basehttp 59264 6207844352 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:24:57,138 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:25:57,152 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:26:44,382 basehttp 59264 6207844352 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:26:44,387 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:26:44,387 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:26:44,400 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:26:44,400 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:26:45,380 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:26:45,380 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:26:45,391 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:26:45,392 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:26:46,047 basehttp 59264 6191017984 "GET /en/hr/departments/10/ HTTP/1.1" 200 52071 +INFO 2025-09-07 16:26:46,058 basehttp 59264 6191017984 "GET /static/plugins/chart.js/dist/chart.js HTTP/1.1" 200 403805 +WARNING 2025-09-07 16:26:46,066 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:26:46,066 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:26:46,117 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:27:46,133 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:28:15,821 basehttp 59264 6191017984 "GET /en/hr/departments/10/ HTTP/1.1" 200 53084 +WARNING 2025-09-07 16:28:15,836 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:28:15,836 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:28:15,892 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:28:27,430 basehttp 59264 6191017984 "GET /en/hr/departments/10/ HTTP/1.1" 200 53084 +WARNING 2025-09-07 16:28:27,449 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:28:27,449 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:28:27,510 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:28:37,552 basehttp 59264 6191017984 "GET /en/hr/departments/10/ HTTP/1.1" 200 53084 +WARNING 2025-09-07 16:28:37,569 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:28:37,569 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:28:37,614 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:29:20,934 basehttp 59264 6191017984 "GET /en/hr/departments/10/ HTTP/1.1" 200 52404 +WARNING 2025-09-07 16:29:20,949 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:29:20,950 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:29:21,002 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:29:28,213 basehttp 59264 6191017984 "GET /en/hr/departments/10/ HTTP/1.1" 200 52071 +WARNING 2025-09-07 16:29:28,231 log 59264 6191017984 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:29:28,231 basehttp 59264 6191017984 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:29:28,283 basehttp 59264 6191017984 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:29:48,811 basehttp 59264 6191017984 "GET /en/admin/hr/employee/ HTTP/1.1" 200 158543 +INFO 2025-09-07 16:29:48,826 basehttp 59264 6224670720 "GET /static/admin/css/nav_sidebar.css HTTP/1.1" 200 2810 +INFO 2025-09-07 16:29:48,826 basehttp 59264 6207844352 "GET /static/admin/css/dark_mode.css HTTP/1.1" 200 2808 +INFO 2025-09-07 16:29:48,827 basehttp 59264 6191017984 "GET /static/admin/css/base.css HTTP/1.1" 200 22120 +INFO 2025-09-07 16:29:48,827 basehttp 59264 6241497088 "GET /static/admin/css/changelists.css HTTP/1.1" 200 6878 +INFO 2025-09-07 16:29:48,827 basehttp 59264 6258323456 "GET /static/admin/js/theme.js HTTP/1.1" 200 1653 +INFO 2025-09-07 16:29:48,828 basehttp 59264 6207844352 "GET /static/admin/css/responsive.css HTTP/1.1" 200 16565 +INFO 2025-09-07 16:29:48,828 basehttp 59264 6241497088 "GET /static/admin/js/core.js HTTP/1.1" 200 6208 +INFO 2025-09-07 16:29:48,828 basehttp 59264 6191017984 "GET /static/admin/js/jquery.init.js HTTP/1.1" 200 347 +INFO 2025-09-07 16:29:48,830 basehttp 59264 6258323456 "GET /static/admin/js/admin/RelatedObjectLookups.js HTTP/1.1" 200 9777 +INFO 2025-09-07 16:29:48,830 basehttp 59264 6241497088 "GET /static/admin/js/prepopulate.js HTTP/1.1" 200 1531 +INFO 2025-09-07 16:29:48,831 basehttp 59264 6207844352 "GET /static/admin/js/actions.js HTTP/1.1" 200 8076 +INFO 2025-09-07 16:29:48,832 basehttp 59264 6191017984 "GET /static/admin/js/urlify.js HTTP/1.1" 200 7887 +INFO 2025-09-07 16:29:48,833 basehttp 59264 6241497088 "GET /static/admin/img/search.svg HTTP/1.1" 200 458 +INFO 2025-09-07 16:29:48,835 basehttp 59264 6275149824 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-07 16:29:48,835 basehttp 59264 6224670720 "GET /static/admin/js/vendor/jquery/jquery.js HTTP/1.1" 200 285314 +INFO 2025-09-07 16:29:48,839 basehttp 59264 6224670720 "GET /static/admin/js/nav_sidebar.js HTTP/1.1" 200 3063 +INFO 2025-09-07 16:29:48,839 basehttp 59264 6258323456 "GET /static/admin/js/vendor/xregexp/xregexp.js HTTP/1.1" 200 325171 +INFO 2025-09-07 16:29:48,840 basehttp 59264 6258323456 "GET /static/admin/js/filters.js HTTP/1.1" 200 978 +INFO 2025-09-07 16:29:48,848 basehttp 59264 6258323456 "GET /static/admin/img/icon-addlink.svg HTTP/1.1" 200 331 +INFO 2025-09-07 16:29:48,848 basehttp 59264 6224670720 "GET /static/admin/img/tooltag-add.svg HTTP/1.1" 200 331 +INFO 2025-09-07 16:29:48,849 basehttp 59264 6224670720 "GET /static/admin/img/icon-viewlink.svg HTTP/1.1" 200 581 +INFO 2025-09-07 16:29:56,778 basehttp 59264 6224670720 "GET /en/admin/hr/employee/56/change/ HTTP/1.1" 200 156606 +INFO 2025-09-07 16:29:56,788 basehttp 59264 6224670720 "GET /static/admin/css/forms.css HTTP/1.1" 200 8525 +INFO 2025-09-07 16:29:56,790 basehttp 59264 6191017984 "GET /static/admin/js/prepopulate_init.js HTTP/1.1" 200 586 +INFO 2025-09-07 16:29:56,791 basehttp 59264 6207844352 "GET /static/admin/css/widgets.css HTTP/1.1" 200 11991 +INFO 2025-09-07 16:29:56,791 basehttp 59264 6241497088 "GET /static/admin/js/inlines.js HTTP/1.1" 200 15628 +INFO 2025-09-07 16:29:56,791 basehttp 59264 6258323456 "GET /static/admin/js/calendar.js HTTP/1.1" 200 9141 +INFO 2025-09-07 16:29:56,791 basehttp 59264 6275149824 "GET /static/admin/js/admin/DateTimeShortcuts.js HTTP/1.1" 200 19319 +INFO 2025-09-07 16:29:56,793 basehttp 59264 6275149824 "GET /static/admin/img/icon-changelink.svg HTTP/1.1" 200 380 +INFO 2025-09-07 16:29:56,794 basehttp 59264 6224670720 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-07 16:29:56,794 basehttp 59264 6275149824 "GET /static/admin/img/icon-deletelink.svg HTTP/1.1" 200 392 +INFO 2025-09-07 16:29:56,795 basehttp 59264 6275149824 "GET /static/admin/img/icon-unknown.svg HTTP/1.1" 200 655 +INFO 2025-09-07 16:29:56,795 basehttp 59264 6224670720 "GET /static/admin/js/change_form.js HTTP/1.1" 200 606 +INFO 2025-09-07 16:29:56,826 basehttp 59264 6224670720 "GET /static/admin/img/icon-calendar.svg HTTP/1.1" 200 1086 +INFO 2025-09-07 16:29:57,267 basehttp 59264 6224670720 "GET /en/admin/hr/employee/ HTTP/1.1" 200 158543 +INFO 2025-09-07 16:29:58,269 basehttp 59264 6224670720 "GET /en/admin/hr/employee/56/change/ HTTP/1.1" 200 156606 +INFO 2025-09-07 16:29:58,284 basehttp 59264 6224670720 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-07 16:30:29,184 basehttp 59264 6224670720 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:31:06,779 basehttp 59264 6224670720 "GET /en/admin/hr/employee/ HTTP/1.1" 200 158543 +INFO 2025-09-07 16:31:08,868 basehttp 59264 6224670720 "GET /en/admin/hr/employee/25/change/ HTTP/1.1" 200 288687 +INFO 2025-09-07 16:31:08,887 basehttp 59264 6224670720 "GET /en/admin/jsi18n/ HTTP/1.1" 200 3342 +INFO 2025-09-07 16:31:08,932 basehttp 59264 6224670720 "GET /static/admin/img/icon-clock.svg HTTP/1.1" 200 677 +INFO 2025-09-07 16:31:30,175 basehttp 59264 6224670720 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:31:32,318 basehttp 59264 6224670720 "GET /en/admin/hr/employee/ HTTP/1.1" 200 158543 +INFO 2025-09-07 16:32:31,121 basehttp 59264 6224670720 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:33:32,123 basehttp 59264 6224670720 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:34:08,088 autoreload 59264 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 16:34:08,524 autoreload 71999 8747049152 Watching for file changes with StatReloader +WARNING 2025-09-07 16:34:10,955 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:34:10,955 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:34:11,988 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:34:11,989 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:34:12,973 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:34:12,973 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:34:13,585 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:34:13,585 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:34:14,036 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:34:14,036 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:34:14,547 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:34:14,547 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:34:40,331 basehttp 71999 6157496320 "GET /en/hr/training/ HTTP/1.1" 200 117094 +WARNING 2025-09-07 16:34:40,352 basehttp 71999 6174322688 "GET /static/plugins/datatables.net/js/jquery.dataTables.min.js HTTP/1.1" 404 2077 +WARNING 2025-09-07 16:34:40,354 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:34:40,354 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:34:40,424 basehttp 71999 6157496320 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:35:24,917 basehttp 71999 6157496320 "GET /en/hr/training/ HTTP/1.1" 200 117087 +WARNING 2025-09-07 16:35:24,942 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:35:24,942 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:35:24,993 basehttp 71999 6157496320 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 16:35:36,374 log 71999 6157496320 Internal Server Error: /en/hr/training/142/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 42, in select_template + return engine.get_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 79, in get_template + return Template(self.engine.get_template(template_name), self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 177, in get_template + template, origin = self.find_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 159, in find_template + template = loader.get_template(name, skip=skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/cached.py", line 57, in get_template + template = super().get_template(template_name, skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/base.py", line 28, in get_template + return Template( + ^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__ + self.nodelist = self.compile_nodelist() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 299, in do_extends + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 234, in do_block + nodelist = parser.parse(("endblock",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 862, in do_for + nodelist_loop = parser.parse( + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 489, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 487, in parse + filter_expression = self.compile_filter(token.contents) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 609, in compile_filter + return FilterExpression(token, self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 705, in __init__ + filter_func = parser.find_filter(filter_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 615, in find_filter + raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name) +django.template.exceptions.TemplateSyntaxError: Invalid filter: 'split' +ERROR 2025-09-07 16:35:36,376 basehttp 71999 6157496320 "GET /en/hr/training/142/ HTTP/1.1" 500 375709 +WARNING 2025-09-07 16:35:36,395 log 71999 6157496320 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:35:36,395 basehttp 71999 6157496320 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:36:29,062 autoreload 71999 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 16:36:29,463 autoreload 73004 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 16:36:29,881 log 73004 6191345664 Internal Server Error: /en/hr/training/142/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 42, in select_template + return engine.get_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 79, in get_template + return Template(self.engine.get_template(template_name), self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 177, in get_template + template, origin = self.find_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 159, in find_template + template = loader.get_template(name, skip=skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/cached.py", line 57, in get_template + template = super().get_template(template_name, skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/base.py", line 28, in get_template + return Template( + ^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__ + self.nodelist = self.compile_nodelist() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 299, in do_extends + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 234, in do_block + nodelist = parser.parse(("endblock",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 862, in do_for + nodelist_loop = parser.parse( + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 489, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 487, in parse + filter_expression = self.compile_filter(token.contents) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 609, in compile_filter + return FilterExpression(token, self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 705, in __init__ + filter_func = parser.find_filter(filter_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 615, in find_filter + raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name) +django.template.exceptions.TemplateSyntaxError: Invalid filter: 'split' +ERROR 2025-09-07 16:36:29,883 basehttp 73004 6191345664 "GET /en/hr/training/142/ HTTP/1.1" 500 375846 +WARNING 2025-09-07 16:36:29,900 log 73004 6191345664 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:36:29,900 basehttp 73004 6191345664 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:36:35,163 basehttp 73004 6191345664 "GET /en/hr/training HTTP/1.1" 301 0 +ERROR 2025-09-07 16:36:35,261 log 73004 6208172032 Internal Server Error: /en/hr/training/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'get_program_details' not found. 'get_program_details' is not a valid view function or pattern name. +ERROR 2025-09-07 16:36:35,262 basehttp 73004 6208172032 "GET /en/hr/training/ HTTP/1.1" 500 215315 +WARNING 2025-09-07 16:36:35,282 log 73004 6208172032 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:36:35,282 basehttp 73004 6208172032 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 16:40:38,449 log 73004 6208172032 Internal Server Error: /en/hr/training/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'update_program' not found. 'update_program' is not a valid view function or pattern name. +ERROR 2025-09-07 16:40:38,450 basehttp 73004 6208172032 "GET /en/hr/training/ HTTP/1.1" 500 217002 +WARNING 2025-09-07 16:40:38,462 log 73004 6208172032 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:40:38,462 basehttp 73004 6208172032 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 16:41:03,400 log 73004 6208172032 Internal Server Error: /en/hr/training/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'program_detail' not found. 'program_detail' is not a valid view function or pattern name. +ERROR 2025-09-07 16:41:03,401 basehttp 73004 6208172032 "GET /en/hr/training/ HTTP/1.1" 500 217084 +WARNING 2025-09-07 16:41:03,420 log 73004 6208172032 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:41:03,420 basehttp 73004 6208172032 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:43:49,987 basehttp 73004 6208172032 "GET /en/hr/training/ HTTP/1.1" 200 51267 +WARNING 2025-09-07 16:43:50,002 log 73004 6208172032 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:43:50,003 basehttp 73004 6208172032 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:43:50,050 basehttp 73004 6208172032 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:44:50,053 basehttp 73004 6208172032 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:45:14,901 autoreload 73004 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 16:45:15,356 autoreload 76878 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 16:45:16,032 basehttp 76878 6132101120 "GET /en/hr/training/ HTTP/1.1" 200 117087 +WARNING 2025-09-07 16:45:16,050 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:45:16,050 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:45:16,113 basehttp 76878 6132101120 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:45:35,524 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:45:35,524 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:45:40,288 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:45:40,289 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:45:43,734 basehttp 76878 6132101120 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 16:45:43,749 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:45:43,750 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:45:43,797 basehttp 76878 6132101120 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:45:54,662 basehttp 76878 6132101120 "GET /en/hr/training/ HTTP/1.1" 200 117087 +WARNING 2025-09-07 16:45:54,680 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:45:54,680 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:45:54,737 basehttp 76878 6132101120 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:45:56,841 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:45:56,842 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:45:56,881 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:45:56,881 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:46:43,810 basehttp 76878 6132101120 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:47:43,813 basehttp 76878 6132101120 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:47:44,830 basehttp 76878 6132101120 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 16:47:44,846 log 76878 6132101120 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:47:44,846 basehttp 76878 6132101120 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:47:44,893 basehttp 76878 6132101120 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:48:44,905 basehttp 76878 6132101120 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:49:35,670 autoreload 76878 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 16:49:35,990 autoreload 78804 8747049152 Watching for file changes with StatReloader +WARNING 2025-09-07 16:49:37,066 log 78804 6140686336 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:37,066 basehttp 78804 6140686336 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:49:37,106 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:49:37,137 log 78804 6123859968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:37,137 basehttp 78804 6123859968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:49:38,055 log 78804 6123859968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:38,055 basehttp 78804 6123859968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:49:38,064 log 78804 6123859968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:38,064 basehttp 78804 6123859968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:49:38,551 basehttp 78804 6123859968 "GET /en/hr/ HTTP/1.1" 200 42394 +WARNING 2025-09-07 16:49:38,562 log 78804 6123859968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:38,563 basehttp 78804 6123859968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:49:38,611 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 16:49:40,061 log 78804 6123859968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:40,061 basehttp 78804 6123859968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 16:49:40,074 log 78804 6123859968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:40,075 basehttp 78804 6123859968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:49:40,983 basehttp 78804 6123859968 "GET /en/hr/training/ HTTP/1.1" 200 51267 +WARNING 2025-09-07 16:49:41,003 log 78804 6123859968 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 16:49:41,003 basehttp 78804 6123859968 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 16:49:41,049 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:50:41,063 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:51:41,068 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:52:41,094 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:53:42,091 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:54:43,092 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:55:44,095 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:56:46,088 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 16:58:09,082 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:00:09,077 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:02:09,203 basehttp 78804 6123859968 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:02:22,937 autoreload 78804 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 17:02:23,361 autoreload 84426 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 17:02:36,218 basehttp 84426 6157742080 "GET /en/hr/training/ HTTP/1.1" 200 94607 +WARNING 2025-09-07 17:02:36,238 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:02:36,238 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 17:02:36,328 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 17:02:59,699 log 84426 6157742080 Internal Server Error: /en/hr/training/642/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 42, in select_template + return engine.get_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 79, in get_template + return Template(self.engine.get_template(template_name), self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 177, in get_template + template, origin = self.find_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 159, in find_template + template = loader.get_template(name, skip=skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/cached.py", line 57, in get_template + template = super().get_template(template_name, skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/base.py", line 28, in get_template + return Template( + ^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__ + self.nodelist = self.compile_nodelist() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 299, in do_extends + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 234, in do_block + nodelist = parser.parse(("endblock",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 862, in do_for + nodelist_loop = parser.parse( + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 489, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 487, in parse + filter_expression = self.compile_filter(token.contents) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 609, in compile_filter + return FilterExpression(token, self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 705, in __init__ + filter_func = parser.find_filter(filter_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 615, in find_filter + raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name) +django.template.exceptions.TemplateSyntaxError: Invalid filter: 'split' +ERROR 2025-09-07 17:02:59,703 basehttp 84426 6157742080 "GET /en/hr/training/642/ HTTP/1.1" 500 375709 +WARNING 2025-09-07 17:02:59,716 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:02:59,716 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 17:03:56,329 log 84426 6325039104 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:03:56,330 basehttp 84426 6325039104 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 17:03:56,331 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 17:03:56,341 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:03:56,341 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 17:03:57,012 basehttp 84426 6157742080 "GET /en/hr/training/ HTTP/1.1" 200 94613 +WARNING 2025-09-07 17:03:57,026 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:03:57,026 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 17:03:57,107 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 17:04:41,775 log 84426 6157742080 Internal Server Error: /en/hr/training/313/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 510, in parse + compile_func = self.tags[command] + ~~~~~~~~~^^^^^^^^^ +KeyError: "set_badge='success'" + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 42, in select_template + return engine.get_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 79, in get_template + return Template(self.engine.get_template(template_name), self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 177, in get_template + template, origin = self.find_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 159, in find_template + template = loader.get_template(name, skip=skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/cached.py", line 57, in get_template + template = super().get_template(template_name, skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/base.py", line 28, in get_template + return Template( + ^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__ + self.nodelist = self.compile_nodelist() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 299, in do_extends + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 234, in do_block + nodelist = parser.parse(("endblock",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 1540, in do_with + nodelist = parser.parse(("endwith",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 512, in parse + self.invalid_block_tag(token, command, parse_until) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 567, in invalid_block_tag + raise self.error( +django.template.exceptions.TemplateSyntaxError: Invalid block tag on line 48: 'set_badge='success'', expected 'elif', 'else' or 'endif'. Did you forget to register or load this tag? +ERROR 2025-09-07 17:04:41,778 basehttp 84426 6157742080 "GET /en/hr/training/313/ HTTP/1.1" 500 314845 +WARNING 2025-09-07 17:04:41,793 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:04:41,793 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 17:04:47,934 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:04:47,934 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 17:04:47,946 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:04:47,946 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 17:04:57,134 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 17:05:08,240 log 84426 6157742080 Internal Server Error: /en/hr/training/9/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 42, in select_template + return engine.get_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 79, in get_template + return Template(self.engine.get_template(template_name), self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 177, in get_template + template, origin = self.find_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 159, in find_template + template = loader.get_template(name, skip=skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/cached.py", line 57, in get_template + template = super().get_template(template_name, skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/base.py", line 28, in get_template + return Template( + ^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__ + self.nodelist = self.compile_nodelist() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 299, in do_extends + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 234, in do_block + nodelist = parser.parse(("endblock",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 862, in do_for + nodelist_loop = parser.parse( + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 489, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 487, in parse + filter_expression = self.compile_filter(token.contents) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 609, in compile_filter + return FilterExpression(token, self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 705, in __init__ + filter_func = parser.find_filter(filter_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 615, in find_filter + raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name) +django.template.exceptions.TemplateSyntaxError: Invalid filter: 'split' +ERROR 2025-09-07 17:05:08,242 basehttp 84426 6157742080 "GET /en/hr/training/9/ HTTP/1.1" 500 375659 +WARNING 2025-09-07 17:05:08,256 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:05:08,256 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 17:05:28,071 log 84426 6157742080 Internal Server Error: /en/hr/training/9/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 42, in select_template + return engine.get_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 79, in get_template + return Template(self.engine.get_template(template_name), self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 177, in get_template + template, origin = self.find_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 159, in find_template + template = loader.get_template(name, skip=skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/cached.py", line 57, in get_template + template = super().get_template(template_name, skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/base.py", line 28, in get_template + return Template( + ^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__ + self.nodelist = self.compile_nodelist() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 299, in do_extends + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 234, in do_block + nodelist = parser.parse(("endblock",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 862, in do_for + nodelist_loop = parser.parse( + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 489, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 487, in parse + filter_expression = self.compile_filter(token.contents) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 609, in compile_filter + return FilterExpression(token, self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 705, in __init__ + filter_func = parser.find_filter(filter_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 615, in find_filter + raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name) +django.template.exceptions.TemplateSyntaxError: Invalid filter: 'split' +ERROR 2025-09-07 17:05:28,073 basehttp 84426 6157742080 "GET /en/hr/training/9/ HTTP/1.1" 500 320532 +WARNING 2025-09-07 17:05:28,089 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:05:28,089 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 17:05:40,036 log 84426 6157742080 Internal Server Error: /en/hr/training/9/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'employee_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['en/hr/employees/(?P[0-9]+)/\\Z'] +ERROR 2025-09-07 17:05:40,038 basehttp 84426 6157742080 "GET /en/hr/training/9/ HTTP/1.1" 500 179703 +WARNING 2025-09-07 17:05:40,051 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:05:40,051 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +ERROR 2025-09-07 17:06:30,036 log 84426 6157742080 Internal Server Error: /en/hr/training/9/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'employee_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['en/hr/employees/(?P[0-9]+)/\\Z'] +ERROR 2025-09-07 17:06:30,037 basehttp 84426 6157742080 "GET /en/hr/training/9/ HTTP/1.1" 500 179703 +WARNING 2025-09-07 17:06:30,049 log 84426 6157742080 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:06:30,049 basehttp 84426 6157742080 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 17:13:58,575 log 84426 6325039104 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:13:58,575 basehttp 84426 6325039104 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 17:13:58,579 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 17:13:58,583 log 84426 6325039104 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 17:13:58,583 basehttp 84426 6325039104 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 17:14:58,570 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:15:00,153 basehttp 84426 6325039104 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 17:15:00,213 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:15:07,473 basehttp 84426 6325039104 "GET /en/blood-bank/units/38/ HTTP/1.1" 200 35788 +INFO 2025-09-07 17:15:07,484 basehttp 84426 6325039104 "GET /static/plugins/sweetalert/dist/sweetalert.min.js HTTP/1.1" 200 40808 +INFO 2025-09-07 17:15:07,520 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:15:14,164 basehttp 84426 6325039104 "GET /en/blood-bank/units/38/test/ HTTP/1.1" 200 45659 +INFO 2025-09-07 17:15:14,194 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:15:21,406 basehttp 84426 6325039104 "GET /en/blood-bank/donors/46/ HTTP/1.1" 200 29824 +INFO 2025-09-07 17:15:21,443 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:15:26,546 basehttp 84426 6325039104 "GET /en/blood-bank/donors/46/eligibility/ HTTP/1.1" 200 33976 +INFO 2025-09-07 17:15:26,582 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:16:06,428 basehttp 84426 6157742080 "GET /en/blood-bank/donors/46/eligibility/ HTTP/1.1" 200 33976 +INFO 2025-09-07 17:16:06,466 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:16:27,765 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:16:30,194 basehttp 84426 6157742080 "GET /en/blood-bank/units/13/ HTTP/1.1" 200 36506 +INFO 2025-09-07 17:16:30,234 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:16:47,814 basehttp 84426 6157742080 "GET /en/blood-bank/donors/46/eligibility/ HTTP/1.1" 200 33976 +INFO 2025-09-07 17:16:47,852 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:16:55,138 basehttp 84426 6157742080 "GET /en/blood-bank/donors/ HTTP/1.1" 200 82651 +INFO 2025-09-07 17:16:55,182 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:17:08,876 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:17:24,261 basehttp 84426 6157742080 "GET /en/blood-bank/inventory/ HTTP/1.1" 200 34369 +INFO 2025-09-07 17:17:24,299 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:17:43,987 basehttp 84426 6157742080 "GET /en/blood-bank/donors/ HTTP/1.1" 200 82651 +INFO 2025-09-07 17:17:44,028 basehttp 84426 6157742080 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:17:49,526 basehttp 84426 6157742080 "GET /en/blood-bank/units/create/ HTTP/1.1" 200 56247 +INFO 2025-09-07 17:17:49,534 basehttp 84426 6157742080 "GET /static/plugins/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css HTTP/1.1" 200 15733 +INFO 2025-09-07 17:17:49,534 basehttp 84426 6325039104 "GET /static/plugins/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js HTTP/1.1" 200 33871 +INFO 2025-09-07 17:17:49,565 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:18:49,580 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:19:49,585 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:20:49,583 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:21:17,193 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:21:17,777 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:21:23,031 basehttp 84426 6325039104 "GET /en/hr/training/ HTTP/1.1" 200 94613 +INFO 2025-09-07 17:21:23,076 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 17:21:24,288 log 84426 6325039104 Internal Server Error: /en/hr/training/9/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'employee_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['en/hr/employees/(?P[0-9]+)/\\Z'] +ERROR 2025-09-07 17:21:24,291 basehttp 84426 6325039104 "GET /en/hr/training/9/ HTTP/1.1" 500 179587 +INFO 2025-09-07 17:22:23,081 basehttp 84426 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:22:49,206 autoreload 84426 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 17:22:49,647 autoreload 93365 8747049152 Watching for file changes with StatReloader +ERROR 2025-09-07 17:22:52,504 log 93365 6132805632 Internal Server Error: /en/hr/training/9/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 480, in render + url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/base.py", line 98, in reverse + resolved_url = resolver._reverse_with_prefix(view, prefix, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 831, in _reverse_with_prefix + raise NoReverseMatch(msg) +django.urls.exceptions.NoReverseMatch: Reverse for 'training_record_print' not found. 'training_record_print' is not a valid view function or pattern name. +ERROR 2025-09-07 17:22:52,506 basehttp 93365 6132805632 "GET /en/hr/training/9/ HTTP/1.1" 500 177519 +INFO 2025-09-07 17:23:43,843 basehttp 93365 6132805632 "GET /en/hr/training/9/ HTTP/1.1" 200 28657 +INFO 2025-09-07 17:23:43,879 basehttp 93365 6132805632 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:24:43,895 basehttp 93365 6132805632 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:24:50,025 basehttp 93365 6132805632 "GET /en/hr/training/9/ HTTP/1.1" 200 28729 +INFO 2025-09-07 17:24:50,064 basehttp 93365 6132805632 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:25:18,410 basehttp 93365 6132805632 "GET /en/hr/training/9/ HTTP/1.1" 200 28765 +INFO 2025-09-07 17:25:18,451 basehttp 93365 6132805632 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:26:03,810 basehttp 93365 6132805632 "GET /en/hr/training/9/ HTTP/1.1" 200 28800 +INFO 2025-09-07 17:26:03,849 basehttp 93365 6132805632 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:27:03,861 basehttp 93365 6132805632 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:28:03,865 basehttp 93365 6132805632 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:29:21,091 autoreload 96269 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 17:29:32,040 basehttp 96269 6134935552 "GET /en/hr/training/9/ HTTP/1.1" 200 28800 +INFO 2025-09-07 17:29:32,081 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:30:12,259 basehttp 96269 6134935552 "GET /en/hr/employees/1/ HTTP/1.1" 200 35234 +INFO 2025-09-07 17:30:12,298 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:30:32,087 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:31:32,094 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:32:16,229 basehttp 96269 6134935552 "GET /en/hr/training/9/ HTTP/1.1" 200 28824 +INFO 2025-09-07 17:32:16,268 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:32:52,240 basehttp 96269 6134935552 "GET /en/hr/training/9/ HTTP/1.1" 200 28891 +INFO 2025-09-07 17:32:52,278 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:33:52,295 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:34:52,286 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:35:52,294 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:36:52,299 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:37:52,303 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:38:52,305 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:39:52,308 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:40:52,301 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:41:52,313 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:42:52,305 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:43:52,316 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:44:52,319 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:45:52,325 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:46:52,323 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:47:52,321 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:48:52,322 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:49:52,323 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:50:52,323 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:51:52,326 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:52:52,317 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:53:52,329 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:54:52,330 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:55:52,336 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:56:52,333 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:57:52,325 basehttp 96269 6134935552 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:58:30,257 autoreload 96269 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/models.py changed, reloading. +INFO 2025-09-07 17:58:30,606 autoreload 9737 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 17:58:31,247 basehttp 9737 6197653504 "GET /en/hr/training/9/ HTTP/1.1" 200 28891 +INFO 2025-09-07 17:58:31,281 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 17:58:34,709 basehttp 9737 6197653504 "GET /en/hr/training/ HTTP/1.1" 200 94613 +INFO 2025-09-07 17:58:35,629 basehttp 9737 6197653504 "GET /en/hr/training/ HTTP/1.1" 200 94613 +INFO 2025-09-07 17:58:35,671 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 17:58:40,144 log 9737 6197653504 Internal Server Error: /en/hr/training/create/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 90, in rendered_content + template = self.resolve_template(self.template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 72, in resolve_template + return select_template(template, using=self.using) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader.py", line 42, in select_template + return engine.get_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 79, in get_template + return Template(self.engine.get_template(template_name), self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 177, in get_template + template, origin = self.find_template(template_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/engine.py", line 159, in find_template + template = loader.get_template(name, skip=skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/cached.py", line 57, in get_template + template = super().get_template(template_name, skip) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loaders/base.py", line 28, in get_template + return Template( + ^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 154, in __init__ + self.nodelist = self.compile_nodelist() + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 196, in compile_nodelist + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 299, in do_extends + nodelist = parser.parse() + ^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 234, in do_block + nodelist = parser.parse(("endblock",)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 962, in do_if + nodelist = parser.parse(("elif", "else", "endif")) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 518, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 516, in parse + compiled_result = compile_func(self, token) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 862, in do_for + nodelist_loop = parser.parse( + ^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 489, in parse + raise self.error(token, e) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 487, in parse + filter_expression = self.compile_filter(token.contents) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 609, in compile_filter + return FilterExpression(token, self) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 705, in __init__ + filter_func = parser.find_filter(filter_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 615, in find_filter + raise TemplateSyntaxError("Invalid filter: '%s'" % filter_name) +django.template.exceptions.TemplateSyntaxError: Invalid filter: 'split' +ERROR 2025-09-07 17:58:40,147 basehttp 9737 6197653504 "GET /en/hr/training/create/ HTTP/1.1" 500 351884 +INFO 2025-09-07 18:00:40,415 basehttp 9737 6197653504 "GET /en/hr/training/create/ HTTP/1.1" 200 50385 +INFO 2025-09-07 18:00:40,425 basehttp 9737 6197653504 "GET /static/plugins/summernote/dist/summernote-lite.css HTTP/1.1" 200 38212 +INFO 2025-09-07 18:00:40,429 basehttp 9737 6197653504 "GET /static/plugins/summernote/dist/summernote-lite.min.js HTTP/1.1" 200 186367 +INFO 2025-09-07 18:00:40,458 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:00:55,121 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:01:55,122 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:02:55,113 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:03:55,114 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:04:55,114 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:05:55,118 basehttp 9737 6197653504 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:06:47,949 autoreload 9737 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/models.py changed, reloading. +INFO 2025-09-07 18:06:48,365 autoreload 13342 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 18:49:22,974 autoreload 31933 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 18:49:25,303 basehttp 31933 6191558656 "GET /en/hr/training/ HTTP/1.1" 200 94613 +INFO 2025-09-07 18:49:25,355 basehttp 31933 6191558656 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:49:28,905 basehttp 31933 6191558656 "GET /en/hr/training/9/ HTTP/1.1" 200 28891 +INFO 2025-09-07 18:49:28,934 basehttp 31933 6191558656 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 18:49:33,840 log 31933 6191558656 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 18:49:33,840 basehttp 31933 6191558656 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 18:49:42,876 basehttp 31933 6191558656 "GET /en/hr/training/9/update/ HTTP/1.1" 200 50484 +WARNING 2025-09-07 18:49:42,892 log 31933 6191558656 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 18:49:42,892 basehttp 31933 6191558656 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 18:49:42,964 basehttp 31933 6191558656 "GET /static/plugins/summernote/dist/summernote-lite.css.map HTTP/1.1" 200 52049 +INFO 2025-09-07 18:49:42,973 basehttp 31933 6191558656 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:50:42,989 basehttp 31933 6191558656 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:51:42,981 basehttp 31933 6191558656 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:52:35,424 autoreload 31933 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/models.py changed, reloading. +INFO 2025-09-07 18:52:35,775 autoreload 33342 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 18:52:43,036 basehttp 33342 6171783168 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:53:32,887 autoreload 33342 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/models.py changed, reloading. +INFO 2025-09-07 18:53:33,210 autoreload 33823 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 18:53:43,035 basehttp 33823 6158364672 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:54:42,988 basehttp 33823 6158364672 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:55:42,996 basehttp 33823 6158364672 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:56:42,995 basehttp 33823 6158364672 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:57:43,002 basehttp 33823 6158364672 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 18:58:14,610 autoreload 33823 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/models.py changed, reloading. +INFO 2025-09-07 18:58:14,946 autoreload 35826 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 19:01:36,616 autoreload 37400 8747049152 Watching for file changes with StatReloader +WARNING 2025-09-07 19:01:39,903 log 37400 6165229568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:01:39,903 basehttp 37400 6165229568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:01:40,024 basehttp 37400 6165229568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:01:49,447 basehttp 37400 6165229568 "GET /en/hr/training-management HTTP/1.1" 200 54669 +WARNING 2025-09-07 19:01:49,464 log 37400 6165229568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:01:49,465 basehttp 37400 6165229568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:01:49,534 basehttp 37400 6165229568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:02:05,029 autoreload 37400 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 19:02:05,363 autoreload 37565 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 19:02:05,952 basehttp 37565 6196097024 "GET /en/hr/training-management HTTP/1.1" 200 94613 +WARNING 2025-09-07 19:02:05,971 log 37565 6196097024 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:02:05,971 basehttp 37565 6196097024 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:02:06,058 basehttp 37565 6196097024 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:02:31,038 basehttp 37565 6196097024 "GET /en/hr/training/create/ HTTP/1.1" 200 50385 +WARNING 2025-09-07 19:02:31,056 log 37565 6196097024 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:02:31,056 basehttp 37565 6196097024 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:02:31,137 basehttp 37565 6196097024 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 19:02:35,803 log 37565 6196097024 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:02:35,803 basehttp 37565 6196097024 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 19:02:35,812 log 37565 6196097024 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:02:35,813 basehttp 37565 6196097024 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:03:06,065 basehttp 37565 6196097024 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:03:56,545 autoreload 37565 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 19:03:56,902 autoreload 38419 8747049152 Watching for file changes with StatReloader +WARNING 2025-09-07 19:03:57,860 log 38419 6159265792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:03:57,861 basehttp 38419 6159265792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 19:03:57,872 log 38419 6159265792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:03:57,872 basehttp 38419 6159265792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:03:59,887 basehttp 38419 6159265792 "GET /en/hr/training-management HTTP/1.1" 200 97400 +WARNING 2025-09-07 19:03:59,901 log 38419 6159265792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:03:59,901 basehttp 38419 6159265792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:03:59,985 basehttp 38419 6159265792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:04:02,939 basehttp 38419 6159265792 "GET /en/hr/training-management?page=2 HTTP/1.1" 200 97758 +WARNING 2025-09-07 19:04:02,962 log 38419 6159265792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:04:02,962 basehttp 38419 6159265792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:04:03,046 basehttp 38419 6159265792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:04:22,791 basehttp 38419 6159265792 "GET /en/hr/training/ HTTP/1.1" 200 36297 +WARNING 2025-09-07 19:04:22,810 log 38419 6159265792 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:04:22,810 basehttp 38419 6159265792 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:04:22,892 basehttp 38419 6159265792 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:04:40,791 autoreload 38419 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hr/views.py changed, reloading. +INFO 2025-09-07 19:04:41,117 autoreload 38736 8747049152 Watching for file changes with StatReloader +WARNING 2025-09-07 19:04:42,402 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:04:42,403 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 19:04:42,413 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:04:42,414 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:04:43,092 basehttp 38736 6197555200 "GET /en/hr/training/ HTTP/1.1" 200 117087 +WARNING 2025-09-07 19:04:43,108 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:04:43,109 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:04:43,204 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:05:43,209 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:05:59,216 basehttp 38736 6197555200 "GET /en/hr/training/ HTTP/1.1" 200 117148 +WARNING 2025-09-07 19:05:59,233 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:05:59,233 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:05:59,324 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:06:31,125 basehttp 38736 6197555200 "GET /en/hr/training/ HTTP/1.1" 200 117168 +WARNING 2025-09-07 19:06:31,138 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:06:31,138 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:06:31,232 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:07:05,391 basehttp 38736 6197555200 "GET /en/hr/training/ HTTP/1.1" 200 117193 +WARNING 2025-09-07 19:07:05,407 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:07:05,407 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:07:05,502 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:07:23,355 basehttp 38736 6197555200 "GET /en/hr/training/ HTTP/1.1" 200 117188 +WARNING 2025-09-07 19:07:23,372 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:07:23,372 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:07:23,466 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:07:59,729 basehttp 38736 6197555200 "GET /en/hr/training/ HTTP/1.1" 200 117193 +WARNING 2025-09-07 19:07:59,746 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:07:59,746 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:07:59,839 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:08:14,555 basehttp 38736 6197555200 "GET /en/hr/training/ HTTP/1.1" 200 117173 +WARNING 2025-09-07 19:08:14,570 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:08:14,570 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:08:14,664 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 19:08:30,306 log 38736 6214381568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +INFO 2025-09-07 19:08:30,307 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 19:08:30,307 basehttp 38736 6214381568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 19:08:30,316 log 38736 6214381568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:08:30,316 basehttp 38736 6214381568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:08:31,215 basehttp 38736 6214381568 "GET /en/hr/training-management?page=2 HTTP/1.1" 200 97758 +WARNING 2025-09-07 19:08:31,229 log 38736 6214381568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:08:31,230 basehttp 38736 6214381568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:08:31,318 basehttp 38736 6214381568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:08:43,991 basehttp 38736 6214381568 "GET /en/hr/training/986/ HTTP/1.1" 200 28844 +WARNING 2025-09-07 19:08:44,014 log 38736 6214381568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:08:44,014 basehttp 38736 6214381568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:08:44,086 basehttp 38736 6214381568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:09:44,092 basehttp 38736 6214381568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:10:44,103 basehttp 38736 6214381568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:11:44,106 basehttp 38736 6214381568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:12:44,111 basehttp 38736 6214381568 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:12:54,530 basehttp 38736 6214381568 "GET / HTTP/1.1" 302 0 +INFO 2025-09-07 19:12:54,555 basehttp 38736 6197555200 "GET /en/ HTTP/1.1" 200 49700 +WARNING 2025-09-07 19:12:54,573 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:12:54,573 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:12:54,664 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:12:54,674 basehttp 38736 6248034304 "GET /en/htmx/tenant-info/ HTTP/1.1" 200 1043 +INFO 2025-09-07 19:12:54,676 basehttp 38736 6231207936 "GET /en/htmx/system-health/ HTTP/1.1" 200 1356 +INFO 2025-09-07 19:12:54,677 basehttp 38736 6214381568 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +WARNING 2025-09-07 19:13:04,688 log 38736 6214381568 Not Found: /en/core/departments +WARNING 2025-09-07 19:13:04,689 basehttp 38736 6214381568 "GET /en/core/departments HTTP/1.1" 404 30136 +WARNING 2025-09-07 19:13:04,710 log 38736 6214381568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:13:04,710 basehttp 38736 6214381568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 19:13:26,185 log 38736 6214381568 Not Found: /en/core/departments +WARNING 2025-09-07 19:13:26,186 basehttp 38736 6214381568 "GET /en/core/departments HTTP/1.1" 404 30136 +WARNING 2025-09-07 19:13:26,203 log 38736 6214381568 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:13:26,203 basehttp 38736 6214381568 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:13:32,301 basehttp 38736 6214381568 "GET /en/departments HTTP/1.1" 301 0 +INFO 2025-09-07 19:13:32,322 basehttp 38736 6231207936 "GET /en/departments/ HTTP/1.1" 200 134624 +WARNING 2025-09-07 19:13:32,336 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:13:32,336 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:13:32,421 basehttp 38736 6231207936 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:13:38,966 basehttp 38736 6231207936 "GET /en/departments/12/ HTTP/1.1" 200 38676 +WARNING 2025-09-07 19:13:38,987 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:13:38,987 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:13:39,308 basehttp 38736 6231207936 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:13:55,079 basehttp 38736 6231207936 "GET /en/inventory/items/?department=12 HTTP/1.1" 200 73409 +WARNING 2025-09-07 19:13:55,094 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:13:55,095 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:13:55,191 basehttp 38736 6231207936 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 19:14:06,976 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:14:06,976 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 19:14:06,988 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:14:06,988 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:14:27,071 basehttp 38736 6231207936 "GET /en/hr/departments/12/ HTTP/1.1" 200 35042 +WARNING 2025-09-07 19:14:27,093 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:14:27,093 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:14:27,168 basehttp 38736 6231207936 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:14:34,406 basehttp 38736 6231207936 "GET /en/hr/departments/ HTTP/1.1" 200 125426 +WARNING 2025-09-07 19:14:34,428 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:14:34,428 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:14:34,516 basehttp 38736 6231207936 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:15:06,152 basehttp 38736 6231207936 "GET /en/hr/departments/create/ HTTP/1.1" 200 41288 +WARNING 2025-09-07 19:15:06,169 basehttp 38736 6248034304 "GET /static/plugins/select2-bootstrap5-theme/select2-bootstrap5.min.css HTTP/1.1" 404 2104 +WARNING 2025-09-07 19:15:06,174 log 38736 6231207936 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:15:06,174 basehttp 38736 6231207936 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:15:06,248 basehttp 38736 6231207936 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:15:58,471 basehttp 38736 6197555200 "GET /en/departments/create/ HTTP/1.1" 200 43115 +WARNING 2025-09-07 19:15:58,493 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:15:58,493 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:15:58,576 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:16:23,074 basehttp 38736 6197555200 "GET /en/hr/departments/create/ HTTP/1.1" 200 41288 +WARNING 2025-09-07 19:16:23,090 basehttp 38736 6214381568 "GET /static/plugins/select2-bootstrap5-theme/select2-bootstrap5.min.css HTTP/1.1" 404 2104 +WARNING 2025-09-07 19:16:23,094 log 38736 6197555200 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 19:16:23,094 basehttp 38736 6197555200 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 19:16:23,174 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:17:23,199 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:18:23,191 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:19:23,309 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:20:23,323 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:21:23,325 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:22:23,329 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:23:23,331 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:24:23,324 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 19:25:23,331 basehttp 38736 6197555200 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:16:49,289 autoreload 70364 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:17:02,711 autoreload 70364 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/models.py changed, reloading. +INFO 2025-09-07 20:17:03,014 autoreload 70456 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:17:18,406 autoreload 70456 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/admin.py changed, reloading. +INFO 2025-09-07 20:17:18,672 autoreload 70620 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:17:27,955 autoreload 70620 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/admin.py changed, reloading. +INFO 2025-09-07 20:17:28,275 autoreload 70706 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:17:39,722 autoreload 70706 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/views.py changed, reloading. +INFO 2025-09-07 20:17:40,062 autoreload 70801 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:17:48,381 autoreload 70801 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/forms.py changed, reloading. +INFO 2025-09-07 20:17:48,674 autoreload 70896 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:18:05,260 autoreload 70896 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/forms.py changed, reloading. +INFO 2025-09-07 20:18:05,558 autoreload 70980 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:19:38,162 autoreload 71715 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:20:42,235 autoreload 72212 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:21:00,993 autoreload 72212 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/forms.py changed, reloading. +INFO 2025-09-07 20:21:01,300 autoreload 72401 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:22:50,198 autoreload 73233 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:23:06,046 autoreload 73233 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/quality/forms.py changed, reloading. +INFO 2025-09-07 20:23:06,357 autoreload 73391 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:23:16,822 autoreload 73391 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/views.py changed, reloading. +INFO 2025-09-07 20:23:17,128 autoreload 73473 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:23:22,390 autoreload 73473 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/admin.py changed, reloading. +INFO 2025-09-07 20:23:22,700 autoreload 73486 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:23:56,461 autoreload 73486 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/models.py changed, reloading. +INFO 2025-09-07 20:23:56,769 autoreload 73801 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:24:00,929 autoreload 73820 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:24:15,641 autoreload 73820 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/forms.py changed, reloading. +INFO 2025-09-07 20:24:15,992 autoreload 73904 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:24:20,396 autoreload 73904 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/blood_bank/forms.py changed, reloading. +INFO 2025-09-07 20:24:20,713 autoreload 73991 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:24:40,610 autoreload 74164 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:25:54,846 autoreload 74745 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:26:42,932 autoreload 74745 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/core/models.py changed, reloading. +INFO 2025-09-07 20:26:43,364 autoreload 75052 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:26:48,819 basehttp 75052 6202585088 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +WARNING 2025-09-07 20:26:49,726 log 75052 6202585088 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 20:26:49,726 basehttp 75052 6202585088 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 20:26:51,621 basehttp 75052 6202585088 "GET / HTTP/1.1" 302 0 +INFO 2025-09-07 20:26:51,644 basehttp 75052 6219411456 "GET /en/ HTTP/1.1" 200 49790 +INFO 2025-09-07 20:26:51,735 basehttp 75052 6219411456 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:26:51,739 basehttp 75052 6202585088 "GET /en/htmx/dashboard-stats/ HTTP/1.1" 200 2094 +INFO 2025-09-07 20:26:51,745 basehttp 75052 6253064192 "GET /en/htmx/tenant-info/ HTTP/1.1" 200 1043 +INFO 2025-09-07 20:26:51,746 basehttp 75052 6236237824 "GET /en/htmx/system-health/ HTTP/1.1" 200 1356 +WARNING 2025-09-07 20:26:53,943 log 75052 6236237824 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 20:26:53,943 basehttp 75052 6236237824 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +WARNING 2025-09-07 20:26:55,517 log 75052 6236237824 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 20:26:55,518 basehttp 75052 6236237824 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 20:26:58,151 basehttp 75052 6236237824 "GET /en/blood-bank HTTP/1.1" 301 0 +INFO 2025-09-07 20:26:58,179 basehttp 75052 6253064192 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +WARNING 2025-09-07 20:26:58,194 log 75052 6253064192 Not Found: /.well-known/appspecific/com.chrome.devtools.json +WARNING 2025-09-07 20:26:58,194 basehttp 75052 6253064192 "GET /.well-known/appspecific/com.chrome.devtools.json HTTP/1.1" 404 2668 +INFO 2025-09-07 20:26:58,280 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:27:16,483 basehttp 75052 6253064192 "GET /en/blood-bank/units/38/ HTTP/1.1" 200 35788 +INFO 2025-09-07 20:27:16,522 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:27:27,392 basehttp 75052 6253064192 "GET /en/blood-bank/units/38/test/ HTTP/1.1" 200 45659 +INFO 2025-09-07 20:27:27,427 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:27:40,160 basehttp 75052 6253064192 "GET /en/blood-bank/donors/46/ HTTP/1.1" 200 29824 +INFO 2025-09-07 20:27:40,196 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:27:46,387 basehttp 75052 6253064192 "GET /en/blood-bank/donors/46/eligibility/ HTTP/1.1" 200 33976 +INFO 2025-09-07 20:27:46,422 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:28:28,942 basehttp 75052 6253064192 "GET /en/blood-bank/donors/46/eligibility/ HTTP/1.1" 200 33976 +INFO 2025-09-07 20:28:28,979 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:28:31,872 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:28:34,119 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:28:36,679 basehttp 75052 6253064192 "GET /en/blood-bank/units/ HTTP/1.1" 200 88820 +INFO 2025-09-07 20:28:36,725 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:28:41,682 basehttp 75052 6253064192 "GET /en/blood-bank/units/48/ HTTP/1.1" 200 36489 +INFO 2025-09-07 20:28:41,718 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:29:36,734 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:29:48,297 basehttp 75052 6253064192 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +ERROR 2025-09-07 20:30:04,781 log 75052 6253064192 Internal Server Error: /en/hr/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/sqlite3/base.py", line 360, in execute + return super().execute(query, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +sqlite3.OperationalError: no such column: hr_employee.national_id + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 199, in render + len_values = len(values) + ^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 366, in __len__ + self._fetch_all() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1949, in _fetch_all + self._result_cache = list(self._iterable_class(self)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 91, in __iter__ + results = compiler.execute_sql( + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 1623, in execute_sql + cursor.execute(sql, params) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 122, in execute + return super().execute(sql, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 79, in execute + return self._execute_with_wrappers( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers + return executor(sql, params, many, context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 100, in _execute + with self.db.wrap_database_errors: + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/utils.py", line 91, in __exit__ + raise dj_exc_value.with_traceback(traceback) from exc_value + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/sqlite3/base.py", line 360, in execute + return super().execute(query, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +django.db.utils.OperationalError: no such column: hr_employee.national_id +ERROR 2025-09-07 20:30:04,784 basehttp 75052 6253064192 "GET /en/hr/ HTTP/1.1" 500 235599 +ERROR 2025-09-07 20:30:05,673 log 75052 6253064192 Internal Server Error: /en/hr/ +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/sqlite3/base.py", line 360, in execute + return super().execute(query, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +sqlite3.OperationalError: no such column: hr_employee.national_id + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response + response = response.render() + ^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render + self.content = self.rendered_content + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content + return template.render(context, self._request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/backends/django.py", line 107, in render + return self.template.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 171, in render + return self._render(context) + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 159, in render + return compiled_parent._render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 163, in _render + return self.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/loader_tags.py", line 65, in render + result = block.nodelist.render(context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 1016, in render + return SafeString("".join([node.render_annotated(context) for node in self])) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/base.py", line 977, in render_annotated + return self.render(context) + ^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/template/defaulttags.py", line 199, in render + len_values = len(values) + ^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 366, in __len__ + self._fetch_all() + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 1949, in _fetch_all + self._result_cache = list(self._iterable_class(self)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/query.py", line 91, in __iter__ + results = compiler.execute_sql( + ^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/models/sql/compiler.py", line 1623, in execute_sql + cursor.execute(sql, params) + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 122, in execute + return super().execute(sql, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 79, in execute + return self._execute_with_wrappers( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 92, in _execute_with_wrappers + return executor(sql, params, many, context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 100, in _execute + with self.db.wrap_database_errors: + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/utils.py", line 91, in __exit__ + raise dj_exc_value.with_traceback(traceback) from exc_value + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 105, in _execute + return self.cursor.execute(sql, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/Users/marwanalwali/manus_project/hospital_management_system_v4/.venv/lib/python3.12/site-packages/django/db/backends/sqlite3/base.py", line 360, in execute + return super().execute(query, params) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +django.db.utils.OperationalError: no such column: hr_employee.national_id +ERROR 2025-09-07 20:30:05,674 basehttp 75052 6253064192 "GET /en/hr/ HTTP/1.1" 500 235325 +INFO 2025-09-07 20:32:25,310 autoreload 77623 8747049152 Watching for file changes with StatReloader +INFO 2025-09-07 20:32:27,794 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:32:27,802 basehttp 77623 6150778880 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 20:32:27,852 basehttp 77623 6150778880 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:32:29,943 basehttp 77623 6150778880 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 20:32:30,000 basehttp 77623 6150778880 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:32:34,727 basehttp 77623 6150778880 "GET /en/inpatients/ HTTP/1.1" 200 41725 +INFO 2025-09-07 20:32:34,781 basehttp 77623 6150778880 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:32:34,782 basehttp 77623 6133952512 "GET /en/inpatients/stats/ HTTP/1.1" 200 3000 +INFO 2025-09-07 20:32:34,805 basehttp 77623 6167605248 "GET /en/inpatients/bed-grid/ HTTP/1.1" 200 611361 +INFO 2025-09-07 20:32:59,005 basehttp 77623 6167605248 "GET /en/inpatients/beds/ HTTP/1.1" 200 2109891 +INFO 2025-09-07 20:32:59,099 basehttp 77623 6167605248 "GET /static/plugins/dropzone/dist/min/dropzone.min.js HTTP/1.1" 200 114702 +INFO 2025-09-07 20:32:59,124 basehttp 77623 6167605248 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:32:59,242 basehttp 77623 6167605248 "GET /en/inpatients/beds/ HTTP/1.1" 200 2109891 +INFO 2025-09-07 20:33:01,667 basehttp 77623 6167605248 "GET /en/inpatients/beds/1619/ HTTP/1.1" 200 31653 +INFO 2025-09-07 20:33:01,702 basehttp 77623 6167605248 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:33:25,036 basehttp 77623 6167605248 "GET /en/inpatients/stats/ HTTP/1.1" 200 3000 +INFO 2025-09-07 20:33:34,007 basehttp 77623 6167605248 "GET /en/patients/ HTTP/1.1" 200 139651 +INFO 2025-09-07 20:33:34,059 basehttp 77623 6167605248 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:33:34,063 basehttp 77623 6133952512 "GET /en/patients/patient-stats/ HTTP/1.1" 200 12305 +INFO 2025-09-07 20:33:39,047 basehttp 77623 6133952512 "GET /en/patients/patientprofile/39/details/ HTTP/1.1" 200 32460 +INFO 2025-09-07 20:33:39,082 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:34:39,100 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:35:39,416 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:36:40,417 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:37:41,413 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:38:42,412 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:39:43,413 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:40:45,399 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:42:09,408 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:43:09,410 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:45:09,404 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:46:09,397 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:48:09,395 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:49:09,402 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:51:09,395 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:52:09,397 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:53:31,269 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:53:38,787 basehttp 77623 6133952512 "GET /en/patients/insurance-info/39/ HTTP/1.1" 200 36065 +INFO 2025-09-07 20:53:38,809 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:53:51,162 basehttp 77623 6133952512 "GET /en/patients/consent-forms/39/ HTTP/1.1" 200 599 +INFO 2025-09-07 20:53:56,274 basehttp 77623 6133952512 "GET /en/patients/ HTTP/1.1" 200 139651 +INFO 2025-09-07 20:53:56,326 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 20:53:56,329 basehttp 77623 6150778880 "GET /en/patients/patient-stats/ HTTP/1.1" 200 12305 +INFO 2025-09-07 20:58:11,348 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 22:29:09,343 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 22:56:12,284 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:10:41,271 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:11:38,278 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:11:38,451 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:12:39,264 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:13:40,266 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:18:49,454 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:19:50,455 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:20:47,478 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:20:47,588 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:21:48,460 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:22:49,458 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:23:50,458 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:24:51,454 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:25:48,475 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:25:48,575 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:26:49,450 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:27:50,437 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:28:51,448 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:29:52,450 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:30:49,463 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:30:49,579 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:31:50,445 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:32:51,454 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:33:52,448 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:34:53,454 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:35:50,472 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:35:50,581 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:36:51,456 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:37:52,458 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:38:53,458 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:39:54,460 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:40:51,483 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:40:51,576 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:41:52,467 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:42:53,469 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:43:54,465 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:44:55,470 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:45:52,487 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:45:52,587 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:46:53,465 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:47:54,470 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:48:55,465 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:49:56,477 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:50:53,495 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:50:53,598 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:51:54,481 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:52:55,479 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:53:56,481 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:54:57,475 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:55:54,499 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-07 23:55:54,616 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:56:55,481 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:57:56,484 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:58:57,482 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-07 23:59:58,476 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:00:55,502 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-08 00:00:55,612 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:01:56,485 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:02:57,488 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:03:58,489 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:04:59,490 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:05:56,497 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-08 00:05:56,590 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:06:57,493 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:07:58,492 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:08:59,495 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:10:00,488 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:10:57,507 basehttp 77623 6133952512 "GET /en/blood-bank/ HTTP/1.1" 200 121063 +INFO 2025-09-08 00:10:57,573 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:11:58,483 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:12:59,487 basehttp 77623 6133952512 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:13:41,726 autoreload 77623 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/accounts/forms.py changed, reloading. +INFO 2025-09-08 00:13:42,196 autoreload 15542 8747049152 Watching for file changes with StatReloader +INFO 2025-09-08 00:14:00,567 basehttp 15542 6325039104 "GET /en/htmx/system-notifications/ HTTP/1.1" 200 3840 +INFO 2025-09-08 00:14:29,118 autoreload 15542 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/accounts/views.py changed, reloading. +INFO 2025-09-08 00:14:29,485 autoreload 15863 8747049152 Watching for file changes with StatReloader +INFO 2025-09-08 01:20:56,549 autoreload 15863 8747049152 /Users/marwanalwali/manus_project/hospital_management_system_v4/hospital_management/settings.py changed, reloading. +INFO 2025-09-08 01:20:56,938 autoreload 42555 8747049152 Watching for file changes with StatReloader +INFO 2025-09-08 02:59:34,343 autoreload 86776 8747049152 Watching for file changes with StatReloader diff --git a/operating_theatre/__pycache__/flows.cpython-312.pyc b/operating_theatre/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..9fe415f3 Binary files /dev/null and b/operating_theatre/__pycache__/flows.cpython-312.pyc differ diff --git a/operating_theatre/flows.py b/operating_theatre/flows.py new file mode 100644 index 00000000..3221e7e1 --- /dev/null +++ b/operating_theatre/flows.py @@ -0,0 +1,689 @@ +# """ +# Viewflow workflows for operating theatre app. +# Provides surgical scheduling, perioperative workflows, and OR management. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import SurgicalCase, SurgicalNote, EquipmentUsage, OperatingRoom +# from .views import ( +# SurgicalSchedulingView, PreoperativeChecklistView, ORSetupView, +# AnesthesiaInductionView, SurgicalProcedureView, PostoperativeView, +# SurgicalNoteView, EquipmentTrackingView +# ) +# +# +# class SurgicalCaseProcess(Process): +# """ +# Viewflow process model for surgical cases +# """ +# surgical_case = ModelField(SurgicalCase, help_text='Associated surgical case') +# +# # Process status tracking +# case_scheduled = models.BooleanField(default=False) +# preop_checklist_completed = models.BooleanField(default=False) +# or_setup_completed = models.BooleanField(default=False) +# anesthesia_induced = models.BooleanField(default=False) +# surgery_started = models.BooleanField(default=False) +# surgery_completed = models.BooleanField(default=False) +# postop_care_initiated = models.BooleanField(default=False) +# surgical_note_completed = models.BooleanField(default=False) +# case_closed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Surgical Case Process' +# verbose_name_plural = 'Surgical Case Processes' +# +# +# class SurgicalCaseFlow(Flow): +# """ +# Surgical Case Workflow +# +# This flow manages the complete surgical process from scheduling +# through postoperative care and documentation. +# """ +# +# process_class = SurgicalCaseProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_surgical_case) +# .Next(this.schedule_surgery) +# ) +# +# schedule_surgery = ( +# flow_view(SurgicalSchedulingView) +# .Permission('operating_theatre.can_schedule_surgery') +# .Next(this.preoperative_checklist) +# ) +# +# preoperative_checklist = ( +# flow_view(PreoperativeChecklistView) +# .Permission('operating_theatre.can_complete_preop_checklist') +# .Next(this.setup_or) +# ) +# +# setup_or = ( +# flow_view(ORSetupView) +# .Permission('operating_theatre.can_setup_or') +# .Next(this.induce_anesthesia) +# ) +# +# induce_anesthesia = ( +# flow_view(AnesthesiaInductionView) +# .Permission('operating_theatre.can_induce_anesthesia') +# .Next(this.perform_surgery) +# ) +# +# perform_surgery = ( +# flow_view(SurgicalProcedureView) +# .Permission('operating_theatre.can_perform_surgery') +# .Next(this.postoperative_care) +# ) +# +# postoperative_care = ( +# flow_view(PostoperativeView) +# .Permission('operating_theatre.can_provide_postop_care') +# .Next(this.parallel_documentation) +# ) +# +# parallel_documentation = ( +# flow_func(this.start_parallel_documentation) +# .Next(this.complete_surgical_note) +# .Next(this.track_equipment) +# ) +# +# complete_surgical_note = ( +# flow_view(SurgicalNoteView) +# .Permission('operating_theatre.can_complete_surgical_notes') +# .Next(this.join_documentation) +# ) +# +# track_equipment = ( +# flow_view(EquipmentTrackingView) +# .Permission('operating_theatre.can_track_equipment') +# .Next(this.join_documentation) +# ) +# +# join_documentation = ( +# flow_func(this.join_parallel_documentation) +# .Next(this.finalize_case) +# ) +# +# finalize_case = ( +# flow_func(this.complete_surgical_case) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_surgical_case) +# +# # Flow functions +# def start_surgical_case(self, activation): +# """Initialize the surgical case process""" +# process = activation.process +# surgical_case = process.surgical_case +# +# # Update case status +# surgical_case.status = 'SCHEDULED' +# surgical_case.save() +# +# # Send notification to OR staff +# self.notify_or_staff(surgical_case) +# +# # Check for emergency cases +# if surgical_case.priority == 'EMERGENCY': +# self.notify_emergency_surgery(surgical_case) +# +# def start_parallel_documentation(self, activation): +# """Start parallel documentation tasks""" +# process = activation.process +# +# # Create documentation tasks +# self.create_documentation_tasks(process.surgical_case) +# +# def join_parallel_documentation(self, activation): +# """Wait for all documentation to complete""" +# process = activation.process +# +# # Check if all documentation is completed +# if (process.surgical_note_completed and +# self.equipment_tracking_completed(process.surgical_case)): +# +# # Proceed to case finalization +# self.notify_case_ready_for_closure(process.surgical_case) +# +# def complete_surgical_case(self, activation): +# """Finalize the surgical case process""" +# process = activation.process +# surgical_case = process.surgical_case +# +# # Update case status +# surgical_case.status = 'COMPLETED' +# surgical_case.actual_end_time = timezone.now() +# surgical_case.save() +# +# # Update OR status +# if surgical_case.operating_room: +# surgical_case.operating_room.status = 'TURNOVER' +# surgical_case.operating_room.save() +# +# # Mark process as completed +# process.case_closed = True +# process.save() +# +# # Send completion notifications +# self.notify_case_completion(surgical_case) +# +# # Schedule OR cleaning +# self.schedule_or_cleaning(surgical_case.operating_room) +# +# def end_surgical_case(self, activation): +# """End the surgical case workflow""" +# process = activation.process +# +# # Generate case summary report +# self.generate_case_summary(process.surgical_case) +# +# # Update quality metrics +# self.update_quality_metrics(process.surgical_case) +# +# # Helper methods +# def notify_or_staff(self, surgical_case): +# """Notify OR staff of scheduled surgery""" +# from django.contrib.auth.models import Group +# +# or_staff = User.objects.filter( +# groups__name='OR Staff' +# ) +# +# for staff in or_staff: +# send_mail( +# subject=f'Surgery Scheduled: {surgical_case.case_number}', +# message=f'Surgery scheduled for {surgical_case.patient.get_full_name()} on {surgical_case.scheduled_start_time}.', +# from_email='or@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_emergency_surgery(self, surgical_case): +# """Notify of emergency surgery""" +# emergency_staff = User.objects.filter( +# groups__name__in=['OR Staff', 'Anesthesiologists', 'Surgeons'] +# ) +# +# for staff in emergency_staff: +# send_mail( +# subject=f'EMERGENCY Surgery: {surgical_case.case_number}', +# message=f'Emergency surgery required for {surgical_case.patient.get_full_name()}.', +# from_email='or@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def create_documentation_tasks(self, surgical_case): +# """Create documentation tasks""" +# # This would create tasks in a task management system +# pass +# +# def equipment_tracking_completed(self, surgical_case): +# """Check if equipment tracking is completed""" +# # This would check equipment tracking completion +# return True +# +# def notify_case_ready_for_closure(self, surgical_case): +# """Notify that case is ready for closure""" +# if surgical_case.primary_surgeon and surgical_case.primary_surgeon.email: +# send_mail( +# subject=f'Case Ready for Closure: {surgical_case.case_number}', +# message=f'All documentation completed for {surgical_case.patient.get_full_name()}.', +# from_email='or@hospital.com', +# recipient_list=[surgical_case.primary_surgeon.email], +# fail_silently=True +# ) +# +# def notify_case_completion(self, surgical_case): +# """Notify relevant staff of case completion""" +# # Notify recovery room staff +# recovery_staff = User.objects.filter( +# groups__name='Recovery Room Staff' +# ) +# +# for staff in recovery_staff: +# send_mail( +# subject=f'Patient to Recovery: {surgical_case.patient.get_full_name()}', +# message=f'Patient from OR {surgical_case.operating_room.room_number} coming to recovery.', +# from_email='or@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def schedule_or_cleaning(self, operating_room): +# """Schedule OR cleaning and turnover""" +# # This would schedule cleaning with housekeeping +# pass +# +# def generate_case_summary(self, surgical_case): +# """Generate surgical case summary report""" +# # This would generate a comprehensive case report +# pass +# +# def update_quality_metrics(self, surgical_case): +# """Update quality and performance metrics""" +# # This would update OR efficiency and quality metrics +# pass +# +# +# class ORSchedulingProcess(Process): +# """ +# Viewflow process model for OR scheduling +# """ +# scheduling_date = models.DateField(help_text='Date being scheduled') +# +# # Process status tracking +# schedule_reviewed = models.BooleanField(default=False) +# conflicts_resolved = models.BooleanField(default=False) +# staff_assigned = models.BooleanField(default=False) +# equipment_reserved = models.BooleanField(default=False) +# schedule_finalized = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'OR Scheduling Process' +# verbose_name_plural = 'OR Scheduling Processes' +# +# +# class ORSchedulingFlow(Flow): +# """ +# Operating Room Scheduling Workflow +# +# This flow manages OR scheduling including conflict resolution, +# staff assignment, and resource allocation. +# """ +# +# process_class = ORSchedulingProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_or_scheduling) +# .Next(this.review_schedule) +# ) +# +# review_schedule = ( +# flow_view(ScheduleReviewView) +# .Permission('operating_theatre.can_review_schedule') +# .Next(this.resolve_conflicts) +# ) +# +# resolve_conflicts = ( +# flow_view(ConflictResolutionView) +# .Permission('operating_theatre.can_resolve_conflicts') +# .Next(this.assign_staff) +# ) +# +# assign_staff = ( +# flow_view(StaffAssignmentView) +# .Permission('operating_theatre.can_assign_staff') +# .Next(this.reserve_equipment) +# ) +# +# reserve_equipment = ( +# flow_view(EquipmentReservationView) +# .Permission('operating_theatre.can_reserve_equipment') +# .Next(this.finalize_schedule) +# ) +# +# finalize_schedule = ( +# flow_func(this.complete_or_scheduling) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_or_scheduling) +# +# # Flow functions +# def start_or_scheduling(self, activation): +# """Initialize the OR scheduling process""" +# process = activation.process +# +# # Notify scheduling staff +# self.notify_scheduling_staff(process.scheduling_date) +# +# def complete_or_scheduling(self, activation): +# """Finalize the OR scheduling process""" +# process = activation.process +# +# # Mark schedule as finalized +# process.schedule_finalized = True +# process.save() +# +# # Send schedule notifications +# self.send_schedule_notifications(process.scheduling_date) +# +# def end_or_scheduling(self, activation): +# """End the OR scheduling workflow""" +# process = activation.process +# +# # Generate schedule report +# self.generate_schedule_report(process.scheduling_date) +# +# # Helper methods +# def notify_scheduling_staff(self, scheduling_date): +# """Notify scheduling staff""" +# scheduling_staff = User.objects.filter( +# groups__name='OR Scheduling' +# ) +# +# for staff in scheduling_staff: +# send_mail( +# subject=f'OR Schedule Review Required: {scheduling_date}', +# message=f'OR schedule for {scheduling_date} requires review.', +# from_email='or@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def send_schedule_notifications(self, scheduling_date): +# """Send schedule notifications to all staff""" +# # This would send schedule notifications +# pass +# +# def generate_schedule_report(self, scheduling_date): +# """Generate OR schedule report""" +# # This would generate schedule report +# pass +# +# +# class EquipmentMaintenanceProcess(Process): +# """ +# Viewflow process model for equipment maintenance +# """ +# equipment_id = CharField(max_length=50, help_text='Equipment identifier') +# maintenance_type = CharField(max_length=20, help_text='Type of maintenance') +# +# # Process status tracking +# maintenance_scheduled = models.BooleanField(default=False) +# equipment_inspected = models.BooleanField(default=False) +# maintenance_performed = models.BooleanField(default=False) +# quality_check_completed = models.BooleanField(default=False) +# equipment_returned = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Equipment Maintenance Process' +# verbose_name_plural = 'Equipment Maintenance Processes' +# +# +# class EquipmentMaintenanceFlow(Flow): +# """ +# Equipment Maintenance Workflow +# +# This flow manages equipment maintenance including scheduling, +# inspection, repair, and quality verification. +# """ +# +# process_class = EquipmentMaintenanceProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_equipment_maintenance) +# .Next(this.schedule_maintenance) +# ) +# +# schedule_maintenance = ( +# flow_view(MaintenanceSchedulingView) +# .Permission('operating_theatre.can_schedule_maintenance') +# .Next(this.inspect_equipment) +# ) +# +# inspect_equipment = ( +# flow_view(EquipmentInspectionView) +# .Permission('operating_theatre.can_inspect_equipment') +# .Next(this.perform_maintenance) +# ) +# +# perform_maintenance = ( +# flow_view(MaintenanceExecutionView) +# .Permission('operating_theatre.can_perform_maintenance') +# .Next(this.quality_check) +# ) +# +# quality_check = ( +# flow_view(MaintenanceQualityCheckView) +# .Permission('operating_theatre.can_quality_check_equipment') +# .Next(this.return_equipment) +# ) +# +# return_equipment = ( +# flow_func(this.complete_equipment_maintenance) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_equipment_maintenance) +# +# # Flow functions +# def start_equipment_maintenance(self, activation): +# """Initialize the equipment maintenance process""" +# process = activation.process +# +# # Notify maintenance staff +# self.notify_maintenance_staff(process.equipment_id, process.maintenance_type) +# +# def complete_equipment_maintenance(self, activation): +# """Finalize the equipment maintenance process""" +# process = activation.process +# +# # Mark equipment as available +# self.return_equipment_to_service(process.equipment_id) +# +# # Mark process as completed +# process.equipment_returned = True +# process.save() +# +# def end_equipment_maintenance(self, activation): +# """End the equipment maintenance workflow""" +# process = activation.process +# +# # Generate maintenance report +# self.generate_maintenance_report(process.equipment_id) +# +# # Helper methods +# def notify_maintenance_staff(self, equipment_id, maintenance_type): +# """Notify maintenance staff""" +# maintenance_staff = User.objects.filter( +# groups__name='Equipment Maintenance' +# ) +# +# for staff in maintenance_staff: +# send_mail( +# subject=f'Equipment Maintenance Required: {equipment_id}', +# message=f'{maintenance_type} maintenance required for equipment {equipment_id}.', +# from_email='maintenance@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def return_equipment_to_service(self, equipment_id): +# """Return equipment to service""" +# # This would update equipment status +# pass +# +# def generate_maintenance_report(self, equipment_id): +# """Generate maintenance report""" +# # This would generate maintenance report +# pass +# +# +# class SterilizationProcess(Process): +# """ +# Viewflow process model for instrument sterilization +# """ +# sterilization_batch = CharField(max_length=50, help_text='Sterilization batch identifier') +# +# # Process status tracking +# instruments_collected = models.BooleanField(default=False) +# cleaning_completed = models.BooleanField(default=False) +# packaging_completed = models.BooleanField(default=False) +# sterilization_completed = models.BooleanField(default=False) +# quality_verified = models.BooleanField(default=False) +# instruments_distributed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Sterilization Process' +# verbose_name_plural = 'Sterilization Processes' +# +# +# class SterilizationFlow(Flow): +# """ +# Instrument Sterilization Workflow +# +# This flow manages the sterilization process for surgical instruments +# including cleaning, packaging, sterilization, and quality verification. +# """ +# +# process_class = SterilizationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_sterilization) +# .Next(this.collect_instruments) +# ) +# +# collect_instruments = ( +# flow_view(InstrumentCollectionView) +# .Permission('operating_theatre.can_collect_instruments') +# .Next(this.clean_instruments) +# ) +# +# clean_instruments = ( +# flow_view(InstrumentCleaningView) +# .Permission('operating_theatre.can_clean_instruments') +# .Next(this.package_instruments) +# ) +# +# package_instruments = ( +# flow_view(InstrumentPackagingView) +# .Permission('operating_theatre.can_package_instruments') +# .Next(this.sterilize_instruments) +# ) +# +# sterilize_instruments = ( +# flow_view(SterilizationExecutionView) +# .Permission('operating_theatre.can_sterilize_instruments') +# .Next(this.verify_sterilization) +# ) +# +# verify_sterilization = ( +# flow_view(SterilizationVerificationView) +# .Permission('operating_theatre.can_verify_sterilization') +# .Next(this.distribute_instruments) +# ) +# +# distribute_instruments = ( +# flow_func(this.complete_sterilization) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_sterilization) +# +# # Flow functions +# def start_sterilization(self, activation): +# """Initialize the sterilization process""" +# process = activation.process +# +# # Notify sterilization staff +# self.notify_sterilization_staff(process.sterilization_batch) +# +# def complete_sterilization(self, activation): +# """Finalize the sterilization process""" +# process = activation.process +# +# # Mark instruments as available +# self.mark_instruments_available(process.sterilization_batch) +# +# # Mark process as completed +# process.instruments_distributed = True +# process.save() +# +# def end_sterilization(self, activation): +# """End the sterilization workflow""" +# process = activation.process +# +# # Generate sterilization report +# self.generate_sterilization_report(process.sterilization_batch) +# +# # Helper methods +# def notify_sterilization_staff(self, batch): +# """Notify sterilization staff""" +# sterilization_staff = User.objects.filter( +# groups__name='Sterilization Staff' +# ) +# +# for staff in sterilization_staff: +# send_mail( +# subject=f'Sterilization Batch Ready: {batch}', +# message=f'Sterilization batch {batch} is ready for processing.', +# from_email='sterilization@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def mark_instruments_available(self, batch): +# """Mark instruments as available""" +# # This would update instrument availability +# pass +# +# def generate_sterilization_report(self, batch): +# """Generate sterilization report""" +# # This would generate sterilization report +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_schedule_or_cleaning(room_id): +# """Background task to automatically schedule OR cleaning""" +# try: +# # This would schedule OR cleaning +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_case_delays(): +# """Background task to monitor surgical case delays""" +# try: +# # This would monitor for delays and send alerts +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_or_utilization_report(): +# """Background task to generate OR utilization report""" +# try: +# # This would generate utilization reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_assign_or_staff(case_id): +# """Background task to automatically assign OR staff""" +# try: +# # This would auto-assign staff based on availability +# return True +# except Exception: +# return False +# diff --git a/patients/__pycache__/flows.cpython-312.pyc b/patients/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..6bc9bd7f Binary files /dev/null and b/patients/__pycache__/flows.cpython-312.pyc differ diff --git a/patients/__pycache__/views.cpython-312.pyc b/patients/__pycache__/views.cpython-312.pyc index dcddb5e3..9d78f15d 100644 Binary files a/patients/__pycache__/views.cpython-312.pyc and b/patients/__pycache__/views.cpython-312.pyc differ diff --git a/patients/flows.py b/patients/flows.py new file mode 100644 index 00000000..b7455331 --- /dev/null +++ b/patients/flows.py @@ -0,0 +1,761 @@ +# """ +# Viewflow workflows for patients app. +# Provides patient registration, consent management, and record management workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import PatientProfile, ConsentForm, ConsentTemplate, PatientNote +# from .views import ( +# PatientRegistrationView, IdentityVerificationView, InsuranceVerificationView, +# ConsentCollectionView, MedicalHistoryView, EmergencyContactView, +# ConsentPresentationView, ConsentSigningView, ConsentWitnessView, +# ConsentVerificationView +# ) +# +# +# class PatientRegistrationProcess(Process): +# """ +# Viewflow process model for patient registration +# """ +# patient = ModelField(PatientProfile, help_text='Associated patient') +# +# # Process status tracking +# patient_created = models.BooleanField(default=False) +# identity_verified = models.BooleanField(default=False) +# insurance_verified = models.BooleanField(default=False) +# consents_collected = models.BooleanField(default=False) +# medical_history_collected = models.BooleanField(default=False) +# emergency_contacts_added = models.BooleanField(default=False) +# registration_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Patient Registration Process' +# verbose_name_plural = 'Patient Registration Processes' +# +# +# class PatientRegistrationFlow(Flow): +# """ +# Patient Registration Workflow +# +# This flow manages the complete patient registration process including +# identity verification, insurance verification, and consent collection. +# """ +# +# process_class = PatientRegistrationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_registration) +# .Next(this.create_patient_record) +# ) +# +# create_patient_record = ( +# flow_view(PatientRegistrationView) +# .Permission('patients.can_register_patients') +# .Next(this.verify_identity) +# ) +# +# verify_identity = ( +# flow_view(IdentityVerificationView) +# .Permission('patients.can_verify_identity') +# .Next(this.verify_insurance) +# ) +# +# verify_insurance = ( +# flow_view(InsuranceVerificationView) +# .Permission('patients.can_verify_insurance') +# .Next(this.parallel_data_collection) +# ) +# +# parallel_data_collection = ( +# flow_func(this.start_parallel_collection) +# .Next(this.collect_consents) +# .Next(this.collect_medical_history) +# .Next(this.collect_emergency_contacts) +# ) +# +# collect_consents = ( +# flow_view(ConsentCollectionView) +# .Permission('patients.can_collect_consents') +# .Next(this.join_data_collection) +# ) +# +# collect_medical_history = ( +# flow_view(MedicalHistoryView) +# .Permission('patients.can_collect_medical_history') +# .Next(this.join_data_collection) +# ) +# +# collect_emergency_contacts = ( +# flow_view(EmergencyContactView) +# .Permission('patients.can_collect_emergency_contacts') +# .Next(this.join_data_collection) +# ) +# +# join_data_collection = ( +# flow_func(this.join_parallel_collection) +# .Next(this.finalize_registration) +# ) +# +# finalize_registration = ( +# flow_func(this.complete_registration) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_registration) +# +# # Flow functions +# def start_registration(self, activation): +# """Initialize the registration process""" +# process = activation.process +# +# # Log registration start +# self.log_registration_start(process.patient) +# +# # Notify registration staff +# self.notify_registration_staff(process.patient) +# +# def start_parallel_collection(self, activation): +# """Start parallel data collection tasks""" +# process = activation.process +# +# # Create parallel collection tasks +# self.create_collection_tasks(process.patient) +# +# def join_parallel_collection(self, activation): +# """Wait for all data collection to complete""" +# process = activation.process +# +# # Check if all collection is completed +# if (process.consents_collected and +# process.medical_history_collected and +# process.emergency_contacts_added): +# +# # Proceed to finalization +# self.notify_registration_ready(process.patient) +# +# def complete_registration(self, activation): +# """Finalize the registration process""" +# process = activation.process +# patient = process.patient +# +# # Update patient status +# patient.registration_status = 'COMPLETED' +# patient.save() +# +# # Generate MRN if not already assigned +# if not patient.mrn: +# patient.mrn = self.generate_mrn() +# patient.save() +# +# # Mark process as completed +# process.registration_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_registration_completion(patient) +# +# # Create patient chart +# self.create_patient_chart(patient) +# +# def end_registration(self, activation): +# """End the registration workflow""" +# process = activation.process +# +# # Generate registration summary report +# self.generate_registration_summary(process.patient) +# +# # Update registration metrics +# self.update_registration_metrics(process.patient) +# +# # Helper methods +# def log_registration_start(self, patient): +# """Log registration start""" +# # This would log the registration start +# pass +# +# def notify_registration_staff(self, patient): +# """Notify registration staff of new patient""" +# from django.contrib.auth.models import Group +# +# registration_staff = User.objects.filter( +# groups__name='Registration Staff' +# ) +# +# for staff in registration_staff: +# send_mail( +# subject=f'New Patient Registration: {patient.get_full_name()}', +# message=f'New patient registration started for {patient.get_full_name()}.', +# from_email='registration@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def create_collection_tasks(self, patient): +# """Create data collection tasks""" +# # This would create tasks in a task management system +# pass +# +# def notify_registration_ready(self, patient): +# """Notify that registration is ready for completion""" +# registration_staff = User.objects.filter( +# groups__name='Registration Staff' +# ) +# +# for staff in registration_staff: +# send_mail( +# subject=f'Registration Ready: {patient.get_full_name()}', +# message=f'Patient registration for {patient.get_full_name()} is ready for completion.', +# from_email='registration@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def generate_mrn(self): +# """Generate unique Medical Record Number""" +# from django.utils.crypto import get_random_string +# return f"MRN{timezone.now().strftime('%Y%m%d')}{get_random_string(6, '0123456789')}" +# +# def notify_registration_completion(self, patient): +# """Notify relevant parties of registration completion""" +# # Notify patient if email available +# if patient.email: +# send_mail( +# subject='Registration Complete', +# message=f'Welcome {patient.first_name}! Your registration is complete. Your MRN is: {patient.mrn}', +# from_email='registration@hospital.com', +# recipient_list=[patient.email], +# fail_silently=True +# ) +# +# def create_patient_chart(self, patient): +# """Create initial patient chart""" +# # This would create the initial patient chart +# pass +# +# def generate_registration_summary(self, patient): +# """Generate registration summary report""" +# # This would generate a comprehensive registration report +# pass +# +# def update_registration_metrics(self, patient): +# """Update registration metrics""" +# # This would update registration performance metrics +# pass +# +# +# class ConsentManagementProcess(Process): +# """ +# Viewflow process model for consent management +# """ +# consent_form = ModelField(ConsentForm, help_text='Associated consent form') +# +# # Process status tracking +# consent_presented = models.BooleanField(default=False) +# patient_reviewed = models.BooleanField(default=False) +# questions_answered = models.BooleanField(default=False) +# consent_signed = models.BooleanField(default=False) +# witness_signed = models.BooleanField(default=False) +# consent_verified = models.BooleanField(default=False) +# consent_filed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Consent Management Process' +# verbose_name_plural = 'Consent Management Processes' +# +# +# class ConsentManagementFlow(Flow): +# """ +# Consent Management Workflow +# +# This flow manages the consent collection process including presentation, +# review, signing, witnessing, and verification. +# """ +# +# process_class = ConsentManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_consent_process) +# .Next(this.present_consent) +# ) +# +# present_consent = ( +# flow_view(ConsentPresentationView) +# .Permission('patients.can_present_consents') +# .Next(this.patient_review) +# ) +# +# patient_review = ( +# flow_view(PatientConsentReviewView) +# .Permission('patients.can_review_consents') +# .Next(this.answer_questions) +# ) +# +# answer_questions = ( +# flow_view(ConsentQuestionView) +# .Permission('patients.can_answer_consent_questions') +# .Next(this.sign_consent) +# ) +# +# sign_consent = ( +# flow_view(ConsentSigningView) +# .Permission('patients.can_sign_consents') +# .Next(this.witness_consent) +# ) +# +# witness_consent = ( +# flow_view(ConsentWitnessView) +# .Permission('patients.can_witness_consents') +# .Next(this.verify_consent) +# ) +# +# verify_consent = ( +# flow_view(ConsentVerificationView) +# .Permission('patients.can_verify_consents') +# .Next(this.file_consent) +# ) +# +# file_consent = ( +# flow_func(this.complete_consent_process) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_consent_process) +# +# # Flow functions +# def start_consent_process(self, activation): +# """Initialize the consent process""" +# process = activation.process +# consent = process.consent_form +# +# # Update consent status +# consent.status = 'PENDING' +# consent.save() +# +# # Notify relevant staff +# self.notify_consent_required(consent) +# +# def complete_consent_process(self, activation): +# """Finalize the consent process""" +# process = activation.process +# consent = process.consent_form +# +# # Update consent status +# if consent.is_fully_signed: +# consent.status = 'SIGNED' +# else: +# consent.status = 'DECLINED' +# +# consent.save() +# +# # Mark process as completed +# process.consent_filed = True +# process.save() +# +# # Send completion notifications +# self.notify_consent_completion(consent) +# +# # File consent in patient record +# self.file_consent_in_record(consent) +# +# def end_consent_process(self, activation): +# """End the consent workflow""" +# process = activation.process +# +# # Generate consent summary report +# self.generate_consent_summary(process.consent_form) +# +# # Helper methods +# def notify_consent_required(self, consent): +# """Notify staff that consent is required""" +# nursing_staff = User.objects.filter( +# groups__name='Nursing Staff' +# ) +# +# for staff in nursing_staff: +# send_mail( +# subject=f'Consent Required: {consent.patient.get_full_name()}', +# message=f'Consent form "{consent.template.name}" required for {consent.patient.get_full_name()}.', +# from_email='consents@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_consent_completion(self, consent): +# """Notify relevant parties of consent completion""" +# # Notify ordering physician if applicable +# if hasattr(consent, 'ordering_physician') and consent.ordering_physician: +# if consent.ordering_physician.email: +# send_mail( +# subject=f'Consent {consent.status}: {consent.patient.get_full_name()}', +# message=f'Consent form "{consent.template.name}" has been {consent.status.lower()}.', +# from_email='consents@hospital.com', +# recipient_list=[consent.ordering_physician.email], +# fail_silently=True +# ) +# +# def file_consent_in_record(self, consent): +# """File consent in patient record""" +# # This would file the consent in the patient's medical record +# pass +# +# def generate_consent_summary(self, consent): +# """Generate consent summary report""" +# # This would generate a comprehensive consent report +# pass +# +# +# class PatientRecordManagementProcess(Process): +# """ +# Viewflow process model for patient record management +# """ +# patient_id = CharField(max_length=50, help_text='Patient identifier') +# record_action = CharField(max_length=20, help_text='Record management action') +# +# # Process status tracking +# record_requested = models.BooleanField(default=False) +# authorization_verified = models.BooleanField(default=False) +# record_prepared = models.BooleanField(default=False) +# quality_checked = models.BooleanField(default=False) +# record_delivered = models.BooleanField(default=False) +# delivery_confirmed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Patient Record Management Process' +# verbose_name_plural = 'Patient Record Management Processes' +# +# +# class PatientRecordManagementFlow(Flow): +# """ +# Patient Record Management Workflow +# +# This flow manages patient record requests including authorization, +# preparation, quality checking, and delivery. +# """ +# +# process_class = PatientRecordManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_record_management) +# .Next(this.verify_authorization) +# ) +# +# verify_authorization = ( +# flow_view(RecordAuthorizationView) +# .Permission('patients.can_verify_record_authorization') +# .Next(this.prepare_record) +# ) +# +# prepare_record = ( +# flow_view(RecordPreparationView) +# .Permission('patients.can_prepare_records') +# .Next(this.quality_check) +# ) +# +# quality_check = ( +# flow_view(RecordQualityCheckView) +# .Permission('patients.can_quality_check_records') +# .Next(this.deliver_record) +# ) +# +# deliver_record = ( +# flow_view(RecordDeliveryView) +# .Permission('patients.can_deliver_records') +# .Next(this.confirm_delivery) +# ) +# +# confirm_delivery = ( +# flow_func(this.complete_record_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_record_management) +# +# # Flow functions +# def start_record_management(self, activation): +# """Initialize the record management process""" +# process = activation.process +# +# # Log record request +# self.log_record_request(process.patient_id, process.record_action) +# +# # Notify records staff +# self.notify_records_staff(process.patient_id, process.record_action) +# +# def complete_record_management(self, activation): +# """Finalize the record management process""" +# process = activation.process +# +# # Mark delivery as confirmed +# process.delivery_confirmed = True +# process.save() +# +# # Generate delivery confirmation +# self.generate_delivery_confirmation(process.patient_id, process.record_action) +# +# def end_record_management(self, activation): +# """End the record management workflow""" +# process = activation.process +# +# # Generate record management summary +# self.generate_record_summary(process.patient_id, process.record_action) +# +# # Helper methods +# def log_record_request(self, patient_id, action): +# """Log record request""" +# # This would log the record request +# pass +# +# def notify_records_staff(self, patient_id, action): +# """Notify records staff""" +# records_staff = User.objects.filter( +# groups__name='Medical Records' +# ) +# +# for staff in records_staff: +# send_mail( +# subject=f'Record Request: {patient_id}', +# message=f'Record {action} requested for patient {patient_id}.', +# from_email='records@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def generate_delivery_confirmation(self, patient_id, action): +# """Generate delivery confirmation""" +# # This would generate delivery confirmation +# pass +# +# def generate_record_summary(self, patient_id, action): +# """Generate record management summary""" +# # This would generate record management summary +# pass +# +# +# class PatientTransferProcess(Process): +# """ +# Viewflow process model for patient transfers between facilities +# """ +# patient_id = CharField(max_length=50, help_text='Patient identifier') +# transfer_type = CharField(max_length=20, help_text='Type of transfer') +# +# # Process status tracking +# transfer_requested = models.BooleanField(default=False) +# receiving_facility_contacted = models.BooleanField(default=False) +# transfer_approved = models.BooleanField(default=False) +# records_prepared = models.BooleanField(default=False) +# transport_arranged = models.BooleanField(default=False) +# patient_transferred = models.BooleanField(default=False) +# transfer_confirmed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Patient Transfer Process' +# verbose_name_plural = 'Patient Transfer Processes' +# +# +# class PatientTransferFlow(Flow): +# """ +# Patient Transfer Workflow +# +# This flow manages patient transfers between facilities including +# coordination, approval, preparation, and execution. +# """ +# +# process_class = PatientTransferProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_transfer) +# .Next(this.contact_receiving_facility) +# ) +# +# contact_receiving_facility = ( +# flow_view(FacilityContactView) +# .Permission('patients.can_contact_facilities') +# .Next(this.approve_transfer) +# ) +# +# approve_transfer = ( +# flow_view(TransferApprovalView) +# .Permission('patients.can_approve_transfers') +# .Next(this.parallel_preparation) +# ) +# +# parallel_preparation = ( +# flow_func(this.start_parallel_preparation) +# .Next(this.prepare_records) +# .Next(this.arrange_transport) +# ) +# +# prepare_records = ( +# flow_view(TransferRecordPreparationView) +# .Permission('patients.can_prepare_transfer_records') +# .Next(this.join_preparation) +# ) +# +# arrange_transport = ( +# flow_view(TransportArrangementView) +# .Permission('patients.can_arrange_transport') +# .Next(this.join_preparation) +# ) +# +# join_preparation = ( +# flow_func(this.join_parallel_preparation) +# .Next(this.execute_transfer) +# ) +# +# execute_transfer = ( +# flow_view(TransferExecutionView) +# .Permission('patients.can_execute_transfers') +# .Next(this.confirm_transfer) +# ) +# +# confirm_transfer = ( +# flow_func(this.complete_transfer) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_transfer) +# +# # Flow functions +# def start_transfer(self, activation): +# """Initialize the transfer process""" +# process = activation.process +# +# # Log transfer request +# self.log_transfer_request(process.patient_id, process.transfer_type) +# +# # Notify transfer coordinator +# self.notify_transfer_coordinator(process.patient_id, process.transfer_type) +# +# def start_parallel_preparation(self, activation): +# """Start parallel preparation tasks""" +# process = activation.process +# +# # Create preparation tasks +# self.create_preparation_tasks(process.patient_id) +# +# def join_parallel_preparation(self, activation): +# """Wait for all preparation to complete""" +# process = activation.process +# +# # Check if all preparation is completed +# if process.records_prepared and process.transport_arranged: +# # Proceed to transfer execution +# self.notify_transfer_ready(process.patient_id) +# +# def complete_transfer(self, activation): +# """Finalize the transfer process""" +# process = activation.process +# +# # Mark transfer as confirmed +# process.transfer_confirmed = True +# process.save() +# +# # Send confirmation notifications +# self.notify_transfer_completion(process.patient_id) +# +# def end_transfer(self, activation): +# """End the transfer workflow""" +# process = activation.process +# +# # Generate transfer summary report +# self.generate_transfer_summary(process.patient_id, process.transfer_type) +# +# # Helper methods +# def log_transfer_request(self, patient_id, transfer_type): +# """Log transfer request""" +# # This would log the transfer request +# pass +# +# def notify_transfer_coordinator(self, patient_id, transfer_type): +# """Notify transfer coordinator""" +# coordinators = User.objects.filter( +# groups__name='Transfer Coordinators' +# ) +# +# for coordinator in coordinators: +# send_mail( +# subject=f'Patient Transfer Request: {patient_id}', +# message=f'{transfer_type} transfer requested for patient {patient_id}.', +# from_email='transfers@hospital.com', +# recipient_list=[coordinator.email], +# fail_silently=True +# ) +# +# def create_preparation_tasks(self, patient_id): +# """Create preparation tasks""" +# # This would create preparation tasks +# pass +# +# def notify_transfer_ready(self, patient_id): +# """Notify that transfer is ready""" +# # This would notify that transfer is ready +# pass +# +# def notify_transfer_completion(self, patient_id): +# """Notify transfer completion""" +# # This would notify transfer completion +# pass +# +# def generate_transfer_summary(self, patient_id, transfer_type): +# """Generate transfer summary""" +# # This would generate transfer summary +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_verify_insurance(patient_id): +# """Background task to automatically verify insurance""" +# try: +# # This would perform automated insurance verification +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_consent_expiry(): +# """Background task to monitor consent expiry""" +# try: +# # This would monitor expiring consents +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_patient_reports(): +# """Background task to generate patient reports""" +# try: +# # This would generate patient reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_schedule_follow_ups(patient_id): +# """Background task to automatically schedule follow-ups""" +# try: +# # This would schedule follow-up appointments +# return True +# except Exception: +# return False +# diff --git a/patients/views.py b/patients/views.py index f6983794..7f40554b 100644 --- a/patients/views.py +++ b/patients/views.py @@ -1,6 +1,7 @@ """ Patients app views for hospital management system with comprehensive CRUD operations. """ +import uuid from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required @@ -17,6 +18,7 @@ from django.core.paginator import Paginator from datetime import timedelta, date from appointments.models import AppointmentRequest +from core.models import AuditLogEntry from .models import ( PatientProfile, EmergencyContact, InsuranceInfo, ConsentTemplate, ConsentForm, PatientNote @@ -2288,7 +2290,7 @@ class ConsentManagementView(LoginRequiredMixin, PermissionRequiredMixin, Templat # Get expired/expiring consents today = timezone.now().date() - expiry_threshold = today + timezone.timedelta(days=30) + expiry_threshold = today + timedelta(days=30) expiring_consents = ConsentForm.objects.filter( patient__tenant=self.request.user.tenant, @@ -2359,14 +2361,10 @@ class ConsentManagementView(LoginRequiredMixin, PermissionRequiredMixin, Templat return redirect('patients:consent_management') # Process template form - template_form = ConsentTemplateForm( - request.POST, - user=request.user, - tenant=request.user.tenant - ) + template_form = ConsentTemplateForm - if template_form.is_valid(): - template = template_form.save() + if template_form.is_valid: + template = template_form.save messages.success( request, f"Consent template '{template.name}' created successfully." @@ -2718,7 +2716,14 @@ class ConsentManagementView(LoginRequiredMixin, PermissionRequiredMixin, Templat # 'patient': patient # }) # -# + +@login_required +def insurance_details_api(request, insurance_id): + insurance_info = get_object_or_404(InsuranceInfo, pk=insurance_id) + return JsonResponse({'insurance_info': insurance_info}) + + + # @login_required # def insurance_info_list(request, patient_id): # """ diff --git a/pharmacy/__pycache__/flows.cpython-312.pyc b/pharmacy/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..c1131893 Binary files /dev/null and b/pharmacy/__pycache__/flows.cpython-312.pyc differ diff --git a/pharmacy/flows.py b/pharmacy/flows.py new file mode 100644 index 00000000..a315a720 --- /dev/null +++ b/pharmacy/flows.py @@ -0,0 +1,672 @@ +# """ +# Viewflow workflows for pharmacy app. +# Provides prescription processing, dispensing, and medication administration workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import Prescription, DispenseRecord, MedicationAdministration, DrugInteraction +# from .views import ( +# PrescriptionReviewView, DrugInteractionCheckView, InventoryCheckView, +# MedicationPreparationView, PharmacistVerificationView, DispenseView, +# PatientCounselingView, MedicationAdministrationView +# ) +# +# +# class PrescriptionProcess(Process): +# """ +# Viewflow process model for prescription processing +# """ +# prescription = ModelField(Prescription, help_text='Associated prescription') +# +# # Process status tracking +# prescription_received = models.BooleanField(default=False) +# clinical_review_completed = models.BooleanField(default=False) +# drug_interactions_checked = models.BooleanField(default=False) +# inventory_verified = models.BooleanField(default=False) +# medication_prepared = models.BooleanField(default=False) +# pharmacist_verified = models.BooleanField(default=False) +# patient_counseled = models.BooleanField(default=False) +# dispensed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Prescription Process' +# verbose_name_plural = 'Prescription Processes' +# +# +# class PrescriptionFlow(Flow): +# """ +# Pharmacy Prescription Processing Workflow +# +# This flow manages the complete prescription processing from +# receipt through dispensing and patient counseling. +# """ +# +# process_class = PrescriptionProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_prescription) +# .Next(this.clinical_review) +# ) +# +# clinical_review = ( +# flow_view(PrescriptionReviewView) +# .Permission('pharmacy.can_review_prescriptions') +# .Next(this.check_drug_interactions) +# ) +# +# check_drug_interactions = ( +# flow_view(DrugInteractionCheckView) +# .Permission('pharmacy.can_check_interactions') +# .Next(this.verify_inventory) +# ) +# +# verify_inventory = ( +# flow_view(InventoryCheckView) +# .Permission('pharmacy.can_check_inventory') +# .Next(this.prepare_medication) +# ) +# +# prepare_medication = ( +# flow_view(MedicationPreparationView) +# .Permission('pharmacy.can_prepare_medications') +# .Next(this.pharmacist_verification) +# ) +# +# pharmacist_verification = ( +# flow_view(PharmacistVerificationView) +# .Permission('pharmacy.can_verify_prescriptions') +# .Next(this.dispense_medication) +# ) +# +# dispense_medication = ( +# flow_view(DispenseView) +# .Permission('pharmacy.can_dispense_medications') +# .Next(this.patient_counseling) +# ) +# +# patient_counseling = ( +# flow_view(PatientCounselingView) +# .Permission('pharmacy.can_counsel_patients') +# .Next(this.finalize_prescription) +# ) +# +# finalize_prescription = ( +# flow_func(this.complete_prescription) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_prescription) +# +# # Flow functions +# def start_prescription(self, activation): +# """Initialize the prescription process""" +# process = activation.process +# prescription = process.prescription +# +# # Update prescription status +# prescription.status = 'RECEIVED' +# prescription.save() +# +# # Send notification to pharmacy staff +# self.notify_pharmacy_staff(prescription) +# +# # Check for priority prescriptions +# if prescription.priority in ['STAT', 'URGENT']: +# self.notify_priority_prescription(prescription) +# +# def complete_prescription(self, activation): +# """Finalize the prescription process""" +# process = activation.process +# prescription = process.prescription +# +# # Update prescription status +# prescription.status = 'COMPLETED' +# prescription.save() +# +# # Mark process as completed +# process.dispensed = True +# process.save() +# +# # Send completion notifications +# self.notify_prescription_completion(prescription) +# +# # Schedule follow-up if needed +# self.schedule_follow_up(prescription) +# +# def end_prescription(self, activation): +# """End the prescription workflow""" +# process = activation.process +# +# # Generate prescription summary report +# self.generate_prescription_summary(process.prescription) +# +# # Helper methods +# def notify_pharmacy_staff(self, prescription): +# """Notify pharmacy staff of new prescription""" +# from django.contrib.auth.models import Group +# +# pharmacy_staff = User.objects.filter( +# groups__name='Pharmacy Staff' +# ) +# +# for staff in pharmacy_staff: +# send_mail( +# subject=f'New Prescription: {prescription.prescription_number}', +# message=f'New {prescription.get_priority_display()} prescription for {prescription.patient.get_full_name()}.', +# from_email='pharmacy@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_priority_prescription(self, prescription): +# """Notify of high priority prescription""" +# pharmacists = User.objects.filter( +# groups__name='Pharmacists' +# ) +# +# for pharmacist in pharmacists: +# send_mail( +# subject=f'PRIORITY Prescription: {prescription.prescription_number}', +# message=f'{prescription.get_priority_display()} prescription requires immediate attention.', +# from_email='pharmacy@hospital.com', +# recipient_list=[pharmacist.email], +# fail_silently=True +# ) +# +# def notify_prescription_completion(self, prescription): +# """Notify prescribing physician of completion""" +# if prescription.prescribing_physician and prescription.prescribing_physician.email: +# send_mail( +# subject=f'Prescription Dispensed: {prescription.prescription_number}', +# message=f'Prescription has been dispensed for {prescription.patient.get_full_name()}.', +# from_email='pharmacy@hospital.com', +# recipient_list=[prescription.prescribing_physician.email], +# fail_silently=True +# ) +# +# def schedule_follow_up(self, prescription): +# """Schedule follow-up for certain medications""" +# # This would schedule follow-up based on medication type +# pass +# +# def generate_prescription_summary(self, prescription): +# """Generate prescription summary report""" +# # This would generate a comprehensive prescription report +# pass +# +# +# class MedicationAdministrationProcess(Process): +# """ +# Viewflow process model for medication administration +# """ +# administration = ModelField(MedicationAdministration, help_text='Associated administration record') +# +# # Process status tracking +# medication_prepared = models.BooleanField(default=False) +# patient_identified = models.BooleanField(default=False) +# medication_verified = models.BooleanField(default=False) +# administration_completed = models.BooleanField(default=False) +# response_documented = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Medication Administration Process' +# verbose_name_plural = 'Medication Administration Processes' +# +# +# class MedicationAdministrationFlow(Flow): +# """ +# Medication Administration Workflow +# +# This flow manages the medication administration process for inpatients +# following the "5 Rights" of medication administration. +# """ +# +# process_class = MedicationAdministrationProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_administration) +# .Next(this.prepare_medication) +# ) +# +# prepare_medication = ( +# flow_view(MedicationPreparationView) +# .Permission('pharmacy.can_prepare_medications') +# .Next(this.verify_patient) +# ) +# +# verify_patient = ( +# flow_view(PatientIdentificationView) +# .Permission('pharmacy.can_administer_medications') +# .Next(this.verify_medication) +# ) +# +# verify_medication = ( +# flow_view(MedicationVerificationView) +# .Permission('pharmacy.can_administer_medications') +# .Next(this.administer_medication) +# ) +# +# administer_medication = ( +# flow_view(MedicationAdministrationView) +# .Permission('pharmacy.can_administer_medications') +# .Next(this.document_response) +# ) +# +# document_response = ( +# flow_view(AdministrationDocumentationView) +# .Permission('pharmacy.can_administer_medications') +# .Next(this.finalize_administration) +# ) +# +# finalize_administration = ( +# flow_func(this.complete_administration) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_administration) +# +# # Flow functions +# def start_administration(self, activation): +# """Initialize the administration process""" +# process = activation.process +# administration = process.administration +# +# # Update administration status +# administration.status = 'SCHEDULED' +# administration.save() +# +# # Check for overdue medications +# if administration.is_overdue: +# self.notify_overdue_medication(administration) +# +# def complete_administration(self, activation): +# """Finalize the administration process""" +# process = activation.process +# administration = process.administration +# +# # Update administration status +# administration.status = 'GIVEN' +# administration.actual_datetime = timezone.now() +# administration.save() +# +# # Mark process as completed +# process.administration_completed = True +# process.response_documented = True +# process.save() +# +# # Check for adverse reactions +# self.check_adverse_reactions(administration) +# +# def end_administration(self, activation): +# """End the administration workflow""" +# process = activation.process +# +# # Update medication administration record +# self.update_mar(process.administration) +# +# # Helper methods +# def notify_overdue_medication(self, administration): +# """Notify nursing staff of overdue medication""" +# nursing_staff = User.objects.filter( +# groups__name='Nursing Staff', +# profile__department=administration.patient.current_ward +# ) +# +# for nurse in nursing_staff: +# send_mail( +# subject=f'Overdue Medication: {administration.patient.get_full_name()}', +# message=f'Medication administration is overdue for {administration.prescription.medication.display_name}.', +# from_email='pharmacy@hospital.com', +# recipient_list=[nurse.email], +# fail_silently=True +# ) +# +# def check_adverse_reactions(self, administration): +# """Check for potential adverse reactions""" +# # This would implement adverse reaction monitoring +# pass +# +# def update_mar(self, administration): +# """Update Medication Administration Record""" +# # This would update the MAR system +# pass +# +# +# class DrugInteractionProcess(Process): +# """ +# Viewflow process model for drug interaction checking +# """ +# patient_id = CharField(max_length=50, help_text='Patient identifier') +# interaction_severity = CharField(max_length=20, help_text='Interaction severity level') +# +# # Process status tracking +# interactions_identified = models.BooleanField(default=False) +# clinical_review_completed = models.BooleanField(default=False) +# physician_notified = models.BooleanField(default=False) +# resolution_documented = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Drug Interaction Process' +# verbose_name_plural = 'Drug Interaction Processes' +# +# +# class DrugInteractionFlow(Flow): +# """ +# Drug Interaction Checking Workflow +# +# This flow manages drug interaction checking and clinical decision support. +# """ +# +# process_class = DrugInteractionProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_interaction_check) +# .Next(this.identify_interactions) +# ) +# +# identify_interactions = ( +# flow_func(this.check_drug_interactions) +# .Next(this.clinical_review) +# ) +# +# clinical_review = ( +# flow_view(InteractionReviewView) +# .Permission('pharmacy.can_review_interactions') +# .Next(this.notify_physician) +# ) +# +# notify_physician = ( +# flow_func(this.send_physician_notification) +# .Next(this.document_resolution) +# ) +# +# document_resolution = ( +# flow_view(InteractionResolutionView) +# .Permission('pharmacy.can_resolve_interactions') +# .Next(this.finalize_interaction_check) +# ) +# +# finalize_interaction_check = ( +# flow_func(this.complete_interaction_check) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_interaction_check) +# +# # Flow functions +# def start_interaction_check(self, activation): +# """Initialize the interaction checking process""" +# process = activation.process +# +# # Log interaction check initiation +# self.log_interaction_check(process.patient_id) +# +# def check_drug_interactions(self, activation): +# """Check for drug interactions""" +# process = activation.process +# +# # Perform interaction checking logic +# interactions = self.perform_interaction_check(process.patient_id) +# +# if interactions: +# process.interactions_identified = True +# process.interaction_severity = self.determine_severity(interactions) +# process.save() +# +# # Alert if severe interactions found +# if process.interaction_severity in ['MAJOR', 'CONTRAINDICATED']: +# self.alert_severe_interaction(process.patient_id, interactions) +# +# def send_physician_notification(self, activation): +# """Send notification to prescribing physician""" +# process = activation.process +# +# # Notify physician of interactions +# self.notify_prescribing_physician(process.patient_id, process.interaction_severity) +# +# process.physician_notified = True +# process.save() +# +# def complete_interaction_check(self, activation): +# """Finalize the interaction checking process""" +# process = activation.process +# +# # Mark process as completed +# process.resolution_documented = True +# process.save() +# +# def end_interaction_check(self, activation): +# """End the interaction checking workflow""" +# process = activation.process +# +# # Generate interaction report +# self.generate_interaction_report(process.patient_id) +# +# # Helper methods +# def log_interaction_check(self, patient_id): +# """Log interaction check initiation""" +# # This would log the interaction check +# pass +# +# def perform_interaction_check(self, patient_id): +# """Perform drug interaction checking""" +# # This would implement interaction checking logic +# return [] +# +# def determine_severity(self, interactions): +# """Determine overall severity of interactions""" +# # This would determine the highest severity level +# return 'MINOR' +# +# def alert_severe_interaction(self, patient_id, interactions): +# """Alert staff of severe interactions""" +# # This would send immediate alerts +# pass +# +# def notify_prescribing_physician(self, patient_id, severity): +# """Notify prescribing physician""" +# # This would send notification to physician +# pass +# +# def generate_interaction_report(self, patient_id): +# """Generate interaction checking report""" +# # This would generate a comprehensive interaction report +# pass +# +# +# class InventoryManagementProcess(Process): +# """ +# Viewflow process model for pharmacy inventory management +# """ +# medication_id = CharField(max_length=50, help_text='Medication identifier') +# action_type = CharField(max_length=20, help_text='Inventory action type') +# +# # Process status tracking +# stock_checked = models.BooleanField(default=False) +# order_placed = models.BooleanField(default=False) +# shipment_received = models.BooleanField(default=False) +# inventory_updated = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Inventory Management Process' +# verbose_name_plural = 'Inventory Management Processes' +# +# +# class InventoryManagementFlow(Flow): +# """ +# Pharmacy Inventory Management Workflow +# +# This flow manages pharmacy inventory including ordering, receiving, and stock management. +# """ +# +# process_class = InventoryManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_inventory_management) +# .Next(this.check_stock_levels) +# ) +# +# check_stock_levels = ( +# flow_func(this.monitor_stock_levels) +# .Next(this.place_order) +# ) +# +# place_order = ( +# flow_view(InventoryOrderView) +# .Permission('pharmacy.can_manage_inventory') +# .Next(this.receive_shipment) +# ) +# +# receive_shipment = ( +# flow_view(ShipmentReceiptView) +# .Permission('pharmacy.can_receive_inventory') +# .Next(this.update_inventory) +# ) +# +# update_inventory = ( +# flow_func(this.update_stock_levels) +# .Next(this.finalize_inventory) +# ) +# +# finalize_inventory = ( +# flow_func(this.complete_inventory_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_inventory_management) +# +# # Flow functions +# def start_inventory_management(self, activation): +# """Initialize the inventory management process""" +# process = activation.process +# +# # Log inventory management initiation +# self.log_inventory_action(process.medication_id, process.action_type) +# +# def monitor_stock_levels(self, activation): +# """Monitor stock levels and identify low stock""" +# process = activation.process +# +# # Check stock levels +# low_stock_items = self.check_low_stock(process.medication_id) +# +# if low_stock_items: +# process.stock_checked = True +# process.save() +# +# # Alert pharmacy staff of low stock +# self.alert_low_stock(low_stock_items) +# +# def update_stock_levels(self, activation): +# """Update inventory stock levels""" +# process = activation.process +# +# # Update stock levels in system +# self.update_medication_stock(process.medication_id) +# +# process.inventory_updated = True +# process.save() +# +# def complete_inventory_management(self, activation): +# """Finalize the inventory management process""" +# process = activation.process +# +# # Generate inventory report +# self.generate_inventory_report(process.medication_id) +# +# def end_inventory_management(self, activation): +# """End the inventory management workflow""" +# process = activation.process +# +# # Archive inventory transaction +# self.archive_inventory_transaction(process.medication_id) +# +# # Helper methods +# def log_inventory_action(self, medication_id, action_type): +# """Log inventory action""" +# # This would log the inventory action +# pass +# +# def check_low_stock(self, medication_id): +# """Check for low stock items""" +# # This would check stock levels +# return [] +# +# def alert_low_stock(self, low_stock_items): +# """Alert staff of low stock""" +# # This would send low stock alerts +# pass +# +# def update_medication_stock(self, medication_id): +# """Update medication stock levels""" +# # This would update stock levels +# pass +# +# def generate_inventory_report(self, medication_id): +# """Generate inventory report""" +# # This would generate inventory report +# pass +# +# def archive_inventory_transaction(self, medication_id): +# """Archive inventory transaction""" +# # This would archive the transaction +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_check_drug_interactions(patient_id): +# """Background task to automatically check drug interactions""" +# try: +# # This would perform automated interaction checking +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_medication_adherence(patient_id): +# """Background task to monitor medication adherence""" +# try: +# # This would monitor patient adherence +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_pharmacy_reports(): +# """Background task to generate daily pharmacy reports""" +# try: +# # This would generate daily pharmacy reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_reorder_medications(): +# """Background task to automatically reorder low stock medications""" +# try: +# # This would automatically reorder medications +# return True +# except Exception: +# return False +# diff --git a/pyproject.toml b/pyproject.toml index 36ef7027..04669975 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,45 +4,61 @@ version = "0.1.0" description = "Add your description here" requires-python = ">=3.12" dependencies = [ + "base>=0.0.0", "black>=25.1.0", - "boto3>=1.40.1", + "boto3==1.40.25", + "botocore==1.40.25", "celery>=5.5.3", - "coverage>=7.10.2", + "charset-normalizer==3.4.3", + "coverage==7.10.6", "crispy-bootstrap5>=2025.6", - "django>=5.2.4", - "django-allauth>=65.10.0", - "django-anymail>=13.0.1", + "cron-descriptor==2.0.6", + "decorators>=2.0.7", + "django==5.2.6", + "django-allauth==65.11.1", + "django-anymail==13.1", "django-celery-beat>=2.8.1", "django-cors-headers>=4.7.0", "django-crispy-forms>=2.4", "django-debug-toolbar>=6.0.0", "django-extensions>=4.1", "django-filter>=25.1", - "django-guardian>=3.0.3", + "django-guardian==3.1.0", "django-health-check>=3.20.0", "django-otp>=1.6.1", "django-redis>=6.0.0", "django-storages>=1.14.6", - "djangorestframework>=3.16.0", + "django-viewflow>=2.2.12", + "djangorestframework==3.16.1", "drf-spectacular>=0.28.0", "factory-boy>=3.3.3", + "faker==37.6.0", + "filelock==3.19.1", "flake8>=7.3.0", "gunicorn>=23.0.0", + "identify==2.6.14", + "jsonschema==4.25.1", "mysqlclient>=2.2.7", "openpyxl>=3.1.5", - "pandas>=2.3.1", + "pandas==2.3.2", "pillow>=11.3.0", - "pre-commit>=4.2.0", + "platformdirs==4.4.0", + "pre-commit==4.3.0", + "prompt-toolkit==3.0.52", "psutil>=7.0.0", "psycopg2-binary>=2.9.10", + "pytest==8.4.2", "pytest-django>=4.11.1", "python-dateutil>=2.9.0.post0", "python-decouple>=3.8", "pytz>=2025.2", - "redis>=6.2.0", + "redis==6.4.0", "reportlab>=4.4.3", - "requests>=2.32.4", - "sentry-sdk>=2.34.1", + "requests==2.32.5", + "rpds-py==0.27.1", + "sentry-sdk==2.37.0", + "typing-extensions==4.15.0", "urllib3>=2.5.0", + "virtualenv==20.34.0", "whitenoise>=6.9.0", ] diff --git a/quality/__pycache__/flows.cpython-312.pyc b/quality/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..65ccec61 Binary files /dev/null and b/quality/__pycache__/flows.cpython-312.pyc differ diff --git a/quality/__pycache__/forms.cpython-312.pyc b/quality/__pycache__/forms.cpython-312.pyc index 71c284bb..9c3df46b 100644 Binary files a/quality/__pycache__/forms.cpython-312.pyc and b/quality/__pycache__/forms.cpython-312.pyc differ diff --git a/quality/__pycache__/views.cpython-312.pyc b/quality/__pycache__/views.cpython-312.pyc index abc6d08b..f0a8f47f 100644 Binary files a/quality/__pycache__/views.cpython-312.pyc and b/quality/__pycache__/views.cpython-312.pyc differ diff --git a/quality/flows.py b/quality/flows.py new file mode 100644 index 00000000..501e6a13 --- /dev/null +++ b/quality/flows.py @@ -0,0 +1,983 @@ +# """ +# Viewflow workflows for quality app. +# Provides quality assurance, incident management, and improvement workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import ( +# QualityIndicator, QualityMeasurement, IncidentReport, RiskAssessment, +# AuditPlan, AuditFinding, ImprovementProject +# ) +# from .views import ( +# IncidentReportingView, IncidentInvestigationView, RootCauseAnalysisView, +# CorrectiveActionView, IncidentClosureView, QualityMeasurementView, +# IndicatorAnalysisView, AuditPlanningView, AuditExecutionView, +# FindingManagementView, ImprovementProjectView, RiskAssessmentView +# ) +# +# +# class IncidentManagementProcess(Process): +# """ +# Viewflow process model for incident management +# """ +# incident_report = ModelField(IncidentReport, help_text='Associated incident report') +# +# # Process status tracking +# incident_reported = models.BooleanField(default=False) +# initial_assessment_completed = models.BooleanField(default=False) +# investigation_assigned = models.BooleanField(default=False) +# investigation_completed = models.BooleanField(default=False) +# root_cause_identified = models.BooleanField(default=False) +# corrective_actions_planned = models.BooleanField(default=False) +# actions_implemented = models.BooleanField(default=False) +# effectiveness_verified = models.BooleanField(default=False) +# incident_closed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Incident Management Process' +# verbose_name_plural = 'Incident Management Processes' +# +# +# class IncidentManagementFlow(Flow): +# """ +# Incident Management Workflow +# +# This flow manages patient safety incidents from reporting through +# investigation, corrective action, and closure. +# """ +# +# process_class = IncidentManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_incident_management) +# .Next(this.report_incident) +# ) +# +# report_incident = ( +# flow_view(IncidentReportingView) +# .Permission('quality.can_report_incidents') +# .Next(this.assess_incident) +# ) +# +# assess_incident = ( +# flow_func(this.perform_initial_assessment) +# .Next(this.assign_investigation) +# ) +# +# assign_investigation = ( +# flow_view(InvestigationAssignmentView) +# .Permission('quality.can_assign_investigations') +# .Next(this.investigate_incident) +# ) +# +# investigate_incident = ( +# flow_view(IncidentInvestigationView) +# .Permission('quality.can_investigate_incidents') +# .Next(this.analyze_root_cause) +# ) +# +# analyze_root_cause = ( +# flow_view(RootCauseAnalysisView) +# .Permission('quality.can_analyze_root_causes') +# .Next(this.plan_corrective_actions) +# ) +# +# plan_corrective_actions = ( +# flow_view(CorrectiveActionView) +# .Permission('quality.can_plan_corrective_actions') +# .Next(this.implement_actions) +# ) +# +# implement_actions = ( +# flow_view(ActionImplementationView) +# .Permission('quality.can_implement_actions') +# .Next(this.verify_effectiveness) +# ) +# +# verify_effectiveness = ( +# flow_view(EffectivenessVerificationView) +# .Permission('quality.can_verify_effectiveness') +# .Next(this.close_incident) +# ) +# +# close_incident = ( +# flow_func(this.complete_incident_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_incident_management) +# +# # Flow functions +# def start_incident_management(self, activation): +# """Initialize the incident management process""" +# process = activation.process +# incident = process.incident_report +# +# # Update incident status +# incident.status = 'reported' +# incident.save() +# +# # Send immediate notifications +# self.notify_incident_reported(incident) +# +# # Check for high-severity incidents +# if incident.severity in ['severe_harm', 'death']: +# self.notify_critical_incident(incident) +# self.notify_regulatory_bodies(incident) +# +# def perform_initial_assessment(self, activation): +# """Perform initial incident assessment""" +# process = activation.process +# incident = process.incident_report +# +# # Update incident status +# incident.status = 'under_investigation' +# incident.save() +# +# # Mark assessment completed +# process.initial_assessment_completed = True +# process.save() +# +# # Determine investigation priority +# self.determine_investigation_priority(incident) +# +# # Send assessment notifications +# self.notify_assessment_completed(incident) +# +# def complete_incident_management(self, activation): +# """Finalize the incident management process""" +# process = activation.process +# incident = process.incident_report +# +# # Update incident status +# incident.status = 'closed' +# incident.closed_date = timezone.now() +# incident.save() +# +# # Mark process as completed +# process.incident_closed = True +# process.save() +# +# # Send completion notifications +# self.notify_incident_closure(incident) +# +# # Update quality metrics +# self.update_incident_metrics(incident) +# +# # Generate lessons learned +# self.generate_lessons_learned(incident) +# +# def end_incident_management(self, activation): +# """End the incident management workflow""" +# process = activation.process +# +# # Generate incident summary report +# self.generate_incident_summary(process.incident_report) +# +# # Helper methods +# def notify_incident_reported(self, incident): +# """Notify quality staff of incident report""" +# from django.contrib.auth.models import Group +# +# quality_staff = User.objects.filter( +# groups__name='Quality Staff' +# ) +# +# for staff in quality_staff: +# send_mail( +# subject=f'Incident Reported: {incident.incident_number}', +# message=f'New {incident.get_severity_display()} incident reported: {incident.title}', +# from_email='quality@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_critical_incident(self, incident): +# """Notify of critical incident""" +# quality_managers = User.objects.filter( +# groups__name='Quality Managers' +# ) +# +# for manager in quality_managers: +# send_mail( +# subject=f'CRITICAL INCIDENT: {incident.incident_number}', +# message=f'Critical incident requiring immediate attention: {incident.title}', +# from_email='quality@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def notify_regulatory_bodies(self, incident): +# """Notify regulatory bodies if required""" +# if incident.regulatory_notification: +# # This would implement regulatory notification logic +# pass +# +# def determine_investigation_priority(self, incident): +# """Determine investigation priority based on severity""" +# severity_priority_map = { +# 'death': 'urgent', +# 'severe_harm': 'high', +# 'moderate_harm': 'medium', +# 'minor_harm': 'low', +# 'no_harm': 'low' +# } +# +# incident.priority = severity_priority_map.get(incident.severity, 'medium') +# incident.save() +# +# def notify_assessment_completed(self, incident): +# """Notify assessment completion""" +# if incident.assigned_to and incident.assigned_to.email: +# send_mail( +# subject=f'Investigation Assignment: {incident.incident_number}', +# message=f'You have been assigned to investigate incident: {incident.title}', +# from_email='quality@hospital.com', +# recipient_list=[incident.assigned_to.email], +# fail_silently=True +# ) +# +# def notify_incident_closure(self, incident): +# """Notify incident closure""" +# # Notify reporter +# if incident.reported_by and incident.reported_by.email: +# send_mail( +# subject=f'Incident Closed: {incident.incident_number}', +# message=f'The incident you reported has been investigated and closed.', +# from_email='quality@hospital.com', +# recipient_list=[incident.reported_by.email], +# fail_silently=True +# ) +# +# def update_incident_metrics(self, incident): +# """Update incident quality metrics""" +# # This would update incident reporting metrics +# pass +# +# def generate_lessons_learned(self, incident): +# """Generate lessons learned from incident""" +# # This would create lessons learned documentation +# pass +# +# def generate_incident_summary(self, incident): +# """Generate incident summary report""" +# # This would generate comprehensive incident report +# pass +# +# +# class QualityMonitoringProcess(Process): +# """ +# Viewflow process model for quality monitoring +# """ +# quality_indicator = ModelField(QualityIndicator, help_text='Associated quality indicator') +# +# # Process status tracking +# data_collected = models.BooleanField(default=False) +# measurement_calculated = models.BooleanField(default=False) +# analysis_completed = models.BooleanField(default=False) +# trends_identified = models.BooleanField(default=False) +# actions_recommended = models.BooleanField(default=False) +# report_generated = models.BooleanField(default=False) +# monitoring_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Quality Monitoring Process' +# verbose_name_plural = 'Quality Monitoring Processes' +# +# +# class QualityMonitoringFlow(Flow): +# """ +# Quality Monitoring Workflow +# +# This flow manages quality indicator monitoring including data +# collection, analysis, and reporting. +# """ +# +# process_class = QualityMonitoringProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_quality_monitoring) +# .Next(this.collect_data) +# ) +# +# collect_data = ( +# flow_view(DataCollectionView) +# .Permission('quality.can_collect_data') +# .Next(this.calculate_measurement) +# ) +# +# calculate_measurement = ( +# flow_view(QualityMeasurementView) +# .Permission('quality.can_calculate_measurements') +# .Next(this.analyze_results) +# ) +# +# analyze_results = ( +# flow_view(IndicatorAnalysisView) +# .Permission('quality.can_analyze_indicators') +# .Next(this.identify_trends) +# ) +# +# identify_trends = ( +# flow_func(this.perform_trend_analysis) +# .Next(this.recommend_actions) +# ) +# +# recommend_actions = ( +# flow_view(ActionRecommendationView) +# .Permission('quality.can_recommend_actions') +# .Next(this.generate_report) +# ) +# +# generate_report = ( +# flow_view(QualityReportView) +# .Permission('quality.can_generate_reports') +# .Next(this.complete_monitoring) +# ) +# +# complete_monitoring = ( +# flow_func(this.finalize_quality_monitoring) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_quality_monitoring) +# +# # Flow functions +# def start_quality_monitoring(self, activation): +# """Initialize the quality monitoring process""" +# process = activation.process +# indicator = process.quality_indicator +# +# # Send notification to responsible staff +# self.notify_monitoring_due(indicator) +# +# def perform_trend_analysis(self, activation): +# """Perform trend analysis on quality data""" +# process = activation.process +# indicator = process.quality_indicator +# +# # Analyze trends in measurements +# trends = self.analyze_indicator_trends(indicator) +# +# if trends: +# process.trends_identified = True +# process.save() +# +# # Alert if concerning trends identified +# if self.is_concerning_trend(trends): +# self.alert_quality_managers(indicator, trends) +# +# def finalize_quality_monitoring(self, activation): +# """Finalize the quality monitoring process""" +# process = activation.process +# indicator = process.quality_indicator +# +# # Mark monitoring as completed +# process.monitoring_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_monitoring_completion(indicator) +# +# # Schedule next monitoring cycle +# self.schedule_next_monitoring(indicator) +# +# def end_quality_monitoring(self, activation): +# """End the quality monitoring workflow""" +# process = activation.process +# +# # Generate monitoring summary +# self.generate_monitoring_summary(process.quality_indicator) +# +# # Helper methods +# def notify_monitoring_due(self, indicator): +# """Notify responsible staff of monitoring due""" +# if indicator.responsible_user and indicator.responsible_user.email: +# send_mail( +# subject=f'Quality Monitoring Due: {indicator.name}', +# message=f'Quality indicator monitoring is due for: {indicator.name}', +# from_email='quality@hospital.com', +# recipient_list=[indicator.responsible_user.email], +# fail_silently=True +# ) +# +# def analyze_indicator_trends(self, indicator): +# """Analyze trends in quality indicator""" +# # This would implement trend analysis logic +# return {} +# +# def is_concerning_trend(self, trends): +# """Check if trends are concerning""" +# # This would implement trend evaluation logic +# return False +# +# def alert_quality_managers(self, indicator, trends): +# """Alert quality managers of concerning trends""" +# quality_managers = User.objects.filter( +# groups__name='Quality Managers' +# ) +# +# for manager in quality_managers: +# send_mail( +# subject=f'Quality Alert: {indicator.name}', +# message=f'Concerning trend identified in quality indicator: {indicator.name}', +# from_email='quality@hospital.com', +# recipient_list=[manager.email], +# fail_silently=True +# ) +# +# def notify_monitoring_completion(self, indicator): +# """Notify monitoring completion""" +# # This would notify relevant parties +# pass +# +# def schedule_next_monitoring(self, indicator): +# """Schedule next monitoring cycle""" +# # This would schedule the next monitoring cycle +# pass +# +# def generate_monitoring_summary(self, indicator): +# """Generate monitoring summary""" +# # This would generate monitoring summary +# pass +# +# +# class AuditManagementProcess(Process): +# """ +# Viewflow process model for audit management +# """ +# audit_plan = ModelField(AuditPlan, help_text='Associated audit plan') +# +# # Process status tracking +# audit_planned = models.BooleanField(default=False) +# team_assigned = models.BooleanField(default=False) +# audit_conducted = models.BooleanField(default=False) +# findings_documented = models.BooleanField(default=False) +# corrective_actions_planned = models.BooleanField(default=False) +# actions_implemented = models.BooleanField(default=False) +# follow_up_completed = models.BooleanField(default=False) +# audit_closed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Audit Management Process' +# verbose_name_plural = 'Audit Management Processes' +# +# +# class AuditManagementFlow(Flow): +# """ +# Audit Management Workflow +# +# This flow manages quality audits from planning through +# execution, finding management, and closure. +# """ +# +# process_class = AuditManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_audit_management) +# .Next(this.plan_audit) +# ) +# +# plan_audit = ( +# flow_view(AuditPlanningView) +# .Permission('quality.can_plan_audits') +# .Next(this.assign_team) +# ) +# +# assign_team = ( +# flow_view(AuditTeamAssignmentView) +# .Permission('quality.can_assign_audit_teams') +# .Next(this.conduct_audit) +# ) +# +# conduct_audit = ( +# flow_view(AuditExecutionView) +# .Permission('quality.can_conduct_audits') +# .Next(this.document_findings) +# ) +# +# document_findings = ( +# flow_view(FindingManagementView) +# .Permission('quality.can_document_findings') +# .Next(this.plan_corrective_actions) +# ) +# +# plan_corrective_actions = ( +# flow_view(CorrectiveActionPlanningView) +# .Permission('quality.can_plan_corrective_actions') +# .Next(this.implement_actions) +# ) +# +# implement_actions = ( +# flow_view(ActionImplementationView) +# .Permission('quality.can_implement_actions') +# .Next(this.follow_up) +# ) +# +# follow_up = ( +# flow_view(AuditFollowUpView) +# .Permission('quality.can_follow_up_audits') +# .Next(this.close_audit) +# ) +# +# close_audit = ( +# flow_func(this.complete_audit_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_audit_management) +# +# # Flow functions +# def start_audit_management(self, activation): +# """Initialize the audit management process""" +# process = activation.process +# audit = process.audit_plan +# +# # Update audit status +# audit.status = 'planned' +# audit.save() +# +# # Send notification to audit team +# self.notify_audit_planned(audit) +# +# def complete_audit_management(self, activation): +# """Finalize the audit management process""" +# process = activation.process +# audit = process.audit_plan +# +# # Update audit status +# audit.status = 'completed' +# audit.actual_end_date = timezone.now().date() +# audit.save() +# +# # Mark process as completed +# process.audit_closed = True +# process.save() +# +# # Send completion notifications +# self.notify_audit_completion(audit) +# +# # Update audit metrics +# self.update_audit_metrics(audit) +# +# def end_audit_management(self, activation): +# """End the audit management workflow""" +# process = activation.process +# +# # Generate audit summary report +# self.generate_audit_summary(process.audit_plan) +# +# # Helper methods +# def notify_audit_planned(self, audit): +# """Notify audit team of planned audit""" +# audit_team = audit.audit_team.all() +# for member in audit_team: +# if member.email: +# send_mail( +# subject=f'Audit Planned: {audit.title}', +# message=f'You have been assigned to audit: {audit.title}', +# from_email='quality@hospital.com', +# recipient_list=[member.email], +# fail_silently=True +# ) +# +# def notify_audit_completion(self, audit): +# """Notify audit completion""" +# # Notify department being audited +# if audit.department: +# department_staff = User.objects.filter( +# department=audit.department +# ) +# for staff in department_staff: +# if staff.email: +# send_mail( +# subject=f'Audit Completed: {audit.title}', +# message=f'The audit of your department has been completed.', +# from_email='quality@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def update_audit_metrics(self, audit): +# """Update audit performance metrics""" +# # This would update audit metrics +# pass +# +# def generate_audit_summary(self, audit): +# """Generate audit summary report""" +# # This would generate comprehensive audit report +# pass +# +# +# class ImprovementProjectProcess(Process): +# """ +# Viewflow process model for improvement projects +# """ +# improvement_project = ModelField(ImprovementProject, help_text='Associated improvement project') +# +# # Process status tracking +# project_initiated = models.BooleanField(default=False) +# team_assembled = models.BooleanField(default=False) +# baseline_established = models.BooleanField(default=False) +# improvements_implemented = models.BooleanField(default=False) +# results_measured = models.BooleanField(default=False) +# sustainability_ensured = models.BooleanField(default=False) +# project_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Improvement Project Process' +# verbose_name_plural = 'Improvement Project Processes' +# +# +# class ImprovementProjectFlow(Flow): +# """ +# Improvement Project Workflow +# +# This flow manages quality improvement projects using +# structured methodologies like PDSA and Lean. +# """ +# +# process_class = ImprovementProjectProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_improvement_project) +# .Next(this.initiate_project) +# ) +# +# initiate_project = ( +# flow_view(ProjectInitiationView) +# .Permission('quality.can_initiate_projects') +# .Next(this.assemble_team) +# ) +# +# assemble_team = ( +# flow_view(TeamAssemblyView) +# .Permission('quality.can_assemble_teams') +# .Next(this.establish_baseline) +# ) +# +# establish_baseline = ( +# flow_view(BaselineEstablishmentView) +# .Permission('quality.can_establish_baseline') +# .Next(this.implement_improvements) +# ) +# +# implement_improvements = ( +# flow_view(ImprovementImplementationView) +# .Permission('quality.can_implement_improvements') +# .Next(this.measure_results) +# ) +# +# measure_results = ( +# flow_view(ResultsMeasurementView) +# .Permission('quality.can_measure_results') +# .Next(this.ensure_sustainability) +# ) +# +# ensure_sustainability = ( +# flow_view(SustainabilityView) +# .Permission('quality.can_ensure_sustainability') +# .Next(this.complete_project) +# ) +# +# complete_project = ( +# flow_func(this.finalize_improvement_project) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_improvement_project) +# +# # Flow functions +# def start_improvement_project(self, activation): +# """Initialize the improvement project process""" +# process = activation.process +# project = process.improvement_project +# +# # Update project status +# project.status = 'planned' +# project.save() +# +# # Send notification to project team +# self.notify_project_initiated(project) +# +# def finalize_improvement_project(self, activation): +# """Finalize the improvement project process""" +# process = activation.process +# project = process.improvement_project +# +# # Update project status +# project.status = 'completed' +# project.actual_end_date = timezone.now().date() +# project.save() +# +# # Mark process as completed +# process.project_completed = True +# process.save() +# +# # Send completion notifications +# self.notify_project_completion(project) +# +# # Calculate ROI +# self.calculate_project_roi(project) +# +# def end_improvement_project(self, activation): +# """End the improvement project workflow""" +# process = activation.process +# +# # Generate project summary report +# self.generate_project_summary(process.improvement_project) +# +# # Helper methods +# def notify_project_initiated(self, project): +# """Notify project team of project initiation""" +# project_team = project.project_team.all() +# for member in project_team: +# if member.email: +# send_mail( +# subject=f'Improvement Project Started: {project.title}', +# message=f'You have been assigned to improvement project: {project.title}', +# from_email='quality@hospital.com', +# recipient_list=[member.email], +# fail_silently=True +# ) +# +# def notify_project_completion(self, project): +# """Notify project completion""" +# # Notify sponsor +# if project.sponsor and project.sponsor.email: +# send_mail( +# subject=f'Project Completed: {project.title}', +# message=f'The improvement project you sponsored has been completed.', +# from_email='quality@hospital.com', +# recipient_list=[project.sponsor.email], +# fail_silently=True +# ) +# +# def calculate_project_roi(self, project): +# """Calculate project return on investment""" +# # This would implement ROI calculation logic +# pass +# +# def generate_project_summary(self, project): +# """Generate project summary report""" +# # This would generate comprehensive project report +# pass +# +# +# class RiskManagementProcess(Process): +# """ +# Viewflow process model for risk management +# """ +# risk_assessment = ModelField(RiskAssessment, help_text='Associated risk assessment') +# +# # Process status tracking +# risk_identified = models.BooleanField(default=False) +# risk_assessed = models.BooleanField(default=False) +# controls_evaluated = models.BooleanField(default=False) +# mitigation_planned = models.BooleanField(default=False) +# controls_implemented = models.BooleanField(default=False) +# effectiveness_monitored = models.BooleanField(default=False) +# risk_managed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Risk Management Process' +# verbose_name_plural = 'Risk Management Processes' +# +# +# class RiskManagementFlow(Flow): +# """ +# Risk Management Workflow +# +# This flow manages risk identification, assessment, +# mitigation, and monitoring activities. +# """ +# +# process_class = RiskManagementProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_risk_management) +# .Next(this.identify_risk) +# ) +# +# identify_risk = ( +# flow_view(RiskIdentificationView) +# .Permission('quality.can_identify_risks') +# .Next(this.assess_risk) +# ) +# +# assess_risk = ( +# flow_view(RiskAssessmentView) +# .Permission('quality.can_assess_risks') +# .Next(this.evaluate_controls) +# ) +# +# evaluate_controls = ( +# flow_view(ControlEvaluationView) +# .Permission('quality.can_evaluate_controls') +# .Next(this.plan_mitigation) +# ) +# +# plan_mitigation = ( +# flow_view(MitigationPlanningView) +# .Permission('quality.can_plan_mitigation') +# .Next(this.implement_controls) +# ) +# +# implement_controls = ( +# flow_view(ControlImplementationView) +# .Permission('quality.can_implement_controls') +# .Next(this.monitor_effectiveness) +# ) +# +# monitor_effectiveness = ( +# flow_view(EffectivenessMonitoringView) +# .Permission('quality.can_monitor_effectiveness') +# .Next(this.manage_risk) +# ) +# +# manage_risk = ( +# flow_func(this.complete_risk_management) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_risk_management) +# +# # Flow functions +# def start_risk_management(self, activation): +# """Initialize the risk management process""" +# process = activation.process +# risk = process.risk_assessment +# +# # Update risk status +# risk.status = 'active' +# risk.save() +# +# # Send notification to risk owner +# self.notify_risk_identified(risk) +# +# def complete_risk_management(self, activation): +# """Finalize the risk management process""" +# process = activation.process +# risk = process.risk_assessment +# +# # Update risk status based on residual risk level +# if risk.residual_risk_level in ['low', 'medium']: +# risk.status = 'active' +# else: +# risk.status = 'under_review' +# +# risk.save() +# +# # Mark process as completed +# process.risk_managed = True +# process.save() +# +# # Send completion notifications +# self.notify_risk_management_completion(risk) +# +# # Schedule risk review +# self.schedule_risk_review(risk) +# +# def end_risk_management(self, activation): +# """End the risk management workflow""" +# process = activation.process +# +# # Generate risk management summary +# self.generate_risk_summary(process.risk_assessment) +# +# # Helper methods +# def notify_risk_identified(self, risk): +# """Notify risk owner of identified risk""" +# if risk.responsible_person and risk.responsible_person.email: +# send_mail( +# subject=f'Risk Assignment: {risk.title}', +# message=f'You have been assigned responsibility for risk: {risk.title}', +# from_email='quality@hospital.com', +# recipient_list=[risk.responsible_person.email], +# fail_silently=True +# ) +# +# def notify_risk_management_completion(self, risk): +# """Notify risk management completion""" +# # This would notify relevant parties +# pass +# +# def schedule_risk_review(self, risk): +# """Schedule risk review""" +# # This would schedule periodic risk reviews +# pass +# +# def generate_risk_summary(self, risk): +# """Generate risk management summary""" +# # This would generate risk summary +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_generate_quality_reports(): +# """Background task to automatically generate quality reports""" +# try: +# # This would generate scheduled quality reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_quality_indicators(): +# """Background task to monitor quality indicators""" +# try: +# # This would check quality indicators for threshold breaches +# return True +# except Exception: +# return False +# +# +# @celery.job +# def schedule_audits(): +# """Background task to schedule audits""" +# try: +# # This would schedule regular audits +# return True +# except Exception: +# return False +# +# +# @celery.job +# def track_corrective_actions(): +# """Background task to track corrective action progress""" +# try: +# # This would monitor corrective action due dates +# return True +# except Exception: +# return False +# +# +# @celery.job +# def risk_monitoring(): +# """Background task to monitor risks""" +# try: +# # This would monitor risk levels and control effectiveness +# return True +# except Exception: +# return False +# diff --git a/radiology/__pycache__/flows.cpython-312.pyc b/radiology/__pycache__/flows.cpython-312.pyc new file mode 100644 index 00000000..b105d99a Binary files /dev/null and b/radiology/__pycache__/flows.cpython-312.pyc differ diff --git a/radiology/flows.py b/radiology/flows.py new file mode 100644 index 00000000..5a8936c4 --- /dev/null +++ b/radiology/flows.py @@ -0,0 +1,746 @@ +# """ +# Viewflow workflows for radiology app. +# Provides imaging order processing, study execution, and report generation workflows. +# """ +# +# from viewflow import Flow, lock +# from viewflow.base import this, flow_func +# from viewflow.contrib import celery +# from viewflow.decorators import flow_view +# from viewflow.fields import CharField, ModelField +# from viewflow.forms import ModelForm +# from viewflow.views import CreateProcessView, UpdateProcessView +# from viewflow.models import Process, Task +# from django.contrib.auth.models import User +# from django.urls import reverse_lazy +# from django.utils import timezone +# from django.db import transaction +# from django.core.mail import send_mail +# +# from .models import ImagingOrder, ImagingStudy, RadiologyReport, ReportTemplate +# from .views import ( +# ImagingOrderView, OrderVerificationView, StudySchedulingView, +# PatientPreparationView, StudyExecutionView, ImageQualityCheckView, +# ReportDictationView, ReportTranscriptionView, ReportVerificationView, +# CriticalFindingNotificationView +# ) +# +# +# class ImagingOrderProcess(Process): +# """ +# Viewflow process model for imaging orders +# """ +# imaging_order = ModelField(ImagingOrder, help_text='Associated imaging order') +# +# # Process status tracking +# order_received = models.BooleanField(default=False) +# order_verified = models.BooleanField(default=False) +# study_scheduled = models.BooleanField(default=False) +# patient_prepared = models.BooleanField(default=False) +# study_completed = models.BooleanField(default=False) +# images_reviewed = models.BooleanField(default=False) +# report_dictated = models.BooleanField(default=False) +# report_finalized = models.BooleanField(default=False) +# results_communicated = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Imaging Order Process' +# verbose_name_plural = 'Imaging Order Processes' +# +# +# class ImagingOrderFlow(Flow): +# """ +# Imaging Order Workflow +# +# This flow manages the complete imaging process from order receipt +# through study execution and report delivery. +# """ +# +# process_class = ImagingOrderProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_imaging_order) +# .Next(this.receive_order) +# ) +# +# receive_order = ( +# flow_view(ImagingOrderView) +# .Permission('radiology.can_receive_orders') +# .Next(this.verify_order) +# ) +# +# verify_order = ( +# flow_view(OrderVerificationView) +# .Permission('radiology.can_verify_orders') +# .Next(this.schedule_study) +# ) +# +# schedule_study = ( +# flow_view(StudySchedulingView) +# .Permission('radiology.can_schedule_studies') +# .Next(this.prepare_patient) +# ) +# +# prepare_patient = ( +# flow_view(PatientPreparationView) +# .Permission('radiology.can_prepare_patients') +# .Next(this.execute_study) +# ) +# +# execute_study = ( +# flow_view(StudyExecutionView) +# .Permission('radiology.can_execute_studies') +# .Next(this.review_images) +# ) +# +# review_images = ( +# flow_view(ImageQualityCheckView) +# .Permission('radiology.can_review_images') +# .Next(this.dictate_report) +# ) +# +# dictate_report = ( +# flow_view(ReportDictationView) +# .Permission('radiology.can_dictate_reports') +# .Next(this.transcribe_report) +# ) +# +# transcribe_report = ( +# flow_view(ReportTranscriptionView) +# .Permission('radiology.can_transcribe_reports') +# .Next(this.verify_report) +# ) +# +# verify_report = ( +# flow_view(ReportVerificationView) +# .Permission('radiology.can_verify_reports') +# .Next(this.check_critical_findings) +# ) +# +# check_critical_findings = ( +# flow_func(this.assess_critical_findings) +# .Next(this.finalize_report) +# ) +# +# finalize_report = ( +# flow_func(this.complete_imaging_order) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_imaging_order) +# +# # Flow functions +# def start_imaging_order(self, activation): +# """Initialize the imaging order process""" +# process = activation.process +# order = process.imaging_order +# +# # Update order status +# order.status = 'RECEIVED' +# order.save() +# +# # Send notification to radiology staff +# self.notify_radiology_staff(order) +# +# # Check for STAT orders +# if order.priority in ['STAT', 'EMERGENCY']: +# self.notify_stat_order(order) +# +# def assess_critical_findings(self, activation): +# """Check for critical findings and handle notifications""" +# process = activation.process +# order = process.imaging_order +# +# # Get the associated report +# try: +# report = RadiologyReport.objects.get(study__imaging_order=order) +# +# if report.critical_finding: +# # Handle critical finding notification +# self.handle_critical_finding(report) +# +# # Mark as critical communicated +# report.critical_communicated = True +# report.critical_communicated_datetime = timezone.now() +# report.save() +# except RadiologyReport.DoesNotExist: +# pass +# +# def complete_imaging_order(self, activation): +# """Finalize the imaging order process""" +# process = activation.process +# order = process.imaging_order +# +# # Update order status +# order.status = 'COMPLETED' +# order.completion_datetime = timezone.now() +# order.save() +# +# # Mark process as completed +# process.results_communicated = True +# process.save() +# +# # Send completion notifications +# self.notify_order_completion(order) +# +# # Update quality metrics +# self.update_quality_metrics(order) +# +# def end_imaging_order(self, activation): +# """End the imaging order workflow""" +# process = activation.process +# +# # Generate order summary report +# self.generate_order_summary(process.imaging_order) +# +# # Helper methods +# def notify_radiology_staff(self, order): +# """Notify radiology staff of new order""" +# from django.contrib.auth.models import Group +# +# radiology_staff = User.objects.filter( +# groups__name='Radiology Staff' +# ) +# +# for staff in radiology_staff: +# send_mail( +# subject=f'New Imaging Order: {order.order_number}', +# message=f'New {order.get_priority_display()} imaging order for {order.patient.get_full_name()}.', +# from_email='radiology@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def notify_stat_order(self, order): +# """Notify of STAT imaging order""" +# radiologists = User.objects.filter( +# groups__name='Radiologists' +# ) +# +# for radiologist in radiologists: +# send_mail( +# subject=f'STAT Imaging Order: {order.order_number}', +# message=f'{order.get_priority_display()} imaging order requires immediate attention.', +# from_email='radiology@hospital.com', +# recipient_list=[radiologist.email], +# fail_silently=True +# ) +# +# def handle_critical_finding(self, report): +# """Handle critical finding notification""" +# # Notify ordering physician immediately +# if report.study.referring_physician and report.study.referring_physician.email: +# send_mail( +# subject=f'CRITICAL FINDING: {report.study.accession_number}', +# message=f'Critical finding identified in imaging study. Please review immediately.', +# from_email='radiology@hospital.com', +# recipient_list=[report.study.referring_physician.email], +# fail_silently=True +# ) +# +# # Notify radiology supervisor +# supervisors = User.objects.filter( +# groups__name='Radiology Supervisors' +# ) +# +# for supervisor in supervisors: +# send_mail( +# subject=f'Critical Finding Communicated: {report.study.accession_number}', +# message=f'Critical finding has been communicated for study {report.study.accession_number}.', +# from_email='radiology@hospital.com', +# recipient_list=[supervisor.email], +# fail_silently=True +# ) +# +# def notify_order_completion(self, order): +# """Notify ordering physician of completed study""" +# if order.ordering_provider and order.ordering_provider.email: +# send_mail( +# subject=f'Imaging Results Available: {order.order_number}', +# message=f'Imaging results are now available for {order.patient.get_full_name()}.', +# from_email='radiology@hospital.com', +# recipient_list=[order.ordering_provider.email], +# fail_silently=True +# ) +# +# def update_quality_metrics(self, order): +# """Update radiology quality metrics""" +# # This would update quality and performance metrics +# pass +# +# def generate_order_summary(self, order): +# """Generate imaging order summary report""" +# # This would generate a comprehensive order report +# pass +# +# +# class RadiologyReportProcess(Process): +# """ +# Viewflow process model for radiology reports +# """ +# radiology_report = ModelField(RadiologyReport, help_text='Associated radiology report') +# +# # Process status tracking +# report_initiated = models.BooleanField(default=False) +# preliminary_read = models.BooleanField(default=False) +# report_dictated = models.BooleanField(default=False) +# report_transcribed = models.BooleanField(default=False) +# report_reviewed = models.BooleanField(default=False) +# report_signed = models.BooleanField(default=False) +# report_distributed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Radiology Report Process' +# verbose_name_plural = 'Radiology Report Processes' +# +# +# class RadiologyReportFlow(Flow): +# """ +# Radiology Report Workflow +# +# This flow manages the radiology reporting process from initial +# interpretation through final report distribution. +# """ +# +# process_class = RadiologyReportProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_report) +# .Next(this.preliminary_interpretation) +# ) +# +# preliminary_interpretation = ( +# flow_view(PreliminaryInterpretationView) +# .Permission('radiology.can_preliminary_interpret') +# .Next(this.dictate_report) +# ) +# +# dictate_report = ( +# flow_view(ReportDictationView) +# .Permission('radiology.can_dictate_reports') +# .Next(this.transcribe_report) +# ) +# +# transcribe_report = ( +# flow_view(ReportTranscriptionView) +# .Permission('radiology.can_transcribe_reports') +# .Next(this.review_report) +# ) +# +# review_report = ( +# flow_view(ReportReviewView) +# .Permission('radiology.can_review_reports') +# .Next(this.sign_report) +# ) +# +# sign_report = ( +# flow_view(ReportSigningView) +# .Permission('radiology.can_sign_reports') +# .Next(this.distribute_report) +# ) +# +# distribute_report = ( +# flow_func(this.complete_report) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_report) +# +# # Flow functions +# def start_report(self, activation): +# """Initialize the report process""" +# process = activation.process +# report = process.radiology_report +# +# # Update report status +# report.status = 'DRAFT' +# report.save() +# +# # Assign to radiologist +# self.assign_radiologist(report) +# +# def complete_report(self, activation): +# """Finalize the report process""" +# process = activation.process +# report = process.radiology_report +# +# # Update report status +# report.status = 'FINAL' +# report.finalized_datetime = timezone.now() +# report.save() +# +# # Mark process as completed +# process.report_distributed = True +# process.save() +# +# # Send distribution notifications +# self.distribute_final_report(report) +# +# def end_report(self, activation): +# """End the report workflow""" +# process = activation.process +# +# # Generate report metrics +# self.generate_report_metrics(process.radiology_report) +# +# # Helper methods +# def assign_radiologist(self, report): +# """Assign radiologist to report""" +# # This would implement radiologist assignment logic +# pass +# +# def distribute_final_report(self, report): +# """Distribute final report""" +# # Notify referring physician +# if report.study.referring_physician and report.study.referring_physician.email: +# send_mail( +# subject=f'Final Report Available: {report.study.accession_number}', +# message=f'Final radiology report is available for {report.study.patient.get_full_name()}.', +# from_email='radiology@hospital.com', +# recipient_list=[report.study.referring_physician.email], +# fail_silently=True +# ) +# +# def generate_report_metrics(self, report): +# """Generate report performance metrics""" +# # This would generate reporting metrics +# pass +# +# +# class QualityAssuranceProcess(Process): +# """ +# Viewflow process model for radiology quality assurance +# """ +# study_id = CharField(max_length=50, help_text='Study identifier') +# qa_type = CharField(max_length=20, help_text='Type of QA review') +# +# # Process status tracking +# qa_initiated = models.BooleanField(default=False) +# images_reviewed = models.BooleanField(default=False) +# report_reviewed = models.BooleanField(default=False) +# discrepancies_identified = models.BooleanField(default=False) +# feedback_provided = models.BooleanField(default=False) +# qa_completed = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Quality Assurance Process' +# verbose_name_plural = 'Quality Assurance Processes' +# +# +# class QualityAssuranceFlow(Flow): +# """ +# Radiology Quality Assurance Workflow +# +# This flow manages quality assurance reviews including +# image quality, report accuracy, and peer review. +# """ +# +# process_class = QualityAssuranceProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_qa_review) +# .Next(this.review_images) +# ) +# +# review_images = ( +# flow_view(ImageQualityReviewView) +# .Permission('radiology.can_review_image_quality') +# .Next(this.review_report) +# ) +# +# review_report = ( +# flow_view(ReportQualityReviewView) +# .Permission('radiology.can_review_report_quality') +# .Next(this.identify_discrepancies) +# ) +# +# identify_discrepancies = ( +# flow_func(this.assess_discrepancies) +# .Next(this.provide_feedback) +# ) +# +# provide_feedback = ( +# flow_view(QAFeedbackView) +# .Permission('radiology.can_provide_qa_feedback') +# .Next(this.finalize_qa) +# ) +# +# finalize_qa = ( +# flow_func(this.complete_qa_review) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_qa_review) +# +# # Flow functions +# def start_qa_review(self, activation): +# """Initialize the QA review process""" +# process = activation.process +# +# # Notify QA staff +# self.notify_qa_staff(process.study_id, process.qa_type) +# +# def assess_discrepancies(self, activation): +# """Assess for discrepancies""" +# process = activation.process +# +# # Check for discrepancies +# discrepancies = self.check_discrepancies(process.study_id) +# +# if discrepancies: +# process.discrepancies_identified = True +# process.save() +# +# # Alert QA supervisor +# self.alert_qa_supervisor(process.study_id, discrepancies) +# +# def complete_qa_review(self, activation): +# """Finalize the QA review process""" +# process = activation.process +# +# # Mark QA as completed +# process.qa_completed = True +# process.save() +# +# # Generate QA report +# self.generate_qa_report(process.study_id, process.qa_type) +# +# def end_qa_review(self, activation): +# """End the QA review workflow""" +# process = activation.process +# +# # Update QA metrics +# self.update_qa_metrics(process.study_id, process.qa_type) +# +# # Helper methods +# def notify_qa_staff(self, study_id, qa_type): +# """Notify QA staff""" +# qa_staff = User.objects.filter( +# groups__name='Radiology QA' +# ) +# +# for staff in qa_staff: +# send_mail( +# subject=f'QA Review Required: {study_id}', +# message=f'{qa_type} QA review required for study {study_id}.', +# from_email='radiology@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def check_discrepancies(self, study_id): +# """Check for discrepancies""" +# # This would implement discrepancy checking logic +# return [] +# +# def alert_qa_supervisor(self, study_id, discrepancies): +# """Alert QA supervisor of discrepancies""" +# supervisors = User.objects.filter( +# groups__name='Radiology QA Supervisors' +# ) +# +# for supervisor in supervisors: +# send_mail( +# subject=f'QA Discrepancies Found: {study_id}', +# message=f'Quality assurance discrepancies identified for study {study_id}.', +# from_email='radiology@hospital.com', +# recipient_list=[supervisor.email], +# fail_silently=True +# ) +# +# def generate_qa_report(self, study_id, qa_type): +# """Generate QA report""" +# # This would generate QA report +# pass +# +# def update_qa_metrics(self, study_id, qa_type): +# """Update QA metrics""" +# # This would update QA metrics +# pass +# +# +# class EquipmentMaintenanceProcess(Process): +# """ +# Viewflow process model for radiology equipment maintenance +# """ +# equipment_id = CharField(max_length=50, help_text='Equipment identifier') +# maintenance_type = CharField(max_length=20, help_text='Type of maintenance') +# +# # Process status tracking +# maintenance_scheduled = models.BooleanField(default=False) +# equipment_inspected = models.BooleanField(default=False) +# maintenance_performed = models.BooleanField(default=False) +# quality_testing_completed = models.BooleanField(default=False) +# equipment_calibrated = models.BooleanField(default=False) +# equipment_returned = models.BooleanField(default=False) +# +# class Meta: +# verbose_name = 'Equipment Maintenance Process' +# verbose_name_plural = 'Equipment Maintenance Processes' +# +# +# class EquipmentMaintenanceFlow(Flow): +# """ +# Radiology Equipment Maintenance Workflow +# +# This flow manages equipment maintenance including scheduling, +# inspection, repair, calibration, and quality testing. +# """ +# +# process_class = EquipmentMaintenanceProcess +# +# # Flow definition +# start = ( +# flow_func(this.start_equipment_maintenance) +# .Next(this.schedule_maintenance) +# ) +# +# schedule_maintenance = ( +# flow_view(MaintenanceSchedulingView) +# .Permission('radiology.can_schedule_maintenance') +# .Next(this.inspect_equipment) +# ) +# +# inspect_equipment = ( +# flow_view(EquipmentInspectionView) +# .Permission('radiology.can_inspect_equipment') +# .Next(this.perform_maintenance) +# ) +# +# perform_maintenance = ( +# flow_view(MaintenanceExecutionView) +# .Permission('radiology.can_perform_maintenance') +# .Next(this.quality_testing) +# ) +# +# quality_testing = ( +# flow_view(QualityTestingView) +# .Permission('radiology.can_perform_quality_testing') +# .Next(this.calibrate_equipment) +# ) +# +# calibrate_equipment = ( +# flow_view(EquipmentCalibrationView) +# .Permission('radiology.can_calibrate_equipment') +# .Next(this.return_equipment) +# ) +# +# return_equipment = ( +# flow_func(this.complete_equipment_maintenance) +# .Next(this.end) +# ) +# +# end = flow_func(this.end_equipment_maintenance) +# +# # Flow functions +# def start_equipment_maintenance(self, activation): +# """Initialize the equipment maintenance process""" +# process = activation.process +# +# # Notify maintenance staff +# self.notify_maintenance_staff(process.equipment_id, process.maintenance_type) +# +# # Take equipment offline +# self.take_equipment_offline(process.equipment_id) +# +# def complete_equipment_maintenance(self, activation): +# """Finalize the equipment maintenance process""" +# process = activation.process +# +# # Mark equipment as available +# self.return_equipment_to_service(process.equipment_id) +# +# # Mark process as completed +# process.equipment_returned = True +# process.save() +# +# # Notify completion +# self.notify_maintenance_completion(process.equipment_id) +# +# def end_equipment_maintenance(self, activation): +# """End the equipment maintenance workflow""" +# process = activation.process +# +# # Generate maintenance report +# self.generate_maintenance_report(process.equipment_id, process.maintenance_type) +# +# # Helper methods +# def notify_maintenance_staff(self, equipment_id, maintenance_type): +# """Notify maintenance staff""" +# maintenance_staff = User.objects.filter( +# groups__name='Radiology Maintenance' +# ) +# +# for staff in maintenance_staff: +# send_mail( +# subject=f'Equipment Maintenance Required: {equipment_id}', +# message=f'{maintenance_type} maintenance required for equipment {equipment_id}.', +# from_email='maintenance@hospital.com', +# recipient_list=[staff.email], +# fail_silently=True +# ) +# +# def take_equipment_offline(self, equipment_id): +# """Take equipment offline for maintenance""" +# # This would update equipment status +# pass +# +# def return_equipment_to_service(self, equipment_id): +# """Return equipment to service""" +# # This would update equipment status +# pass +# +# def notify_maintenance_completion(self, equipment_id): +# """Notify maintenance completion""" +# # This would notify relevant staff +# pass +# +# def generate_maintenance_report(self, equipment_id, maintenance_type): +# """Generate maintenance report""" +# # This would generate maintenance report +# pass +# +# +# # Celery tasks for background processing +# @celery.job +# def auto_schedule_studies(): +# """Background task to automatically schedule imaging studies""" +# try: +# # This would perform automated study scheduling +# return True +# except Exception: +# return False +# +# +# @celery.job +# def monitor_report_turnaround_times(): +# """Background task to monitor report turnaround times""" +# try: +# # This would monitor reporting performance +# return True +# except Exception: +# return False +# +# +# @celery.job +# def generate_radiology_metrics(): +# """Background task to generate radiology performance metrics""" +# try: +# # This would generate performance reports +# return True +# except Exception: +# return False +# +# +# @celery.job +# def auto_assign_radiologists(): +# """Background task to automatically assign radiologists to studies""" +# try: +# # This would auto-assign radiologists +# return True +# except Exception: +# return False +# diff --git a/templates/.DS_Store b/templates/.DS_Store index cb3de779..6ad85e18 100644 Binary files a/templates/.DS_Store and b/templates/.DS_Store differ diff --git a/templates/billing/bills/bill_detail.html b/templates/billing/bills/bill_detail.html index df025b37..cf32a32a 100644 --- a/templates/billing/bills/bill_detail.html +++ b/templates/billing/bills/bill_detail.html @@ -435,7 +435,7 @@ - + diff --git a/templates/billing/bills/bill_form.html b/templates/billing/bills/bill_form.html index 86077449..1f3e072a 100644 --- a/templates/billing/bills/bill_form.html +++ b/templates/billing/bills/bill_form.html @@ -5,479 +5,541 @@ {% block content %}
- -
-
-

{% if object %}Edit Medical Bill{% else %}Create Medical Bill{% endif %}

- -
-
- - Back to List - - {% if object %} - - View Details - - {% endif %} -
+ +
+
+

{% if object %}Edit Medical Bill{% else %}Create Medical Bill{% endif %}

+
+
+ + Back to List + + {% if object %} + + View Details + + {% endif %} +
+
-
- {% csrf_token %} - -
- -
-
- -
-
-
- Patient Information -
-
-
-
-
-
- {{ form.patient }} - - {% if form.patient.errors %} -
- {{ form.patient.errors.0 }} -
- {% endif %} -
-
-
-
- {{ form.encounter }} - - {% if form.encounter.errors %} -
- {{ form.encounter.errors.0 }} -
- {% endif %} -
-
-
-
-
+ + {% csrf_token %} - -
-
-
- Bill Details -
-
-
-
-
-
- {{ form.bill_number }} - - {% if form.bill_number.errors %} -
- {{ form.bill_number.errors.0 }} -
- {% endif %} -
-
-
-
- {{ form.bill_date }} - - {% if form.bill_date.errors %} -
- {{ form.bill_date.errors.0 }} -
- {% endif %} -
-
-
-
- {{ form.due_date }} - - {% if form.due_date.errors %} -
- {{ form.due_date.errors.0 }} -
- {% endif %} -
-
-
-
- {{ form.status }} - - {% if form.status.errors %} -
- {{ form.status.errors.0 }} -
- {% endif %} -
-
-
-
- {{ form.billing_provider }} - - {% if form.billing_provider.errors %} -
- {{ form.billing_provider.errors.0 }} -
- {% endif %} -
-
-
-
- {{ form.notes }} - - {% if form.notes.errors %} -
- {{ form.notes.errors.0 }} -
- {% endif %} -
-
-
-
-
+
+ +
+
- -
-
-
- Line Items -
- -
-
-
- - {% if object.billlineitem_set.all %} - {% for line_item in object.billlineitem_set.all %} -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
- -
-
-
- {% endfor %} - {% else %} -
- -

No line items added yet. Click "Add Item" to get started.

-
- {% endif %} -
-
-
- - -
-
-
- -
- - - {% if not object %} - - {% endif %} -
-
-
-
+ +
+
+

Patient & Context

+
+ +
+
+
+ {% if object %} +
+
+ Bill # {{ object.bill_number }}
+
Created: {{ object.created_at|date:"M d, Y H:i" }}
+
+ {% endif %} + +
+
+
+ {{ form.patient }} + + {% if form.patient.errors %}
{{ form.patient.errors.0 }}
{% endif %} +
+
+
+
+ {{ form.bill_type }} + + {% if form.bill_type.errors %}
{{ form.bill_type.errors.0 }}
{% endif %} +
+
+
+ +
+
+
+ {{ form.encounter }} + + {% if form.encounter.errors %}
{{ form.encounter.errors.0 }}
{% endif %} +
+
+
+
+ {{ form.admission }} + + {% if form.admission.errors %}
{{ form.admission.errors.0 }}
{% endif %} +
+
+
+ +
+
+
+ {{ form.payment_terms }} + + {% if form.payment_terms.errors %}
{{ form.payment_terms.errors.0 }}
{% endif %} +
+
+
+
+
+ + +
+
+

Service & Dates

+
+ +
+
+
+
+
+
+ {{ form.service_date_from }} + + {% if form.service_date_from.errors %}
{{ form.service_date_from.errors.0 }}
{% endif %} +
+
+
+
+ {{ form.service_date_to }} + + {% if form.service_date_to.errors %}
{{ form.service_date_to.errors.0 }}
{% endif %} +
+
+
+
+ {{ form.bill_date }} + + {% if form.bill_date.errors %}
{{ form.bill_date.errors.0 }}
{% endif %} +
+
+
+
+
+
+ {{ form.due_date }} + + {% if form.due_date.errors %}
{{ form.due_date.errors.0 }}
{% endif %} +
+
+
+
+
+ + +
+
+

Providers & Insurance

+
+ +
+
+
+
+
+
+ {{ form.attending_provider }} + + {% if form.attending_provider.errors %}
{{ form.attending_provider.errors.0 }}
{% endif %} +
+
+
+
+ {{ form.billing_provider }} + + {% if form.billing_provider.errors %}
{{ form.billing_provider.errors.0 }}
{% endif %} +
+
+
+
+
+
+ {{ form.primary_insurance }} + + {% if form.primary_insurance.errors %}
{{ form.primary_insurance.errors.0 }}
{% endif %} +
+
+
+
+ {{ form.secondary_insurance }} + + {% if form.secondary_insurance.errors %}
{{ form.secondary_insurance.errors.0 }}
{% endif %} +
+
+
+
+
+ + +
+
+

Notes

+
+ +
+
+
+
+ {{ form.notes }} + {% if form.notes.errors %}
{{ form.notes.errors.0 }}
{% endif %} +
+
+
+ + +
+
+

Line Items

+
+ + +
+
+
+
+ {% if object and object.billlineitem_set.all %} + {% for line_item in object.billlineitem_set.all %} +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+ {% endfor %} + {% else %} +
+ +

No line items added yet. Click "Add Item" to get started.

+
+ {% endif %} +
+
+
+ + +
+
+
+ +
+ + + {% if not object %} + + {% endif %} +
+
+
+
+ +
+
+ + +
+ +
+
+

Bill Summary

+
+ +
+
+
+ +
+ Subtotal: $0.00 +
+
+ Tax: $0.00 +
+
+ Discount: $0.00 +
+
+
+ Total: $0.00
- -
- -
-
-
- Bill Summary -
-
-
-
- Subtotal: - $0.00 -
-
- Tax: - $0.00 -
-
- Discount: - $0.00 -
-
-
- Total: - $0.00 -
-
-
- - -
-
-
- Help & Guidelines -
-
-
-
-
-

- -

-
-
-
    -
  • Select the patient for this bill
  • -
  • Link to a specific encounter if applicable
  • -
  • Verify patient insurance information
  • -
-
-
-
-
-

- -

-
-
-
    -
  • Use standard CPT/HCPCS codes
  • -
  • Include modifier codes when applicable
  • -
  • Verify codes with current fee schedule
  • -
-
-
-
-
-

- -

-
-
-
    -
  • Draft: Bill is being prepared
  • -
  • Pending: Ready for review
  • -
  • Submitted: Sent to patient/insurance
  • -
  • Paid: Payment received in full
  • -
-
-
-
-
-
-
+ +
+ {{ form.subtotal }} + {{ form.tax_amount }} + {{ form.discount_amount }} + {{ form.adjustment_amount }}
+
- + + +
+
+

Help & Guidelines

+
+ +
+
+
+
+
+

+ +

+
+
+
    +
  • Select the patient for this bill
  • +
  • Link to a specific encounter if applicable
  • +
  • Verify patient insurance information
  • +
+
+
+
+
+

+ +

+
+
+
    +
  • Use standard CPT/HCPCS codes
  • +
  • Include modifier codes when applicable
  • +
  • Verify codes with current fee schedule
  • +
+
+
+
+
+

+ +

+
+
+
    +
  • Draft: Bill is being prepared
  • +
  • Pending: Ready for review
  • +
  • Submitted: Sent to patient/insurance
  • +
  • Paid: Payment received in full
  • +
+
+
+
+
+
+
+
+
+
-{% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/templates/billing/bills/bill_list.html b/templates/billing/bills/bill_list.html index 980986f4..82634ec9 100644 --- a/templates/billing/bills/bill_list.html +++ b/templates/billing/bills/bill_list.html @@ -5,405 +5,395 @@ {% block content %}
- -
-
-

Medical Bills

- -
-
- - Create Bill - - - -
+ +
+
+

Medical Bills

+
- - -
-
-
-
-
-
-
Total Bills
-

{{ stats.total_bills }}

-
-
- -
-
-
-
-
-
-
-
-
-
-
Total Amount
-

ê{{ stats.total_amount|default:0|floatformat:'2g' }}

-
-
- -
-
-
-
-
-
-
-
-
-
-
Total Paid
-

ê{{ stats.total_paid|default:0|floatformat:'2g' }}

-
-
- -
-
-
-
-
-
-
-
-
-
-
Outstanding
-

ê{{ stats.outstanding_amount|default:0|floatformat:'2g' }}

-
-
- -
-
-
-
-
+
+ + Create Bill + + +
+
- -
-
-
- Search & Filter -
-
+ +
+
+
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
- -
-
+
+
+
Total Bills
+

{{ stats.total_bills|default:0 }}

+
+
+ +
+
+
+
+
+
+
+
+
Total Amount
+

ê{{ stats.total_amount|default:0|floatformat:'2g' }}

+
+
+ +
+
+
+
+
+
+
+
+
+
+
Total Paid
+

ê{{ stats.total_paid|default:0|floatformat:'2g' }}

+
+
+ +
+
+
+
+
+
+
+
+
+
+
Outstanding
+

ê{{ stats.outstanding_amount|default:0|floatformat:'2g' }}

+
+
+ +
+
+
+
+
+
- -
-
-
- Medical Bills - {{ page_obj.paginator.count }} total -
-
- - - -
-
-
-
-
- - - - - - - - - - - - - - - - - {% for bill in page_obj %} - - - - - - - - - - - - - {% empty %} - - - - {% endfor %} - -
-
- -
-
Bill NumberPatientDateTotal AmountPaid AmountBalanceStatusDue DateActions
-
- -
-
- - {{ bill.bill_number }} - - -
- {{ bill.patient.get_full_name }} -
MRN: {{ bill.patient.mrn }} -
-
{{ bill.bill_date|date:"M d, Y" }}ê{{ bill.total_amount|floatformat:2 }}ê{{ bill.paid_amount|floatformat:2 }} - - ê{{ bill.balance_amount|floatformat:2 }} - - - {% if bill.status == 'DRAFT' %} - Draft - {% elif bill.status == 'PENDING' %} - Pending - {% elif bill.status == 'SUBMITTED' %} - Submitted - {% elif bill.status == 'PARTIAL_PAID' %} - Partially Paid - {% elif bill.status == 'PAID' %} - Paid - {% elif bill.status == 'OVERDUE' %} - Overdue - {% elif bill.status == 'COLLECTIONS' %} - Collections - {% elif bill.status == 'WRITTEN_OFF' %} - Written Off - {% elif bill.status == 'CANCELLED' %} - Cancelled - {% endif %} - - {% if bill.due_date %} - - {{ bill.due_date|date:"M d, Y" }} - - {% else %} - - - {% endif %} - -
- - - - {% if bill.status == 'DRAFT' %} - - - - {% endif %} -
- - -
-
-
-
- -
No bills found
-

No medical bills match your current filters.

- - Create First Bill - -
-
-
-
-
- - - {% if is_paginated %} - {% include 'partial/pagination.html' %} - {% endif %} + +
+
+

Search & Filter

+
+ +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+
+ + +
+
+

+ Medical Bills + {{ page_obj.paginator.count }} total +

+
+ + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + {% for bill in page_obj %} + + + + + + + + + + + + + {% empty %} + + + + {% endfor %} + +
+
+ +
+
Bill NumberPatientDateTotal AmountPaid AmountBalanceStatusDue DateActions
+
+ +
+
+ + {{ bill.bill_number }} + + +
+ {{ bill.patient.get_full_name }} +
MRN: {{ bill.patient.mrn }} +
+
{{ bill.bill_date|date:"M d, Y" }}ê{{ bill.total_amount|floatformat:2 }}ê{{ bill.paid_amount|floatformat:2 }} + + ê{{ bill.balance_amount|floatformat:2 }} + + + {% if bill.status == 'DRAFT' %} + Draft + {% elif bill.status == 'PENDING' %} + Pending + {% elif bill.status == 'SUBMITTED' %} + Submitted + {% elif bill.status == 'PARTIAL_PAID' %} + Partially Paid + {% elif bill.status == 'PAID' %} + Paid + {% elif bill.status == 'OVERDUE' %} + Overdue + {% elif bill.status == 'COLLECTIONS' %} + Collections + {% elif bill.status == 'WRITTEN_OFF' %} + Written Off + {% elif bill.status == 'CANCELLED' %} + Cancelled + {% endif %} + + {% if bill.due_date %} + + {{ bill.due_date|date:"M d, Y" }} + + {% else %} + - + {% endif %} + +
+ + + + {% if bill.status == 'DRAFT' %} + + + + {% endif %} +
+ + +
+
+
+
+ +
No bills found
+

No medical bills match your current filters.

+ + Create First Bill + +
+
+
+
+
+
+ + + {% if is_paginated %} + {% include 'partial/pagination.html' %} + {% endif %}
-{% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/templates/billing/claims/claim_detail.html b/templates/billing/claims/claim_detail.html index eff12889..5071be1b 100644 --- a/templates/billing/claims/claim_detail.html +++ b/templates/billing/claims/claim_detail.html @@ -31,13 +31,13 @@ Actions