'required', ]); if ($errors) { json_error('رقم الشركة مطلوب', 422, $errors); } $companyId = $data['company_id']; $source = $data['source'] ?? 'mobile_scan'; $expectedImages = (int)($data['expected_images'] ?? 0); // 2. Permission check $db = Database::getInstance(); $stmt = $db->prepare("SELECT id, tenant_id FROM companies WHERE id = ? AND deleted_at IS NULL"); $stmt->execute([$companyId]); $company = $stmt->fetch(); if (!$company) { json_error('الشركة غير موجودة', 404); } // Check tenant match if not super_admin if ($decoded['role'] !== 'super_admin' && $company['tenant_id'] !== $tenantId) { json_error('الوصول مرفوض لهذه الشركة', 403); } // Use the actual tenant of the company $targetTenantId = $company['tenant_id']; // 3. Check quota (preview — don't increment yet) if ($decoded['role'] !== 'super_admin') { try { QuotaMiddleware::checkInvoiceQuota($targetTenantId); } catch (\Exception $e) { json_error('تم استنفاد رصيد الفواتير لهذا الشهر. قم بترقية باقتك.', 429); } } // 4. Generate batch ID $batchId = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(random_bytes(16)), 4)); // 5. Create batch record $stmt = $db->prepare(" INSERT INTO invoice_batches (id, tenant_id, company_id, uploaded_by, total_images, source, status) VALUES (?, ?, ?, ?, ?, ?, 'uploading') "); $stmt->execute([$batchId, $targetTenantId, $companyId, $userId, $expectedImages, $source]); // 6. Create upload directory $uploadDir = STORAGE_PATH . '/invoices/' . $targetTenantId . '/' . $companyId . '/batches/' . $batchId; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); } json_success([ 'batch_id' => $batchId, 'upload_url' => 'v1/batches/upload-image', ], 'تم إنشاء الدفعة بنجاح. ابدأ برفع الصور.');