Update: 2026-05-08 04:58:23
This commit is contained in:
142
app/modules_app/reports/company_health.php
Normal file
142
app/modules_app/reports/company_health.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/**
|
||||
* AI Company Health Report
|
||||
* GET /v1/reports/company-health?company_id=xxx
|
||||
*
|
||||
* Generates an AI-powered financial health analysis using invoice data.
|
||||
* Returns insights, warnings, and recommendations in Arabic.
|
||||
*/
|
||||
|
||||
use App\Core\Database;
|
||||
use App\Core\Encryption;
|
||||
use App\Core\AI;
|
||||
use App\Middleware\AuthMiddleware;
|
||||
|
||||
$decoded = AuthMiddleware::check();
|
||||
$db = Database::getInstance();
|
||||
|
||||
$tenantId = $decoded['tenant_id'];
|
||||
$role = $decoded['role'];
|
||||
$companyId = $_GET['company_id'] ?? null;
|
||||
|
||||
if (!$companyId) {
|
||||
json_error('معرّف الشركة مطلوب', 422);
|
||||
}
|
||||
|
||||
// Verify access
|
||||
$accessQuery = ($role === 'super_admin')
|
||||
? "SELECT id, name, tax_identification_number FROM companies WHERE id = ? AND deleted_at IS NULL"
|
||||
: "SELECT id, name, tax_identification_number FROM companies WHERE id = ? AND tenant_id = ? AND deleted_at IS NULL";
|
||||
|
||||
$accessParams = ($role === 'super_admin') ? [$companyId] : [$companyId, $tenantId];
|
||||
$stmt = $db->prepare($accessQuery);
|
||||
$stmt->execute($accessParams);
|
||||
$company = $stmt->fetch();
|
||||
|
||||
if (!$company) {
|
||||
json_error('الشركة غير موجودة أو ليس لديك صلاحية', 404);
|
||||
}
|
||||
|
||||
$companyName = Encryption::decrypt($company['name']) ?: $company['name'];
|
||||
|
||||
try {
|
||||
// 1. Gather last 3 months of data
|
||||
$months = [];
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$m = date('m', strtotime("-{$i} months"));
|
||||
$y = date('Y', strtotime("-{$i} months"));
|
||||
|
||||
$stmt = $db->prepare("
|
||||
SELECT
|
||||
COUNT(*) as total_invoices,
|
||||
COALESCE(SUM(grand_total), 0) as revenue,
|
||||
COALESCE(SUM(tax_amount), 0) as tax,
|
||||
COALESCE(SUM(discount_total), 0) as discounts,
|
||||
COALESCE(AVG(grand_total), 0) as avg_invoice,
|
||||
SUM(CASE WHEN status = 'submitted' THEN 1 ELSE 0 END) as submitted_count,
|
||||
SUM(CASE WHEN status = 'extracted' THEN 1 ELSE 0 END) as pending_count
|
||||
FROM invoices
|
||||
WHERE company_id = ? AND MONTH(created_at) = ? AND YEAR(created_at) = ?
|
||||
");
|
||||
$stmt->execute([$companyId, $m, $y]);
|
||||
$data = $stmt->fetch();
|
||||
$data['month'] = (int)$m;
|
||||
$data['year'] = (int)$y;
|
||||
$months[] = $data;
|
||||
}
|
||||
|
||||
// 2. Pending invoices count
|
||||
$pendingStmt = $db->prepare("SELECT COUNT(*) FROM invoices WHERE company_id = ? AND status = 'extracted'");
|
||||
$pendingStmt->execute([$companyId]);
|
||||
$pendingCount = (int)$pendingStmt->fetchColumn();
|
||||
|
||||
// 3. Build AI prompt
|
||||
$dataJson = json_encode([
|
||||
'company_name' => $companyName,
|
||||
'tin' => $company['tax_identification_number'],
|
||||
'monthly_data' => $months,
|
||||
'pending_invoices' => $pendingCount,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$prompt = <<<PROMPT
|
||||
أنت محلل مالي خبير. حلل البيانات التالية لشركة وأعطِ تقريراً مختصراً بالعربية.
|
||||
|
||||
البيانات:
|
||||
{$dataJson}
|
||||
|
||||
أعد الرد بصيغة JSON فقط بدون أي نص إضافي:
|
||||
{
|
||||
"health_score": (رقم من 1 إلى 10),
|
||||
"health_label": ("ممتاز" أو "جيد" أو "متوسط" أو "يحتاج انتباه"),
|
||||
"summary": "ملخص من سطرين عن الحالة المالية",
|
||||
"insights": ["ملاحظة 1", "ملاحظة 2", "ملاحظة 3"],
|
||||
"warnings": ["تحذير إن وجد"],
|
||||
"recommendations": ["توصية 1", "توصية 2"]
|
||||
}
|
||||
PROMPT;
|
||||
|
||||
$aiResponse = AI::ask($prompt, $tenantId);
|
||||
|
||||
// Parse AI response
|
||||
$report = null;
|
||||
if ($aiResponse) {
|
||||
// Extract JSON from response
|
||||
$cleaned = preg_replace('/```json?\s*|```/', '', $aiResponse);
|
||||
$report = json_decode(trim($cleaned), true);
|
||||
}
|
||||
|
||||
// Fallback if AI fails
|
||||
if (!$report) {
|
||||
$currentMonth = $months[0] ?? [];
|
||||
$prevMonth = $months[1] ?? [];
|
||||
$score = 5;
|
||||
|
||||
if (($currentMonth['total_invoices'] ?? 0) > 0) $score += 2;
|
||||
if (($currentMonth['submitted_count'] ?? 0) > 0) $score += 1;
|
||||
if ($pendingCount === 0) $score += 1;
|
||||
if (($currentMonth['revenue'] ?? 0) > ($prevMonth['revenue'] ?? 0)) $score += 1;
|
||||
|
||||
$report = [
|
||||
'health_score' => min(10, $score),
|
||||
'health_label' => $score >= 8 ? 'ممتاز' : ($score >= 6 ? 'جيد' : 'متوسط'),
|
||||
'summary' => 'تقرير مبني على البيانات المتوفرة بدون تحليل AI.',
|
||||
'insights' => ['عدد الفواتير: ' . ($currentMonth['total_invoices'] ?? 0)],
|
||||
'warnings' => $pendingCount > 0 ? ["يوجد {$pendingCount} فاتورة بانتظار المراجعة"] : [],
|
||||
'recommendations' => ['تأكد من إرسال جميع الفواتير المعتمدة لجوفوترا'],
|
||||
];
|
||||
}
|
||||
|
||||
json_success([
|
||||
'company_id' => $companyId,
|
||||
'company_name' => $companyName,
|
||||
'report' => $report,
|
||||
'data' => [
|
||||
'monthly_summary' => $months,
|
||||
'pending_count' => $pendingCount,
|
||||
],
|
||||
'generated_at' => date('c'),
|
||||
], 'تقرير صحة الشركة');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
safe_error($e, 'reports/company-health', 'حدث خطأ في إنشاء التقرير.');
|
||||
}
|
||||
Reference in New Issue
Block a user