*** Begin Patch *** Update File: app/Services/Analytics/LoanAnalyticsService.php @@ private function fetchTopProducts(array $clauses, array $params, array $period, int $limit = 5): array { $localClauses = $clauses; $localClauses[] = 'lp.product_type IS NOT NULL'; $localClauses[] = 'lp.product_type != :excluded_product_type'; @@ $this->bindParams($stmt, $localParams); $stmt->bindValue(':product_limit', $limit, PDO::PARAM_INT); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: []; return array_map(static function (array $row): array { return [ 'id' => isset($row['sub_product_id']) ? (int) $row['sub_product_id'] : null, 'label' => $row['sub_product_name'] ?? LoanAnalyticsService::formatProductLabel($row['product_type'] ?? null), 'product_type' => $row['product_type'] ?? null, 'total' => (int) ($row['total'] ?? 0), 'volume_total' => $row['volume_total'] !== null ? (float) $row['volume_total'] : 0.0, 'disbursed_total' => $row['disbursed_total'] !== null ? (float) $row['disbursed_total'] : 0.0, ]; }, $rows); } + + /** + * @param array $clauses + * @param array $params + * @return array> + */ + private function fetchCancellationRanking(array $clauses, array $params, array $period, int $limit = 12): array + { + $localClauses = $clauses; + $localParams = $params; + $localClauses[] = 'lp.status IN (:ranking_cancelled, :ranking_rejected)'; + $localParams['ranking_cancelled'] = LoanProposal::STATUS_CANCELLED; + $localParams['ranking_rejected'] = LoanProposal::STATUS_REJECTED; + [$localClauses, $localParams] = $this->appendPeriodFilter( + $localClauses, + $localParams, + $period, + 'lp.created_at', + 'cancellation_ranking_created' + ); + + $sql = "SELECT + lp.status, + COALESCE(sc.label, lp.status) AS status_label, + CASE + WHEN lp.status_reason_label IS NOT NULL AND lp.status_reason_label != '' THEN lp.status_reason_label + WHEN sr.label IS NOT NULL THEN sr.label + ELSE 'Nao informado' + END AS reason_label, + CASE + WHEN lp.api_integration_id IS NOT NULL THEN COALESCE(ai.name, CONCAT('Integracao #', lp.api_integration_id)) + WHEN NULLIF(TRIM(lp.operation_bank_code), '') IS NOT NULL THEN + COALESCE( + bc.name, + CONCAT('Banco ', NULLIF(TRIM(lp.operation_bank_code), '')) + ) + ELSE 'Nao informado' + END AS bank_name, + COALESCE(sp.name, 'Nao informado') AS sub_product_name, + lp.product_type, + COALESCE(employee.name, 'Nao atribuido') AS employee_name, + COUNT(*) AS total + FROM loan_proposals AS lp + LEFT JOIN loan_proposal_status_catalog AS sc ON sc.slug = lp.status + LEFT JOIN loan_proposal_status_reasons AS sr ON sr.id = lp.status_reason_id + LEFT JOIN loan_sub_products AS sp ON sp.id = lp.sub_product_id + LEFT JOIN users AS employee ON employee.id = lp.employee_id + LEFT JOIN api_integrations AS ai ON ai.id = lp.api_integration_id + LEFT JOIN bank_catalog AS bc ON bc.code = lp.operation_bank_code"; + + $sql .= $this->buildWhere($localClauses); + + $sql .= ' GROUP BY + lp.status, + status_label, + reason_label, + bank_name, + lp.product_type, + sub_product_name, + employee_name + ORDER BY total DESC + LIMIT :cancellation_limit'; + + $stmt = $this->db->prepare($sql); + $this->bindParams($stmt, $localParams); + $stmt->bindValue(':cancellation_limit', $limit, PDO::PARAM_INT); + $stmt->execute(); + + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: []; + + return array_map(static function (array $row): array { + $productType = isset($row['product_type']) && $row['product_type'] !== '' + ? (string) $row['product_type'] + : null; + + return [ + 'status' => (string) ($row['status'] ?? ''), + 'status_label' => (string) ($row['status_label'] ?? ($row['status'] ?? 'Status')), + 'reason_label' => (string) ($row['reason_label'] ?? 'Nao informado'), + 'bank_name' => (string) ($row['bank_name'] ?? 'Nao informado'), + 'product_type' => $productType, + 'product_label' => self::formatProductLabel($productType), + 'sub_product_name' => (string) ($row['sub_product_name'] ?? 'Nao informado'), + 'employee_name' => (string) ($row['employee_name'] ?? 'Nao atribuido'), + 'total' => (int) ($row['total'] ?? 0), + ]; + }, $rows); + } *** End Patch