# API Reference - ERP Construccion

Referencia completa de endpoints REST.

**Base URL:** `http://localhost:3000/api/v1`

---

## Autenticacion

Todas las rutas (excepto login/register) requieren header:

```http
Authorization: Bearer <access_token>
```

---

## Auth Endpoints

### POST /auth/login

Autenticar usuario.

**Request:**
```json
{
  "email": "user@example.com",
  "password": "securePassword123"
}
```

**Response 200:**
```json
{
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "firstName": "Juan",
    "lastName": "Perez",
    "role": "admin"
  },
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
  "expiresIn": 900
}
```

**Response 401:**
```json
{
  "error": "Unauthorized",
  "message": "Invalid credentials"
}
```

---

### POST /auth/register

Registrar nuevo usuario.

**Request:**
```json
{
  "email": "nuevo@example.com",
  "password": "securePassword123",
  "firstName": "Maria",
  "lastName": "Lopez",
  "tenantId": "tenant-uuid"
}
```

**Response 201:**
```json
{
  "user": {
    "id": "new-uuid",
    "email": "nuevo@example.com",
    "firstName": "Maria",
    "lastName": "Lopez",
    "role": "viewer"
  },
  "accessToken": "...",
  "refreshToken": "...",
  "expiresIn": 900
}
```

---

### POST /auth/refresh

Renovar access token.

**Request:**
```json
{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}
```

**Response 200:**
```json
{
  "accessToken": "new-access-token",
  "refreshToken": "new-refresh-token",
  "expiresIn": 900
}
```

---

### POST /auth/logout

Revocar refresh token.

**Request:**
```json
{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}
```

**Response 200:**
```json
{
  "success": true
}
```

---

### POST /auth/change-password

Cambiar password del usuario autenticado.

**Headers:**
```
Authorization: Bearer <access_token>
```

**Request:**
```json
{
  "currentPassword": "oldPassword123",
  "newPassword": "newSecurePassword456"
}
```

**Response 200:**
```json
{
  "success": true
}
```

---

## Conceptos Endpoints

### GET /conceptos

Listar conceptos con paginacion.

**Query Parameters:**
| Param | Tipo | Default | Descripcion |
|-------|------|---------|-------------|
| `page` | number | 1 | Pagina actual |
| `limit` | number | 20 | Items por pagina |
| `search` | string | - | Buscar por codigo/nombre |
| `parentId` | uuid | - | Filtrar por padre |

**Response 200:**
```json
{
  "data": [
    {
      "id": "uuid-1",
      "code": "01",
      "name": "Preliminares",
      "unit": "PZA",
      "unitPrice": 0,
      "level": 0,
      "path": "01",
      "isActive": true
    },
    {
      "id": "uuid-2",
      "code": "01.01",
      "name": "Trazo y nivelacion",
      "unit": "M2",
      "unitPrice": 25.50,
      "level": 1,
      "path": "01/01",
      "parentId": "uuid-1",
      "isActive": true
    }
  ],
  "total": 150,
  "page": 1,
  "limit": 20,
  "totalPages": 8
}
```

---

### GET /conceptos/:id

Obtener concepto por ID.

**Response 200:**
```json
{
  "id": "uuid-1",
  "code": "01",
  "name": "Preliminares",
  "description": "Trabajos preliminares de obra",
  "unit": "PZA",
  "unitPrice": 0,
  "level": 0,
  "path": "01",
  "isActive": true,
  "createdAt": "2025-01-01T00:00:00Z",
  "updatedAt": "2025-01-01T00:00:00Z"
}
```

**Response 404:**
```json
{
  "error": "Not Found",
  "message": "Concepto not found"
}
```

---

### POST /conceptos

Crear nuevo concepto.

**Request:**
```json
{
  "code": "01.02",
  "name": "Demoliciones",
  "description": "Trabajos de demolicion",
  "unit": "M3",
  "unitPrice": 150.00,
  "parentId": "uuid-1"
}
```

**Response 201:**
```json
{
  "id": "new-uuid",
  "code": "01.02",
  "name": "Demoliciones",
  "description": "Trabajos de demolicion",
  "unit": "M3",
  "unitPrice": 150.00,
  "level": 1,
  "path": "01/02",
  "parentId": "uuid-1",
  "isActive": true,
  "createdAt": "2025-01-15T10:30:00Z"
}
```

---

### GET /conceptos/tree

Obtener arbol de conceptos.

**Query Parameters:**
| Param | Tipo | Descripcion |
|-------|------|-------------|
| `rootId` | uuid | ID del nodo raiz (opcional) |

