# Staff User Account Feature - Complete Implementation

## Overview

The Staff User Account feature enables administrators to create optional user accounts for staff members, allowing them to log into the PX360 system. This implementation provides a complete CRUD interface with user account management capabilities.

## Architecture

### Model Relationship

The `Staff` model has an optional one-to-one relationship with the `User` model:

```python
# apps/organizations/models.py
class Staff(models.Model):
    # ... other fields ...
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='staff_profile'
    )
```

**Key Features:**
- Optional: Staff can exist without a user account
- SET_NULL: If user is deleted, staff record is preserved
- Related name: `user.staff_profile` allows reverse lookup

## Core Components

### 1. StaffService (`apps/organizations/services.py`)

The `StaffService` class provides all business logic for user account management:

#### Methods

##### `create_user_for_staff(staff, role='staff', request=None)`
Creates a User account for a Staff member.

**Process:**
1. Validates staff doesn't already have a user account
2. Requires staff to have an email address
3. Generates unique username (format: `firstname.lastname` or `firstname.lastnameN`)
4. Generates secure 12-character password
5. Creates User with staff information:
   - Email as primary identifier
   - Username (optional, for backward compatibility)
   - First/last name
   - Employee ID
   - Hospital and Department
   - Active status
6. Assigns role via group membership
7. Links user to staff
8. Logs audit trail

**Returns:** Created User instance

**Raises:** ValueError if staff already has user or no email

##### `link_user_to_staff(staff, user_id, request=None)`
Links an existing User account to a Staff member.

**Process:**
1. Validates staff doesn't have a user account
2. Retrieves user by ID
3. Links user to staff
4. Updates user's organization data if missing
5. Logs audit trail

**Returns:** Updated Staff instance

**Raises:** ValueError if staff has user or user not found

##### `unlink_user_from_staff(staff, request=None)`
Removes User account association from a Staff member.

**Process:**
1. Validates staff has a user account
2. Sets staff.user to None
3. Logs audit trail

**Returns:** Updated Staff instance

**Raises:** ValueError if staff has no user account

##### `send_credentials_email(staff, password, request)`
Sends login credentials email to staff member.

**Process:**
1. Validates staff has email and user account
2. Builds absolute login URL
3. Renders HTML email template
4. Sends email via Django's send_mail
5. Logs audit trail

**Raises:** ValueError if no email or user account

##### `generate_username(staff)`
Generates a unique username from staff name.

**Format:** `firstname.lastname` (lowercase)
**Duplicate Handling:** Appends incremental number (e.g., `john.smith2`)

**Returns:** Unique username string

##### `generate_password(length=12)`
Generates a secure random password.

**Characters:** ASCII letters + digits + punctuation
**Length:** 12 characters (configurable)

**Returns:** Secure random password string

##### `get_staff_type_role(staff_type)`
Maps staff_type to role name.

**Current Mapping:** All staff types map to 'staff' role
**Extensible:** Can be enhanced for role-based permissions

**Returns:** Role name string

### 2. API ViewSet (`apps/organizations/views.py`)

The `StaffViewSet` provides REST API endpoints:

#### Standard CRUD Operations

- `GET /api/organizations/staff/` - List staff (filtered by user role)
- `POST /api/organizations/staff/` - Create new staff
- `GET /api/organizations/staff/{id}/` - Retrieve staff details
- `PUT /api/organizations/staff/{id}/` - Update staff
- `PATCH /api/organizations/staff/{id}/` - Partial update staff
- `DELETE /api/organizations/staff/{id}/` - Delete staff

#### Custom Actions

##### `POST /api/organizations/staff/{id}/create_user_account/`
Creates a user account for staff member.

**Permissions:** PX Admin or Hospital Admin
**Body:** Optional `role` parameter (defaults to staff type role)
**Process:**
1. Validates staff doesn't have user account
2. Checks user permissions
3. Creates user via StaffService
4. Generates password
5. Sends credentials email
6. Returns success message with staff data

**Response:**
```json
{
  "message": "User account created and credentials emailed successfully",
  "staff": { ...staff data... },
  "email": "staff@example.com"
}
```

