SuperCafe: use Alumnos for persons, fix sysadmin add-user form
Co-authored-by: naielv <109038805+naielv@users.noreply.github.com>
This commit is contained in:
@@ -17,8 +17,7 @@ DATA/
|
||||
│ │ ├── aulario_abc123.json
|
||||
│ │ └── aulario_xyz456.json
|
||||
│ └── SuperCafe/ # SuperCafe data (per centro)
|
||||
│ ├── Personas.json # People directory
|
||||
│ ├── Menu.json # Menu items / categories
|
||||
│ ├── Menu.json # Menu items / categories (optional)
|
||||
│ └── Comandas/ # One JSON file per order
|
||||
│ └── sc<id>.json
|
||||
└── centro2/
|
||||
@@ -28,14 +27,10 @@ DATA/
|
||||
|
||||
## File Examples
|
||||
|
||||
### SuperCafe Persons (DATA/entreaulas/Centros/{centro_id}/SuperCafe/Personas.json)
|
||||
### SuperCafe (persons come from the existing Alumnos system)
|
||||
|
||||
```json
|
||||
{
|
||||
"persona1": { "Nombre": "Ana García", "Region": "Clase A" },
|
||||
"persona2": { "Nombre": "Luis Martínez", "Region": "Clase B" }
|
||||
}
|
||||
```
|
||||
Persons are loaded automatically from the aulario Alumnos directories — no separate configuration file is needed.
|
||||
See the **Aulario Student Names** section for the alumnos data format.
|
||||
|
||||
### SuperCafe Menu (DATA/entreaulas/Centros/{centro_id}/SuperCafe/Menu.json)
|
||||
|
||||
@@ -57,13 +52,14 @@ DATA/
|
||||
```json
|
||||
{
|
||||
"Fecha": "2024-01-15",
|
||||
"Persona": "persona1",
|
||||
"Persona": "aulario_abc123:Juan",
|
||||
"Comanda": "1x Café, 1x Bocadillo",
|
||||
"Notas": "Sin azúcar",
|
||||
"Estado": "Pedido"
|
||||
}
|
||||
```
|
||||
|
||||
`Persona` is stored as `{aulario_id}:{alumno_name}` and resolved to a display name at render time.
|
||||
Order statuses: `Pedido`, `En preparación`, `Listo`, `Entregado`, `Deuda`.
|
||||
A person with 3 or more orders in `Deuda` status cannot place new orders.
|
||||
|
||||
|
||||
@@ -17,6 +17,53 @@ function sc_safe_order_id($value)
|
||||
return preg_replace('/[^a-zA-Z0-9_-]/', '', basename((string)$value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load personas from the existing Alumnos system.
|
||||
* Returns array keyed by "{aulario_id}:{alumno_name}" with
|
||||
* ['Nombre', 'Region' (aulario display name), 'AularioID', 'HasPhoto'] entries.
|
||||
*/
|
||||
function sc_load_personas_from_alumnos($centro_id)
|
||||
{
|
||||
$aularios_path = "/DATA/entreaulas/Centros/$centro_id/Aularios";
|
||||
$personas = [];
|
||||
if (!is_dir($aularios_path)) {
|
||||
return $personas;
|
||||
}
|
||||
foreach (glob("$aularios_path/*.json") ?: [] as $aulario_file) {
|
||||
$aulario_id = basename($aulario_file, '.json');
|
||||
$aulario_data = json_decode(file_get_contents($aulario_file), true);
|
||||
$aulario_name = $aulario_data['name'] ?? $aulario_id;
|
||||
$alumnos_path = "$aularios_path/$aulario_id/Alumnos";
|
||||
if (!is_dir($alumnos_path)) {
|
||||
continue;
|
||||
}
|
||||
foreach (glob("$alumnos_path/*/", GLOB_ONLYDIR) ?: [] as $alumno_dir) {
|
||||
$alumno_name = basename($alumno_dir);
|
||||
$key = $aulario_id . ':' . $alumno_name;
|
||||
$personas[$key] = [
|
||||
'Nombre' => $alumno_name,
|
||||
'Region' => $aulario_name,
|
||||
'AularioID' => $aulario_id,
|
||||
'HasPhoto' => file_exists("$alumno_dir/photo.jpg"),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $personas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human-readable label for a persona key.
|
||||
* Falls back to showing the raw stored value for legacy orders.
|
||||
*/
|
||||
function sc_persona_label($persona_key, $personas)
|
||||
{
|
||||
if (isset($personas[$persona_key])) {
|
||||
$p = $personas[$persona_key];
|
||||
return $p['Nombre'] . ' (' . $p['Region'] . ')';
|
||||
}
|
||||
return $persona_key;
|
||||
}
|
||||
|
||||
$centro_id = safe_centro_id_sc($_SESSION['auth_data']['entreaulas']['centro'] ?? '');
|
||||
if ($centro_id === '') {
|
||||
require_once "_incl/pre-body.php";
|
||||
@@ -37,6 +84,7 @@ $estados_colores = [
|
||||
];
|
||||
|
||||
$can_edit = in_array('supercafe:edit', $_SESSION['auth_data']['permissions'] ?? []);
|
||||
$personas = sc_load_personas_from_alumnos($centro_id);
|
||||
|
||||
// Handle POST actions (requires edit permission)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $can_edit) {
|
||||
@@ -139,7 +187,7 @@ require_once "_incl/pre-body.php";
|
||||
?>
|
||||
<tr style="background: <?= htmlspecialchars($bg) ?>;">
|
||||
<td><?= htmlspecialchars($order['Fecha'] ?? '') ?></td>
|
||||
<td><?= htmlspecialchars($order['Persona'] ?? '') ?></td>
|
||||
<td><?= htmlspecialchars(sc_persona_label($order['Persona'] ?? '', $personas)) ?></td>
|
||||
<td style="white-space: pre-wrap; max-width: 250px;"><?= htmlspecialchars($order['Comanda'] ?? '') ?></td>
|
||||
<td><?= htmlspecialchars($order['Notas'] ?? '') ?></td>
|
||||
<td><strong><?= htmlspecialchars($estado) ?></strong></td>
|
||||
@@ -203,7 +251,7 @@ require_once "_incl/pre-body.php";
|
||||
<?php foreach ($orders_deuda as $order): ?>
|
||||
<tr style="background: #f5d3ff;">
|
||||
<td><?= htmlspecialchars($order['Fecha'] ?? '') ?></td>
|
||||
<td><?= htmlspecialchars($order['Persona'] ?? '') ?></td>
|
||||
<td><?= htmlspecialchars(sc_persona_label($order['Persona'] ?? '', $personas)) ?></td>
|
||||
<td style="white-space: pre-wrap; max-width: 250px;"><?= htmlspecialchars($order['Comanda'] ?? '') ?></td>
|
||||
<td><?= htmlspecialchars($order['Notas'] ?? '') ?></td>
|
||||
<?php if ($can_edit): ?>
|
||||
|
||||
@@ -31,14 +31,45 @@ define('SC_MAX_DEBTS', 3);
|
||||
|
||||
$valid_statuses = ['Pedido', 'En preparación', 'Listo', 'Entregado', 'Deuda'];
|
||||
|
||||
function sc_load_personas($sc_base)
|
||||
/**
|
||||
* Load personas from the existing Alumnos system (alumnos.php).
|
||||
* Returns array keyed by "{aulario_id}:{alumno_name}" with
|
||||
* ['Nombre', 'Region' (aulario display name), 'AularioID'] entries.
|
||||
* Groups are sorted by aulario name, alumnos sorted alphabetically.
|
||||
*/
|
||||
function sc_load_personas_from_alumnos($centro_id)
|
||||
{
|
||||
$path = "$sc_base/Personas.json";
|
||||
if (!file_exists($path)) {
|
||||
return [];
|
||||
$aularios_path = "/DATA/entreaulas/Centros/$centro_id/Aularios";
|
||||
$personas = [];
|
||||
if (!is_dir($aularios_path)) {
|
||||
return $personas;
|
||||
}
|
||||
$data = json_decode(file_get_contents($path), true);
|
||||
return is_array($data) ? $data : [];
|
||||
$aulario_files = glob("$aularios_path/*.json") ?: [];
|
||||
foreach ($aulario_files as $aulario_file) {
|
||||
$aulario_id = basename($aulario_file, '.json');
|
||||
$aulario_data = json_decode(file_get_contents($aulario_file), true);
|
||||
$aulario_name = $aulario_data['name'] ?? $aulario_id;
|
||||
$alumnos_path = "$aularios_path/$aulario_id/Alumnos";
|
||||
if (!is_dir($alumnos_path)) {
|
||||
continue;
|
||||
}
|
||||
$alumno_dirs = glob("$alumnos_path/*/", GLOB_ONLYDIR) ?: [];
|
||||
usort($alumno_dirs, function ($a, $b) {
|
||||
return strcasecmp(basename($a), basename($b));
|
||||
});
|
||||
foreach ($alumno_dirs as $alumno_dir) {
|
||||
$alumno_name = basename($alumno_dir);
|
||||
// Key uses ':' as separator; safe_id_segment chars [A-Za-z0-9_-] exclude ':'
|
||||
$key = $aulario_id . ':' . $alumno_name;
|
||||
$personas[$key] = [
|
||||
'Nombre' => $alumno_name,
|
||||
'Region' => $aulario_name,
|
||||
'AularioID' => $aulario_id,
|
||||
'HasPhoto' => file_exists("$alumno_dir/photo.jpg"),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $personas;
|
||||
}
|
||||
|
||||
function sc_load_menu($sc_base)
|
||||
@@ -51,7 +82,7 @@ function sc_load_menu($sc_base)
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
function sc_count_debts($persona_id)
|
||||
function sc_count_debts($persona_key)
|
||||
{
|
||||
if (!is_dir(SC_DATA_DIR)) {
|
||||
return 0;
|
||||
@@ -60,7 +91,7 @@ function sc_count_debts($persona_id)
|
||||
foreach (glob(SC_DATA_DIR . '/*.json') ?: [] as $file) {
|
||||
$data = json_decode(file_get_contents($file), true);
|
||||
if (is_array($data)
|
||||
&& ($data['Persona'] ?? '') === $persona_id
|
||||
&& ($data['Persona'] ?? '') === $persona_key
|
||||
&& ($data['Estado'] ?? '') === 'Deuda') {
|
||||
$count++;
|
||||
}
|
||||
@@ -92,13 +123,19 @@ if (!$is_new && is_readable($order_file)) {
|
||||
}
|
||||
}
|
||||
|
||||
$personas = sc_load_personas($sc_base);
|
||||
$personas = sc_load_personas_from_alumnos($centro_id);
|
||||
$menu = sc_load_menu($sc_base);
|
||||
|
||||
// Group personas by aulario for the optgroup picker
|
||||
$personas_by_aulario = [];
|
||||
foreach ($personas as $key => $pinfo) {
|
||||
$personas_by_aulario[$pinfo['Region']][$key] = $pinfo;
|
||||
}
|
||||
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$persona_id = $_POST['Persona'] ?? '';
|
||||
$persona_key = $_POST['Persona'] ?? '';
|
||||
$notas = trim($_POST['Notas'] ?? '');
|
||||
$estado = $_POST['Estado'] ?? 'Pedido';
|
||||
|
||||
@@ -106,8 +143,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$estado = 'Pedido';
|
||||
}
|
||||
|
||||
if ($persona_id === '') {
|
||||
$error = '¡Hay que elegir una persona!';
|
||||
// Validate that the submitted persona key exists in the loaded list.
|
||||
// When no alumnos are configured ($personas is empty), accept any non-empty free-text value.
|
||||
if ($persona_key === '' || (!empty($personas) && !array_key_exists($persona_key, $personas))) {
|
||||
$error = '¡Hay que elegir una persona válida!';
|
||||
} else {
|
||||
// Build comanda string from selected menu items
|
||||
$comanda_parts = [];
|
||||
@@ -122,7 +161,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No menu configured: accept free-text input
|
||||
$manual = trim($_POST['Comanda_manual'] ?? '');
|
||||
if ($manual !== '') {
|
||||
$comanda_parts[] = $manual;
|
||||
@@ -130,10 +168,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
$comanda_str = implode(', ', $comanda_parts);
|
||||
|
||||
// Debt check: only for new orders or when changing the person
|
||||
// Debt check: only for new orders or when the person changes
|
||||
$prev_persona = $order_data['Persona'] ?? '';
|
||||
if ($is_new || $prev_persona !== $persona_id) {
|
||||
$debt_count = sc_count_debts($persona_id);
|
||||
if ($is_new || $prev_persona !== $persona_key) {
|
||||
$debt_count = sc_count_debts($persona_key);
|
||||
if ($debt_count >= SC_MAX_DEBTS) {
|
||||
$error = 'Esta persona tiene ' . $debt_count . ' comandas en deuda. No se puede realizar el pedido.';
|
||||
}
|
||||
@@ -142,7 +180,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if ($error === '') {
|
||||
$new_data = [
|
||||
'Fecha' => date('Y-m-d'),
|
||||
'Persona' => $persona_id,
|
||||
'Persona' => $persona_key,
|
||||
'Comanda' => $comanda_str,
|
||||
'Notas' => $notas,
|
||||
'Estado' => $is_new ? 'Pedido' : $estado,
|
||||
@@ -192,26 +230,44 @@ require_once "_incl/pre-body.php";
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>Persona</strong></label>
|
||||
<?php if (!empty($personas)): ?>
|
||||
<?php if (!empty($personas_by_aulario)): ?>
|
||||
<select name="Persona" class="form-select" required>
|
||||
<option value="">-- Selecciona una persona --</option>
|
||||
<?php foreach ($personas as $pid => $pinfo): ?>
|
||||
<option value="<?= htmlspecialchars($pid) ?>"
|
||||
<?= ($order_data['Persona'] === (string)$pid) ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($pinfo['Nombre'] ?? $pid) ?>
|
||||
<?php if (!empty($pinfo['Region'])): ?>
|
||||
(<?= htmlspecialchars($pinfo['Region']) ?>)
|
||||
<?php endif; ?>
|
||||
<?php foreach ($personas_by_aulario as $region_name => $group): ?>
|
||||
<optgroup label="<?= htmlspecialchars($region_name) ?>">
|
||||
<?php foreach ($group as $pkey => $pinfo): ?>
|
||||
<option value="<?= htmlspecialchars($pkey) ?>"
|
||||
<?= ($order_data['Persona'] === $pkey) ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($pinfo['Nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php
|
||||
// Show photo of the currently selected person (if editing)
|
||||
$sel_key = $order_data['Persona'];
|
||||
$sel_info = $personas[$sel_key] ?? null;
|
||||
if ($sel_info && $sel_info['HasPhoto']):
|
||||
?>
|
||||
<div id="sc-persona-photo" style="margin-top: 8px;">
|
||||
<?php $photo_url = '/entreaulas/_filefetch.php?type=alumno_photo'
|
||||
. '¢ro=' . urlencode($centro_id)
|
||||
. '&aulario=' . urlencode($sel_info['AularioID'])
|
||||
. '&alumno=' . urlencode($sel_info['Nombre']); ?>
|
||||
<img src="<?= htmlspecialchars($photo_url) ?>"
|
||||
alt="Foto de <?= htmlspecialchars($sel_info['Nombre']) ?>"
|
||||
style="height: 80px; border-radius: 8px; border: 2px solid #dee2e6;">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<input type="text" name="Persona" class="form-control"
|
||||
value="<?= htmlspecialchars($order_data['Persona']) ?>"
|
||||
placeholder="Nombre de la persona" required>
|
||||
<small class="text-muted">
|
||||
No hay personas configuradas en
|
||||
<code>/DATA/entreaulas/Centros/<?= htmlspecialchars($centro_id) ?>/SuperCafe/Personas.json</code>.
|
||||
No hay alumnos registrados en los aularios de este centro.
|
||||
Añade alumnos desde
|
||||
<a href="/entreaulas/">EntreAulas</a>.
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -281,3 +337,4 @@ require_once "_incl/pre-body.php";
|
||||
</form>
|
||||
|
||||
<?php require_once "_incl/post-body.php"; ?>
|
||||
|
||||
|
||||
@@ -192,6 +192,33 @@ switch ($_GET['action'] ?? '') {
|
||||
<button type="submit" class="btn btn-primary mt-3">Crear Usuario</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card pad">
|
||||
<div>
|
||||
<h2>EntreAulas: Configuración</h2>
|
||||
<div class="mb-3">
|
||||
<label for="centro" class="form-label">Centro asociado:</label>
|
||||
<select id="centro" name="centro" class="form-select">
|
||||
<option value="">-- Selecciona un centro --</option>
|
||||
<?php
|
||||
$centros_folders_add = glob("/DATA/entreaulas/Centros/*", GLOB_ONLYDIR) ?: [];
|
||||
foreach ($centros_folders_add as $centro_folder) {
|
||||
$centro_id_opt = basename($centro_folder);
|
||||
echo '<option value="' . htmlspecialchars($centro_id_opt) . '">' . htmlspecialchars($centro_id_opt) . '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="role" class="form-label">Rol en EntreAulas:</label>
|
||||
<select id="role" name="role" class="form-select">
|
||||
<option value="">-- Selecciona un rol --</option>
|
||||
<option value="teacher">Profesor</option>
|
||||
<option value="student">Estudiante</option>
|
||||
</select>
|
||||
</div>
|
||||
<p class="text-muted"><small>Las aulas podrán asignarse tras guardar el usuario.</small></p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
require_once "_incl/post-body.php";
|
||||
|
||||
Reference in New Issue
Block a user