prepare("SELECT * FROM companies WHERE phone_number_id = ? AND is_active = 1 LIMIT 1"); $stmt->execute([$phoneNumberId]); $row = $stmt->fetch(); return $row ?: null; } public static function findById(int $id): ?array { $stmt = db()->prepare("SELECT * FROM companies WHERE id = ? LIMIT 1"); $stmt->execute([$id]); $row = $stmt->fetch(); return $row ?: null; } public static function findByApiKey(string $apiKey): ?array { $stmt = db()->prepare("SELECT * FROM companies WHERE api_key = ? AND is_active = 1 LIMIT 1"); $stmt->execute([$apiKey]); $row = $stmt->fetch(); return $row ?: null; } public static function findAll(bool $includeInactive = false): array { $where = $includeInactive ? '1=1' : 'is_active = 1'; return db()->query("SELECT * FROM companies WHERE {$where} ORDER BY name")->fetchAll(); } /** * @throws \RuntimeException with a human-readable message on DB error */ public static function save(array $data): int { $db = db(); $id = (int)($data['id'] ?? 0); $fields = ['name', 'display_name', 'phone_number_id', 'display_phone', 'api_base_url', 'api_key', 'bot_type', 'requires_approval', 'is_active', 'config_json', 'erp_active_users']; // Checkboxes only default to 0 on full company-form saves (when 'name' is present). // Partial saves (e.g. bot-config saving only config_json) must NOT touch is_active. if (array_key_exists('name', $data)) { foreach (['requires_approval', 'is_active'] as $cb) { if (!array_key_exists($cb, $data)) { $data[$cb] = 0; } } } // Integer fields: cast so empty string '' doesn't fail the INT column foreach (['requires_approval', 'is_active', 'erp_active_users'] as $f) { if (array_key_exists($f, $data)) { $data[$f] = (int)$data[$f]; } } $params = []; $sets = []; foreach ($fields as $f) { if (array_key_exists($f, $data)) { $sets[] = "{$f} = ?"; $params[] = is_array($data[$f]) || is_object($data[$f]) ? json_encode($data[$f]) : $data[$f]; } } try { if ($id > 0) { $params[] = $id; $db->prepare("UPDATE companies SET " . implode(', ', $sets) . " WHERE id = ?") ->execute($params); return $id; } // INSERT — require name if (trim($data['name'] ?? '') === '') { throw new \RuntimeException('El nombre de la empresa es requerido.'); } $insertData = []; foreach ($fields as $f) { if (array_key_exists($f, $data)) { $insertData[$f] = $data[$f]; } } $cols = implode(', ', array_keys($insertData)); $vals = implode(', ', array_fill(0, count($insertData), '?')); $db->prepare("INSERT INTO companies ({$cols}) VALUES ({$vals})") ->execute(array_values($insertData)); return (int)$db->lastInsertId(); } catch (\PDOException $e) { $msg = $e->getMessage(); // Duplicate entry on name unique key if (str_contains($msg, '1062') || str_contains($msg, 'Duplicate entry')) { throw new \RuntimeException('Ya existe una empresa con ese nombre.'); } throw new \RuntimeException('Error al guardar: ' . $msg); } } public static function delete(int $id): bool { $stmt = db()->prepare("DELETE FROM companies WHERE id = ?"); $stmt->execute([$id]); return $stmt->rowCount() > 0; } }