kamau1's picture
fix: make user_id optional for self-service and auto-set before auth check; update schema, service, and docs
c5fdc5d
# Inventory API - Field Agent Quick Reference
## Base URL
`/api/v1/inventory`
---
## Field Agent Endpoints
### 1. Get My Inventory Stats
**GET** `/my-stats`
**Purpose:** Dashboard stats for field agents
**Response:**
```json
{
"user_id": "uuid",
"user_name": "John Doe",
"total_assignments": 25,
"active_assignments": 3,
"returned_count": 18,
"installed_count": 4,
"consumed_count": 0,
"by_item_type": {
"tool": 1,
"equipment": 2,
"consumable": 0,
"ppe": 0
}
}
```
---
### 2. Get My Current Inventory
**GET** `/my-inventory`
**Purpose:** See what equipment I currently have (not returned/installed/consumed)
**Response:**
```json
{
"items": [
{
"id": "uuid",
"unit_identifier": "ONT-12345",
"equipment_type": "ONT",
"equipment_name": "Huawei HG8546M",
"item_type": "equipment",
"issued_at": "2025-12-01T08:30:00Z",
"days_issued": 5,
"status": "issued",
"is_active": true,
"ticket_id": "uuid",
"ticket_reference": "TKT-001",
"region_name": "Nairobi West",
"notes": "For installation at customer site"
}
],
"total": 3,
"page": 1,
"page_size": 100,
"total_pages": 1
}
```
---
### 3. Get Available Inventory at Hub
**GET** `/regions/{region_id}/available`
**Purpose:** See what's available at my regional hub before going to collect
**Response:**
```json
{
"items": [
{
"id": "uuid",
"equipment_type": "ONT",
"equipment_name": "Huawei HG8546M",
"item_type": "equipment",
"quantity_available": 45.00,
"quantity_allocated": 100.00,
"quantity_issued": 55.00,
"region_name": "Nairobi West",
"allocated_date": "2025-11-15",
"serial_numbers": [...]
}
],
"total": 5,
"page": 1,
"page_size": 100,
"total_pages": 1
}
```
---
### 4. Record Collection from Hub
**POST** `/assignments`
**Purpose:** Record what I collected from the hub (self-service)
**Request:**
```json
{
"project_inventory_distribution_id": "uuid",
"unit_identifier": "ONT-12345",
"ticket_id": "uuid",
"notes": "Collected for TKT-001"
}
```
**Notes:**
- `user_id` is optional - auto-set to yourself for self-service
- Field agents can only record for themselves (admins/PMs can specify user_id for others)
- `unit_identifier` must be unique (serial number, box number, etc.)
- `ticket_id` is optional - link to ticket if you know which job it's for
**Response:**
```json
{
"id": "uuid",
"unit_identifier": "ONT-12345",
"equipment_type": "ONT",
"equipment_name": "Huawei HG8546M",
"item_type": "equipment",
"issued_at": "2025-12-01T10:30:00Z",
"issued_by_user_id": "uuid",
"status": "issued",
"is_active": true,
"days_issued": 0,
"ticket_id": "uuid",
"notes": "Collected for TKT-001"
}
```
---
### 5. Return Tool to Hub
**POST** `/assignments/{assignment_id}/return`
**Purpose:** Record tool return (for reusable tools only)
**Request:**
```json
{
"return_condition": "good",
"return_notes": "Tool in good condition"
}
```
**Valid conditions:** `good`, `damaged`, `lost`, `worn`
**Response:**
```json
{
"id": "uuid",
"unit_identifier": "DRILL-789",
"equipment_type": "Drill",
"item_type": "tool",
"issued_at": "2025-11-28T08:00:00Z",
"returned_at": "2025-12-01T17:00:00Z",
"return_condition": "good",
"is_returned": true,
"status": "returned",
"days_issued": 3
}
```
---
### 6. Mark Equipment as Installed
**POST** `/assignments/{assignment_id}/install`
**Purpose:** Mark equipment as installed at customer site (for equipment only)
**Request:**
```json
{
"ticket_id": "uuid",
"installation_notes": "Installed at customer premises"
}
```
**Response:**
```json
{
"id": "uuid",
"unit_identifier": "ONT-12345",
"equipment_type": "ONT",
"item_type": "equipment",
"issued_at": "2025-12-01T08:30:00Z",
"installed_at": "2025-12-01T14:30:00Z",
"status": "installed",
"is_active": false,
"days_issued": 0,
"ticket_id": "uuid"
}
```
---
### 7. Link Equipment to Ticket
**POST** `/assignments/{assignment_id}/link-ticket?ticket_id={ticket_id}`
**Purpose:** Link collected equipment to a specific ticket/job
**Query Params:**
- `ticket_id` (required): UUID of ticket to link to
**Response:**
```json
{
"id": "uuid",
"unit_identifier": "ONT-12345",
"ticket_id": "uuid",
"ticket_reference": "TKT-001",
"status": "issued",
"additional_metadata": {
"linked_to_ticket_at": "2025-12-01T10:45:00Z",
"linked_by_user_id": "uuid"
}
}
```
---
### 8. List My Assignments (with filters)
**GET** `/assignments?user_id={user_id}&status={status}&is_returned={bool}`
**Purpose:** View assignment history with filters
**Query Params:**
- `page` (default: 1)
- `page_size` (default: 50, max: 100)
- `user_id` (optional): Filter by user (field agents auto-filtered to self)
- `status` (optional): `issued`, `returned`, `installed`
- `is_returned` (optional): `true` or `false`
- `ticket_id` (optional): Filter by ticket
**Response:**
```json
{
"items": [...],
"total": 25,
"page": 1,
"page_size": 50,
"total_pages": 1
}
```
---
## Item Types & Workflows
### Tool (Returnable)
1. Collect from hub → `POST /assignments`
2. Use for job
3. Return to hub → `POST /assignments/{id}/return`
### Equipment (Installable)
1. Collect from hub → `POST /assignments`
2. Link to ticket → `POST /assignments/{id}/link-ticket`
3. Install at customer → `POST /assignments/{id}/install`
### Consumable (Single-use)
1. Collect from hub → `POST /assignments`
2. Use up (no return needed)
### PPE (Long-term)
1. Collect from hub → `POST /assignments`
2. Keep for extended period
---
## Error Responses
**400 Bad Request:**
```json
{
"detail": "No inventory available at this regional hub"
}
```
**403 Forbidden:**
```json
{
"detail": "Not authorized to record inventory collection at this region"
}
```
**404 Not Found:**
```json
{
"detail": "Assignment not found: {uuid}"
}
```
**409 Conflict:**
```json
{
"detail": "Unit ONT-12345 already assigned"
}
```
---
---
### 9. Initiate Transfer to Another Agent
**POST** `/assignments/{assignment_id}/transfer`
**Purpose:** Transfer equipment to another field agent (peer-to-peer)
**Request:**
```json
{
"to_user_id": "uuid",
"transfer_reason": "Agent B needs ONT urgently, I have extra",
"requires_approval": true,
"transfer_latitude": -1.2921,
"transfer_longitude": 36.8219,
"notes": "Meeting at regional office"
}
```
**Response:**
```json
{
"id": "uuid",
"from_assignment_id": "uuid",
"from_user_id": "uuid",
"to_user_id": "uuid",
"unit_identifier": "ONT-12345",
"transfer_reason": "Agent B needs ONT urgently, I have extra",
"status": "pending",
"requires_approval": true,
"created_at": "2025-12-01T10:00:00Z"
}
```
---
### 10. Accept Transfer
**POST** `/transfers/{transfer_id}/accept`
**Purpose:** Accept equipment transfer from another agent
**Response:**
```json
{
"id": "uuid",
"status": "completed",
"to_assignment_id": "uuid",
"accepted_by_to_user_at": "2025-12-01T10:30:00Z",
"completed_at": "2025-12-01T10:30:00Z"
}
```
---
### 11. Get My Pending Transfers
**GET** `/transfers/pending`
**Purpose:** See transfers waiting for my acceptance
**Response:**
```json
{
"incoming": [
{
"id": "uuid",
"from_user_name": "John Doe",
"unit_identifier": "ONT-12345",
"equipment_name": "Huawei HG8546M",
"transfer_reason": "You need this for urgent job",
"status": "approved",
"created_at": "2025-12-01T09:00:00Z"
}
],
"outgoing": [
{
"id": "uuid",
"to_user_name": "Jane Smith",
"unit_identifier": "DRILL-789",
"equipment_name": "Power Drill",
"status": "pending",
"created_at": "2025-12-01T08:00:00Z"
}
]
}
```
---
## Authorization
All endpoints require authentication. Field agents can only:
- View their own assignments
- Record their own collections
- Return their own items
- View available inventory at hubs in their project
- Initiate transfers of their own equipment
- Accept transfers sent to them
Admins/PMs can perform actions on behalf of any user and approve transfers.