**Response 200:**
```json
{
  "data": [
    {
      "id": "uuid-1",
      "code": "01",
      "name": "Preliminares",
      "level": 0,
      "children": [
        {
          "id": "uuid-2",
          "code": "01.01",
          "name": "Trazo y nivelacion",
          "level": 1,
          "children": []
        },
        {
          "id": "uuid-3",
          "code": "01.02",
          "name": "Demoliciones",
          "level": 1,
          "children": []
        }
      ]
    }
  ]
}
```

---

## Presupuestos Endpoints

### GET /presupuestos

Listar presupuestos.

**Query Parameters:**
| Param | Tipo | Descripcion |
|-------|------|-------------|
| `fraccionamientoId` | uuid | Filtrar por proyecto |
| `status` | string | draft/submitted/approved |
| `page` | number | Pagina |
| `limit` | number | Items por pagina |

**Response 200:**
```json
{
  "data": [
    {
      "id": "uuid-1",
      "code": "PPTO-2025-001",
      "name": "Presupuesto Casa Tipo A",
      "version": 1,
      "status": "approved",
      "totalAmount": 1500000.00,
      "fraccionamiento": {
        "id": "frac-uuid",
        "name": "Residencial Los Pinos"
      },
      "approvedAt": "2025-01-10T15:00:00Z"
    }
  ],
  "total": 25,
  "page": 1,
  "limit": 20,
  "totalPages": 2
}
```

---

### GET /presupuestos/:id

Obtener presupuesto con partidas.

**Response 200:**
```json
{
  "id": "uuid-1",
  "code": "PPTO-2025-001",
  "name": "Presupuesto Casa Tipo A",
  "version": 1,
  "status": "approved",
  "totalAmount": 1500000.00,
  "partidas": [
    {
      "id": "partida-1",
      "concepto": {
        "id": "concepto-uuid",
        "code": "01.01",
        "name": "Trazo y nivelacion",
        "unit": "M2"
      },
      "quantity": 120.00,
      "unitPrice": 25.50,
      "totalAmount": 3060.00
    }
  ],
  "fraccionamiento": {
    "id": "frac-uuid",
    "name": "Residencial Los Pinos"
  },
  "createdAt": "2025-01-01T00:00:00Z",
  "approvedAt": "2025-01-10T15:00:00Z",
  "approvedBy": {
    "id": "user-uuid",
    "firstName": "Juan",
    "lastName": "Director"
  }
}
```

---

### POST /presupuestos

Crear presupuesto.

**Request:**
```json
{
  "code": "PPTO-2025-002",
  "name": "Presupuesto Casa Tipo B",
  "fraccionamientoId": "frac-uuid"
}
```

**Response 201:**
```json
{
  "id": "new-uuid",
  "code": "PPTO-2025-002",
  "name": "Presupuesto Casa Tipo B",
  "version": 1,
  "status": "draft",
  "totalAmount": 0,
  "fraccionamientoId": "frac-uuid",
  "createdAt": "2025-01-15T10:30:00Z"
}
```

---

### POST /presupuestos/:id/partidas

Agregar partida a presupuesto.

**Request:**
```json
{
  "conceptoId": "concepto-uuid",
  "quantity": 100.00,
  "unitPrice": 25.50
}
```

**Response 201:**
```json
{
  "id": "partida-uuid",
  "presupuestoId": "presupuesto-uuid",
  "conceptoId": "concepto-uuid",
  "quantity": 100.00,
  "unitPrice": 25.50,
  "totalAmount": 2550.00
}
```

---

### POST /presupuestos/:id/approve

Aprobar presupuesto.

**Response 200:**
```json
{
  "id": "presupuesto-uuid",
  "status": "approved",
  "approvedAt": "2025-01-15T12:00:00Z",
  "approvedById": "user-uuid"
}
```

---

### POST /presupuestos/:id/version

Crear nueva version del presupuesto.

**Response 201:**
```json
{
  "id": "new-version-uuid",
  "code": "PPTO-2025-001",
  "name": "Presupuesto Casa Tipo A",
  "version": 2,
  "status": "draft",
  "totalAmount": 1500000.00,
  "partidas": [...]
}
```

---

## Avances Endpoints

### GET /avances

Listar avances de obra.

**Query Parameters:**
| Param | Tipo | Descripcion |
|-------|------|-------------|
| `loteId` | uuid | Filtrar por lote |
| `departamentoId` | uuid | Filtrar por departamento |
| `status` | string | captured/reviewed/approved/rejected |
| `dateFrom` | date | Fecha desde |
| `dateTo` | date | Fecha hasta |

**Response 200:**
```json
{
  "data": [
    {
      "id": "avance-uuid",
      "lote": {
        "id": "lote-uuid",
        "number": "L-001"
      },
      "concepto": {
        "id": "concepto-uuid",
        "code": "02.01",
        "name": "Cimentacion",
        "unit": "M3"
      },
      "quantity": 15.50,
      "progressDate": "2025-01-15",
      "status": "approved",
      "capturedBy": {
        "firstName": "Pedro",
        "lastName": "Residente"
      }
    }
  ],
  "total": 150,
  "page": 1,
  "limit": 20,
  "totalPages": 8
}
```

