Compare commits

...

4 Commits

Author SHA1 Message Date
dadc46acf9 Edit index.php via Editor 2025-10-24 10:08:35 +00:00
75599b6a0f aaa 2025-10-24 10:07:22 +00:00
3404f5328d Edit index.php via Editor 2025-10-24 09:58:46 +00:00
Flatlogic Bot
b88fb2e6d7 son 2025-10-24 09:40:09 +00:00
12 changed files with 899 additions and 150 deletions

75
assets/css/custom.css Normal file
View File

@ -0,0 +1,75 @@
/* Custom Styles for Stock Management App */
body {
font-family: 'Roboto', sans-serif;
background-color: #121212;
color: #FFFFFF;
}
.navbar {
background-color: #1E1E1E;
border-bottom: 1px solid #FFA500;
}
.navbar-brand {
color: #FFA500 !important;
font-weight: bold;
}
.stat-card {
background-color: #1E1E1E;
border: 1px solid #333;
border-radius: .5rem;
padding: 1.5rem;
margin-bottom: 1rem;
color: #FFFFFF;
}
.stat-card h5 {
color: #A0A0A0;
font-size: 1rem;
text-transform: uppercase;
}
.stat-card .stat-value {
font-size: 2.5rem;
font-weight: bold;
color: #FFA500;
}
.btn-primary {
background-color: #FFA500;
border-color: #FFA500;
color: #121212;
font-weight: bold;
}
.btn-primary:hover {
background-color: #FFC107;
border-color: #FFC107;
color: #121212;
}
.table {
background-color: #1E1E1E;
color: #FFFFFF;
}
thead th {
border-bottom: 2px solid #FFA500 !important;
color: #FFFFFF;
}
tbody td {
border-color: #333 !important;
}
.table-hover tbody tr:hover {
background-color: #2a2a2a;
color: #FFA500;
}
.badge-warning {
background-color: #FFA500;
color: #121212;
}

5
assets/js/main.js Normal file
View File

@ -0,0 +1,5 @@
// Custom JS for Stock Management App
document.addEventListener('DOMContentLoaded', function () {
// Future interactive scripts will go here
});

View File

