1643 lines
No EOL
39 KiB
Markdown
1643 lines
No EOL
39 KiB
Markdown
# API V2 — Documentación de endpoints
|
|
|
|
**Base URL real:** `/2.0`
|
|
**Base URL mock:** `/2.0-mock` *(sin autenticación, datos de ejemplo)*
|
|
|
|
> Las rutas protegidas requieren el header `Authorization: Bearer {token}` obtenido en `/login`.
|
|
> Todas las respuestas son `Content-Type: application/json`.
|
|
|
|
---
|
|
|
|
## Índice
|
|
|
|
1. [Auth](#1-auth)
|
|
2. [People (abonado)](#2-people-abonado)
|
|
3. [Activities (actividades)](#3-activities-actividades)
|
|
4. [Booking (reservas — app)](#4-booking-reservas--app)
|
|
5. [Payments](#5-payments)
|
|
6. [Wallet (monedero)](#6-wallet-monedero)
|
|
7. [Search (búsqueda)](#7-search-búsqueda)
|
|
8. [Members (socios — admin)](#8-members-socios--admin)
|
|
9. [Courses (cursos — admin)](#9-courses-cursos--admin)
|
|
10. [Bills (recibos — admin)](#10-bills-recibos--admin)
|
|
11. [Booking Admin (reservas — admin)](#11-booking-admin-reservas--admin)
|
|
12. [Cash (caja — admin)](#12-cash-caja--admin)
|
|
13. [Dayoff / Celebrations](#13-dayoff--celebrations)
|
|
14. [Remittance (remesas especiales)](#14-remittance-remesas-especiales)
|
|
15. [Inscriptions (preinscripciones)](#15-inscriptions-preinscripciones)
|
|
16. [Admin Misc](#16-admin-misc)
|
|
17. [Printer](#17-printer)
|
|
18. [Hash (público)](#18-hash-público)
|
|
|
|
---
|
|
|
|
## 1. Auth
|
|
|
|
### `POST /login`
|
|
|
|
Autentica al usuario y devuelve un token Bearer.
|
|
|
|
**Body (form/JSON)**
|
|
|
|
| Campo | Tipo | Descripción |
|
|
|----------|--------|------------------|
|
|
| email | string | Email del abonado |
|
|
| password | string | Contraseña |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"access_token": "4Km9xQzLp2VnRtYwEoJbFsUcXgHdAiMkNlOqPrSvTu"
|
|
}
|
|
```
|
|
|
|
**Respuesta 401**
|
|
```json
|
|
{
|
|
"message": "Contraseña incorrecta."
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /forgot`
|
|
|
|
Envía un email de recuperación de contraseña.
|
|
|
|
**Body**
|
|
|
|
| Campo | Tipo |
|
|
|-------|--------|
|
|
| email | string |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"error": "Se le ha enviado un email con instrucciones"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /logout` 🔒
|
|
|
|
Cierra la sesión del usuario autenticado.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"logout": "ok"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 2. People (abonado)
|
|
|
|
### `GET /people/me` 🔒
|
|
|
|
Devuelve los datos del abonado autenticado.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"member": "00042",
|
|
"family": 1,
|
|
"first_name": "María",
|
|
"last_name": "García López",
|
|
"email": "maria@example.com",
|
|
"phone": "612345678",
|
|
"dni": "12345678A",
|
|
"birth_date": "15/03/1985",
|
|
"address": "Calle Mayor 12",
|
|
"city": "Madrid",
|
|
"zip": "28001",
|
|
"type": "FAMILIAR",
|
|
"balance": "12.50 €",
|
|
"is_unreg": false,
|
|
"b_paid": 0
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /people/qr` 🔒
|
|
|
|
Genera un código QR temporal (válido 15 minutos) para el abonado.
|
|
|
|
**Body**
|
|
|
|
| Campo | Tipo | Descripción |
|
|
|--------|---------|--------------------------------------|
|
|
| family | integer | (opcional) Número de familiar de la unidad |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"m": "00042",
|
|
"f": "01",
|
|
"code": "ABCDEF123456"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /people/card` 🔒
|
|
|
|
Devuelve el carnet digital del abonado en base64.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"card": "iVBORw0KGgoAAAANSUhEUgAA...",
|
|
"me": 1
|
|
}
|
|
```
|
|
|
|
> `card` es una imagen PNG codificada en base64. Si no existe, devuelve `""`.
|
|
|
|
---
|
|
|
|
### `GET /people` 🔒
|
|
|
|
Devuelve todos los miembros de la unidad familiar del abonado autenticado.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"people": [
|
|
{
|
|
"member": "00042",
|
|
"family": 1,
|
|
"first_name": "María",
|
|
"last_name": "García López",
|
|
"email": "maria@example.com",
|
|
"phone": "612345678",
|
|
"is_unreg": false
|
|
},
|
|
{
|
|
"member": "00042",
|
|
"family": 2,
|
|
"first_name": "Carlos",
|
|
"last_name": "García López",
|
|
"email": "carlos@example.com",
|
|
"phone": "623456789",
|
|
"is_unreg": false
|
|
}
|
|
],
|
|
"me": 1
|
|
}
|
|
```
|
|
|
|
> `me` indica el número de familiar del usuario autenticado dentro del array.
|
|
|
|
---
|
|
|
|
## 3. Activities (actividades)
|
|
|
|
### `GET /activities` 🔒
|
|
|
|
Devuelve el árbol completo de actividades/cursos disponibles.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{
|
|
"id": "001",
|
|
"name": "PÁDEL",
|
|
"levels": [
|
|
{
|
|
"id": "00101",
|
|
"name": "Iniciación",
|
|
"groups": [
|
|
{
|
|
"id": "0010101",
|
|
"name": "Lunes 18h",
|
|
"monitor": "Carlos",
|
|
"place": "Pista 1",
|
|
"hour": "L 18:00-19:00",
|
|
"price": "25.00"
|
|
},
|
|
{
|
|
"id": "0010102",
|
|
"name": "Miércoles 19h",
|
|
"monitor": "Carlos",
|
|
"place": "Pista 2",
|
|
"hour": "X 19:00-20:00",
|
|
"price": "25.00"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "00102",
|
|
"name": "Avanzado",
|
|
"groups": [
|
|
{
|
|
"id": "0010201",
|
|
"name": "Martes 20h",
|
|
"monitor": "Ana",
|
|
"place": "Pista 3",
|
|
"hour": "M 20:00-21:00",
|
|
"price": "30.00"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"id": "002",
|
|
"name": "NATACIÓN",
|
|
"levels": [
|
|
{
|
|
"id": "00201",
|
|
"name": "Adultos",
|
|
"groups": [
|
|
{
|
|
"id": "0020101",
|
|
"name": "Lunes y Miércoles",
|
|
"monitor": "María",
|
|
"place": "Piscina",
|
|
"hour": "L-X 07:30-08:30",
|
|
"price": "35.00"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /activities` 🔒
|
|
|
|
Preinscribe a un miembro de la familia en una actividad.
|
|
|
|
**Body**
|
|
|
|
| Campo | Tipo | Descripción |
|
|
|----------------|---------|--------------------------------------------|
|
|
| activity | string | Código de actividad (7 dígitos, ej. `0010101`) |
|
|
| family | integer | Número de familiar |
|
|
| date_reg | string | Fecha de alta `dd/mm/yyyy` (opcional) |
|
|
| test_run | string | `permanent` o `test` |
|
|
| comment | string | Comentario / cuestionario de salud |
|
|
| privacy_policy | boolean | Aceptación política de privacidad |
|
|
| privacy_sports | boolean | Aceptación cláusula deportiva |
|
|
|
|
**Respuesta 200 — éxito**
|
|
```json
|
|
{
|
|
"msg": "Su preinscripción está siendo procesada, cuando sea aceptado/a en el grupo le llegará un mensaje de confirmación.",
|
|
"error": "0"
|
|
}
|
|
```
|
|
|
|
**Respuesta 200 — error**
|
|
```json
|
|
{
|
|
"msg": "El abonado/a ya está inscrito en la actividad",
|
|
"error": "3"
|
|
}
|
|
```
|
|
|
|
> Códigos de error: `1` actividad no permitida · `2` ya en lista de espera · `3` ya inscrito · `4` error al guardar.
|
|
|
|
---
|
|
|
|
### `GET /activities/unreg` 🔒
|
|
|
|
Devuelve las actividades e inscripciones de lista de espera de todos los miembros de la familia para solicitar bajas.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{
|
|
"fk_i_member_id": "00042",
|
|
"i_family": 1,
|
|
"s_first_name": "María",
|
|
"s_last_name": "García",
|
|
"courses": [
|
|
{ "i_activity": "0010101", "s_name": "Pádel Iniciación - Lunes 18h", "d_reg_date": "01/09/2025" },
|
|
{ "i_activity": "0030101", "s_name": "Fitness Mañanas", "d_reg_date": "15/09/2025" }
|
|
],
|
|
"waitlist": [
|
|
{ "i_activity": "0020101", "s_name": "Natación Adultos - L-X", "dt_date": "10/10/2025" }
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /activities/unreg` 🔒
|
|
|
|
Solicita la baja de actividades e inscripciones de lista de espera.
|
|
|
|
**Body**
|
|
|
|
| Campo | Tipo | Descripción |
|
|
|---------|--------|---------------------------------------------------------------|
|
|
| acs | object | Mapa `"{family}-{activity}": 1` de actividades a dar de baja |
|
|
| wls | object | Mapa `"{family}-{activity}": 1` de listas de espera |
|
|
| comment | string | Motivo / comentario |
|
|
| reason | string | Razón de baja |
|
|
| deftemp | string | `definitiva` o `temporal` |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"msg": "Su solicitud de baja ha sido procesada. Muchas gracias.",
|
|
"error": "0"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Booking (reservas — app)
|
|
|
|
### `GET /booking` 🔒
|
|
|
|
Devuelve la rejilla de disponibilidad de pistas para una actividad y fecha.
|
|
|
|
**Query params**
|
|
|
|
| Param | Tipo | Ejemplo |
|
|
|----------|--------|----------------|
|
|
| actividad | integer | `1` |
|
|
| fecha | string | `18/03/2026` |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"columns": ["Horarios", "01", "02", "03", "04"],
|
|
"data": [
|
|
[
|
|
{ "row": 0, "hour_id": 1, "text": "0900-1000", "type": "H" },
|
|
{ "id": "", "paid": "", "hourText": "0900-1000", "courtText": "01", "hour": 1, "court": 0, "type": "E", "text": "" },
|
|
{ "id": 4521, "paid": 0, "hourText": "0900-1000", "courtText": "02", "hour": 1, "court": 1, "type": "R", "text": "R" },
|
|
{ "id": "", "paid": "", "hourText": "0900-1000", "courtText": "03", "hour": 1, "court": 2, "type": "E", "text": "" },
|
|
{ "id": "", "paid": "", "hourText": "0900-1000", "courtText": "04", "hour": 1, "court": 3, "type": "E", "text": "" }
|
|
]
|
|
],
|
|
"ac": { "pk_i_activity_id": 1, "s_name": "PÁDEL MURO", "i_courts": 4 },
|
|
"light": "1.00",
|
|
"extra": "1.50",
|
|
"amount": "6.00"
|
|
}
|
|
```
|
|
|
|
> Tipos de celda: `H` cabecera horario · `E` disponible · `R` ocupada (otro) · `I` tuya sin pagar · `P` tuya pagada.
|
|
|
|
---
|
|
|
|
### `GET /booking/book/{id}` 🔒
|
|
|
|
Devuelve el detalle de una reserva concreta.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"pk_i_id": 1234,
|
|
"fk_i_activity_id": 1,
|
|
"d_date": "2026-03-18",
|
|
"fk_i_court_id": 2,
|
|
"fk_i_hour": 3,
|
|
"s_hour": "1100-1200",
|
|
"fk_i_member_id": 42,
|
|
"fk_i_family": 1,
|
|
"b_paid": 0,
|
|
"s_source": "APP"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /booking/checkout/{id}` 🔒
|
|
|
|
Devuelve los datos de pago para una reserva.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"booking_id": 1234,
|
|
"amount": "6.00",
|
|
"status": "pending",
|
|
"payment_url": "https://example.com/checkout/1234"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /booking` 🔒
|
|
|
|
Realiza una reserva de pista.
|
|
|
|
**Body**
|
|
|
|
| Campo | Tipo | Descripción |
|
|
|-------------------|---------|------------------------------|
|
|
| fk_i_activity_id | integer | ID de actividad |
|
|
| hour | integer | ID de hora |
|
|
| d_date | string | Fecha `dd/mm/yyyy` |
|
|
| court | integer | Número de pista (base 0) |
|
|
| light | boolean | Solicitar luz |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"msg": "Reserva realizada correctamente",
|
|
"error": "0",
|
|
"id": 5678
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /booking/cancel` 🔒
|
|
|
|
Cancela una reserva existente.
|
|
|
|
**Body**
|
|
|
|
| Campo | Tipo |
|
|
|-------|---------|
|
|
| id | integer |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"msg": "Reserva cancelada correctamente",
|
|
"error": "0"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /booking/edit` 🔒
|
|
|
|
Edita una reserva existente.
|
|
|
|
**Body**
|
|
|
|
| Campo | Tipo | Descripción |
|
|
|-------|---------|-------------|
|
|
| id | integer | ID de reserva |
|
|
| light | boolean | Activar/desactivar luz |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"msg": "Reserva editada correctamente",
|
|
"error": "0"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /booking/refresh` 🔒
|
|
|
|
Refresca el estado de una reserva (actualiza pagos pendientes).
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"msg": "ok",
|
|
"error": "0"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Payments
|
|
|
|
### `GET /payments` 🔒
|
|
|
|
Devuelve el historial de pagos del abonado.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"payments": [
|
|
{
|
|
"id": 1,
|
|
"description": "Cuota mensual",
|
|
"amount": "35.00",
|
|
"date": "01/03/2026",
|
|
"status": "Pagado",
|
|
"type": "REMESA"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"description": "Actividad pádel",
|
|
"amount": "25.00",
|
|
"date": "15/02/2026",
|
|
"status": "Pagado",
|
|
"type": "CAJA"
|
|
}
|
|
],
|
|
"error": "0"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Wallet (monedero)
|
|
|
|
### `GET /wallet` 🔒
|
|
|
|
Devuelve el saldo y el historial de transacciones del monedero.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"transactions": [
|
|
{
|
|
"id": 1,
|
|
"concept": "Recarga monedero",
|
|
"amount": "20.00",
|
|
"date": "10/03/2026 09:15",
|
|
"balance": "20.00"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"concept": "Pago reserva pádel",
|
|
"amount": "-6.00",
|
|
"date": "12/03/2026 18:32",
|
|
"balance": "14.00"
|
|
}
|
|
],
|
|
"balance": "14.00 €",
|
|
"error": "0"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Search (búsqueda)
|
|
|
|
### `GET /search` 🔒
|
|
|
|
Búsqueda rápida de socios por nombre, apellido, número o DNI.
|
|
|
|
**Query params**
|
|
|
|
| Param | Tipo | Descripción |
|
|
|-------|--------|-------------------|
|
|
| q | string | Término de búsqueda |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{ "id": "0004201", "member": "00042", "family": "01", "name": "García, María", "phone": "612345678" },
|
|
{ "id": "0012301", "member": "00123", "family": "01", "name": "García, Antonio", "phone": "623456789" }
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /search/new` 🔒
|
|
|
|
Búsqueda avanzada con filtros de tipo y estado.
|
|
|
|
**Query params**
|
|
|
|
| Param | Tipo | Valores |
|
|
|--------|--------|-----------------------------|
|
|
| q | string | Término |
|
|
| type | string | `all` · `FAMILIAR` · `INDIVIDUAL` · `SABIC` |
|
|
| status | string | `all` · `active` · `inactive` |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"results": [
|
|
{
|
|
"id": "0004201",
|
|
"member": "00042",
|
|
"family": "01",
|
|
"name": "García, María",
|
|
"phone": "612345678",
|
|
"email": "maria@example.com",
|
|
"dni": "12345678A",
|
|
"type": "FAMILIAR",
|
|
"is_unreg": false,
|
|
"unreg_reason": "",
|
|
"b_paid": 0
|
|
}
|
|
],
|
|
"total": 1
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /search/doorlog` 🔒
|
|
|
|
Devuelve el log de accesos por torniquete de un abonado.
|
|
|
|
**Query params**
|
|
|
|
| Param | Tipo | Descripción |
|
|
|--------|---------|----------------------------|
|
|
| member | string | Número de socio (5 dígitos)|
|
|
| family | integer | Número de familiar (def. 1)|
|
|
| limit | integer | Máx. registros (def. 100) |
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{
|
|
"pk_i_id": 1,
|
|
"fk_i_member_id": "00042",
|
|
"fk_i_people_id": 1,
|
|
"dt_date": "2026-03-15 09:23:11",
|
|
"s_source": "TORNIQUETE"
|
|
},
|
|
{
|
|
"pk_i_id": 2,
|
|
"fk_i_member_id": "00042",
|
|
"fk_i_people_id": 1,
|
|
"dt_date": "2026-03-14 18:45:02",
|
|
"s_source": "APP"
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Members (socios — admin)
|
|
|
|
> Todos los endpoints de esta sección requieren autenticación 🔒.
|
|
|
|
El objeto **member** tiene la siguiente estructura completa:
|
|
|
|
```json
|
|
{
|
|
"pk_i_id": 42,
|
|
"d_reg_date": "2018-03-15",
|
|
"s_address": "Calle Mayor 12",
|
|
"s_city": "Madrid",
|
|
"s_zip": "28001",
|
|
"s_email": "socio@example.com",
|
|
"s_phone": "612345678",
|
|
"s_bank": "0049",
|
|
"s_bank_office": "1500",
|
|
"s_bank_sec_code": "42",
|
|
"s_bank_account": "0123456789",
|
|
"s_bank_name": "Santander",
|
|
"s_mandate": "MNDT-00042",
|
|
"s_type": "FAMILIAR",
|
|
"s_comment": "",
|
|
"s_comment2": "",
|
|
"b_paid": 0,
|
|
"b_rem_special": 0,
|
|
"b_retenido": 0,
|
|
"d_unreg_date": null,
|
|
"s_unreg_reason": "",
|
|
"people": [
|
|
{
|
|
"fk_i_member_id": 42,
|
|
"i_family": 1,
|
|
"s_first_name": "María",
|
|
"s_last_name": "García",
|
|
"s_dni": "12345678A",
|
|
"d_birth_date": "1985-03-15",
|
|
"s_phone": "612345678",
|
|
"s_email": "maria@example.com",
|
|
"b_lopd": 1,
|
|
"b_newsletter": 1,
|
|
"b_authorized": 1,
|
|
"b_authorized2": 0,
|
|
"s_photo_path": null
|
|
}
|
|
],
|
|
"cautions": [],
|
|
"comments": []
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /members/quick` — Búsqueda rápida por número
|
|
|
|
**Query:** `fk_i_member_id=42` · `i_family=1` (opcional)
|
|
**Respuesta:** objeto `member` completo
|
|
|
|
---
|
|
|
|
### `GET /members/first` — Primer socio
|
|
### `GET /members/last` — Último socio
|
|
### `GET /members/{id}` — Socio por ID
|
|
### `GET /members/{id}/prev` — Socio anterior
|
|
### `GET /members/{id}/next` — Socio siguiente
|
|
|
|
Todas devuelven el objeto `member` completo.
|
|
|
|
---
|
|
|
|
### `GET /members/search` — Autocompletar socios
|
|
|
|
**Query:** `term=garcia`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"0004201": "(00042-01) García, María",
|
|
"0004202": "(00042-02) García, Carlos"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /members/edit`
|
|
|
|
**Body:** campos del objeto member a actualizar (`pk_i_id` requerido).
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "msg": "Socio editado correctamente", "member": { "...": "objeto member completo" } }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /members/paid-caution` — Toggle flag recibos pendientes
|
|
|
|
**Body:** `pk_i_id`
|
|
**Respuesta:** objeto `member` actualizado
|
|
|
|
---
|
|
|
|
### `POST /members/recover` — Reactivar socio dado de baja
|
|
|
|
**Body:** `pk_i_id`
|
|
**Respuesta:** objeto `member` actualizado
|
|
|
|
---
|
|
|
|
### `POST /members/pre-delete` — Pre-verificación antes de dar de baja
|
|
|
|
**Body:** `pk_i_id`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "pendientes": 0, "devueltos": 2, "revision": 0 }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /members/delete` — Dar de baja a un socio
|
|
|
|
**Body:** `pk_i_id` · `d_unreg_date` · `s_unreg_reason`
|
|
**Respuesta:** objeto `member` actualizado
|
|
|
|
---
|
|
|
|
### `POST /members/change-type` — Cambiar tipo de socio
|
|
|
|
**Body:** `id` · `s_type`
|
|
**Respuesta 200:** `{ "error": 0, "msg": "ok" }`
|
|
|
|
---
|
|
|
|
### `POST /members/rem-special` — Toggle remesa especial
|
|
|
|
**Body:** `pk_i_id` · `b_rem_special`
|
|
**Respuesta:** objeto `member` con campo `error`
|
|
|
|
---
|
|
|
|
### `POST /members/retener` / `POST /members/retener-cancel`
|
|
|
|
Marca/desmarca al socio como retenido.
|
|
**Body:** `member`
|
|
**Respuesta:** `{ "msg": "...", "member": { ... } }`
|
|
|
|
---
|
|
|
|
### `POST /members/promotion` — Registrar promoción
|
|
|
|
**Body:** `pk_i_id` · `friend`
|
|
**Respuesta:** `{ "msg": "Promoción añadida correctamente", "member": { ... } }`
|
|
|
|
---
|
|
|
|
### `POST /members/edit-comment` — Editar comentario interno
|
|
|
|
**Body:** `pk_i_id` · `s_comment2`
|
|
**Respuesta:** `{ "msg": "...", "member": { ... } }`
|
|
|
|
---
|
|
|
|
### `POST /members/comment/add` — Añadir comentario
|
|
|
|
**Body:** `member` · `comment`
|
|
**Respuesta:** `{ "msg": "...", "member": { ... } }`
|
|
|
|
---
|
|
|
|
### `GET /members/comment/edit` — Obtener comentario para editar
|
|
|
|
**Query:** `id`
|
|
**Respuesta:** `{ "comment": { "id": 1, "comment": "texto", "created_at": "..." } }`
|
|
|
|
---
|
|
|
|
### `POST /members/comment/edit-save` — Guardar edición de comentario
|
|
|
|
**Body:** `id` · `comment` · `pk_i_id`
|
|
**Respuesta:** `{ "msg": "...", "member": { ... } }`
|
|
|
|
---
|
|
|
|
### `POST /members/comment/delete` — Eliminar comentario
|
|
|
|
**Body:** `id` (`"old"` para el comentario heredado) · `member_id`
|
|
**Respuesta:** `{ "msg": "Comentario borrado", "member": { ... } }`
|
|
|
|
---
|
|
|
|
### Familiares (people)
|
|
|
|
| Método | Ruta | Descripción |
|
|
|--------|------|-------------|
|
|
| `POST` | `/members/people/add` | Añadir familiar |
|
|
| `POST` | `/members/people/edit` | Editar familiar |
|
|
| `POST` | `/members/people/delete` | Eliminar familiar |
|
|
| `POST` | `/members/people/auth` | Toggle autorización acceso |
|
|
| `POST` | `/members/people/auth2` | Toggle autorización 2 |
|
|
| `POST` | `/members/people/picture/upload` | Subir foto (multipart `webcam`) |
|
|
| `POST` | `/members/people/picture/delete` | Eliminar foto |
|
|
| `GET` | `/members/people/card` | Tarjetas de acceso |
|
|
| `POST` | `/members/people/card/add` | Añadir tarjeta |
|
|
| `POST` | `/members/people/card/delete` | Eliminar tarjeta |
|
|
| `POST` | `/members/people/password` | Generar enlace de reset de contraseña |
|
|
| `GET` | `/members/people/card/preview` | Previsualizar carnet |
|
|
| `POST` | `/members/people/card/print` | Imprimir carnet |
|
|
| `POST` | `/members/people/minors-card` | Actualizar visibilidad carnets menores |
|
|
|
|
Todas las respuestas de escritura devuelven `{ "msg": "...", "member": { ... } }` o `{ "error": 0, "msg": "..." }`.
|
|
|
|
**`GET /members/people/card`** devuelve:
|
|
```json
|
|
{
|
|
"cards": [
|
|
{ "pk_i_id": 1, "fk_i_member_id": 42, "i_family": 1, "s_card": "ABCD1234EFGH5678" }
|
|
]
|
|
}
|
|
```
|
|
|
|
**`POST /members/people/password`** devuelve:
|
|
```json
|
|
{ "h": "https://app.example.com/password/reset/TOKEN?email=socio@example.com" }
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Courses (cursos — admin)
|
|
|
|
### `GET /courses/levels` 🔒
|
|
|
|
**Query:** `course` (código de actividad)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{ "i_code1": 1, "i_code2": 1, "i_code3": 0, "s_name": "Iniciación" },
|
|
{ "i_code1": 1, "i_code2": 2, "i_code3": 0, "s_name": "Avanzado" }
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /courses/groups` 🔒
|
|
|
|
**Query:** `course` · `level`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{
|
|
"i_code1": 1, "i_code2": 1, "i_code3": 1,
|
|
"s_name": "Lunes 18h-19h",
|
|
"f_price": "25.00",
|
|
"i_max_students": 15,
|
|
"s_hour": "L 18:00-19:00",
|
|
"s_monitor": "Carlos",
|
|
"s_place": "Pista 1",
|
|
"i_one_bill": 0,
|
|
"b_fitness": 0,
|
|
"b_pending_count": 0,
|
|
"s_comment": ""
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /courses/group` 🔒
|
|
|
|
**Query:** `course` · `level` · `group`
|
|
**Respuesta:** objeto grupo (igual que el array anterior, un único elemento)
|
|
|
|
---
|
|
|
|
### `GET /courses/data-alumni` 🔒
|
|
|
|
Actividades en las que está inscrito un abonado.
|
|
|
|
**Query:** `code` (7 dígitos: `{member}{family}`)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{ "i_activity": "0010101", "s_name": "Pádel Iniciación L18h" },
|
|
{ "i_activity": "0030101", "s_name": "Fitness Mañanas" }
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /courses/alumnis` 🔒
|
|
|
|
Lista de alumnos de un grupo.
|
|
|
|
**Query:** `course` · `level` · `group` · `month` (opcional) · `year` (opcional)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
[
|
|
{
|
|
"pk_i_id": 1234,
|
|
"fk_i_member_id": "00042",
|
|
"fk_i_family": "01",
|
|
"i_activity": "0010101",
|
|
"s_last_name": "García",
|
|
"s_first_name": "María",
|
|
"d_reg_date": "01/09/2025",
|
|
"f_price": "25.00",
|
|
"mod_price": "25.00",
|
|
"ac_price": "25.00",
|
|
"s_type": "REMESA",
|
|
"s_comment": "",
|
|
"b_authorized": 1,
|
|
"b_authorized2": 0,
|
|
"i_door_log_count": 0
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /courses/waitlist` 🔒
|
|
|
|
**Query:** `course` · `level` · `group`
|
|
**Respuesta:** igual que `/courses/alumnis` con campo adicional `dt_date`.
|
|
|
|
---
|
|
|
|
### `GET /courses/alumni/get-reg-comment` 🔒
|
|
|
|
**Query:** `m` · `f` · `a`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"fk_i_member_id": "00042",
|
|
"fk_i_family": "01",
|
|
"i_activity": "0010101",
|
|
"s_comment": "Interesada en el grupo de tarde si hay plaza."
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /courses/alumni/get-unreg-comment` 🔒
|
|
|
|
**Query:** `i` (ID del registro en unreg_requests)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "id": 5, "comment": "Se marcha al extranjero temporalmente." }
|
|
```
|
|
|
|
---
|
|
|
|
### Escritura de cursos
|
|
|
|
| Método | Ruta | Body principal | Respuesta |
|
|
|--------|------|----------------|-----------|
|
|
| `POST` | `/courses/add` | `s_name` | Nuevo `i_code1` |
|
|
| `POST` | `/courses/edit` | `course` · `s_name` | `"ok"` |
|
|
| `POST` | `/courses/delete` | `course` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/level/add` | `course` · `s_name` | Nuevo `i_code2` |
|
|
| `POST` | `/courses/level/edit` | `course` · `level` · `s_name` | `"ok"` |
|
|
| `POST` | `/courses/level/delete` | `course` · `level` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/group/add` | `course` · `level` · `s_name` · `f_price` · `i_max_students` · `s_hour` · `s_monitor` · `s_place` | `"ok"` |
|
|
| `POST` | `/courses/group/edit` | `id` · `s_field` · `s_value` | `"ok"` |
|
|
| `POST` | `/courses/group/delete` | `course` · `group` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/group/comment` | `course` · `level` · `group` · `comment` | `{ "msg": "...", "error": 0 }` |
|
|
| `POST` | `/courses/alumni/add` | `course` · `level` · `group` · `fk_i_member_id` · `d_date` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/add-from-wait` | idem + `email` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/delete` | `course` · `level` · `group` · `fk_i_member_id` · `fk_i_family` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/delete-by-id` | `id` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/delete-by-ids` | `ids` (CSV) | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/delete-wait` | `course` · `level` · `group` · `fk_i_member_id` · `fk_i_family` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/empty` | `course` · `level` · `group` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/import` | `ocourse` · `olevel` · `ogroup` · `dcourse` · `dlevel` · `dgroup` · `date` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/auth` | `id` · `value` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/auth2` | `id` · `value` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/reg-comment` | `m` · `f` · `a` · `s_comment` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/courses/alumni/unreg-comment` | `id` · `s_comment` | `{ "error": 0, "msg": "..." }` |
|
|
|
|
---
|
|
|
|
## 10. Bills (recibos — admin)
|
|
|
|
### `GET /bills/member-search` 🔒
|
|
|
|
**Query:** `fk_i_member_id`
|
|
|
|
**Respuesta 200** — array de recibos:
|
|
```json
|
|
[
|
|
{
|
|
"alumni": 1234,
|
|
"member": "00042",
|
|
"family": "01",
|
|
"name": "García, María",
|
|
"ac_name": "Pádel Iniciación L18h",
|
|
"activity": "0010101",
|
|
"price": "25.00",
|
|
"user_price": "25.00",
|
|
"bill_price": "25.00",
|
|
"month": 3,
|
|
"year": 2026,
|
|
"month_name": "marzo",
|
|
"status": 0,
|
|
"type": "REMESA",
|
|
"bonus": 0,
|
|
"cash_date": ""
|
|
}
|
|
]
|
|
```
|
|
|
|
> Estado (`status`): `0` pendiente · `1` pagado · `2` eliminado · `4` devuelto.
|
|
|
|
---
|
|
|
|
### `GET /bills/alumni` 🔒
|
|
|
|
**Query:** `id` (ID de alumno)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"pk_i_id": 1234,
|
|
"fk_i_member_id": "00042",
|
|
"fk_i_family": "01",
|
|
"i_activity": "0010101",
|
|
"f_price": "25.00",
|
|
"s_type": "REMESA",
|
|
"s_comment": "",
|
|
"person": { "s_first_name": "María", "s_last_name": "García" },
|
|
"next_bills": [
|
|
{ "i_month": 4, "i_year": 2026, "i_status": 0, "f_price": "25.00" },
|
|
{ "i_month": 5, "i_year": 2026, "i_status": 0, "f_price": "25.00" }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /bills/from-alumni` 🔒
|
|
|
|
**Query:** `id`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"pk_i_id": 1234,
|
|
"i_activity": "0010101",
|
|
"person": { "s_first_name": "María", "s_last_name": "García" },
|
|
"bills": [
|
|
{ "i_month": 1, "i_year": 2026, "i_status": 1, "f_price": "25.00", "year": 0 },
|
|
{ "i_month": 2, "i_year": 2026, "i_status": 1, "f_price": "25.00", "year": 0 },
|
|
{ "i_month": 3, "i_year": 2026, "i_status": 0, "f_price": "25.00", "year": 0 }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /bills/number` 🔒
|
|
|
|
**Query:** `course` · `level` · `group` · `month` · `year` · `type` (`BANK`/`ALL`) · `alumni[]` (opcional)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
12
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /bills/pending` 🔒
|
|
|
|
**Query:** `id` (member) · `complete` (0/1)
|
|
|
|
**Respuesta 200** — array de recibos pendientes (misma estructura que `/bills/member-search`)
|
|
|
|
---
|
|
|
|
### `GET /bills/search` 🔒
|
|
|
|
**Query:** `fk_i_member_id` · `i_month` · `status` · `ext`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"iTotalRecords": 5,
|
|
"iTotalDisplayRecords": 5,
|
|
"aaData": [ { "...": "objeto recibo" } ]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /bills/remittance-return/member` 🔒
|
|
|
|
**Query:** `member`
|
|
|
|
**Respuesta 200** — mapa de miembros con recibos devueltos:
|
|
```json
|
|
{
|
|
"42": {
|
|
"pk_i_id": 42,
|
|
"people": [ { "...": "..." } ],
|
|
"months": { "3": 1 },
|
|
"bills": [ { "...": "..." } ],
|
|
"i_total": "25.00"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Escritura de recibos
|
|
|
|
| Método | Ruta | Body | Respuesta |
|
|
|--------|------|------|-----------|
|
|
| `POST` | `/bills/alumni/edit` | `id` · `price` · `type` · `comment` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/bills/generate` | `id` · `month` · `year` | `{ "error": 0, "msg": "Recibo creado" }` |
|
|
| `POST` | `/bills/generate-next` | `course` · `level` · `group` · `month` · `year` | `{ "msg": "Recibos generados", "error": 0 }` |
|
|
| `POST` | `/bills/generate-multi` | `activity` · `id` · `months[]` | `{ "iTotalRecords": N, "aaData": [...] }` |
|
|
| `POST` | `/bills/generate-remittance` | `course` · `level` · `group` · `month` · `year` | `{ "error": 0, "msg": "...", "paid_bills": 12 }` |
|
|
| `POST` | `/bills/ticket` | `bills[]` | `{ "error": 0, "msg": "...", "ticket_number": "2025/000123", "lines": [] }` |
|
|
| `POST` | `/bills/cancel` | `acs[]` | `{ "error": 0, "msg": "OK", "lines": [] }` |
|
|
| `POST` | `/bills/delete` | `acs[]` | `{ "error": 0, "msg": "OK" }` |
|
|
| `POST` | `/bills/delete-alumni` | `ids` (CSV) · `month` · `year` | `{ "error": 0, "msg": "OK" }` |
|
|
| `POST` | `/bills/recover` | `acs[]` | `{ "error": 0, "msg": "OK" }` |
|
|
| `POST` | `/bills/remittance-return/add` | `member` · `month` · `year` | `{ "error": 0, "msg": "OK" }` |
|
|
| `POST` | `/bills/remittance-return/delete` | `alumni` · `month` · `year` · `id` · `special` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/bills/remittance-return/print` | `id` | `{ "msg": "...", "data": { "id": 1 }, "lines": [] }` |
|
|
|
|
---
|
|
|
|
## 11. Booking Admin (reservas — admin)
|
|
|
|
### `GET /booking-admin/grid` 🔒
|
|
|
|
**Query:** `fk_i_activity_id` · `d_date` (`dd/mm/yyyy`)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"aaData": [
|
|
["<div id=\"0\">0900-1000</div>", "00042.1+", "", "00123.2", ""],
|
|
["<div id=\"1\">1000-1100</div>", "", "", "", "00456.1"]
|
|
],
|
|
"aoColumns": [
|
|
{ "sTitle": "Horarios", "sClass": "celda_horario", "sWidth": "65px" },
|
|
{ "sTitle": "01", "sClass": "celda_normal", "sWidth": "95px" },
|
|
{ "sTitle": "02", "sClass": "celda_normal", "sWidth": "95px" }
|
|
],
|
|
"ac": { "pk_i_activity_id": 1, "s_name": "PÁDEL MURO", "i_courts": 4 },
|
|
"light": 100,
|
|
"extra": 150,
|
|
"extra2": 150
|
|
}
|
|
```
|
|
|
|
> En `aaData`, la celda contiene `{member}.{family}[+]` si está ocupada, `""` si libre. El `+` indica pagado.
|
|
|
|
---
|
|
|
|
### `GET /booking-admin/shared` 🔒
|
|
|
|
**Query:** `fk_i_activity_id` · `d_date` · `hour` · `court`
|
|
|
|
**Respuesta 200** — array de reservas en la misma hora/pista (compartidas)
|
|
|
|
---
|
|
|
|
### `GET /booking-admin/single` 🔒
|
|
|
|
**Query:** `fk_i_activity_id` · `d_date` · `hour` · `aPos[1]`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "fk_i_member_id": 42, "fk_i_family": 1, "d_date": "2026-03-18", "b_paid": 0 }
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /booking-admin/single-by-id` 🔒
|
|
|
|
**Query:** `id`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "pk_i_id": 1234, "fk_i_member_id": 42, "fk_i_family": 1, "d_date": "2026-03-18", "b_paid": 0 }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /booking-admin/do` 🔒
|
|
|
|
**Body:** `fk_i_activity_id` · `hour` · `d_date` · `court` · `member` · `aPos[]`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"msg": "Pista reservada correctamente",
|
|
"error": 1,
|
|
"cell": "2x1",
|
|
"book": { "fk_i_member_id": 42 }
|
|
}
|
|
```
|
|
|
|
> `error`: `0` fallo · `1` OK · `2` ya pagada · `3` ocupada por otro · `4` recibos pendientes · `5` dado de baja.
|
|
|
|
---
|
|
|
|
### `POST /booking-admin/confirm` 🔒
|
|
|
|
**Body:** `id` (ID de reserva pendiente de confirmar)
|
|
|
|
**Respuesta 200** — misma estructura que `/booking-admin/do`
|
|
|
|
---
|
|
|
|
### `POST /booking-admin/empty` 🔒
|
|
|
|
**Body:** `fk_i_activity_id` · `hour` · `s_hour` · `d_date` · `aPos[]`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 2, "book": { "pk_i_id": 1234, "b_paid": 0, "text": "" } }
|
|
```
|
|
|
|
> `error`: `0` nada que vaciar · `1` estaba pagada (devolver ticket) · `2` eliminada (no pagada) · `3` eliminada (pagada sin ticket).
|
|
|
|
---
|
|
|
|
### `POST /booking-admin/empty-by-id` 🔒
|
|
|
|
**Body:** `id`
|
|
**Respuesta:** igual que `/booking-admin/empty`
|
|
|
|
---
|
|
|
|
## 12. Cash (caja — admin)
|
|
|
|
### `GET /cash/last-ticket` 🔒
|
|
|
|
**Query:** `iPage` (paginación, base 0)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"ticket": [
|
|
{ "dt_date": "2026-03-18 10:23:45", "i_line": 1, "s_line": "--------------------------------" },
|
|
{ "dt_date": "2026-03-18 10:23:45", "i_line": 2, "s_line": "CLUB DEPORTIVO SANTA ANA" },
|
|
{ "dt_date": "2026-03-18 10:23:45", "i_line": 3, "s_line": "Reserva pádel 6,00 €" }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /cash/search` 🔒
|
|
|
|
**Query:** `searchQuery` · `paymentType` · `iPage`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"items": [
|
|
{
|
|
"pk_i_id": 12345,
|
|
"pk_s_id": "2026/000042",
|
|
"d_year": 2026,
|
|
"dt_date": "2026-03-18 10:23:45",
|
|
"fk_s_activity_group_id":"AC",
|
|
"fk_i_activity_id": "01",
|
|
"fk_i_member_id": "00042",
|
|
"s_name": "García, María",
|
|
"s_concept": "Reserva pádel",
|
|
"f_price": 6000000,
|
|
"f_tax": 0,
|
|
"f_amount": "6.00",
|
|
"s_type": "CAJA"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /cash/ticket-from-booking` 🔒
|
|
|
|
**Query:** `ac` · `hour` · `court` · `date`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "ticket": [ { "...": "objeto cash" } ] }
|
|
```
|
|
|
|
---
|
|
|
|
### Escritura de caja
|
|
|
|
| Método | Ruta | Body | Respuesta |
|
|
|--------|------|------|-----------|
|
|
| `POST` | `/cash/post` | `fk_i_member_id` · `items[]` · `prices[]` · `concepts[]` · `taxes[]` · `amounts[]` · `payment_type` · `dt_date` | `{ "msg": "...", "total": 6000000, "pk_s_id": "2026/000042", "data": "" }` |
|
|
| `POST` | `/cash/post-ticket` | datos del ticket | `{ "msg": "...", "data": "", "lines": [] }` |
|
|
| `POST` | `/cash/print-ticket` | `date` | `{ "lines": ["linea1", "linea2"] }` |
|
|
| `POST` | `/cash/delete` | `id` | `{ "error": 0, "msg": "..." }` |
|
|
| `POST` | `/cash/delete-mov` | `sdate` · `edate` | `{ "error": 0, "msg": "OK" }` |
|
|
| `POST` | `/cash/book-ticket` | datos reserva + pago | `{ "msg": "...", "data": "", "lines": [] }` |
|
|
| `POST` | `/cash/book-return` | datos devolución | `{ "error": 0, "book": {}, "lines": [] }` |
|
|
| `POST` | `/cash/bonus-ticket` | datos bono | `{ "error": 0, "lines": [] }` |
|
|
| `POST` | `/cash/bonus-ticket-nopaid` | datos bono | `{ "error": 0, "lines": [] }` |
|
|
| `POST` | `/cash/qr` | `member` · `familiar` | `{ "msg": "ok", "error": 0, "qr": "00042-01-ABCDEF123456" }` |
|
|
|
|
---
|
|
|
|
## 13. Dayoff / Celebrations
|
|
|
|
| Método | Ruta | Body | Respuesta |
|
|
|--------|------|------|-----------|
|
|
| `POST` | `/dayoff/add` | `d_date` (`dd/mm/yyyy`) · `s_name` · `type` | `1` |
|
|
| `POST` | `/dayoff/delete` | `d_date` · `s_name` | `1` |
|
|
| `POST` | `/celebration/add` | `date` (`dd/mm/yyyy`) · `name` · `member` · `comment` | `1` |
|
|
| `POST` | `/celebration/delete` | `id` | `1` |
|
|
|
|
---
|
|
|
|
## 14. Remittance (remesas especiales)
|
|
|
|
### `POST /remittance/member/add` 🔒
|
|
|
|
**Body:** `id` (remittance ID) · `member` · `amount` · `concept`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "msg": "Socio añadido correctamente" }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /remittance/member/delete` 🔒
|
|
|
|
**Body:** `id`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "msg": "Socio eliminado correctamente" }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /remittance/edit` 🔒
|
|
|
|
**Body:** `id` · `field` · `value`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "msg": "Editado correctamente" }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /remittance/sepa` 🔒
|
|
|
|
**Body:** `id` (remittance ID)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{
|
|
"error": 0,
|
|
"msg": "Remesa generada correctamente",
|
|
"file": "/storage/remesas/2026_sepa.xml",
|
|
"count": 42
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 15. Inscriptions (preinscripciones)
|
|
|
|
El objeto **inscription** tiene esta estructura:
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"address": "Calle Mayor 12",
|
|
"city": "Madrid",
|
|
"zip_code": "28001",
|
|
"emergency_phone": "612345678",
|
|
"bank": "0049",
|
|
"bank_office": "1500",
|
|
"bank_sec_code": "42",
|
|
"bank_account": "0123456789",
|
|
"comment": "",
|
|
"know_us": "amigo",
|
|
"know_us_comment": "",
|
|
"know_us_by_who": "",
|
|
"created_at": "2026-03-01T10:00:00.000Z",
|
|
"people": [
|
|
{
|
|
"first_name": "Luis",
|
|
"last_name": "Pérez",
|
|
"email": "luis@example.com",
|
|
"phone": "634567890",
|
|
"birth_date": "15/04/1990",
|
|
"dni": "87654321B"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
| Método | Ruta | Descripción | Respuesta |
|
|
|----------|------|-------------|-----------|
|
|
| `GET` | `/inscriptions/first` | Primera preinscripción | objeto inscription |
|
|
| `GET` | `/inscriptions/last` | Última preinscripción | objeto inscription |
|
|
| `GET` | `/inscriptions/{id}` | Preinscripción por ID | objeto inscription |
|
|
| `GET` | `/inscriptions/{id}/prev` | Anterior | objeto inscription |
|
|
| `GET` | `/inscriptions/{id}/next` | Siguiente | objeto inscription |
|
|
| `POST` | `/inscriptions` | Convertir en socio | `{ "error": 0, "msg": "Usuario creado correctamente", "id": 1234 }` |
|
|
| `DELETE` | `/inscriptions/{id}` | Eliminar preinscripción | objeto inscription siguiente |
|
|
|
|
**`POST /inscriptions` — Body**
|
|
|
|
| Campo | Tipo |
|
|
|----------------|---------|
|
|
| inscription_id | integer |
|
|
| s_type | string (`INDIVIDUAL` / `FAMILIAR` / `SABIC` / ...) |
|
|
| id | integer | (opcional, número de socio a asignar) |
|
|
| d_reg_date | string |
|
|
|
|
---
|
|
|
|
## 16. Admin Misc
|
|
|
|
### `POST /admin/quota` 🔒
|
|
|
|
Actualiza el precio/cupo de una actividad.
|
|
|
|
**Body:** `pk_s_group_id` · `pk_i_activity_id` · `s_field` · `s_value`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
1
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /admin/reboot` 🔒
|
|
|
|
Reinicia la impresora.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "msg": "Reiniciando impresora..." }
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /admin/check-reboot` 🔒
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "status": "ok" }
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /admin/bank-sec-code` 🔒
|
|
|
|
Calcula el dígito de control bancario.
|
|
|
|
**Query:** `bank` · `office` · `account`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
"42"
|
|
```
|
|
|
|
---
|
|
|
|
### `GET /admin/bank-name` 🔒
|
|
|
|
**Query:** `bank` (código 4 dígitos)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "name": "Banco Santander" }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /admin/print-card` 🔒
|
|
|
|
**Body:** `member` · `family`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "msg": "Carnet enviado a imprimir" }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /admin/set-printer` 🔒
|
|
|
|
**Body:** `printer` (nombre/IP)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "msg": "Impresora configurada correctamente" }
|
|
```
|
|
|
|
---
|
|
|
|
### `POST /admin/sorteo` 🔒
|
|
|
|
Registra participaciones en sorteo.
|
|
|
|
**Body:** `data[]` (array de `{ member, name, email, phone, tickets }`)
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "msg": "Participación registrada" }
|
|
```
|
|
|
|
---
|
|
|
|
## 17. Printer
|
|
|
|
### `GET /printer/lines` 🔒
|
|
|
|
Devuelve líneas pendientes de imprimir.
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "error": 0, "lines": [] }
|
|
```
|
|
|
|
---
|
|
|
|
## 18. Hash (público)
|
|
|
|
### `GET /hash/{hash}`
|
|
|
|
Devuelve el hash BCrypt de un valor, en base64. Útil para generar contraseñas desde scripts.
|
|
|
|
**Ejemplo:** `GET /2.0/hash/mipassword`
|
|
|
|
**Respuesta 200**
|
|
```json
|
|
{ "h": "JDJ5JDEwJGFCQ0Rm..." }
|
|
```
|
|
|
|
---
|
|
|
|
## Códigos de error comunes
|
|
|
|
| Campo `error` | Significado |
|
|
|---------------|-------------|
|
|
| `"0"` / `0` | Operación correcta |
|
|
| `"1"` / `1` | Error genérico o entidad no encontrada |
|
|
| `"2"` | Ya existe / ya está pagado |
|
|
| `"3"` | Ocupado por otro usuario |
|
|
| `"4"` | Recibos pendientes — acceso restringido |
|
|
| `"5"` | Dado de baja — acceso restringido |
|
|
|
|
---
|
|
|
|
## Convenciones
|
|
|
|
- **Montos** se almacenan internamente en **millonésimas de euro** (`6000000` = `6.00 €`). La API devuelve el valor formateado como string (`"6.00"`) en los recursos de la app.
|
|
- **Fechas** en pantalla usan formato `dd/mm/yyyy`; en base de datos `yyyy-mm-dd`.
|
|
- **Códigos de actividad** son cadenas de 7 dígitos: `{course:3}{level:2}{group:2}` → `0010102`.
|
|
- **Identificador de abonado** combina miembro y familiar: `{member:5}{family:2}` → `0004201`. |