🚀 مُصادَق: تحديث برمجي جديد 2026-05-03 13:39

This commit is contained in:
Hamza-Ayed
2026-05-03 13:39:05 +03:00
parent 2de6a0adfd
commit ea415e3a11
19 changed files with 972 additions and 7 deletions

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Queue\Jobs;
use App\Services\RiskAnalysisService;
use App\Core\Database;
use Throwable;
final class RiskAnalysisJob
{
public function __construct(
private readonly RiskAnalysisService $riskService
) {}
public function handle(array $payload): void
{
$companyId = $payload['company_id'];
$tenantId = $payload['tenant_id'];
try {
$analysis = $this->riskService->calculateCompanyRiskScore($companyId);
// Store or update risk score
$db = Database::getInstance();
$stmt = $db->prepare("SELECT id FROM risk_scores WHERE company_id = ? LIMIT 1");
$stmt->execute([$companyId]);
$existing = $stmt->fetch();
if ($existing) {
$stmt = $db->prepare("UPDATE risk_scores SET risk_level = ?, score = ?, factors = ?, calculated_at = NOW() WHERE company_id = ?");
$stmt->execute([
$analysis['level'],
$analysis['score'],
json_encode($analysis['factors'], JSON_UNESCAPED_UNICODE),
$companyId
]);
} else {
$stmt = $db->prepare("INSERT INTO risk_scores (id, tenant_id, company_id, risk_level, score, factors, calculated_at) VALUES (?, ?, ?, ?, ?, ?, NOW())");
$stmt->execute([
\Ramsey\Uuid\Uuid::uuid4()->toString(),
$tenantId,
$companyId,
$analysis['level'],
$analysis['score'],
json_encode($analysis['factors'], JSON_UNESCAPED_UNICODE)
]);
}
} catch (Throwable $e) {
echo "[!] Risk Analysis failed for company {$companyId}: " . $e->getMessage() . "\n";
throw $e;
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Queue\Jobs;
use App\Core\Database;
use Throwable;
final class SendNotificationJob
{
public function handle(array $payload): void
{
$userId = $payload['user_id'];
$title = $payload['title'];
$message = $payload['message'];
$type = $payload['type'] ?? 'info';
try {
$db = Database::getInstance();
$stmt = $db->prepare("INSERT INTO notifications (id, user_id, title, message, type, is_read, created_at) VALUES (?, ?, ?, ?, ?, 0, NOW())");
$stmt->execute([
\Ramsey\Uuid\Uuid::uuid4()->toString(),
$userId,
$title,
$message,
$type
]);
// Here we could also trigger WebSockets or push notifications if implemented
} catch (Throwable $e) {
echo "[!] Notification failed for user {$userId}: " . $e->getMessage() . "\n";
throw $e;
}
}
}

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace Queue\Jobs;
use App\Modules\Invoices\InvoiceModel;
use App\Modules\Companies\CompanyService;
use App\Services\JoFotara\JoFotaraGateway;
use App\Services\JoFotara\UBLGeneratorService;
use Throwable;
final class SubmitJoFotaraJob
{
public function __construct(
private readonly InvoiceModel $invoiceModel,
private readonly CompanyService $companyService,
private readonly UBLGeneratorService $ublGenerator,
private readonly JoFotaraGateway $jofotaraGateway
) {}
public function handle(array $payload): void
{
$invoiceId = $payload['invoice_id'];
try {
// 1. Update status to submitting
$this->invoiceModel->update($invoiceId, ['status' => 'submitting']);
// 2. Fetch Invoice
$db = \App\Core\Database::getInstance();
$stmt = $db->prepare("SELECT * FROM invoices WHERE id = ? LIMIT 1");
$stmt->execute([$invoiceId]);
$invoice = $stmt->fetch();
if (!$invoice) {
throw new \Exception("Invoice not found.");
}
// 3. Fetch Company Credentials
$credentials = $this->companyService->getJoFotaraCredentials($invoice['company_id']);
if (empty($credentials['clientId']) || empty($credentials['secretKey'])) {
throw new \Exception("Company is not linked to JoFotara.");
}
// 4. Fetch Invoice Lines
$stmt = $db->prepare("SELECT * FROM invoice_lines WHERE invoice_id = ?");
$stmt->execute([$invoiceId]);
$lines = $stmt->fetchAll();
// 5. Generate UBL XML
$xmlString = $this->ublGenerator->generate($invoice, $lines);
$xmlBase64 = base64_encode($xmlString);
// 6. Submit to JoFotara
$response = $this->jofotaraGateway->submitInvoice($invoice['company_id'], $xmlBase64, $credentials);
// 7. Process Response
// Assuming response contains a success boolean and possibly qr_code
if (isset($response['success']) && $response['success']) {
$this->invoiceModel->update($invoiceId, [
'status' => 'approved',
'qr_code' => $response['qr_code'] ?? null,
'jofotara_response' => json_encode($response, JSON_UNESCAPED_UNICODE)
]);
} else {
$this->invoiceModel->update($invoiceId, [
'status' => 'rejected',
'jofotara_response' => json_encode($response, JSON_UNESCAPED_UNICODE)
]);
}
} catch (Throwable $e) {
$this->invoiceModel->update($invoiceId, [
'status' => 'validation_failed',
'validation_errors' => json_encode([['message_ar' => 'فشل الإرسال: ' . $e->getMessage()]], JSON_UNESCAPED_UNICODE)
]);
throw $e;
}
}
}