first commit
This commit is contained in:
13
server/db-init.js
Normal file
13
server/db-init.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const { db, initialize } = require('./db');
|
||||
|
||||
initialize()
|
||||
.then(() => {
|
||||
console.log('Veritabani hazirlandi.');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Veritabani hazirlama hatasi:', err);
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.finally(() => {
|
||||
db.close();
|
||||
});
|
||||
916
server/db.js
Normal file
916
server/db.js
Normal file
@@ -0,0 +1,916 @@
|
||||
const path = require('path');
|
||||
const sqlite3 = require('sqlite3').verbose();
|
||||
|
||||
const dbPath = path.join(__dirname, '..', 'data', 'app.db');
|
||||
const db = new sqlite3.Database(dbPath);
|
||||
|
||||
const SAMPLE_USERS = [
|
||||
{
|
||||
username: 'admin',
|
||||
password: 'Admin!123',
|
||||
role: 'admin',
|
||||
displayName: 'Istasyon Admini'
|
||||
},
|
||||
{
|
||||
username: 'yakitsorum',
|
||||
password: 'Yakit@123',
|
||||
role: 'fuel_manager',
|
||||
displayName: 'Yakit Sorumlusu'
|
||||
},
|
||||
{
|
||||
username: 'malsorum1',
|
||||
password: 'Mal@123',
|
||||
role: 'inventory_manager',
|
||||
displayName: 'Mal Sorumlusu 1'
|
||||
}
|
||||
];
|
||||
|
||||
const SAMPLE_VEHICLES = [
|
||||
{ brand: 'Ford', model: 'Transit', year: 2021, plate: '34 AYT 312' },
|
||||
{ brand: 'Isuzu', model: 'NPR', year: 2019, plate: '34 FZT 908' }
|
||||
];
|
||||
|
||||
const SAMPLE_UNITS = [
|
||||
{
|
||||
name: 'Merkez Birlik',
|
||||
address: 'Cumhuriyet Mah. İstasyon Cad. No:12/1 İstanbul',
|
||||
stk: 'STK-4589',
|
||||
btk: 'BTK-9021',
|
||||
contactName: 'Yzb. Murat Kaya',
|
||||
contactRank: 'Yuzbasi',
|
||||
contactRegistry: 'MK4587',
|
||||
contactIdentity: '25478963210',
|
||||
contactPhone: '+90 532 456 78 12'
|
||||
},
|
||||
{
|
||||
name: 'Doğu Lojistik Birimi',
|
||||
address: 'Sanayi Mah. Depo Sok. No:8 Erzurum',
|
||||
stk: 'STK-7865',
|
||||
btk: 'BTK-6674',
|
||||
contactName: 'Uzm. Cav. Esra Yilmaz',
|
||||
contactRank: 'Uzman Cavus',
|
||||
contactRegistry: 'EY3345',
|
||||
contactIdentity: '19876543219',
|
||||
contactPhone: '+90 532 998 11 44'
|
||||
}
|
||||
];
|
||||
|
||||
const SAMPLE_FUEL_PERSONNEL = [
|
||||
{
|
||||
fullName: 'Astsb. Cahit Demir',
|
||||
rank: 'Astsubay',
|
||||
registryNumber: 'CD5561',
|
||||
identityNumber: '14523698741',
|
||||
phone: '+90 532 223 45 67'
|
||||
},
|
||||
{
|
||||
fullName: 'Sv. Uzm. Er Ali Korkmaz',
|
||||
rank: 'Sozlesmeli Er',
|
||||
registryNumber: 'AK7812',
|
||||
identityNumber: '32987456100',
|
||||
phone: '+90 555 893 22 10'
|
||||
}
|
||||
];
|
||||
|
||||
function run(query, params = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(query, params, function callback(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(this);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function ensureColumn(table, column, definition) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(`PRAGMA table_info(${table})`, [], (err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const exists = rows.some((row) => row.name === column);
|
||||
if (exists) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
db.run(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`, (alterErr) => {
|
||||
if (alterErr) {
|
||||
reject(alterErr);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.serialize(async () => {
|
||||
try {
|
||||
await 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 CHECK(role IN ('admin','fuel_manager','inventory_manager')),
|
||||
display_name TEXT NOT NULL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)`
|
||||
);
|
||||
|
||||
await run(
|
||||
`CREATE TABLE IF NOT EXISTS vehicles (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
brand TEXT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
year INTEGER NOT NULL,
|
||||
plate TEXT UNIQUE NOT NULL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)`
|
||||
);
|
||||
|
||||
await run(
|
||||
`CREATE TABLE IF NOT EXISTS units (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
stk TEXT NOT NULL,
|
||||
btk TEXT NOT NULL,
|
||||
contact_name TEXT NOT NULL,
|
||||
contact_rank TEXT NOT NULL,
|
||||
contact_registry TEXT NOT NULL,
|
||||
contact_identity TEXT NOT NULL,
|
||||
contact_phone TEXT NOT NULL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)`
|
||||
);
|
||||
|
||||
await run(
|
||||
`CREATE TABLE IF NOT EXISTS fuel_personnel (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
full_name TEXT NOT NULL,
|
||||
rank TEXT NOT NULL,
|
||||
registry_number TEXT UNIQUE NOT NULL,
|
||||
identity_number TEXT NOT NULL,
|
||||
phone TEXT NOT NULL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)`
|
||||
);
|
||||
|
||||
await run(
|
||||
`CREATE TABLE IF NOT EXISTS fuel_slips (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
slip_number INTEGER UNIQUE,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
slip_date TEXT NOT NULL,
|
||||
force TEXT NOT NULL,
|
||||
unit_id INTEGER NOT NULL,
|
||||
unit_name TEXT NOT NULL,
|
||||
vehicle_id INTEGER NOT NULL,
|
||||
vehicle_description TEXT NOT NULL,
|
||||
plate TEXT NOT NULL,
|
||||
fuel_amount_number REAL NOT NULL,
|
||||
fuel_amount_text TEXT NOT NULL,
|
||||
fuel_type TEXT NOT NULL,
|
||||
receiver_id INTEGER NOT NULL,
|
||||
receiver_name TEXT NOT NULL,
|
||||
receiver_rank TEXT NOT NULL,
|
||||
receiver_registry TEXT NOT NULL,
|
||||
receiver_phone TEXT NOT NULL,
|
||||
giver_id INTEGER NOT NULL,
|
||||
giver_name TEXT NOT NULL,
|
||||
giver_rank TEXT NOT NULL,
|
||||
giver_registry TEXT NOT NULL,
|
||||
giver_phone TEXT NOT NULL,
|
||||
notes TEXT,
|
||||
inventory_manager_id INTEGER NOT NULL,
|
||||
fuel_manager_id INTEGER NOT NULL,
|
||||
status TEXT DEFAULT 'pending',
|
||||
rejection_reason TEXT,
|
||||
FOREIGN KEY (unit_id) REFERENCES units(id),
|
||||
FOREIGN KEY (vehicle_id) REFERENCES vehicles(id),
|
||||
FOREIGN KEY (receiver_id) REFERENCES fuel_personnel(id),
|
||||
FOREIGN KEY (giver_id) REFERENCES fuel_personnel(id),
|
||||
FOREIGN KEY (inventory_manager_id) REFERENCES users(id),
|
||||
FOREIGN KEY (fuel_manager_id) REFERENCES users(id)
|
||||
)`
|
||||
);
|
||||
|
||||
await Promise.all([
|
||||
ensureColumn('fuel_slips', 'inventory_manager_id', 'INTEGER'),
|
||||
ensureColumn('fuel_slips', 'fuel_manager_id', 'INTEGER'),
|
||||
ensureColumn('fuel_slips', 'status', "TEXT DEFAULT 'pending'"),
|
||||
ensureColumn('fuel_slips', 'rejection_reason', 'TEXT')
|
||||
]).catch((err) => {
|
||||
// Ignored if columns already exist
|
||||
if (err && !/duplicate column/i.test(err.message)) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
for (const user of SAMPLE_USERS) {
|
||||
await run(
|
||||
`INSERT OR IGNORE INTO users (username, password, role, display_name)
|
||||
VALUES (?, ?, ?, ?)`,
|
||||
[user.username, user.password, user.role, user.displayName]
|
||||
);
|
||||
}
|
||||
|
||||
for (const vehicle of SAMPLE_VEHICLES) {
|
||||
await run(
|
||||
`INSERT OR IGNORE INTO vehicles (brand, model, year, plate)
|
||||
VALUES (?, ?, ?, ?)`,
|
||||
[vehicle.brand, vehicle.model, vehicle.year, vehicle.plate]
|
||||
);
|
||||
}
|
||||
|
||||
for (const unit of SAMPLE_UNITS) {
|
||||
await run(
|
||||
`INSERT OR IGNORE INTO units (
|
||||
name, address, stk, btk, contact_name, contact_rank,
|
||||
contact_registry, contact_identity, contact_phone
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
unit.name,
|
||||
unit.address,
|
||||
unit.stk,
|
||||
unit.btk,
|
||||
unit.contactName,
|
||||
unit.contactRank,
|
||||
unit.contactRegistry,
|
||||
unit.contactIdentity,
|
||||
unit.contactPhone
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
for (const personnel of SAMPLE_FUEL_PERSONNEL) {
|
||||
await run(
|
||||
`INSERT OR IGNORE INTO fuel_personnel (
|
||||
full_name, rank, registry_number, identity_number, phone
|
||||
) VALUES (?, ?, ?, ?, ?)`,
|
||||
[
|
||||
personnel.fullName,
|
||||
personnel.rank,
|
||||
personnel.registryNumber,
|
||||
personnel.identityNumber,
|
||||
personnel.phone
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
resolve();
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getUserByUsername(username) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get(
|
||||
`SELECT id, username, password, role, display_name AS displayName
|
||||
FROM users
|
||||
WHERE username = ?`,
|
||||
[username],
|
||||
(err, row) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(row);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function createInventoryManager({ username, password, displayName }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
`INSERT INTO users (username, password, role, display_name)
|
||||
VALUES (?, ?, 'inventory_manager', ?)`,
|
||||
[username, password, displayName],
|
||||
function insertCallback(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
id: this.lastID,
|
||||
username,
|
||||
displayName,
|
||||
role: 'inventory_manager'
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function listInventoryManagers() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(
|
||||
`SELECT id, username, display_name AS displayName, created_at AS createdAt
|
||||
FROM users
|
||||
WHERE role = 'inventory_manager'
|
||||
ORDER BY created_at DESC`,
|
||||
(err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rows);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateInventoryManager({ id, displayName, password }) {
|
||||
const updates = [];
|
||||
const params = [];
|
||||
|
||||
if (displayName) {
|
||||
updates.push('display_name = ?');
|
||||
params.push(displayName);
|
||||
}
|
||||
|
||||
if (password) {
|
||||
updates.push('password = ?');
|
||||
params.push(password);
|
||||
}
|
||||
|
||||
if (updates.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
params.push(id);
|
||||
|
||||
return run(
|
||||
`UPDATE users SET ${updates.join(', ')} WHERE id = ? AND role = 'inventory_manager'`,
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
function deleteInventoryManager(id) {
|
||||
return run(`DELETE FROM users WHERE id = ? AND role = 'inventory_manager'`, [id]);
|
||||
}
|
||||
|
||||
function createVehicle({ brand, model, year, plate }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
`INSERT INTO vehicles (brand, model, year, plate)
|
||||
VALUES (?, ?, ?, ?)`,
|
||||
[brand, model, year, plate],
|
||||
function insertCallback(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
id: this.lastID,
|
||||
brand,
|
||||
model,
|
||||
year,
|
||||
plate
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function listVehicles() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(
|
||||
`SELECT id, brand, model, year, plate, created_at AS createdAt
|
||||
FROM vehicles
|
||||
ORDER BY created_at DESC`,
|
||||
(err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rows);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateVehicle({ id, brand, model, year, plate }) {
|
||||
return run(
|
||||
`UPDATE vehicles
|
||||
SET brand = ?, model = ?, year = ?, plate = ?
|
||||
WHERE id = ?`,
|
||||
[brand, model, year, plate, id]
|
||||
);
|
||||
}
|
||||
|
||||
function deleteVehicle(id) {
|
||||
return run(`DELETE FROM vehicles WHERE id = ?`, [id]);
|
||||
}
|
||||
|
||||
function createUnit(payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
`INSERT INTO units (
|
||||
name, address, stk, btk, contact_name, contact_rank,
|
||||
contact_registry, contact_identity, contact_phone
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
payload.name,
|
||||
payload.address,
|
||||
payload.stk,
|
||||
payload.btk,
|
||||
payload.contactName,
|
||||
payload.contactRank,
|
||||
payload.contactRegistry,
|
||||
payload.contactIdentity,
|
||||
payload.contactPhone
|
||||
],
|
||||
function insertCallback(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
id: this.lastID,
|
||||
...payload
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function listUnits() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(
|
||||
`SELECT
|
||||
id,
|
||||
name,
|
||||
address,
|
||||
stk,
|
||||
btk,
|
||||
contact_name AS contactName,
|
||||
contact_rank AS contactRank,
|
||||
contact_registry AS contactRegistry,
|
||||
contact_identity AS contactIdentity,
|
||||
contact_phone AS contactPhone,
|
||||
created_at AS createdAt
|
||||
FROM units
|
||||
ORDER BY created_at DESC`,
|
||||
(err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rows);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateUnit(payload) {
|
||||
return run(
|
||||
`UPDATE units
|
||||
SET name = ?, address = ?, stk = ?, btk = ?, contact_name = ?, contact_rank = ?,
|
||||
contact_registry = ?, contact_identity = ?, contact_phone = ?
|
||||
WHERE id = ?`,
|
||||
[
|
||||
payload.name,
|
||||
payload.address,
|
||||
payload.stk,
|
||||
payload.btk,
|
||||
payload.contactName,
|
||||
payload.contactRank,
|
||||
payload.contactRegistry,
|
||||
payload.contactIdentity,
|
||||
payload.contactPhone,
|
||||
payload.id
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function deleteUnit(id) {
|
||||
return run(`DELETE FROM units WHERE id = ?`, [id]);
|
||||
}
|
||||
|
||||
function createFuelPersonnel(payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
`INSERT INTO fuel_personnel (
|
||||
full_name, rank, registry_number, identity_number, phone
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
[
|
||||
payload.fullName,
|
||||
payload.rank,
|
||||
payload.registryNumber,
|
||||
payload.identityNumber,
|
||||
payload.phone
|
||||
],
|
||||
function insertCallback(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
id: this.lastID,
|
||||
...payload
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function listFuelPersonnel() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(
|
||||
`SELECT
|
||||
id,
|
||||
full_name AS fullName,
|
||||
rank,
|
||||
registry_number AS registryNumber,
|
||||
identity_number AS identityNumber,
|
||||
phone,
|
||||
created_at AS createdAt
|
||||
FROM fuel_personnel
|
||||
ORDER BY created_at DESC`,
|
||||
(err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rows);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateFuelPersonnel(payload) {
|
||||
return run(
|
||||
`UPDATE fuel_personnel
|
||||
SET full_name = ?, rank = ?, registry_number = ?, identity_number = ?, phone = ?
|
||||
WHERE id = ?`,
|
||||
[
|
||||
payload.fullName,
|
||||
payload.rank,
|
||||
payload.registryNumber,
|
||||
payload.identityNumber,
|
||||
payload.phone,
|
||||
payload.id
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function deleteFuelPersonnel(id) {
|
||||
return run(`DELETE FROM fuel_personnel WHERE id = ?`, [id]);
|
||||
}
|
||||
|
||||
function getVehicleById(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get(
|
||||
`SELECT id, brand, model, year, plate, created_at AS createdAt
|
||||
FROM vehicles
|
||||
WHERE id = ?`,
|
||||
[id],
|
||||
(err, row) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(row);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function getUnitById(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get(
|
||||
`SELECT id, name, address, stk, btk, contact_name AS contactName, contact_rank AS contactRank,
|
||||
contact_registry AS contactRegistry, contact_identity AS contactIdentity,
|
||||
contact_phone AS contactPhone
|
||||
FROM units
|
||||
WHERE id = ?`,
|
||||
[id],
|
||||
(err, row) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(row);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function getFuelPersonnelById(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get(
|
||||
`SELECT id, full_name AS fullName, rank, registry_number AS registryNumber,
|
||||
identity_number AS identityNumber, phone
|
||||
FROM fuel_personnel
|
||||
WHERE id = ?`,
|
||||
[id],
|
||||
(err, row) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(row);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function getInventoryManagerById(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get(
|
||||
`SELECT id, username, display_name AS displayName
|
||||
FROM users
|
||||
WHERE id = ? AND role = 'inventory_manager'`,
|
||||
[id],
|
||||
(err, row) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(row);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function createFuelSlip(payload) {
|
||||
const nextNumber = await new Promise((resolve, reject) => {
|
||||
db.get(`SELECT IFNULL(MAX(slip_number), 0) + 1 AS nextNumber FROM fuel_slips`, [], (err, row) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(row ? row.nextNumber : 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
`INSERT INTO fuel_slips (
|
||||
slip_number,
|
||||
slip_date,
|
||||
force,
|
||||
unit_id,
|
||||
unit_name,
|
||||
vehicle_id,
|
||||
vehicle_description,
|
||||
plate,
|
||||
fuel_amount_number,
|
||||
fuel_amount_text,
|
||||
fuel_type,
|
||||
receiver_id,
|
||||
receiver_name,
|
||||
receiver_rank,
|
||||
receiver_registry,
|
||||
receiver_phone,
|
||||
giver_id,
|
||||
giver_name,
|
||||
giver_rank,
|
||||
giver_registry,
|
||||
giver_phone,
|
||||
notes,
|
||||
inventory_manager_id,
|
||||
fuel_manager_id,
|
||||
status,
|
||||
rejection_reason
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ,
|
||||
[
|
||||
nextNumber,
|
||||
payload.date,
|
||||
payload.force,
|
||||
payload.unit.id,
|
||||
payload.unit.name,
|
||||
payload.vehicle.id,
|
||||
payload.vehicle.description,
|
||||
payload.vehicle.plate,
|
||||
payload.fuelAmountNumber,
|
||||
payload.fuelAmountText,
|
||||
payload.fuelType,
|
||||
payload.receiver.id,
|
||||
payload.receiver.fullName,
|
||||
payload.receiver.rank,
|
||||
payload.receiver.registryNumber,
|
||||
payload.receiver.phone,
|
||||
payload.giver.id,
|
||||
payload.giver.fullName,
|
||||
payload.giver.rank,
|
||||
payload.giver.registryNumber,
|
||||
payload.giver.phone,
|
||||
payload.notes || null,
|
||||
payload.inventoryManager.id,
|
||||
payload.fuelManagerId,
|
||||
'pending',
|
||||
null
|
||||
],
|
||||
function insertCallback(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve({ id: this.lastID, slipNumber: nextNumber });
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function listFuelSlips() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(
|
||||
`SELECT
|
||||
fs.id,
|
||||
fs.slip_number AS slipNumber,
|
||||
fs.created_at AS createdAt,
|
||||
fs.slip_date AS slipDate,
|
||||
fs.force,
|
||||
fs.unit_id AS unitId,
|
||||
fs.unit_name AS unitName,
|
||||
fs.vehicle_id AS vehicleId,
|
||||
fs.vehicle_description AS vehicleDescription,
|
||||
fs.plate,
|
||||
fs.fuel_amount_number AS fuelAmountNumber,
|
||||
fs.fuel_amount_text AS fuelAmountText,
|
||||
fs.fuel_type AS fuelType,
|
||||
fs.receiver_id AS receiverId,
|
||||
fs.receiver_name AS receiverName,
|
||||
fs.receiver_rank AS receiverRank,
|
||||
fs.receiver_registry AS receiverRegistry,
|
||||
fs.receiver_phone AS receiverPhone,
|
||||
fs.giver_id AS giverId,
|
||||
fs.giver_name AS giverName,
|
||||
fs.giver_rank AS giverRank,
|
||||
fs.giver_registry AS giverRegistry,
|
||||
fs.giver_phone AS giverPhone,
|
||||
fs.notes,
|
||||
fs.inventory_manager_id AS inventoryManagerId,
|
||||
inv.display_name AS inventoryManagerName,
|
||||
fs.fuel_manager_id AS fuelManagerId,
|
||||
fs.status,
|
||||
fs.rejection_reason AS rejectionReason
|
||||
FROM fuel_slips fs
|
||||
LEFT JOIN users inv ON inv.id = fs.inventory_manager_id
|
||||
ORDER BY fs.created_at DESC`,
|
||||
(err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rows);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function listFuelSlipsByInventoryManager(inventoryManagerId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all(
|
||||
`SELECT
|
||||
fs.id,
|
||||
fs.slip_number AS slipNumber,
|
||||
fs.created_at AS createdAt,
|
||||
fs.slip_date AS slipDate,
|
||||
fs.force,
|
||||
fs.unit_id AS unitId,
|
||||
fs.unit_name AS unitName,
|
||||
fs.vehicle_id AS vehicleId,
|
||||
fs.vehicle_description AS vehicleDescription,
|
||||
fs.plate,
|
||||
fs.fuel_amount_number AS fuelAmountNumber,
|
||||
fs.fuel_amount_text AS fuelAmountText,
|
||||
fs.fuel_type AS fuelType,
|
||||
fs.receiver_id AS receiverId,
|
||||
fs.receiver_name AS receiverName,
|
||||
fs.receiver_rank AS receiverRank,
|
||||
fs.receiver_registry AS receiverRegistry,
|
||||
fs.receiver_phone AS receiverPhone,
|
||||
fs.giver_id AS giverId,
|
||||
fs.giver_name AS giverName,
|
||||
fs.giver_rank AS giverRank,
|
||||
fs.giver_registry AS giverRegistry,
|
||||
fs.giver_phone AS giverPhone,
|
||||
fs.notes,
|
||||
fs.inventory_manager_id AS inventoryManagerId,
|
||||
inv.display_name AS inventoryManagerName,
|
||||
fs.fuel_manager_id AS fuelManagerId,
|
||||
fs.status,
|
||||
fs.rejection_reason AS rejectionReason
|
||||
FROM fuel_slips fs
|
||||
LEFT JOIN users inv ON inv.id = fs.inventory_manager_id
|
||||
WHERE fs.inventory_manager_id = ?
|
||||
ORDER BY fs.created_at DESC`,
|
||||
[inventoryManagerId],
|
||||
(err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(rows);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function getFuelSlipById(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get(
|
||||
`SELECT
|
||||
fs.id,
|
||||
fs.slip_number AS slipNumber,
|
||||
fs.created_at AS createdAt,
|
||||
fs.slip_date AS slipDate,
|
||||
fs.force,
|
||||
fs.unit_id AS unitId,
|
||||
fs.unit_name AS unitName,
|
||||
fs.vehicle_id AS vehicleId,
|
||||
fs.vehicle_description AS vehicleDescription,
|
||||
fs.plate,
|
||||
fs.fuel_amount_number AS fuelAmountNumber,
|
||||
fs.fuel_amount_text AS fuelAmountText,
|
||||
fs.fuel_type AS fuelType,
|
||||
fs.receiver_id AS receiverId,
|
||||
fs.receiver_name AS receiverName,
|
||||
fs.receiver_rank AS receiverRank,
|
||||
fs.receiver_registry AS receiverRegistry,
|
||||
fs.receiver_phone AS receiverPhone,
|
||||
fs.giver_id AS giverId,
|
||||
fs.giver_name AS giverName,
|
||||
fs.giver_rank AS giverRank,
|
||||
fs.giver_registry AS giverRegistry,
|
||||
fs.giver_phone AS giverPhone,
|
||||
fs.notes,
|
||||
fs.inventory_manager_id AS inventoryManagerId,
|
||||
inv.display_name AS inventoryManagerName,
|
||||
fs.fuel_manager_id AS fuelManagerId,
|
||||
fs.status,
|
||||
fs.rejection_reason AS rejectionReason
|
||||
FROM fuel_slips fs
|
||||
LEFT JOIN users inv ON inv.id = fs.inventory_manager_id
|
||||
WHERE fs.id = ?`,
|
||||
[id],
|
||||
(err, row) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(row);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateFuelSlipStatus({ id, status, rejectionReason }) {
|
||||
return run(
|
||||
`UPDATE fuel_slips
|
||||
SET status = ?, rejection_reason = ?
|
||||
WHERE id = ?`,
|
||||
[status, rejectionReason || null, id]
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
db,
|
||||
initialize,
|
||||
getUserByUsername,
|
||||
createInventoryManager,
|
||||
listInventoryManagers,
|
||||
updateInventoryManager,
|
||||
deleteInventoryManager,
|
||||
createVehicle,
|
||||
listVehicles,
|
||||
updateVehicle,
|
||||
deleteVehicle,
|
||||
createUnit,
|
||||
listUnits,
|
||||
updateUnit,
|
||||
deleteUnit,
|
||||
createFuelPersonnel,
|
||||
listFuelPersonnel,
|
||||
updateFuelPersonnel,
|
||||
deleteFuelPersonnel,
|
||||
getVehicleById,
|
||||
getUnitById,
|
||||
getFuelPersonnelById,
|
||||
getInventoryManagerById,
|
||||
createFuelSlip,
|
||||
listFuelSlips,
|
||||
listFuelSlipsByInventoryManager,
|
||||
getFuelSlipById,
|
||||
updateFuelSlipStatus
|
||||
};
|
||||
835
server/index.js
Normal file
835
server/index.js
Normal file
@@ -0,0 +1,835 @@
|
||||
const http = require('http');
|
||||
const crypto = require('crypto');
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const { Server } = require('socket.io');
|
||||
|
||||
const {
|
||||
db,
|
||||
initialize,
|
||||
getUserByUsername,
|
||||
createInventoryManager,
|
||||
listInventoryManagers,
|
||||
updateInventoryManager,
|
||||
deleteInventoryManager,
|
||||
createVehicle,
|
||||
listVehicles,
|
||||
updateVehicle,
|
||||
deleteVehicle,
|
||||
createUnit,
|
||||
listUnits,
|
||||
updateUnit,
|
||||
deleteUnit,
|
||||
createFuelPersonnel,
|
||||
listFuelPersonnel,
|
||||
updateFuelPersonnel,
|
||||
deleteFuelPersonnel,
|
||||
getVehicleById,
|
||||
getUnitById,
|
||||
getFuelPersonnelById,
|
||||
getInventoryManagerById,
|
||||
createFuelSlip,
|
||||
listFuelSlips,
|
||||
listFuelSlipsByInventoryManager,
|
||||
getFuelSlipById,
|
||||
updateFuelSlipStatus
|
||||
} = require('./db');
|
||||
|
||||
const PDFDocument = require('pdfkit');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 5005;
|
||||
const sessions = new Map();
|
||||
|
||||
const httpServer = http.createServer(app);
|
||||
const io = new Server(httpServer, {
|
||||
cors: {
|
||||
origin: '*'
|
||||
}
|
||||
});
|
||||
|
||||
const FUEL_FORCES = ['MSB', 'K.K.K.', 'Dz.K.K.', 'Hv.K.K.', 'SGK', 'Gnkur. Bşk.', 'Hrt.Gn.K.'];
|
||||
|
||||
const fuelManagerSockets = new Map();
|
||||
const inventoryManagerSockets = new Map();
|
||||
|
||||
function addSocket(map, key, socket) {
|
||||
if (!map.has(key)) {
|
||||
map.set(key, new Set());
|
||||
}
|
||||
map.get(key).add(socket);
|
||||
}
|
||||
|
||||
function removeSocket(map, key, socket) {
|
||||
const set = map.get(key);
|
||||
if (!set) {
|
||||
return;
|
||||
}
|
||||
set.delete(socket);
|
||||
if (set.size === 0) {
|
||||
map.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
function emitToInventoryManager(id, event, payload) {
|
||||
const set = inventoryManagerSockets.get(id);
|
||||
if (!set) {
|
||||
return;
|
||||
}
|
||||
for (const socket of set) {
|
||||
socket.emit(event, payload);
|
||||
}
|
||||
}
|
||||
|
||||
function emitToFuelManager(id, event, payload) {
|
||||
const set = fuelManagerSockets.get(id);
|
||||
if (!set) {
|
||||
return;
|
||||
}
|
||||
for (const socket of set) {
|
||||
socket.emit(event, payload);
|
||||
}
|
||||
}
|
||||
|
||||
io.use((socket, next) => {
|
||||
const token = socket.handshake.auth?.token || socket.handshake.query?.token;
|
||||
|
||||
if (!token || !sessions.has(token)) {
|
||||
return next(new Error('Oturum bulunamadı.'));
|
||||
}
|
||||
|
||||
socket.sessionToken = token;
|
||||
socket.user = sessions.get(token);
|
||||
return next();
|
||||
});
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
const { user } = socket;
|
||||
|
||||
if (user.role === 'fuel_manager') {
|
||||
addSocket(fuelManagerSockets, user.id, socket);
|
||||
} else if (user.role === 'inventory_manager') {
|
||||
addSocket(inventoryManagerSockets, user.id, socket);
|
||||
}
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
if (user.role === 'fuel_manager') {
|
||||
removeSocket(fuelManagerSockets, user.id, socket);
|
||||
} else if (user.role === 'inventory_manager') {
|
||||
removeSocket(inventoryManagerSockets, user.id, socket);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
function createSession(user) {
|
||||
const token = crypto.randomBytes(24).toString('hex');
|
||||
const session = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
displayName: user.displayName
|
||||
};
|
||||
sessions.set(token, session);
|
||||
return { token, session };
|
||||
}
|
||||
|
||||
function requireSession(req, res, next) {
|
||||
const token = req.header('x-session-token');
|
||||
|
||||
if (!token || !sessions.has(token)) {
|
||||
return res.status(401).json({ message: 'Oturum bulunamadi.' });
|
||||
}
|
||||
|
||||
req.session = sessions.get(token);
|
||||
req.sessionToken = token;
|
||||
return next();
|
||||
}
|
||||
|
||||
function requireAdmin(req, res, next) {
|
||||
if (req.session.role !== 'admin') {
|
||||
return res.status(403).json({ message: 'Bu islem icin yetki yok.' });
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
function requireFuelManager(req, res, next) {
|
||||
if (req.session.role !== 'fuel_manager') {
|
||||
return res.status(403).json({ message: 'Bu islem icin yetki yok.' });
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
function requireInventoryManager(req, res, next) {
|
||||
if (req.session.role !== 'inventory_manager') {
|
||||
return res.status(403).json({ message: 'Bu islem icin yetki yok.' });
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
app.post('/api/auth/login', async (req, res) => {
|
||||
const { username, password } = req.body || {};
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ message: 'Kullanici adi ve sifre zorunlu.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await getUserByUsername(username);
|
||||
|
||||
if (!user || user.password !== password) {
|
||||
return res.status(401).json({ message: 'Kullanici adi veya sifre hatali.' });
|
||||
}
|
||||
|
||||
const { token, session } = createSession(user);
|
||||
|
||||
return res.json({
|
||||
token,
|
||||
user: session
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Login hatasi:', err);
|
||||
return res.status(500).json({ message: 'Beklenmeyen bir sorun olustu.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/auth/logout', requireSession, (req, res) => {
|
||||
sessions.delete(req.sessionToken);
|
||||
return res.json({ message: 'Oturum kapatildi.' });
|
||||
});
|
||||
|
||||
app.get('/api/session', requireSession, (req, res) => {
|
||||
return res.json({
|
||||
user: req.session
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/inventory-managers', requireSession, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const managers = await listInventoryManagers();
|
||||
return res.json({ managers });
|
||||
} catch (err) {
|
||||
console.error('Listeleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Mal sorumlulari okunamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/inventory-managers', requireSession, requireAdmin, async (req, res) => {
|
||||
const { username, password, displayName } = req.body || {};
|
||||
|
||||
if (!username || !password || !displayName) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: 'Kullanici adi, sifre ve gorunen ad zorunlu alanlardir.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const created = await createInventoryManager({ username, password, displayName });
|
||||
return res.status(201).json({ manager: created });
|
||||
} catch (err) {
|
||||
if (err && err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.status(409).json({ message: 'Bu kullanici adi zaten mevcut.' });
|
||||
}
|
||||
|
||||
console.error('Ekleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Mal sorumlusu eklenemedi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/inventory-managers/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { displayName, password } = req.body || {};
|
||||
|
||||
if (!displayName && !password) {
|
||||
return res.status(400).json({ message: 'Guncelleme icin en az bir alan girilmeli.' });
|
||||
}
|
||||
|
||||
try {
|
||||
await updateInventoryManager({ id, displayName, password });
|
||||
return res.json({ message: 'Kayit guncellendi.' });
|
||||
} catch (err) {
|
||||
console.error('Mal sorumlusu guncelleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Guncelleme yapilamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/inventory-managers/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await deleteInventoryManager(id);
|
||||
return res.status(204).end();
|
||||
} catch (err) {
|
||||
console.error('Mal sorumlusu silme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Silme islemi tamamlanamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/vehicles', requireSession, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const vehicles = await listVehicles();
|
||||
return res.json({ vehicles });
|
||||
} catch (err) {
|
||||
console.error('Arac listeleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Araçlar okunamadı.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/vehicles', requireSession, requireAdmin, async (req, res) => {
|
||||
const { brand, model, year, plate } = req.body || {};
|
||||
|
||||
if (!brand || !model || !year || !plate) {
|
||||
return res.status(400).json({ message: 'Marka, model, yıl ve plaka zorunludur.' });
|
||||
}
|
||||
|
||||
const parsedYear = Number(year);
|
||||
|
||||
if (!Number.isInteger(parsedYear) || parsedYear < 1990 || parsedYear > new Date().getFullYear() + 1) {
|
||||
return res.status(400).json({ message: 'Lütfen geçerli bir model yılı girin.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const vehicle = await createVehicle({
|
||||
brand,
|
||||
model,
|
||||
year: parsedYear,
|
||||
plate: plate.trim().toUpperCase()
|
||||
});
|
||||
return res.status(201).json({ vehicle });
|
||||
} catch (err) {
|
||||
if (err && err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.status(409).json({ message: 'Bu plaka ile kayıt zaten mevcut.' });
|
||||
}
|
||||
|
||||
console.error('Arac ekleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Araç kaydedilemedi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/vehicles/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { brand, model, year, plate } = req.body || {};
|
||||
|
||||
if (!brand || !model || !year || !plate) {
|
||||
return res.status(400).json({ message: 'Tum alanlar zorunlusudur.' });
|
||||
}
|
||||
|
||||
const parsedYear = Number(year);
|
||||
if (!Number.isInteger(parsedYear) || parsedYear < 1990 || parsedYear > new Date().getFullYear() + 1) {
|
||||
return res.status(400).json({ message: 'Gecerli bir model yılı girin.' });
|
||||
}
|
||||
|
||||
try {
|
||||
await updateVehicle({ id, brand, model, year: parsedYear, plate: plate.trim().toUpperCase() });
|
||||
return res.json({ message: 'Araç kaydı güncellendi.' });
|
||||
} catch (err) {
|
||||
if (err && err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.status(409).json({ message: 'Bu plaka ile kayıt mevcut.' });
|
||||
}
|
||||
|
||||
console.error('Arac guncelleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Guncelleme yapilamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/vehicles/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await deleteVehicle(id);
|
||||
return res.status(204).end();
|
||||
} catch (err) {
|
||||
console.error('Arac silme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Silme islemi tamamlanamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/units', requireSession, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const units = await listUnits();
|
||||
return res.json({ units });
|
||||
} catch (err) {
|
||||
console.error('Birlik listeleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Birlikler okunamadı.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/units', requireSession, requireAdmin, async (req, res) => {
|
||||
const {
|
||||
name,
|
||||
address,
|
||||
stk,
|
||||
btk,
|
||||
contactName,
|
||||
contactRank,
|
||||
contactRegistry,
|
||||
contactIdentity,
|
||||
contactPhone
|
||||
} = req.body || {};
|
||||
|
||||
if (
|
||||
!name ||
|
||||
!address ||
|
||||
!stk ||
|
||||
!btk ||
|
||||
!contactName ||
|
||||
!contactRank ||
|
||||
!contactRegistry ||
|
||||
!contactIdentity ||
|
||||
!contactPhone
|
||||
) {
|
||||
return res.status(400).json({ message: 'Birlik ve sorumlu bilgileri eksiksiz girilmeli.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const unit = await createUnit({
|
||||
name,
|
||||
address,
|
||||
stk,
|
||||
btk,
|
||||
contactName,
|
||||
contactRank,
|
||||
contactRegistry,
|
||||
contactIdentity,
|
||||
contactPhone
|
||||
});
|
||||
return res.status(201).json({ unit });
|
||||
} catch (err) {
|
||||
if (err && err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.status(409).json({ message: 'Bu birlik adı ile kayıt mevcut.' });
|
||||
}
|
||||
|
||||
console.error('Birlik ekleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Birlik kaydedilemedi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/units/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
name,
|
||||
address,
|
||||
stk,
|
||||
btk,
|
||||
contactName,
|
||||
contactRank,
|
||||
contactRegistry,
|
||||
contactIdentity,
|
||||
contactPhone
|
||||
} = req.body || {};
|
||||
|
||||
if (
|
||||
!name ||
|
||||
!address ||
|
||||
!stk ||
|
||||
!btk ||
|
||||
!contactName ||
|
||||
!contactRank ||
|
||||
!contactRegistry ||
|
||||
!contactIdentity ||
|
||||
!contactPhone
|
||||
) {
|
||||
return res.status(400).json({ message: 'Tum alanlar zorunludur.' });
|
||||
}
|
||||
|
||||
try {
|
||||
await updateUnit({
|
||||
id,
|
||||
name,
|
||||
address,
|
||||
stk,
|
||||
btk,
|
||||
contactName,
|
||||
contactRank,
|
||||
contactRegistry,
|
||||
contactIdentity,
|
||||
contactPhone
|
||||
});
|
||||
return res.json({ message: 'Birlik kaydı güncellendi.' });
|
||||
} catch (err) {
|
||||
if (err && err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.status(409).json({ message: 'Bu birlik adı ile kayıt mevcut.' });
|
||||
}
|
||||
|
||||
console.error('Birlik guncelleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Birlik güncellenemedi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/units/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await deleteUnit(id);
|
||||
return res.status(204).end();
|
||||
} catch (err) {
|
||||
console.error('Birlik silme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Silme islemi tamamlanamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/fuel-personnel', requireSession, requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const personnel = await listFuelPersonnel();
|
||||
return res.json({ personnel });
|
||||
} catch (err) {
|
||||
console.error('Personel listeleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Yakıt personeli okunamadı.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/fuel-personnel', requireSession, requireAdmin, async (req, res) => {
|
||||
const { fullName, rank, registryNumber, identityNumber, phone } = req.body || {};
|
||||
|
||||
if (!fullName || !rank || !registryNumber || !identityNumber || !phone) {
|
||||
return res.status(400).json({ message: 'Personel bilgileri eksiksiz girilmeli.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const created = await createFuelPersonnel({
|
||||
fullName,
|
||||
rank,
|
||||
registryNumber,
|
||||
identityNumber,
|
||||
phone
|
||||
});
|
||||
return res.status(201).json({ personnel: created });
|
||||
} catch (err) {
|
||||
if (err && err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.status(409).json({ message: 'Bu sicil numarası ile kayıt mevcut.' });
|
||||
}
|
||||
|
||||
console.error('Personel ekleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Personel kaydedilemedi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/fuel-personnel/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { fullName, rank, registryNumber, identityNumber, phone } = req.body || {};
|
||||
|
||||
if (!fullName || !rank || !registryNumber || !identityNumber || !phone) {
|
||||
return res.status(400).json({ message: 'Tum alanlar zorunludur.' });
|
||||
}
|
||||
|
||||
try {
|
||||
await updateFuelPersonnel({
|
||||
id,
|
||||
fullName,
|
||||
rank,
|
||||
registryNumber,
|
||||
identityNumber,
|
||||
phone
|
||||
});
|
||||
return res.json({ message: 'Personel kaydı güncellendi.' });
|
||||
} catch (err) {
|
||||
if (err && err.code === 'SQLITE_CONSTRAINT') {
|
||||
return res.status(409).json({ message: 'Bu sicil numarası ile kayıt mevcut.' });
|
||||
}
|
||||
|
||||
console.error('Personel guncelleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Guncelleme yapilamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/fuel-personnel/:id', requireSession, requireAdmin, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await deleteFuelPersonnel(id);
|
||||
return res.status(204).end();
|
||||
} catch (err) {
|
||||
console.error('Personel silme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Silme islemi tamamlanamadi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/fuel/resources', requireSession, requireFuelManager, async (req, res) => {
|
||||
try {
|
||||
const [vehicles, units, personnel, inventoryManagers] = await Promise.all([
|
||||
listVehicles(),
|
||||
listUnits(),
|
||||
listFuelPersonnel(),
|
||||
listInventoryManagers()
|
||||
]);
|
||||
|
||||
return res.json({
|
||||
forces: FUEL_FORCES,
|
||||
vehicles,
|
||||
units,
|
||||
personnel,
|
||||
inventoryManagers
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Kaynaklar okunamadi:', err);
|
||||
return res.status(500).json({ message: 'Referans verileri yüklenemedi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/fuel-slips', requireSession, requireFuelManager, async (req, res) => {
|
||||
try {
|
||||
const slips = await listFuelSlips();
|
||||
return res.json({ slips });
|
||||
} catch (err) {
|
||||
console.error('Fisi listeleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Fişler okunamadı.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/fuel-slips/assigned', requireSession, requireInventoryManager, async (req, res) => {
|
||||
try {
|
||||
const slips = await listFuelSlipsByInventoryManager(req.session.id);
|
||||
return res.json({ slips });
|
||||
} catch (err) {
|
||||
console.error('Atanan fişleri listeleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Fişler okunamadı.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/fuel-slips', requireSession, requireFuelManager, async (req, res) => {
|
||||
const {
|
||||
date,
|
||||
force,
|
||||
unitId,
|
||||
vehicleId,
|
||||
fuelAmountNumber,
|
||||
fuelAmountText,
|
||||
fuelType,
|
||||
receiverId,
|
||||
giverId,
|
||||
receiverPhone,
|
||||
giverPhone,
|
||||
notes,
|
||||
inventoryManagerId
|
||||
} = req.body || {};
|
||||
|
||||
if (
|
||||
!date ||
|
||||
!force ||
|
||||
!unitId ||
|
||||
!vehicleId ||
|
||||
!fuelAmountNumber ||
|
||||
!fuelAmountText ||
|
||||
!fuelType ||
|
||||
!receiverId ||
|
||||
!giverId ||
|
||||
!inventoryManagerId
|
||||
) {
|
||||
return res.status(400).json({ message: 'Fiş oluşturmak için zorunlu alanları doldurun.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const [unit, vehicle, receiver, giver, inventoryManager] = await Promise.all([
|
||||
getUnitById(unitId),
|
||||
getVehicleById(vehicleId),
|
||||
getFuelPersonnelById(receiverId),
|
||||
getFuelPersonnelById(giverId),
|
||||
getInventoryManagerById(inventoryManagerId)
|
||||
]);
|
||||
|
||||
if (!unit || !vehicle || !receiver || !giver || !inventoryManager) {
|
||||
return res.status(404).json({ message: 'Referans kaydı bulunamadı.' });
|
||||
}
|
||||
|
||||
const payload = {
|
||||
date,
|
||||
force,
|
||||
unit: { id: unit.id, name: unit.name },
|
||||
vehicle: {
|
||||
id: vehicle.id,
|
||||
description: `${vehicle.brand} ${vehicle.model}`.trim(),
|
||||
plate: vehicle.plate
|
||||
},
|
||||
fuelAmountNumber: Number(fuelAmountNumber),
|
||||
fuelAmountText,
|
||||
fuelType,
|
||||
receiver: {
|
||||
id: receiver.id,
|
||||
fullName: receiver.fullName,
|
||||
rank: receiver.rank,
|
||||
registryNumber: receiver.registryNumber,
|
||||
phone: receiverPhone || receiver.phone
|
||||
},
|
||||
giver: {
|
||||
id: giver.id,
|
||||
fullName: giver.fullName,
|
||||
rank: giver.rank,
|
||||
registryNumber: giver.registryNumber,
|
||||
phone: giverPhone || giver.phone
|
||||
},
|
||||
inventoryManager: {
|
||||
id: inventoryManager.id,
|
||||
displayName: inventoryManager.displayName
|
||||
},
|
||||
fuelManagerId: req.session.id,
|
||||
notes: notes || null
|
||||
};
|
||||
|
||||
const created = await createFuelSlip(payload);
|
||||
const slip = await getFuelSlipById(created.id);
|
||||
|
||||
emitToInventoryManager(slip.inventoryManagerId, 'fuelSlip:new', slip);
|
||||
emitToFuelManager(req.session.id, 'fuelSlip:status', slip);
|
||||
|
||||
return res.status(201).json({ slip });
|
||||
} catch (err) {
|
||||
console.error('Fiş olusturma hatasi:', err);
|
||||
return res.status(500).json({ message: 'Fiş olusturulamadı.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.patch('/api/fuel-slips/:id/status', requireSession, requireInventoryManager, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { status, reason } = req.body || {};
|
||||
|
||||
if (!['approved', 'rejected'].includes(status)) {
|
||||
return res.status(400).json({ message: 'Geçersiz durum değeri.' });
|
||||
}
|
||||
|
||||
if (status === 'rejected' && (!reason || !reason.trim())) {
|
||||
return res.status(400).json({ message: 'Red gerekçesi girilmeli.' });
|
||||
}
|
||||
|
||||
try {
|
||||
const slip = await getFuelSlipById(id);
|
||||
|
||||
if (!slip) {
|
||||
return res.status(404).json({ message: 'Fiş bulunamadı.' });
|
||||
}
|
||||
|
||||
if (slip.inventoryManagerId !== req.session.id) {
|
||||
return res.status(403).json({ message: 'Bu fiş size atanmamış.' });
|
||||
}
|
||||
|
||||
if (slip.status !== 'pending') {
|
||||
return res.status(409).json({ message: 'Fiş durumu zaten güncellenmiş.' });
|
||||
}
|
||||
|
||||
const trimmedReason = status === 'rejected' ? reason.trim() : null;
|
||||
|
||||
await updateFuelSlipStatus({ id, status, rejectionReason: trimmedReason });
|
||||
const updated = await getFuelSlipById(id);
|
||||
|
||||
emitToFuelManager(updated.fuelManagerId, 'fuelSlip:status', updated);
|
||||
emitToInventoryManager(updated.inventoryManagerId, 'fuelSlip:status', updated);
|
||||
|
||||
return res.json({ slip: updated });
|
||||
} catch (err) {
|
||||
console.error('Fiş durum güncelleme hatasi:', err);
|
||||
return res.status(500).json({ message: 'Durum güncellenemedi.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/fuel-slips/:id/pdf', requireSession, requireFuelManager, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const slip = await getFuelSlipById(id);
|
||||
if (!slip) {
|
||||
return res.status(404).json({ message: 'Fiş bulunamadı.' });
|
||||
}
|
||||
|
||||
res.setHeader('Content-Type', 'application/pdf');
|
||||
res.setHeader('Content-Disposition', `inline; filename=akaryakit-senedi-${slip.slipNumber}.pdf`);
|
||||
|
||||
const doc = new PDFDocument({ size: 'A4', margin: 36 });
|
||||
doc.pipe(res);
|
||||
|
||||
const title = 'TSK AKARYAKIT İKMAL SENEDİ';
|
||||
doc.fontSize(18).text(title, { align: 'center', underline: true });
|
||||
doc.moveDown(0.4);
|
||||
doc.fontSize(11).text(`Seri No: ${slip.slipNumber}`, { align: 'center' });
|
||||
doc.moveDown(0.6);
|
||||
|
||||
const startX = doc.page.margins.left;
|
||||
let y = doc.y;
|
||||
const tableWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right;
|
||||
const rowHeight = 28;
|
||||
|
||||
const drawCell = (x, yPos, width, height) => {
|
||||
doc.rect(x, yPos, width, height).stroke();
|
||||
};
|
||||
|
||||
const writeCell = (x, yPos, width, label, value) => {
|
||||
drawCell(x, yPos, width, rowHeight);
|
||||
doc.fontSize(9).font('Helvetica-Bold').text(label, x + 6, yPos + 6, {
|
||||
width: width - 12
|
||||
});
|
||||
if (value) {
|
||||
doc.fontSize(10).font('Helvetica').text(value, x + 6, yPos + 14, {
|
||||
width: width - 12
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const halfWidth = tableWidth / 2;
|
||||
|
||||
writeCell(startX, y, halfWidth, 'Tarih', new Date(slip.slipDate).toLocaleDateString('tr-TR'));
|
||||
writeCell(startX + halfWidth, y, halfWidth, 'Fiş No', String(slip.slipNumber).padStart(4, '0'));
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, tableWidth, 'Aracın Ait Olduğu Kuvvet', slip.force);
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, tableWidth, 'Aracın Ait Olduğu Birlik', slip.unitName);
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, tableWidth, 'Aracın Cinsi', slip.vehicleDescription);
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, tableWidth, 'Aracın Plakası', slip.plate);
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, halfWidth, 'Yakıt Miktarı (Rakam)', `${slip.fuelAmountNumber}`);
|
||||
writeCell(startX + halfWidth, y, halfWidth, 'Yakıt Miktarı (Yazı)', slip.fuelAmountText);
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, halfWidth, 'Yakıt Cinsi', slip.fuelType);
|
||||
writeCell(startX + halfWidth, y, halfWidth, 'Not', slip.notes || '-');
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, halfWidth, 'Teslim Alan', `${slip.receiverName}\n${slip.receiverRank} / ${slip.receiverRegistry}`);
|
||||
writeCell(startX + halfWidth, y, halfWidth, 'Teslim Eden', `${slip.giverName}\n${slip.giverRank} / ${slip.giverRegistry}`);
|
||||
y += rowHeight;
|
||||
|
||||
writeCell(startX, y, halfWidth, 'Teslim Alan Telefonu', slip.receiverPhone);
|
||||
writeCell(startX + halfWidth, y, halfWidth, 'Teslim Eden Telefonu', slip.giverPhone);
|
||||
y += rowHeight;
|
||||
|
||||
doc.moveDown(2);
|
||||
doc.fontSize(9).text('Not: Seri numarası yıl + sıra şeklinde takip edilir. Bu fiş sistem üzerinden oluşturulmuştur.', {
|
||||
align: 'center'
|
||||
});
|
||||
|
||||
doc.end();
|
||||
} catch (err) {
|
||||
console.error('PDF olusturma hatasi:', err);
|
||||
return res.status(500).json({ message: 'PDF oluşturulamadı.' });
|
||||
}
|
||||
});
|
||||
|
||||
initialize()
|
||||
.then(() => {
|
||||
httpServer.listen(PORT, () => {
|
||||
console.log(`Sunucu ${PORT} portunda hazir.`);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Sunucu baslatilamadi:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log('Sunucu kapatiliyor...');
|
||||
io.close();
|
||||
db.close(() => {
|
||||
httpServer.close(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user