# Command Group 2: Numbers

Manage phone number inventory.

### `numbers list`

List all phone numbers in the tenant inventory.

```
teams-phone numbers list [OPTIONS]
```

**Options:**
| Option | Description |
|--------|-------------|
| `--status <status>` | Filter by status: `assigned`, `unassigned`, `reserved` |
| `--type <type>` | Filter by number type: `calling-plan`, `direct-routing`, `operator-connect` |
| `--city <city>` | Filter by city/location |
| `--assigned-to <user>` | Filter by assigned user (UPN, display name, or object ID) |
| `--limit <n>` | Limit results (default: 100) |
| `--all` | Fetch all numbers (may be slow for large inventories) |

**Validation:**
- If both `--limit` and `--all` are provided → error: "Cannot specify both --limit and --all"

**Output Fields:**
- Phone Number (E.164 format)
- Status (Assigned/Unassigned/Reserved)
- Type (Calling Plan/Direct Routing/Operator Connect)
- Assigned To (user or "—")
- City/Location
- Capabilities (User/Service/Conference)

**Example:**
```bash
# List all phone numbers
teams-phone numbers list

# List only unassigned Calling Plan numbers
teams-phone numbers list --status unassigned --type calling-plan

# List all numbers in Seattle
teams-phone numbers list --city Seattle --all
```

---

### `numbers show <number>`

Show detailed information for a specific phone number.

```
teams-phone numbers show <number> [OPTIONS]
```

**Arguments:**
| Argument | Description |
|----------|-------------|
| `<number>` | Phone number (E.164 or partial) |

**Output Sections:**
1. **Number Details**: Full E.164 number, formatted display, operator ID
2. **Assignment**: Status, assigned user (if any), assignment date, assignment category (primary/private/alternate)
3. **Activation**: Activation state (activated/assignmentPending/assignmentFailed/updatePending/updateFailed)
4. **Source**: Number type, acquisition date, source details (online/onPremises)
5. **Port Status**: Port-in status (if applicable): completed, firmOrderCommitmentAccepted, or N/A
6. **Capabilities**: User assignment, service assignment, conferencing
7. **Location**: City, state/region, country, emergency location ID (if assigned)
8. **Network**: Network site ID (if assigned, for Location-Based Routing)

**Notes:**
- If multiple numbers match a partial input, return an error and list the matches.

**Example:**
```bash
# Show number details
teams-phone numbers show +12065551234

# Show by partial number (last 4 digits)
teams-phone numbers show 1234
```

---

### `numbers search <pattern>`

Search phone numbers by pattern.

```
teams-phone numbers search <pattern> [OPTIONS]
```

**Arguments:**
| Argument | Description |
|----------|-------------|
| `<pattern>` | Search pattern (supports partial matching, wildcards) |

**Options:**
| Option | Description |
|--------|-------------|
| `--status <status>` | Filter results by status |
| `--assigned-to <user>` | Limit results to numbers assigned to a specific user |
| `--limit <n>` | Maximum results (default: 25) |

**Search Patterns:**
- Last N digits: `1234` matches `+12065551234`
- Area code: `206*` matches all 206 numbers
- Full number: `+12065551234` exact match
- Wildcard: `*555*` matches numbers containing 555

**Example:**
```bash
# Search by last 4 digits
teams-phone numbers search 5678

# Search by area code, unassigned only
teams-phone numbers search "206*" --status unassigned

# Search for pattern
teams-phone numbers search "*555*"
```

---

### `numbers assign <user> <number> [location]`

Assign a phone number to a user with emergency location.

```
teams-phone numbers assign <user> <number> [location] [OPTIONS]
```

**Arguments:**
| Argument | Description |
|----------|-------------|
| `<user>` | User identifier (UPN, display name, or object ID) |
| `<number>` | Phone number to assign (E.164 format: +12065551234) |
| `[location]` | Emergency location (ID or name). **Required for Calling Plan numbers** (E911 regulations). Optional for Direct Routing (can be set later via `numbers update`). Required unless default configured. |

**Options:**
| Option | Description |
|--------|-------------|
| `--location <loc>` | Emergency location (alternative to positional argument) |
| `--dry-run` | Preview the assignment without making changes |
| `--force` | Skip confirmation prompt |
| `--wait` | Wait for operation to complete (default: true) |
| `--no-wait` | Return immediately after submitting (async mode) |
| `--timeout <seconds>` | Maximum wait time (default: 60) |