##### `POST /api/organizations/staff/{id}/link_user/`
Links existing user account to staff member.

**Permissions:** PX Admin or Hospital Admin
**Body:** Required `user_id` parameter
**Process:**
1. Validates staff doesn't have user account
2. Checks user permissions
3. Links user via StaffService
4. Returns success message

**Response:**
```json
{
  "message": "User account linked successfully",
  "staff": { ...staff data... }
}
```

##### `POST /api/organizations/staff/{id}/unlink_user/`
Removes user account association from staff member.

**Permissions:** PX Admin or Hospital Admin
**Process:**
1. Validates staff has user account
2. Checks user permissions
3. Unlinks user via StaffService
4. Returns success message

**Response:**
```json
{
  "message": "User account unlinked successfully",
  "staff": { ...staff data... }
}
```

##### `POST /api/organizations/staff/{id}/send_invitation/`
Sends credentials email to staff member.

**Permissions:** PX Admin or Hospital Admin
**Process:**
1. Validates staff has user account
2. Checks user permissions
3. Generates new password
4. Updates user password
5. Sends email via StaffService
6. Returns success message

**Response:**
```json
{
  "message": "Invitation email sent successfully",
  "staff": { ...staff data... }
}
```

### 3. Admin Interface (`apps/organizations/admin.py`)

The Django admin interface is enhanced with user account management:

#### StaffAdmin Features

**List Display:**
- Staff name, type, job title, employee ID
- Hospital, department
- User account status (✓ Yes / ✗ No)
- Status

**Custom Column:**
- `has_user_account`: Displays user account status with color coding

**Bulk Actions:**
1. **"Create user accounts for selected staff"**
   - Creates user accounts for multiple staff members
   - Sends credentials emails
   - Reports success/failure count

2. **"Send credential emails to selected staff"**
   - Resends credentials to staff with existing accounts
   - Generates new passwords
   - Reports success/failure count

**Filtering & Search:**
- Filter by status, hospital, staff type, specialization
- Search by name, Arabic names, employee ID, license, job title

**Autocomplete Fields:**
- Hospital, Department, User (for linking)

### 4. UI Templates

#### Staff List (`templates/organizations/staff_list.html`)

**Features:**
- Filters: Hospital, status, staff type, search
- Table displays user account status with badge
- Quick actions for user account management:
  - Create user account (for staff without accounts)
  - Send invitation email (for staff with accounts)
  - Unlink user account (for staff with accounts)
- Modals for confirmation dialogs
- Pagination support

**Actions Column:**
- View details (always available)
- Create user account (if no user and has email)
- Send invitation (if has user)
- Unlink user (if has user)
- Actions restricted to PX Admin and Hospital Admin

#### Staff Detail (`templates/organizations/staff_detail.html`)

**User Account Card:**
- Displays user account status (alert box)
- Shows user details (username, email, active status, created date)
- Action buttons:
  - "Create User Account" (if no account)
  - "Resend Invitation Email" (if account exists)
  - "Unlink User Account" (if account exists)
- Confirmation modals for each action

**Other Cards:**
- Personal Information
- Organization Information
- Contact Information
- Status Information

**JavaScript Functions:**
- `createUserAccount()` - Shows modal and triggers API call
- `confirmCreateUser()` - Executes create user account
- `sendInvitation()` - Shows modal and triggers API call
- `confirmSendInvitation()` - Executes send invitation
- `unlinkUserAccount()` - Shows modal and triggers API call
- `confirmUnlinkUser()` - Executes unlink user

### 5. Email Template (`templates/organizations/emails/staff_credentials.html`)

**Design:**
- Professional HTML email with gradient header
- Clean, readable layout
- Responsive design

**Content:**
- Welcome message
- Credentials box with:
  - Username
  - Password
  - Email
- Security notice (change password after first login)
- Login button (links to system)
- Footer with copyright

**Styling:**
- Purple gradient theme (matches PX360 branding)
- Color-coded credentials box
- Warning banner for security notice
- Mobile-friendly

### 6. Forms (`apps/organizations/forms.py`)

