Bot Jualan dengan Update Stok Real-time
Cara buat bot jualan WhatsApp dengan stok real-time. Auto update, low stock alert, prevent oversell. Tutorial lengkap!
Oversell = Masalah besar!
Customer order, ternyata stok habis. Kecewa, refund, trust hilang.
Solusinya: Bot dengan stok real-time!
Fitur Stok Management
✅ Cek stok otomatis saat customer tanya
✅ Auto update setelah order
✅ Low stock alert ke admin
✅ Auto "Sold Out" jika habis
✅ Restock notification ke customerFlow Stok Real-time
Customer: "Stok sepatu size 42?"
↓
Bot: Query database
↓
Bot: "Sepatu A size 42: Ready 5 pcs! ✅"
--- Saat Order ---
Customer: Order 2 pcs
↓
Bot: Update stok 5 → 3
↓
Bot: "Order confirmed! Stok tersisa: 3"
--- Low Stock ---
Stok = 3 (threshold: 5)
↓
Bot: Alert admin "Stok menipis!"Template Response Stok
Cek Stok:
📦 STOK [PRODUK]
[Gambar Produk]
Size 40: ✅ Ready (8 pcs)
Size 41: ✅ Ready (5 pcs)
Size 42: ✅ Ready (3 pcs)
Size 43: ⚠️ Sisa 1 pcs!
Size 44: ❌ Sold Out
💰 Harga: Rp 250.000
Mau order? Ketik:
ORDER [PRODUK] [SIZE] [QTY]Stok Habis:
😢 MAAF, STOK HABIS!
[PRODUK] [SIZE/VARIAN] sedang kosong.
Pilihan:
1. Pre-order (estimasi restock: [TANGGAL])
2. Pilih size/warna lain
3. Notif saat restock
Reply:
- PO - untuk pre-order
- LAIN - lihat varian lain
- NOTIF - dapat notifikasi restockRestock Notification:
🔔 BACK IN STOCK!
Hai Kak [NAMA]!
[PRODUK] yang kemarin habis sudah ready!
📦 Stok: [QTY] pcs
💰 Harga: Rp [HARGA]
Siapa cepat dia dapat!
Reply ORDER untuk beli sekarang.Low Stock Alert (ke Admin):
⚠️ LOW STOCK ALERT!
Produk: [NAMA]
Varian: [VARIAN]
Stok sekarang: [QTY]
Threshold: [THRESHOLD]
Action needed:
- Restock segera
- Atau update status ke "Pre-order"Implementasi
Database Schema:
javascript
// Products collection
{
id: 'PRD001',
name: 'Sepatu Sneakers A',
price: 250000,
variants: [
{ size: '40', stock: 8 },
{ size: '41', stock: 5 },
{ size: '42', stock: 3 },
{ size: '43', stock: 1 },
{ size: '44', stock: 0 }
],
lowStockThreshold: 3,
notifyOnRestock: ['628xxx', '628yyy'] // Customers waiting
}Check Stock Function:
javascript
async function checkStock(productId, variant) {
const product = await db.products.findById(productId);
const variantData = product.variants.find(v => v.size === variant);
return {
available: variantData.stock > 0,
quantity: variantData.stock,
isLow: variantData.stock <= product.lowStockThreshold
};
}
// Bot handler
client.on('message', async msg => {
const text = msg.body.toLowerCase();
if (text.startsWith('stok ')) {
const productName = text.replace('stok ', '');
const product = await findProduct(productName);
if (product) {
await msg.reply(formatStockMessage(product));
} else {
await msg.reply('Produk tidak ditemukan. Ketik KATALOG untuk lihat produk.');
}
}
});Update Stock on Order:
javascript
async function processOrder(order) {
const product = await db.products.findById(order.productId);
const variant = product.variants.find(v => v.size === order.size);
// Check availability
if (variant.stock < order.quantity) {
return { success: false, message: 'Stok tidak cukup!' };
}
// Decrease stock
variant.stock -= order.quantity;
await db.products.update(product.id, { variants: product.variants });
// Check low stock
if (variant.stock <= product.lowStockThreshold) {
await sendLowStockAlert(product, variant);
}
// Check sold out
if (variant.stock === 0) {
await notifyWaitingCustomers(product, variant);
}
return { success: true, remainingStock: variant.stock };
}Restock & Notify:
javascript
async function restockProduct(productId, variant, quantity) {
const product = await db.products.findById(productId);
const variantData = product.variants.find(v => v.size === variant);
const wasOutOfStock = variantData.stock === 0;
variantData.stock += quantity;
await db.products.update(productId, { variants: product.variants });
// Notify waiting customers
if (wasOutOfStock && product.notifyOnRestock.length > 0) {
for (const phone of product.notifyOnRestock) {
await sendRestockNotification(phone, product, variant);
}
// Clear notification list
product.notifyOnRestock = [];
await db.products.update(productId, { notifyOnRestock: [] });
}
}Sync dengan Inventory System
Untuk yang pakai sistem lain:
javascript
// Sync dari sistem inventory external
async function syncInventory() {
const externalStock = await inventoryAPI.getAll();
for (const item of externalStock) {
await db.products.update(
{ sku: item.sku },
{ $set: { 'variants.$[].stock': item.quantity } }
);
}
}
// Run setiap 5 menit
cron.schedule('*/5 * * * *', syncInventory);Webhook dari Marketplace:
javascript
// Terima update dari Tokopedia/Shopee
app.post('/webhook/marketplace-stock', async (req, res) => {
const { sku, newStock } = req.body;
await db.products.update(
{ sku },
{ $set: { stock: newStock } }
);
res.status(200).send('OK');
});Best Practices
1. Buffer Stock
Tampilkan stok - buffer untuk safety:
Actual: 10 pcs
Display: 8 pcs (buffer 2)
Mencegah race condition oversell.2. Real-time vs Near Real-time
Real-time: Setiap transaksi update
Near real-time: Sync setiap 1-5 menit
Untuk volume tinggi, near real-time lebih praktis.3. Reservation System
Saat customer mulai checkout:
→ Reserve stok 15 menit
→ Jika tidak bayar, release kembali
Mencegah stok "terkunci" oleh yang tidak jadi beli.FAQ
Bagaimana jika 2 customer order bersamaan?
Gunakan database transaction atau locking untuk prevent race condition. First come first served.
Perlu sync dengan marketplace?
Ideal ya! Jika jualan di Tokopedia + Shopee + WA, stok harus sinkron supaya tidak oversell.
Bagaimana handle pre-order?
Stok 0 tapi masih bisa order = Pre-order mode. Set flag allowPreorder: true dan tampilkan estimasi restock.
Kesimpulan
Real-time stock = No more oversell!
| Tanpa Real-time | Dengan Real-time |
|---|---|
| Oversell sering | Stok akurat |
| Manual update | Auto update |
| Customer kecewa | Customer happy |
Prevent oversell, build trust!