From b8c7f0bcc41994b8027f8631559086d66f4e0b1d Mon Sep 17 00:00:00 2001
From: 000balaai-cloud <000balaai@gmail.com>
Date: Tue, 30 Dec 2025 05:15:12 +0530
Subject: [PATCH 01/30] Update homepage message
Signed-off-by: 000balaai-cloud <000balaai@gmail.com>
---
views/pages/index.ejs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/views/pages/index.ejs b/views/pages/index.ejs
index ea7498435d..95a9bfc746 100644
--- a/views/pages/index.ejs
+++ b/views/pages/index.ejs
@@ -13,7 +13,7 @@
-
This is a sample Node application deployed to Heroku. It's a reasonably simple app - but a good foundation for understanding how to get the most out of the Heroku platform.
Getting Started on Heroku with Node.js Getting Started on Heroku Fir with Node.js From bde4276c6541c7711f06854958b2e6e70c6cdfc8 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Tue, 30 Dec 2025 05:17:17 +0530 Subject: [PATCH 02/30] Update homepage message Signed-off-by: 000balaai-cloud <000balaai@gmail.com> From dbc6080263ac78b65384deea857f716a525a2904 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Tue, 30 Dec 2025 15:57:35 +0530 Subject: [PATCH 03/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 67 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index 19d020f11f..1cf0ab1fc4 100644 --- a/index.js +++ b/index.js @@ -1,36 +1,57 @@ -const express = require('express') -const path = require('path') +const express = require('express'); +const path = require('path'); -const port = process.env.PORT || 5006 +const port = process.env.PORT || 5006; +const app = express(); -const app = express() +// Middleware +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); +app.use(express.static(path.join(__dirname, 'public'))); -app.use(express.static(path.join(__dirname, 'public'))) -app.set('views', path.join(__dirname, 'views')) -app.set('view engine', 'ejs') +// View engine +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'ejs'); +// Home route app.get('/', (req, res) => { - console.log(`Rendering 'pages/index' for route '/'`) - res.render('pages/index') -}) + console.log(`Rendering 'pages/index' for route '/'`); + res.render('pages/index'); +}); +/* ================================ + WhatsApp Webhook Verification + ================================ */ +app.get('/webhook', (req, res) => { + const VERIFY_TOKEN = process.env.VERIFY_TOKEN; + + const mode = req.query['hub.mode']; + const token = req.query['hub.verify_token']; + const challenge = req.query['hub.challenge']; + + if (mode === 'subscribe' && token === VERIFY_TOKEN) { + console.log('β Webhook verified successfully'); + return res.status(200).send(challenge); + } else { + console.log('β Webhook verification failed'); + return res.sendStatus(403); + } +}); + +// Start server const server = app.listen(port, () => { - console.log(`Listening on ${port}`) -}) + console.log(`Listening on ${port}`); +}); -// The number of seconds an idle Keep-Alive connection is kept open. This should be greater than the Heroku Router's -// Keep-Alive idle timeout of 90 seconds: -// - to ensure that the closing of idle connections is always initiated by the router and not the Node.js server -// - to prevent a race condition if the router sends a request to the app just as Node.js is closing the connection -// https://devcenter.heroku.com/articles/http-routing#keepalives -// https://nodejs.org/api/http.html#serverkeepalivetimeout -server.keepAliveTimeout = 95 * 1000 +// Keep-alive config (important for Render/Heroku) +server.keepAliveTimeout = 95 * 1000; +// Graceful shutdown process.on('SIGTERM', async () => { - console.log('SIGTERM signal received: gracefully shutting down') + console.log('SIGTERM signal received: gracefully shutting down'); if (server) { server.close(() => { - console.log('HTTP server closed') - }) + console.log('HTTP server closed'); + }); } -}) +}); From ffcaf680608f45385557e33abd52ef53eee80657 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Tue, 30 Dec 2025 17:54:02 +0530 Subject: [PATCH 04/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 86 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/index.js b/index.js index 1cf0ab1fc4..738565e826 100644 --- a/index.js +++ b/index.js @@ -1,57 +1,61 @@ -const express = require('express'); -const path = require('path'); +const express = require('express') +const path = require('path') -const port = process.env.PORT || 5006; -const app = express(); +const app = express() +const port = process.env.PORT || 5006 // Middleware -app.use(express.json()); -app.use(express.urlencoded({ extended: true })); -app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.json()) +app.use(express.urlencoded({ extended: true })) -// View engine -app.set('views', path.join(__dirname, 'views')); -app.set('view engine', 'ejs'); +// Views +app.use(express.static(path.join(__dirname, 'public'))) +app.set('views', path.join(__dirname, 'views')) +app.set('view engine', 'ejs') -// Home route +// Homepage app.get('/', (req, res) => { - console.log(`Rendering 'pages/index' for route '/'`); - res.render('pages/index'); -}); + res.render('pages/index') +}) -/* ================================ - WhatsApp Webhook Verification - ================================ */ +// Webhook verification (already working) app.get('/webhook', (req, res) => { - const VERIFY_TOKEN = process.env.VERIFY_TOKEN; + const VERIFY_TOKEN = process.env.VERIFY_TOKEN - const mode = req.query['hub.mode']; - const token = req.query['hub.verify_token']; - const challenge = req.query['hub.challenge']; + const mode = req.query['hub.mode'] + const token = req.query['hub.verify_token'] + const challenge = req.query['hub.challenge'] if (mode === 'subscribe' && token === VERIFY_TOKEN) { - console.log('β Webhook verified successfully'); - return res.status(200).send(challenge); + console.log('Webhook verified') + res.status(200).send(challenge) } else { - console.log('β Webhook verification failed'); - return res.sendStatus(403); + res.sendStatus(403) } -}); +}) + +// Receive WhatsApp messages +app.post('/webhook', (req, res) => { + console.log('Incoming webhook:', JSON.stringify(req.body, null, 2)) + + const entry = req.body.entry?.[0] + const changes = entry?.changes?.[0] + const value = changes?.value + const messages = value?.messages + + if (messages && messages.length > 0) { + const from = messages[0].from + const text = messages[0].text?.body + + console.log(`Message from ${from}: ${text}`) + } + + res.sendStatus(200) +}) // Start server const server = app.listen(port, () => { - console.log(`Listening on ${port}`); -}); - -// Keep-alive config (important for Render/Heroku) -server.keepAliveTimeout = 95 * 1000; - -// Graceful shutdown -process.on('SIGTERM', async () => { - console.log('SIGTERM signal received: gracefully shutting down'); - if (server) { - server.close(() => { - console.log('HTTP server closed'); - }); - } -}); + console.log(`Listening on ${port}`) +}) + +server.keepAliveTimeout = 95 * 1000 From ae29a184245b015633f2e38add3e5ea0354266e9 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Tue, 30 Dec 2025 17:56:30 +0530 Subject: [PATCH 05/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> From 8007a13ab42781d603d85dbba353ac726bd681f2 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Wed, 31 Dec 2025 17:38:48 +0530 Subject: [PATCH 06/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 85 +++++++++++++++++++------------------------------------- 1 file changed, 29 insertions(+), 56 deletions(-) diff --git a/index.js b/index.js index 738565e826..801c581f35 100644 --- a/index.js +++ b/index.js @@ -1,61 +1,34 @@ -const express = require('express') -const path = require('path') +app.post('/webhook', async (req, res) => { + console.log('Incoming webhook:', JSON.stringify(req.body, null, 2)); -const app = express() -const port = process.env.PORT || 5006 - -// Middleware -app.use(express.json()) -app.use(express.urlencoded({ extended: true })) - -// Views -app.use(express.static(path.join(__dirname, 'public'))) -app.set('views', path.join(__dirname, 'views')) -app.set('view engine', 'ejs') - -// Homepage -app.get('/', (req, res) => { - res.render('pages/index') -}) - -// Webhook verification (already working) -app.get('/webhook', (req, res) => { - const VERIFY_TOKEN = process.env.VERIFY_TOKEN - - const mode = req.query['hub.mode'] - const token = req.query['hub.verify_token'] - const challenge = req.query['hub.challenge'] - - if (mode === 'subscribe' && token === VERIFY_TOKEN) { - console.log('Webhook verified') - res.status(200).send(challenge) - } else { - res.sendStatus(403) - } -}) - -// Receive WhatsApp messages -app.post('/webhook', (req, res) => { - console.log('Incoming webhook:', JSON.stringify(req.body, null, 2)) - - const entry = req.body.entry?.[0] - const changes = entry?.changes?.[0] - const value = changes?.value - const messages = value?.messages + const entry = req.body.entry?.[0]; + const changes = entry?.changes?.[0]; + const value = changes?.value; + const messages = value?.messages; if (messages && messages.length > 0) { - const from = messages[0].from - const text = messages[0].text?.body - - console.log(`Message from ${from}: ${text}`) + const from = messages[0].from; + const text = messages[0].text?.body; + + console.log(`Message from ${from}: ${text}`); + + // Send auto-reply + await fetch( + `https://graph.facebook.com/v19.0/${process.env.PHONE_NUMBER_ID}/messages`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.WHATSAPP_TOKEN}` + }, + body: JSON.stringify({ + messaging_product: 'whatsapp', + to: from, + text: { body: 'π Hello! Your message has been received.' } + }) + } + ); } - res.sendStatus(200) -}) - -// Start server -const server = app.listen(port, () => { - console.log(`Listening on ${port}`) -}) - -server.keepAliveTimeout = 95 * 1000 + res.sendStatus(200); +}); From 0e72c338222859e5c8787d7ccaccffdf8ce9eeb3 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Wed, 31 Dec 2025 17:46:13 +0530 Subject: [PATCH 07/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 801c581f35..f60f8d10f0 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,40 @@ +const express = require('express'); +const path = require('path'); + +const app = express(); +const port = process.env.PORT || 5006; + +// Middleware +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); + +// Static & views +app.use(express.static(path.join(__dirname, 'public'))); +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'ejs'); + +// Home route +app.get('/', (req, res) => { + res.send('WhatsApp Webhook is running β '); +}); + +// π Webhook verification (Meta Step) +app.get('/webhook', (req, res) => { + const VERIFY_TOKEN = 'my_verify_token'; // must match Meta token + + const mode = req.query['hub.mode']; + const token = req.query['hub.verify_token']; + const challenge = req.query['hub.challenge']; + + if (mode === 'subscribe' && token === VERIFY_TOKEN) { + console.log('Webhook verified'); + res.status(200).send(challenge); + } else { + res.sendStatus(403); + } +}); + +// π© Receive WhatsApp messages app.post('/webhook', async (req, res) => { console.log('Incoming webhook:', JSON.stringify(req.body, null, 2)); @@ -12,7 +49,7 @@ app.post('/webhook', async (req, res) => { console.log(`Message from ${from}: ${text}`); - // Send auto-reply + // Auto-reply await fetch( `https://graph.facebook.com/v19.0/${process.env.PHONE_NUMBER_ID}/messages`, { @@ -24,7 +61,7 @@ app.post('/webhook', async (req, res) => { body: JSON.stringify({ messaging_product: 'whatsapp', to: from, - text: { body: 'π Hello! Your message has been received.' } + text: { body: 'π Hello! Your message has been received successfully.' } }) } ); @@ -32,3 +69,10 @@ app.post('/webhook', async (req, res) => { res.sendStatus(200); }); + +// Start server +const server = app.listen(port, () => { + console.log(`Server running on port ${port}`); +}); + +server.keepAliveTimeout = 95 * 1000; From 4e7aa33e84fb9e881a5f9d2aa4bcb1420b00ec04 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Fri, 2 Jan 2026 13:30:38 +0530 Subject: [PATCH 08/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 143 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 50 deletions(-) diff --git a/index.js b/index.js index f60f8d10f0..631f6c2e25 100644 --- a/index.js +++ b/index.js @@ -1,55 +1,102 @@ -const express = require('express'); -const path = require('path'); +app.post('/webhook', async (req, res) => { + try { + const entry = req.body.entry?.[0]; + const changes = entry?.changes?.[0]; + const value = changes?.value; + const messages = value?.messages; -const app = express(); -const port = process.env.PORT || 5006; + if (!messages) { + return res.sendStatus(200); + } -// Middleware -app.use(express.json()); -app.use(express.urlencoded({ extended: true })); + const from = messages[0].from; + const text = messages[0].text?.body?.trim(); -// Static & views -app.use(express.static(path.join(__dirname, 'public'))); -app.set('views', path.join(__dirname, 'views')); -app.set('view engine', 'ejs'); + let reply = ''; -// Home route -app.get('/', (req, res) => { - res.send('WhatsApp Webhook is running β '); -}); + // Greeting / Menu + if (!text || ['hi', 'hello', 'menu'].includes(text.toLowerCase())) { + reply = + `Welcome to *Bala Milk Store* π₯\n\n` + + `Please choose an option:\n` + + `1οΈβ£ Buffalo Milk β βΉ100/L\n` + + `2οΈβ£ Cow Milk β βΉ120/L\n` + + `3οΈβ£ Paneer β βΉ600/Kg\n` + + `4οΈβ£ Ghee β βΉ1000/Kg\n` + + `5οΈβ£ Daily Milk Subscription\n` + + `6οΈβ£ Talk to Owner\n\n` + + `Reply with the option number.`; + } -// π Webhook verification (Meta Step) -app.get('/webhook', (req, res) => { - const VERIFY_TOKEN = 'my_verify_token'; // must match Meta token + // Option 1 - Buffalo Milk + else if (text === '1') { + reply = + `π₯ *Buffalo Milk*\n\n` + + `Price: βΉ100 per liter\n` + + `Fresh & Pure\n\n` + + `Reply with quantity in liters (Example: 2L)`; + } - const mode = req.query['hub.mode']; - const token = req.query['hub.verify_token']; - const challenge = req.query['hub.challenge']; + // Option 2 - Cow Milk + else if (text === '2') { + reply = + `π₯ *Cow Milk*\n\n` + + `Price: βΉ120 per liter\n` + + `Healthy & Natural\n\n` + + `Reply with quantity in liters (Example: 1L)`; + } - if (mode === 'subscribe' && token === VERIFY_TOKEN) { - console.log('Webhook verified'); - res.status(200).send(challenge); - } else { - res.sendStatus(403); - } -}); + // Option 3 - Paneer + else if (text === '3') { + reply = + `π§ *Paneer*\n\n` + + `Price: βΉ600 per Kg\n` + + `Fresh homemade paneer\n\n` + + `Reply with quantity (Example: 0.5 Kg)`; + } -// π© Receive WhatsApp messages -app.post('/webhook', async (req, res) => { - console.log('Incoming webhook:', JSON.stringify(req.body, null, 2)); + // Option 4 - Ghee + else if (text === '4') { + reply = + `π« *Pure Ghee*\n\n` + + `Price: βΉ1000 per Kg\n` + + `Traditional & aromatic\n\n` + + `Reply with quantity (Example: 1 Kg)`; + } - const entry = req.body.entry?.[0]; - const changes = entry?.changes?.[0]; - const value = changes?.value; - const messages = value?.messages; + // Option 5 - Subscription + else if (text === '5') { + reply = + `π *Daily Milk Subscription*\n\n` + + `β Morning delivery\n` + + `β Monthly billing\n` + + `β Fresh every day\n\n` + + `Reply *YES* to subscribe or *NO* to cancel.`; + } - if (messages && messages.length > 0) { - const from = messages[0].from; - const text = messages[0].text?.body; + // Option 6 - Talk to Owner + else if (text === '6') { + reply = + `π *Talk to Owner*\n\n` + + `Name: Bala\n` + + `Mobile: +91-XXXXXXXXXX\n\n` + + `Call anytime between 6 AM β 10 PM`; + } - console.log(`Message from ${from}: ${text}`); + // Invalid input + else { + reply = + `β Invalid option\n\n` + + `Please reply with:\n` + + `1οΈβ£ Buffalo Milk\n` + + `2οΈβ£ Cow Milk\n` + + `3οΈβ£ Paneer\n` + + `4οΈβ£ Ghee\n` + + `5οΈβ£ Subscription\n` + + `6οΈβ£ Talk to Owner`; + } - // Auto-reply + // Send WhatsApp message await fetch( `https://graph.facebook.com/v19.0/${process.env.PHONE_NUMBER_ID}/messages`, { @@ -61,18 +108,14 @@ app.post('/webhook', async (req, res) => { body: JSON.stringify({ messaging_product: 'whatsapp', to: from, - text: { body: 'π Hello! Your message has been received successfully.' } + text: { body: reply } }) } ); - } - - res.sendStatus(200); -}); -// Start server -const server = app.listen(port, () => { - console.log(`Server running on port ${port}`); + res.sendStatus(200); + } catch (err) { + console.error('Webhook Error:', err); + res.sendStatus(500); + } }); - -server.keepAliveTimeout = 95 * 1000; From 56fd0a8d43f34101f1e4c0ed31b535ecd14458ac Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Fri, 2 Jan 2026 13:38:06 +0530 Subject: [PATCH 09/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 212 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 118 insertions(+), 94 deletions(-) diff --git a/index.js b/index.js index 631f6c2e25..2dc87dca56 100644 --- a/index.js +++ b/index.js @@ -1,121 +1,145 @@ +const express = require('express'); + +const app = express(); +const PORT = process.env.PORT || 5000; + +// ====== Middleware ====== +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); + +// ====== Root check ====== +app.get('/', (req, res) => { + res.send('Bala Milk Store WhatsApp Bot is running β '); +}); + +// ====== WhatsApp Webhook ====== app.post('/webhook', async (req, res) => { try { const entry = req.body.entry?.[0]; const changes = entry?.changes?.[0]; const value = changes?.value; - const messages = value?.messages; + const messages = value?.messages?.[0]; + // If no message, return OK if (!messages) { return res.sendStatus(200); } - const from = messages[0].from; - const text = messages[0].text?.body?.trim(); + const from = messages.from; // customer WhatsApp number + const text = messages.text?.body?.trim(); + + console.log('From:', from); + console.log('Message:', text); let reply = ''; - // Greeting / Menu - if (!text || ['hi', 'hello', 'menu'].includes(text.toLowerCase())) { - reply = - `Welcome to *Bala Milk Store* π₯\n\n` + - `Please choose an option:\n` + - `1οΈβ£ Buffalo Milk β βΉ100/L\n` + - `2οΈβ£ Cow Milk β βΉ120/L\n` + - `3οΈβ£ Paneer β βΉ600/Kg\n` + - `4οΈβ£ Ghee β βΉ1000/Kg\n` + - `5οΈβ£ Daily Milk Subscription\n` + - `6οΈβ£ Talk to Owner\n\n` + - `Reply with the option number.`; - } + switch (text) { + case '1': + reply = `π₯ *Buffalo Milk* +Price: βΉ100 / Litre +Fresh & Pure - // Option 1 - Buffalo Milk - else if (text === '1') { - reply = - `π₯ *Buffalo Milk*\n\n` + - `Price: βΉ100 per liter\n` + - `Fresh & Pure\n\n` + - `Reply with quantity in liters (Example: 2L)`; - } +Reply *ORDER* to place order`; + break; - // Option 2 - Cow Milk - else if (text === '2') { - reply = - `π₯ *Cow Milk*\n\n` + - `Price: βΉ120 per liter\n` + - `Healthy & Natural\n\n` + - `Reply with quantity in liters (Example: 1L)`; - } + case '2': + reply = `π₯ *Cow Milk* +Price: βΉ120 / Litre +Healthy & Fresh - // Option 3 - Paneer - else if (text === '3') { - reply = - `π§ *Paneer*\n\n` + - `Price: βΉ600 per Kg\n` + - `Fresh homemade paneer\n\n` + - `Reply with quantity (Example: 0.5 Kg)`; - } +Reply *ORDER* to place order`; + break; - // Option 4 - Ghee - else if (text === '4') { - reply = - `π« *Pure Ghee*\n\n` + - `Price: βΉ1000 per Kg\n` + - `Traditional & aromatic\n\n` + - `Reply with quantity (Example: 1 Kg)`; - } + case '3': + reply = `π§ *Paneer* +Price: βΉ600 / Kg +Fresh Homemade Paneer - // Option 5 - Subscription - else if (text === '5') { - reply = - `π *Daily Milk Subscription*\n\n` + - `β Morning delivery\n` + - `β Monthly billing\n` + - `β Fresh every day\n\n` + - `Reply *YES* to subscribe or *NO* to cancel.`; - } +Reply *ORDER* to place order`; + break; - // Option 6 - Talk to Owner - else if (text === '6') { - reply = - `π *Talk to Owner*\n\n` + - `Name: Bala\n` + - `Mobile: +91-XXXXXXXXXX\n\n` + - `Call anytime between 6 AM β 10 PM`; - } + case '4': + reply = `π§ *Ghee* +Price: βΉ1000 / Kg +Pure Desi Ghee - // Invalid input - else { - reply = - `β Invalid option\n\n` + - `Please reply with:\n` + - `1οΈβ£ Buffalo Milk\n` + - `2οΈβ£ Cow Milk\n` + - `3οΈβ£ Paneer\n` + - `4οΈβ£ Ghee\n` + - `5οΈβ£ Subscription\n` + - `6οΈβ£ Talk to Owner`; +Reply *ORDER* to place order`; + break; + + case '5': + reply = `π¦ *Daily Milk Subscription* +β Morning delivery +β Monthly billing + +Reply *SUBSCRIBE* to continue`; + break; + + case '6': + reply = `π *Talk to Owner* +Please call: 9XXXXXXXXX`; + break; + + case 'ORDER': + reply = `β Thank you! +Please reply with: +Product name +Quantity +Delivery address`; + break; + + case 'SUBSCRIBE': + reply = `π Subscription details: +Milk type: +Quantity per day: +Address:`; + break; + + default: + reply = `Welcome to *Bala Milk Store* π₯ + +Please choose an option: +1οΈβ£ Buffalo Milk β βΉ100/L +2οΈβ£ Cow Milk β βΉ120/L +3οΈβ£ Paneer β βΉ600/Kg +4οΈβ£ Ghee β βΉ1000/Kg +5οΈβ£ Daily Milk Subscription +6οΈβ£ Talk to Owner + +Reply with the option number.`; } - // Send WhatsApp message - await fetch( - `https://graph.facebook.com/v19.0/${process.env.PHONE_NUMBER_ID}/messages`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${process.env.WHATSAPP_TOKEN}` - }, - body: JSON.stringify({ - messaging_product: 'whatsapp', - to: from, - text: { body: reply } - }) - } - ); + // ====== Send reply to WhatsApp ====== + await sendWhatsAppMessage(from, reply); res.sendStatus(200); - } catch (err) { - console.error('Webhook Error:', err); + } catch (error) { + console.error('Webhook error:', error); res.sendStatus(500); } }); + +// ====== Send message function ====== +async function sendWhatsAppMessage(to, message) { + const token = process.env.WHATSAPP_TOKEN; + const phoneNumberId = process.env.PHONE_NUMBER_ID; + + const url = `https://graph.facebook.com/v19.0/${phoneNumberId}/messages`; + + await fetch(url, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + messaging_product: 'whatsapp', + to: to, + text: { body: message } + }) + }); +} + +// ====== Start Server ====== +app.listen(PORT, () => { + console.log(`Server started on port ${PORT}`); +}); From 5c8ccdc2a6c3c6eef321d70b65fe0f33ad1ae96c Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Fri, 2 Jan 2026 14:03:10 +0530 Subject: [PATCH 10/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 185 +++++++++++++++++-------------------------------------- 1 file changed, 58 insertions(+), 127 deletions(-) diff --git a/index.js b/index.js index 2dc87dca56..26fb1384ef 100644 --- a/index.js +++ b/index.js @@ -1,145 +1,76 @@ const express = require('express'); +const axios = require('axios'); const app = express(); -const PORT = process.env.PORT || 5000; - -// ====== Middleware ====== app.use(express.json()); -app.use(express.urlencoded({ extended: true })); - -// ====== Root check ====== -app.get('/', (req, res) => { - res.send('Bala Milk Store WhatsApp Bot is running β '); -}); - -// ====== WhatsApp Webhook ====== -app.post('/webhook', async (req, res) => { - try { - const entry = req.body.entry?.[0]; - const changes = entry?.changes?.[0]; - const value = changes?.value; - const messages = value?.messages?.[0]; - - // If no message, return OK - if (!messages) { - return res.sendStatus(200); - } - - const from = messages.from; // customer WhatsApp number - const text = messages.text?.body?.trim(); - - console.log('From:', from); - console.log('Message:', text); - - let reply = ''; - - switch (text) { - case '1': - reply = `π₯ *Buffalo Milk* -Price: βΉ100 / Litre -Fresh & Pure - -Reply *ORDER* to place order`; - break; - - case '2': - reply = `π₯ *Cow Milk* -Price: βΉ120 / Litre -Healthy & Fresh - -Reply *ORDER* to place order`; - break; - case '3': - reply = `π§ *Paneer* -Price: βΉ600 / Kg -Fresh Homemade Paneer +const PORT = process.env.PORT || 10000; -Reply *ORDER* to place order`; - break; +// ENV variables (must be set in Render) +const TOKEN = process.env.WHATSAPP_TOKEN; +const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID; - case '4': - reply = `π§ *Ghee* -Price: βΉ1000 / Kg -Pure Desi Ghee +// Webhook verification +app.get('/webhook', (req, res) => { + const VERIFY_TOKEN = process.env.VERIFY_TOKEN; -Reply *ORDER* to place order`; - break; + const mode = req.query['hub.mode']; + const token = req.query['hub.verify_token']; + const challenge = req.query['hub.challenge']; - case '5': - reply = `π¦ *Daily Milk Subscription* -β Morning delivery -β Monthly billing - -Reply *SUBSCRIBE* to continue`; - break; - - case '6': - reply = `π *Talk to Owner* -Please call: 9XXXXXXXXX`; - break; - - case 'ORDER': - reply = `β Thank you! -Please reply with: -Product name -Quantity -Delivery address`; - break; - - case 'SUBSCRIBE': - reply = `π Subscription details: -Milk type: -Quantity per day: -Address:`; - break; - - default: - reply = `Welcome to *Bala Milk Store* π₯ - -Please choose an option: -1οΈβ£ Buffalo Milk β βΉ100/L -2οΈβ£ Cow Milk β βΉ120/L -3οΈβ£ Paneer β βΉ600/Kg -4οΈβ£ Ghee β βΉ1000/Kg -5οΈβ£ Daily Milk Subscription -6οΈβ£ Talk to Owner - -Reply with the option number.`; - } + if (mode === 'subscribe' && token === VERIFY_TOKEN) { + return res.status(200).send(challenge); + } + return res.sendStatus(403); +}); - // ====== Send reply to WhatsApp ====== - await sendWhatsAppMessage(from, reply); +// Receive messages +app.post('/webhook', async (req, res) => { + try { + const entry = req.body.entry?.[0]; + const change = entry?.changes?.[0]; + const message = change?.value?.messages?.[0]; + + if (!message) return res.sendStatus(200); + + const from = message.from; + const text = message.text?.body; + + console.log("From:", from); + console.log("Message:", text); + + let reply = "Welcome to Bala Milk Store π₯\n\nReply:\n1οΈβ£ Buffalo Milk\n2οΈβ£ Cow Milk\n3οΈβ£ Paneer\n4οΈβ£ Ghee\n5οΈβ£ Subscription\n6οΈβ£ Talk to Owner"; + + if (text === "1") reply = "π₯ Buffalo Milk β βΉ100/L"; + else if (text === "2") reply = "π Cow Milk β βΉ120/L"; + else if (text === "3") reply = "π§ Paneer β βΉ600/Kg"; + else if (text === "4") reply = "π§ Ghee β βΉ1000/Kg"; + else if (text === "5") reply = "π Daily Milk Subscription β Please share quantity"; + else if (text === "6") reply = "π Owner will contact you shortly"; + + // SEND MESSAGE TO WHATSAPP + await axios.post( + `https://graph.facebook.com/v19.0/${PHONE_NUMBER_ID}/messages`, + { + messaging_product: "whatsapp", + to: from, + text: { body: reply } + }, + { + headers: { + Authorization: `Bearer ${TOKEN}`, + "Content-Type": "application/json" + } + } + ); res.sendStatus(200); - } catch (error) { - console.error('Webhook error:', error); + } catch (err) { + console.error("Error:", err.response?.data || err.message); res.sendStatus(500); } }); -// ====== Send message function ====== -async function sendWhatsAppMessage(to, message) { - const token = process.env.WHATSAPP_TOKEN; - const phoneNumberId = process.env.PHONE_NUMBER_ID; - - const url = `https://graph.facebook.com/v19.0/${phoneNumberId}/messages`; - - await fetch(url, { - method: 'POST', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - messaging_product: 'whatsapp', - to: to, - text: { body: message } - }) - }); -} - -// ====== Start Server ====== app.listen(PORT, () => { - console.log(`Server started on port ${PORT}`); + console.log(`Server running on port ${PORT}`); }); From 38a8c0a357d3e57da2d2a137bff204812b413d4d Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Fri, 2 Jan 2026 14:25:47 +0530 Subject: [PATCH 11/30] Update package.json Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 4893c4ab02..b584d5e5b7 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,10 @@ "start": "node index.js", "test": "jest" }, - "dependencies": { - "ejs": "^3.1.10", - "express": "^5.2.1" + "dependencies": { + "ejs": "^3.1.9", + "express": "^5.0.1", + "axios": "^1.6.8" }, "devDependencies": { "jest": "^30.2.0" From 3e04fb76de32f1c5fc4332a9c233a64395981ca9 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 19:50:46 +0530 Subject: [PATCH 12/30] Update package.json Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- package.json | 157 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 126 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index b584d5e5b7..b86c2ca582 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,126 @@ -{ - "name": "nodejs-getting-started", - "private": true, - "description": "A sample Node.js app using Express", - "engines": { - "node": "20.x || 22.x || 24.x" - }, - "main": "index.js", - "scripts": { - "start": "node index.js", - "test": "jest" - }, - "dependencies": { - "ejs": "^3.1.9", - "express": "^5.0.1", - "axios": "^1.6.8" - }, - "devDependencies": { - "jest": "^30.2.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/heroku/nodejs-getting-started" - }, - "keywords": [ - "node", - "heroku", - "express" - ], - "license": "MIT" -} +const express = require("express"); +const axios = require("axios"); + +const app = express(); + +// Render / Express config +app.use(express.json()); + +const PORT = process.env.PORT || 10000; + +// ENV variables (set in Render) +const WHATSAPP_TOKEN = process.env.WHATSAPP_TOKEN; +const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID; +const VERIFY_TOKEN = process.env.VERIFY_TOKEN || "bala_verify_token"; + +// --------------------------- +// 1οΈβ£ Webhook Verification (GET) +// --------------------------- +app.get("/webhook", (req, res) => { + const mode = req.query["hub.mode"]; + const token = req.query["hub.verify_token"]; + const challenge = req.query["hub.challenge"]; + + if (mode === "subscribe" && token === VERIFY_TOKEN) { + console.log("β Webhook verified"); + res.status(200).send(challenge); + } else { + res.sendStatus(403); + } +}); + +// --------------------------- +// 2οΈβ£ Receive WhatsApp Messages (POST) +// --------------------------- +app.post("/webhook", async (req, res) => { + try { + const entry = req.body.entry?.[0]; + const changes = entry?.changes?.[0]; + const value = changes?.value; + const message = value?.messages?.[0]; + + if (!message) { + return res.sendStatus(200); + } + + const from = message.from; // user phone number + const text = message.text?.body?.trim(); + + console.log("π© From:", from); + console.log("π¬ Message:", text); + + let reply = ""; + + switch (text) { + case "1": + reply = "π₯ *Buffalo Milk*\nβΉ100 per litre\nFresh & daily supply."; + break; + case "2": + reply = "π *Cow Milk*\nβΉ120 per litre\nPure & hygienic."; + break; + case "3": + reply = "π§ *Paneer*\nβΉ600 per Kg\nFresh homemade paneer."; + break; + case "4": + reply = "π§ *Ghee*\nβΉ1000 per Kg\nTraditional & pure."; + break; + case "5": + reply = + "π *Daily Milk Subscription*\nReply YES to start subscription."; + break; + case "6": + reply = + "π *Talk to Owner*\nCall or WhatsApp: +91 81218 93882"; + break; + default: + reply = + "π *Welcome to Bala Milk Store π₯*\n\n" + + "Please choose an option:\n" + + "1οΈβ£ Buffalo Milk β βΉ100/L\n" + + "2οΈβ£ Cow Milk β βΉ120/L\n" + + "3οΈβ£ Paneer β βΉ600/Kg\n" + + "4οΈβ£ Ghee β βΉ1000/Kg\n" + + "5οΈβ£ Daily Milk Subscription\n" + + "6οΈβ£ Talk to Owner\n\n" + + "Reply with the option number."; + } + + // --------------------------- + // 3οΈβ£ Send WhatsApp Reply + // --------------------------- + await axios.post( + `https://graph.facebook.com/v19.0/${PHONE_NUMBER_ID}/messages`, + { + messaging_product: "whatsapp", + to: from, + text: { body: reply }, + }, + { + headers: { + Authorization: `Bearer ${WHATSAPP_TOKEN}`, + "Content-Type": "application/json", + }, + } + ); + + console.log("β Reply sent"); + res.sendStatus(200); + } catch (error) { + console.error("β Error:", error.response?.data || error.message); + res.sendStatus(200); + } +}); + +// --------------------------- +// 4οΈβ£ Health Check +// --------------------------- +app.get("/", (req, res) => { + res.send("β Bala Milk Store WhatsApp Bot is running"); +}); + +// --------------------------- +// Start Server +// --------------------------- +app.listen(PORT, () => { + console.log(`π Server running on port ${PORT}`); +}); From 6a346c100c449dd722ead9575e07b409dfc301cc Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 19:52:02 +0530 Subject: [PATCH 13/30] Update package.json Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- package.json | 160 +++++++++++++-------------------------------------- 1 file changed, 40 insertions(+), 120 deletions(-) diff --git a/package.json b/package.json index b86c2ca582..649e7dd7ce 100644 --- a/package.json +++ b/package.json @@ -1,126 +1,46 @@ -const express = require("express"); -const axios = require("axios"); - -const app = express(); - -// Render / Express config -app.use(express.json()); - -const PORT = process.env.PORT || 10000; - -// ENV variables (set in Render) -const WHATSAPP_TOKEN = process.env.WHATSAPP_TOKEN; -const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID; -const VERIFY_TOKEN = process.env.VERIFY_TOKEN || "bala_verify_token"; - -// --------------------------- -// 1οΈβ£ Webhook Verification (GET) -// --------------------------- -app.get("/webhook", (req, res) => { - const mode = req.query["hub.mode"]; - const token = req.query["hub.verify_token"]; - const challenge = req.query["hub.challenge"]; - - if (mode === "subscribe" && token === VERIFY_TOKEN) { - console.log("β Webhook verified"); - res.status(200).send(challenge); - } else { - res.sendStatus(403); +const message = text.toLowerCase().trim(); +const from = phone; + +if (!userState[from]) { + userState[from] = {}; +} + +/* STEP A: MENU SELECTION */ +if (!userState[from].step) { + if (message === '1') { + userState[from] = { step: 'qty', product: 'Buffalo Milk', price: 100 }; + reply = 'π₯ Buffalo Milk selected.\nHow many liters?'; + } + else if (message === '2') { + userState[from] = { step: 'qty', product: 'Cow Milk', price: 120 }; + reply = 'π₯ Cow Milk selected.\nHow many liters?'; } -}); - -// --------------------------- -// 2οΈβ£ Receive WhatsApp Messages (POST) -// --------------------------- -app.post("/webhook", async (req, res) => { - try { - const entry = req.body.entry?.[0]; - const changes = entry?.changes?.[0]; - const value = changes?.value; - const message = value?.messages?.[0]; - - if (!message) { - return res.sendStatus(200); - } - - const from = message.from; // user phone number - const text = message.text?.body?.trim(); - - console.log("π© From:", from); - console.log("π¬ Message:", text); + else { + reply = `Welcome to Bala Milk Store π₯ +1οΈβ£ Buffalo Milk β βΉ100/L +2οΈβ£ Cow Milk β βΉ120/L +3οΈβ£ Paneer β βΉ600/Kg +4οΈβ£ Ghee β βΉ1000/Kg +Reply with option number.`; + } +} - let reply = ""; +/* STEP B: QUANTITY */ +else if (userState[from].step === 'qty') { + const qty = parseInt(message); + if (isNaN(qty) || qty <= 0) { + reply = 'Please enter a valid quantity.'; + } else { + const total = qty * userState[from].price; - switch (text) { - case "1": - reply = "π₯ *Buffalo Milk*\nβΉ100 per litre\nFresh & daily supply."; - break; - case "2": - reply = "π *Cow Milk*\nβΉ120 per litre\nPure & hygienic."; - break; - case "3": - reply = "π§ *Paneer*\nβΉ600 per Kg\nFresh homemade paneer."; - break; - case "4": - reply = "π§ *Ghee*\nβΉ1000 per Kg\nTraditional & pure."; - break; - case "5": - reply = - "π *Daily Milk Subscription*\nReply YES to start subscription."; - break; - case "6": - reply = - "π *Talk to Owner*\nCall or WhatsApp: +91 81218 93882"; - break; - default: - reply = - "π *Welcome to Bala Milk Store π₯*\n\n" + - "Please choose an option:\n" + - "1οΈβ£ Buffalo Milk β βΉ100/L\n" + - "2οΈβ£ Cow Milk β βΉ120/L\n" + - "3οΈβ£ Paneer β βΉ600/Kg\n" + - "4οΈβ£ Ghee β βΉ1000/Kg\n" + - "5οΈβ£ Daily Milk Subscription\n" + - "6οΈβ£ Talk to Owner\n\n" + - "Reply with the option number."; - } + reply = `β Order Confirmed +Product: ${userState[from].product} +Quantity: ${qty} +Total: βΉ${total} - // --------------------------- - // 3οΈβ£ Send WhatsApp Reply - // --------------------------- - await axios.post( - `https://graph.facebook.com/v19.0/${PHONE_NUMBER_ID}/messages`, - { - messaging_product: "whatsapp", - to: from, - text: { body: reply }, - }, - { - headers: { - Authorization: `Bearer ${WHATSAPP_TOKEN}`, - "Content-Type": "application/json", - }, - } - ); +Thank you! π`; - console.log("β Reply sent"); - res.sendStatus(200); - } catch (error) { - console.error("β Error:", error.response?.data || error.message); - res.sendStatus(200); + // store order later (Google Sheets) + userState[from] = {}; // reset } -}); - -// --------------------------- -// 4οΈβ£ Health Check -// --------------------------- -app.get("/", (req, res) => { - res.send("β Bala Milk Store WhatsApp Bot is running"); -}); - -// --------------------------- -// Start Server -// --------------------------- -app.listen(PORT, () => { - console.log(`π Server running on port ${PORT}`); -}); +} From 4b47e2970f111ada94297bdcf294676ff92331dd Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 19:53:25 +0530 Subject: [PATCH 14/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 128 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 89 insertions(+), 39 deletions(-) diff --git a/index.js b/index.js index 26fb1384ef..b86c2ca582 100644 --- a/index.js +++ b/index.js @@ -1,76 +1,126 @@ -const express = require('express'); -const axios = require('axios'); +const express = require("express"); +const axios = require("axios"); const app = express(); + +// Render / Express config app.use(express.json()); const PORT = process.env.PORT || 10000; -// ENV variables (must be set in Render) -const TOKEN = process.env.WHATSAPP_TOKEN; +// ENV variables (set in Render) +const WHATSAPP_TOKEN = process.env.WHATSAPP_TOKEN; const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID; +const VERIFY_TOKEN = process.env.VERIFY_TOKEN || "bala_verify_token"; -// Webhook verification -app.get('/webhook', (req, res) => { - const VERIFY_TOKEN = process.env.VERIFY_TOKEN; - - const mode = req.query['hub.mode']; - const token = req.query['hub.verify_token']; - const challenge = req.query['hub.challenge']; +// --------------------------- +// 1οΈβ£ Webhook Verification (GET) +// --------------------------- +app.get("/webhook", (req, res) => { + const mode = req.query["hub.mode"]; + const token = req.query["hub.verify_token"]; + const challenge = req.query["hub.challenge"]; - if (mode === 'subscribe' && token === VERIFY_TOKEN) { - return res.status(200).send(challenge); + if (mode === "subscribe" && token === VERIFY_TOKEN) { + console.log("β Webhook verified"); + res.status(200).send(challenge); + } else { + res.sendStatus(403); } - return res.sendStatus(403); }); -// Receive messages -app.post('/webhook', async (req, res) => { +// --------------------------- +// 2οΈβ£ Receive WhatsApp Messages (POST) +// --------------------------- +app.post("/webhook", async (req, res) => { try { const entry = req.body.entry?.[0]; - const change = entry?.changes?.[0]; - const message = change?.value?.messages?.[0]; + const changes = entry?.changes?.[0]; + const value = changes?.value; + const message = value?.messages?.[0]; - if (!message) return res.sendStatus(200); + if (!message) { + return res.sendStatus(200); + } - const from = message.from; - const text = message.text?.body; + const from = message.from; // user phone number + const text = message.text?.body?.trim(); - console.log("From:", from); - console.log("Message:", text); + console.log("π© From:", from); + console.log("π¬ Message:", text); - let reply = "Welcome to Bala Milk Store π₯\n\nReply:\n1οΈβ£ Buffalo Milk\n2οΈβ£ Cow Milk\n3οΈβ£ Paneer\n4οΈβ£ Ghee\n5οΈβ£ Subscription\n6οΈβ£ Talk to Owner"; + let reply = ""; - if (text === "1") reply = "π₯ Buffalo Milk β βΉ100/L"; - else if (text === "2") reply = "π Cow Milk β βΉ120/L"; - else if (text === "3") reply = "π§ Paneer β βΉ600/Kg"; - else if (text === "4") reply = "π§ Ghee β βΉ1000/Kg"; - else if (text === "5") reply = "π Daily Milk Subscription β Please share quantity"; - else if (text === "6") reply = "π Owner will contact you shortly"; + switch (text) { + case "1": + reply = "π₯ *Buffalo Milk*\nβΉ100 per litre\nFresh & daily supply."; + break; + case "2": + reply = "π *Cow Milk*\nβΉ120 per litre\nPure & hygienic."; + break; + case "3": + reply = "π§ *Paneer*\nβΉ600 per Kg\nFresh homemade paneer."; + break; + case "4": + reply = "π§ *Ghee*\nβΉ1000 per Kg\nTraditional & pure."; + break; + case "5": + reply = + "π *Daily Milk Subscription*\nReply YES to start subscription."; + break; + case "6": + reply = + "π *Talk to Owner*\nCall or WhatsApp: +91 81218 93882"; + break; + default: + reply = + "π *Welcome to Bala Milk Store π₯*\n\n" + + "Please choose an option:\n" + + "1οΈβ£ Buffalo Milk β βΉ100/L\n" + + "2οΈβ£ Cow Milk β βΉ120/L\n" + + "3οΈβ£ Paneer β βΉ600/Kg\n" + + "4οΈβ£ Ghee β βΉ1000/Kg\n" + + "5οΈβ£ Daily Milk Subscription\n" + + "6οΈβ£ Talk to Owner\n\n" + + "Reply with the option number."; + } - // SEND MESSAGE TO WHATSAPP + // --------------------------- + // 3οΈβ£ Send WhatsApp Reply + // --------------------------- await axios.post( `https://graph.facebook.com/v19.0/${PHONE_NUMBER_ID}/messages`, { messaging_product: "whatsapp", to: from, - text: { body: reply } + text: { body: reply }, }, { headers: { - Authorization: `Bearer ${TOKEN}`, - "Content-Type": "application/json" - } + Authorization: `Bearer ${WHATSAPP_TOKEN}`, + "Content-Type": "application/json", + }, } ); + console.log("β Reply sent"); + res.sendStatus(200); + } catch (error) { + console.error("β Error:", error.response?.data || error.message); res.sendStatus(200); - } catch (err) { - console.error("Error:", err.response?.data || err.message); - res.sendStatus(500); } }); +// --------------------------- +// 4οΈβ£ Health Check +// --------------------------- +app.get("/", (req, res) => { + res.send("β Bala Milk Store WhatsApp Bot is running"); +}); + +// --------------------------- +// Start Server +// --------------------------- app.listen(PORT, () => { - console.log(`Server running on port ${PORT}`); + console.log(`π Server running on port ${PORT}`); }); From 040bdf09b64a1de7be8cd62af79e1cce11ba0629 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 20:01:54 +0530 Subject: [PATCH 15/30] Update package.json Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- package.json | 58 +++++++++++++--------------------------------------- 1 file changed, 14 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 649e7dd7ce..5daa26c6e5 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,16 @@ -const message = text.toLowerCase().trim(); -const from = phone; - -if (!userState[from]) { - userState[from] = {}; -} - -/* STEP A: MENU SELECTION */ -if (!userState[from].step) { - if (message === '1') { - userState[from] = { step: 'qty', product: 'Buffalo Milk', price: 100 }; - reply = 'π₯ Buffalo Milk selected.\nHow many liters?'; - } - else if (message === '2') { - userState[from] = { step: 'qty', product: 'Cow Milk', price: 120 }; - reply = 'π₯ Cow Milk selected.\nHow many liters?'; - } - else { - reply = `Welcome to Bala Milk Store π₯ -1οΈβ£ Buffalo Milk β βΉ100/L -2οΈβ£ Cow Milk β βΉ120/L -3οΈβ£ Paneer β βΉ600/Kg -4οΈβ£ Ghee β βΉ1000/Kg -Reply with option number.`; - } -} - -/* STEP B: QUANTITY */ -else if (userState[from].step === 'qty') { - const qty = parseInt(message); - if (isNaN(qty) || qty <= 0) { - reply = 'Please enter a valid quantity.'; - } else { - const total = qty * userState[from].price; - - reply = `β Order Confirmed -Product: ${userState[from].product} -Quantity: ${qty} -Total: βΉ${total} - -Thank you! π`; - - // store order later (Google Sheets) - userState[from] = {}; // reset +{ + "name": "bala-whatsapp-bot", + "version": "1.0.0", + "description": "WhatsApp Cloud API bot for Bala Milk Store", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "engines": { + "node": ">=18" + }, + "dependencies": { + "axios": "^1.6.2", + "express": "^4.18.2" } } From 6dd575ed90fcba7b53a834493b6ec3d1077b5c32 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 20:02:19 +0530 Subject: [PATCH 16/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 84 ++++++++++++++++++++++---------------------------------- 1 file changed, 33 insertions(+), 51 deletions(-) diff --git a/index.js b/index.js index b86c2ca582..cc0f35a574 100644 --- a/index.js +++ b/index.js @@ -2,20 +2,18 @@ const express = require("express"); const axios = require("axios"); const app = express(); - -// Render / Express config app.use(express.json()); const PORT = process.env.PORT || 10000; -// ENV variables (set in Render) +// ENV variables (Render) const WHATSAPP_TOKEN = process.env.WHATSAPP_TOKEN; const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID; const VERIFY_TOKEN = process.env.VERIFY_TOKEN || "bala_verify_token"; -// --------------------------- -// 1οΈβ£ Webhook Verification (GET) -// --------------------------- +// -------------------- +// Webhook verification +// -------------------- app.get("/webhook", (req, res) => { const mode = req.query["hub.mode"]; const token = req.query["hub.verify_token"]; @@ -23,104 +21,88 @@ app.get("/webhook", (req, res) => { if (mode === "subscribe" && token === VERIFY_TOKEN) { console.log("β Webhook verified"); - res.status(200).send(challenge); - } else { - res.sendStatus(403); + return res.status(200).send(challenge); } + return res.sendStatus(403); }); -// --------------------------- -// 2οΈβ£ Receive WhatsApp Messages (POST) -// --------------------------- +// -------------------- +// Receive messages +// -------------------- app.post("/webhook", async (req, res) => { try { - const entry = req.body.entry?.[0]; - const changes = entry?.changes?.[0]; - const value = changes?.value; - const message = value?.messages?.[0]; + const message = + req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; - if (!message) { - return res.sendStatus(200); - } + if (!message) return res.sendStatus(200); - const from = message.from; // user phone number + const from = message.from; const text = message.text?.body?.trim(); console.log("π© From:", from); console.log("π¬ Message:", text); - let reply = ""; + let reply; switch (text) { case "1": - reply = "π₯ *Buffalo Milk*\nβΉ100 per litre\nFresh & daily supply."; + reply = "π₯ *Buffalo Milk*\nβΉ100 per litre"; break; case "2": - reply = "π *Cow Milk*\nβΉ120 per litre\nPure & hygienic."; + reply = "π *Cow Milk*\nβΉ120 per litre"; break; case "3": - reply = "π§ *Paneer*\nβΉ600 per Kg\nFresh homemade paneer."; + reply = "π§ *Paneer*\nβΉ600 per Kg"; break; case "4": - reply = "π§ *Ghee*\nβΉ1000 per Kg\nTraditional & pure."; + reply = "π§ *Ghee*\nβΉ1000 per Kg"; break; case "5": - reply = - "π *Daily Milk Subscription*\nReply YES to start subscription."; + reply = "π Daily milk subscription\nReply YES to continue"; break; case "6": - reply = - "π *Talk to Owner*\nCall or WhatsApp: +91 81218 93882"; + reply = "π Owner: +91 81218 93882"; break; default: reply = "π *Welcome to Bala Milk Store π₯*\n\n" + - "Please choose an option:\n" + - "1οΈβ£ Buffalo Milk β βΉ100/L\n" + - "2οΈβ£ Cow Milk β βΉ120/L\n" + - "3οΈβ£ Paneer β βΉ600/Kg\n" + - "4οΈβ£ Ghee β βΉ1000/Kg\n" + - "5οΈβ£ Daily Milk Subscription\n" + + "1οΈβ£ Buffalo Milk\n" + + "2οΈβ£ Cow Milk\n" + + "3οΈβ£ Paneer\n" + + "4οΈβ£ Ghee\n" + + "5οΈβ£ Subscription\n" + "6οΈβ£ Talk to Owner\n\n" + - "Reply with the option number."; + "Reply with option number"; } - // --------------------------- - // 3οΈβ£ Send WhatsApp Reply - // --------------------------- await axios.post( `https://graph.facebook.com/v19.0/${PHONE_NUMBER_ID}/messages`, { messaging_product: "whatsapp", to: from, - text: { body: reply }, + text: { body: reply } }, { headers: { Authorization: `Bearer ${WHATSAPP_TOKEN}`, - "Content-Type": "application/json", - }, + "Content-Type": "application/json" + } } ); console.log("β Reply sent"); res.sendStatus(200); - } catch (error) { - console.error("β Error:", error.response?.data || error.message); + } catch (err) { + console.error("β Error:", err.response?.data || err.message); res.sendStatus(200); } }); -// --------------------------- -// 4οΈβ£ Health Check -// --------------------------- +// -------------------- app.get("/", (req, res) => { - res.send("β Bala Milk Store WhatsApp Bot is running"); + res.send("β Bala WhatsApp Bot is running"); }); -// --------------------------- -// Start Server -// --------------------------- app.listen(PORT, () => { console.log(`π Server running on port ${PORT}`); }); From d7163177c4d8f3d9cbb71a984cb10196b660a13c Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 20:51:02 +0530 Subject: [PATCH 17/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 125 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 48 deletions(-) diff --git a/index.js b/index.js index cc0f35a574..3c557689a0 100644 --- a/index.js +++ b/index.js @@ -4,105 +4,134 @@ const axios = require("axios"); const app = express(); app.use(express.json()); -const PORT = process.env.PORT || 10000; +const PORT = process.env.PORT || 3000; -// ENV variables (Render) -const WHATSAPP_TOKEN = process.env.WHATSAPP_TOKEN; -const PHONE_NUMBER_ID = process.env.PHONE_NUMBER_ID; -const VERIFY_TOKEN = process.env.VERIFY_TOKEN || "bala_verify_token"; - -// -------------------- -// Webhook verification -// -------------------- +// =============================== +// WEBHOOK VERIFICATION (META) +// =============================== app.get("/webhook", (req, res) => { + const VERIFY_TOKEN = process.env.VERIFY_TOKEN; + const mode = req.query["hub.mode"]; const token = req.query["hub.verify_token"]; const challenge = req.query["hub.challenge"]; if (mode === "subscribe" && token === VERIFY_TOKEN) { console.log("β Webhook verified"); - return res.status(200).send(challenge); + res.status(200).send(challenge); + } else { + res.sendStatus(403); } - return res.sendStatus(403); }); -// -------------------- -// Receive messages -// -------------------- +// =============================== +// RECEIVE WHATSAPP MESSAGE +// =============================== app.post("/webhook", async (req, res) => { try { - const message = - req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; + const entry = req.body.entry?.[0]; + const changes = entry?.changes?.[0]; + const value = changes?.value; + const message = value?.messages?.[0]; - if (!message) return res.sendStatus(200); + if (!message) { + return res.sendStatus(200); + } - const from = message.from; + const from = message.from; // customer phone const text = message.text?.body?.trim(); - console.log("π© From:", from); - console.log("π¬ Message:", text); + console.log("π© From:", from, "Message:", text); - let reply; + // =============================== + // MENU LOGIC + // =============================== + let replyText = ""; + let product = ""; switch (text) { case "1": - reply = "π₯ *Buffalo Milk*\nβΉ100 per litre"; + product = "Buffalo Milk"; + replyText = "π₯ Buffalo Milk selected\nPrice: βΉ100/L\nThank you for your order!"; break; + case "2": - reply = "π *Cow Milk*\nβΉ120 per litre"; + product = "Cow Milk"; + replyText = "π₯ Cow Milk selected\nPrice: βΉ120/L\nThank you for your order!"; break; + case "3": - reply = "π§ *Paneer*\nβΉ600 per Kg"; + product = "Paneer"; + replyText = "π§ Paneer selected\nPrice: βΉ600/Kg\nThank you for your order!"; break; + case "4": - reply = "π§ *Ghee*\nβΉ1000 per Kg"; + product = "Ghee"; + replyText = "π§ Ghee selected\nPrice: βΉ1000/Kg\nThank you for your order!"; break; + case "5": - reply = "π Daily milk subscription\nReply YES to continue"; + replyText = "π Daily Milk Subscription\nOwner will contact you shortly."; + product = "Subscription"; break; + case "6": - reply = "π Owner: +91 81218 93882"; + replyText = "π Owner will call you shortly.\nThank you!"; + product = "Talk to Owner"; break; + default: - reply = - "π *Welcome to Bala Milk Store π₯*\n\n" + - "1οΈβ£ Buffalo Milk\n" + - "2οΈβ£ Cow Milk\n" + - "3οΈβ£ Paneer\n" + - "4οΈβ£ Ghee\n" + - "5οΈβ£ Subscription\n" + + replyText = + "Welcome to *Bala Milk Store* π₯\n\n" + + "Please choose an option:\n" + + "1οΈβ£ Buffalo Milk β βΉ100/L\n" + + "2οΈβ£ Cow Milk β βΉ120/L\n" + + "3οΈβ£ Paneer β βΉ600/Kg\n" + + "4οΈβ£ Ghee β βΉ1000/Kg\n" + + "5οΈβ£ Daily Milk Subscription\n" + "6οΈβ£ Talk to Owner\n\n" + - "Reply with option number"; + "Reply with the option number."; + product = "Menu Shown"; } + // =============================== + // SAVE ORDER TO GOOGLE SHEET + // =============================== + await axios.post(process.env.GOOGLE_SHEET_URL, { + phone: from, + product: product, + quantity: 1, + message: text, + }); + + // =============================== + // SEND WHATSAPP REPLY + // =============================== await axios.post( - `https://graph.facebook.com/v19.0/${PHONE_NUMBER_ID}/messages`, + `https://graph.facebook.com/v18.0/${process.env.PHONE_NUMBER_ID}/messages`, { messaging_product: "whatsapp", to: from, - text: { body: reply } + text: { body: replyText }, }, { headers: { - Authorization: `Bearer ${WHATSAPP_TOKEN}`, - "Content-Type": "application/json" - } + Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`, + "Content-Type": "application/json", + }, } ); - console.log("β Reply sent"); res.sendStatus(200); - } catch (err) { - console.error("β Error:", err.response?.data || err.message); + } catch (error) { + console.error("β Error:", error.response?.data || error.message); res.sendStatus(200); } }); -// -------------------- -app.get("/", (req, res) => { - res.send("β Bala WhatsApp Bot is running"); -}); - +// =============================== +// SERVER START +// =============================== app.listen(PORT, () => { console.log(`π Server running on port ${PORT}`); }); From fbd9d25a8c367bc1a1fff321084a3fc90324cb7a Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 21:03:06 +0530 Subject: [PATCH 18/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 166 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 69 deletions(-) diff --git a/index.js b/index.js index 3c557689a0..82f39a8d7b 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,12 @@ app.use(express.json()); const PORT = process.env.PORT || 3000; // =============================== -// WEBHOOK VERIFICATION (META) +// TEMP SESSION STORAGE +// =============================== +const sessions = {}; + +// =============================== +// WEBHOOK VERIFY // =============================== app.get("/webhook", (req, res) => { const VERIFY_TOKEN = process.env.VERIFY_TOKEN; @@ -17,102 +22,127 @@ app.get("/webhook", (req, res) => { const challenge = req.query["hub.challenge"]; if (mode === "subscribe" && token === VERIFY_TOKEN) { - console.log("β Webhook verified"); - res.status(200).send(challenge); - } else { - res.sendStatus(403); + return res.status(200).send(challenge); } + res.sendStatus(403); }); // =============================== -// RECEIVE WHATSAPP MESSAGE +// WEBHOOK RECEIVE // =============================== app.post("/webhook", async (req, res) => { try { - const entry = req.body.entry?.[0]; - const changes = entry?.changes?.[0]; - const value = changes?.value; - const message = value?.messages?.[0]; - - if (!message) { - return res.sendStatus(200); - } + const message = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; + if (!message) return res.sendStatus(200); - const from = message.from; // customer phone + const from = message.from; const text = message.text?.body?.trim(); - console.log("π© From:", from, "Message:", text); + if (!sessions[from]) { + sessions[from] = { step: "MENU" }; + } + + let reply = ""; // =============================== - // MENU LOGIC + // STEP 1: MENU // =============================== - let replyText = ""; - let product = ""; - - switch (text) { - case "1": - product = "Buffalo Milk"; - replyText = "π₯ Buffalo Milk selected\nPrice: βΉ100/L\nThank you for your order!"; - break; - - case "2": - product = "Cow Milk"; - replyText = "π₯ Cow Milk selected\nPrice: βΉ120/L\nThank you for your order!"; - break; - - case "3": - product = "Paneer"; - replyText = "π§ Paneer selected\nPrice: βΉ600/Kg\nThank you for your order!"; - break; - - case "4": - product = "Ghee"; - replyText = "π§ Ghee selected\nPrice: βΉ1000/Kg\nThank you for your order!"; - break; - - case "5": - replyText = "π Daily Milk Subscription\nOwner will contact you shortly."; - product = "Subscription"; - break; - - case "6": - replyText = "π Owner will call you shortly.\nThank you!"; - product = "Talk to Owner"; - break; - - default: - replyText = + if (sessions[from].step === "MENU") { + if (["1", "2", "3", "4", "5", "6"].includes(text)) { + const products = { + "1": "Buffalo Milk", + "2": "Cow Milk", + "3": "Paneer", + "4": "Ghee", + "5": "Daily Milk Subscription", + "6": "Talk to Owner", + }; + + sessions[from].product = products[text]; + sessions[from].step = "QUANTITY"; + + reply = + `π *${products[text]} selected*\n\n` + + "Please select quantity:\n" + + "1οΈβ£ 1 Litre\n" + + "2οΈβ£ 2 Litres\n" + + "3οΈβ£ 3 Litres\n\n" + + "Reply with number."; + } else { + reply = "Welcome to *Bala Milk Store* π₯\n\n" + - "Please choose an option:\n" + "1οΈβ£ Buffalo Milk β βΉ100/L\n" + "2οΈβ£ Cow Milk β βΉ120/L\n" + "3οΈβ£ Paneer β βΉ600/Kg\n" + "4οΈβ£ Ghee β βΉ1000/Kg\n" + "5οΈβ£ Daily Milk Subscription\n" + "6οΈβ£ Talk to Owner\n\n" + - "Reply with the option number."; - product = "Menu Shown"; + "Reply with option number."; + } + } + + // =============================== + // STEP 2: QUANTITY + // =============================== + else if (sessions[from].step === "QUANTITY") { + const qtyMap = { "1": "1 Litre", "2": "2 Litres", "3": "3 Litres" }; + + if (!qtyMap[text]) { + reply = "β Invalid option.\nPlease reply 1 / 2 / 3"; + } else { + sessions[from].quantity = qtyMap[text]; + sessions[from].step = "ADDRESS"; + reply = "π Please send your *delivery address*."; + } + } + + // =============================== + // STEP 3: ADDRESS + // =============================== + else if (sessions[from].step === "ADDRESS") { + sessions[from].address = text; + sessions[from].step = "START_DATE"; + + reply = + "π From which date do you want milk?\n\n" + + "Example: *05-Jan-2026*"; } // =============================== - // SAVE ORDER TO GOOGLE SHEET + // STEP 4: START DATE // =============================== - await axios.post(process.env.GOOGLE_SHEET_URL, { - phone: from, - product: product, - quantity: 1, - message: text, - }); + else if (sessions[from].step === "START_DATE") { + sessions[from].startDate = text; + + // SAVE TO GOOGLE SHEET + await axios.post(process.env.GOOGLE_SHEET_URL, { + phone: from, + product: sessions[from].product, + quantity: sessions[from].quantity, + address: sessions[from].address, + startDate: sessions[from].startDate, + }); + + reply = + "β *Order Confirmed!*\n\n" + + `π₯ Product: ${sessions[from].product}\n` + + `π¦ Quantity: ${sessions[from].quantity}\n` + + `π Address: ${sessions[from].address}\n` + + `π Start Date: ${sessions[from].startDate}\n\n` + + "Thank you for choosing *Bala Milk Store* π"; + + delete sessions[from]; // clear session + } // =============================== - // SEND WHATSAPP REPLY + // SEND MESSAGE // =============================== await axios.post( `https://graph.facebook.com/v18.0/${process.env.PHONE_NUMBER_ID}/messages`, { messaging_product: "whatsapp", to: from, - text: { body: replyText }, + text: { body: reply }, }, { headers: { @@ -123,14 +153,12 @@ app.post("/webhook", async (req, res) => { ); res.sendStatus(200); - } catch (error) { - console.error("β Error:", error.response?.data || error.message); + } catch (err) { + console.error("Error:", err.message); res.sendStatus(200); } }); -// =============================== -// SERVER START // =============================== app.listen(PORT, () => { console.log(`π Server running on port ${PORT}`); From ea5b3a3eb5c680e65acc06d44775d6691ff56893 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 21:12:33 +0530 Subject: [PATCH 19/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 140 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 96 insertions(+), 44 deletions(-) diff --git a/index.js b/index.js index 82f39a8d7b..2c82c38248 100644 --- a/index.js +++ b/index.js @@ -15,14 +15,11 @@ const sessions = {}; // WEBHOOK VERIFY // =============================== app.get("/webhook", (req, res) => { - const VERIFY_TOKEN = process.env.VERIFY_TOKEN; - - const mode = req.query["hub.mode"]; - const token = req.query["hub.verify_token"]; - const challenge = req.query["hub.challenge"]; - - if (mode === "subscribe" && token === VERIFY_TOKEN) { - return res.status(200).send(challenge); + if ( + req.query["hub.mode"] === "subscribe" && + req.query["hub.verify_token"] === process.env.VERIFY_TOKEN + ) { + return res.status(200).send(req.query["hub.challenge"]); } res.sendStatus(403); }); @@ -37,10 +34,9 @@ app.post("/webhook", async (req, res) => { const from = message.from; const text = message.text?.body?.trim(); + const location = message.location; - if (!sessions[from]) { - sessions[from] = { step: "MENU" }; - } + if (!sessions[from]) sessions[from] = { step: "MENU" }; let reply = ""; @@ -48,25 +44,26 @@ app.post("/webhook", async (req, res) => { // STEP 1: MENU // =============================== if (sessions[from].step === "MENU") { - if (["1", "2", "3", "4", "5", "6"].includes(text)) { - const products = { - "1": "Buffalo Milk", - "2": "Cow Milk", - "3": "Paneer", - "4": "Ghee", - "5": "Daily Milk Subscription", - "6": "Talk to Owner", - }; - + const products = { + "1": "Buffalo Milk", + "2": "Cow Milk", + "3": "Paneer", + "4": "Ghee", + "5": "Daily Milk Subscription", + "6": "Talk to Owner", + }; + + if (products[text]) { sessions[from].product = products[text]; sessions[from].step = "QUANTITY"; reply = - `π *${products[text]} selected*\n\n` + - "Please select quantity:\n" + - "1οΈβ£ 1 Litre\n" + - "2οΈβ£ 2 Litres\n" + - "3οΈβ£ 3 Litres\n\n" + + `π₯ *${products[text]} selected*\n\n` + + "Choose quantity:\n" + + "1οΈβ£ 500 ml β βΉ50\n" + + "2οΈβ£ 1 L β βΉ100\n" + + "3οΈβ£ 2 L β βΉ200\n" + + "4οΈβ£ 3 L β βΉ300\n\n" + "Reply with number."; } else { reply = @@ -85,53 +82,111 @@ app.post("/webhook", async (req, res) => { // STEP 2: QUANTITY // =============================== else if (sessions[from].step === "QUANTITY") { - const qtyMap = { "1": "1 Litre", "2": "2 Litres", "3": "3 Litres" }; + const qtyMap = { + "1": { qty: "500 ml", price: 50 }, + "2": { qty: "1 L", price: 100 }, + "3": { qty: "2 L", price: 200 }, + "4": { qty: "3 L", price: 300 }, + }; if (!qtyMap[text]) { - reply = "β Invalid option.\nPlease reply 1 / 2 / 3"; + reply = "β Invalid choice. Please reply 1 / 2 / 3 / 4"; } else { - sessions[from].quantity = qtyMap[text]; + sessions[from].quantity = qtyMap[text].qty; + sessions[from].price = qtyMap[text].price; sessions[from].step = "ADDRESS"; - reply = "π Please send your *delivery address*."; + + reply = + "π Please share *delivery address* or use π β *Location* option."; } } // =============================== - // STEP 3: ADDRESS + // STEP 3: ADDRESS / LOCATION // =============================== else if (sessions[from].step === "ADDRESS") { - sessions[from].address = text; + if (location) { + sessions[from].address = `Location: ${location.latitude}, ${location.longitude}`; + } else { + sessions[from].address = text; + } + sessions[from].step = "START_DATE"; reply = - "π From which date do you want milk?\n\n" + - "Example: *05-Jan-2026*"; + "π Select start date:\n\n" + + "1οΈβ£ Today\n" + + "2οΈβ£ Tomorrow\n" + + "3οΈβ£ Custom Date"; } // =============================== // STEP 4: START DATE // =============================== else if (sessions[from].step === "START_DATE") { + if (text === "1") { + sessions[from].startDate = "Today"; + sessions[from].step = "DELIVERY_TIME"; + } else if (text === "2") { + sessions[from].startDate = "Tomorrow"; + sessions[from].step = "DELIVERY_TIME"; + } else if (text === "3") { + sessions[from].step = "CUSTOM_DATE"; + reply = "βοΈ Please type date (DD-MM-YYYY)"; + } else { + reply = "β Invalid option. Reply 1 / 2 / 3"; + } + + if (sessions[from].step === "DELIVERY_TIME") { + reply = + "β° Choose delivery time:\n\n" + + "1οΈβ£ Morning\n" + + "2οΈβ£ Evening"; + } + } + + // =============================== + // CUSTOM DATE + // =============================== + else if (sessions[from].step === "CUSTOM_DATE") { sessions[from].startDate = text; + sessions[from].step = "DELIVERY_TIME"; + + reply = + "β° Choose delivery time:\n\n" + + "1οΈβ£ Morning\n" + + "2οΈβ£ Evening"; + } + + // =============================== + // DELIVERY TIME + // =============================== + else if (sessions[from].step === "DELIVERY_TIME") { + sessions[from].deliveryTime = + text === "1" ? "Morning" : "Evening"; // SAVE TO GOOGLE SHEET await axios.post(process.env.GOOGLE_SHEET_URL, { phone: from, product: sessions[from].product, quantity: sessions[from].quantity, + price: sessions[from].price, address: sessions[from].address, startDate: sessions[from].startDate, + deliveryTime: sessions[from].deliveryTime, }); reply = "β *Order Confirmed!*\n\n" + - `π₯ Product: ${sessions[from].product}\n` + - `π¦ Quantity: ${sessions[from].quantity}\n` + - `π Address: ${sessions[from].address}\n` + - `π Start Date: ${sessions[from].startDate}\n\n` + + `π₯ ${sessions[from].product}\n` + + `π¦ ${sessions[from].quantity}\n` + + `π° βΉ${sessions[from].price}\n` + + `π ${sessions[from].address}\n` + + `π ${sessions[from].startDate}\n` + + `β° ${sessions[from].deliveryTime}\n\n` + "Thank you for choosing *Bala Milk Store* π"; - delete sessions[from]; // clear session + delete sessions[from]; } // =============================== @@ -154,12 +209,9 @@ app.post("/webhook", async (req, res) => { res.sendStatus(200); } catch (err) { - console.error("Error:", err.message); + console.error(err.message); res.sendStatus(200); } }); -// =============================== -app.listen(PORT, () => { - console.log(`π Server running on port ${PORT}`); -}); +app.listen(PORT, () => console.log(`π Server running on ${PORT}`)); From 1d640c204611d915a7720711d59a01a5147a24dd Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 21:29:49 +0530 Subject: [PATCH 20/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 310 +++++++++++++++++++++++++------------------------------ 1 file changed, 138 insertions(+), 172 deletions(-) diff --git a/index.js b/index.js index 2c82c38248..ae375e4aab 100644 --- a/index.js +++ b/index.js @@ -1,217 +1,183 @@ const express = require("express"); -const axios = require("axios"); +const bodyParser = require("body-parser"); const app = express(); -app.use(express.json()); +const PORT = process.env.PORT || 10000; -const PORT = process.env.PORT || 3000; +app.use(bodyParser.json()); -// =============================== -// TEMP SESSION STORAGE -// =============================== const sessions = {}; -// =============================== -// WEBHOOK VERIFY -// =============================== -app.get("/webhook", (req, res) => { - if ( - req.query["hub.mode"] === "subscribe" && - req.query["hub.verify_token"] === process.env.VERIFY_TOKEN - ) { - return res.status(200).send(req.query["hub.challenge"]); - } - res.sendStatus(403); +// Health check +app.get("/", (req, res) => { + res.send("Bala Milk Store WhatsApp Bot is running β "); }); -// =============================== -// WEBHOOK RECEIVE -// =============================== app.post("/webhook", async (req, res) => { try { - const message = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; - if (!message) return res.sendStatus(200); + const entry = req.body.entry?.[0]; + const changes = entry?.changes?.[0]; + const value = changes?.value; - const from = message.from; - const text = message.text?.body?.trim(); - const location = message.location; + if (!value?.messages) { + return res.sendStatus(200); + } - if (!sessions[from]) sessions[from] = { step: "MENU" }; + const messageObj = value.messages[0]; + const from = messageObj.from; + const text = messageObj.text?.body?.trim(); - let reply = ""; + if (!sessions[from]) { + sessions[from] = { step: "START" }; + } - // =============================== - // STEP 1: MENU - // =============================== - if (sessions[from].step === "MENU") { - const products = { - "1": "Buffalo Milk", - "2": "Cow Milk", - "3": "Paneer", - "4": "Ghee", - "5": "Daily Milk Subscription", - "6": "Talk to Owner", - }; - - if (products[text]) { - sessions[from].product = products[text]; - sessions[from].step = "QUANTITY"; + let reply = ""; - reply = - `π₯ *${products[text]} selected*\n\n` + - "Choose quantity:\n" + - "1οΈβ£ 500 ml β βΉ50\n" + - "2οΈβ£ 1 L β βΉ100\n" + - "3οΈβ£ 2 L β βΉ200\n" + - "4οΈβ£ 3 L β βΉ300\n\n" + - "Reply with number."; - } else { + switch (sessions[from].step) { + case "START": reply = "Welcome to *Bala Milk Store* π₯\n\n" + + "Please choose an option:\n" + "1οΈβ£ Buffalo Milk β βΉ100/L\n" + "2οΈβ£ Cow Milk β βΉ120/L\n" + "3οΈβ£ Paneer β βΉ600/Kg\n" + "4οΈβ£ Ghee β βΉ1000/Kg\n" + "5οΈβ£ Daily Milk Subscription\n" + "6οΈβ£ Talk to Owner\n\n" + - "Reply with option number."; - } - } - - // =============================== - // STEP 2: QUANTITY - // =============================== - else if (sessions[from].step === "QUANTITY") { - const qtyMap = { - "1": { qty: "500 ml", price: 50 }, - "2": { qty: "1 L", price: 100 }, - "3": { qty: "2 L", price: 200 }, - "4": { qty: "3 L", price: 300 }, - }; - - if (!qtyMap[text]) { - reply = "β Invalid choice. Please reply 1 / 2 / 3 / 4"; - } else { - sessions[from].quantity = qtyMap[text].qty; - sessions[from].price = qtyMap[text].price; - sessions[from].step = "ADDRESS"; + "Reply with the option number."; + sessions[from].step = "PRODUCT"; + break; + + case "PRODUCT": + if (text === "1") { + sessions[from].product = "Buffalo Milk"; + sessions[from].pricePerL = 100; + } else if (text === "2") { + sessions[from].product = "Cow Milk"; + sessions[from].pricePerL = 120; + } else { + reply = "β Invalid option. Please reply with a valid number."; + break; + } reply = - "π Please share *delivery address* or use π β *Location* option."; - } - } + `π₯ *${sessions[from].product} selected*\n\n` + + "Choose quantity:\n" + + "1οΈβ£ 500ml β βΉ50\n" + + "2οΈβ£ 1 L\n" + + "3οΈβ£ 2 L"; + + sessions[from].step = "QUANTITY"; + break; + + case "QUANTITY": + if (text === "1") { + sessions[from].quantity = "500ml"; + sessions[from].price = 50; + } else if (text === "2") { + sessions[from].quantity = "1 L"; + sessions[from].price = sessions[from].pricePerL; + } else if (text === "3") { + sessions[from].quantity = "2 L"; + sessions[from].price = sessions[from].pricePerL * 2; + } else { + reply = "β Invalid quantity. Choose 1, 2 or 3."; + break; + } + + reply = "π Please send your *delivery address*."; + sessions[from].step = "ADDRESS"; + break; - // =============================== - // STEP 3: ADDRESS / LOCATION - // =============================== - else if (sessions[from].step === "ADDRESS") { - if (location) { - sessions[from].address = `Location: ${location.latitude}, ${location.longitude}`; - } else { + case "ADDRESS": sessions[from].address = text; - } - sessions[from].step = "START_DATE"; + reply = + "π From when do you want delivery?\n\n" + + "1οΈβ£ From Today\n" + + "2οΈβ£ From Tomorrow\n" + + "3οΈβ£ Pick a custom date"; + + sessions[from].step = "START_DATE"; + break; + + case "START_DATE": + if (text === "1") sessions[from].startDate = "Today"; + else if (text === "2") sessions[from].startDate = "Tomorrow"; + else if (text === "3") { + reply = "π Please type the start date (DD-MM-YYYY)"; + sessions[from].step = "CUSTOM_DATE"; + break; + } else { + reply = "β Invalid option."; + break; + } - reply = - "π Select start date:\n\n" + - "1οΈβ£ Today\n" + - "2οΈβ£ Tomorrow\n" + - "3οΈβ£ Custom Date"; - } + reply = + "β° Choose delivery time:\n" + + "1οΈβ£ Morning\n" + + "2οΈβ£ Evening"; - // =============================== - // STEP 4: START DATE - // =============================== - else if (sessions[from].step === "START_DATE") { - if (text === "1") { - sessions[from].startDate = "Today"; - sessions[from].step = "DELIVERY_TIME"; - } else if (text === "2") { - sessions[from].startDate = "Tomorrow"; sessions[from].step = "DELIVERY_TIME"; - } else if (text === "3") { - sessions[from].step = "CUSTOM_DATE"; - reply = "βοΈ Please type date (DD-MM-YYYY)"; - } else { - reply = "β Invalid option. Reply 1 / 2 / 3"; - } - - if (sessions[from].step === "DELIVERY_TIME") { + break; + + case "CUSTOM_DATE": + sessions[from].startDate = text; + reply = - "β° Choose delivery time:\n\n" + + "β° Choose delivery time:\n" + "1οΈβ£ Morning\n" + "2οΈβ£ Evening"; - } - } - // =============================== - // CUSTOM DATE - // =============================== - else if (sessions[from].step === "CUSTOM_DATE") { - sessions[from].startDate = text; - sessions[from].step = "DELIVERY_TIME"; - - reply = - "β° Choose delivery time:\n\n" + - "1οΈβ£ Morning\n" + - "2οΈβ£ Evening"; - } + sessions[from].step = "DELIVERY_TIME"; + break; + + case "DELIVERY_TIME": + if (text === "1") sessions[from].deliveryTime = "Morning"; + else if (text === "2") sessions[from].deliveryTime = "Evening"; + else { + reply = "β Invalid option."; + break; + } - // =============================== - // DELIVERY TIME - // =============================== - else if (sessions[from].step === "DELIVERY_TIME") { - sessions[from].deliveryTime = - text === "1" ? "Morning" : "Evening"; - - // SAVE TO GOOGLE SHEET - await axios.post(process.env.GOOGLE_SHEET_URL, { - phone: from, - product: sessions[from].product, - quantity: sessions[from].quantity, - price: sessions[from].price, - address: sessions[from].address, - startDate: sessions[from].startDate, - deliveryTime: sessions[from].deliveryTime, - }); - - reply = - "β *Order Confirmed!*\n\n" + - `π₯ ${sessions[from].product}\n` + - `π¦ ${sessions[from].quantity}\n` + - `π° βΉ${sessions[from].price}\n` + - `π ${sessions[from].address}\n` + - `π ${sessions[from].startDate}\n` + - `β° ${sessions[from].deliveryTime}\n\n` + - "Thank you for choosing *Bala Milk Store* π"; - - delete sessions[from]; + reply = + "β *Order Confirmed!*\n\n" + + `π₯ ${sessions[from].product}\n` + + `π¦ ${sessions[from].quantity}\n` + + `π ${sessions[from].address}\n` + + `π From: ${sessions[from].startDate}\n` + + `β° ${sessions[from].deliveryTime}\n` + + `π° βΉ${sessions[from].price}\n\n` + + "π³ *Payment Required*\n" + + "UPI ID: *8121893882-2@ybl*\n\n" + + "πΈ After payment, please send the screenshot here."; + + sessions[from].step = "WAIT_PAYMENT"; + break; + + case "WAIT_PAYMENT": + reply = + "π Thank you!\n\n" + + "πΈ Payment screenshot received.\n" + + "Our team will verify and confirm your order shortly."; + break; + + default: + reply = "Something went wrong. Please say Hi again."; + sessions[from].step = "START"; } - // =============================== - // SEND MESSAGE - // =============================== - await axios.post( - `https://graph.facebook.com/v18.0/${process.env.PHONE_NUMBER_ID}/messages`, - { - messaging_product: "whatsapp", - to: from, - text: { body: reply }, - }, - { - headers: { - Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`, - "Content-Type": "application/json", - }, - } - ); + console.log("From:", from); + console.log("Message:", text); + console.log("Reply:", reply); res.sendStatus(200); } catch (err) { - console.error(err.message); - res.sendStatus(200); + console.error(err); + res.sendStatus(500); } }); -app.listen(PORT, () => console.log(`π Server running on ${PORT}`)); +app.listen(PORT, () => { + console.log("Server started on port", PORT); +}); From f31f111d2fe7987b5a0e99852f1929e9818b5544 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 22:00:09 +0530 Subject: [PATCH 21/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 231 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 117 insertions(+), 114 deletions(-) diff --git a/index.js b/index.js index ae375e4aab..dc16c7475b 100644 --- a/index.js +++ b/index.js @@ -1,31 +1,45 @@ const express = require("express"); -const bodyParser = require("body-parser"); +const axios = require("axios"); const app = express(); -const PORT = process.env.PORT || 10000; - -app.use(bodyParser.json()); +app.use(express.json()); const sessions = {}; -// Health check -app.get("/", (req, res) => { - res.send("Bala Milk Store WhatsApp Bot is running β "); +const PRODUCTS = { + "500ml": 50, + "1L": 90, + "2L": 170 +}; + +/* ========================= + WEBHOOK VERIFY +========================= */ +app.get("/webhook", (req, res) => { + const mode = req.query["hub.mode"]; + const token = req.query["hub.verify_token"]; + const challenge = req.query["hub.challenge"]; + + if (mode === "subscribe" && token === process.env.VERIFY_TOKEN) { + return res.status(200).send(challenge); + } + res.sendStatus(403); }); +/* ========================= + WEBHOOK RECEIVE MESSAGE +========================= */ app.post("/webhook", async (req, res) => { try { const entry = req.body.entry?.[0]; - const changes = entry?.changes?.[0]; - const value = changes?.value; + const change = entry?.changes?.[0]; + const value = change?.value; + const messageObj = value?.messages?.[0]; - if (!value?.messages) { - return res.sendStatus(200); - } + if (!messageObj) return res.sendStatus(200); - const messageObj = value.messages[0]; const from = messageObj.from; - const text = messageObj.text?.body?.trim(); + const text = messageObj.text?.body?.toLowerCase(); if (!sessions[from]) { sessions[from] = { step: "START" }; @@ -34,150 +48,139 @@ app.post("/webhook", async (req, res) => { let reply = ""; switch (sessions[from].step) { - case "START": - reply = - "Welcome to *Bala Milk Store* π₯\n\n" + - "Please choose an option:\n" + - "1οΈβ£ Buffalo Milk β βΉ100/L\n" + - "2οΈβ£ Cow Milk β βΉ120/L\n" + - "3οΈβ£ Paneer β βΉ600/Kg\n" + - "4οΈβ£ Ghee β βΉ1000/Kg\n" + - "5οΈβ£ Daily Milk Subscription\n" + - "6οΈβ£ Talk to Owner\n\n" + - "Reply with the option number."; - sessions[from].step = "PRODUCT"; - break; - - case "PRODUCT": - if (text === "1") { - sessions[from].product = "Buffalo Milk"; - sessions[from].pricePerL = 100; - } else if (text === "2") { - sessions[from].product = "Cow Milk"; - sessions[from].pricePerL = 120; - } else { - reply = "β Invalid option. Please reply with a valid number."; - break; - } + /* ===== START ===== */ + case "START": reply = - `π₯ *${sessions[from].product} selected*\n\n` + - "Choose quantity:\n" + + "π₯ *Welcome to Milk Service*\n\n" + + "Select Quantity:\n" + "1οΈβ£ 500ml β βΉ50\n" + - "2οΈβ£ 1 L\n" + - "3οΈβ£ 2 L"; - - sessions[from].step = "QUANTITY"; + "2οΈβ£ 1L β βΉ90\n" + + "3οΈβ£ 2L β βΉ170\n\n" + + "Reply with 1 / 2 / 3"; + sessions[from].step = "QTY"; break; - case "QUANTITY": - if (text === "1") { - sessions[from].quantity = "500ml"; - sessions[from].price = 50; - } else if (text === "2") { - sessions[from].quantity = "1 L"; - sessions[from].price = sessions[from].pricePerL; - } else if (text === "3") { - sessions[from].quantity = "2 L"; - sessions[from].price = sessions[from].pricePerL * 2; - } else { - reply = "β Invalid quantity. Choose 1, 2 or 3."; + /* ===== QUANTITY ===== */ + case "QTY": + if (text === "1") sessions[from].quantity = "500ml"; + else if (text === "2") sessions[from].quantity = "1L"; + else if (text === "3") sessions[from].quantity = "2L"; + else { + reply = "β Please reply 1 / 2 / 3"; break; } - reply = "π Please send your *delivery address*."; + sessions[from].price = PRODUCTS[sessions[from].quantity]; + reply = "π Please share delivery address."; sessions[from].step = "ADDRESS"; break; + /* ===== ADDRESS ===== */ case "ADDRESS": sessions[from].address = text; - reply = - "π From when do you want delivery?\n\n" + - "1οΈβ£ From Today\n" + - "2οΈβ£ From Tomorrow\n" + - "3οΈβ£ Pick a custom date"; - - sessions[from].step = "START_DATE"; + "π Select start date:\n\n" + + "1οΈβ£ Today\n" + + "2οΈβ£ Tomorrow\n\n" + + "Reply 1 or 2"; + sessions[from].step = "DATE"; break; - case "START_DATE": + /* ===== DATE ===== */ + case "DATE": if (text === "1") sessions[from].startDate = "Today"; else if (text === "2") sessions[from].startDate = "Tomorrow"; - else if (text === "3") { - reply = "π Please type the start date (DD-MM-YYYY)"; - sessions[from].step = "CUSTOM_DATE"; - break; - } else { - reply = "β Invalid option."; + else { + reply = "β Reply 1 or 2"; break; } reply = - "β° Choose delivery time:\n" + + "β° Delivery Time:\n\n" + "1οΈβ£ Morning\n" + - "2οΈβ£ Evening"; - - sessions[from].step = "DELIVERY_TIME"; + "2οΈβ£ Evening\n\n" + + "Reply 1 or 2"; + sessions[from].step = "TIME"; break; - case "CUSTOM_DATE": - sessions[from].startDate = text; - - reply = - "β° Choose delivery time:\n" + - "1οΈβ£ Morning\n" + - "2οΈβ£ Evening"; - - sessions[from].step = "DELIVERY_TIME"; - break; - - case "DELIVERY_TIME": + /* ===== TIME ===== */ + case "TIME": if (text === "1") sessions[from].deliveryTime = "Morning"; else if (text === "2") sessions[from].deliveryTime = "Evening"; else { - reply = "β Invalid option."; + reply = "β Reply 1 or 2"; break; } reply = - "β *Order Confirmed!*\n\n" + - `π₯ ${sessions[from].product}\n` + - `π¦ ${sessions[from].quantity}\n` + - `π ${sessions[from].address}\n` + - `π From: ${sessions[from].startDate}\n` + - `β° ${sessions[from].deliveryTime}\n` + - `π° βΉ${sessions[from].price}\n\n` + - "π³ *Payment Required*\n" + - "UPI ID: *8121893882-2@ybl*\n\n" + - "πΈ After payment, please send the screenshot here."; - + `π° *Payment Details*\n\n` + + `Amount: βΉ${sessions[from].price}\n` + + `UPI ID: 8121893882-2@ybl\n\n` + + `After payment, please send *payment screenshot*.`; sessions[from].step = "WAIT_PAYMENT"; break; + /* ===== PAYMENT SCREENSHOT ===== */ case "WAIT_PAYMENT": - reply = - "π Thank you!\n\n" + - "πΈ Payment screenshot received.\n" + - "Our team will verify and confirm your order shortly."; + if (messageObj.image) { + const imageId = messageObj.image.id; + + await axios.post(process.env.GOOGLE_SHEET_URL, { + phone: from, + product: "Milk", + quantity: sessions[from].quantity, + price: sessions[from].price, + address: sessions[from].address, + startDate: sessions[from].startDate, + deliveryTime: sessions[from].deliveryTime, + paymentScreenshot: imageId + }); + + reply = + "β *Payment Received!*\n\n" + + "Your order is confirmed π\n" + + "Thank you for choosing us."; + + delete sessions[from]; + } else { + reply = "πΈ Please send payment screenshot to confirm order."; + } break; - - default: - reply = "Something went wrong. Please say Hi again."; - sessions[from].step = "START"; } - console.log("From:", from); - console.log("Message:", text); - console.log("Reply:", reply); + if (reply) { + await sendMessage(from, reply); + } res.sendStatus(200); + } catch (err) { console.error(err); res.sendStatus(500); } }); -app.listen(PORT, () => { - console.log("Server started on port", PORT); -}); +/* ========================= + SEND MESSAGE FUNCTION +========================= */ +async function sendMessage(to, text) { + await axios.post( + `https://graph.facebook.com/v19.0/${process.env.PHONE_NUMBER_ID}/messages`, + { + messaging_product: "whatsapp", + to, + text: { body: text } + }, + { + headers: { + Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`, + "Content-Type": "application/json" + } + } + ); +} + +/* ========================= */ +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => console.log("Server running on port", PORT)); From 44e9fac2f6c0e41fb146aeb31b9b3e27d1cf76bf Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 22:20:09 +0530 Subject: [PATCH 22/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 215 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 119 insertions(+), 96 deletions(-) diff --git a/index.js b/index.js index dc16c7475b..4e7a3cbc9a 100644 --- a/index.js +++ b/index.js @@ -7,163 +7,188 @@ app.use(express.json()); const sessions = {}; const PRODUCTS = { - "500ml": 50, - "1L": 90, - "2L": 170 + milk: { + name: "Milk", + quantities: { + "1": { label: "500ml", price: 50 }, + "2": { label: "1L", price: 90 }, + "3": { label: "2L", price: 170 } + } + } }; /* ========================= WEBHOOK VERIFY ========================= */ app.get("/webhook", (req, res) => { - const mode = req.query["hub.mode"]; - const token = req.query["hub.verify_token"]; - const challenge = req.query["hub.challenge"]; - - if (mode === "subscribe" && token === process.env.VERIFY_TOKEN) { - return res.status(200).send(challenge); + if ( + req.query["hub.mode"] === "subscribe" && + req.query["hub.verify_token"] === process.env.VERIFY_TOKEN + ) { + return res.status(200).send(req.query["hub.challenge"]); } res.sendStatus(403); }); /* ========================= - WEBHOOK RECEIVE MESSAGE + WEBHOOK RECEIVE ========================= */ app.post("/webhook", async (req, res) => { try { - const entry = req.body.entry?.[0]; - const change = entry?.changes?.[0]; - const value = change?.value; - const messageObj = value?.messages?.[0]; + const msg = + req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; + const contact = + req.body.entry?.[0]?.changes?.[0]?.value?.contacts?.[0]; - if (!messageObj) return res.sendStatus(200); + if (!msg) return res.sendStatus(200); - const from = messageObj.from; - const text = messageObj.text?.body?.toLowerCase(); + const from = msg.from; + const text = msg.text?.body?.toLowerCase(); + const name = contact?.profile?.name || ""; if (!sessions[from]) { - sessions[from] = { step: "START" }; + sessions[from] = { step: "START", name }; } let reply = ""; + /* ========================= + FLOW + ========================= */ switch (sessions[from].step) { - /* ===== START ===== */ + /* ---- START ---- */ case "START": - reply = - "π₯ *Welcome to Milk Service*\n\n" + - "Select Quantity:\n" + - "1οΈβ£ 500ml β βΉ50\n" + - "2οΈβ£ 1L β βΉ90\n" + - "3οΈβ£ 2L β βΉ170\n\n" + - "Reply with 1 / 2 / 3"; - sessions[from].step = "QTY"; + if (text === "hi" || text === "hello") { + reply = + "π Welcome to *Bala Milk Store* π₯\n\n" + + "Please choose a product:\n" + + "1οΈβ£ Milk\n" + + "2οΈβ£ Enquiry only"; + sessions[from].step = "PRODUCT"; + } break; - /* ===== QUANTITY ===== */ + /* ---- PRODUCT ---- */ + case "PRODUCT": + if (text === "1") { + sessions[from].product = "Milk"; + reply = + "Select Quantity:\n\n" + + "1οΈβ£ 500ml β βΉ50\n" + + "2οΈβ£ 1L β βΉ90\n" + + "3οΈβ£ 2L β βΉ170"; + sessions[from].step = "QTY"; + } else if (text === "2") { + await saveToSheet({ + phone: from, + name, + type: "Enquiry" + }); + reply = "π Thank you! We will contact you shortly."; + delete sessions[from]; + } else { + reply = "β Please reply 1 or 2"; + } + break; + + /* ---- QUANTITY ---- */ case "QTY": - if (text === "1") sessions[from].quantity = "500ml"; - else if (text === "2") sessions[from].quantity = "1L"; - else if (text === "3") sessions[from].quantity = "2L"; - else { - reply = "β Please reply 1 / 2 / 3"; + const qty = PRODUCTS.milk.quantities[text]; + if (!qty) { + reply = "β Please select 1 / 2 / 3"; break; } - - sessions[from].price = PRODUCTS[sessions[from].quantity]; - reply = "π Please share delivery address."; + sessions[from].quantity = qty.label; + sessions[from].price = qty.price; + reply = + "π Please type your delivery address\n" + + "OR share your *current location*."; sessions[from].step = "ADDRESS"; break; - /* ===== ADDRESS ===== */ + /* ---- ADDRESS ---- */ case "ADDRESS": - sessions[from].address = text; - reply = - "π Select start date:\n\n" + - "1οΈβ£ Today\n" + - "2οΈβ£ Tomorrow\n\n" + - "Reply 1 or 2"; - sessions[from].step = "DATE"; - break; - - /* ===== DATE ===== */ - case "DATE": - if (text === "1") sessions[from].startDate = "Today"; - else if (text === "2") sessions[from].startDate = "Tomorrow"; - else { - reply = "β Reply 1 or 2"; - break; - } - + sessions[from].address = text || "Location Shared"; reply = "β° Delivery Time:\n\n" + "1οΈβ£ Morning\n" + - "2οΈβ£ Evening\n\n" + - "Reply 1 or 2"; + "2οΈβ£ Evening"; sessions[from].step = "TIME"; break; - /* ===== TIME ===== */ + /* ---- TIME ---- */ case "TIME": - if (text === "1") sessions[from].deliveryTime = "Morning"; - else if (text === "2") sessions[from].deliveryTime = "Evening"; + if (text === "1") sessions[from].time = "Morning"; + else if (text === "2") sessions[from].time = "Evening"; else { - reply = "β Reply 1 or 2"; + reply = "β Please reply 1 or 2"; break; } reply = - `π° *Payment Details*\n\n` + - `Amount: βΉ${sessions[from].price}\n` + - `UPI ID: 8121893882-2@ybl\n\n` + - `After payment, please send *payment screenshot*.`; - sessions[from].step = "WAIT_PAYMENT"; + "π³ Payment Method:\n\n" + + "1οΈβ£ Cash on Delivery\n" + + "2οΈβ£ UPI Payment"; + sessions[from].step = "PAYMENT_METHOD"; break; - /* ===== PAYMENT SCREENSHOT ===== */ - case "WAIT_PAYMENT": - if (messageObj.image) { - const imageId = messageObj.image.id; - - await axios.post(process.env.GOOGLE_SHEET_URL, { - phone: from, - product: "Milk", - quantity: sessions[from].quantity, - price: sessions[from].price, - address: sessions[from].address, - startDate: sessions[from].startDate, - deliveryTime: sessions[from].deliveryTime, - paymentScreenshot: imageId - }); - + /* ---- PAYMENT METHOD ---- */ + case "PAYMENT_METHOD": + if (text === "1") { + sessions[from].payment = "Cash on Delivery"; + await confirmOrder(from, name, "Payment"); + reply = "β Order confirmed!\nPayment: Cash on Delivery"; + delete sessions[from]; + } else if (text === "2") { + sessions[from].payment = "UPI"; reply = - "β *Payment Received!*\n\n" + - "Your order is confirmed π\n" + - "Thank you for choosing us."; + "π° Amount: βΉ" + sessions[from].price + "\n\n" + + "UPI ID:\n8121893882-2@ybl\n\n" + + "πΈ After payment, send screenshot."; + sessions[from].step = "WAIT_SCREENSHOT"; + } else { + reply = "β Please reply 1 or 2"; + } + break; + /* ---- SCREENSHOT ---- */ + case "WAIT_SCREENSHOT": + if (msg.image) { + await confirmOrder(from, name, "Payment", msg.image.id); + reply = "β Payment received! Order confirmed π"; delete sessions[from]; } else { - reply = "πΈ Please send payment screenshot to confirm order."; + reply = "πΈ Please send payment screenshot."; } break; } - if (reply) { - await sendMessage(from, reply); - } - + if (reply) await sendMessage(from, reply); res.sendStatus(200); - } catch (err) { - console.error(err); + } catch (e) { + console.error(e); res.sendStatus(500); } }); /* ========================= - SEND MESSAGE FUNCTION + HELPERS ========================= */ +async function confirmOrder(phone, name, type, screenshot = "") { + await saveToSheet({ + phone, + name, + type, + screenshot + }); +} + +async function saveToSheet(data) { + await axios.post(process.env.GOOGLE_SHEET_URL, data); +} + async function sendMessage(to, text) { await axios.post( `https://graph.facebook.com/v19.0/${process.env.PHONE_NUMBER_ID}/messages`, @@ -181,6 +206,4 @@ async function sendMessage(to, text) { ); } -/* ========================= */ -const PORT = process.env.PORT || 3000; -app.listen(PORT, () => console.log("Server running on port", PORT)); +app.listen(process.env.PORT || 3000); From 935629a76c5694cfadee594900851beed6b18fea Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 22:38:38 +0530 Subject: [PATCH 23/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 294 ++++++++++++++++++++++++++----------------------------- 1 file changed, 138 insertions(+), 156 deletions(-) diff --git a/index.js b/index.js index 4e7a3cbc9a..8c2117a7a3 100644 --- a/index.js +++ b/index.js @@ -7,19 +7,13 @@ app.use(express.json()); const sessions = {}; const PRODUCTS = { - milk: { - name: "Milk", - quantities: { - "1": { label: "500ml", price: 50 }, - "2": { label: "1L", price: 90 }, - "3": { label: "2L", price: 170 } - } - } + "1": { name: "Buffalo Milk", price: 100 }, + "2": { name: "Cow Milk", price: 120 }, + "3": { name: "Paneer", price: 600 }, + "4": { name: "Ghee", price: 1000 } }; -/* ========================= - WEBHOOK VERIFY -========================= */ +/* ================= VERIFY ================= */ app.get("/webhook", (req, res) => { if ( req.query["hub.mode"] === "subscribe" && @@ -30,163 +24,147 @@ app.get("/webhook", (req, res) => { res.sendStatus(403); }); -/* ========================= - WEBHOOK RECEIVE -========================= */ +/* ================= WEBHOOK ================= */ app.post("/webhook", async (req, res) => { - try { - const msg = - req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; - const contact = - req.body.entry?.[0]?.changes?.[0]?.value?.contacts?.[0]; - - if (!msg) return res.sendStatus(200); - - const from = msg.from; - const text = msg.text?.body?.toLowerCase(); - const name = contact?.profile?.name || ""; - - if (!sessions[from]) { - sessions[from] = { step: "START", name }; - } + const msg = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; + const contact = req.body.entry?.[0]?.changes?.[0]?.value?.contacts?.[0]; + if (!msg) return res.sendStatus(200); + + const from = msg.from; + const text = msg.text?.body?.trim().toLowerCase(); + const name = contact?.profile?.name || ""; + + if (!sessions[from] || text === "0") { + sessions[from] = { step: "MENU", name }; + await sendMenu(from); + return res.sendStatus(200); + } - let reply = ""; - - /* ========================= - FLOW - ========================= */ - switch (sessions[from].step) { - - /* ---- START ---- */ - case "START": - if (text === "hi" || text === "hello") { - reply = - "π Welcome to *Bala Milk Store* π₯\n\n" + - "Please choose a product:\n" + - "1οΈβ£ Milk\n" + - "2οΈβ£ Enquiry only"; - sessions[from].step = "PRODUCT"; - } - break; + let s = sessions[from]; + let reply = ""; - /* ---- PRODUCT ---- */ - case "PRODUCT": - if (text === "1") { - sessions[from].product = "Milk"; - reply = - "Select Quantity:\n\n" + - "1οΈβ£ 500ml β βΉ50\n" + - "2οΈβ£ 1L β βΉ90\n" + - "3οΈβ£ 2L β βΉ170"; - sessions[from].step = "QTY"; - } else if (text === "2") { - await saveToSheet({ - phone: from, - name, - type: "Enquiry" - }); - reply = "π Thank you! We will contact you shortly."; - delete sessions[from]; - } else { - reply = "β Please reply 1 or 2"; - } - break; + switch (s.step) { - /* ---- QUANTITY ---- */ - case "QTY": - const qty = PRODUCTS.milk.quantities[text]; - if (!qty) { - reply = "β Please select 1 / 2 / 3"; - break; - } - sessions[from].quantity = qty.label; - sessions[from].price = qty.price; - reply = - "π Please type your delivery address\n" + - "OR share your *current location*."; - sessions[from].step = "ADDRESS"; + /* -------- MENU -------- */ + case "MENU": + if (text === "5") { + reply = "π Daily Milk Subscription coming soon!"; break; - - /* ---- ADDRESS ---- */ - case "ADDRESS": - sessions[from].address = text || "Location Shared"; - reply = - "β° Delivery Time:\n\n" + - "1οΈβ£ Morning\n" + - "2οΈβ£ Evening"; - sessions[from].step = "TIME"; + } + if (text === "6") { + reply = "π Owner will contact you shortly."; + await saveSheet({ phone: from, name, type: "Enquiry" }); + delete sessions[from]; break; - - /* ---- TIME ---- */ - case "TIME": - if (text === "1") sessions[from].time = "Morning"; - else if (text === "2") sessions[from].time = "Evening"; - else { - reply = "β Please reply 1 or 2"; - break; - } - - reply = - "π³ Payment Method:\n\n" + - "1οΈβ£ Cash on Delivery\n" + - "2οΈβ£ UPI Payment"; - sessions[from].step = "PAYMENT_METHOD"; + } + if (!PRODUCTS[text]) { + reply = "β Please choose valid option"; break; - - /* ---- PAYMENT METHOD ---- */ - case "PAYMENT_METHOD": - if (text === "1") { - sessions[from].payment = "Cash on Delivery"; - await confirmOrder(from, name, "Payment"); - reply = "β Order confirmed!\nPayment: Cash on Delivery"; - delete sessions[from]; - } else if (text === "2") { - sessions[from].payment = "UPI"; - reply = - "π° Amount: βΉ" + sessions[from].price + "\n\n" + - "UPI ID:\n8121893882-2@ybl\n\n" + - "πΈ After payment, send screenshot."; - sessions[from].step = "WAIT_SCREENSHOT"; - } else { - reply = "β Please reply 1 or 2"; - } + } + s.product = PRODUCTS[text].name; + s.pricePerUnit = PRODUCTS[text].price; + reply = + `π§΄ ${s.product}\n\nSelect Quantity:\n` + + `1οΈβ£ 500ml\n2οΈβ£ 1L\n3οΈβ£ 2L\n\n0οΈβ£ Back`; + s.step = "QTY"; + break; + + /* -------- QUANTITY -------- */ + case "QTY": + const qtyMap = { "1": "500ml", "2": "1L", "3": "2L" }; + if (!qtyMap[text]) { + reply = "β Select 1 / 2 / 3 or 0"; break; - - /* ---- SCREENSHOT ---- */ - case "WAIT_SCREENSHOT": - if (msg.image) { - await confirmOrder(from, name, "Payment", msg.image.id); - reply = "β Payment received! Order confirmed π"; - delete sessions[from]; - } else { - reply = "πΈ Please send payment screenshot."; - } + } + s.quantity = qtyMap[text]; + reply = + "π Please enter delivery address\n" + + "OR share your *current location*\n\n0οΈβ£ Back"; + s.step = "ADDRESS"; + break; + + /* -------- ADDRESS -------- */ + case "ADDRESS": + s.address = text; + reply = + "π Choose Delivery Slot:\n\n" + + "1οΈβ£ Morning\n2οΈβ£ Evening\n\n0οΈβ£ Back"; + s.step = "SLOT"; + break; + + /* -------- SLOT -------- */ + case "SLOT": + if (text === "1") s.slot = "Morning"; + else if (text === "2") s.slot = "Evening"; + else { + reply = "β Choose 1 or 2"; break; - } - - if (reply) await sendMessage(from, reply); - res.sendStatus(200); - - } catch (e) { - console.error(e); - res.sendStatus(500); + } + reply = + `β° Enter delivery time\n` + + `Example: 6:30 AM or 7:00 PM\n\n0οΈβ£ Back`; + s.step = "TIME"; + break; + + /* -------- TIME -------- */ + case "TIME": + s.time = text; + reply = + "π³ Payment Method:\n\n" + + "1οΈβ£ Cash on Delivery\n" + + "2οΈβ£ UPI Payment\n\n0οΈβ£ Back"; + s.step = "PAYMENT"; + break; + + /* -------- PAYMENT -------- */ + case "PAYMENT": + if (text === "1") { + s.payment = "Cash on Delivery"; + await saveSheet({ ...s, phone: from, type: "Payment" }); + reply = "β Order Confirmed!\nPayment: COD π"; + delete sessions[from]; + } else if (text === "2") { + s.payment = "UPI"; + reply = + `π° Pay using UPI\n\n` + + `8121893882-2@ybl\n\n` + + `πΈ Send payment screenshot\n\n0οΈβ£ Back`; + s.step = "SCREENSHOT"; + } else { + reply = "β Choose 1 or 2"; + } + break; + + /* -------- SCREENSHOT -------- */ + case "SCREENSHOT": + if (msg.image) { + s.screenshot = msg.image.id; + await saveSheet({ ...s, phone: from, type: "Payment" }); + reply = "β Payment received! Order confirmed π"; + delete sessions[from]; + } else { + reply = "πΈ Please send payment screenshot"; + } + break; } -}); -/* ========================= - HELPERS -========================= */ -async function confirmOrder(phone, name, type, screenshot = "") { - await saveToSheet({ - phone, - name, - type, - screenshot - }); -} + if (reply) await sendMessage(from, reply); + res.sendStatus(200); +}); -async function saveToSheet(data) { - await axios.post(process.env.GOOGLE_SHEET_URL, data); +/* ================= HELPERS ================= */ + +async function sendMenu(to) { + const text = + "π₯ *Bala Milk Store*\n\n" + + "Please choose an option:\n\n" + + "1οΈβ£ Buffalo Milk β βΉ100/L\n" + + "2οΈβ£ Cow Milk β βΉ120/L\n" + + "3οΈβ£ Paneer β βΉ600/Kg\n" + + "4οΈβ£ Ghee β βΉ1000/Kg\n" + + "5οΈβ£ Daily Milk Subscription\n" + + "6οΈβ£ Talk to Owner"; + await sendMessage(to, text); } async function sendMessage(to, text) { @@ -206,4 +184,8 @@ async function sendMessage(to, text) { ); } +async function saveSheet(data) { + await axios.post(process.env.GOOGLE_SHEET_URL, data); +} + app.listen(process.env.PORT || 3000); From 433b24b8d24a2e377c669728107924a0c4fd95cc Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 22:47:13 +0530 Subject: [PATCH 24/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 126 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 49 deletions(-) diff --git a/index.js b/index.js index 8c2117a7a3..b7f837ae4e 100644 --- a/index.js +++ b/index.js @@ -6,11 +6,44 @@ app.use(express.json()); const sessions = {}; +/* ================= PRODUCTS ================= */ const PRODUCTS = { - "1": { name: "Buffalo Milk", price: 100 }, - "2": { name: "Cow Milk", price: 120 }, - "3": { name: "Paneer", price: 600 }, - "4": { name: "Ghee", price: 1000 } + "1": { + name: "Buffalo Milk", + emoji: "π", + units: { + "1": { qty: "500ml", price: 50 }, + "2": { qty: "1 Litre", price: 100 }, + "3": { qty: "2 Litres", price: 200 } + } + }, + "2": { + name: "Cow Milk", + emoji: "π", + units: { + "1": { qty: "500ml", price: 60 }, + "2": { qty: "1 Litre", price: 120 }, + "3": { qty: "2 Litres", price: 240 } + } + }, + "3": { + name: "Paneer", + emoji: "π§", + units: { + "1": { qty: "250g", price: 150 }, + "2": { qty: "500g", price: 300 }, + "3": { qty: "1 Kg", price: 600 } + } + }, + "4": { + name: "Ghee", + emoji: "π₯", + units: { + "1": { qty: "250ml", price: 250 }, + "2": { qty: "500ml", price: 500 }, + "3": { qty: "1 Litre", price: 1000 } + } + } }; /* ================= VERIFY ================= */ @@ -31,7 +64,7 @@ app.post("/webhook", async (req, res) => { if (!msg) return res.sendStatus(200); const from = msg.from; - const text = msg.text?.body?.trim().toLowerCase(); + const text = msg.text?.body?.trim(); const name = contact?.profile?.name || ""; if (!sessions[from] || text === "0") { @@ -40,46 +73,41 @@ app.post("/webhook", async (req, res) => { return res.sendStatus(200); } - let s = sessions[from]; + const s = sessions[from]; let reply = ""; switch (s.step) { /* -------- MENU -------- */ case "MENU": - if (text === "5") { - reply = "π Daily Milk Subscription coming soon!"; - break; - } if (text === "6") { - reply = "π Owner will contact you shortly."; await saveSheet({ phone: from, name, type: "Enquiry" }); + reply = "π Owner will contact you shortly."; delete sessions[from]; break; } if (!PRODUCTS[text]) { - reply = "β Please choose valid option"; + reply = "β Please select valid option"; break; } + s.productKey = text; s.product = PRODUCTS[text].name; - s.pricePerUnit = PRODUCTS[text].price; - reply = - `π§΄ ${s.product}\n\nSelect Quantity:\n` + - `1οΈβ£ 500ml\n2οΈβ£ 1L\n3οΈβ£ 2L\n\n0οΈβ£ Back`; + reply = formatQuantityMenu(PRODUCTS[text]); s.step = "QTY"; break; - /* -------- QUANTITY -------- */ + /* -------- QTY -------- */ case "QTY": - const qtyMap = { "1": "500ml", "2": "1L", "3": "2L" }; - if (!qtyMap[text]) { - reply = "β Select 1 / 2 / 3 or 0"; + const product = PRODUCTS[s.productKey]; + if (!product.units[text]) { + reply = "β Please select valid quantity"; break; } - s.quantity = qtyMap[text]; + s.quantity = product.units[text].qty; + s.price = product.units[text].price; reply = "π Please enter delivery address\n" + - "OR share your *current location*\n\n0οΈβ£ Back"; + "or share *current location*\n\n0οΈβ£ Back"; s.step = "ADDRESS"; break; @@ -87,7 +115,7 @@ app.post("/webhook", async (req, res) => { case "ADDRESS": s.address = text; reply = - "π Choose Delivery Slot:\n\n" + + "π Delivery Slot:\n\n" + "1οΈβ£ Morning\n2οΈβ£ Evening\n\n0οΈβ£ Back"; s.step = "SLOT"; break; @@ -96,13 +124,8 @@ app.post("/webhook", async (req, res) => { case "SLOT": if (text === "1") s.slot = "Morning"; else if (text === "2") s.slot = "Evening"; - else { - reply = "β Choose 1 or 2"; - break; - } - reply = - `β° Enter delivery time\n` + - `Example: 6:30 AM or 7:00 PM\n\n0οΈβ£ Back`; + else { reply = "β Choose 1 or 2"; break; } + reply = "β° Enter delivery time (eg: 6:30 AM)"; s.step = "TIME"; break; @@ -121,18 +144,16 @@ app.post("/webhook", async (req, res) => { if (text === "1") { s.payment = "Cash on Delivery"; await saveSheet({ ...s, phone: from, type: "Payment" }); - reply = "β Order Confirmed!\nPayment: COD π"; + reply = "β Order Confirmed (COD) π"; delete sessions[from]; } else if (text === "2") { s.payment = "UPI"; reply = - `π° Pay using UPI\n\n` + - `8121893882-2@ybl\n\n` + - `πΈ Send payment screenshot\n\n0οΈβ£ Back`; + `π° Amount: βΉ${s.price}\n\n` + + `UPI ID:\n8121893882-2@ybl\n\n` + + `πΈ Send payment screenshot`; s.step = "SCREENSHOT"; - } else { - reply = "β Choose 1 or 2"; - } + } else reply = "β Choose 1 or 2"; break; /* -------- SCREENSHOT -------- */ @@ -140,11 +161,9 @@ app.post("/webhook", async (req, res) => { if (msg.image) { s.screenshot = msg.image.id; await saveSheet({ ...s, phone: from, type: "Payment" }); - reply = "β Payment received! Order confirmed π"; + reply = "β Payment received. Order confirmed π"; delete sessions[from]; - } else { - reply = "πΈ Please send payment screenshot"; - } + } else reply = "πΈ Please send screenshot"; break; } @@ -154,17 +173,26 @@ app.post("/webhook", async (req, res) => { /* ================= HELPERS ================= */ +function formatQuantityMenu(product) { + let txt = `${product.emoji} *${product.name} β Price Details*\n\n`; + Object.entries(product.units).forEach(([k, v]) => { + txt += `${k}οΈβ£ ${v.qty} β βΉ${v.price}\n`; + }); + txt += "\n0οΈβ£ β¬ Back"; + return txt; +} + async function sendMenu(to) { - const text = + await sendMessage( + to, "π₯ *Bala Milk Store*\n\n" + - "Please choose an option:\n\n" + - "1οΈβ£ Buffalo Milk β βΉ100/L\n" + - "2οΈβ£ Cow Milk β βΉ120/L\n" + - "3οΈβ£ Paneer β βΉ600/Kg\n" + - "4οΈβ£ Ghee β βΉ1000/Kg\n" + + "1οΈβ£ Buffalo Milk\n" + + "2οΈβ£ Cow Milk\n" + + "3οΈβ£ Paneer\n" + + "4οΈβ£ Ghee\n" + "5οΈβ£ Daily Milk Subscription\n" + - "6οΈβ£ Talk to Owner"; - await sendMessage(to, text); + "6οΈβ£ Talk to Owner" + ); } async function sendMessage(to, text) { From 05d239dcfc3b45fb2c0da58175d5b2272ca83d25 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 23:48:45 +0530 Subject: [PATCH 25/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 387 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 198 insertions(+), 189 deletions(-) diff --git a/index.js b/index.js index b7f837ae4e..0a2f2a15f2 100644 --- a/index.js +++ b/index.js @@ -1,219 +1,228 @@ const express = require("express"); const axios = require("axios"); +const bodyParser = require("body-parser"); const app = express(); -app.use(express.json()); +app.use(bodyParser.json()); + +const PORT = process.env.PORT || 10000; + +/* ================= CONFIG ================= */ + +const TOKEN = process.env.WHATSAPP_TOKEN; +const PHONE_ID = process.env.PHONE_NUMBER_ID; +const SHEET_URL = process.env.SHEET_WEBHOOK; // Google Apps Script URL +const OWNER_UPI = "8121893882-2@ybl"; + +/* ================= SESSION ================= */ const sessions = {}; +function newSession(phone) { + return { + orderId: "ORD-" + Date.now(), + phone, + step: "MENU", + }; +} + /* ================= PRODUCTS ================= */ + const PRODUCTS = { - "1": { - name: "Buffalo Milk", - emoji: "π", - units: { - "1": { qty: "500ml", price: 50 }, - "2": { qty: "1 Litre", price: 100 }, - "3": { qty: "2 Litres", price: 200 } + "1": { name: "Buffalo Milk", price: 100 }, + "2": { name: "Cow Milk", price: 120 }, + "3": { name: "Paneer", price: 600 }, + "4": { name: "Ghee", price: 1000 }, + "5": { name: "Daily Milk Subscription" }, + "6": { name: "Talk to Owner" }, +}; + +/* ================= WHATSAPP SEND ================= */ + +async function sendMessage(to, text) { + await axios.post( + `https://graph.facebook.com/v18.0/${PHONE_ID}/messages`, + { + messaging_product: "whatsapp", + to, + text: { body: text }, + }, + { + headers: { + Authorization: `Bearer ${TOKEN}`, + "Content-Type": "application/json", + }, } - }, - "2": { - name: "Cow Milk", - emoji: "π", - units: { - "1": { qty: "500ml", price: 60 }, - "2": { qty: "1 Litre", price: 120 }, - "3": { qty: "2 Litres", price: 240 } + ); +} + +/* ================= GOOGLE SHEET ================= */ + +async function saveToSheet(data) { + await axios.post(SHEET_URL, data); +} + +/* ================= MENU ================= */ + +function menuText() { + return `π₯ Welcome to *Bala Milk Store* + +Please choose an option: +1οΈβ£ Buffalo Milk β βΉ100/L +2οΈβ£ Cow Milk β βΉ120/L +3οΈβ£ Paneer β βΉ600/Kg +4οΈβ£ Ghee β βΉ1000/Kg +5οΈβ£ Daily Milk Subscription +6οΈβ£ Talk to Owner + +Reply with option number.`; +} + +/* ================= WEBHOOK ================= */ + +app.post("/webhook", async (req, res) => { + const entry = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; + if (!entry) return res.sendStatus(200); + + const from = entry.from; + const text = entry.text?.body?.trim(); + const image = entry.image; + + if (!sessions[from]) { + sessions[from] = newSession(from); + await sendMessage(from, menuText()); + return res.sendStatus(200); + } + + const s = sessions[from]; + + /* ===== MENU ===== */ + if (s.step === "MENU") { + if (!PRODUCTS[text]) { + await sendMessage(from, "β Invalid option. Please choose again.\n\n" + menuText()); + return res.sendStatus(200); } - }, - "3": { - name: "Paneer", - emoji: "π§", - units: { - "1": { qty: "250g", price: 150 }, - "2": { qty: "500g", price: 300 }, - "3": { qty: "1 Kg", price: 600 } + + if (text === "6") { + await sendMessage(from, "π Please call: 8121893882"); + delete sessions[from]; + return res.sendStatus(200); } - }, - "4": { - name: "Ghee", - emoji: "π₯", - units: { - "1": { qty: "250ml", price: 250 }, - "2": { qty: "500ml", price: 500 }, - "3": { qty: "1 Litre", price: 1000 } + + s.product = PRODUCTS[text].name; + s.unitPrice = PRODUCTS[text].price; + s.step = "QTY"; + + await sendMessage( + from, + `π§Ύ *${s.product}*\n\nChoose quantity:\n1οΈβ£ 500ml\n2οΈβ£ 1 L\n3οΈβ£ 2 L` + ); + return res.sendStatus(200); + } + + /* ===== QUANTITY ===== */ + if (s.step === "QTY") { + if (!["1", "2", "3"].includes(text)) { + await sendMessage(from, "β Choose 1 / 2 / 3"); + return res.sendStatus(200); } + + s.quantity = + text === "1" ? "500ml" : text === "2" ? "1L" : "2L"; + + const multiplier = text === "1" ? 0.5 : text === "2" ? 1 : 2; + s.price = s.unitPrice * multiplier; + + s.step = "ADDRESS"; + await sendMessage(from, "π Please send your delivery address."); + return res.sendStatus(200); } -}; -/* ================= VERIFY ================= */ -app.get("/webhook", (req, res) => { - if ( - req.query["hub.mode"] === "subscribe" && - req.query["hub.verify_token"] === process.env.VERIFY_TOKEN - ) { - return res.status(200).send(req.query["hub.challenge"]); + /* ===== ADDRESS ===== */ + if (s.step === "ADDRESS") { + s.address = text; + s.step = "SLOT"; + await sendMessage(from, "π Choose delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); + return res.sendStatus(200); } - res.sendStatus(403); -}); -/* ================= WEBHOOK ================= */ -app.post("/webhook", async (req, res) => { - const msg = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; - const contact = req.body.entry?.[0]?.changes?.[0]?.value?.contacts?.[0]; - if (!msg) return res.sendStatus(200); + /* ===== SLOT ===== */ + if (s.step === "SLOT") { + if (!["1", "2"].includes(text)) { + await sendMessage(from, "β Choose 1 or 2"); + return res.sendStatus(200); + } - const from = msg.from; - const text = msg.text?.body?.trim(); - const name = contact?.profile?.name || ""; + s.slot = text === "1" ? "Morning" : "Evening"; + s.step = "TIME"; + await sendMessage(from, "β° Enter delivery time (example: 6:30 AM)"); + return res.sendStatus(200); + } + + /* ===== TIME ===== */ + if (s.step === "TIME") { + s.time = text; + s.step = "PAYMENT"; - if (!sessions[from] || text === "0") { - sessions[from] = { step: "MENU", name }; - await sendMenu(from); + await sendMessage( + from, + `π° *Payment Options*\n\nUPI ID:\n${OWNER_UPI}\n\n1οΈβ£ Send payment screenshot\n2οΈβ£ Cash on Delivery` + ); return res.sendStatus(200); } - const s = sessions[from]; - let reply = ""; - - switch (s.step) { - - /* -------- MENU -------- */ - case "MENU": - if (text === "6") { - await saveSheet({ phone: from, name, type: "Enquiry" }); - reply = "π Owner will contact you shortly."; - delete sessions[from]; - break; - } - if (!PRODUCTS[text]) { - reply = "β Please select valid option"; - break; - } - s.productKey = text; - s.product = PRODUCTS[text].name; - reply = formatQuantityMenu(PRODUCTS[text]); - s.step = "QTY"; - break; - - /* -------- QTY -------- */ - case "QTY": - const product = PRODUCTS[s.productKey]; - if (!product.units[text]) { - reply = "β Please select valid quantity"; - break; - } - s.quantity = product.units[text].qty; - s.price = product.units[text].price; - reply = - "π Please enter delivery address\n" + - "or share *current location*\n\n0οΈβ£ Back"; - s.step = "ADDRESS"; - break; - - /* -------- ADDRESS -------- */ - case "ADDRESS": - s.address = text; - reply = - "π Delivery Slot:\n\n" + - "1οΈβ£ Morning\n2οΈβ£ Evening\n\n0οΈβ£ Back"; - s.step = "SLOT"; - break; - - /* -------- SLOT -------- */ - case "SLOT": - if (text === "1") s.slot = "Morning"; - else if (text === "2") s.slot = "Evening"; - else { reply = "β Choose 1 or 2"; break; } - reply = "β° Enter delivery time (eg: 6:30 AM)"; - s.step = "TIME"; - break; - - /* -------- TIME -------- */ - case "TIME": - s.time = text; - reply = - "π³ Payment Method:\n\n" + - "1οΈβ£ Cash on Delivery\n" + - "2οΈβ£ UPI Payment\n\n0οΈβ£ Back"; - s.step = "PAYMENT"; - break; - - /* -------- PAYMENT -------- */ - case "PAYMENT": - if (text === "1") { - s.payment = "Cash on Delivery"; - await saveSheet({ ...s, phone: from, type: "Payment" }); - reply = "β Order Confirmed (COD) π"; - delete sessions[from]; - } else if (text === "2") { - s.payment = "UPI"; - reply = - `π° Amount: βΉ${s.price}\n\n` + - `UPI ID:\n8121893882-2@ybl\n\n` + - `πΈ Send payment screenshot`; - s.step = "SCREENSHOT"; - } else reply = "β Choose 1 or 2"; - break; - - /* -------- SCREENSHOT -------- */ - case "SCREENSHOT": - if (msg.image) { - s.screenshot = msg.image.id; - await saveSheet({ ...s, phone: from, type: "Payment" }); - reply = "β Payment received. Order confirmed π"; - delete sessions[from]; - } else reply = "πΈ Please send screenshot"; - break; + /* ===== PAYMENT ===== */ + if (s.step === "PAYMENT") { + if (text === "2") { + s.paymentMethod = "Cash on Delivery"; + } + + if (image) { + s.paymentMethod = "UPI"; + s.screenshot = image.id; + } + + if (!s.paymentMethod) { + await sendMessage(from, "β Please choose payment option"); + return res.sendStatus(200); + } + + await saveToSheet({ + orderId: s.orderId, + date: new Date().toLocaleString(), + phone: s.phone, + product: s.product, + quantity: s.quantity, + price: s.price, + address: s.address, + delivery: `${s.slot} ${s.time}`, + payment: s.paymentMethod, + screenshot: s.screenshot || "", + }); + + await sendMessage( + from, + `β *Order Confirmed!*\n\nπ§Ύ Order ID: ${s.orderId}\nπ₯ ${s.product}\nπ¦ ${s.quantity}\nπ° βΉ${s.price}\nπ ${s.slot} ${s.time}\n\nπ Thank you for choosing Bala Milk Store` + ); + + delete sessions[from]; // π₯ IMPORTANT + return res.sendStatus(200); } - if (reply) await sendMessage(from, reply); res.sendStatus(200); }); -/* ================= HELPERS ================= */ - -function formatQuantityMenu(product) { - let txt = `${product.emoji} *${product.name} β Price Details*\n\n`; - Object.entries(product.units).forEach(([k, v]) => { - txt += `${k}οΈβ£ ${v.qty} β βΉ${v.price}\n`; - }); - txt += "\n0οΈβ£ β¬ Back"; - return txt; -} - -async function sendMenu(to) { - await sendMessage( - to, - "π₯ *Bala Milk Store*\n\n" + - "1οΈβ£ Buffalo Milk\n" + - "2οΈβ£ Cow Milk\n" + - "3οΈβ£ Paneer\n" + - "4οΈβ£ Ghee\n" + - "5οΈβ£ Daily Milk Subscription\n" + - "6οΈβ£ Talk to Owner" - ); -} +/* ================= VERIFY ================= */ -async function sendMessage(to, text) { - await axios.post( - `https://graph.facebook.com/v19.0/${process.env.PHONE_NUMBER_ID}/messages`, - { - messaging_product: "whatsapp", - to, - text: { body: text } - }, - { - headers: { - Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`, - "Content-Type": "application/json" - } - } - ); -} +app.get("/webhook", (req, res) => { + if (req.query["hub.verify_token"] === process.env.VERIFY_TOKEN) { + return res.send(req.query["hub.challenge"]); + } + res.sendStatus(403); +}); -async function saveSheet(data) { - await axios.post(process.env.GOOGLE_SHEET_URL, data); -} +/* ================= START ================= */ -app.listen(process.env.PORT || 3000); +app.listen(PORT, () => { + console.log("Server running on port", PORT); +}); From c21c3384fe1db6a2585a138513d44ace3b4c5d6d Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Sun, 4 Jan 2026 23:59:52 +0530 Subject: [PATCH 26/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 162 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 108 insertions(+), 54 deletions(-) diff --git a/index.js b/index.js index 0a2f2a15f2..76e12bca73 100644 --- a/index.js +++ b/index.js @@ -7,14 +7,14 @@ app.use(bodyParser.json()); const PORT = process.env.PORT || 10000; -/* ================= CONFIG ================= */ +/* ========== CONFIG ========== */ const TOKEN = process.env.WHATSAPP_TOKEN; const PHONE_ID = process.env.PHONE_NUMBER_ID; -const SHEET_URL = process.env.SHEET_WEBHOOK; // Google Apps Script URL +const SHEET_URL = process.env.SHEET_WEBHOOK; const OWNER_UPI = "8121893882-2@ybl"; -/* ================= SESSION ================= */ +/* ========== SESSION STORE ========== */ const sessions = {}; @@ -26,7 +26,7 @@ function newSession(phone) { }; } -/* ================= PRODUCTS ================= */ +/* ========== PRODUCTS ========== */ const PRODUCTS = { "1": { name: "Buffalo Milk", price: 100 }, @@ -37,7 +37,7 @@ const PRODUCTS = { "6": { name: "Talk to Owner" }, }; -/* ================= WHATSAPP SEND ================= */ +/* ========== SEND MESSAGE ========== */ async function sendMessage(to, text) { await axios.post( @@ -56,16 +56,16 @@ async function sendMessage(to, text) { ); } -/* ================= GOOGLE SHEET ================= */ +/* ========== SAVE TO SHEET ========== */ async function saveToSheet(data) { await axios.post(SHEET_URL, data); } -/* ================= MENU ================= */ +/* ========== MENU TEXT ========== */ function menuText() { - return `π₯ Welcome to *Bala Milk Store* + return `π₯ *Welcome to Bala Milk Store* Please choose an option: 1οΈβ£ Buffalo Milk β βΉ100/L @@ -78,15 +78,16 @@ Please choose an option: Reply with option number.`; } -/* ================= WEBHOOK ================= */ +/* ========== WEBHOOK ========== */ app.post("/webhook", async (req, res) => { - const entry = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; - if (!entry) return res.sendStatus(200); + const msg = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; + if (!msg) return res.sendStatus(200); - const from = entry.from; - const text = entry.text?.body?.trim(); - const image = entry.image; + const from = msg.from; + const text = msg.text?.body?.trim(); + const location = msg.location; + const image = msg.image; if (!sessions[from]) { sessions[from] = newSession(from); @@ -99,7 +100,7 @@ app.post("/webhook", async (req, res) => { /* ===== MENU ===== */ if (s.step === "MENU") { if (!PRODUCTS[text]) { - await sendMessage(from, "β Invalid option. Please choose again.\n\n" + menuText()); + await sendMessage(from, "β Invalid option.\n\n" + menuText()); return res.sendStatus(200); } @@ -115,7 +116,12 @@ app.post("/webhook", async (req, res) => { await sendMessage( from, - `π§Ύ *${s.product}*\n\nChoose quantity:\n1οΈβ£ 500ml\n2οΈβ£ 1 L\n3οΈβ£ 2 L` + `π§Ύ *${s.product}* + +Choose quantity: +1οΈβ£ 500ml β βΉ${s.unitPrice * 0.5} +2οΈβ£ 1 L β βΉ${s.unitPrice} +3οΈβ£ 2 L β βΉ${s.unitPrice * 2}` ); return res.sendStatus(200); } @@ -127,20 +133,34 @@ app.post("/webhook", async (req, res) => { return res.sendStatus(200); } - s.quantity = - text === "1" ? "500ml" : text === "2" ? "1L" : "2L"; - - const multiplier = text === "1" ? 0.5 : text === "2" ? 1 : 2; - s.price = s.unitPrice * multiplier; + const map = { + "1": { qty: "500ml", mul: 0.5 }, + "2": { qty: "1L", mul: 1 }, + "3": { qty: "2L", mul: 2 }, + }; + s.quantity = map[text].qty; + s.price = s.unitPrice * map[text].mul; s.step = "ADDRESS"; - await sendMessage(from, "π Please send your delivery address."); + + await sendMessage( + from, + `π *Delivery Address* + +1οΈβ£ Send live location +2οΈβ£ Type address manually` + ); return res.sendStatus(200); } /* ===== ADDRESS ===== */ if (s.step === "ADDRESS") { - s.address = text; + if (location) { + s.address = `Live Location: ${location.latitude}, ${location.longitude}`; + } else { + s.address = text; + } + s.step = "SLOT"; await sendMessage(from, "π Choose delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); return res.sendStatus(200); @@ -162,57 +182,91 @@ app.post("/webhook", async (req, res) => { /* ===== TIME ===== */ if (s.step === "TIME") { s.time = text; - s.step = "PAYMENT"; + s.step = "PAYMENT_CHOICE"; await sendMessage( from, - `π° *Payment Options*\n\nUPI ID:\n${OWNER_UPI}\n\n1οΈβ£ Send payment screenshot\n2οΈβ£ Cash on Delivery` + `π° Choose payment method: +1οΈβ£ UPI +2οΈβ£ Cash on Delivery` ); return res.sendStatus(200); } - /* ===== PAYMENT ===== */ - if (s.step === "PAYMENT") { - if (text === "2") { - s.paymentMethod = "Cash on Delivery"; - } - - if (image) { + /* ===== PAYMENT CHOICE ===== */ + if (s.step === "PAYMENT_CHOICE") { + if (text === "1") { s.paymentMethod = "UPI"; - s.screenshot = image.id; + s.step = "UPI_SCREENSHOT"; + await sendMessage( + from, + `π² Pay using UPI: + +${OWNER_UPI} + +After payment, please send screenshot.` + ); + return res.sendStatus(200); } - if (!s.paymentMethod) { - await sendMessage(from, "β Please choose payment option"); + if (text === "2") { + s.paymentMethod = "Cash on Delivery"; + await finalizeOrder(from, s); return res.sendStatus(200); } - await saveToSheet({ - orderId: s.orderId, - date: new Date().toLocaleString(), - phone: s.phone, - product: s.product, - quantity: s.quantity, - price: s.price, - address: s.address, - delivery: `${s.slot} ${s.time}`, - payment: s.paymentMethod, - screenshot: s.screenshot || "", - }); + await sendMessage(from, "β Choose 1 or 2"); + return res.sendStatus(200); + } - await sendMessage( - from, - `β *Order Confirmed!*\n\nπ§Ύ Order ID: ${s.orderId}\nπ₯ ${s.product}\nπ¦ ${s.quantity}\nπ° βΉ${s.price}\nπ ${s.slot} ${s.time}\n\nπ Thank you for choosing Bala Milk Store` - ); + /* ===== UPI SCREENSHOT ===== */ + if (s.step === "UPI_SCREENSHOT") { + if (!image) { + await sendMessage(from, "β Please send payment screenshot."); + return res.sendStatus(200); + } - delete sessions[from]; // π₯ IMPORTANT + s.screenshot = image.id; + await finalizeOrder(from, s); return res.sendStatus(200); } res.sendStatus(200); }); -/* ================= VERIFY ================= */ +/* ========== FINALIZE ORDER ========== */ + +async function finalizeOrder(from, s) { + await saveToSheet({ + orderId: s.orderId, + date: new Date().toLocaleString(), + phone: s.phone, + product: s.product, + quantity: s.quantity, + price: s.price, + address: s.address, + delivery: `${s.slot} ${s.time}`, + payment: s.paymentMethod, + screenshot: s.screenshot || "", + }); + + await sendMessage( + from, + `β *Order Confirmed!* + +π§Ύ Order ID: ${s.orderId} +π₯ ${s.product} +π¦ ${s.quantity} +π° βΉ${s.price} +π ${s.slot} ${s.time} + +π Thank you for choosing *Bala Milk Store*` + ); + + delete sessions[from]; +} + +/* ========== VERIFY ========== */ app.get("/webhook", (req, res) => { if (req.query["hub.verify_token"] === process.env.VERIFY_TOKEN) { @@ -221,7 +275,7 @@ app.get("/webhook", (req, res) => { res.sendStatus(403); }); -/* ================= START ================= */ +/* ========== START ========== */ app.listen(PORT, () => { console.log("Server running on port", PORT); From b44107b038c264a7593e23c63da13b711018d9a4 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Mon, 5 Jan 2026 10:25:27 +0530 Subject: [PATCH 27/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 156 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 67 deletions(-) diff --git a/index.js b/index.js index 76e12bca73..7666755397 100644 --- a/index.js +++ b/index.js @@ -7,26 +7,14 @@ app.use(bodyParser.json()); const PORT = process.env.PORT || 10000; -/* ========== CONFIG ========== */ - const TOKEN = process.env.WHATSAPP_TOKEN; const PHONE_ID = process.env.PHONE_NUMBER_ID; const SHEET_URL = process.env.SHEET_WEBHOOK; const OWNER_UPI = "8121893882-2@ybl"; -/* ========== SESSION STORE ========== */ - const sessions = {}; -function newSession(phone) { - return { - orderId: "ORD-" + Date.now(), - phone, - step: "MENU", - }; -} - -/* ========== PRODUCTS ========== */ +/* ================= PRODUCTS ================= */ const PRODUCTS = { "1": { name: "Buffalo Milk", price: 100 }, @@ -34,10 +22,24 @@ const PRODUCTS = { "3": { name: "Paneer", price: 600 }, "4": { name: "Ghee", price: 1000 }, "5": { name: "Daily Milk Subscription" }, - "6": { name: "Talk to Owner" }, + "6": { name: "Talk to Owner" } }; -/* ========== SEND MESSAGE ========== */ +/* ================= HELPERS ================= */ + +function menuText() { + return `π₯ *Welcome to Bala Milk Store* + +Please choose an option: +1οΈβ£ Buffalo Milk β βΉ100/L +2οΈβ£ Cow Milk β βΉ120/L +3οΈβ£ Paneer β βΉ600/Kg +4οΈβ£ Ghee β βΉ1000/Kg +5οΈβ£ Daily Milk Subscription +6οΈβ£ Talk to Owner + +Reply with option number.`; +} async function sendMessage(to, text) { await axios.post( @@ -45,40 +47,30 @@ async function sendMessage(to, text) { { messaging_product: "whatsapp", to, - text: { body: text }, + text: { body: text } }, { headers: { Authorization: `Bearer ${TOKEN}`, - "Content-Type": "application/json", - }, + "Content-Type": "application/json" + } } ); } -/* ========== SAVE TO SHEET ========== */ - async function saveToSheet(data) { await axios.post(SHEET_URL, data); } -/* ========== MENU TEXT ========== */ - -function menuText() { - return `π₯ *Welcome to Bala Milk Store* - -Please choose an option: -1οΈβ£ Buffalo Milk β βΉ100/L -2οΈβ£ Cow Milk β βΉ120/L -3οΈβ£ Paneer β βΉ600/Kg -4οΈβ£ Ghee β βΉ1000/Kg -5οΈβ£ Daily Milk Subscription -6οΈβ£ Talk to Owner - -Reply with option number.`; +function newSession(phone) { + return { + orderId: "ORD-" + Date.now(), + phone, + step: "MENU" + }; } -/* ========== WEBHOOK ========== */ +/* ================= WEBHOOK ================= */ app.post("/webhook", async (req, res) => { const msg = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; @@ -97,10 +89,10 @@ app.post("/webhook", async (req, res) => { const s = sessions[from]; - /* ===== MENU ===== */ + /* ============ MENU ============ */ if (s.step === "MENU") { if (!PRODUCTS[text]) { - await sendMessage(from, "β Invalid option.\n\n" + menuText()); + await sendMessage(from, menuText()); return res.sendStatus(200); } @@ -120,53 +112,79 @@ app.post("/webhook", async (req, res) => { Choose quantity: 1οΈβ£ 500ml β βΉ${s.unitPrice * 0.5} -2οΈβ£ 1 L β βΉ${s.unitPrice} -3οΈβ£ 2 L β βΉ${s.unitPrice * 2}` +2οΈβ£ 1L β βΉ${s.unitPrice} +3οΈβ£ 2L β βΉ${s.unitPrice * 2}` ); return res.sendStatus(200); } - /* ===== QUANTITY ===== */ + /* ============ QUANTITY ============ */ if (s.step === "QTY") { - if (!["1", "2", "3"].includes(text)) { - await sendMessage(from, "β Choose 1 / 2 / 3"); - return res.sendStatus(200); - } - const map = { "1": { qty: "500ml", mul: 0.5 }, "2": { qty: "1L", mul: 1 }, - "3": { qty: "2L", mul: 2 }, + "3": { qty: "2L", mul: 2 } }; + if (!map[text]) { + await sendMessage(from, "β Choose 1 / 2 / 3"); + return res.sendStatus(200); + } + s.quantity = map[text].qty; s.price = s.unitPrice * map[text].mul; - s.step = "ADDRESS"; + s.step = "ADDRESS_CHOICE"; await sendMessage( from, `π *Delivery Address* - 1οΈβ£ Send live location 2οΈβ£ Type address manually` ); return res.sendStatus(200); } - /* ===== ADDRESS ===== */ - if (s.step === "ADDRESS") { - if (location) { - s.address = `Live Location: ${location.latitude}, ${location.longitude}`; - } else { - s.address = text; + /* ============ ADDRESS CHOICE ============ */ + if (s.step === "ADDRESS_CHOICE") { + if (text === "1") { + s.step = "WAIT_LOCATION"; + await sendMessage(from, "π Please share your live location now."); + return res.sendStatus(200); + } + + if (text === "2") { + s.step = "ADDRESS_TEXT"; + await sendMessage(from, "βοΈ Please type your delivery address."); + return res.sendStatus(200); + } + + await sendMessage(from, "β Choose 1 or 2"); + return res.sendStatus(200); + } + + /* ============ WAIT LOCATION ============ */ + if (s.step === "WAIT_LOCATION") { + if (!location) { + await sendMessage(from, "π Please send live location using WhatsApp."); + return res.sendStatus(200); } + s.address = `Lat:${location.latitude}, Lng:${location.longitude}`; s.step = "SLOT"; + await sendMessage(from, "π Choose delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); return res.sendStatus(200); } - /* ===== SLOT ===== */ + /* ============ ADDRESS TEXT ============ */ + if (s.step === "ADDRESS_TEXT") { + s.address = text; + s.step = "SLOT"; + await sendMessage(from, "π Choose delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); + return res.sendStatus(200); + } + + /* ============ SLOT ============ */ if (s.step === "SLOT") { if (!["1", "2"].includes(text)) { await sendMessage(from, "β Choose 1 or 2"); @@ -175,11 +193,12 @@ Choose quantity: s.slot = text === "1" ? "Morning" : "Evening"; s.step = "TIME"; + await sendMessage(from, "β° Enter delivery time (example: 6:30 AM)"); return res.sendStatus(200); } - /* ===== TIME ===== */ + /* ============ TIME ============ */ if (s.step === "TIME") { s.time = text; s.step = "PAYMENT_CHOICE"; @@ -193,18 +212,21 @@ Choose quantity: return res.sendStatus(200); } - /* ===== PAYMENT CHOICE ===== */ + /* ============ PAYMENT CHOICE ============ */ if (s.step === "PAYMENT_CHOICE") { if (text === "1") { s.paymentMethod = "UPI"; - s.step = "UPI_SCREENSHOT"; + s.step = "WAIT_SCREENSHOT"; + await sendMessage( from, - `π² Pay using UPI: + `π² *UPI Payment* +UPI ID: ${OWNER_UPI} -After payment, please send screenshot.` +Please complete payment in any UPI app +and send payment screenshot here.` ); return res.sendStatus(200); } @@ -219,8 +241,8 @@ After payment, please send screenshot.` return res.sendStatus(200); } - /* ===== UPI SCREENSHOT ===== */ - if (s.step === "UPI_SCREENSHOT") { + /* ============ SCREENSHOT ============ */ + if (s.step === "WAIT_SCREENSHOT") { if (!image) { await sendMessage(from, "β Please send payment screenshot."); return res.sendStatus(200); @@ -234,7 +256,7 @@ After payment, please send screenshot.` res.sendStatus(200); }); -/* ========== FINALIZE ORDER ========== */ +/* ================= FINALIZE ================= */ async function finalizeOrder(from, s) { await saveToSheet({ @@ -247,7 +269,7 @@ async function finalizeOrder(from, s) { address: s.address, delivery: `${s.slot} ${s.time}`, payment: s.paymentMethod, - screenshot: s.screenshot || "", + screenshot: s.screenshot || "" }); await sendMessage( @@ -260,13 +282,13 @@ async function finalizeOrder(from, s) { π° βΉ${s.price} π ${s.slot} ${s.time} -π Thank you for choosing *Bala Milk Store*` +π *Thank you for ordering from Balaβs Milk Dairy* π₯` ); delete sessions[from]; } -/* ========== VERIFY ========== */ +/* ================= VERIFY ================= */ app.get("/webhook", (req, res) => { if (req.query["hub.verify_token"] === process.env.VERIFY_TOKEN) { @@ -275,7 +297,7 @@ app.get("/webhook", (req, res) => { res.sendStatus(403); }); -/* ========== START ========== */ +/* ================= START ================= */ app.listen(PORT, () => { console.log("Server running on port", PORT); From 4d7f79ee5f3b9098f2bb3974a0e016930fe9c3f7 Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Mon, 5 Jan 2026 10:47:37 +0530 Subject: [PATCH 28/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 175 +++++++++++++++++++++---------------------------------- 1 file changed, 66 insertions(+), 109 deletions(-) diff --git a/index.js b/index.js index 7666755397..a4a363e44f 100644 --- a/index.js +++ b/index.js @@ -6,12 +6,12 @@ const app = express(); app.use(bodyParser.json()); const PORT = process.env.PORT || 10000; - const TOKEN = process.env.WHATSAPP_TOKEN; const PHONE_ID = process.env.PHONE_NUMBER_ID; const SHEET_URL = process.env.SHEET_WEBHOOK; -const OWNER_UPI = "8121893882-2@ybl"; +const VERIFY_TOKEN = process.env.VERIFY_TOKEN; +const OWNER_UPI = "8121893882-2@ybl"; const sessions = {}; /* ================= PRODUCTS ================= */ @@ -20,27 +20,11 @@ const PRODUCTS = { "1": { name: "Buffalo Milk", price: 100 }, "2": { name: "Cow Milk", price: 120 }, "3": { name: "Paneer", price: 600 }, - "4": { name: "Ghee", price: 1000 }, - "5": { name: "Daily Milk Subscription" }, - "6": { name: "Talk to Owner" } + "4": { name: "Ghee", price: 1000 } }; /* ================= HELPERS ================= */ -function menuText() { - return `π₯ *Welcome to Bala Milk Store* - -Please choose an option: -1οΈβ£ Buffalo Milk β βΉ100/L -2οΈβ£ Cow Milk β βΉ120/L -3οΈβ£ Paneer β βΉ600/Kg -4οΈβ£ Ghee β βΉ1000/Kg -5οΈβ£ Daily Milk Subscription -6οΈβ£ Talk to Owner - -Reply with option number.`; -} - async function sendMessage(to, text) { await axios.post( `https://graph.facebook.com/v18.0/${PHONE_ID}/messages`, @@ -62,12 +46,15 @@ async function saveToSheet(data) { await axios.post(SHEET_URL, data); } -function newSession(phone) { - return { - orderId: "ORD-" + Date.now(), - phone, - step: "MENU" - }; +function menuText() { + return `π₯ *Welcome to Balaβs Milk Dairy* + +1οΈβ£ Buffalo Milk β βΉ100/L +2οΈβ£ Cow Milk β βΉ120/L +3οΈβ£ Paneer β βΉ600/Kg +4οΈβ£ Ghee β βΉ1000/Kg + +Reply with option number.`; } /* ================= WEBHOOK ================= */ @@ -77,31 +64,32 @@ app.post("/webhook", async (req, res) => { if (!msg) return res.sendStatus(200); const from = msg.from; - const text = msg.text?.body?.trim(); - const location = msg.location; + const text = msg.text?.body?.trim()?.toLowerCase(); const image = msg.image; + const location = msg.location; + /* ===== START ONLY ON HI ===== */ if (!sessions[from]) { - sessions[from] = newSession(from); - await sendMessage(from, menuText()); + if (text === "hi" || text === "hello") { + sessions[from] = { + orderId: "ORD-" + Date.now(), + phone: from, + step: "MENU" + }; + await sendMessage(from, menuText()); + } return res.sendStatus(200); } const s = sessions[from]; - /* ============ MENU ============ */ + /* ===== MENU ===== */ if (s.step === "MENU") { if (!PRODUCTS[text]) { await sendMessage(from, menuText()); return res.sendStatus(200); } - if (text === "6") { - await sendMessage(from, "π Please call: 8121893882"); - delete sessions[from]; - return res.sendStatus(200); - } - s.product = PRODUCTS[text].name; s.unitPrice = PRODUCTS[text].price; s.step = "QTY"; @@ -109,87 +97,70 @@ app.post("/webhook", async (req, res) => { await sendMessage( from, `π§Ύ *${s.product}* - -Choose quantity: -1οΈβ£ 500ml β βΉ${s.unitPrice * 0.5} +1οΈβ£ 500ml β βΉ${s.unitPrice / 2} 2οΈβ£ 1L β βΉ${s.unitPrice} 3οΈβ£ 2L β βΉ${s.unitPrice * 2}` ); return res.sendStatus(200); } - /* ============ QUANTITY ============ */ + /* ===== QUANTITY ===== */ if (s.step === "QTY") { - const map = { + const q = { "1": { qty: "500ml", mul: 0.5 }, "2": { qty: "1L", mul: 1 }, "3": { qty: "2L", mul: 2 } }; - if (!map[text]) { - await sendMessage(from, "β Choose 1 / 2 / 3"); - return res.sendStatus(200); - } + if (!q[text]) return res.sendStatus(200); - s.quantity = map[text].qty; - s.price = s.unitPrice * map[text].mul; - s.step = "ADDRESS_CHOICE"; + s.quantity = q[text].qty; + s.price = s.unitPrice * q[text].mul; + s.step = "ADDR_TYPE"; await sendMessage( from, - `π *Delivery Address* -1οΈβ£ Send live location -2οΈβ£ Type address manually` + "π Delivery address:\n1οΈβ£ Send live location\n2οΈβ£ Type address" ); return res.sendStatus(200); } - /* ============ ADDRESS CHOICE ============ */ - if (s.step === "ADDRESS_CHOICE") { + /* ===== ADDRESS TYPE ===== */ + if (s.step === "ADDR_TYPE") { if (text === "1") { s.step = "WAIT_LOCATION"; - await sendMessage(from, "π Please share your live location now."); + await sendMessage(from, "π Please share live location now."); return res.sendStatus(200); } - if (text === "2") { - s.step = "ADDRESS_TEXT"; - await sendMessage(from, "βοΈ Please type your delivery address."); + s.step = "ADDR_TEXT"; + await sendMessage(from, "βοΈ Please type your address."); return res.sendStatus(200); } - - await sendMessage(from, "β Choose 1 or 2"); - return res.sendStatus(200); } - /* ============ WAIT LOCATION ============ */ + /* ===== WAIT LOCATION ===== */ if (s.step === "WAIT_LOCATION") { - if (!location) { - await sendMessage(from, "π Please send live location using WhatsApp."); - return res.sendStatus(200); - } + if (!location) return res.sendStatus(200); - s.address = `Lat:${location.latitude}, Lng:${location.longitude}`; + s.address = `Lat:${location.latitude},Lng:${location.longitude}`; s.step = "SLOT"; - await sendMessage(from, "π Choose delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); + await sendMessage(from, "π Delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); return res.sendStatus(200); } - /* ============ ADDRESS TEXT ============ */ - if (s.step === "ADDRESS_TEXT") { + /* ===== ADDRESS TEXT ===== */ + if (s.step === "ADDR_TEXT") { s.address = text; s.step = "SLOT"; - await sendMessage(from, "π Choose delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); + await sendMessage(from, "π Delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); return res.sendStatus(200); } - /* ============ SLOT ============ */ + /* ===== SLOT ===== */ if (s.step === "SLOT") { - if (!["1", "2"].includes(text)) { - await sendMessage(from, "β Choose 1 or 2"); - return res.sendStatus(200); - } + if (!["1", "2"].includes(text)) return res.sendStatus(200); s.slot = text === "1" ? "Morning" : "Evening"; s.step = "TIME"; @@ -198,58 +169,49 @@ Choose quantity: return res.sendStatus(200); } - /* ============ TIME ============ */ + /* ===== TIME ===== */ if (s.step === "TIME") { s.time = text; - s.step = "PAYMENT_CHOICE"; + s.step = "PAYMENT"; await sendMessage( from, - `π° Choose payment method: -1οΈβ£ UPI -2οΈβ£ Cash on Delivery` + "π° Payment method:\n1οΈβ£ UPI\n2οΈβ£ Cash on Delivery" ); return res.sendStatus(200); } - /* ============ PAYMENT CHOICE ============ */ - if (s.step === "PAYMENT_CHOICE") { + /* ===== PAYMENT ===== */ + if (s.step === "PAYMENT") { if (text === "1") { - s.paymentMethod = "UPI"; + s.payment = "UPI"; s.step = "WAIT_SCREENSHOT"; await sendMessage( from, - `π² *UPI Payment* + `π² Pay using any UPI app UPI ID: ${OWNER_UPI} -Please complete payment in any UPI app -and send payment screenshot here.` +After payment, send screenshot here.` ); return res.sendStatus(200); } if (text === "2") { - s.paymentMethod = "Cash on Delivery"; - await finalizeOrder(from, s); + s.payment = "Cash on Delivery"; + await finalize(from, s); return res.sendStatus(200); } - - await sendMessage(from, "β Choose 1 or 2"); - return res.sendStatus(200); } - /* ============ SCREENSHOT ============ */ + /* ===== SCREENSHOT ===== */ if (s.step === "WAIT_SCREENSHOT") { - if (!image) { - await sendMessage(from, "β Please send payment screenshot."); - return res.sendStatus(200); - } + if (!image) return res.sendStatus(200); s.screenshot = image.id; - await finalizeOrder(from, s); + await finalize(from, s); return res.sendStatus(200); } @@ -258,23 +220,22 @@ and send payment screenshot here.` /* ================= FINALIZE ================= */ -async function finalizeOrder(from, s) { +async function finalize(from, s) { await saveToSheet({ orderId: s.orderId, - date: new Date().toLocaleString(), phone: s.phone, product: s.product, quantity: s.quantity, price: s.price, address: s.address, delivery: `${s.slot} ${s.time}`, - payment: s.paymentMethod, + payment: s.payment, screenshot: s.screenshot || "" }); await sendMessage( from, - `β *Order Confirmed!* + `β *Order Confirmed* π§Ύ Order ID: ${s.orderId} π₯ ${s.product} @@ -282,23 +243,19 @@ async function finalizeOrder(from, s) { π° βΉ${s.price} π ${s.slot} ${s.time} -π *Thank you for ordering from Balaβs Milk Dairy* π₯` +π Thank you for ordering from *Balaβs Milk Dairy* π₯` ); - delete sessions[from]; + delete sessions[from]; // π₯ THIS STOPS MENU REPEAT } /* ================= VERIFY ================= */ app.get("/webhook", (req, res) => { - if (req.query["hub.verify_token"] === process.env.VERIFY_TOKEN) { + if (req.query["hub.verify_token"] === VERIFY_TOKEN) { return res.send(req.query["hub.challenge"]); } res.sendStatus(403); }); -/* ================= START ================= */ - -app.listen(PORT, () => { - console.log("Server running on port", PORT); -}); +app.listen(PORT, () => console.log("Running on", PORT)); From aeb7b7867475cce852c20261239d7a641892d17d Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Mon, 5 Jan 2026 10:57:12 +0530 Subject: [PATCH 29/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 132 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 40 deletions(-) diff --git a/index.js b/index.js index a4a363e44f..703aa4b9b6 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,9 @@ const PRODUCTS = { "1": { name: "Buffalo Milk", price: 100 }, "2": { name: "Cow Milk", price: 120 }, "3": { name: "Paneer", price: 600 }, - "4": { name: "Ghee", price: 1000 } + "4": { name: "Ghee", price: 1000 }, + "5": { name: "Daily Milk Subscription" }, + "6": { name: "Enquiry / Talk to Owner" } }; /* ================= HELPERS ================= */ @@ -47,14 +49,17 @@ async function saveToSheet(data) { } function menuText() { - return `π₯ *Welcome to Balaβs Milk Dairy* + return `π₯ *Balaβs Milk Dairy* 1οΈβ£ Buffalo Milk β βΉ100/L 2οΈβ£ Cow Milk β βΉ120/L 3οΈβ£ Paneer β βΉ600/Kg 4οΈβ£ Ghee β βΉ1000/Kg +5οΈβ£ Daily Milk Subscription +6οΈβ£ Enquiry / Talk to Owner -Reply with option number.`; +Reply with option number. +Type *0* anytime to go back.`; } /* ================= WEBHOOK ================= */ @@ -64,13 +69,13 @@ app.post("/webhook", async (req, res) => { if (!msg) return res.sendStatus(200); const from = msg.from; - const text = msg.text?.body?.trim()?.toLowerCase(); + const text = msg.text?.body?.trim(); const image = msg.image; const location = msg.location; /* ===== START ONLY ON HI ===== */ if (!sessions[from]) { - if (text === "hi" || text === "hello") { + if (text?.toLowerCase() === "hi" || text?.toLowerCase() === "hello") { sessions[from] = { orderId: "ORD-" + Date.now(), phone: from, @@ -83,8 +88,26 @@ app.post("/webhook", async (req, res) => { const s = sessions[from]; + /* ===== BACK BUTTON ===== */ + if (text === "0") { + if (s.step === "MENU") { + await sendMessage(from, menuText()); + return res.sendStatus(200); + } + s.step = s.prev || "MENU"; + await sendMessage(from, menuText()); + return res.sendStatus(200); + } + /* ===== MENU ===== */ if (s.step === "MENU") { + if (text === "6") { + s.prev = "MENU"; + s.step = "ENQUIRY"; + await sendMessage(from, "βοΈ Please type your enquiry.\n(0 = Back)"); + return res.sendStatus(200); + } + if (!PRODUCTS[text]) { await sendMessage(from, menuText()); return res.sendStatus(200); @@ -92,35 +115,61 @@ app.post("/webhook", async (req, res) => { s.product = PRODUCTS[text].name; s.unitPrice = PRODUCTS[text].price; + s.prev = "MENU"; s.step = "QTY"; await sendMessage( from, `π§Ύ *${s.product}* + 1οΈβ£ 500ml β βΉ${s.unitPrice / 2} 2οΈβ£ 1L β βΉ${s.unitPrice} -3οΈβ£ 2L β βΉ${s.unitPrice * 2}` +3οΈβ£ 2L β βΉ${s.unitPrice * 2} + +0οΈβ£ Back` ); return res.sendStatus(200); } + /* ===== ENQUIRY ===== */ + if (s.step === "ENQUIRY") { + await saveToSheet({ + Type: "Enquiry", + OrderId: "", + Phone: s.phone, + Enquiry: text, + Date: new Date().toLocaleString() + }); + + await sendMessage( + from, + `π Thank you for contacting *Balaβs Milk Dairy*. + +We will get back to you shortly.` + ); + + delete sessions[from]; + return res.sendStatus(200); + } + /* ===== QUANTITY ===== */ if (s.step === "QTY") { - const q = { + const map = { "1": { qty: "500ml", mul: 0.5 }, "2": { qty: "1L", mul: 1 }, "3": { qty: "2L", mul: 2 } }; - if (!q[text]) return res.sendStatus(200); + if (!map[text]) return res.sendStatus(200); - s.quantity = q[text].qty; - s.price = s.unitPrice * q[text].mul; + s.quantity = map[text].qty; + s.price = s.unitPrice * map[text].mul; + s.prev = "QTY"; s.step = "ADDR_TYPE"; await sendMessage( from, - "π Delivery address:\n1οΈβ£ Send live location\n2οΈβ£ Type address" + "π Delivery Address:\n1οΈβ£ Send live location\n2οΈβ£ Type address\n0οΈβ£ Back" ); return res.sendStatus(200); } @@ -128,13 +177,15 @@ app.post("/webhook", async (req, res) => { /* ===== ADDRESS TYPE ===== */ if (s.step === "ADDR_TYPE") { if (text === "1") { + s.prev = "ADDR_TYPE"; s.step = "WAIT_LOCATION"; - await sendMessage(from, "π Please share live location now."); + await sendMessage(from, "π Please share live location now.\n0οΈβ£ Back"); return res.sendStatus(200); } if (text === "2") { + s.prev = "ADDR_TYPE"; s.step = "ADDR_TEXT"; - await sendMessage(from, "βοΈ Please type your address."); + await sendMessage(from, "βοΈ Type your address.\n0οΈβ£ Back"); return res.sendStatus(200); } } @@ -142,41 +193,40 @@ app.post("/webhook", async (req, res) => { /* ===== WAIT LOCATION ===== */ if (s.step === "WAIT_LOCATION") { if (!location) return res.sendStatus(200); - s.address = `Lat:${location.latitude},Lng:${location.longitude}`; + s.prev = "WAIT_LOCATION"; s.step = "SLOT"; - - await sendMessage(from, "π Delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); + await sendMessage(from, "π Delivery Slot:\n1οΈβ£ Morning\n2οΈβ£ Evening\n0οΈβ£ Back"); return res.sendStatus(200); } /* ===== ADDRESS TEXT ===== */ if (s.step === "ADDR_TEXT") { s.address = text; + s.prev = "ADDR_TEXT"; s.step = "SLOT"; - await sendMessage(from, "π Delivery slot:\n1οΈβ£ Morning\n2οΈβ£ Evening"); + await sendMessage(from, "π Delivery Slot:\n1οΈβ£ Morning\n2οΈβ£ Evening\n0οΈβ£ Back"); return res.sendStatus(200); } /* ===== SLOT ===== */ if (s.step === "SLOT") { if (!["1", "2"].includes(text)) return res.sendStatus(200); - s.slot = text === "1" ? "Morning" : "Evening"; + s.prev = "SLOT"; s.step = "TIME"; - - await sendMessage(from, "β° Enter delivery time (example: 6:30 AM)"); + await sendMessage(from, "β° Enter delivery time (e.g. 6:30 AM)\n0οΈβ£ Back"); return res.sendStatus(200); } /* ===== TIME ===== */ if (s.step === "TIME") { s.time = text; + s.prev = "TIME"; s.step = "PAYMENT"; - await sendMessage( from, - "π° Payment method:\n1οΈβ£ UPI\n2οΈβ£ Cash on Delivery" + "π° Payment Method:\n1οΈβ£ UPI\n2οΈβ£ Cash on Delivery\n0οΈβ£ Back" ); return res.sendStatus(200); } @@ -185,23 +235,24 @@ app.post("/webhook", async (req, res) => { if (s.step === "PAYMENT") { if (text === "1") { s.payment = "UPI"; + s.prev = "PAYMENT"; s.step = "WAIT_SCREENSHOT"; - await sendMessage( from, - `π² Pay using any UPI app + `π² Pay via any UPI app UPI ID: ${OWNER_UPI} -After payment, send screenshot here.` +Send payment screenshot here. +0οΈβ£ Back` ); return res.sendStatus(200); } if (text === "2") { s.payment = "Cash on Delivery"; - await finalize(from, s); + await finalizeOrder(from, s); return res.sendStatus(200); } } @@ -209,9 +260,8 @@ After payment, send screenshot here.` /* ===== SCREENSHOT ===== */ if (s.step === "WAIT_SCREENSHOT") { if (!image) return res.sendStatus(200); - s.screenshot = image.id; - await finalize(from, s); + await finalizeOrder(from, s); return res.sendStatus(200); } @@ -220,17 +270,19 @@ After payment, send screenshot here.` /* ================= FINALIZE ================= */ -async function finalize(from, s) { +async function finalizeOrder(from, s) { await saveToSheet({ - orderId: s.orderId, - phone: s.phone, - product: s.product, - quantity: s.quantity, - price: s.price, - address: s.address, - delivery: `${s.slot} ${s.time}`, - payment: s.payment, - screenshot: s.screenshot || "" + Type: "Order", + OrderId: s.orderId, + Phone: s.phone, + Product: s.product, + Quantity: s.quantity, + Price: s.price, + Address: s.address, + Delivery: `${s.slot} ${s.time}`, + Payment: s.payment, + Screenshot: s.screenshot || "", + Date: new Date().toLocaleString() }); await sendMessage( @@ -246,7 +298,7 @@ async function finalize(from, s) { π Thank you for ordering from *Balaβs Milk Dairy* π₯` ); - delete sessions[from]; // π₯ THIS STOPS MENU REPEAT + delete sessions[from]; } /* ================= VERIFY ================= */ @@ -258,4 +310,4 @@ app.get("/webhook", (req, res) => { res.sendStatus(403); }); -app.listen(PORT, () => console.log("Running on", PORT)); +app.listen(PORT, () => console.log("Server running on", PORT)); From b161dca9d8b0d3619ab105e90a454b52935e89ac Mon Sep 17 00:00:00 2001 From: 000balaai-cloud <000balaai@gmail.com> Date: Mon, 5 Jan 2026 11:33:45 +0530 Subject: [PATCH 30/30] Update index.js Signed-off-by: 000balaai-cloud <000balaai@gmail.com> --- index.js | 494 ++++++++++++++++++++++++------------------------------- 1 file changed, 211 insertions(+), 283 deletions(-) diff --git a/index.js b/index.js index 703aa4b9b6..2db32461a9 100644 --- a/index.js +++ b/index.js @@ -1,313 +1,241 @@ -const express = require("express"); const axios = require("axios"); -const bodyParser = require("body-parser"); -const app = express(); -app.use(bodyParser.json()); +const SCRIPT_URL = "PASTE_YOUR_NEW_GOOGLE_SCRIPT_URL_HERE"; +const UPI_ID = "8121893882-2@ybl"; -const PORT = process.env.PORT || 10000; -const TOKEN = process.env.WHATSAPP_TOKEN; -const PHONE_ID = process.env.PHONE_NUMBER_ID; -const SHEET_URL = process.env.SHEET_WEBHOOK; -const VERIFY_TOKEN = process.env.VERIFY_TOKEN; +let sessions = {}; -const OWNER_UPI = "8121893882-2@ybl"; -const sessions = {}; +module.exports = async (req, res) => { + const msg = req.body.data?.body?.trim(); + const from = req.body.data?.from; + const name = req.body.data?.notifyName || ""; -/* ================= PRODUCTS ================= */ + if (!sessions[from]) { + sessions[from] = { step: "MENU", phone: from, name }; + } -const PRODUCTS = { - "1": { name: "Buffalo Milk", price: 100 }, - "2": { name: "Cow Milk", price: 120 }, - "3": { name: "Paneer", price: 600 }, - "4": { name: "Ghee", price: 1000 }, - "5": { name: "Daily Milk Subscription" }, - "6": { name: "Enquiry / Talk to Owner" } -}; + const s = sessions[from]; -/* ================= HELPERS ================= */ - -async function sendMessage(to, text) { - await axios.post( - `https://graph.facebook.com/v18.0/${PHONE_ID}/messages`, - { - messaging_product: "whatsapp", - to, - text: { body: text } - }, - { - headers: { - Authorization: `Bearer ${TOKEN}`, - "Content-Type": "application/json" - } - } - ); -} + // BACK OPTION + if (msg === "0") { + s.step = "MENU"; + } -async function saveToSheet(data) { - await axios.post(SHEET_URL, data); -} + let reply = ""; + + switch (s.step) { -function menuText() { - return `π₯ *Balaβs Milk Dairy* + // ---------------- MENU ---------------- + case "MENU": + reply = +`π₯ *Welcome to Bala Milk Dairy* +Please choose an option: 1οΈβ£ Buffalo Milk β βΉ100/L 2οΈβ£ Cow Milk β βΉ120/L 3οΈβ£ Paneer β βΉ600/Kg 4οΈβ£ Ghee β βΉ1000/Kg 5οΈβ£ Daily Milk Subscription -6οΈβ£ Enquiry / Talk to Owner - -Reply with option number. -Type *0* anytime to go back.`; -} - -/* ================= WEBHOOK ================= */ - -app.post("/webhook", async (req, res) => { - const msg = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; - if (!msg) return res.sendStatus(200); - - const from = msg.from; - const text = msg.text?.body?.trim(); - const image = msg.image; - const location = msg.location; +6οΈβ£ Enquiry Only + +Reply with option number.`; + s.step = "PRODUCT"; + break; + + // ---------------- PRODUCT ---------------- + case "PRODUCT": + if (msg === "6") { + s.type = "Enquiry"; + s.step = "ENQUIRY"; + reply = "βοΈ Please type your enquiry.\n\n0οΈβ£ Back"; + break; + } - /* ===== START ONLY ON HI ===== */ - if (!sessions[from]) { - if (text?.toLowerCase() === "hi" || text?.toLowerCase() === "hello") { - sessions[from] = { - orderId: "ORD-" + Date.now(), - phone: from, - step: "MENU" + const products = { + "1": { name: "Buffalo Milk", price: 100 }, + "2": { name: "Cow Milk", price: 120 }, + "3": { name: "Paneer", price: 600 }, + "4": { name: "Ghee", price: 1000 } }; - await sendMessage(from, menuText()); - } - return res.sendStatus(200); - } - - const s = sessions[from]; - - /* ===== BACK BUTTON ===== */ - if (text === "0") { - if (s.step === "MENU") { - await sendMessage(from, menuText()); - return res.sendStatus(200); - } - s.step = s.prev || "MENU"; - await sendMessage(from, menuText()); - return res.sendStatus(200); - } - - /* ===== MENU ===== */ - if (s.step === "MENU") { - if (text === "6") { - s.prev = "MENU"; - s.step = "ENQUIRY"; - await sendMessage(from, "βοΈ Please type your enquiry.\n(0 = Back)"); - return res.sendStatus(200); - } - - if (!PRODUCTS[text]) { - await sendMessage(from, menuText()); - return res.sendStatus(200); - } - - s.product = PRODUCTS[text].name; - s.unitPrice = PRODUCTS[text].price; - s.prev = "MENU"; - s.step = "QTY"; - - await sendMessage( - from, - `π§Ύ *${s.product}* - -1οΈβ£ 500ml β βΉ${s.unitPrice / 2} -2οΈβ£ 1L β βΉ${s.unitPrice} -3οΈβ£ 2L β βΉ${s.unitPrice * 2} - -0οΈβ£ Back` - ); - return res.sendStatus(200); - } - - /* ===== ENQUIRY ===== */ - if (s.step === "ENQUIRY") { - await saveToSheet({ - Type: "Enquiry", - OrderId: "", - Phone: s.phone, - Enquiry: text, - Date: new Date().toLocaleString() - }); - - await sendMessage( - from, - `π Thank you for contacting *Balaβs Milk Dairy*. - -We will get back to you shortly.` - ); - - delete sessions[from]; - return res.sendStatus(200); - } - - /* ===== QUANTITY ===== */ - if (s.step === "QTY") { - const map = { - "1": { qty: "500ml", mul: 0.5 }, - "2": { qty: "1L", mul: 1 }, - "3": { qty: "2L", mul: 2 } - }; - - if (!map[text]) return res.sendStatus(200); - - s.quantity = map[text].qty; - s.price = s.unitPrice * map[text].mul; - s.prev = "QTY"; - s.step = "ADDR_TYPE"; - - await sendMessage( - from, - "π Delivery Address:\n1οΈβ£ Send live location\n2οΈβ£ Type address\n0οΈβ£ Back" - ); - return res.sendStatus(200); - } - - /* ===== ADDRESS TYPE ===== */ - if (s.step === "ADDR_TYPE") { - if (text === "1") { - s.prev = "ADDR_TYPE"; - s.step = "WAIT_LOCATION"; - await sendMessage(from, "π Please share live location now.\n0οΈβ£ Back"); - return res.sendStatus(200); - } - if (text === "2") { - s.prev = "ADDR_TYPE"; - s.step = "ADDR_TEXT"; - await sendMessage(from, "βοΈ Type your address.\n0οΈβ£ Back"); - return res.sendStatus(200); - } - } - /* ===== WAIT LOCATION ===== */ - if (s.step === "WAIT_LOCATION") { - if (!location) return res.sendStatus(200); - s.address = `Lat:${location.latitude},Lng:${location.longitude}`; - s.prev = "WAIT_LOCATION"; - s.step = "SLOT"; - await sendMessage(from, "π Delivery Slot:\n1οΈβ£ Morning\n2οΈβ£ Evening\n0οΈβ£ Back"); - return res.sendStatus(200); - } - - /* ===== ADDRESS TEXT ===== */ - if (s.step === "ADDR_TEXT") { - s.address = text; - s.prev = "ADDR_TEXT"; - s.step = "SLOT"; - await sendMessage(from, "π Delivery Slot:\n1οΈβ£ Morning\n2οΈβ£ Evening\n0οΈβ£ Back"); - return res.sendStatus(200); - } + if (!products[msg]) { + reply = "β Invalid option.\n0οΈβ£ Back"; + break; + } - /* ===== SLOT ===== */ - if (s.step === "SLOT") { - if (!["1", "2"].includes(text)) return res.sendStatus(200); - s.slot = text === "1" ? "Morning" : "Evening"; - s.prev = "SLOT"; - s.step = "TIME"; - await sendMessage(from, "β° Enter delivery time (e.g. 6:30 AM)\n0οΈβ£ Back"); - return res.sendStatus(200); - } + s.product = products[msg]; + reply = +`π§Ύ *${s.product.name}* + +Choose quantity: +1οΈβ£ 500ml β βΉ${s.product.price / 2} +2οΈβ£ 1 L β βΉ${s.product.price} +3οΈβ£ 2 L β βΉ${s.product.price * 2} + +0οΈβ£ Back`; + s.step = "QUANTITY"; + break; + + // ---------------- QUANTITY ---------------- + case "QUANTITY": + const qtyMap = { + "1": { q: "500ml", m: 0.5 }, + "2": { q: "1L", m: 1 }, + "3": { q: "2L", m: 2 } + }; - /* ===== TIME ===== */ - if (s.step === "TIME") { - s.time = text; - s.prev = "TIME"; - s.step = "PAYMENT"; - await sendMessage( - from, - "π° Payment Method:\n1οΈβ£ UPI\n2οΈβ£ Cash on Delivery\n0οΈβ£ Back" - ); - return res.sendStatus(200); - } + if (!qtyMap[msg]) { + reply = "β Choose valid quantity.\n0οΈβ£ Back"; + break; + } - /* ===== PAYMENT ===== */ - if (s.step === "PAYMENT") { - if (text === "1") { - s.payment = "UPI"; - s.prev = "PAYMENT"; - s.step = "WAIT_SCREENSHOT"; - await sendMessage( - from, - `π² Pay via any UPI app - -UPI ID: -${OWNER_UPI} - -Send payment screenshot here. -0οΈβ£ Back` - ); - return res.sendStatus(200); - } - - if (text === "2") { - s.payment = "Cash on Delivery"; - await finalizeOrder(from, s); - return res.sendStatus(200); - } - } + s.quantity = qtyMap[msg].q; + s.price = s.product.price * qtyMap[msg].m; + + reply = +`π Delivery Address: +1οΈβ£ Send live location +2οΈβ£ Type address manually + +0οΈβ£ Back`; + s.step = "ADDRESS"; + break; + + // ---------------- ADDRESS ---------------- + case "ADDRESS": + if (msg === "1") { + reply = "π Please share live location now."; + s.step = "LOCATION"; + } else if (msg === "2") { + reply = "βοΈ Please type your full address.\n\n0οΈβ£ Back"; + s.step = "ADDRESS_TEXT"; + } else { + reply = "β Invalid option.\n0οΈβ£ Back"; + } + break; + + case "ADDRESS_TEXT": + s.address = msg; + s.step = "DELIVERY"; + reply = +`β° Delivery Slot: +1οΈβ£ Morning +2οΈβ£ Evening + +0οΈβ£ Back`; + break; + + case "LOCATION": + s.address = "Live Location Shared"; + s.step = "DELIVERY"; + reply = +`β° Delivery Slot: +1οΈβ£ Morning +2οΈβ£ Evening + +0οΈβ£ Back`; + break; + + // ---------------- DELIVERY ---------------- + case "DELIVERY": + if (msg === "1") s.delivery = "Morning"; + else if (msg === "2") s.delivery = "Evening"; + else { + reply = "β Invalid option.\n0οΈβ£ Back"; + break; + } - /* ===== SCREENSHOT ===== */ - if (s.step === "WAIT_SCREENSHOT") { - if (!image) return res.sendStatus(200); - s.screenshot = image.id; - await finalizeOrder(from, s); - return res.sendStatus(200); + reply = +`π Enter delivery time (example: 6:30 AM)\n\n0οΈβ£ Back`; + s.step = "TIME"; + break; + + case "TIME": + s.deliveryTime = `${s.delivery} ${msg}`; + reply = +`π° Payment Method: +1οΈβ£ UPI +2οΈβ£ Cash on Delivery + +0οΈβ£ Back`; + s.step = "PAYMENT"; + break; + + // ---------------- PAYMENT ---------------- + case "PAYMENT": + if (msg === "1") { + s.payment = "UPI"; + reply = +`π³ Pay using UPI: +π ${UPI_ID} + +πΈ After payment, send screenshot. + +0οΈβ£ Back`; + s.step = "SCREENSHOT"; + } else if (msg === "2") { + s.payment = "Cash on Delivery"; + await saveToSheet(s, "COD"); + reply = +`β Order Confirmed! + +π Thank you for ordering from *Bala Milk Dairy* π₯`; + delete sessions[from]; + } else { + reply = "β Invalid option.\n0οΈβ£ Back"; + } + break; + + // ---------------- SCREENSHOT ---------------- + case "SCREENSHOT": + await saveToSheet(s, "UPI Screenshot"); + reply = +`β Payment received! + +π Thank you for ordering from *Bala Milk Dairy* π₯`; + delete sessions[from]; + break; + + // ---------------- ENQUIRY ---------------- + case "ENQUIRY": + await saveToSheet({ + phone: s.phone, + name: s.name, + type: "Enquiry", + product: msg + }, "Enquiry"); + + reply = +`π Thank you for contacting *Bala Milk Dairy*. +We will get back to you soon.`; + delete sessions[from]; + break; } + await sendMessage(from, reply); res.sendStatus(200); -}); +}; -/* ================= FINALIZE ================= */ +// -------- SEND MESSAGE ---------- +async function sendMessage(to, body) { + await axios.post(process.env.WHATSAPP_API_URL, { + to, + body + }); +} -async function finalizeOrder(from, s) { - await saveToSheet({ - Type: "Order", - OrderId: s.orderId, +// -------- SAVE TO GOOGLE SHEET ---------- +async function saveToSheet(s, method) { + await axios.post(SCRIPT_URL, { + OrderId: "ORD-" + Date.now(), Phone: s.phone, - Product: s.product, - Quantity: s.quantity, - Price: s.price, - Address: s.address, - Delivery: `${s.slot} ${s.time}`, - Payment: s.payment, - Screenshot: s.screenshot || "", - Date: new Date().toLocaleString() + ContactName: s.name, + Type: s.type || "Payment", + Product: s.product?.name || "", + Quantity: s.quantity || "", + Price: s.price || "", + Address: s.address || "", + Delivery: s.deliveryTime || "", + Payment: method }); - - await sendMessage( - from, - `β *Order Confirmed* - -π§Ύ Order ID: ${s.orderId} -π₯ ${s.product} -π¦ ${s.quantity} -π° βΉ${s.price} -π ${s.slot} ${s.time} - -π Thank you for ordering from *Balaβs Milk Dairy* π₯` - ); - - delete sessions[from]; } - -/* ================= VERIFY ================= */ - -app.get("/webhook", (req, res) => { - if (req.query["hub.verify_token"] === VERIFY_TOKEN) { - return res.send(req.query["hub.challenge"]); - } - res.sendStatus(403); -}); - -app.listen(PORT, () => console.log("Server running on", PORT));