---

### POST /avances

Registrar avance de obra.

**Request:**
```json
{
  "loteId": "lote-uuid",
  "conceptoId": "concepto-uuid",
  "quantity": 15.50,
  "progressDate": "2025-01-15",
  "notes": "Cimentacion completada"
}
```

**Response 201:**
```json
{
  "id": "new-avance-uuid",
  "loteId": "lote-uuid",
  "conceptoId": "concepto-uuid",
  "quantity": 15.50,
  "progressDate": "2025-01-15",
  "status": "captured",
  "capturedById": "user-uuid",
  "notes": "Cimentacion completada",
  "createdAt": "2025-01-15T14:30:00Z"
}
```

---

### POST /avances/:id/fotos

Agregar foto a avance.

**Request (multipart/form-data):**
```
file: <archivo imagen>
description: "Vista frontal de cimentacion"
latitude: 20.123456
longitude: -99.654321
```

**Response 201:**
```json
{
  "id": "foto-uuid",
  "avanceObraId": "avance-uuid",
  "fileName": "IMG_20250115_143000.jpg",
  "filePath": "/uploads/avances/2025/01/IMG_20250115_143000.jpg",
  "fileSize": 2048576,
  "mimeType": "image/jpeg",
  "latitude": 20.123456,
  "longitude": -99.654321,
  "description": "Vista frontal de cimentacion",
  "takenAt": "2025-01-15T14:30:00Z"
}
```

---

### POST /avances/:id/review

Revisar avance (workflow).

**Response 200:**
```json
{
  "id": "avance-uuid",
  "status": "reviewed",
  "reviewedAt": "2025-01-15T16:00:00Z",
  "reviewedById": "supervisor-uuid"
}
```

---

### POST /avances/:id/approve

Aprobar avance (workflow).

**Response 200:**
```json
{
  "id": "avance-uuid",
  "status": "approved",
  "approvedAt": "2025-01-15T17:00:00Z",
  "approvedById": "manager-uuid"
}
```

---

### POST /avances/:id/reject

Rechazar avance (workflow).

**Request:**
```json
{
  "reason": "Cantidad incorrecta, verificar medicion"
}
```

**Response 200:**
```json
{
  "id": "avance-uuid",
  "status": "rejected",
  "rejectedAt": "2025-01-15T16:30:00Z",
  "rejectedById": "supervisor-uuid",
  "rejectionReason": "Cantidad incorrecta, verificar medicion"
}
```

---

## Bitacora Endpoints

### GET /bitacora/:fraccionamientoId

Obtener entradas de bitacora.

**Query Parameters:**
| Param | Tipo | Descripcion |
|-------|------|-------------|
| `dateFrom` | date | Fecha desde |
| `dateTo` | date | Fecha hasta |

**Response 200:**
```json
{
  "data": [
    {
      "id": "bitacora-uuid",
      "entryNumber": 125,
      "entryDate": "2025-01-15",
      "weather": "Soleado",
      "temperature": 28.5,
      "workersCount": 45,
      "activities": "Colado de cimentacion lotes 15-20",
      "incidents": "Ninguno",
      "observations": "Se requiere mas cemento para manana",
      "createdBy": {
        "firstName": "Pedro",
        "lastName": "Residente"
      }
    }
  ],
  "total": 125,
  "page": 1,
  "limit": 20,
  "totalPages": 7
}
```

---

### POST /bitacora

Crear entrada de bitacora.

**Request:**
```json
{
  "fraccionamientoId": "frac-uuid",
  "entryDate": "2025-01-15",
  "weather": "Soleado",
  "temperature": 28.5,
  "workersCount": 45,
  "activities": "Colado de cimentacion lotes 15-20",
  "incidents": "Ninguno",
  "observations": "Se requiere mas cemento para manana"
}
```

**Response 201:**
```json
{
  "id": "new-bitacora-uuid",
  "entryNumber": 126,
  "entryDate": "2025-01-15",
  "weather": "Soleado",
  "temperature": 28.5,
  "workersCount": 45,
  "activities": "Colado de cimentacion lotes 15-20",
  "createdById": "user-uuid",
  "createdAt": "2025-01-15T18:00:00Z"
}
```

---

## Estimaciones Endpoints

### GET /estimaciones

Listar estimaciones.

**Query Parameters:**
| Param | Tipo | Descripcion |
|-------|------|-------------|
| `contratoId` | uuid | Filtrar por contrato |
| `status` | string | draft/submitted/reviewed/approved/rejected |

