Files
ytp-glm/src/server.js

1818 lines
48 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import express from 'express';
import session from 'express-session';
import { createServer } from 'http';
import { Server } from 'socket.io';
import sqlite3 from 'sqlite3';
import bcrypt from 'bcrypt';
import { promises as fs } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import {
getGoodsManagers,
addGoodsManager,
updateGoodsManager,
deleteGoodsManager,
findGoodsManagerById,
findGoodsManagerByUsername
} from './lib/data/goodsManagers.js';
// Units veritabanı
let units = [
{
id: 1,
name: '1. Motorlu Piyade Tugayı',
address: 'Mecidiyeköy, Şişli/İstanbul',
stk: 'STK-12345',
btk: 'BTK-67890',
commander: {
full_name: 'Mehmet Yılmaz',
rank: 'Yüzbaşı',
registration_number: '123456',
tc_kimlik: '12345678901',
phone: '05321234567'
},
created_at: new Date().toISOString()
},
{
id: 2,
name: '2. Zırhlı Tabur',
address: 'Havran, Balıkesir',
stk: 'STK-54321',
btk: 'BTK-09876',
commander: {
full_name: 'Ali Kaya',
rank: 'Binbaşı',
registration_number: '654321',
tc_kimlik: '98765432109',
phone: '05337654321'
},
created_at: new Date().toISOString()
},
{
id: 3,
name: '3. Komutanlık',
address: 'Çankaya, Ankara',
stk: 'STK-11111',
btk: 'BTK-22222',
commander: {
full_name: 'Hasan Demir',
rank: 'Üsteğmen',
registration_number: '111111',
tc_kimlik: '11111111111',
phone: '05321111111'
},
created_at: new Date().toISOString()
}
];
let nextUnitId = 4;
const getUnitById = (unitId) => {
if (unitId === null || unitId === undefined) {
return null;
}
const id = parseInt(unitId);
return units.find((unit) => unit.id === id) || null;
};
const getUnitNameById = (unitId) => {
return getUnitById(unitId)?.name || 'Belirtilmemiş';
};
// Vehicles veritabanı
let vehicles = [
{
id: 1,
brand: 'Mercedes-Benz',
model: 'Actros 1851',
year: 2020,
plate: '34 ABC 123',
unit_id: 1,
fuel_type: 'Dizel',
fuel_capacity: 500,
current_fuel: 300,
status: 'Aktif',
driver_id: 3,
driver_name: 'Ali Veli',
created_at: new Date().toISOString()
},
{
id: 2,
brand: 'Volvo',
model: 'FH16 750',
year: 2021,
plate: '34 XYZ 789',
unit_id: 2,
fuel_type: 'Dizel',
fuel_capacity: 600,
current_fuel: 450,
status: 'Aktif',
driver_id: 4,
driver_name: 'İbrahim Kara',
created_at: new Date().toISOString()
},
{
id: 3,
brand: 'Scania',
model: 'R730',
year: 2019,
plate: '34 DEF 456',
unit_id: 3,
fuel_type: 'Dizel',
fuel_capacity: 550,
current_fuel: 200,
status: 'Bakımda',
driver_id: null,
driver_name: null,
created_at: new Date().toISOString()
}
];
vehicles = vehicles.map((vehicle) => ({
...vehicle,
unit_name: getUnitNameById(vehicle.unit_id)
}));
let nextVehicleId = 4;
// Fuel Personnel veritabanı
let fuelPersonnel = [
{
id: 1,
full_name: 'Ahmet Demir',
rank: 'Üsteğmen',
registration_number: 'FP-111222',
tc_kimlik: '11111111111',
phone: '05321112233',
is_active: true,
created_at: new Date().toISOString()
},
{
id: 2,
full_name: 'Mustafa Çelik',
rank: 'Astsubay',
registration_number: 'FP-333444',
tc_kimlik: '22222222222',
phone: '05334455566',
is_active: true,
created_at: new Date().toISOString()
}
];
let nextFuelPersonnelId = 3;
// Unit personnel listesi (teslim alanlar)
let unitPersonnel = [
{
id: 1,
full_name: 'Serkan Yılmaz',
rank: 'Teğmen',
registration_number: 'UP-1001',
tc_kimlik: '12312312312',
phone: '05320001122',
unit_id: 1,
is_active: true,
created_at: new Date().toISOString()
},
{
id: 2,
full_name: 'Barış Aksoy',
rank: 'Astsubay',
registration_number: 'UP-2001',
tc_kimlik: '98798798798',
phone: '05323334455',
unit_id: 2,
is_active: true,
created_at: new Date().toISOString()
},
{
id: 3,
full_name: 'Hakan Güler',
rank: 'Üstçavuş',
registration_number: 'UP-3001',
tc_kimlik: '55544433322',
phone: '05324445566',
unit_id: 3,
is_active: true,
created_at: new Date().toISOString()
}
];
let nextUnitPersonnelId = 4;
function parseMukannenValue(value) {
if (value === null || value === undefined || value === '') {
return 0;
}
if (typeof value === 'number') {
return value;
}
const parsed = parseFloat(value.toString().replace(',', '.'));
return isNaN(parsed) ? 0 : parsed;
}
const app = express();
const server = createServer(app);
const io = new Server(server, {
cors: {
origin: "http://localhost:5173",
methods: ["GET", "POST"]
}
});
// Export io for use in other modules
// export { io }; // Commented out to avoid circular dependency
const PORT = process.env.PORT || 3000;
// ES Module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Database path setup - ensure /db directory exists and use it
const projectRoot = dirname(__dirname); // Go up from src/ to project root
const dbDir = join(projectRoot, 'db');
const dbPath = join(dbDir, 'yakit_takip.db');
// Middleware
app.use(express.json());
// Note: static file serving removed - SvelteKit handles frontend in development
// Session middleware
app.use(session({
secret: 'yakit-takip-modulu-secret-key-2023',
resave: false,
saveUninitialized: false,
cookie: {
secure: false, // development için false
maxAge: 24 * 60 * 60 * 1000 // 24 saat
}
}));
// Ensure /db directory exists
async function ensureDbDirectory() {
try {
await fs.mkdir(dbDir, { recursive: true });
console.log(`📁 Database directory ensured: ${dbDir}`);
} catch (error) {
console.error('❌ Error creating database directory:', error);
throw error;
}
}
// Veritabanı değişkeni (başlangıçta null)
let db;
// Veritabanı bağlantısını oluştur
async function createDatabaseConnection() {
return new Promise((resolve, reject) => {
db = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error('❌ Database connection error:', err);
reject(err);
} else {
console.log('✅ Database connection established');
resolve();
}
});
});
}
// Veritabanı tablolarını oluştur
async function initializeDatabase() {
return new Promise((resolve, reject) => {
db.serialize(() => {
// Kullanıcılar tablosu
db.run(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
role TEXT NOT NULL,
full_name TEXT,
unit_id INTEGER,
unit_name TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT 1
)`, (err) => {
if (err) reject(err);
});
// Ensure optional columns exist (for older databases)
db.all('PRAGMA table_info(users)', (pragmaErr, columns) => {
if (pragmaErr) {
console.error('⚠️ Unable to inspect users table columns:', pragmaErr);
} else {
const colNames = columns.map(col => col.name);
const ensureColumn = (name, definition) => {
if (!colNames.includes(name)) {
db.run(`ALTER TABLE users ADD COLUMN ${definition}`, (alterErr) => {
if (alterErr) {
console.warn(`⚠️ Could not add column ${name}:`, alterErr.message);
} else {
console.log(` Added column ${name} to users table.`);
}
});
}
};
ensureColumn('unit_id', 'unit_id INTEGER');
ensureColumn('unit_name', 'unit_name TEXT');
ensureColumn('rank', 'rank TEXT');
}
});
// Yakıt fişleri tablosu
db.run(`CREATE TABLE IF NOT EXISTS fuel_slips (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
force_command TEXT NOT NULL,
unit_id INTEGER,
unit_name TEXT,
vehicle_id INTEGER,
vehicle_info TEXT,
fuel_type TEXT NOT NULL,
liters REAL NOT NULL,
km INTEGER,
personnel_id INTEGER,
personnel_info TEXT,
goods_manager_id INTEGER,
goods_manager_info TEXT,
fuel_manager_id INTEGER,
fuel_manager_info TEXT,
status TEXT DEFAULT 'pending',
notes TEXT,
approval_date TEXT,
approval_notes TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`, (err) => {
if (err) reject(err);
});
// Tablolar oluşturulduktan sonra kullanıcıları ekle
setTimeout(async () => {
// Örnek kullanıcıları ekle
const users = [
{ username: 'admin', password: 'admin123', role: 'admin', full_name: 'Sistem Yöneticisi', rank: 'Yönetici' },
{ username: 'fuel', password: 'fuel123', role: 'fuel_manager', full_name: 'Yakıt Sorumlusu', rank: 'Yüzbaşı' },
{ username: 'goods', password: 'goods123', role: 'goods_manager', full_name: 'Ali Veli', unit_id: 1, unit_name: '1. Motorlu Piyade Tugayı', rank: 'Binbaşı' },
{ username: 'ibrahim_kara', password: 'kara123', role: 'goods_manager', full_name: 'İbrahim Kara', unit_id: 2, unit_name: '2. Zırhlı Tabur', rank: 'Yüzbaşı' },
{ username: 'osmankocak', password: 'osman123', role: 'goods_manager', full_name: 'Osman Koçak', unit_id: 3, unit_name: '3. Komutanlık', rank: 'Üsteğmen' }
];
// Her kullanıcıyı kontrol et ve yoksa ekle
for (const user of users) {
const hashedPassword = await bcrypt.hash(user.password, 10);
db.get('SELECT id, unit_id, unit_name, rank FROM users WHERE username = ?', [user.username], (err, row) => {
if (!row) {
db.run('INSERT INTO users (username, password, role, full_name, unit_id, unit_name, rank) VALUES (?, ?, ?, ?, ?, ?, ?)',
[user.username, hashedPassword, user.role, user.full_name, user.unit_id || null, user.unit_name || null, user.rank || null]);
} else if ((user.unit_id && !row.unit_id) || (user.unit_name && !row.unit_name) || (user.rank && !row.rank)) {
db.run('UPDATE users SET unit_id = COALESCE(unit_id, ?), unit_name = COALESCE(unit_name, ?), rank = COALESCE(rank, ?) WHERE username = ?',
[user.unit_id || null, user.unit_name || null, user.rank || null, user.username]);
}
});
}
resolve();
}, 100);
});
});
}
// API Routes
// Login endpoint
app.post('/api/login', async (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ message: 'Kullanıcı adı ve şifre gerekli.' });
}
try {
db.get('SELECT * FROM users WHERE username = ? AND is_active = 1', [username], async (err, user) => {
if (err) {
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
if (!user) {
return res.status(401).json({ message: 'Kullanıcı bulunamadı.' });
}
const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) {
return res.status(401).json({ message: 'Şifre hatalı.' });
}
// Session oluştur
let sessionUser = {
id: user.id,
username: user.username,
role: user.role,
full_name: user.full_name,
rank: user.rank || null,
unit_id: user.unit_id ? parseInt(user.unit_id) : null,
unit_name: user.unit_name || null
};
// Eğer goods_manager ise, goodsManagers verisinden profil bilgilerini al
if (user.role === 'goods_manager') {
const goodsManager = findGoodsManagerByUsername(user.username);
if (goodsManager) {
sessionUser.goods_manager_profile_id = goodsManager.id;
sessionUser.id = goodsManager.id;
if (!sessionUser.unit_id || !sessionUser.unit_name) {
sessionUser.unit_id = goodsManager.unit_id;
sessionUser.unit_name = goodsManager.unit_name;
sessionUser.rank = goodsManager.rank;
db.run('UPDATE users SET unit_id = ?, unit_name = ?, rank = ? WHERE id = ?', [
goodsManager.unit_id,
goodsManager.unit_name,
goodsManager.rank,
user.id
]);
}
if (!sessionUser.rank) {
sessionUser.rank = goodsManager.rank;
}
console.log(`✅ Goods manager logged in: ${goodsManager.full_name} (ID: ${goodsManager.id})`);
} else {
if (!sessionUser.unit_id || !sessionUser.unit_name) {
console.warn(`⚠️ Goods manager profile not found for username: ${user.username}`);
}
}
}
req.session.user = sessionUser;
res.json({
message: 'Giriş başarılı.',
user: sessionUser
});
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Logout endpoint
app.post('/api/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
return res.status(500).json({ message: ıkış yapılamadı.' });
}
res.json({ message: ıkış başarılı.' });
});
});
// Mevcut kullanıcı bilgisi
app.get('/api/user', (req, res) => {
if (!req.session.user) {
return res.status(401).json({ message: 'Oturum bulunamadı.' });
}
res.json({ user: req.session.user });
});
// Socket.IO bildirim endpoint'i
app.post('/api/socket-notify', (req, res) => {
const { event, data } = req.body;
if (!event || !data) {
return res.status(400).json({ message: 'Event ve data zorunludur.' });
}
// Socket.IO ile olay yayınla
console.log(`📢 Socket.IO event emitted: ${event}`, data);
io.emit(event, data);
res.json({ message: 'Bildirim gönderildi.' });
});
// Tüm kullanıcıları getir (sadece admin)
app.get('/api/users', (req, res) => {
if (!req.session.user || req.session.user.role !== 'admin') {
return res.status(403).json({ message: 'Yetkisiz erişim.' });
}
db.all('SELECT id, username, role, full_name, created_at, is_active FROM users', (err, users) => {
if (err) {
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
res.json({ users });
});
});
// Units API endpoint'leri
// GET - Tüm birlikleri listele
app.get('/api/units', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
res.json({ units });
});
// POST - Yeni birlik ekle
app.post('/api/units', async (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const {
name,
address,
stk,
btk,
commander
} = req.body;
// Validasyon
if (!name || !address || !stk || !btk || !commander) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
// Komutan validasyonu
const { full_name, rank, registration_number, tc_kimlik, phone, username, password } = commander;
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone || !username || !password) {
return res.status(400).json({ message: 'Mal sorumlusunun tüm bilgileri zorunludur.' });
}
// TC Kimlik numarası validasyonu
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
// Yeni birlik oluştur
const newUnit = {
id: nextUnitId++,
name: name.trim(),
address: address.trim(),
stk: stk.trim().toUpperCase(),
btk: btk.trim().toUpperCase(),
commander: {
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
username: username.trim(),
password: password.trim()
},
created_at: new Date().toISOString()
};
// Mal sorumlusu için kullanıcı oluştur
try {
const hashedPassword = await bcrypt.hash(password, 10);
// Kullanıcı adı benzersizliğini kontrol et
const existingUser = await new Promise((resolve, reject) => {
db.get('SELECT id FROM users WHERE username = ?', [username], (err, row) => {
if (err) reject(err);
else resolve(row);
});
});
if (existingUser) {
return res.status(400).json({ message: 'Bu kullanıcı adı zaten kullanımda.' });
}
// Mal sorumlusu kullanıcı olarak ekle
await new Promise((resolve, reject) => {
db.run(
'INSERT INTO users (username, password, role, full_name, unit_id, unit_name, rank) VALUES (?, ?, ?, ?, ?, ?, ?)',
[
username.trim(),
hashedPassword,
'goods_manager',
full_name.trim(),
newUnit.id,
newUnit.name,
rank.trim()
],
(err) => {
if (err) reject(err);
else resolve();
}
);
});
console.log(`✅ Mal sorumlusu kullanıcı oluşturuldu: ${username}`);
} catch (userError) {
console.error('❌ Mal sorumlusu kullanıcı oluşturma hatası:', userError);
return res.status(500).json({ message: 'Mal sorumlusu kullanıcı oluşturulamadı.' });
}
units.push(newUnit);
res.json({
message: 'Birlik başarıyla eklendi.',
unit: newUnit
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Birlik güncelle
app.put('/api/units', async (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const {
id,
name,
address,
stk,
btk,
commander
} = req.body;
// Validasyon
if (!id || !name || !address || !stk || !btk || !commander) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
// Komutan validasyonu
const { full_name, rank, registration_number, tc_kimlik, phone, username, password } = commander;
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone || !username || !password) {
return res.status(400).json({ message: 'Mal sorumlusunun tüm bilgileri zorunludur.' });
}
// TC Kimlik numarası validasyonu
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
// Birlik bul
const unitIndex = units.findIndex(u => u.id === parseInt(id));
if (unitIndex === -1) {
return res.status(404).json({ message: 'Birlik bulunamadı.' });
}
// Mevcut komutan bilgisini sakla (DB senkronu için)
const previousUnitState = {
...units[unitIndex],
commander: { ...units[unitIndex].commander }
};
// Birlik güncelle
const updatedCommander = {
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
username: username.trim(),
password: password.trim()
};
const previousCommanderUsername = previousUnitState?.commander?.username || updatedCommander.username;
units[unitIndex] = {
...units[unitIndex],
name: name.trim(),
address: address.trim(),
stk: stk.trim().toUpperCase(),
btk: btk.trim().toUpperCase(),
commander: updatedCommander
};
// Mal sorumlusu kullanıcı kaydını güncelle
try {
const hashedPassword = await bcrypt.hash(password, 10);
await new Promise((resolve, reject) => {
db.run(
`UPDATE users
SET username = ?, password = ?, full_name = ?, unit_id = ?, unit_name = ?, rank = ?
WHERE username = ?`,
[
updatedCommander.username,
hashedPassword,
updatedCommander.full_name,
units[unitIndex].id,
units[unitIndex].name,
updatedCommander.rank,
previousCommanderUsername
],
function (err) {
if (err) {
return reject(err);
}
if (this.changes === 0) {
return reject(new Error('Mal sorumlusu kullanıcı kaydı bulunamadı.'));
}
return resolve();
}
);
});
console.log(`✅ Mal sorumlusu kullanıcı güncellendi: ${updatedCommander.username}`);
} catch (userError) {
console.error('❌ Mal sorumlusu kullanıcı güncelleme hatası:', userError);
// Kullanıcı güncellenemezse, birlik güncellemesi geri alınsın
units[unitIndex] = previousUnitState;
return res.status(500).json({ message: 'Mal sorumlusu kullanıcı güncellenemedi.' });
}
res.json({
message: 'Birlik başarıyla güncellendi.',
unit: units[unitIndex]
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Birlik sil
app.delete('/api/units', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Birlik ID zorunludur.' });
}
// Birlik bul
const unitIndex = units.findIndex(u => u.id === parseInt(id));
if (unitIndex === -1) {
return res.status(404).json({ message: 'Birlik bulunamadı.' });
}
// Birlik sil
const deletedUnit = units.splice(unitIndex, 1)[0];
res.json({
message: 'Birlik başarıyla silindi.',
unit: deletedUnit
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Goods Managers API endpoint'leri
// GET - Tüm mal sorumlularını listele
app.get('/api/goods-managers', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const goodsManagers = getGoodsManagers();
res.json({ goodsManagers });
} catch (error) {
res.status(500).json({ message: 'Mal sorumluları alınırken hata oluştu.' });
}
});
// POST - Yeni mal sorumlusu ekle
app.post('/api/goods-managers', async (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const {
full_name,
rank,
registration_number,
tc_kimlik,
phone,
unit_id,
username,
password,
is_active = true
} = req.body;
const newManager = addGoodsManager({
full_name,
rank,
registration_number,
tc_kimlik,
phone,
unit_id,
unit_name: units.find(u => u.id === parseInt(unit_id))?.name || 'Bilinmeyen Birlik',
username,
password,
is_active
});
res.json({
message: 'Personel başarıyla eklendi.',
goodsManager: newManager
});
} catch (error) {
if (error.message.includes('zorunludur') ||
error.message.includes('zaten kayıtlı') ||
error.message.includes('Geçersiz') ||
error.message.includes('karakter')) {
return res.status(400).json({ message: error.message });
}
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Mal sorumlusu güncelle
app.put('/api/goods-managers', async (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const {
id,
full_name,
rank,
registration_number,
tc_kimlik,
phone,
unit_id,
username,
password,
is_active
} = req.body;
const updatedManager = updateGoodsManager(id, {
full_name,
rank,
registration_number,
tc_kimlik,
phone,
unit_id,
unit_name: units.find(u => u.id === parseInt(unit_id))?.name || 'Bilinmeyen Birlik',
username,
password,
is_active
});
res.json({
message: 'Personel başarıyla güncellendi.',
goodsManager: updatedManager
});
} catch (error) {
if (error.message.includes('zorunludur') ||
error.message.includes('bulunamadı') ||
error.message.includes('zaten kayıtlı') ||
error.message.includes('Geçersiz') ||
error.message.includes('karakter')) {
return res.status(error.message.includes('bulunamadı') ? 404 : 400).json({ message: error.message });
}
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Mal sorumlusu sil
app.delete('/api/goods-managers', async (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Mal sorumlusu ID zorunludur.' });
}
const deletedManager = deleteGoodsManager(id);
res.json({
message: 'Mal sorumlusu başarıyla silindi.',
goodsManager: deletedManager
});
} catch (error) {
if (error.message.includes('bulunamadı')) {
return res.status(404).json({ message: error.message });
}
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Fuel Personnel API endpoint'leri
// GET - Tüm yakıt personelini listele
app.get('/api/fuel-personnel', (req, res) => {
res.json({ fuelPersonnel });
});
// POST - Yeni yakıt personeli ekle
app.post('/api/fuel-personnel', async (req, res) => {
try {
const {
full_name,
rank,
registration_number,
tc_kimlik,
phone,
is_active = true
} = req.body;
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
const existingPersonnel = fuelPersonnel.find(p =>
p.registration_number === registration_number || p.tc_kimlik === tc_kimlik
);
if (existingPersonnel) {
return res.status(400).json({ message: 'Bu personel zaten kayıtlı.' });
}
const newPersonnel = {
id: nextFuelPersonnelId++,
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
is_active: Boolean(is_active),
created_at: new Date().toISOString()
};
fuelPersonnel.push(newPersonnel);
res.json({
message: 'Yakıt personeli başarıyla eklendi.',
fuelPersonnel: newPersonnel
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Yakıt personeli güncelle
app.put('/api/fuel-personnel', (req, res) => {
try {
const {
id,
full_name,
rank,
registration_number,
tc_kimlik,
phone,
is_active
} = req.body;
if (!id || !full_name || !rank || !registration_number || !tc_kimlik || !phone) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
const personnelIndex = fuelPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
const duplicate = fuelPersonnel.find(p =>
p.id !== parseInt(id) && (p.registration_number === registration_number || p.tc_kimlik === tc_kimlik)
);
if (duplicate) {
return res.status(400).json({ message: 'Aynı sicil veya TC Kimlik başka bir personelde mevcut.' });
}
fuelPersonnel[personnelIndex] = {
...fuelPersonnel[personnelIndex],
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
is_active: Boolean(is_active)
};
res.json({
message: 'Yakıt personeli güncellendi.',
fuelPersonnel: fuelPersonnel[personnelIndex]
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Yakıt personeli sil
app.delete('/api/fuel-personnel', (req, res) => {
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Personel ID zorunludur.' });
}
const personnelIndex = fuelPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
const deletedPersonnel = fuelPersonnel.splice(personnelIndex, 1)[0];
res.json({
message: 'Yakıt personeli silindi.',
fuelPersonnel: deletedPersonnel
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Unit Personnel API endpoint'leri (Teslim Alan personeller)
app.get('/api/unit-personnel', (req, res) => {
res.json({ unitPersonnel });
});
app.post('/api/unit-personnel', (req, res) => {
try {
const {
full_name,
rank,
registration_number,
tc_kimlik,
phone,
unit_id,
is_active = true
} = req.body;
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone || !unit_id) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
const duplicate = unitPersonnel.find(p =>
p.registration_number === registration_number || p.tc_kimlik === tc_kimlik
);
if (duplicate) {
return res.status(400).json({ message: 'Bu personel zaten kayıtlı.' });
}
const newPersonnel = {
id: nextUnitPersonnelId++,
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
unit_id: parseInt(unit_id),
is_active: Boolean(is_active),
created_at: new Date().toISOString()
};
unitPersonnel.push(newPersonnel);
res.json({
message: 'Personel başarıyla eklendi.',
personnel: newPersonnel
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
app.put('/api/unit-personnel', (req, res) => {
try {
const {
id,
full_name,
rank,
registration_number,
tc_kimlik,
phone,
unit_id,
is_active
} = req.body;
if (!id || !full_name || !rank || !registration_number || !tc_kimlik || !phone || !unit_id) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
const personnelIndex = unitPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
const duplicate = unitPersonnel.find(p =>
p.id !== parseInt(id) && (p.registration_number === registration_number || p.tc_kimlik === tc_kimlik)
);
if (duplicate) {
return res.status(400).json({ message: 'Bu sicil veya TC Kimlik başka bir personelde mevcut.' });
}
unitPersonnel[personnelIndex] = {
...unitPersonnel[personnelIndex],
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
unit_id: parseInt(unit_id),
is_active: Boolean(is_active)
};
res.json({
message: 'Personel güncellendi.',
personnel: unitPersonnel[personnelIndex]
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
app.delete('/api/unit-personnel', (req, res) => {
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Personel ID zorunludur.' });
}
const personnelIndex = unitPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
const deletedPersonnel = unitPersonnel.splice(personnelIndex, 1)[0];
res.json({
message: 'Personel silindi.',
personnel: deletedPersonnel
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Fuel Slips API endpoint'leri
// GET - Yakıt fişlerini listele
app.get('/api/fuel-slips', (req, res) => {
const searchParams = req.query;
const status = searchParams.status;
const manager_id = searchParams.manager_id;
const fuel_manager_id = searchParams.fuel_manager_id;
const unit_id = searchParams.unit_id;
// Veritabanı sorgusu
let query = 'SELECT * FROM fuel_slips WHERE 1=1';
const params = [];
// Status filtreleme
if (status) {
query += ' AND status = ?';
params.push(status);
}
// Mal sorumlusu filtreleme
if (manager_id) {
query += ' AND goods_manager_id = ?';
params.push(manager_id);
}
// Yakıt sorumlusu filtreleme
if (fuel_manager_id) {
query += ' AND fuel_manager_id = ?';
params.push(fuel_manager_id);
}
// Birlik filtreleme
if (unit_id) {
query += ' AND unit_id = ?';
params.push(parseInt(unit_id));
}
// Tarihe göre ters sırala
query += ' ORDER BY created_at DESC';
db.all(query, params, (err, rows) => {
if (err) {
console.error('GET fuel slips error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
// JSON string olarak saklanan alanları parse et
const fuelSlips = rows.map(row => ({
...row,
vehicle_info: row.vehicle_info ? JSON.parse(row.vehicle_info) : null,
personnel_info: row.personnel_info ? JSON.parse(row.personnel_info) : null,
goods_manager_info: row.goods_manager_info ? JSON.parse(row.goods_manager_info) : null,
fuel_manager_info: row.fuel_manager_info ? JSON.parse(row.fuel_manager_info) : null
}));
res.json({ fuelSlips });
});
});
// POST - Yeni yakıt fişi oluştur
app.post('/api/fuel-slips', async (req, res) => {
try {
const slipData = req.body;
console.log('📝 Creating new fuel slip with data:', slipData);
// Validasyon
const requiredFields = [
'date', 'force_command', 'unit_id', 'vehicle_id',
'fuel_type', 'liters', 'km', 'personnel_id',
'goods_manager_id', 'fuel_manager_id'
];
for (const field of requiredFields) {
if (!slipData[field]) {
return res.status(400).json({ message: `${field} alanı zorunludur.` });
}
}
// Litre ve KM validasyonu
if (slipData.liters <= 0 || slipData.km < 0) {
return res.status(400).json({ message: 'Litre ve KM değerleri geçersiz.' });
}
const unitId = parseInt(slipData.unit_id);
const vehicleId = parseInt(slipData.vehicle_id);
const personnelId = parseInt(slipData.personnel_id);
const goodsManagerId = parseInt(slipData.goods_manager_id);
const fuelManagerId = parseInt(slipData.fuel_manager_id);
// Araç, personel ve mal sorumlusu bilgilerini getir
const vehicle = vehicles.find(v => v.id === vehicleId);
const unit = units.find(u => u.id === unitId);
const person = fuelPersonnel.find(p => p.id === personnelId && p.is_active);
const receivingPerson = unitPersonnel.find(p => p.id === goodsManagerId && p.is_active);
if (!person) {
return res.status(400).json({ message: 'Teslim eden personel bulunamadı veya pasif durumda.' });
}
if (!receivingPerson) {
return res.status(400).json({ message: 'Teslim alan personel bulunamadı veya pasif durumda.' });
}
if (receivingPerson.unit_id !== unitId) {
return res.status(400).json({ message: 'Seçilen personel bu birliğe bağlı değil.' });
}
const vehicleInfo = vehicle ? {
brand: vehicle.brand,
model: vehicle.model,
plate: vehicle.plate,
year: vehicle.year
} : {
brand: 'Bilinmeyen',
model: 'Araç',
plate: 'Bilinmiyor',
year: 0
};
const personnelInfo = person ? {
full_name: person.full_name,
rank: person.rank,
unit_id: person.unit_id,
registration_number: person.registration_number
} : {
full_name: 'Bilinmeyen Personel',
rank: ''
};
const goodsManagerInfo = receivingPerson ? {
full_name: receivingPerson.full_name,
rank: receivingPerson.rank,
unit_id: receivingPerson.unit_id,
unit_name: getUnitNameById(receivingPerson.unit_id)
} : {
full_name: 'Bilinmeyen Mal Sorumlusu',
rank: ''
};
const fuelManagerInfo = { full_name: 'Yakıt Sorumlusu', rank: 'Yüzbaşı' };
const query = `
INSERT INTO fuel_slips (
date, force_command, unit_id, unit_name, vehicle_id, vehicle_info,
fuel_type, liters, km, personnel_id, personnel_info, goods_manager_id,
goods_manager_info, fuel_manager_id, fuel_manager_info, status, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
const params = [
slipData.date,
slipData.force_command,
unitId,
unit?.name || `Birim ${unitId}`,
vehicleId,
JSON.stringify(vehicleInfo),
slipData.fuel_type,
parseFloat(slipData.liters),
parseInt(slipData.km),
personnelId,
JSON.stringify(personnelInfo),
goodsManagerId,
JSON.stringify(goodsManagerInfo),
fuelManagerId,
JSON.stringify(fuelManagerInfo),
'pending',
slipData.notes || ''
];
db.run(query, params, function(err) {
if (err) {
console.error('Create fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
const newSlip = {
id: this.lastID,
date: slipData.date,
force_command: slipData.force_command,
unit_id: unitId,
unit_name: unit?.name || `Birim ${unitId}`,
vehicle_id: vehicleId,
vehicle_info: vehicleInfo,
fuel_type: slipData.fuel_type,
liters: parseFloat(slipData.liters),
km: parseInt(slipData.km),
personnel_id: personnelId,
personnel_info: personnelInfo,
goods_manager_id: goodsManagerId,
goods_manager_info: goodsManagerInfo,
fuel_manager_id: fuelManagerId,
fuel_manager_info: fuelManagerInfo,
status: 'pending',
notes: slipData.notes || '',
created_at: new Date().toISOString()
};
console.log('✅ Fuel slip created:', newSlip);
// Socket.IO ile mal sorumlusuna bildirim gönder
const socketData = {
goods_manager_id: newSlip.goods_manager_id,
unit_id: newSlip.unit_id,
fuel_slip_id: newSlip.id,
message: `${newSlip.vehicle_info.plate} plakalı araç için yeni yakıt fişi`
};
console.log('📢 Sending socket notification: fuel-slip-assigned', socketData);
io.emit('fuel-slip-assigned', socketData);
res.json({
message: 'Yakıt fişi başarıyla oluşturuldu.',
fuelSlip: newSlip
});
});
} catch (error) {
console.error('Create fuel slip error:', error);
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Fiş durumunu güncelle (onay/reddet)
app.put('/api/fuel-slips', async (req, res) => {
try {
const { id, status, approval_notes } = req.body;
if (!id || !status) {
return res.status(400).json({ message: 'ID ve durum zorunludur.' });
}
if (!['approved', 'rejected'].includes(status)) {
return res.status(400).json({ message: 'Geçersiz durum.' });
}
const query = `
UPDATE fuel_slips
SET status = ?, approval_date = ?, approval_notes = ?
WHERE id = ?
`;
const params = [
status,
new Date().toISOString(),
approval_notes || '',
parseInt(id)
];
db.run(query, params, function(err) {
if (err) {
console.error('Update fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
if (this.changes === 0) {
return res.status(404).json({ message: 'Fiş bulunamadı.' });
}
// Güncellenmiş fişi getir
db.get('SELECT * FROM fuel_slips WHERE id = ?', [id], (err, row) => {
if (err) {
console.error('Get updated fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
const updatedSlip = {
...row,
vehicle_info: row.vehicle_info ? JSON.parse(row.vehicle_info) : null,
personnel_info: row.personnel_info ? JSON.parse(row.personnel_info) : null,
goods_manager_info: row.goods_manager_info ? JSON.parse(row.goods_manager_info) : null,
fuel_manager_info: row.fuel_manager_info ? JSON.parse(row.fuel_manager_info) : null
};
console.log('✅ Fuel slip updated:', updatedSlip);
// Socket.IO ile yakıt sorumlusuna bildirim gönder
const socketData = {
goods_manager_id: updatedSlip.goods_manager_id,
fuel_manager_id: updatedSlip.fuel_manager_id,
unit_id: updatedSlip.unit_id,
fuel_slip_id: updatedSlip.id,
status: updatedSlip.status,
approval_notes: updatedSlip.approval_notes
};
console.log('📢 Sending socket notification: fuel-slip-updated', socketData);
io.emit('fuel-slip-updated', socketData);
res.json({
message: `Fiş başarıyla ${status === 'approved' ? 'onaylandı' : 'reddedildi'}.`,
fuelSlip: updatedSlip
});
});
});
} catch (error) {
console.error('Update fuel slip error:', error);
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Fiş sil
app.delete('/api/fuel-slips', async (req, res) => {
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Fiş ID zorunludur.' });
}
// Önce fişin durumunu kontrol et
db.get('SELECT status FROM fuel_slips WHERE id = ?', [id], (err, row) => {
if (err) {
console.error('Check fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
if (!row) {
return res.status(404).json({ message: 'Fiş bulunamadı.' });
}
// Sadece pending olan fişler silinebilir
if (row.status !== 'pending') {
return res.status(400).json({ message: 'Sadece bekleyen fişler silinebilir.' });
}
// Fiş sil
db.run('DELETE FROM fuel_slips WHERE id = ?', [id], function(err) {
if (err) {
console.error('Delete fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
if (this.changes === 0) {
return res.status(404).json({ message: 'Fiş bulunamadı.' });
}
res.json({
message: 'Fiş başarıyla silindi.',
fuelSlipId: parseInt(id)
});
});
});
} catch (error) {
console.error('Delete fuel slip error:', error);
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Vehicles API endpoint'leri
// Yardımcı: goods manager birlik bilgisi al
function getGoodsManagerUnit(req) {
const sessionUser = req.session?.user;
if (!sessionUser || sessionUser.role !== 'goods_manager') {
return { isGoodsManager: false, unitId: null };
}
const unitId = sessionUser.unit_id ? parseInt(sessionUser.unit_id) : null;
return { isGoodsManager: true, unitId };
}
// GET - Tüm araçları listele
app.get('/api/vehicles', (req, res) => {
const { isGoodsManager, unitId } = getGoodsManagerUnit(req);
if (isGoodsManager && !unitId) {
return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisi ile iletişime geçin.' });
}
const filteredVehicles = isGoodsManager
? vehicles.filter(vehicle => vehicle.unit_id === unitId)
: vehicles;
res.json({ vehicles: filteredVehicles });
});
// POST - Yeni araç ekle
app.post('/api/vehicles', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const { isGoodsManager, unitId: managerUnitId } = getGoodsManagerUnit(req);
const {
brand,
model,
year,
plate,
unit_id,
fuel_type,
fuel_capacity,
current_fuel,
yazlik_mukannen = 0,
kislik_mukannen = 0,
status = 'Aktif',
driver_id,
driver_name
} = req.body;
const resolvedUnitId = isGoodsManager ? managerUnitId : parseInt(unit_id);
// Validasyon
if (!brand || !model || !year || !plate || (!resolvedUnitId && !isGoodsManager) || !fuel_type || !fuel_capacity) {
return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' });
}
if (isGoodsManager && !managerUnitId) {
return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisi ile iletişime geçin.' });
}
const targetUnit = units.find(u => u.id === resolvedUnitId);
if (!targetUnit) {
return res.status(400).json({ message: 'Geçerli bir birlik seçin.' });
}
if (year < 1990 || year > new Date().getFullYear() + 1) {
return res.status(400).json({ message: 'Geçerli bir yıl girin.' });
}
if (current_fuel < 0 || current_fuel > fuel_capacity) {
return res.status(400).json({ message: 'Mevcut yakıt değeri geçersiz.' });
}
// Plaka tekrar kontrolü
const existingVehicle = vehicles.find(v =>
v.plate.toLowerCase() === plate.toLowerCase()
);
if (existingVehicle) {
return res.status(400).json({ message: 'Bu plaka zaten kayıtlı.' });
}
// Yeni araç oluştur
const unitName = targetUnit.name;
const newVehicle = {
id: nextVehicleId++,
brand: brand.trim(),
model: model.trim(),
year: parseInt(year),
plate: plate.trim().toUpperCase(),
unit_id: resolvedUnitId,
fuel_type: fuel_type.trim(),
fuel_capacity: parseInt(fuel_capacity),
current_fuel: parseInt(current_fuel) || 0,
yazlik_mukannen: parseMukannenValue(yazlik_mukannen),
kislik_mukannen: parseMukannenValue(kislik_mukannen),
status: (status || 'Aktif').trim(),
unit_name: unitName,
driver_id: driver_id ? parseInt(driver_id) : null,
driver_name: driver_name ? driver_name.trim() : null,
created_at: new Date().toISOString()
};
vehicles.push(newVehicle);
res.json({
message: 'Araç başarıyla eklendi.',
vehicle: newVehicle
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Araç güncelle
app.put('/api/vehicles', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const { isGoodsManager, unitId: managerUnitId } = getGoodsManagerUnit(req);
const {
id,
brand,
model,
year,
plate,
unit_id,
fuel_type,
fuel_capacity,
current_fuel,
yazlik_mukannen,
kislik_mukannen,
status,
driver_id,
driver_name
} = req.body;
const resolvedUnitId = isGoodsManager ? managerUnitId : parseInt(unit_id);
// Validasyon
if (!id || !brand || !model || !year || !plate || (!resolvedUnitId && !isGoodsManager) || !fuel_type || !fuel_capacity) {
return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' });
}
if (isGoodsManager && !managerUnitId) {
return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisine başvurun.' });
}
const targetUnit = units.find(u => u.id === resolvedUnitId);
if (!targetUnit) {
return res.status(400).json({ message: 'Geçerli bir birlik seçin.' });
}
if (year < 1990 || year > new Date().getFullYear() + 1) {
return res.status(400).json({ message: 'Geçerli bir yıl girin.' });
}
if (current_fuel < 0 || current_fuel > fuel_capacity) {
return res.status(400).json({ message: 'Mevcut yakıt değeri geçersiz.' });
}
// Araç bul
const vehicleIndex = vehicles.findIndex(v => v.id === parseInt(id));
if (vehicleIndex === -1) {
return res.status(404).json({ message: 'Araç bulunamadı.' });
}
if (isGoodsManager && vehicles[vehicleIndex].unit_id !== managerUnitId) {
return res.status(403).json({ message: 'Bu aracı güncelleme yetkiniz yok.' });
}
// Plaka tekrar kontrolü (diğer araçlar için)
const existingVehicle = vehicles.find(v =>
v.id !== parseInt(id) && v.plate.toLowerCase() === plate.toLowerCase()
);
if (existingVehicle) {
return res.status(400).json({ message: 'Bu plaka başka bir araçta kullanılıyor.' });
}
// Araç güncelle
const unitName = targetUnit.name;
vehicles[vehicleIndex] = {
...vehicles[vehicleIndex],
brand: brand.trim(),
model: model.trim(),
year: parseInt(year),
plate: plate.trim().toUpperCase(),
unit_id: resolvedUnitId,
fuel_type: fuel_type.trim(),
fuel_capacity: parseInt(fuel_capacity),
current_fuel: parseInt(current_fuel) || 0,
yazlik_mukannen: parseMukannenValue(yazlik_mukannen),
kislik_mukannen: parseMukannenValue(kislik_mukannen),
status: (status || 'Aktif').trim(),
unit_name: unitName,
driver_id: driver_id ? parseInt(driver_id) : null,
driver_name: driver_name ? driver_name.trim() : null
};
res.json({
message: 'Araç başarıyla güncellendi.',
vehicle: vehicles[vehicleIndex]
});
} catch (error) {
console.error('❌ PUT /api/vehicles error:', error);
console.error('Error details:', {
message: error.message,
stack: error.stack,
body: req.body
});
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Araç sil
app.delete('/api/vehicles', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const { isGoodsManager, unitId: managerUnitId } = getGoodsManagerUnit(req);
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Araç ID zorunludur.' });
}
// Araç bul
const vehicleIndex = vehicles.findIndex(v => v.id === parseInt(id));
if (vehicleIndex === -1) {
return res.status(404).json({ message: 'Araç bulunamadı.' });
}
if (isGoodsManager) {
if (!managerUnitId) {
return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisine başvurun.' });
}
if (vehicles[vehicleIndex].unit_id !== managerUnitId) {
return res.status(403).json({ message: 'Bu aracı silme yetkiniz yok.' });
}
}
// Araç sil
const deletedVehicle = vehicles.splice(vehicleIndex, 1)[0];
res.json({
message: 'Araç başarıyla silindi.',
vehicle: deletedVehicle
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Socket.IO bağlantıları
io.on('connection', (socket) => {
console.log('✅ Bir kullanıcı bağlandı:', socket.id);
// API'den gelen event'ları dinle ve broadcast et
socket.on('api-fuel-slip-assigned', (data) => {
console.log('📢 API event received: api-fuel-slip-assigned, broadcasting to all clients', data);
io.emit('fuel-slip-assigned', data);
});
socket.on('api-fuel-slip-updated', (data) => {
console.log('📢 API event received: api-fuel-slip-updated, broadcasting to all clients', data);
io.emit('fuel-slip-updated', data);
});
socket.on('disconnect', () => {
console.log('❌ Bir kullanıcı ayrıldı:', socket.id);
});
});
// API server only - frontend handled by SvelteKit dev server in development
// In production, the build will be served differently
// Sunucuyu başlat
async function startServer() {
try {
// Ensure database directory exists first
await ensureDbDirectory();
console.log(`📄 Database file path: ${dbPath}`);
// Create database connection
await createDatabaseConnection();
// Initialize database and tables
await initializeDatabase();
server.listen(PORT, () => {
console.log(`🚀 Sunucu http://localhost:${PORT} adresinde çalışıyor`);
console.log(`📱 Socket.IO sunucusu aktif`);
console.log(`💾 Veritabanı: ${dbPath}`);
});
} catch (error) {
console.error('❌ Sunucu başlatılamadı:', error);
process.exit(1);
}
}
startServer();