@ -7,11 +7,29 @@ define('DB_PASS', '9eb17a13-4a89-4e11-8517-0c201096e935');
function db() {
static $pdo;
if (!$pdo) {
if ($pdo) {
return $pdo;
}
try {
// Connect to MySQL server without specifying a database
$pdo_temp = new PDO('mysql:host='.DB_HOST, DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// Create the database if it doesn't exist
$pdo_temp->exec("CREATE DATABASE IF NOT EXISTS `".DB_NAME."`");
// Now connect to the specific database
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
} catch (PDOException $e) {
// If connection fails, it might be a more serious issue
die("Database connection failed: " . $e->getMessage());
}
return $pdo;
}

22
db/migrate.php Normal file
View File

@ -0,0 +1,22 @@
<?php
require_once __DIR__ . '/config.php';
echo "Running migrations...\n";
try {
$pdo = db();
$migration_files = glob(__DIR__ . '/migrations/*.sql');
sort($migration_files);
foreach ($migration_files as $file) {
echo "- Applying " . basename($file) . "...\n";
$sql = file_get_contents($file);
$pdo->exec($sql);
}
echo "All migrations completed successfully!\n";
} catch (PDOException $e) {
die("Migration failed: " . $e->getMessage() . "\n");
}

View File

@ -0,0 +1,31 @@
-- Initial Schema for Stock Management App
CREATE TABLE IF NOT EXISTS `products` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL,
`type` ENUM('jant', 'lastik', 'akü') NOT NULL,
`stock_quantity` INT NOT NULL DEFAULT 0,
`purchase_price` DECIMAL(10, 2) NOT NULL,
`sale_price` DECIMAL(10, 2) NOT NULL,
`low_stock_threshold` INT NOT NULL DEFAULT 5,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `sales` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`total_amount` DECIMAL(10, 2) NOT NULL,
`profit_amount` DECIMAL(10, 2) NOT NULL,
`payment_method` VARCHAR(50) DEFAULT 'nakit',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `sale_items` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`sale_id` INT NOT NULL,
`product_id` INT NOT NULL,
`quantity` INT NOT NULL,
`unit_price` DECIMAL(10, 2) NOT NULL,
`total_price` DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (`sale_id`) REFERENCES `sales`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS `users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(50) NOT NULL UNIQUE,
`password` VARCHAR(255) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

108
edit-product.php Normal file
View File

@ -0,0 +1,108 @@
<?php
require_once 'db/config.php';
$product_id = $_GET['id'] ?? null;
// ID yoksa veya geçersizse ana sayfaya yönlendir
if (!$product_id) {
$_SESSION['error'] = "Geçersiz ürün ID'si.";
header('Location: products.php');
exit();
}
$pdo = db();
// Form gönderildiğinde (POST request)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? '';
$type = $_POST['type'] ?? '';
$stock_quantity = $_POST['stock_quantity'] ?? 0;
$purchase_price = $_POST['purchase_price'] ?? 0.0;
$sale_price = $_POST['sale_price'] ?? 0.0;
$low_stock_threshold = $_POST['low_stock_threshold'] ?? 5;
if (!empty($name) && !empty($type) && is_numeric($stock_quantity) && is_numeric($purchase_price) && is_numeric($sale_price)) {
try {
$stmt = $pdo->prepare("UPDATE products SET name = ?, type = ?, stock_quantity = ?, purchase_price = ?, sale_price = ?, low_stock_threshold = ? WHERE id = ?");
$stmt->execute([$name, $type, $stock_quantity, $purchase_price, $sale_price, $low_stock_threshold, $product_id]);
$_SESSION['notification'] = "Ürün başarıyla güncellendi.";
header('Location: products.php');
exit();
} catch (PDOException $e) {
$_SESSION['error'] = "Veritabanı hatası: " . $e->getMessage();
}
} else {
$_SESSION['error'] = "Lütfen tüm alanları doğru bir şekilde doldurun.";
}
// Hata durumunda aynı sayfada kal, form tekrar dolsun
header("Location: edit-product.php?id=" . $product_id);
exit();
}
// Sayfa ilk yüklendiğinde (GET request)
try {
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = ?");
$stmt->execute([$product_id]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$product) {
$_SESSION['error'] = "Ürün bulunamadı.";
header('Location: products.php');
exit();
}
} catch (PDOException $e) {
$_SESSION['error'] = "Veritabanı hatası: " . $e->getMessage();
header('Location: products.php');
exit();
}
require_once 'partials/header.php';
?>
<h1 class="mb-4">Ürünü Düzenle</h1>
<div class="card">
<div class="card-header">
<?php echo htmlspecialchars($product['name']); ?>
</div>
<div class="card-body">
<form action="edit-product.php?id=<?php echo $product_id; ?>" method="POST">
<div class="row">
<div class="col-md-6 mb-3">
<label for="name" class="form-label">Ürün Adı</label>
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($product['name']); ?>" required>
</div>
<div class="col-md-6 mb-3">
<label for="type" class="form-label">Ürün Tipi</label>
<select class="form-select" id="type" name="type" required>
<option value="jant" <?php echo ($product['type'] === 'jant') ? 'selected' : ''; ?>>Jant</option>
<option value="lastik" <?php echo ($product['type'] === 'lastik') ? 'selected' : ''; ?>>Lastik</option>
<option value="akü" <?php echo ($product['type'] === 'akü') ? 'selected' : ''; ?>>Akü</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-3 mb-3">
<label for="stock_quantity" class="form-label">Stok Miktarı</label>
<input type="number" class="form-control" id="stock_quantity" name="stock_quantity" value="<?php echo htmlspecialchars($product['stock_quantity']); ?>" required>
</div>
<div class="col-md-3 mb-3">
<label for="purchase_price" class="form-label">Alış Fiyatı</label>
<input type="number" step="0.01" class="form-control" id="purchase_price" name="purchase_price" value="<?php echo htmlspecialchars($product['purchase_price']); ?>" required>
</div>
<div class="col-md-3 mb-3">
<label for="sale_price" class="form-label">Satış Fiyatı</label>
<input type="number" step="0.01" class="form-control" id="sale_price" name="sale_price" value="<?php echo htmlspecialchars($product['sale_price']); ?>" required>
</div>
<div class="col-md-3 mb-3">
<label for="low_stock_threshold" class="form-label">Düşük Stok Uyarısı</label>
<input type="number" class="form-control" id="low_stock_threshold" name="low_stock_threshold" value="<?php echo htmlspecialchars($product['low_stock_threshold']); ?>" required>
</div>
</div>
<button type="submit" class="btn btn-primary">Değişiklikleri Kaydet</button>
<a href="products.php" class="btn btn-secondary">İptal</a>
</form>
</div>
</div>
<?php require_once 'partials/footer.php'; ?>

379
index.php
View File

@ -1,150 +1,249 @@
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
session_start();
/* ========== VERİTABANI BAĞLANTISI ========== */
$host = 'localhost';
$db = 'store_db'; // veritabanı adını değiştir
$user = 'root'; // veritabanı kullanıcı adı
$pass = ''; // veritabanı şifre
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
try {
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
} catch (PDOException $e) {
die("Veritabanına bağlanılamadı: " . $e->getMessage());
}
/* ========== TABLOLARIN OLUŞTURULMASI (İLK SEFERDE YAP) ========== */
$pdo->exec("
CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock_quantity INT DEFAULT 0,
low_stock_threshold INT DEFAULT 5
);
CREATE TABLE IF NOT EXISTS sales (
id INT AUTO_INCREMENT PRIMARY KEY,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS sale_items (
id INT AUTO_INCREMENT PRIMARY KEY,
sale_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
total_price DECIMAL(10,2) NOT NULL,
profit_amount DECIMAL(10,2) NOT NULL,
FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
);
");
/* ========== İŞLEMLER (GET/POST) ========== */
// Ürün ekleme
if(isset($_POST['add_product'])){
$stmt = $pdo->prepare("INSERT INTO products (name, price, stock_quantity, low_stock_threshold) VALUES (?,?,?,?)");
$stmt->execute([$_POST['name'], $_POST['price'], $_POST['stock_quantity'], $_POST['low_stock_threshold']]);
$_SESSION['success'] = "Ürün eklendi.";
}
// Ürün silme
if(isset($_GET['delete_product'])){
$stmt = $pdo->prepare("DELETE FROM products WHERE id=?");
$stmt->execute([$_GET['delete_product']]);
$_SESSION['success'] = "Ürün silindi.";
}
// Satış ekleme
if(isset($_POST['add_sale'])){
$product_ids = $_POST['product_id'];
$quantities = $_POST['quantity'];
try {
$pdo->beginTransaction();
$pdo->exec("INSERT INTO sales (created_at) VALUES (NOW())");
$sale_id = $pdo->lastInsertId();
foreach($product_ids as $i => $pid){
$qty = intval($quantities[$i]);
if($qty <= 0) continue;
$product = $pdo->prepare("SELECT price, stock_quantity FROM products WHERE id=?");
$product->execute([$pid]);
$p = $product->fetch();
if(!$p || $p['stock_quantity'] < $qty) continue;
$total_price = $p['price'] * $qty;
$profit_amount = $total_price * 0.2;
$stmt = $pdo->prepare("INSERT INTO sale_items (sale_id, product_id, quantity, total_price, profit_amount) VALUES (?,?,?,?,?)");
$stmt->execute([$sale_id, $pid, $qty, $total_price, $profit_amount]);
$pdo->prepare("UPDATE products SET stock_quantity = stock_quantity - ? WHERE id=?")->execute([$qty, $pid]);
}
$pdo->commit();
$_SESSION['success'] = "Satış eklendi.";
} catch(PDOException $e){
$pdo->rollBack();
$_SESSION['error'] = "Satış eklenirken hata: ".$e->getMessage();
}
}
/* ========== VERİLERİN ÇEKİLMESİ ========== */
// Dashboard istatistikleri
$stats = [
'total_revenue' => $pdo->query("SELECT SUM(total_price) FROM sale_items")->fetchColumn() ?: 0,
'total_profit' => $pdo->query("SELECT SUM(profit_amount) FROM sale_items")->fetchColumn() ?: 0,
'product_count' => $pdo->query("SELECT COUNT(*) FROM products")->fetchColumn(),
'low_stock_count' => $pdo->query("SELECT COUNT(*) FROM products WHERE stock_quantity <= low_stock_threshold")->fetchColumn()
];
// Son 5 satış
$recent_sales = $pdo->query("
SELECT p.name AS product_name, si.quantity, si.total_price, s.created_at
FROM sale_items si
JOIN sales s ON si.sale_id = s.id
JOIN products p ON si.product_id = p.id
ORDER BY s.created_at DESC
LIMIT 5
")->fetchAll(PDO::FETCH_ASSOC);
// Ürün listesi
$products = $pdo->query("SELECT * FROM products ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
// Stoğu azalan ürünler
$low_stock_products = $pdo->query("SELECT * FROM products WHERE stock_quantity <= low_stock_threshold ORDER BY stock_quantity ASC")->fetchAll(PDO::FETCH_ASSOC);
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?>
<!doctype html>
<html lang="en">
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Style</title>
<?php
// Read project preview data from environment
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
?>
<?php if ($projectDescription): ?>
<!-- Meta description -->
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<!-- Open Graph meta tags -->
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<!-- Twitter meta tags -->
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<?php endif; ?>
<?php if ($projectImageUrl): ?>
<!-- Open Graph image -->
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<!-- Twitter image -->
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<?php endif; ?>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stok & Satış Takip</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
</head>
<body>
<main>
<div class="card">
<h1>Analyzing your requirements and generating your website…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
<div class="container-fluid">
<a class="navbar-brand" href="#">Elit Lastik</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="#">Dashboard</a></li>
<li class="nav-item"><a class="nav-link" href="#products">Ürünler</a></li>
<li class="nav-item"><a class="nav-link" href="#sales">Satışlar</a></li>
</ul>
</div>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will update automatically as the plan is implemented.</p>
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
</div>
</main>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC)
</footer>
</nav>
<div class="container">
<?php if(isset($_SESSION['success'])) { echo "<div class='alert alert-success'>".$_SESSION['success']."</div>"; unset($_SESSION['success']); } ?>
<?php if(isset($_SESSION['error'])) { echo "<div class='alert alert-danger'>".$_SESSION['error']."</div>"; unset($_SESSION['error']); } ?>
<h1 class="mb-4">Dashboard</h1>
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-white bg-primary mb-3">
<div class="card-body">
<h5 class="card-title">Toplam Gelir</h5>
<p class="card-text"><?php echo number_format($stats['total_revenue'],2); ?> TL</p>
</div></div></div>
<div class="col-md-3">
<div class="card text-white bg-success mb-3">
<div class="card-body">
<h5 class="card-title">Toplam Kâr</h5>
<p class="card-text"><?php echo number_format($stats['total_profit'],2); ?> TL</p>
</div></div></div>
<div class="col-md-3">
<div class="card text-white bg-info mb-3">
<div class="card-body">
<h5 class="card-title">Ürün Çeşidi</h5>
<p class="card-text"><?php echo $stats['product_count']; ?></p>
</div></div></div>
<div class="col-md-3">
<div class="card text-white bg-warning mb-3">
<div class="card-body">
<h5 class="card-title">Düşük Stok</h5>
<p class="card-text"><?php echo $stats['low_stock_count']; ?> Ürün</p>
</div></div></div>
</div>
<h2 id="products" class="mb-3">Ürünler</h2>
<form method="POST" class="mb-3">
<div class="row g-2">
<div class="col-md-3"><input type="text" name="name" class="form-control" placeholder="Ürün Adı" required></div>
<div class="col-md-2"><input type="number" step="0.01" name="price" class="form-control" placeholder="Fiyat" required></div>
<div class="col-md-2"><input type="number" name="stock_quantity" class="form-control" placeholder="Stok" required></div>
<div class="col-md-2"><input type="number" name="low_stock_threshold" class="form-control" placeholder="Düşük Stok" required></div>
<div class="col-md-3"><button type="submit" name="add_product" class="btn btn-success w-100">Ürün Ekle</button></div>
</div>
</form>
<table class="table table-striped table-hover mb-5">
<thead>
<tr><th>Ad</th><th>Fiyat</th><th>Stok</th><th>Düşük Stok</th><th>İşlemler</th></tr>
</thead>
<tbody>
<?php foreach($products as $p): ?>
<tr>
<td><?php echo htmlspecialchars($p['name']); ?></td>
<td><?php echo number_format($p['price'],2); ?> TL</td>
<td><?php echo $p['stock_quantity']; ?></td>
<td><?php echo $p['low_stock_threshold']; ?></td>
<td><a href="?delete_product=<?php echo $p['id']; ?>" class="btn btn-danger btn-sm" onclick="return confirm('Silmek istediğine emin misin?')">Sil</a></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h2 id="sales" class="mb-3">Satışlar</h2>
<form method="POST" class="mb-3">
<table class="table table-bordered">
<tr><th>Ürün</th><th>Adet</th></tr>
<?php foreach($products as $p): ?>
<tr>
<td><?php echo htmlspecialchars($p['name']); ?> (Stok: <?php echo $p['stock_quantity']; ?>)</td>
<td>
<input type="number" name="quantity[]" value="0" min="0" max="<?php echo $p['stock_quantity']; ?>" class="form-control">
<input type="hidden" name="product_id[]" value="<?php echo $p['id']; ?>">
</td>
</tr>
<?php endforeach; ?>
</table>
<button type="submit" name="add_sale" class="btn btn-success mb-5">Satışı Kaydet</button>
</form>
<h3 class="mb-3">Son 5 Satış</h3>
<table class="table table-striped table-hover mb-5">
<thead>
<tr><th>Ürün</th><th>Adet</th><th>Toplam</th><th>Tarih</th></tr>
</thead>
<tbody>
<?php foreach($recent_sales as $s): ?>
<tr>
<td><?php echo htmlspecialchars($s['product_name']); ?></td>
<td><?php echo $s['quantity']; ?></td>
<td><?php echo number_format($s['total_price'],2); ?> TL</td>
<td><?php echo date('d/m/Y H:i', strtotime($s['created_at'])); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h3>Düşük Stok Ürünler</h3>
<ul>
<?php foreach($low_stock_products as $lp): ?>
<li><?php echo htmlspecialchars($lp['name']); ?> - Stok: <?php echo $lp['stock_quantity']; ?></li>
<?php endforeach; ?>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

6
partials/footer.php Normal file
View File

@ -0,0 +1,6 @@
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body>
</html>

56
partials/header.php Normal file
View File

@ -0,0 +1,56 @@
<?php
session_start();
$current_page = basename($_SERVER['PHP_SELF']);
?>
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stok Yönetim Sistemi</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<div class="d-flex">
<div class="sidebar d-flex flex-column flex-shrink-0 p-3">
<a href="index.php" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
<i class="bi bi-box-seam-fill me-2"></i>
<span class="fs-4">Stok Yönetimi</span>
</a>
<hr>
<ul class="nav nav-pills flex-column mb-auto">
<li class="nav-item">
<a href="index.php" class="nav-link <?php echo ($current_page == 'index.php') ? 'active' : ''; ?>">
<i class="bi bi-speedometer2 me-2"></i> Ana Panel
</a>
</li>
<li>
<a href="products.php" class="nav-link <?php echo ($current_page == 'products.php') ? 'active' : ''; ?>">
<i class="bi bi-grid me-2"></i> Ürünler
</a>
</li>
<li>
<a href="sales.php" class="nav-link <?php echo ($current_page == 'sales.php') ? 'active' : ''; ?>">
<i class="bi bi-receipt me-2"></i> Satışlar
</a>
</li>
</ul>
<hr>
</div>
<div class="main-content flex-grow-1 p-4">
<?php if (isset($_SESSION['notification'])): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?php echo $_SESSION['notification']; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php unset($_SESSION['notification']); ?>
<?php endif; ?>
<?php if (isset($_SESSION['error'])): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<?php echo $_SESSION['error']; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php unset($_SESSION['error']); ?>
<?php endif; ?>

161
products.php Normal file
View File

@ -0,0 +1,161 @@
<?php
require_once 'db/config.php';
// Form gönderildi mi kontrolü
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$pdo = db();
// Yeni ürün ekleme işlemi
if (isset($_POST['name'])) {
$name = $_POST['name'] ?? '';
$type = $_POST['type'] ?? '';
$stock_quantity = $_POST['stock_quantity'] ?? 0;
$purchase_price = $_POST['purchase_price'] ?? 0.0;
$sale_price = $_POST['sale_price'] ?? 0.0;
$low_stock_threshold = $_POST['low_stock_threshold'] ?? 5;
if (!empty($name) && !empty($type) && is_numeric($stock_quantity) && is_numeric($purchase_price) && is_numeric($sale_price)) {
try {
$stmt = $pdo->prepare("INSERT INTO products (name, type, stock_quantity, purchase_price, sale_price, low_stock_threshold) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$name, $type, $stock_quantity, $purchase_price, $sale_price, $low_stock_threshold]);
$_SESSION['notification'] = "Ürün başarıyla eklendi!";
} catch (PDOException $e) {
$_SESSION['error'] = "Veritabanı hatası: " . $e->getMessage();
}
} else {
$_SESSION['error'] = "Lütfen tüm alanları doğru bir şekilde doldurun.";
}
}
// Ürün silme işlemi
if (isset($_POST['action']) && $_POST['action'] === 'delete') {
$product_id = $_POST['product_id'] ?? null;
if ($product_id) {
try {
$stmt = $pdo->prepare("DELETE FROM products WHERE id = ?");
$stmt->execute([$product_id]);
$_SESSION['notification'] = "Ürün başarıyla silindi.";
} catch (PDOException $e) {
$_SESSION['error'] = "Hata: Ürün silinemedi. İlişkili satış kayıtları olabilir.";
}
}
}
// PRG Pattern: Sayfayı yeniden yönlendirerek formun tekrar gönderilmesini engelle
header("Location: products.php");
exit();
}
// Ürünleri veritabanından çek
$products = [];
try {
$pdo = db();
$stmt = $pdo->query("SELECT * FROM products ORDER BY created_at DESC");
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
// Hata mesajını oturuma kaydet ve sayfayı yenilemekten kaçın
$_SESSION['error'] = "Ürünler çekilirken hata oluştu: " . $e->getMessage();
}
require_once 'partials/header.php';
?>
<h1 class="mb-4">Ürün Yönetimi</h1>
<!-- Yeni Ürün Ekleme Formu -->
<div class="card mb-4">
<div class="card-header">
Yeni Ürün Ekle
</div>
<div class="card-body">
<form action="products.php" method="POST">
<div class="row">
<div class="col-md-6 mb-3">
<label for="name" class="form-label">Ürün Adı</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>
<div class="col-md-6 mb-3">
<label for="type" class="form-label">Ürün Tipi</label>
<select class="form-select" id="type" name="type" required>
<option value="jant">Jant</option>
<option value="lastik">Lastik</option>
<option value="akü">Akü</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-3 mb-3">
<label for="stock_quantity" class="form-label">Stok Miktarı</label>
<input type="number" class="form-control" id="stock_quantity" name="stock_quantity" required>
</div>
<div class="col-md-3 mb-3">
<label for="purchase_price" class="form-label">Alış Fiyatı</label>
<input type="number" step="0.01" class="form-control" id="purchase_price" name="purchase_price" required>
</div>
<div class="col-md-3 mb-3">
<label for="sale_price" class="form-label">Satış Fiyatı</label>
<input type="number" step="0.01" class="form-control" id="sale_price" name="sale_price" required>
</div>
<div class="col-md-3 mb-3">
<label for="low_stock_threshold" class="form-label">Düşük Stok Uyarısı</label>
<input type="number" class="form-control" id="low_stock_threshold" name="low_stock_threshold" value="5" required>
</div>
</div>
<button type="submit" class="btn btn-primary">Ürünü Ekle</button>
</form>
</div>
</div>
<!-- Ürün Listesi -->
<div class="card">
<div class="card-header">
Mevcut Ürünler
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Ad</th>
<th>Tip</th>
<th>Stok</th>
<th>Alış Fiyatı</th>
<th>Satış Fiyatı</th>
<th>Eklendiği Tarih</th>
<th>İşlemler</th>
</tr>
</thead>
<tbody>
<?php if (empty($products)):
<tr>
<td colspan="8" class="text-center">Henüz hiç ürün eklenmemiş.</td>
</tr>
<?php else: ?>
<?php foreach ($products as $product): ?>
<tr>
<td><?php echo htmlspecialchars($product['id']); ?></td>
<td><?php echo htmlspecialchars($product['name']); ?></td>
<td><?php echo htmlspecialchars($product['type']); ?></td>
<td><?php echo htmlspecialchars($product['stock_quantity']); ?></td>
<td><?php echo htmlspecialchars($product['purchase_price']); ?></td>
<td><?php echo htmlspecialchars($product['sale_price']); ?></td>
<td><?php echo htmlspecialchars($product['created_at']); ?></td>
<td>
<a href="edit-product.php?id=<?php echo $product['id']; ?>" class="btn btn-sm btn-warning">Düzenle</a>
<form action="products.php" method="POST" class="d-inline" onsubmit="return confirm('Bu ürünü silmek istediğinizden emin misiniz?');">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="product_id" value="<?php echo $product['id']; ?>">
<button type="submit" class="btn btn-sm btn-danger">Sil</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once 'partials/footer.php'; ?>

162
sales.php Normal file
View File

@ -0,0 +1,162 @@
<?php
require_once 'db/config.php';
// Yeni satış ekleme işlemi
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_sale'])) {
$product_id = $_POST['product_id'] ?? null;
$quantity = $_POST['quantity'] ?? 0;
if (empty($product_id) || empty($quantity) || !is_numeric($quantity) || $quantity <= 0) {
$_SESSION['error'] = "Lütfen geçerli bir ürün ve adet girin.";
header("Location: sales.php");
exit();
}
$pdo = db();
$pdo->beginTransaction();
try {
// 1. Ürün bilgilerini ve stok durumunu kontrol et
$stmt = $pdo->prepare("SELECT name, sale_price, purchase_price, stock_quantity FROM products WHERE id = ? FOR UPDATE");
$stmt->execute([$product_id]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$product) {
throw new Exception("Ürün bulunamadı.");
}
if ($product['stock_quantity'] < $quantity) {
throw new Exception("Yetersiz stok! Mevcut stok: " . $product['stock_quantity']);
}
// 2. Satış hesaplamalarını yap
$total_amount = $product['sale_price'] * $quantity;
$profit_amount = ($product['sale_price'] - $product['purchase_price']) * $quantity;
// 3. 'sales' tablosuna ana satış kaydını ekle
$stmt = $pdo->prepare("INSERT INTO sales (total_amount, profit_amount) VALUES (?, ?)");
$stmt->execute([$total_amount, $profit_amount]);
$sale_id = $pdo->lastInsertId();
// 4. 'sale_items' tablosuna satılan ürünü ekle
$stmt = $pdo->prepare("INSERT INTO sale_items (sale_id, product_id, quantity, unit_price, total_price) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$sale_id, $product_id, $quantity, $product['sale_price'], $total_amount]);
// 5. Ürün stoğunu güncelle
$stmt = $pdo->prepare("UPDATE products SET stock_quantity = stock_quantity - ? WHERE id = ?");
$stmt->execute([$quantity, $product_id]);
// Her şey yolundaysa işlemi onayla
$pdo->commit();
$_SESSION['notification'] = "Satış başarıyla kaydedildi.";
} catch (Exception $e) {
// Bir hata olursa tüm işlemleri geri al
$pdo->rollBack();
$_SESSION['error'] = "Hata: " . $e->getMessage();
}
header("Location: sales.php");
exit();
}
// Sayfa içeriğini hazırlama
$pdo = db();
// Form için ürünleri çek
$products_for_form = [];
try {
$products_stmt = $pdo->query("SELECT id, name, sale_price, stock_quantity FROM products WHERE stock_quantity > 0 ORDER BY name ASC");
$products_for_form = $products_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
$_SESSION['error'] = "Ürünler getirilemedi: " . $e->getMessage();
}
// Görüntülemek için geçmiş satışları çek (JOIN ile)
$sales_list = [];
try {
$sales_stmt = $pdo->query("
SELECT si.id, p.name AS product_name, si.quantity, si.total_price, s.created_at AS sale_date
FROM sale_items si
JOIN sales s ON si.sale_id = s.id
JOIN products p ON si.product_id = p.id
ORDER BY s.created_at DESC
");
$sales_list = $sales_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
$_SESSION['error'] = "Satışlar getirilemedi: " . $e->getMessage();
}
require_once 'partials/header.php';
?>
<h1 class="mb-4">Satış Yönetimi</h1>
<!-- Yeni Satış Ekleme Formu -->
<div class="card mb-4">
<div class="card-header">Yeni Satış Ekle</div>
<div class="card-body">
<form action="sales.php" method="POST">
<input type="hidden" name="add_sale" value="1">
<div class="row">
<div class="col-md-8 mb-3">
<label for="product_id" class="form-label">Ürün Seçin</label>
<select class="form-select" id="product_id" name="product_id" required>
<option value="">-- Bir Ürün Seçin --</option>
<?php foreach ($products_for_form as $product): ?>
<option value="<?php echo htmlspecialchars($product['id']); ?>">
<?php echo htmlspecialchars($product['name']); ?>
(Stok: <?php echo htmlspecialchars($product['stock_quantity']); ?> |
Fiyat: <?php echo htmlspecialchars(number_format($product['sale_price'], 2)); ?> TL)
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4 mb-3">
<label for="quantity" class="form-label">Adet</label>
<input type="number" class="form-control" id="quantity" name="quantity" min="1" required>
</div>
</div>
<button type="submit" class="btn btn-primary">Satış Ekle</button>
</form>
</div>
</div>
<!-- Geçmiş Satışlar -->
<div class="card">
<div class="card-header">Geçmiş Satışlar</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Ürün Adı</th>
<th>Adet</th>
<th>Toplam Fiyat</th>
<th>Satış Tarihi</th>
</tr>
</thead>
<tbody>
<?php if (empty($sales_list)): ?>
<tr>
<td colspan="5" class="text-center">Henüz hiç satış yapılmamış.</td>
</tr>
<?php else: ?>
<?php foreach ($sales_list as $sale): ?>
<tr>
<td><?php echo htmlspecialchars($sale['id']); ?></td>
<td><?php echo htmlspecialchars($sale['product_name']); ?></td>
<td><?php echo htmlspecialchars($sale['quantity']); ?></td>
<td><?php echo htmlspecialchars(number_format($sale['total_price'], 2)); ?> TL</td>
<td><?php echo htmlspecialchars($sale['sale_date']); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php require_once 'partials/footer.php'; ?>