Spaces:
Sleeping
Sleeping
File size: 6,820 Bytes
01f85fe b00cab2 01f85fe b00cab2 01f85fe b00cab2 01f85fe b00cab2 01f85fe b00cab2 01f85fe | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | # Bulk User Invitations via CSV
## Overview
The bulk invitation feature allows admins to invite multiple users at once by uploading a CSV file. The system intelligently handles:
- **Existing users in project** → Skip (already members)
- **Existing users not in project** → Add to project team
- **New users** → Send invitations
## CSV Format
### Organization-Level Invitations
For inviting users to a client or contractor organization:
```csv
email,first_name,last_name,phone,role,invitation_method
john@example.com,John,Doe,+254712345678,field_agent,whatsapp
jane@example.com,Jane,Smith,+254798765432,dispatcher,email
```
**Required columns:**
- `email` - User email address
- `role` - System role (field_agent, dispatcher, project_manager, etc.)
**Optional columns:**
- `first_name` - First name (for personalization)
- `last_name` - Last name
- `phone` - Phone with country code (+254...)
- `invitation_method` - whatsapp, email, or both (default: whatsapp)
### Project-Level Invitations
For inviting users directly to a project with role assignments:
```csv
email,first_name,last_name,phone,role,invitation_method,project_role,region,subcontractor
john@example.com,John,Doe,+254712345678,field_agent,whatsapp,Installer,Nairobi West,
jane@example.com,Jane,Smith,+254798765432,dispatcher,email,Site Supervisor,,
```
**Additional columns for projects:**
- `project_role` - Role name or ID on the project (e.g., "Installer", "Technician")
- `region` - Region name or ID (optional, NULL = project-wide)
- `subcontractor` - Subcontractor name or ID (optional, NULL = main contractor)
## API Workflow
### Step 1: Analyze CSV
Upload CSV and get analysis of users:
```http
POST /api/v1/invitations/bulk/analyze
Content-Type: multipart/form-data
csv_file: <file>
project_id: <uuid> (OR client_id OR contractor_id)
```
**Response:**
```json
{
"total_rows": 50,
"valid_rows": 48,
"invalid_rows": 2,
"analysis": {
"existing_in_project": [
{
"email": "john@example.com",
"user_id": "uuid",
"name": "John Doe",
"current_role": "field_agent",
"status": "already_member"
}
],
"existing_not_in_project": [
{
"email": "jane@example.com",
"user_id": "uuid",
"name": "Jane Smith",
"current_role": "dispatcher",
"action": "add_to_project",
"csv_data": {...}
}
],
"new_users_to_invite": [
{
"email": "bob@example.com",
"action": "send_invitation",
"csv_data": {...}
}
],
"errors": [
{
"row": 5,
"email": "invalid-email",
"errors": ["Invalid email format"]
}
]
}
}
```
### Step 2: Review & Execute
Frontend displays analysis to user for review. User confirms, then:
```http
POST /api/v1/invitations/bulk/execute
Content-Type: application/json
{
"project_id": "uuid",
"users_to_add": [
{
"email": "jane@example.com",
"user_id": "uuid",
"csv_data": {...}
}
],
"users_to_invite": [
{
"email": "bob@example.com",
"csv_data": {...}
}
],
"bulk_operation_id": "BULK_20251211_123456"
}
```
**Response:**
```json
{
"results": {
"users_added": {
"success": 10,
"failed": 0,
"details": [...]
},
"invitations_sent": {
"success": 35,
"failed": 2,
"details": [...]
}
},
"summary": {
"total_processed": 47,
"successful": 45,
"failed": 2
}
}
```
## Download CSV Template
Get a pre-formatted CSV template:
```http
GET /api/v1/invitations/bulk/template/download?template_type=project
```
Template types:
- `organization` - For org-level invites (simpler)
- `project` - For project-level invites (includes project fields)
## Authorization
All roles with `invite_users` permission can use bulk invitations:
**Platform Admin:**
- Can bulk invite to any context (organization or project)
**Client Admin:**
- Can bulk invite to their client organization only
**Contractor Admin:**
- Can bulk invite to their contractor organization only
**Project Manager:**
- Can bulk invite to their own projects
- Must invite to their contractor's organization
**Dispatcher:**
- Can bulk invite to projects in their contractor
- Must invite to their contractor's organization
**Sales Manager:**
- Can bulk invite to projects in their contractor
- Must invite to their contractor's organization
**Note:** Service-level authorization validates that users can only invite within their scope (own organization/projects)
## Tracking
Bulk invitations are tracked in the `invitation_metadata` JSONB field:
```json
{
"bulk_import": true,
"bulk_operation_id": "BULK_20251211_123456"
}
```
This allows filtering/reporting on bulk vs individual invitations without needing a separate table.
## Validation Rules
- Email format validation
- Phone must start with + and country code
- Role must be valid enum value
- Project role/region/subcontractor must exist if specified
- Max 1000 rows per CSV (configurable via `MAX_BULK_INVITATION_ROWS` env var)
- Duplicate detection: won't create duplicate pending invitations
## Error Handling
- Invalid CSV rows are reported but don't block valid rows
- Each user operation (add/invite) is independent
- Partial success is supported (some succeed, some fail)
- Detailed error messages for each failure
## Frontend Flow
1. User uploads CSV
2. Call `/analyze` endpoint
3. Display categorized results:
- "10 users will be added to project"
- "35 invitations will be sent"
- "5 users already in project (skipped)"
- "2 errors found"
4. User reviews and optionally deselects users
5. User confirms
6. Call `/execute` endpoint with selected users
7. Display results with success/failure breakdown
## Implementation Notes
### No Database Table Needed
- Analysis results are returned in-memory (not persisted)
- Frontend manages the review/confirmation flow
- Bulk operations tracked via `invitation_metadata.bulk_operation_id` in existing `user_invitations` table
- Simpler architecture, no session cleanup needed
### Smart User Resolution
- Project roles, regions, and subcontractors can be specified by name or UUID
- Case-insensitive matching for names
- Validates that referenced entities exist and belong to the project
### Files Created
- `src/app/schemas/bulk_invitation.py` - Pydantic schemas
- `src/app/services/bulk_invitation_service.py` - Business logic
- `src/app/api/v1/bulk_invitations.py` - API endpoints
- Registered in `src/app/api/v1/router.py`
### Reuses Existing Infrastructure
- Uses existing `InvitationService` for sending invitations
- Uses existing `UserInvitation` model with metadata tracking
- Uses existing `ProjectTeam` model for adding users to projects
- No new database migrations required
|