আগের পর্বে আমরা সার্চ বার ও কার্ট তৈরি করেছি। কিন্তু "Complete Sale" বাটনে ক্লিক করলে কিছুই হতো না—স্টক কমতো না, রেকর্ড জমা হতো না। আজ আমরা POST /sales API তৈরি করবো, যাতে বিল কাটলেই প্রতিটি প্রোডাক্টের স্টক অটোমেটিক কমে যায় এবং sales.json ফাইলে সেলস রেকর্ড জমা হয়।
Complete Sale কীভাবে কাজ করে?
বিল কাটা মানে হলো গ্রাহক যা যা নিচ্ছে, সেগুলোর স্টক থেকে বাদ দেওয়া এবং একটি রেকর্ড রাখা। সম্পূর্ণ প্রক্রিয়াটি ধাপে ধাপে বুঝে নিই:
| ধাপ | কী হয়? | কে করে? |
|---|---|---|
| ১ | গ্রাহক প্রোডাক্ট কার্টে যোগ করে | ফ্রন্টএন্ড |
| ২ | "Complete Sale" বাটনে ক্লিক | ফ্রন্টএন্ড |
| ৩ | কার্টের ডেটা POST /sales API-তে যায় | ফ্রন্টএন্ড → ব্যাকএন্ড |
| ৪ | প্রতিটি প্রোডাক্টের স্টক কমানো হয় | ব্যাকএন্ড |
| ৫ | sales.json-এ রেকর্ড জমা হয় | ব্যাকএন্ড |
| ৬ | কার্ট খালি করে সাকসেস মেসেজ | ফ্রন্টএন্ড |
ধাপ ১: server.js-এ POST /sales API যোগ করো
cd ~/shop-api
micro server.js
app.delete(...)-এর নিচে এই নতুন API রাউট যোগ করো:
app.post('/sales', (req, res) => {
const { items } = req.body;
if (!items || !items.length) {
return res.status(400).json({ message: 'কোনো আইটেম নেই' });
}
const products = readProducts();
const saleRecord = { id: Date.now(), date: new Date().toISOString(), items: [], total: 0 };
for (let item of items) {
const product = products.find(p => p.id === item.id);
if (!product) return res.status(404).json({ message: `প্রোডাক্ট id ${item.id} পাওয়া যায়নি` });
if (product.stock < item.qty) return res.status(400).json({ message: `${product.name}-এর পর্যাপ্ত স্টক নেই` });
product.stock -= item.qty;
saleRecord.items.push({ id: product.id, name: product.name, price: product.price, qty: item.qty, subtotal: product.price * item.qty });
saleRecord.total += product.price * item.qty;
}
writeProducts(products);
const salesFile = path.join(__dirname, 'sales.json');
let sales = [];
if (fs.existsSync(salesFile)) sales = JSON.parse(fs.readFileSync(salesFile, 'utf8'));
sales.push(saleRecord);
fs.writeFileSync(salesFile, JSON.stringify(sales, null, 2), 'utf8');
res.status(201).json({ message: 'বিল সম্পন্ন হয়েছে', sale: saleRecord });
});
লাইন-বাই-লাইন ব্যাখ্যা
| লাইন/ব্লক | কী করছে? | সহজ ভাষায় |
|---|---|---|
const { items } = req.body | কার্টের আইটেম লিস্ট পড়ছে | "তুমি কী কী নিচ্ছো?" |
if (!items || !items.length) | খালি কার্ট চেক | "কিছু তো নাও!" |
products.find(...) | প্রোডাক্ট খুঁজছে | "এই জিনিসটা দোকানে আছে তো?" |
product.stock < item.qty | পর্যাপ্ত স্টক চেক | "যতটা চাইছো, ততটা আছে তো?" |
product.stock -= item.qty | স্টক কমানো | "এবার স্টক থেকে বাদ দাও" |
sales.json সেভ | বিক্রির রেকর্ড জমা | "কে, কখন, কী কিনল—সব লিখে রাখো" |
ধাপ ২: bill.html-এ Complete Sale ফাংশন যোগ করো
bill.html ওপেন করো:
cd ~/shop-api/public
micro bill.html
<script> ট্যাগের ভেতরে এই নতুন ফাংশন যোগ করো:
async function completeSale() {
if (!cart.length) { alert('❌ কার্ট খালি!'); return; }
try {
const res = await fetch('/sales', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ items: cart.map(i => ({ id: i.id, qty: i.qty })) })
});
const data = await res.json();
if (!res.ok) { alert('❌ ' + (data.message || 'বিল সম্পন্ন করা যায়নি')); return; }
alert('✅ বিল সম্পন্ন! মোট: ' + cart.reduce((s, i) => s + i.qty * i.price, 0) + ' ৳');
cart = []; renderCart();
} catch (err) { alert('❌ নেটওয়ার্ক সমস্যা'); }
}
এবার কার্ট প্যানেলের নিচে (</div> বন্ধ হওয়ার আগে) এই বাটনটি যোগ করো:
<button onclick="completeSale()" style="width:100%; padding:12px; background:#10b981; color:#fff; border:none; border-radius:8px; font-weight:bold; font-size:1rem; margin-top:1rem; cursor:pointer;">✅ Complete Sale</button>
ধাপ ৩: টেস্ট করো
node server.js
termux-open-url http://localhost:3000/bill.html
এখন কিছু প্রোডাক্ট কার্টে যোগ করে "Complete Sale" বাটনে ক্লিক করো। দেখবে—স্টক কমে গেছে এবং sales.json ফাইলে একটি নতুন রেকর্ড যোগ হয়েছে!
আজ তুমি কী শিখলে
- POST /sales API — বিল সম্পন্ন করার API বানানো
- স্টক অটো-আপডেট — বিল কাটলে প্রতিটি প্রোডাক্টের স্টক স্বয়ংক্রিয়ভাবে কমানো
- সেলস রেকর্ড — প্রতিটি বিলের তথ্য
sales.json-এ জমা রাখা - স্টক ভ্যালিডেশন — পর্যাপ্ত স্টক না থাকলে বিল সম্পন্ন না করা
- কার্ট ক্লিয়ার — বিল সম্পন্ন হলে কার্ট খালি করে পরবর্তী গ্রাহকের জন্য প্রস্তুত করা
পরবর্তী পর্বে আমরা সেলস রিপোর্ট বানাবো — যেখানে আজকের বা নির্দিষ্ট দিনের বিক্রির সম্পূর্ণ হিসাব দেখতে পারবে।
In the previous episode, we created the search bar and cart. But clicking "Complete Sale" did nothing—stock didn't reduce, records weren't saved. Today we'll create the POST /sales API to automatically reduce stock and save sales records.
How Complete Sale Works
| Step | What Happens |
|---|---|
| 1 | Customer adds products to cart |
| 2 | Clicks "Complete Sale" |
| 3 | Cart data sent via POST /sales |
| 4 | Server reduces stock for each product |
| 5 | Server saves record to sales.json |
| 6 | Cart cleared, success message shown |
Step 1: Add POST /sales in server.js
app.post('/sales', (req, res) => {
const { items } = req.body;
// validate, reduce stock, save record
});
Step 2: Add completeSale() in bill.html
async function completeSale() {
await fetch('/sales', { method:'POST', body: JSON.stringify({ items: cart.map(...) }) });
cart = []; renderCart();
}
Next episode: Sales Report — view daily or date-wise sales summary.
💬 মন্তব্য / Comments