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 @@ -

Getting Started on Heroku with Node.js

+

Hello from Balaraju πŸš€

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));