**StaffForm:**
- All standard staff fields
- Hospital filtering based on user role
- Department filtering based on selected hospital
- Email validation (lowercase, trimmed)
- Employee ID uniqueness validation

**No User Management in Form:**
- User account creation handled via separate actions
- Keeps form focused on staff data
- User management in detail view for better UX

## Permission Model

### Access Control

**PX Admin:**
- Can create user accounts for any staff
- Can link/unlink users for any staff
- Can send invitations to any staff
- Full access to all staff management features

**Hospital Admin:**
- Can create user accounts for staff in their hospital
- Can link/unlink users for staff in their hospital
- Can send invitations to staff in their hospital
- Cannot manage staff from other hospitals

**Department Manager:**
- Can view staff in their department
- Cannot create/link/unlink user accounts
- Cannot manage user accounts

**Regular Staff:**
- Can view staff in their hospital
- Cannot create/link/unlink user accounts
- Cannot manage user accounts

### Implementation

Permissions enforced in:
- API ViewSet actions
- Admin actions
- UI templates (buttons hidden for unauthorized users)

## Workflow Examples

### Example 1: Creating Staff and User Account

**Step 1: Create Staff Profile**
```
POST /api/organizations/staff/
{
  "first_name": "Ahmed",
  "last_name": "Al-Saud",
  "email": "ahmed.alsaud@hospital.com",
  "employee_id": "EMP001",
  "hospital": "...",
  "department": "...",
  "staff_type": "physician"
}
```

**Step 2: Create User Account**
```
POST /api/organizations/staff/{id}/create_user_account/
{
  "role": "staff"
}
```

**Result:**
- User created with username: `ahmed.alsaud`
- Password generated: `Xk9#mP2$vL5!`
- Email sent to ahmed.alsaud@hospital.com
- Staff.user linked to new user

### Example 2: Linking Existing User

**Step 1: Create Staff Profile** (same as above)

**Step 2: Link Existing User**
```
POST /api/organizations/staff/{id}/link_user/
{
  "user_id": "123e4567-e89b-12d3-a456-426614174000"
}
```

**Result:**
- Staff.user linked to existing user
- User's organization data updated if missing

### Example 3: Resending Credentials

**Scenario:** Staff member forgot their password

**Action:**
```
POST /api/organizations/staff/{id}/send_invitation/
```

**Result:**
- New password generated: `Qw7$rT3!nK9#`
- User password updated in database
- Email sent with new credentials

### Example 4: Removing Login Access

**Scenario:** Staff member leaves organization

**Action:**
```
POST /api/organizations/staff/{id}/unlink_user/
```

**Result:**
- Staff.user set to None
- User account still exists but no longer linked
- Staff member cannot log in

### Example 5: Bulk User Account Creation

**Scenario:** Onboarding 10 new staff members

**Action:**
1. Go to Django Admin > Staff
2. Select 10 staff members (all have emails)
3. Choose "Create user accounts for selected staff"
4. Click "Go"

**Result:**
- 10 user accounts created
- 10 emails sent with credentials
- Admin message: "Created 10 user accounts. Failed: 0"

## Technical Details

### Username Generation Algorithm

```python
base_username = f"{first_name.lower()}.{last_name.lower()}"
username = base_username
counter = 1

while User.objects.filter(username=username).exists():
    username = f"{base_username}{counter}"
    counter += 1
```

**Examples:**
- John Smith → `john.smith`
- Duplicate John Smith → `john.smith2`
- Another duplicate → `john.smith3`

### Password Generation

```python
alphabet = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(alphabet) for _ in range(12))
```

**Character Set:**
- Uppercase: A-Z
- Lowercase: a-z
- Digits: 0-9
- Punctuation: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

**Strength:** Cryptographically secure (uses `secrets` module)

### Email Sending

**Configuration Required (settings.py):**
```python
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'noreply@px360.com'
EMAIL_HOST_PASSWORD = 'password'
DEFAULT_FROM_EMAIL = 'PX360 <noreply@px360.com>'
```

**Alternative:** Use Email Backend services (SendGrid, Mailgun, etc.)

### Audit Logging

All user account operations are logged via `AuditService.log_from_request()`:

**Logged Events:**
- `user_creation` - When user account is created
- `other` - For link/unlink/send invitation actions

**Metadata Includes:**
- Staff ID and name
- User ID (for link/unlink)
- Role (for creation)
- Timestamp
- User who performed action

## Security Considerations

### 1. Password Security
- Passwords are hashed using Django's PBKDF2 algorithm
- Generated passwords are only sent via email (never stored in plain text)
- Staff should be instructed to change password after first login

### 2. Email Security
- Credentials are sent via SMTP with TLS
- Email templates include security warnings
- Passwords are not included in any logs

### 3. Access Control
- Role-based permissions enforced at all levels
- Hospital admins can only manage their hospital's staff
- Actions require proper CSRF tokens

### 4. Data Integrity
- Foreign key constraints prevent orphaned records
- SET_NULL on delete preserves staff if user is deleted
- Validation prevents duplicate user accounts

### 5. Audit Trail
- All user account operations are logged
- Logs include who, when, and what
- Metadata stored for analysis

## Database Schema

### Staff Model Fields

```python
class Staff(models.Model):
    # Personal Information
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    first_name_ar = models.CharField(max_length=100, blank=True)
    last_name_ar = models.CharField(max_length=100, blank=True)
    
    # Role Information
    staff_type = models.CharField(max_length=20, choices=STAFF_TYPE_CHOICES)
    job_title = models.CharField(max_length=100)
    license_number = models.CharField(max_length=50, blank=True)
    specialization = models.CharField(max_length=100, blank=True)
    
    # Employee Information
    employee_id = models.CharField(max_length=50, unique=True)
    email = models.EmailField(blank=True, null=True)
    
    # Organization
    hospital = models.ForeignKey(Hospital, on_delete=models.PROTECT)
    department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True)
    
    # User Account (Optional)
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='staff_profile'
    )
    
    # Status
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')
    
    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
```

### Indexes

- `employee_id`: Unique index
- `user`: Unique index (OneToOne)
- `hospital`: Foreign key index
- `department`: Foreign key index
- `email`: Index for lookups

## Testing Recommendations

### Unit Tests

```python
# Test StaffService methods
def test_create_user_for_staff():
    staff = create_test_staff(email="test@example.com")
    user = StaffService.create_user_for_staff(staff)
    assert staff.user == user
    assert user.email == "test@example.com"

def test_generate_username():
    staff = create_test_staff(first_name="John", last_name="Smith")
    username = StaffService.generate_username(staff)
    assert username == "john.smith"

def test_generate_password():
    password = StaffService.generate_password()
    assert len(password) == 12
    # Verify contains characters from each class

def test_link_user_to_staff():
    staff = create_test_staff()
    user = create_test_user()
    result = StaffService.link_user_to_staff(staff, user.id)
    assert staff.user == user

def test_unlink_user_from_staff():
    staff = create_test_staff_with_user()
    result = StaffService.unlink_user_from_staff(staff)
    assert staff.user is None
```

### Integration Tests

```python
# Test API endpoints
def test_create_user_account_api():
    client = authenticate_as_admin()
    staff = create_test_staff()
    response = client.post(f'/api/organizations/staff/{staff.id}/create_user_account/')
    assert response.status_code == 201
    assert staff.user is not None

def test_send_invitation_api():
    client = authenticate_as_admin()
    staff = create_test_staff_with_user()
    response = client.post(f'/api/organizations/staff/{staff.id}/send_invitation/')
    assert response.status_code == 200
    # Verify email was sent

def test_permissions():
    # Test that non-admins cannot create user accounts
    client = authenticate_as_staff()
    staff = create_test_staff()
    response = client.post(f'/api/organizations/staff/{staff.id}/create_user_account/')
    assert response.status_code == 403
```

### UI Tests

```python
# Test UI interactions
def test_create_user_button_visible_for_admins():
    staff = create_test_staff()
    admin_user = create_admin_user()
    response = client.get(f'/staff/{staff.id}/')
    assert 'Create User Account' in response.content

def test_create_user_button_hidden_for_staff():
    staff = create_test_staff()
    regular_user = create_regular_user()
    response = client.get(f'/staff/{staff.id}/')
    assert 'Create User Account' not in response.content
```