**Async Operation Behavior:**

This command uses the Graph API `assignNumber` endpoint which returns `202 Accepted` and operates asynchronously:

1. **Request submitted** → API returns operation ID
2. **Polling** → CLI polls `/operations/{id}` endpoint every 2-5 seconds
3. **Terminal states** → `succeeded`, `failed`, or `skipped`
4. **Default behavior** → CLI waits for completion (up to 60s timeout)
5. **Non-blocking mode** → Use `--no-wait` to return immediately with operation ID

**Progress Display:**
- Shows spinner/progress indicator while waiting
- Displays final status: ✓ Success or ✗ Failed with error details
- With `--verbose`: shows polling attempts and operation state transitions

**Phone Number Format:**
- Input accepts E.164 format: `+12065551234`
- API requires digits only (no `+`): `12065551234`
- CLI automatically normalizes format before API call

**Validations:**
- User must have Teams Phone license
- Number must be unassigned and have `userAssignment` capability
- Number must be in tenant inventory
- Emergency location must exist (validated against CSV cache if available)

**Number Type Specific Requirements:**
- **Calling Plan (US/Canada)**: Emergency location is REQUIRED (E911 regulatory requirement). API call will fail without locationId.
- **Calling Plan (EMEA)**: Emergency location is REQUIRED at number acquisition/porting time.
- **Direct Routing**: Emergency location is OPTIONAL. Can be assigned without location and set later via `numbers update`.
- **Operator Connect**: Emergency location requirement varies by provider (typically required).

**Note on API vs Enforcement:** The Graph API schema marks `locationId` as optional, but backend validation enforces it for Calling Plan numbers due to E911 regulations. The CLI detects number type and enforces location requirement accordingly.

**Location Resolution:**
1. If both `[location]` and `--location` are provided and differ → error: "Conflicting locations specified"
2. If both are provided and match → use the provided value
3. If only one is provided → use it
4. Else if `default_location` configured for tenant → use it
5. Else if number type is Calling Plan or Operator Connect → error: "Emergency location required for Calling Plan numbers (E911 regulations)" with list of available locations (exit code 5)
6. Else (Direct Routing) → proceed without location (can be set later via `numbers update`)

**Location Lookup:**
- Location can be specified by ID (UUID) or name (case-insensitive partial match)
- If name matches multiple locations → error with candidate list
- If location not found → error: "Location not found: <name>" with suggestions from `locations search`
- If location exists but is not validated → warning displayed, assignment proceeds

**Example:**
```bash
# Assign number with location
teams-phone numbers assign john.doe@contoso.com +12065551234 "Seattle-HQ"

# Assign using --location flag
teams-phone numbers assign john.doe@contoso.com +12065551234 --location "Seattle-HQ"

# Assign using default location from config
teams-phone numbers assign john.doe@contoso.com +12065551234

# Preview assignment
teams-phone numbers assign john.doe@contoso.com +12065551234 "Seattle-HQ" --dry-run

# Assign without confirmation prompt
teams-phone numbers assign john.doe@contoso.com +12065551234 "Seattle-HQ" --force
```

---

### `numbers unassign <number>`

Remove phone number assignment from a user.

```
teams-phone numbers unassign <number> [OPTIONS]
```

**Arguments:**
| Argument | Description |
|----------|-------------|
| `<number>` | Phone number to unassign (E.164 format: +12065551234) |

**Options:**
| Option | Description |
|--------|-------------|
| `--dry-run` | Preview the unassignment without making changes |
| `--force` | Skip confirmation prompt |
| `--wait` | Wait for operation to complete (default: true) |
| `--no-wait` | Return immediately after submitting (async mode) |
| `--timeout <seconds>` | Maximum wait time (default: 60) |

**Async Operation Behavior:**

This command uses the Graph API `unassignNumber` endpoint which returns `202 Accepted` and operates asynchronously:

1. **Request submitted** → API returns operation ID
2. **Polling** → CLI polls `/operations/{id}` endpoint every 2-5 seconds
3. **Terminal states** → `succeeded`, `failed`, or `skipped`
4. **Default behavior** → CLI waits for completion (up to 60s timeout)

**Phone Number Format:**
- Input accepts E.164 format: `+12065551234`
- API requires digits only (no `+`): `12065551234`
- CLI automatically normalizes format before API call

**Validations:**
- Number must be currently assigned to a user
- Does NOT require user ID (API determines from number)