**Response 200:**
```json
{
  "data": [
    {
      "id": "est-uuid",
      "number": 5,
      "periodStart": "2025-01-01",
      "periodEnd": "2025-01-15",
      "status": "approved",
      "subtotal": 500000.00,
      "iva": 80000.00,
      "retentions": 25000.00,
      "amortization": 10000.00,
      "totalAmount": 545000.00,
      "contrato": {
        "id": "contrato-uuid",
        "number": "CTR-2025-001"
      }
    }
  ],
  "total": 5,
  "page": 1,
  "limit": 20,
  "totalPages": 1
}
```

---

### GET /estimaciones/:id

Obtener estimacion con detalles.

**Response 200:**
```json
{
  "id": "est-uuid",
  "number": 5,
  "periodStart": "2025-01-01",
  "periodEnd": "2025-01-15",
  "status": "approved",
  "subtotal": 500000.00,
  "iva": 80000.00,
  "retentions": 25000.00,
  "amortization": 10000.00,
  "totalAmount": 545000.00,
  "conceptos": [
    {
      "id": "est-concepto-uuid",
      "concepto": {
        "code": "02.01",
        "name": "Cimentacion",
        "unit": "M3"
      },
      "contractQuantity": 1000.00,
      "previousQuantity": 400.00,
      "currentQuantity": 150.00,
      "accumulatedQuantity": 550.00,
      "pendingQuantity": 450.00,
      "unitPrice": 1200.00,
      "currentAmount": 180000.00,
      "accumulatedAmount": 660000.00,
      "generadores": [
        {
          "description": "Lotes 15-20",
          "length": 10.00,
          "width": 5.00,
          "height": 0.30,
          "quantity": 6,
          "partial": 90.00
        }
      ]
    }
  ],
  "workflow": [
    {
      "fromStatus": "draft",
      "toStatus": "submitted",
      "changedAt": "2025-01-16T10:00:00Z",
      "changedBy": {
        "firstName": "Pedro",
        "lastName": "Residente"
      }
    }
  ]
}
```

---

### POST /estimaciones

Crear estimacion.

**Request:**
```json
{
  "contratoId": "contrato-uuid",
  "periodStart": "2025-01-16",
  "periodEnd": "2025-01-31"
}
```

**Response 201:**
```json
{
  "id": "new-est-uuid",
  "number": 6,
  "contratoId": "contrato-uuid",
  "periodStart": "2025-01-16",
  "periodEnd": "2025-01-31",
  "status": "draft",
  "subtotal": 0,
  "totalAmount": 0,
  "createdAt": "2025-01-16T09:00:00Z"
}
```

---

### POST /estimaciones/:id/conceptos

Agregar concepto a estimacion.

**Request:**
```json
{
  "conceptoId": "concepto-uuid",
  "contractQuantity": 1000.00,
  "currentQuantity": 150.00,
  "unitPrice": 1200.00
}
```

**Response 201:**
```json
{
  "id": "new-est-concepto-uuid",
  "estimacionId": "est-uuid",
  "conceptoId": "concepto-uuid",
  "contractQuantity": 1000.00,
  "previousQuantity": 550.00,
  "currentQuantity": 150.00,
  "accumulatedQuantity": 700.00,
  "pendingQuantity": 300.00,
  "unitPrice": 1200.00,
  "currentAmount": 180000.00,
  "accumulatedAmount": 840000.00
}
```

---

### POST /estimaciones/:id/submit

Enviar estimacion para revision.

**Response 200:**
```json
{
  "id": "est-uuid",
  "status": "submitted",
  "submittedAt": "2025-01-20T10:00:00Z",
  "submittedById": "user-uuid"
}
```

---

### POST /estimaciones/:id/approve

Aprobar estimacion.

**Response 200:**
```json
{
  "id": "est-uuid",
  "status": "approved",
  "approvedAt": "2025-01-21T15:00:00Z",
  "approvedById": "director-uuid"
}
```

---

## Codigos de Error

| Codigo | Descripcion |
|--------|-------------|
| 400 | Bad Request - Datos invalidos |
| 401 | Unauthorized - Token invalido o expirado |
| 403 | Forbidden - Sin permisos |
| 404 | Not Found - Recurso no encontrado |
| 409 | Conflict - Conflicto (ej: duplicado) |
| 422 | Unprocessable Entity - Validacion fallida |
| 500 | Internal Server Error |

### Formato de Error

```json
{
  "error": "Bad Request",
  "message": "Validation failed",
  "details": [
    {
      "field": "email",
      "message": "Invalid email format"
    }
  ]
}
```

---

## Rate Limiting

| Tipo | Limite |
|------|--------|
| Login | 5 requests/min por IP |
| API General | 100 requests/min por usuario |
| Uploads | 10 requests/min por usuario |

**Headers de respuesta:**
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1610000000
```

---

**Ultima actualizacion:** 2025-12-12
