From f25fdaa10ae7afdd44afb076d98dc3e8c3566863 Mon Sep 17 00:00:00 2001
From: shreyvishal <shreya.vishal@eminds.ai>
Date: Mon, 1 Apr 2024 19:28:35 +0530
Subject: [PATCH] Fixed: As per the comment

---
 .env.sample                                  |  3 +-
 config/openai.json                           | 12 ++-
 controllers/ControlCenter.js                 | 87 ++++++++++----------
 server.js                                    |  8 +-
 services/Actions.js                          |  2 +-
 services/notificationService.js              | 30 -------
 tests/unit/controllers/controlCenter.test.js | 78 ++++++++++++++++++
 utils/constants.js                           |  3 -
 8 files changed, 137 insertions(+), 86 deletions(-)
 delete mode 100644 services/notificationService.js
 create mode 100644 tests/unit/controllers/controlCenter.test.js

diff --git a/.env.sample b/.env.sample
index 29ec50d..dc7d944 100644
--- a/.env.sample
+++ b/.env.sample
@@ -6,4 +6,5 @@ SERVER_PORT=3001
 TWILIO_ACCOUNT_SID=
 TWILIO_AUTH_TOKEN= 
 TWILIO_NUMBER= 
-TEST_RECEPIENT_NUMBER=
\ No newline at end of file
+TEST_RECEPIENT_NUMBER=
+STRAPI_TOURISM_TOKEN=
\ No newline at end of file
diff --git a/config/openai.json b/config/openai.json
index 7ca9729..041363b 100644
--- a/config/openai.json
+++ b/config/openai.json
@@ -11,6 +11,14 @@
         { "role": "system", "content": "A typical order flow should be search > select > init > confirm."},
         { "role": "system", "content": "Use the response of search from assistant to select items from the list of items provided by the assistant."},
         { "role": "system", "content": "Use the response of search request from assistant for filling transaction_id, bpp_id, bpp_uri in the context of all calls except `search`."},
-        { "role": "system", "content": "For `select`, `init`, `confirm`, you must use the item `id` as part of the payload for selected item instead of name or any other key."}
-    ]
+        { "role": "system", "content": "Use the response from assistant to select items from the list of items provided by the assistant."}
+
+    ],
+    "PRESETS" : {
+        "bap_id": "mit-ps-bap.becknprotocol.io",
+        "bap_uri": "https://mit-ps-bap.becknprotocol.io",
+        "version": "1.1.0",
+        "base_url": "https://mit-ps-bap-client.becknprotocol.io",
+        "TOURISM_STRAPI_URL": "https://mit-bpp-tourism.becknprotocol.io/api"
+    }
 }
\ No newline at end of file
diff --git a/controllers/ControlCenter.js b/controllers/ControlCenter.js
index 914da10..e93120a 100644
--- a/controllers/ControlCenter.js
+++ b/controllers/ControlCenter.js
@@ -1,49 +1,49 @@
-import axios from 'axios'
 import Actions from '../services/Actions.js'
+import { readFileSync } from 'fs';
 import logger from '../utils/logger.js'
 import {
     ITEM_ID,
     ITEM_NAME,
     CAT_ATTR_TAG_RELATIONS,
-    STRAPI_TOURISM_TOKEN,
     NEW_CATALOG_AVAILABLE,
     TRIGGER_BLIZZARD_MESSAGE,
     CANCEL_BOOKING_MESSAGE
 } from '../utils/constants.js'
+const config = JSON.parse(readFileSync('./config/openai.json'))
 
 const action = new Actions()
