Files
musadaq-saas/app/modules_app/excel/import.php
2026-05-08 04:58:23 +03:00

123 lines
3.9 KiB
PHP

<?php
/**
* Bulk Excel Import Endpoint
* POST /v1/excel/import
*/
declare(strict_types=1);
use App\Core\Database;
use App\Core\Encryption;
use App\Middleware\AuthMiddleware;
use App\Middleware\QuotaMiddleware;
use PhpOffice\PhpSpreadsheet\IOFactory;
$decoded = AuthMiddleware::check();
$tenantId = $decoded['tenant_id'];
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
json_error('الملف مطلوب', 422);
}
$companyId = input('company_id');
if (!$companyId) {
json_error('يجب تحديد الشركة', 422);
}
$file = $_FILES['file'];
$tmpPath = $file['tmp_name'];
try {
$spreadsheet = IOFactory::load($tmpPath);
$worksheet = $spreadsheet->getActiveSheet();
$rows = $worksheet->toArray();
if (count($rows) < 2) {
json_error('الملف فارغ أو لا يحتوي على بيانات', 422);
}
$header = array_shift($rows);
$mapping = mapColumns($header);
$db = Database::getInstance();
$db->beginTransaction();
$importedCount = 0;
$errors = [];
foreach ($rows as $index => $row) {
if (empty(array_filter($row))) continue; // Skip empty rows
try {
// Check quota for each invoice (preventive)
QuotaMiddleware::checkInvoiceQuota($tenantId);
$invoiceData = [
'id' => Database::generateUuid(),
'tenant_id' => $tenantId,
'company_id' => $companyId,
'invoice_number' => $row[$mapping['number']] ?? 'EXT-' . time() . '-' . $index,
'invoice_date' => formatDate($row[$mapping['date']] ?? date('Y-m-d')),
'customer_name' => Encryption::encrypt($row[$mapping['customer']] ?? 'عميل عام'),
'grand_total' => (float)($row[$mapping['total']] ?? 0),
'tax_amount' => (float)($row[$mapping['tax']] ?? 0),
'status' => 'extracted', // Ready for review/approval
'created_at' => date('Y-m-d H:i:s')
];
$stmt = $db->prepare("
INSERT INTO invoices (id, tenant_id, company_id, invoice_number, invoice_date, customer_name, grand_total, tax_amount, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute(array_values($invoiceData));
$importedCount++;
} catch (\Exception $e) {
$errors[] = "السطر " . ($index + 2) . ": " . $e->getMessage();
}
}
$db->commit();
json_success([
'imported_count' => $importedCount,
'errors' => $errors
], "تم استيراد $importedCount فاتورة بنجاح");
} catch (\Exception $e) {
if (isset($db)) $db->rollBack();
safe_error($e, 'excel/import', 'فشل معالجة ملف الإكسل.');
}
/**
* Intelligent Column Mapping
*/
function mapColumns(array $header): array {
$map = [
'number' => 0,
'date' => 1,
'customer' => 2,
'total' => 3,
'tax' => 4
];
foreach ($header as $i => $col) {
$col = mb_strtolower(trim((string)$col));
if (str_contains($col, 'رقم') || str_contains($col, 'number')) $map['number'] = $i;
if (str_contains($col, 'تاريخ') || str_contains($col, 'date')) $map['date'] = $i;
if (str_contains($col, 'عميل') || str_contains($col, 'customer') || str_contains($col, 'اسم')) $map['customer'] = $i;
if (str_contains($col, 'اجمالي') || str_contains($col, 'total') || str_contains($col, 'المجموع')) $map['total'] = $i;
if (str_contains($col, 'ضريبة') || str_contains($col, 'tax')) $map['tax'] = $i;
}
return $map;
}
function formatDate($val): string {
if (is_numeric($val)) {
return date('Y-m-d', \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($val));
}
$ts = strtotime((string)$val);
return $ts ? date('Y-m-d', $ts) : date('Y-m-d');
}