query("SELECT sku, name, price, cost_price, base_stock, vat, category_id, supplier_id, unit_id FROM items ORDER BY id DESC"); $items = $stmt->fetchAll(PDO::FETCH_ASSOC); header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=stock_export_' . date('Ymd_His') . '.csv'); echo "\xEF\xBB\xBF"; $output = fopen('php://output', 'w'); fputcsv($output, ['SKU', 'Name', 'Price', 'Cost Price', 'Stock', 'VAT', 'Category ID', 'Supplier ID', 'Unit ID']); foreach ($items as $row) { fputcsv($output, $row); } fclose($output); exit; } // Handle Import CSV if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'import_csv') { if (isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] === UPLOAD_ERR_OK) { require_once __DIR__ . '/includes/SimpleXLSX.php'; $pdo = db(); $file_path = $_FILES['csv_file']['tmp_name']; $raw_content = file_get_contents($file_path); $rows = []; # Check if XLSX (starts with PK) if (str_starts_with($raw_content, 'PK')) { if ( $xlsx = Shuchkin\SimpleXLSX::parse($file_path) ) { $rows = $xlsx->rows(); if (count($rows) > 0) { array_shift($rows); # Remove header } } else { header('Location: stock.php?import_error=' . urlencode('خطأ في قراءة ملف الإكسل (XLSX). يرجى التأكد من أن الملف سليم.')); exit; } } else { # Treat as CSV # Remove UTF-8 BOM if present if (str_starts_with($raw_content, "")) { $raw_content = substr($raw_content, 3); } # Fix encoding for Windows-1256 (common in Arabic Excel exports) if (!mb_check_encoding($raw_content, 'UTF-8')) { $raw_content = mb_convert_encoding($raw_content, 'UTF-8', 'Windows-1256'); } # Determine delimiter by checking first line $first_line = strtok($raw_content, " "); $delimiter = ','; if ($first_line !== false && substr_count($first_line, ';') > substr_count($first_line, ',')) { $delimiter = ';'; } $clean_file = tmpfile(); fwrite($clean_file, $raw_content); rewind($clean_file); $header = fgetcsv($clean_file, 0, $delimiter); while (($row = fgetcsv($clean_file, 0, $delimiter)) !== false) { $rows[] = $row; } fclose($clean_file); } $imported = 0; $updated = 0; $pdo->beginTransaction(); try { $stmtInsert = $pdo->prepare("INSERT INTO items (sku, name, price, cost_price, base_stock, vat, category_id, supplier_id, unit_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmtUpdate = $pdo->prepare("UPDATE items SET name=?, price=?, cost_price=?, base_stock=?, vat=?, category_id=?, supplier_id=?, unit_id=? WHERE sku=?"); $stmtCheck = $pdo->prepare("SELECT id FROM items WHERE sku=?"); $valid_categories = $pdo->query("SELECT id FROM categories")->fetchAll(PDO::FETCH_COLUMN); $valid_suppliers = $pdo->query("SELECT id FROM suppliers")->fetchAll(PDO::FETCH_COLUMN); $valid_units = $pdo->query("SELECT id FROM units")->fetchAll(PDO::FETCH_COLUMN); foreach ($rows as $row) { if (count($row) < 5) continue; $sku = trim((string)$row[0]); $name = trim((string)$row[1]); if ($sku === '' || $name === '') continue; $price = (float)($row[2] ?? 0); $cost_price = (float)($row[3] ?? 0); $base_stock = (int)($row[4] ?? 0); $vat = (float)($row[5] ?? 5); $category_id = (!empty($row[6]) && in_array((int)$row[6], $valid_categories)) ? (int)$row[6] : null; $supplier_id = (!empty($row[7]) && in_array((int)$row[7], $valid_suppliers)) ? (int)$row[7] : null; $unit_id = (!empty($row[8]) && in_array((int)$row[8], $valid_units)) ? (int)$row[8] : null; $stmtCheck->execute([$sku]); if ($stmtCheck->fetchColumn()) { $stmtUpdate->execute([$name, $price, $cost_price, $base_stock, $vat, $category_id, $supplier_id, $unit_id, $sku]); $updated++; } else { $stmtInsert->execute([$sku, $name, $price, $cost_price, $base_stock, $vat, $category_id, $supplier_id, $unit_id]); $imported++; } } $pdo->commit(); header('Location: stock.php?import_success=1&imported='.$imported.'&updated='.$updated); exit; } catch (Exception $e) { $pdo->rollBack(); header('Location: stock.php?import_error='.urlencode($e->getMessage())); exit; } } header('Location: stock.php?import_error=No+file'); exit; } // Handle AJAX actions if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { header('Content-Type: application/json'); $pdo = db(); if ($_POST['action'] === 'save') { try { $sku = $_POST['sku'] ?? ''; $name = $_POST['name'] ?? ''; $price = (float)($_POST['price'] ?? 0); $cost_price = (float)($_POST['cost_price'] ?? 0); $base_stock = (int)($_POST['base_stock'] ?? 0); $in_catalog = isset($_POST['in_catalog']) && $_POST['in_catalog'] === '1' ? 1 : 0; $vat = (float)($_POST['vat'] ?? get_setting('vat_percentage', 5)); $category_id = !empty($_POST['category_id']) ? (int)$_POST['category_id'] : null; $supplier_id = !empty($_POST['supplier_id']) ? (int)$_POST['supplier_id'] : null; $unit_id = !empty($_POST['unit_id']) ? (int)$_POST['unit_id'] : null; if (!$sku || !$name) { echo json_encode(['success' => false, 'error' => 'Missing SKU or Name']); exit; } $image_url = $_POST['existing_image_url'] ?? null; if (isset($_FILES['picture']) && $_FILES['picture']['error'] === UPLOAD_ERR_OK) { $uploadDir = __DIR__ . '/assets/images/items/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0775, true); } $ext = pathinfo($_FILES['picture']['name'], PATHINFO_EXTENSION); $filename = time() . '_' . rand(1000, 9999) . '.' . $ext; if (move_uploaded_file($_FILES['picture']['tmp_name'], $uploadDir . $filename)) { $image_url = 'assets/images/items/' . $filename; } } $stmt = $pdo->prepare('SELECT id FROM items WHERE sku = ?'); $stmt->execute([$sku]); $existing = $stmt->fetch(); if (isset($_POST['original_sku']) && $_POST['original_sku'] !== '') { $orig_sku = $_POST['original_sku']; if ($existing && $existing['id'] != ($pdo->query("SELECT id FROM items WHERE sku = " . $pdo->quote($orig_sku))->fetchColumn() ?: -1)) { echo json_encode(['success' => false, 'error' => 'SKU already exists']); exit; } $sql = "UPDATE items SET sku=?, name=?, price=?, cost_price=?, base_stock=?, vat=?, category_id=?, supplier_id=?, unit_id=?, in_catalog=? " . ($image_url ? ", image_url=?" : "") . " WHERE sku=?"; $params = [$sku, $name, $price, $cost_price, $base_stock, $vat, $category_id, $supplier_id, $unit_id, $in_catalog]; if ($image_url) { $params[] = $image_url; } $params[] = $orig_sku; $stmt = $pdo->prepare($sql); $stmt->execute($params); } else { if ($existing) { echo json_encode(['success' => false, 'error' => 'SKU already exists']); exit; } $stmt = $pdo->prepare("INSERT INTO items (sku, name, price, cost_price, base_stock, vat, category_id, supplier_id, unit_id, in_catalog, image_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([$sku, $name, $price, $cost_price, $base_stock, $vat, $category_id, $supplier_id, $unit_id, $in_catalog, $image_url]); } echo json_encode(['success' => true]); exit; } catch (Throwable $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); exit; } } if ($_POST['action'] === 'delete') { try { $sku = $_POST['sku'] ?? ''; if (!$sku) { echo json_encode(['success' => false, 'error' => 'Missing SKU']); exit; } $stmt = $pdo->prepare('DELETE FROM items WHERE sku = ?'); $stmt->execute([$sku]); echo json_encode(['success' => true]); exit; } catch (Throwable $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); exit; } } } $allStock = []; try { $allStock = stock_snapshot(); } catch (Throwable $e) { $dbError = $e->getMessage(); } $categories = []; $suppliers = []; try { $pdo = db(); $categories = $pdo->query('SELECT id, name_ar, name_en FROM categories ORDER BY name_ar ASC')->fetchAll(); $suppliers = $pdo->query('SELECT id, name FROM suppliers ORDER BY name ASC')->fetchAll(); $units = $pdo->query('SELECT id, name_ar, name_en FROM units ORDER BY name_ar ASC')->fetchAll(); } catch (Throwable $e) { // Ignore if not present } // Search and filter logic $search = $_GET['q'] ?? ''; $catFilter = $_GET['category'] ?? ''; $supFilter = $_GET['supplier'] ?? ''; $filteredStock = []; if (empty($dbError)) { $lowerSearch = strtolower($search); foreach ($allStock as $key => $row) { $matchSearch = !$search || str_contains(strtolower((string)$row['sku']), $lowerSearch) || str_contains(strtolower((string)$row['name']), $lowerSearch); $matchCat = !$catFilter || (isset($row['category_id']) && $row['category_id'] == $catFilter); $matchSup = !$supFilter || (isset($row['supplier_id']) && $row['supplier_id'] == $supFilter); if ($matchSearch && $matchCat && $matchSup) { $filteredStock[$key] = $row; } } } // Pagination logic $page = max(1, (int)($_GET['p'] ?? 1)); $limit = 10; $total = count($filteredStock); $totalPages = max(1, ceil($total / $limit)); $offset = ($page - 1) * $limit; $stockRows = array_slice($filteredStock, $offset, $limit, true); require __DIR__ . '/includes/header.php'; ?>

" . $import_success_message . "
"; endif; ?> " . $import_error_message . ""; endif; ?>
SKU
pic
1): ?>