**Example:**
```bash
# Unassign number (waits for completion)
teams-phone numbers unassign +12065551234

# Preview unassignment
teams-phone numbers unassign +12065551234 --dry-run

# Unassign without waiting
teams-phone numbers unassign +12065551234 --no-wait
```

---

### `numbers update <number>`

Update phone number settings (location, network site).

```
teams-phone numbers update <number> [OPTIONS]
```

**Arguments:**
| Argument | Description |
|----------|-------------|
| `<number>` | Phone number to update (E.164 format: +12065551234) |

**Options:**
| Option | Description |
|--------|-------------|
| `--location <loc>` | Update emergency location (ID or name) |
| `--clear-location` | Remove emergency location assignment |
| `--network-site <site>` | Update network site ID (for Location-Based Routing) |
| `--clear-network-site` | Remove network site assignment |
| `--dry-run` | Preview the update without making changes |
| `--force` | Skip confirmation prompt |

**Operation Behavior:**

This command uses the Graph API `updateNumber` endpoint which is **synchronous** (unlike assign/unassign):

1. **Request submitted** → API returns `200 OK` immediately
2. **No polling required** → Changes are applied synchronously
3. **Instant feedback** → Success or error returned immediately

**Phone Number Format:**
- Input accepts E.164 format: `+12065551234`
- API requires E.164 format with `+` prefix (unlike assign/unassign)
- CLI automatically normalizes format before API call

**Clear vs Update Behavior:**
- `--location <loc>` → Sets location to specified value
- `--clear-location` → Sets location to empty string (removes assignment)
- Omit both → Location remains unchanged
- Same logic applies to network site

**Validations:**
- Number must exist in tenant inventory
- Number must be assigned to a user (cannot update unassigned numbers)
- Emergency location must exist (validated against CSV cache if available)

**Example:**
```bash
# Update emergency location
teams-phone numbers update +12065551234 --location "Seattle-HQ"

# Remove location assignment
teams-phone numbers update +12065551234 --clear-location

# Update network site (for Location-Based Routing)
teams-phone numbers update +12065551234 --network-site "site-seattle-01"

# Preview update
teams-phone numbers update +12065551234 --location "Seattle-HQ" --dry-run

# Update both location and network site
teams-phone numbers update +12065551234 --location "Seattle-HQ" --network-site "site-seattle-01"
```

**Notes:**
- Network sites are used for Location-Based Routing (LBR) scenarios
- If you don't use LBR, you can ignore the network site options
- This is faster than unassigning and reassigning a number to change location

---

### `numbers bulk-assign <csv-file>`

Bulk assign phone numbers from a CSV file.

```
teams-phone numbers bulk-assign <csv-file> [OPTIONS]
```

**Arguments:**
| Argument | Description |
|----------|-------------|
| `<csv-file>` | Path to CSV file with assignments |

**Options:**
| Option | Description |
|--------|-------------|
| `--dry-run` | Validate and preview all assignments without executing |
| `--continue-on-error` | Continue processing after failures |
| `--retry-failed <file>` | Retry only failed assignments from previous run |
| `--output <file>` | Write results to file (CSV or JSON based on extension) |
| `--default-location <loc>` | Default location for rows without location column |

**CSV Format:**
```csv
user,phone_number,location
john.doe@contoso.com,+12065551234,Seattle-HQ
jane.smith@contoso.com,+12065555678,Portland-Office
bob.wilson@contoso.com,+14255551234,Seattle-HQ
```

**Location Resolution (per row):**
1. If `location` column present and non-empty → use it
2. Else if `--default-location` flag provided → use it
3. Else if `default_location` configured for tenant → use it
4. Else → row fails validation

**Progress Display:**
- Live progress bar showing completion percentage
- Real-time success/failure count
- Per-line status updates
- Final summary with success/failure breakdown

**Example:**
```bash
# Preview bulk assignment
teams-phone numbers bulk-assign assignments.csv --dry-run

# Execute bulk assignment
teams-phone numbers bulk-assign assignments.csv

# Execute with explicit default location for rows missing location
teams-phone numbers bulk-assign assignments.csv --default-location "Seattle-HQ"

# Continue on errors and save results
teams-phone numbers bulk-assign assignments.csv --continue-on-error --output results.csv

# Retry only failed assignments
teams-phone numbers bulk-assign assignments.csv --retry-failed failed.csv
```

---

