depor_os/docs/api-v2.md
Daniel Esteban 34e7cbc382 first commit
2026-03-18 12:47:06 +01:00

39 KiB

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
  2. People (abonado)
  3. Activities (actividades)
  4. Booking (reservas — app)
  5. Payments
  6. Wallet (monedero)
  7. Search (búsqueda)
  8. Members (socios — admin)
  9. Courses (cursos — admin)
  10. Bills (recibos — admin)
  11. Booking Admin (reservas — admin)
  12. Cash (caja — admin)
  13. Dayoff / Celebrations
  14. Remittance (remesas especiales)
  15. Inscriptions (preinscripciones)
  16. Admin Misc
  17. Printer
  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

{
  "access_token": "4Km9xQzLp2VnRtYwEoJbFsUcXgHdAiMkNlOqPrSvTu"
}

Respuesta 401

{
  "message": "Contraseña incorrecta."
}

POST /forgot

Envía un email de recuperación de contraseña.

Body

Campo Tipo
email string

Respuesta 200

{
  "error": "Se le ha enviado un email con instrucciones"
}

GET /logout 🔒

Cierra la sesión del usuario autenticado.

Respuesta 200

{
  "logout": "ok"
}

2. People (abonado)

GET /people/me 🔒

Devuelve los datos del abonado autenticado.

Respuesta 200

{
  "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

{
  "m":    "00042",
  "f":    "01",
  "code": "ABCDEF123456"
}

GET /people/card 🔒

Devuelve el carnet digital del abonado en base64.

Respuesta 200

{
  "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

{
  "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

[
  {
    "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

{
  "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

{
  "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

[
  {
    "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

{
  "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

{
  "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

{
  "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

{
  "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

{
  "msg":   "Reserva realizada correctamente",
  "error": "0",
  "id":    5678
}

POST /booking/cancel 🔒

Cancela una reserva existente.

Body

Campo Tipo
id integer

Respuesta 200

{
  "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

{
  "msg":   "Reserva editada correctamente",
  "error": "0"
}

POST /booking/refresh 🔒

Refresca el estado de una reserva (actualiza pagos pendientes).

Respuesta 200

{
  "msg":   "ok",
  "error": "0"
}

5. Payments

GET /payments 🔒

Devuelve el historial de pagos del abonado.

Respuesta 200

{
  "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

{
  "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)

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

[
  { "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

{
  "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

[
  {
    "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:

{
  "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

{
  "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

{ "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

{ "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:

{
  "cards": [
    { "pk_i_id": 1, "fk_i_member_id": 42, "i_family": 1, "s_card": "ABCD1234EFGH5678" }
  ]
}

POST /members/people/password devuelve:

{ "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

[
  { "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

[
  {
    "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

[
  { "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

[
  {
    "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

{
  "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

{ "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)

Query: fk_i_member_id

Respuesta 200 — array de recibos:

[
  {
    "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

{
  "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

{
  "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

12

GET /bills/pending 🔒

Query: id (member) · complete (0/1)

Respuesta 200 — array de recibos pendientes (misma estructura que /bills/member-search)


Query: fk_i_member_id · i_month · status · ext

Respuesta 200

{
  "iTotalRecords":        5,
  "iTotalDisplayRecords": 5,
  "aaData": [ { "...": "objeto recibo" } ]
}

GET /bills/remittance-return/member 🔒

Query: member

Respuesta 200 — mapa de miembros con recibos devueltos:

{
  "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

{
  "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

{ "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

{ "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

{
  "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

{ "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

{
  "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 €" }
  ]
}

Query: searchQuery · paymentType · iPage

Respuesta 200

{
  "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

{ "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

{ "error": 0, "msg": "Socio añadido correctamente" }

POST /remittance/member/delete 🔒

Body: id

Respuesta 200

{ "error": 0, "msg": "Socio eliminado correctamente" }

POST /remittance/edit 🔒

Body: id · field · value

Respuesta 200

{ "error": 0, "msg": "Editado correctamente" }

POST /remittance/sepa 🔒

Body: id (remittance ID)

Respuesta 200

{
  "error": 0,
  "msg":   "Remesa generada correctamente",
  "file":  "/storage/remesas/2026_sepa.xml",
  "count": 42
}

15. Inscriptions (preinscripciones)

El objeto inscription tiene esta estructura:

{
  "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
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

1

POST /admin/reboot 🔒

Reinicia la impresora.

Respuesta 200

{ "error": 0, "msg": "Reiniciando impresora..." }

GET /admin/check-reboot 🔒

Respuesta 200

{ "status": "ok" }

GET /admin/bank-sec-code 🔒

Calcula el dígito de control bancario.

Query: bank · office · account

Respuesta 200

"42"

GET /admin/bank-name 🔒

Query: bank (código 4 dígitos)

Respuesta 200

{ "name": "Banco Santander" }

POST /admin/print-card 🔒

Body: member · family

Respuesta 200

{ "error": 0, "msg": "Carnet enviado a imprimir" }

POST /admin/set-printer 🔒

Body: printer (nombre/IP)

Respuesta 200

{ "error": 0, "msg": "Impresora configurada correctamente" }

POST /admin/sorteo 🔒

Registra participaciones en sorteo.

Body: data[] (array de { member, name, email, phone, tickets })

Respuesta 200

{ "error": 0, "msg": "Participación registrada" }

17. Printer

GET /printer/lines 🔒

Devuelve líneas pendientes de imprimir.

Respuesta 200

{ "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

{ "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.