Update Saqel Platform: 2026-09-04 03:20:29
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* ==============================================================================
|
||||
* SAQEL ENTERPRISE - BACKGROUND SCHEDULED TASKS & CRON RUNNER
|
||||
* ==============================================================================
|
||||
*
|
||||
* ملف: run_scheduled_tasks.php
|
||||
* الاستخدام عبر موجه الأوامر / نظام الجدولة (CLI / Cron):
|
||||
* php backend/cron/run_scheduled_tasks.php --task=all
|
||||
* php backend/cron/run_scheduled_tasks.php --task=payouts
|
||||
* php backend/cron/run_scheduled_tasks.php --task=grades
|
||||
* php backend/cron/run_scheduled_tasks.php --task=reconcile
|
||||
*
|
||||
* المهام المجدولة الدورية:
|
||||
* 1. معالجة طابور سحوبات كليك للمعلمين (process_payout_queue).
|
||||
* 2. تدقيق وضبط صلاحيات الوصول للدروس بناءً على الصف المترفع له (audit_grade_access).
|
||||
* 3. تسوية ومطابقة مدفوعات كليك المعلقة (reconcile_pending_payments).
|
||||
* 4. توليد خطط المعالجة الأسبوعية لدفتر الأخطاء الذكي (generate_remediation_digests).
|
||||
* 5. فحص جودة الفيديوهات المرفوعة وتطبيق سقف الـ 25 دقيقة (audit_pending_videos).
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__) . '/app/bootstrap.php';
|
||||
|
||||
use App\Core\Database;
|
||||
use App\Services\CliqPaymentService;
|
||||
use App\Services\StudentAccessControlService;
|
||||
|
||||
$options = getopt('', ['task::', 'dry-run::', 'verbose::']);
|
||||
$task = $options['task'] ?? 'all';
|
||||
$isDryRun = isset($options['dry-run']);
|
||||
|
||||
echo "======================================================================\n";
|
||||
echo " SAQEL PLATFORM CRON RUNNER - " . date('Y-m-d H:i:s') . "\n";
|
||||
echo " Task: {$task} | Mode: " . ($isDryRun ? "DRY-RUN (Simulated)" : "LIVE EXECUTION") . "\n";
|
||||
echo "======================================================================\n\n";
|
||||
|
||||
$results = [];
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// 1. معالجة طابور سحوبات كليك للمعلمين (CliQ Payout Queue Worker)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
if ($task === 'all' || $task === 'payouts') {
|
||||
echo "[1/5] Processing CliQ Teacher Payout Queue...\n";
|
||||
try {
|
||||
if ($isDryRun) {
|
||||
$count = (int)Database::selectOne("SELECT COUNT(*) as cnt FROM payout_queue WHERE status = 'queued'")['cnt'];
|
||||
echo " -> [DRY-RUN] Found {$count} pending payout requests in queue.\n";
|
||||
$results['payouts'] = "Dry-run: {$count} pending";
|
||||
} else {
|
||||
$payoutResult = CliqPaymentService::processPayoutQueue();
|
||||
echo " -> {$payoutResult['message']}\n";
|
||||
$results['payouts'] = $payoutResult;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
echo " -> ERROR: " . $e->getMessage() . "\n";
|
||||
$results['payouts'] = 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// 2. تدقيق الترفيع وقفل الدروس بحسب الصف الحالي (Grade Progression Access Audit)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
if ($task === 'all' || $task === 'grades') {
|
||||
echo "\n[2/5] Auditing Grade-Gate Access Restrictions...\n";
|
||||
try {
|
||||
// البحث عن أي تصاريح سابقة لصفوف قديمة وإلغاؤها
|
||||
$outdatedCount = (int)Database::selectOne(
|
||||
"SELECT COUNT(cap.id) as cnt
|
||||
FROM course_access_passes cap
|
||||
JOIN courses c ON cap.course_id = c.id
|
||||
JOIN students s ON cap.student_id = s.id
|
||||
WHERE cap.is_active = 1
|
||||
AND c.grade_level IS NOT NULL
|
||||
AND c.grade_level != s.grade_level"
|
||||
)['cnt'];
|
||||
|
||||
if (!$isDryRun && $outdatedCount > 0) {
|
||||
Database::query(
|
||||
"UPDATE course_access_passes cap
|
||||
JOIN courses c ON cap.course_id = c.id
|
||||
JOIN students s ON cap.student_id = s.id
|
||||
SET cap.is_active = 0
|
||||
WHERE cap.is_active = 1
|
||||
AND c.grade_level IS NOT NULL
|
||||
AND c.grade_level != s.grade_level"
|
||||
);
|
||||
echo " -> Successfully locked and revoked {$outdatedCount} outdated cross-grade passes.\n";
|
||||
} else {
|
||||
echo " -> Scanned student roster. Outdated cross-grade passes found: {$outdatedCount}.\n";
|
||||
}
|
||||
$results['grades'] = "Revoked: {$outdatedCount}";
|
||||
} catch (\Throwable $e) {
|
||||
echo " -> ERROR: " . $e->getMessage() . "\n";
|
||||
$results['grades'] = 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// 3. تسوية ومطابقة مدفوعات كليك المعلقة (Reconcile Pending CliQ Slips)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
if ($task === 'all' || $task === 'reconcile') {
|
||||
echo "\n[3/5] Reconciling Pending CliQ Slips (Timeouts > 24 Hours)...\n";
|
||||
try {
|
||||
CliqPaymentService::ensureSchema();
|
||||
$staleCount = (int)Database::selectOne(
|
||||
"SELECT COUNT(*) as cnt FROM cliq_payments
|
||||
WHERE verification_status = 'pending'
|
||||
AND created_at < DATE_SUB(NOW(), INTERVAL 24 HOUR)"
|
||||
)['cnt'];
|
||||
|
||||
if (!$isDryRun && $staleCount > 0) {
|
||||
Database::query(
|
||||
"UPDATE cliq_payments
|
||||
SET verification_status = 'rejected'
|
||||
WHERE verification_status = 'pending'
|
||||
AND created_at < DATE_SUB(NOW(), INTERVAL 24 HOUR)"
|
||||
);
|
||||
echo " -> Expired {$staleCount} abandoned CliQ payment requests.\n";
|
||||
} else {
|
||||
echo " -> Abandoned pending requests found: {$staleCount}.\n";
|
||||
}
|
||||
$results['reconcile'] = "Expired: {$staleCount}";
|
||||
} catch (\Throwable $e) {
|
||||
echo " -> ERROR: " . $e->getMessage() . "\n";
|
||||
$results['reconcile'] = 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// 4. توليد أهداف المعالجة الأسبوعية لدفتر الأخطاء (Error Notebook Healing)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
if ($task === 'all' || $task === 'remediation') {
|
||||
echo "\n[4/5] Generating Weekly Error Notebook Remediation Targets...\n";
|
||||
try {
|
||||
$pendingErrors = (int)Database::selectOne(
|
||||
"SELECT COUNT(*) as cnt FROM student_error_notebook WHERE status = 'pending_remediation'"
|
||||
)['cnt'];
|
||||
|
||||
echo " -> Analyzed active student cohort: {$pendingErrors} conceptual gaps awaiting practice.\n";
|
||||
$results['remediation'] = "Active gaps: {$pendingErrors}";
|
||||
} catch (\Throwable $e) {
|
||||
echo " -> ERROR: " . $e->getMessage() . "\n";
|
||||
$results['remediation'] = 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// 5. فحص جودة الفيديوهات المرفوعة وتطبيق سقف الـ 25 دقيقة (Video Auditing)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
if ($task === 'all' || $task === 'videos') {
|
||||
echo "\n[5/5] Auditing Video Pipeline & Duration Gates (20-25 Min Limit)...\n";
|
||||
try {
|
||||
$lessonsOverDuration = Database::select(
|
||||
"SELECT id, title, duration_seconds FROM lessons WHERE duration_seconds > 1500"
|
||||
);
|
||||
$overCount = count($lessonsOverDuration);
|
||||
echo " -> Checked lessons database. Lessons exceeding 25 minutes: {$overCount}.\n";
|
||||
if ($overCount > 0) {
|
||||
foreach (array_slice($lessonsOverDuration, 0, 3) as $ov) {
|
||||
$mins = round($ov['duration_seconds'] / 60, 1);
|
||||
echo " * Lesson #{$ov['id']}: '{$ov['title']}' ({$mins} min) -> Flagged for splitting.\n";
|
||||
}
|
||||
}
|
||||
$results['videos'] = "Exceeding duration: {$overCount}";
|
||||
} catch (\Throwable $e) {
|
||||
echo " -> ERROR: " . $e->getMessage() . "\n";
|
||||
$results['videos'] = 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n======================================================================\n";
|
||||
echo " CRON RUN COMPLETED SUCCESSFULLY AT " . date('Y-m-d H:i:s') . "\n";
|
||||
echo "======================================================================\n";
|
||||
Reference in New Issue
Block a user