125 lines
3.5 KiB
JavaScript
125 lines
3.5 KiB
JavaScript
'use strict';
|
||
|
||
/**
|
||
* routes/stock.js
|
||
* Stok giriş/çıkış hareket rotaları + hareket log sayfası.
|
||
*/
|
||
|
||
const express = require('express');
|
||
const router = express.Router();
|
||
const productModel = require('../models/productModel');
|
||
const stockModel = require('../models/stockModel');
|
||
const lowStockService = require('../services/lowStockService');
|
||
|
||
/** POST /in — stok girişi */
|
||
router.post('/in', (req, res) => {
|
||
const { productId, quantity, note } = req.body || {};
|
||
const product = productModel.findById(productId);
|
||
if (!product) return res.status(404).json({ error: 'Ürün bulunamadı' });
|
||
|
||
const qty = Number(quantity);
|
||
if (!qty || qty <= 0) {
|
||
return res.status(400).json({ error: 'Geçerli bir miktar girilmelidir.' });
|
||
}
|
||
|
||
// Ürün stokunu artır — direct update
|
||
const newStock = Number(product.stock) + qty;
|
||
const updated = productModel.update(product.id, { stock: newStock });
|
||
|
||
const movement = stockModel.addMovement({
|
||
productId: product.id,
|
||
type: 'in',
|
||
quantity: qty,
|
||
note,
|
||
remainingStock: newStock
|
||
});
|
||
|
||
return res.status(201).json({
|
||
product: updated,
|
||
movement,
|
||
lowStock: Number(updated.stock) <= (Number(updated.minimumStock) || 10)
|
||
});
|
||
});
|
||
|
||
/** POST /out — stok çıkışı */
|
||
router.post('/out', (req, res) => {
|
||
const { productId, quantity, note } = req.body || {};
|
||
const product = productModel.findById(productId);
|
||
if (!product) return res.status(404).json({ error: 'Ürün bulunamadı' });
|
||
|
||
const qty = Number(quantity);
|
||
if (!qty || qty <= 0) {
|
||
return res.status(400).json({ error: 'Geçerli bir miktar girilmelidir.' });
|
||
}
|
||
if (qty > Number(product.stock)) {
|
||
return res.status(400).json({
|
||
error: `Yetersiz stok! Mevcut stok: ${product.stock} (istenen: ${qty})`
|
||
});
|
||
}
|
||
|
||
const newStock = Number(product.stock) - qty;
|
||
const updated = productModel.update(product.id, { stock: newStock });
|
||
|
||
const movement = stockModel.addMovement({
|
||
productId: product.id,
|
||
type: 'out',
|
||
quantity: qty,
|
||
note,
|
||
remainingStock: newStock
|
||
});
|
||
|
||
return res.status(201).json({
|
||
product: updated,
|
||
movement,
|
||
lowStock: Number(updated.stock) <= (Number(updated.minimumStock) || 10)
|
||
});
|
||
});
|
||
|
||
/** GET /movements — hareket log sayfası (veya ?json=1 ile JSON) */
|
||
router.get('/movements', (req, res) => {
|
||
const all = stockModel.getAll();
|
||
const typeFilter = req.query.type || '';
|
||
|
||
let movements = all;
|
||
if (typeFilter === 'in' || typeFilter === 'out') {
|
||
movements = all.filter((m) => m.type === typeFilter);
|
||
}
|
||
|
||
const products = productModel.readAll();
|
||
const nameOf = (id) => {
|
||
const p = products.find((x) => x.id === Number(id));
|
||
return p ? p.name : 'Silinmiş Ürün';
|
||
};
|
||
const enriched = movements.map((m) => ({
|
||
...m,
|
||
productName: nameOf(m.productId)
|
||
}));
|
||
|
||
if (req.query.json !== undefined) {
|
||
return res.json({ movements: enriched, typeFilter });
|
||
}
|
||
|
||
const counts = {
|
||
in: all.filter((m) => m.type === 'in').length,
|
||
out: all.filter((m) => m.type === 'out').length,
|
||
total: all.length
|
||
};
|
||
|
||
res.render('stock/movements', {
|
||
title: 'Stok Hareketleri',
|
||
movements: enriched,
|
||
typeFilter,
|
||
counts,
|
||
lowStockCount: lowStockService.countLowStock(),
|
||
bodyClass: 'movements-page'
|
||
});
|
||
});
|
||
|
||
/** GET /movements/:productId — ürüne özel hareketler (API JSON) */
|
||
router.get('/movements/:productId', (req, res) => {
|
||
const movements = stockModel.getByProduct(req.params.productId);
|
||
return res.json(movements);
|
||
});
|
||
|
||
module.exports = router;
|