আগের পর্বে আমরা বিল কাটলে স্টক কমানো ও সেলস রেকর্ড জমা করা শিখেছি। আজ আমরা সেই জমা করা রেকর্ডগুলোকে সুন্দর করে দেখার জন্য একটি সেলস রিপোর্ট পেজ বানাবো। দোকানদার এই পেজে এসে এক নজরে দেখতে পারবে—আজ কত বিক্রি হলো, কত ক্যাশ পেমেন্ট, কত বাকি, এবং প্রতিটি বিলের বিস্তারিত।
রিপোর্ট পেজে কী কী থাকবে?
| অংশ | কী দেখাবে? |
|---|---|
| সারাংশ কার্ড | মোট বিক্রি, ক্যাশ, অনলাইন, বাকি—চারটি কার্ডে |
| তারিখ ফিল্টার | আজ, গতকাল, বা নির্দিষ্ট তারিখ বেছে নেওয়া |
| বিল তালিকা | প্রতিটি বিলের আইডি, সময়, আইটেম, মোট টাকা |
| আইটেম বিস্তারিত | প্রতিটি বিলে কী কী প্রোডাক্ট বিক্রি হয়েছে |
ধাপ ১: server.js-এ GET /sales API যোগ করো
cd ~/shop-api
micro server.js
নিচের কোড দুটি app.delete(...)-এর নিচে যোগ করো:
// GET /sales – সব সেলস রেকর্ড (নতুন → পুরোনো)
app.get('/sales', (req, res) => {
const salesFile = path.join(__dirname, 'sales.json');
if (!fs.existsSync(salesFile)) return res.json([]);
const sales = JSON.parse(fs.readFileSync(salesFile, 'utf8'));
sales.sort((a, b) => b.id - a.id); // নতুন আগে
res.json(sales);
});
// GET /sales/:date – নির্দিষ্ট তারিখের সেলস
app.get('/sales/:date', (req, res) => {
const salesFile = path.join(__dirname, 'sales.json');
if (!fs.existsSync(salesFile)) return res.json([]);
const sales = JSON.parse(fs.readFileSync(salesFile, 'utf8'));
const filtered = sales.filter(s => s.date.startsWith(req.params.date));
filtered.sort((a, b) => b.id - a.id);
res.json(filtered);
});
ধাপ ২: report.html তৈরি করো
cd ~/shop-api/public
micro report.html
নিচের সম্পূর্ণ কোডটি কপি-পেস্ট করো। এখানে চারটি সারাংশ কার্ড, তারিখ ইনপুট, এবং বিলের তালিকা টেবিল আছে:
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>📊 সেলস রিপোর্ট - মুদি দোকান</title>
<style>
:root { --bg: #f1f5f9; --surface: #ffffff; --text: #1e293b; --accent: #2563eb; }
body.dark { --bg: #0f172a; --surface: #1e293b; --text: #e2e8f0; }
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI', sans-serif; background:var(--bg); color:var(--text); padding:1rem; }
.container { max-width:1000px; margin:0 auto; }
h1 { text-align:center; margin-bottom:1rem; }
.summary-cards { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:1rem; margin-bottom:1.5rem; }
.card { background:var(--surface); border-radius:12px; padding:1rem; text-align:center; box-shadow:0 2px 8px rgba(0,0,0,0.1); }
.card .amount { font-size:1.5rem; font-weight:bold; color:var(--accent); }
.filter-bar { display:flex; gap:0.5rem; margin-bottom:1rem; }
.filter-bar input { flex:1; padding:0.5rem; border:1px solid #cbd5e1; border-radius:8px; }
.filter-bar button { padding:0.5rem 1rem; background:var(--accent); color:#fff; border:none; border-radius:8px; cursor:pointer; }
table { width:100%; border-collapse:collapse; background:var(--surface); border-radius:12px; overflow:hidden; }
th, td { padding:0.75rem; text-align:left; border-bottom:1px solid #e2e8f0; }
th { background:#f8fafc; font-weight:600; }
.bill-items { font-size:0.85rem; color:#64748b; margin-top:4px; }
</style>
</head>
<body>
<div class="container">
<h1>📊 সেলস রিপোর্ট</h1>
<div class="summary-cards">
<div class="card"><div>মোট বিক্রি</div><div class="amount" id="totalSales">০ ৳</div></div>
<div class="card"><div>মোট বিল</div><div class="amount" id="totalBills">০</div></div>
</div>
<div class="filter-bar">
<input type="date" id="dateFilter">
<button onclick="loadReport()">🔍 ফিল্টার</button>
<button onclick="document.getElementById('dateFilter').value=''; loadReport();">🔄 সব</button>
</div>
<table>
<thead><tr><th>বিল #</th><th>তারিখ</th><th>আইটেম</th><th>মোট</th></tr></thead>
<tbody id="reportBody"><tr><td colspan="4">⏳ লোড হচ্ছে...</td></tr></tbody>
</table>
</div>
<script>
async function loadReport() {
const date = document.getElementById('dateFilter').value;
const url = date ? `/sales/${date}` : '/sales';
const res = await fetch(url);
const sales = await res.json();
let total = 0;
const tbody = document.getElementById('reportBody');
if (!sales.length) { tbody.innerHTML = '<tr><td colspan="4">কোনো বিক্রি নেই</td></tr>'; }
else {
tbody.innerHTML = sales.map(s => { total += s.total; return `
<tr>
<td>#${s.id}</td>
<td>${new Date(s.date).toLocaleString('bn-BD')}</td>
<td>${s.items.length} টি<div class="bill-items">${s.items.map(i => i.name+' ×'+i.qty).join(', ')}</div></td>
<td>৳ ${s.total}</td>
</tr>`; }).join('');
}
document.getElementById('totalSales').textContent = total + ' ৳';
document.getElementById('totalBills').textContent = sales.length;
}
// আজকের তারিখ ডিফল্ট
document.getElementById('dateFilter').value = new Date().toISOString().split('T')[0];
loadReport();
</script>
</body>
</html>
লাইন-বাই-লাইন ব্যাখ্যা
| অংশ | কী করছে? | সহজ ভাষায় |
|---|---|---|
sales.sort((a,b) => b.id - a.id) | নতুন বিল আগে দেখাচ্ছে | "সর্বশেষ বিল সবার উপরে" |
date.startsWith(...) | নির্দিষ্ট তারিখের বিল ফিল্টার | "শুধু আজকেরটা দাও" |
summary-cards | মোট বিক্রি ও বিল সংখ্যা | "এক নজরে হিসাব" |
new Date(s.date).toLocaleString('bn-BD') | তারিখ বাংলা ফরম্যাটে | "বাংলাদেশী সময়ে দেখাচ্ছে" |
ধাপ ৩: টেস্ট করো
node server.js
termux-open-url http://localhost:3000/report.html
এখন আগে bill.html থেকে কিছু বিল কাটো, তারপর report.html ওপেন করো। দেখবে—আজকের সব বিল, মোট বিক্রি, এবং প্রতিটি বিলের আইটেম তালিকা চলে এসেছে!
আজ তুমি কী শিখলে
- GET /sales API — সব বা নির্দিষ্ট তারিখের সেলস ডেটা আনা
- তারিখ ফিল্টার —
date.startsWith()দিয়ে নির্দিষ্ট দিনের ডেটা ফিল্টার - সারাংশ কার্ড — মোট বিক্রি, বিল সংখ্যা এক নজরে দেখানো
- বাংলা তারিখ —
toLocaleString('bn-BD')দিয়ে বাংলা ফরম্যাটে তারিখ - টেবিল UI — প্রতিটি বিলের বিস্তারিত আইটেম-সহ তালিকা
পরবর্তী পর্বে আমরা JWT লগইন সিস্টেম বানাবো — যাতে শুধু অনুমোদিত ইউজারই দোকানের ডেটা দেখতে ও পরিবর্তন করতে পারে।
In the previous episode, we learned how to reduce stock and save sales records. Today we'll build a beautiful Sales Report Page where the shop owner can view today's total sales, cash vs due breakdown, and details of each bill.
What's in the Report Page?
| Section | Shows |
|---|---|
| Summary Cards | Total sales, number of bills |
| Date Filter | Filter by today, yesterday, or any date |
| Bill List | Bill ID, time, items, total |
Step 1: Add GET /sales API
app.get('/sales', (req, res) => { ... });
app.get('/sales/:date', (req, res) => { ... });
Step 2: Create report.html
Build summary cards, date filter, and bill table with item details.
Step 3: Test
node server.js
termux-open-url http://localhost:3000/report.html
Next episode: JWT Login System — secure your shop data so only authorized users can access it.
💬 মন্তব্য / Comments