-const TOURISM_STRAPI_URL = process.env.TOURISM_STRAPI_URL || ''
-const TWILIO_RECEPIENT_NUMBER = process.env.TOURISM_STRAPI_URL
-export const cancelBookingController = async (req, res) => {
+const STRAPI_TOURISM_TOKEN = process.env.STRAPI_TOURISM_TOKEN || ''
+const TWILIO_RECEPIENT_NUMBER = process.env.TEST_RECEPIENT_NUMBER
+export const cancelBooking = async (req, res) => {
     try {
         const { orderId } = req.body
+        if(!orderId){
+            return res.status(500).json({message:"Order Id is Required", status:false})
+        }
+        const validOrderId = await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/orders/${orderId}`,'GET',{},{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`})
+        if(!validOrderId.status){
+            return res.send({ message: `Invalid Order Id`, status:false })
+        }
         const messageBody = CANCEL_BOOKING_MESSAGE;
-        const getOrderFulfillmentDetails = await axios.get(
-            `${TOURISM_STRAPI_URL}/order-fulfillments?order_id=${orderId}`,
-            {
-                headers: {
-                    Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`,
-                },
-            }
-        )
+        const getOrderAddressDetails = await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/order-addresses?order_id=${orderId}`,'GET',{},{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`})
+        
+        const getOrderFulfillmentDetails = await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/order-fulfillments?order_id=${orderId}`,'GET',{},{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`})
         if (getOrderFulfillmentDetails.data.data.length) {
-            await axios.put(
-                `${TOURISM_STRAPI_URL}/order-fulfillments/${getOrderFulfillmentDetails.data.data[0].id}`,
-                {
-                    data: {
-                        state_code: 'CANCELLED',
-                        state_value: 'CANCELLED BY HOTEL',
-                    },
+            await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/order-fulfillments/${getOrderFulfillmentDetails.data.data[0].id}`,'PUT',{
+                data: {
+                    state_code: 'CANCELLED',
+                    state_value: 'CANCELLED BY HOTEL',
                 },
-                {
-                    headers: {
-                        Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`,
-                    },
-                }
-            )
-
-            await action.send_message(TWILIO_RECEPIENT_NUMBER, messageBody)
-            return res.send({ message: 'Notified' })
+            },{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`})
+            let statusMessage = "";
+            
+            if(getOrderAddressDetails.data.data[0].attributes.phone){
+                statusMessage = (await action.send_message(`+91${getOrderAddressDetails.data.data[0].attributes.phone}`, messageBody)).status.status
+            }
+            else{
+                statusMessage = (await action.send_message(TWILIO_RECEPIENT_NUMBER, messageBody)).status.status
+            }
+            return res.send({ message: `Notification ${statusMessage}` })
         }
 
         return res.send({ message: 'Cancel Booking Failed' })
@@ -55,22 +55,18 @@ export const cancelBookingController = async (req, res) => {
 
 export const updateCatalog = async (req, res) => {
     try {
+        const { userNo = TWILIO_RECEPIENT_NUMBER } = req.body;
         const messageBody = NEW_CATALOG_AVAILABLE;
-        await axios.put(
-            `${TOURISM_STRAPI_URL}/items/${ITEM_ID}`,
-            {
-                data: {
-                    name: ITEM_NAME,
-                    cat_attr_tag_relations: CAT_ATTR_TAG_RELATIONS,
-                },
+        await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/items/${ITEM_ID}`,'PUT',{
+            data: {
+                name: ITEM_NAME,
+                cat_attr_tag_relations: CAT_ATTR_TAG_RELATIONS,
             },
-            {
-                headers: {
-                    Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`,
-                },
-            }
-        )
-        await action.send_message(TWILIO_RECEPIENT_NUMBER, messageBody)
+        },{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`})
+        const notifyResponse = await action.send_message(userNo, messageBody)
+        if(notifyResponse.status.status === "failed"){
+            throw new Error('Notification Failed')
+        }
         return res.send({ message: 'Catalog Updated' })
     } catch (error) {
         logger.error(error.message)
@@ -79,11 +75,12 @@ export const updateCatalog = async (req, res) => {
 }
 
 
-export const notificationController = async (req, res) => {
+export const notify = async (req, res) => {
     try {
+        const { userNo = TWILIO_RECEPIENT_NUMBER } = req.body;
         const messageBody = TRIGGER_BLIZZARD_MESSAGE;
         const sendWhatsappNotificationResponse = await action.send_message(
-            TWILIO_RECEPIENT_NUMBER,
+            userNo,
             messageBody
         )
         return res.send(sendWhatsappNotificationResponse)
diff --git a/server.js b/server.js
index b5ef7b9..e3f73a4 100644
--- a/server.js
+++ b/server.js
@@ -6,10 +6,10 @@ import bodyParser from 'body-parser'
 import logger from './utils/logger.js'
 import messageController from './controllers/Bot.js'
 import DBService from './services/DBService.js'
-import { notificationController } from './controllers/Notification.js'
 import {
-    cancelBookingController,
+    cancelBooking,
     updateCatalog,
+    notify
 } from './controllers/ControlCenter.js'
 const app = express()
 app.use(cors())
@@ -22,8 +22,8 @@ app.use(bodyParser.json())
 // Define endpoints here
 // app.post('/act', actions.act)
 app.post('/webhook', messageController.process_wa_webhook)
-app.post('/notify', notificationController)
-app.post('/cancel-booking', cancelBookingController)
+app.post('/notify', notify)
+app.post('/cancel-booking', cancelBooking)
 app.post('/update-catalog', updateCatalog)
 // Reset all sessions
 const db = new DBService()
diff --git a/services/Actions.js b/services/Actions.js
index f522929..e503d17 100644
--- a/services/Actions.js
+++ b/services/Actions.js
@@ -44,7 +44,7 @@ class Actions {
                 cookies: response.headers['set-cookie'],
             }
             logger.info(`API call was successful: , response.status`)
-            logger.info(JSON.stringify(response.data, null, 2))
+            // logger.info(JSON.stringify(response.data, null, 2))
         } catch (error) {
             logger.error(error)
             
diff --git a/services/notificationService.js b/services/notificationService.js
deleted file mode 100644
index 0f101ce..0000000
--- a/services/notificationService.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import logger from '../utils/logger.js'
-import Twilio from 'twilio'
-const TWILIO_NUMBER = process.env.TWILIO_NUMBER
-const TWILIO_AUTH_TOKEN = process.env.TWILIO_AUTH_TOKEN
-const TWILIO_ACCOUNT_SID = process.env.TWILIO_ACCOUNT_SID
-
-const client = Twilio(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
-
-export const sendWhatsappNotification = async (
-    recipientNumber,
-    messageBody
-) => {
-    try {
-        const data = await client.messages.create({
-            body: messageBody,
-            from: `whatsapp:${TWILIO_NUMBER}`,
-            to: `whatsapp:${recipientNumber}`,
-        })
-
-        const status = await client.messages(data.sid).fetch()
-        console.log('data===>', data)
-        console.log('status===>', status)
-        if(status?.status!=="failed"){
-            return {message:'Notification Sent'}
-        }return {message:'Failed to Send Notification'}
-    } catch (error) {
-        logger.error(error.message)
-        throw new Error(error.message)
-    }
-}
diff --git a/tests/unit/controllers/controlCenter.test.js b/tests/unit/controllers/controlCenter.test.js
new file mode 100644
index 0000000..6a54737
--- /dev/null
+++ b/tests/unit/controllers/controlCenter.test.js
@@ -0,0 +1,78 @@
+import { describe, it} from 'mocha'
+import app from '../../../server.js'
+import request from 'supertest'
+import * as chai from 'chai'
+const expect = chai.expect
+
+
+describe('API tests for /notify endpoint for an end to end Notify Request', () => {
+    it('Should test unsuccess response for invalid whatsapp number.', async () => {
+        const response = await request(app).post('/notify').send({
+            "userNo":"+919123456789"
+        })
+        expect(response._body.status.status).equal('failed')
+    })
+
+    it('Should test success response for no whatsapp number provided in the payload and will sent to TEST_RECEPIENT_NUMBER', async () => {
+        const response = await request(app).post('/notify').send({
+           
+        })
+        expect(response._body.status.status).to.not.equal('failed')
+    })
+
+    it('Should test success response for valid whatsapp number', async () => {
+        const response = await request(app).post('/notify').send({
+            "userNo":process.env.TEST_RECEPIENT_NUMBER
+        })
+        expect(response._body.status.status).to.not.equal('failed')
+    })
+
+    
+})
+
+
+
+describe('API tests for /cancel-booking endpoint for an end to end Notify Message', () => {
+    it('Should test unsuccess response for invalid order Id.', async () => {
+        const response = await request(app).post('/cancel-booking').send({
+            "orderId":"Abcd"
+        })
+        expect(response._body.status).equal(false)
+    })
+
+    it('Should test unsuccess response for no order Id.', async () => {
+        const response = await request(app).post('/cancel-booking').send({})
+        expect(response._body.status).equal(false)
+    })
+
+   
+    it('Should test success response for valid order Id.', async () => {
+        const response = await request(app).post('/cancel-booking').send({
+            "orderId":"1"
+        })
+        expect(response._body.message).equal('Notification delivered')
+    })
+
+    
+})
+
+describe('API tests for /update-catalog endpoint for an end to end Notify Message', () => {
+    it('Should test success response for invalid whatsapp No.', async () => {
+        const response = await request(app).post('/update-catalog').send({
+            "userNo":"+919123456789"
+        })
+        expect(response._body.message).equal('Notification Failed')
+    })
+
+    it('Should test success response for no whatsapp number provided in the payload and will sent to TEST_RECEPIENT_NUMBER', async () => {
+        const response = await request(app).post('/update-catalog').send({})
+        expect(response._body.message).equal('Catalog Updated')
+    })
+
+    it('Should test success response for valid whatsapp number', async () => {
+        const response = await request(app).post('/update-catalog').send({
+            "userNo":process.env.TEST_RECEPIENT_NUMBER
+        })
+        expect(response._body.message).equal('Catalog Updated')
+    })
+})
\ No newline at end of file
diff --git a/utils/constants.js b/utils/constants.js
index af20826..a2219d2 100644
--- a/utils/constants.js
+++ b/utils/constants.js
@@ -1,6 +1,3 @@
-export const STRAPI_TOURISM_TOKEN =
-    '82ed7f48afbd0c0605ef36bf4b81259f90c7e6bc357db032a011b1c0ab2bc7db2a753fa84c959f403b256ee66b44174dcc453bd0a40797ce8c22c1b6dab7f416cf3b8a247c19144bc3d019f229612f36b12612223b35f28a1a7fec6ff779228730b45fd93a793399d8f462ba0bada15077725a843d3023cf133838876da3547e'
-
 export const ITEM_ID = '4'
 export const ITEM_NAME = 'Ticket Pass-Mueseum'