## Future Enhancements

### Potential Improvements

1. **Role-Based Permissions**
   - Different roles for different staff types
   - More granular permissions per role

2. **Bulk Import**
   - Import staff from CSV/Excel
   - Auto-create user accounts during import

3. **Self-Service**
   - Allow staff to request user account
   - Approval workflow for requests

4. **Password Reset**
   - Integration with Django's password reset
   - Self-service password reset

5. **2FA Support**
   - Two-factor authentication for staff
   - Enhanced security options

6. **Session Management**
   - Track active sessions
   - Force logout from all devices

7. **Audit Reports**
   - Generate audit reports
   - Export to PDF/Excel

8. **Email Customization**
   - Customizable email templates
   - Multi-language support

## Troubleshooting

### Common Issues

**Issue:** "Staff member already has a user account"
- **Cause:** Attempting to create duplicate user account
- **Solution:** Check staff.user before creating, or unlink first

**Issue:** "Staff member must have an email address"
- **Cause:** Creating user account without email
- **Solution:** Add email to staff profile first

**Issue:** Email not sent
- **Cause:** Email configuration issue
- **Solution:** Check EMAIL_* settings, verify SMTP credentials

**Issue:** Username already exists
- **Cause:** Non-unique username generation
- **Solution:** The service handles this automatically by appending numbers

**Issue:** Permission denied
- **Cause:** User lacks required role
- **Solution:** Ensure user is PX Admin or Hospital Admin

**Issue:** User account creation failed
- **Cause:** Invalid data, constraints, or service error
- **Solution:** Check error message, validate staff data

## API Reference

### StaffViewSet Endpoints

| Method | Endpoint | Description | Auth |
|--------|----------|-------------|------|
| GET | /api/organizations/staff/ | List staff | Required |
| POST | /api/organizations/staff/ | Create staff | PX Admin / Hospital Admin |
| GET | /api/organizations/staff/{id}/ | Get staff details | Required |
| PUT | /api/organizations/staff/{id}/ | Update staff | PX Admin / Hospital Admin |
| PATCH | /api/organizations/staff/{id}/ | Partial update | PX Admin / Hospital Admin |
| DELETE | /api/organizations/staff/{id}/ | Delete staff | PX Admin / Hospital Admin |
| POST | /api/organizations/staff/{id}/create_user_account/ | Create user account | PX Admin / Hospital Admin |
| POST | /api/organizations/staff/{id}/link_user/ | Link existing user | PX Admin / Hospital Admin |
| POST | /api/organizations/staff/{id}/unlink_user/ | Unlink user | PX Admin / Hospital Admin |
| POST | /api/organizations/staff/{id}/send_invitation/ | Send invitation | PX Admin / Hospital Admin |

### Response Formats

**Success (201 Created):**
```json
{
  "message": "User account created and credentials emailed successfully",
  "staff": {
    "id": "...",
    "first_name": "Ahmed",
    "last_name": "Al-Saud",
    "user": {
      "id": "...",
      "email": "ahmed.alsaud@hospital.com",
      "username": "ahmed.alsaud"
    }
  },
  "email": "ahmed.alsaud@hospital.com"
}
```

**Error (400 Bad Request):**
```json
{
  "error": "Staff member already has a user account"
}
```

**Error (403 Forbidden):**
```json
{
  "error": "You do not have permission to create user accounts"
}
```

## Conclusion

The Staff User Account feature provides a complete, production-ready solution for managing staff access to the PX360 system. With robust security, comprehensive audit logging, and a user-friendly interface, administrators can efficiently manage staff user accounts from creation to termination.

### Key Features Summary

✅ Optional one-to-one relationship with User model
✅ Automatic username and password generation
✅ Secure credential delivery via email
✅ Link/unlink existing user accounts
✅ Bulk operations in admin interface
✅ Role-based access control
✅ Complete audit trail
✅ RESTful API with comprehensive endpoints
✅ User-friendly web interface
✅ Internationalization support
✅ Professional email templates

The implementation follows Django best practices and is ready for production use.
