feat: Fase 3 con campos condicionales; fix del monitor del ERP
Cosecha, polinizacion y fertilizacion en un solo flujo en vez de tres: skip_if muestra el producto solo a las dos que lo llevan y el pase solo a polinizacion. El lote se pregunta antes que el producto porque la dosis depende de los dos — sale de la fertilizacion que se autorizo en su modulo, no la elige el usuario. ErpMonitor construia api_base_url + /health, que no existe en el ERP: la ruta correcta es ?peticion=ping y la URL sale de company_endpoints como el resto. Por eso el panel mostraba el ERP caido. Tampoco mandaba el Bearer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8399a86972
commit
42adeb64d0
+19
-3
@@ -17,9 +17,24 @@ class ErpMonitor
|
||||
|
||||
public static function check(array $company): array
|
||||
{
|
||||
$baseUrl = rtrim($company['api_base_url'] ?? '', '/');
|
||||
$healthUrl = $baseUrl !== '' ? $baseUrl . '/health' : '';
|
||||
// El ERP no expone /health sino ?peticion=ping, y la URL sale de
|
||||
// company_endpoints como el resto de las llamadas: api_base_url no
|
||||
// sirve para esto. Sin esto el panel mostraba el ERP siempre caído.
|
||||
$apiKey = $company['api_key'] ?? '';
|
||||
$healthUrl = '';
|
||||
try {
|
||||
$stmt = db()->prepare(
|
||||
"SELECT url FROM company_endpoints WHERE company_id = ? AND endpoint_key = ? AND is_active = 1 LIMIT 1"
|
||||
);
|
||||
$stmt->execute([(int)$company['id'], 'numeros_dn']);
|
||||
$url = (string)($stmt->fetchColumn() ?: '');
|
||||
if ($url !== '') {
|
||||
// Cualquier endpoint sirve de referencia; se reemplaza por ping
|
||||
$healthUrl = preg_replace('/peticion=[^&]*/', 'peticion=ping', $url);
|
||||
}
|
||||
} catch (\PDOException $e) {
|
||||
$healthUrl = '';
|
||||
}
|
||||
|
||||
if ($healthUrl === '') {
|
||||
return [
|
||||
@@ -27,7 +42,7 @@ class ErpMonitor
|
||||
'company_name' => $company['name'] ?? '',
|
||||
'status' => 'unknown',
|
||||
'latency_ms' => null,
|
||||
'error' => 'Sin URL configurada',
|
||||
'error' => 'Sin endpoint registrado para esta empresa',
|
||||
'last_check' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
}
|
||||
@@ -40,6 +55,7 @@ class ErpMonitor
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: Bearer ' . $apiKey,
|
||||
'X-API-Key: ' . $apiKey,
|
||||
'User-Agent: bot-palmas360-monitor/1.0',
|
||||
],
|
||||
|
||||
@@ -251,6 +251,7 @@ $configJson = [
|
||||
['id' => 'registrar_ciclo', 'modulo' => 'ciclos', 'title' => '🔄 Ciclos', 'description' => 'Abrir o cerrar lotes'],
|
||||
['id' => 'registrar_mantenimiento','modulo' => 'mantenimiento', 'title' => '🔧 Mantenimiento', 'description' => 'Avance sobre lotes pendientes'],
|
||||
['id' => 'registrar_labor', 'modulo' => 'labores', 'title' => '💪 Labor diaria', 'description' => 'Tractorista, transporte, horas extra'],
|
||||
['id' => 'registrar_labor_validada','modulo' => 'labores', 'title' => '🌾 Cosecha y otros','description' => 'Cosecha, polinización, fertilización'],
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -652,6 +653,96 @@ $configJson = [
|
||||
],
|
||||
],
|
||||
|
||||
// Fase 3: labores con validacion previa. Un solo flujo con campos
|
||||
// condicionales en vez de tres: cosecha no lleva producto, y el pase
|
||||
// es solo de polinizacion. El ERP valida inventario y autorizaciones,
|
||||
// y si rechaza algo lo dice en la respuesta.
|
||||
'registrar_labor_validada' => [
|
||||
'type' => 'collect_and_post',
|
||||
'endpoint_key' => 'labores_up',
|
||||
'header' => '🌾 Cosecha, polinización y fertilización',
|
||||
'confirm' => true,
|
||||
'success_text' => '✅ Enviado a Palmas360.',
|
||||
'back' => 'enviar_informacion',
|
||||
'nlu_description' => 'Registrar labor de cosecha, polinización o fertilización',
|
||||
'fields' => [
|
||||
[
|
||||
'key' => 'tipo',
|
||||
'label' => 'Tipo',
|
||||
'type' => 'static_select',
|
||||
'prompt' => '¿Qué vas a registrar?',
|
||||
'options' => [
|
||||
['id' => 'cosecha', 'label' => '🌾 Cosecha'],
|
||||
['id' => 'polinizacion', 'label' => '🌸 Polinización'],
|
||||
['id' => 'fertilizacion','label' => '🧪 Fertilización'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'novedad_id',
|
||||
'label' => 'Labor',
|
||||
'type' => 'select',
|
||||
'prompt' => '¿Qué labor se hizo?',
|
||||
'source_endpoint_key' => 'novedades_labor3_dn',
|
||||
'value_field' => 'id',
|
||||
'label_field' => 'nombre',
|
||||
],
|
||||
[
|
||||
'key' => 'fecha',
|
||||
'label' => 'Fecha',
|
||||
'type' => 'date_quick',
|
||||
'prompt' => '📅 ¿De qué fecha?',
|
||||
'other_validate' => 'date',
|
||||
'other_prompt' => 'Escribe la fecha (YYYY-MM-DD):',
|
||||
],
|
||||
[
|
||||
'key' => 'lote_id',
|
||||
'label' => 'Lote',
|
||||
'type' => 'select',
|
||||
'prompt' => '¿En qué lote?',
|
||||
'source_endpoint_key' => 'lotes_finca_dn',
|
||||
'value_field' => 'id',
|
||||
'label_field' => 'label',
|
||||
],
|
||||
[
|
||||
// Cosecha no lleva producto. La dosis sale de la
|
||||
// fertilizacion autorizada para ese lote, por eso se
|
||||
// pregunta despues del lote y no antes.
|
||||
'key' => 'producto_id',
|
||||
'label' => 'Producto',
|
||||
'type' => 'select',
|
||||
'prompt' => '¿Qué producto se aplicó?',
|
||||
'source_endpoint_key' => 'productos_fertilizacion_dn',
|
||||
'value_field' => 'id',
|
||||
'label_field' => 'nombre',
|
||||
'skip_if' => ['field' => 'tipo', 'not_in' => ['polinizacion', 'fertilizacion']],
|
||||
'empty_text' => '⚠️ Ese lote no tiene fertilización autorizada pendiente.',
|
||||
],
|
||||
[
|
||||
'key' => 'empleados',
|
||||
'label' => 'Trabajadores',
|
||||
'type' => 'multi_select',
|
||||
'prompt' => '¿Quiénes la hicieron? (puedes marcar varios)',
|
||||
'source_endpoint_key' => 'empleados_labor_dn',
|
||||
'value_field' => 'id',
|
||||
'label_field' => 'nombre',
|
||||
'from_phone' => 'tercero_id',
|
||||
],
|
||||
[
|
||||
'key' => 'cantidad',
|
||||
'label' => 'Cantidad',
|
||||
'type' => 'text',
|
||||
'prompt' => '¿Qué cantidad?',
|
||||
],
|
||||
[
|
||||
'key' => 'fase_polinizacion',
|
||||
'label' => 'Pase',
|
||||
'type' => 'text',
|
||||
'prompt' => '¿Qué pase de polinización?',
|
||||
'skip_if' => ['field' => 'tipo', 'equals' => 'polinizacion'],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
// Upload
|
||||
'enviar_informacion' => ['type' => 'menu', 'menu' => 'submenu_subir_ciclos', 'nlu_skip' => true, 'back' => 'show_main_menu'],
|
||||
|
||||
@@ -686,6 +777,7 @@ $configJson = [
|
||||
['id' => 'registrar_ciclo', 'modulo' => 'ciclos', 'title' => '🔄 Ciclos', 'description' => 'Abrir o cerrar lotes'],
|
||||
['id' => 'registrar_mantenimiento','modulo' => 'mantenimiento', 'title' => '🔧 Mantenimiento', 'description' => 'Avance sobre lotes pendientes'],
|
||||
['id' => 'registrar_labor', 'modulo' => 'labores', 'title' => '💪 Labor diaria', 'description' => 'Tractorista, transporte, horas extra'],
|
||||
['id' => 'registrar_labor_validada','modulo' => 'labores', 'title' => '🌾 Cosecha y otros','description' => 'Cosecha, polinización, fertilización'],
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -808,6 +900,9 @@ $endpoints = [
|
||||
['key' => 'lotes_finca_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_x_finca&finca_id={finca_id}'],
|
||||
['key' => 'empleados_labor_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=empleados&estado=1&items=200'],
|
||||
['key' => 'labores_up', 'dir' => 'upload', 'url' => $BASE . '?peticion=labores_up'],
|
||||
// Fase 3: las que arrastran inventario o autorizacion previa
|
||||
['key' => 'novedades_labor3_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=novedades_labor_dn&fase=3'],
|
||||
['key' => 'productos_fertilizacion_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=productos_fertilizacion_dn&lote_id={lote_id}'],
|
||||
['key' => 'lotes_mantenimiento_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_mantenimiento_dn&grupo={grupo_id}&finca_id={finca_id}'],
|
||||
['key' => 'lotes_mantenimiento_todos_dn', 'dir' => 'download', 'url' => $BASE . '?peticion=lotes_mantenimiento_dn&grupo={grupo_id}&finca_id={finca_id}&todos=1'],
|
||||
// Todos los lotes (PDF) por ciclo
|
||||
|
||||
@@ -580,6 +580,48 @@ foreach (['novedades_labor_dn', 'lotes_finca_dn', 'empleados_labor_dn', 'labores
|
||||
check("endpoint {$k} registrado", isset($eps[$k]), true);
|
||||
}
|
||||
|
||||
echo "\nFase 3 — campos según el tipo\n";
|
||||
|
||||
$f3 = $flows['registrar_labor_validada'] ?? [];
|
||||
$c3 = array_column($f3['fields'] ?? [], null, 'key');
|
||||
|
||||
check('ofrece los tres tipos',
|
||||
array_column($c3['tipo']['options'], 'id'), ['cosecha', 'polinizacion', 'fertilizacion']);
|
||||
check('el producto sale de la fertilización autorizada del lote',
|
||||
$c3['producto_id']['source_endpoint_key'] ?? null, 'productos_fertilizacion_dn');
|
||||
|
||||
/** Espejo de capShouldSkip() */
|
||||
$saltear = function (array $campo, array $col): bool {
|
||||
$si = $campo['skip_if'] ?? null;
|
||||
if (!$si) return false;
|
||||
$v = (string)($col[$si['field']] ?? '');
|
||||
if (isset($si['not_in'])) return !in_array($v, array_map('strval', $si['not_in']), true);
|
||||
if (isset($si['equals'])) return $v !== (string)$si['equals'];
|
||||
return false;
|
||||
};
|
||||
$pedidos = function (array $campos, string $tipo) use ($saltear): array {
|
||||
$col = ['tipo' => $tipo];
|
||||
return array_values(array_filter(array_keys($campos),
|
||||
fn($k) => !$saltear($campos[$k], $col)));
|
||||
};
|
||||
|
||||
// Los tres formularios del pedido, sin escribir tres flujos
|
||||
check('cosecha: sin producto ni pase',
|
||||
$pedidos($c3, 'cosecha'), ['tipo', 'novedad_id', 'fecha', 'lote_id', 'empleados', 'cantidad']);
|
||||
check('fertilización: con producto, sin pase',
|
||||
$pedidos($c3, 'fertilizacion'), ['tipo', 'novedad_id', 'fecha', 'lote_id', 'producto_id', 'empleados', 'cantidad']);
|
||||
check('polinización: con producto y pase',
|
||||
$pedidos($c3, 'polinizacion'), ['tipo', 'novedad_id', 'fecha', 'lote_id', 'producto_id', 'empleados', 'cantidad', 'fase_polinizacion']);
|
||||
|
||||
// El producto se pregunta despues del lote: la dosis depende de los dos
|
||||
$orden = array_keys($c3);
|
||||
check('el lote se pregunta antes que el producto',
|
||||
array_search('lote_id', $orden) < array_search('producto_id', $orden), true);
|
||||
|
||||
foreach (['novedades_labor3_dn', 'productos_fertilizacion_dn'] as $k) {
|
||||
check("endpoint {$k} registrado", isset($eps[$k]), true);
|
||||
}
|
||||
|
||||
echo "\nAlcance de fincas por número\n";
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user