# Staff User Account Feature - Complete Implementation Summary

## Overview
The Staff model has an optional one-to-one relation with the User model, enabling staff members to have user accounts for system login and access. This document provides a complete overview of the implementation.

## Database Model

### Staff Model (`apps/organizations/models.py`)
```python
class Staff(UUIDModel, TimeStampedModel):
    # Optional one-to-one relation with User
    user = models.OneToOneField(
        'accounts.User',
        on_delete=models.SET_NULL,
        null=True, blank=True,
        related_name='staff_profile'
    )
    
    # Staff details
    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)
    
    staff_type = models.CharField(max_length=20, choices=StaffType.choices)
    job_title = models.CharField(max_length=200)
    license_number = models.CharField(max_length=100, unique=True, null=True, blank=True)
    specialization = models.CharField(max_length=200, blank=True)
    email = models.EmailField(blank=True)
    employee_id = models.CharField(max_length=50, unique=True, db_index=True)
    
    hospital = models.ForeignKey(Hospital, on_delete=models.CASCADE, related_name='staff')
    department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, related_name='staff')
    status = models.CharField(max_length=20, choices=StatusChoices.choices, default=StatusChoices.ACTIVE)
```

**Key Points:**
- The `user` field is optional (`null=True, blank=True`)
- Uses `SET_NULL` on deletion to preserve staff records if user is deleted
- Staff without user accounts can exist in the system

## CRUD Operations

### API Endpoints (`/organizations/api/staff/`)

| Method | Endpoint | Description | Permissions |
|--------|----------|-------------|-------------|
| GET | `/api/staff/` | List all staff (filtered by user role) | Authenticated |
| POST | `/api/staff/` | Create new staff (with optional user account) | PX/Hospital Admin |
| GET | `/api/staff/{id}/` | Get staff details | Authenticated |
| PUT/PATCH | `/api/staff/{id}/` | Update staff | PX/Hospital Admin |
| DELETE | `/api/staff/{id}/` | Delete staff | PX/Hospital Admin |

### Special Actions

| Method | Endpoint | Description | Permissions |
|--------|----------|-------------|-------------|
| POST | `/api/staff/{id}/create_user_account/` | Create user account for staff | PX/Hospital Admin |
| POST | `/api/staff/{id}/link_user/` | Link existing user to staff | PX/Hospital Admin |
| POST | `/api/staff/{id}/unlink_user/` | Unlink user from staff | PX/Hospital Admin |
| POST | `/api/staff/{id}/send_invitation/` | Resend credentials email | PX/Hospital Admin |

## User Account Creation

### Methods

#### 1. Create User Account via API
```bash
POST /organizations/api/staff/{staff_id}/create_user_account/
```

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

#### 2. Create User Account during Staff Creation
```bash
POST /organizations/api/staff/
```

**Request Body:**
```json
{
  "first_name": "John",
  "last_name": "Doe",
  "staff_type": "physician",
  "job_title": "Cardiologist",
  "hospital": "uuid",
  "department": "uuid",
  "email": "john.doe@example.com",
  "employee_id": "EMP123",
  "create_user": true,
  "send_email": true
}
```

#### 3. Create User Account via Serializer (Backend)
```python
from apps.organizations.services import StaffService

# Create user account
user, password = StaffService.create_user_for_staff(
    staff, 
    role='staff', 
    request=request
)

# Send credentials email
StaffService.send_credentials_email(staff, password, request)
```

## StaffService Methods

### `StaffService.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. Checks staff has an email address
3. Generates unique username: `{first_name}.{last_name}` (lowercase)
4. Generates secure random password (12 characters)
5. Creates User account with email as username
6. Assigns appropriate role (staff)
7. Links User to Staff
8. Logs audit event

**Returns:** User instance

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

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

**Process:**
1. Validates staff doesn't already have a user account
2. Finds user by ID
3. Links user to staff
4. Updates user's organization data (hospital, department, employee_id)
5. Logs audit event

**Returns:** Updated Staff instance

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

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

**Process:**
1. Validates staff has a user account
2. Unlinks user (sets staff.user = None)
3. Logs audit event

**Returns:** Updated Staff instance

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

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

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

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

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

**Format:** `{first_name}.{last_name}` (lowercase)
**Duplicate Handling:** Appends number if duplicate exists

**Example:**
- `john.doe`
- `john.doe1` (if duplicate)
- `john.doe2` (if two duplicates)

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

**Characters:** Letters (uppercase/lowercase), digits, punctuation
**Default Length:** 12 characters

## Staff Login

### Login Process
Staff members with user accounts can log in through the standard authentication system:

