feat: auto-detect collect_and_post fields from endpoint body_fields

Instead of defining fields inline per flow, the admin now defines them
once on the endpoint (direction=upload). The bot reads body_fields from
company_endpoints at runtime, so the same endpoint can be reused by
multiple collect_and_post flows without duplicating field config.

DB: ALTER TABLE company_endpoints ADD COLUMN body_fields TEXT DEFAULT NULL

Changes:
- NormalBot: falls back to endpoint.body_fields when flow.fields is empty
- DashboardController: endpoint rows show a body_fields section for
  upload endpoints (key / label / prompt per field, add/remove rows)
- companyEndpointSave: reads + validates body_fields JSON and persists it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-29 11:10:37 -05:00
co-authored by Claude Sonnet 4.6
parent 3c7ea9fdf9
commit 21d30a0895
2 changed files with 99 additions and 21 deletions
+15 -1
View File
@@ -395,9 +395,23 @@ class NormalBot
private static function handleCollectAndPost(array $flow, array $context, array $company, int $ctxId): ?array
{
$fields = $flow['fields'] ?? [];
// If no inline fields, auto-detect from endpoint's body_fields definition
if (empty($fields)) {
$epKey = $flow['endpoint_key'] ?? '';
if ($epKey !== '') {
$stmt = db()->prepare("SELECT body_fields FROM company_endpoints WHERE company_id=? AND endpoint_key=? AND is_active=1 LIMIT 1");
$stmt->execute([(int)$company['id'], $epKey]);
$row = $stmt->fetch();
if ($row && !empty($row['body_fields'])) {
$fields = json_decode($row['body_fields'], true) ?: [];
}
}
}
if (empty($fields)) {
ConversationContext::reset($ctxId);
return self::sendText('⚠️ Flujo sin campos configurados. Contacta al administrador.', $context['from'], $company);
return self::sendText('⚠️ Flujo sin campos configurados. Define los campos en el endpoint. Escribe *menu* para volver.', $context['from'], $company);
}
$meta = ConversationContext::getMetadata($ctxId);