Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dadc46acf9 | |||
| 75599b6a0f | |||
| 3404f5328d | |||
|
|
b88fb2e6d7 |
75
assets/css/custom.css
Normal file
75
assets/css/custom.css
Normal 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
5
assets/js/main.js
Normal file
@ -0,0 +1,5 @@
|
||||
// Custom JS for Stock Management App
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Future interactive scripts will go here
|
||||
});
|
||||
@ -6,12 +6,30 @@ define('DB_USER', 'app_30972');
|
||||
define('DB_PASS', '9eb17a13-4a89-4e11-8517-0c201096e935');
|
||||
|
||||
function db() {
|
||||
static $pdo;
|
||||
if (!$pdo) {
|
||||
$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,
|
||||
]);
|
||||
}
|
||||
return $pdo;
|
||||
static $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
22
db/migrate.php
Normal 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");
|
||||
}
|
||||
|
||||
|
||||
31
db/migrations/001_initial_schema.sql
Normal file
31
db/migrations/001_initial_schema.sql
Normal 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;
|
||||
6
db/migrations/002_add_users_table.sql
Normal file
6
db/migrations/002_add_users_table.sql
Normal 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
108
edit-product.php
Normal 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'; ?>
|
||||
383
index.php
383
index.php
@ -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>
|
||||
</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 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>
|
||||
</div>
|
||||
</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
6
partials/footer.php
Normal 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
56
partials/header.php
Normal 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
161
products.php
Normal 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
162
sales.php
Normal 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'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user