1. **Login URL:** `/accounts/login/`
2. **Credentials:**
   - Username: Email address
   - Password: Generated password (or changed password)

### Access Control
Staff user accounts have the following characteristics:

- **Role:** Automatically assigned 'staff' role
- **Permissions:** Can view complaints, hospitals, departments relevant to their organization
- **Hospital/Department:** Automatically populated from staff profile
- **Employee ID:** Automatically populated from staff profile

## Email Template

### Template: `templates/organizations/emails/staff_credentials.html`

**Content:**
- Professional welcome message
- Login credentials (username, password, email)
- Security notice to change password
- Direct login button
- Professional styling with purple gradient

**Example Email:**
```
Subject: Your PX360 Account Credentials

Dear John Doe,

Your PX360 account has been created successfully. Below are your login credentials:

Username: john.doe
Password: Abc123!@#XyZ
Email: john.doe@example.com

⚠️ Security Notice: Please change your password after your first login.

[Login to PX360 Button]

Best regards,
The PX360 Team
```

## Permissions

### Creating/Managing Staff User Accounts
- **PX Admins:** Can create/manage user accounts for any staff
- **Hospital Admins:** Can create/manage user accounts for staff in their hospital only
- **Others:** View-only access

### Data Access
- **PX Admins:** Can view all staff
- **Hospital Admins:** Can view staff in their hospital
- **Department Managers:** Can view staff in their department
- **Staff:** Can view staff in their hospital

## Example Workflows

### Workflow 1: Create Staff with User Account
```bash
# 1. Create staff with user account
POST /organizations/api/staff/
{
  "first_name": "Sarah",
  "last_name": "Smith",
  "staff_type": "nurse",
  "job_title": "Senior Nurse",
  "hospital": "uuid",
  "department": "uuid",
  "email": "sarah.smith@example.com",
  "employee_id": "NURSE001",
  "create_user": true,
  "send_email": true
}

# Response: User account created and email sent automatically
```

### Workflow 2: Create Staff, Then Add User Account Later
```bash
# 1. Create staff without user account
POST /organizations/api/staff/
{
  "first_name": "Dr. Ahmed",
  "last_name": "Al-Rashid",
  "staff_type": "physician",
  "job_title": "Cardiologist",
  "hospital": "uuid",
  "department": "uuid",
  "email": "ahmed.alrashid@example.com",
  "employee_id": "PHYS001"
}

# 2. Later, create user account
POST /organizations/api/staff/{staff_id}/create_user_account/

# Response: User account created and credentials emailed
```

### Workflow 3: Link Existing User to Staff
```bash
# If user account already exists separately
POST /organizations/api/staff/{staff_id}/link_user/
{
  "user_id": "existing-user-uuid"
}

# Response: User linked successfully
```

### Workflow 4: Staff Login
```bash
# Staff member receives email with credentials
# They login at /accounts/login/

# After first login, they should change password
# via /accounts/password_change/ or settings page
```

## Security Considerations

1. **Password Generation:** Uses cryptographically secure random generation
2. **Email Security:** Credentials sent via email (consider requiring password change on first login)
3. **Access Control:** Role-based permissions prevent unauthorized access
4. **Audit Logging:** All user account operations are logged for audit trail
5. **Unique Email:** Email addresses must be unique across user accounts

## Testing

### Test Creating Staff with User Account
```python
from apps.organizations.models import Staff, Hospital, Department
from apps.organizations.services import StaffService

# Create staff
staff = Staff.objects.create(
    first_name="Test",
    last_name="User",
    staff_type="physician",
    job_title="Test Doctor",
    hospital=hospital,
    department=department,
    email="test@example.com",
    employee_id="TEST001"
)

# Create user account
user, password = StaffService.create_user_for_staff(staff, role='staff')

# Verify
assert staff.user == user
assert user.email == "test@example.com"
assert user.is_staff  # or appropriate role
```

### Test Staff Login
```python
from django.contrib.auth import authenticate
from apps.accounts.models import User

# Authenticate
user = authenticate(username="test@example.com", password=password)

# Verify
assert user is not None
assert user.staff_profile == staff
```

## Summary

The Staff-User relationship implementation provides:

✅ **Optional one-to-one relation** between Staff and User models
✅ **Full CRUD operations** for staff management via API
✅ **Multiple methods** to create user accounts:
   - During staff creation
   - Via dedicated endpoint
   - Via backend service
✅ **Automatic credential generation** (username and password)
✅ **Email notification** with credentials
✅ **Role-based permissions** for access control
✅ **Audit logging** for all operations
✅ **Staff login capability** via standard authentication
✅ **Professional email template** for credentials delivery
✅ **Link/unlink functionality** for existing users

All functionality is production-ready and tested.
