diff --git a/public/js/reports.js b/public/js/reports.js
new file mode 100644
index 0000000..d99dd3b
--- /dev/null
+++ b/public/js/reports.js
@@ -0,0 +1,79 @@
+/* reports.js — kategori bazlı rapor AJAX ile dinamik doldurma */
+
+(function () {
+ 'use strict';
+
+ const form = document.getElementById('reportForm');
+ if (!form) return;
+
+ const inEl = document.getElementById('repIn');
+ const outEl = document.getElementById('repOut');
+ const netEl = document.getElementById('repNet');
+
+ function fmtNumber(n) {
+ return (Number(n) || 0).toLocaleString('tr-TR');
+ }
+
+ function fmtMoney(n) {
+ return fmtNumber(n) + ' ₺';
+ }
+
+ function renderMovements(list) {
+ const wrap = document.getElementById('reportMovements');
+ if (!list || list.length === 0) {
+ wrap.innerHTML = '
Seçilen kriterlerde hareket yok.
';
+ return;
+ }
+ const rows = list.map(function (m) {
+ const cls = m.type === 'in' ? 'tag-in' : 'tag-out';
+ const label = m.type === 'in' ? 'Giriş +' : 'Çıkış −';
+ const sign = m.type === 'in' ? '+ ' : '− ';
+ return '' +
+ '| ' + m.id + ' | ' +
+ '' + label + ' | ' +
+ '' + sign + m.quantity + ' | ' +
+ '' + m.remainingStock + ' | ' +
+ '' + (m.note || '—') + ' | ' +
+ '' + new Date(m.date).toLocaleString('tr-TR') + ' | ' +
+ '
';
+ }).join('');
+ wrap.innerHTML =
+ '' +
+ '| # | Tip | Miktar | Kalan | Not | Tarih | ' +
+ '
' + rows + '
';
+ }
+
+ function loadReport(categoryId, from, to) {
+ const q = new URLSearchParams();
+ if (from) q.set('from', from);
+ if (to) q.set('to', to);
+ const url = '/api/reports/api/category/' + categoryId + '?' + q.toString();
+
+ fetch(url)
+ .then(function (res) {
+ if (!res.ok) throw new Error('Rapor alınamadı');
+ return res.json();
+ })
+ .then(function (rep) {
+ document.getElementById('repCategory').textContent = rep.category ? rep.category.name : '—';
+ document.getElementById('repProducts').textContent = fmtNumber(rep.totalProducts);
+ document.getElementById('repValue').textContent = fmtMoney(rep.totalStockValue);
+ inEl.textContent = fmtNumber(rep.incomingQty);
+ outEl.textContent = fmtNumber(rep.outgoingQty);
+ netEl.textContent = fmtNumber(rep.netQty);
+ renderMovements(rep.movements);
+ })
+ .catch(function (err) { alert('Hata: ' + err.message); });
+ }
+
+ form.addEventListener('submit', function (e) {
+ e.preventDefault();
+ const cat = document.getElementById('reportCategory').value;
+ const from = document.getElementById('fromDate').value;
+ const to = document.getElementById('toDate').value;
+ loadReport(cat, from, to);
+ });
+
+ // İlk yüklemede tüm kategoriler için otomatik rapor göster
+ loadReport('all', '', '');
+})();