import express from "express"; import bodyParser from "body-parser"; import mongoose from "mongoose"; import cors from "cors"; import atob from "atob"; import dotenv from "dotenv"; import multer from "multer"; import helmet from "helmet"; import morgan from "morgan"; import path from "path"; import { fileURLToPath } from "url"; import authRoutes from "./routes/auth.js"; import userRoutes from "./routes/users.js"; import kdsRoutes from "./routes/kds.js"; import Odoo from "odoo-xmlrpc"; // import webemailRoutes from "./routes/webemail.js"; import axios from "axios"; import WebSocket, { WebSocketServer } from "ws"; // import nodemailer from "nodemailer"; // export const ws = new WebSocket("ws://192.168.50.15:4028/sT1eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY2NDE3OTI4MmE3M2ZlZWQ3MjgyM2ViOCIsImlhdCI6MTcxNTY2ODI4Nn0.ziEOLreXbCJRlyjRyIVLDsJNpeIvk73rf3kU7_HtO8E" // ); // ws.onopen = () => { // console.log("WebSocket connected------------------------------------------"); // // You can send initial messages after the connection is established if needed // // ws.send("Hello, server!"); // // const userId = "meeeee2"; // ws.send(JSON.stringify({ type: "join", userId: "obnPay_test" })); // // ws.send(encryptedMessage2); // }; // ws.onclose = () => { // console.log("Connection closed"); // }; /* CONFIGURATIONS */ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); dotenv.config(); const app = express(); app.use(express.json()); app.use(helmet()); app.use(helmet.crossOriginResourcePolicy({ policy: "cross-origin" })); app.use(morgan("common")); app.use(bodyParser.json({ limit: "30mb", extended: true })); app.use(bodyParser.urlencoded({ limit: "30mb", extended: true })); app.use(cors()); app.use("/assets", express.static(path.join(__dirname, "upload_files"))); /* FILE STORAGE */ const storage = multer.diskStorage({ destination: (req, file, cb) => { const category = req.body.category; // if (category == "message") { // cb(null, "message_uploads"); // } else if (category == "user") { // cb(null, "user_uploads"); // } else { cb(null, "upload_files"); // } }, filename: (req, file, cb) => { const image_id = req.body.image_id; cb(null, image_id + "-" + file.originalname); }, }); const upload = multer({ storage }); /* ROUTES */ app.use("/api/auth", authRoutes); app.use("/api/users", userRoutes); app.use("/api/kds", kdsRoutes); // app.use("/api/web-emails", webemailRoutes); app.post("/api/upload_images", upload.single("image"), async (req, res) => { try { const { filename } = req.file; const { image_id, category } = req.body; res.status(201).send({ filename, category, image_id }); } catch (error) { res.status(400).send(error); } }); function sendEmail(req, res, next) { const apiKey = "ODA4MDc4ZThjMDA4NjVhYzU4MTcyNDJjNTMxY2JlZGU6MGQ4ODg3ZTdiZjY1ZWNkMmQ0NzdiOWJhZGIyYTJhY2Q="; const apiUrl = "https://api.mailjet.com/v3.1/send"; // const otp = generateOTP(6); // You should have a function to generate the OTP const email2 = "kramblooda@gmail.com"; const min = 100000; // Minimum 6-digit number const max = 999999; // Maximum 6-digit number const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min; const requestData = { Messages: [ { From: { Email: "webdev@obanana.com", Name: "Obanana B2B", }, To: [ { Email: req.body.email, Name: "Subscriber", }, ], Subject: "Obanana OTP", TextPart: "Greetings from Obanana!", HTMLPart: req.body.html, }, ], }; const config = { headers: { "Content-Type": "application/json", Authorization: `Basic ${apiKey}`, }, }; axios .post(apiUrl, requestData, config) .then((response) => { // const status = response.data.Messages[0].Status; // console.log(response.data.Messages[0].Status); // console.log(randomNumber); // setotpSent(randomNumber); res.status(200).json(response.data); // return `${status},${randomNumber}`; }) .catch((error) => { res.status(404).json({ message: error }); // console.error("Error sending OTP email:", error); // Handle the error here }); } app.post("/api/send-email/", sendEmail); // const odooClient = new Odoo({ // url: "http://192.168.50.15:8070", // db: "gis.pivi.com.ph", // username: "egalang@obanana.com", // password: "P@$$w0rd!", // }); const odooClient2 = new Odoo({ url: "http://192.168.50.15:8071", db: "pos.obanana.com", username: "mahipe@obanana.com", password: "P@$$w0rd!", }); app.get("/get-assets", async (req, res) => { try { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Basic ')) { return res.status(400).json({ error: 'Authorization header is missing or invalid.' }); } const base64Credentials = authHeader.split(' ')[1]; const decodedCredentials = atob(base64Credentials); const [email, password] = decodedCredentials.split(':'); if (!email || !password) { return res.status(400).json({ error: 'Invalid credentials format.' }); } // console.log(email,password) const odooClient = new Odoo({ url: "http://192.168.50.15:8070", db: "gis.pivi.com.ph", username: email, password: password }); odooClient.connect(async function (err) { if (err) { console.log(err); return res .status(500) .json({ error: "Connection Error: " + err.message }); } console.log("Connected to Odoo server."); // Fetch asset IDs const inParams = []; inParams.push([["name", "!=", false]]); inParams.push(parseInt(req.query.offset) || 0); //offset inParams.push(parseInt(req.query.limit) || 0); //Limit const params = [inParams]; const assets = []; let recordsArray = []; let attributes = []; let bounds = []; let images = []; odooClient.execute_kw( "pivi_assets.pivi_assets", "search", params, async function (err, ids) { if (err) { console.log(err); return res .status(500) .json({ error: "Search Error: " + err.message }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs const paramsRead = [inParamsRead]; odooClient.execute_kw( "pivi_assets.pivi_assets", "read", paramsRead, async function (err2, records) { if (err2) { console.log(err2); return res .status(500) .json({ error: "Read Error: " + err2.message }); } else { recordsArray = records; odooClient.execute_kw( "pivi_assets.attributes", "search", params, async function (err, ids) { if (err) { console.log(err); return res .status(500) .json({ error: "Search Error: " + err.message }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs inParamsRead.push([ "id", "name", "value", "asset", "__last_update", "display_name", "create_uid", "create_date", "write_uid", "write_date", ]); const paramsRead = [inParamsRead]; odooClient.execute_kw( "pivi_assets.attributes", "read", paramsRead, async function (err2, attr) { if (err2) { console.log(err2); return res .status(500) .json({ error: "Read Error: " + err2.message }); } else { attributes = attr; odooClient.execute_kw( "pivi_assets.bounds", "search", params, async function (err, ids) { if (err) { console.log(err); return res.status(500).json({ error: "Search Error: " + err.message, }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs inParamsRead.push([ "id", "name", "longitude", "latitude", "asset", "__last_update", "display_name", "create_uid", "create_date", "write_uid", "write_date", ]); const paramsRead = [inParamsRead]; odooClient.execute_kw( "pivi_assets.bounds", "read", paramsRead, async function (err2, bound) { if (err2) { console.log(err2); return res.status(500).json({ error: "Read Error: " + err2.message, }); } else { bounds = bound; odooClient.execute_kw( "ir.attachment", "search", params, async function (err, ids) { if (err) { console.log(err); return res.status(500).json({ error: "Search Error: " + err.message, }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs inParamsRead.push([ "id", "name", "local_url", "res_id", ]); const paramsRead = [inParamsRead]; odooClient.execute_kw( "ir.attachment", "read", paramsRead, async function (err2, image) { if (err2) { console.log(err2); return res.status(500).json({ error: "Read Error: " + err2.message, }); } else { images = image; const inParams = []; inParams.push([["related_asset", "!=", false]]); inParams.push(parseInt(req.query.offset) || 0); //offset inParams.push(parseInt(req.query.limit) || 0); //Limit const params1 = [inParams]; odooClient.execute_kw( "pivi_assets.related", "search", params1, async function (err, ids) { if (err) { console.log(err); return res.status(500).json({ error: "Search Error: " + err.message, }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs inParamsRead.push([ "id", "related_asset", "asset", ]); const paramsRead = [inParamsRead]; odooClient.execute_kw( "pivi_assets.related", "read", paramsRead, async function (err2, related) { if (err2) { console.log(err2); return res.status(500).json({ error: "Read Error: " + err2.message, }); } else { let relateds relateds = related; const asset = recordsArray.map( (item) => { // Find matching attributes based on the numeric part of attr.assets const matchedAttr = attributes.filter( (attribute) => item.attributes.some( (attrId) => attrId === attribute.id ) // Compare to the first element of attr.assets ); // Find matching bounds based on the numeric part of bounds.assets const matchedBounds = bounds.filter( (bound) => item.bounds.some( (boundId) => boundId === bound.id ) // Compare to the first element of bounds.assets ); // Find matching bounds based on the numeric part of bounds.assets const matchedRelated = relateds.filter( (related) => item.related.some( (relatedId) => relatedId === related.id ) ); // Find matching images based on data.id == images.res_id const matchedImages = images.filter( (image) => image.res_id === item.id ); // Construct the asset object for this item return { attr: matchedAttr, bounds: matchedBounds, data: item, images: matchedImages, related: matchedRelated }; } ); // res.json({ // data: recordsArray, // attr: attributes, // bounds: bounds, // images: images, // }); res.json(asset); } let pendingRequests = records.length; } ); } ); } let pendingRequests = records.length; } ); } ); } } ); } ); } } ); } ); } let pendingRequests = records.length; } ); } ); }); } catch (error) { console.error("Error:", error); res.status(500).json({ error: "Data Fetch Error: " + error.message }); } }); app.get("/get-orders", async (req, res) => { try { odooClient2.connect(async function (err) { if (err) { console.log(err); return res .status(500) .json({ error: "Connection Error: " + err.message }); } console.log("Connected to Odoo server."); // Fetch asset IDs const inParams = []; inParams.push([["name", "!=", false]]); inParams.push(parseInt(req.query.offset) || 0); //offset inParams.push(parseInt(req.query.limit) || 0); //Limit const params = [inParams]; const assets = []; let recordsArray = []; let attributes = []; let bounds = []; let images = []; odooClient2.execute_kw( "pos.order", "search", params, async function (err, ids) { if (err) { console.log(err); return res .status(500) .json({ error: "Search Error: " + err.message }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs const paramsRead = [inParamsRead]; odooClient2.execute_kw( "pos.order", "read", paramsRead, async function (err2, records) { if (err2) { console.log(err2); return res .status(500) .json({ error: "Read Error: " + err2.message }); } else { recordsArray = records; res.json(recordsArray); } let pendingRequests = records.length; } ); } ); }); } catch (error) { console.error("Error:", error); res.status(500).json({ error: "Data Fetch Error: " + error.message }); } }); app.get("/get-products", async (req, res) => { try { odooClient2.connect(async function (err) { if (err) { console.log(err); return res .status(500) .json({ error: "Connection Error: " + err.message }); } console.log("Connected to Odoo server."); // Fetch asset IDs const inParams = []; inParams.push([["name", "!=", false]]); inParams.push(parseInt(req.query.offset) || 0); //offset inParams.push(parseInt(req.query.limit) || 0); //Limit const params = [inParams]; const assets = []; let recordsArray = []; let attributes = []; let bounds = []; let images = []; odooClient2.execute_kw( "product.template", "search", params, async function (err, ids) { if (err) { console.log(err); return res .status(500) .json({ error: "Search Error: " + err.message }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs inParamsRead.push(["id", "name"]); const paramsRead = [inParamsRead]; odooClient2.execute_kw( "product.template", "read", paramsRead, async function (err2, records) { if (err2) { console.log(err2); return res .status(500) .json({ error: "Read Error: " + err2.message }); } else { recordsArray = records; res.json(recordsArray); } let pendingRequests = records.length; } ); } ); }); } catch (error) { console.error("Error:", error); res.status(500).json({ error: "Data Fetch Error: " + error.message }); } }); app.get("/get-product_ordered", async (req, res) => { try { odooClient2.connect(async function (err) { if (err) { console.log(err); return res .status(500) .json({ error: "Connection Error: " + err.message }); } console.log("Connected to Odoo server."); // Fetch asset IDs const inParams = []; inParams.push([["name", "!=", false]]); inParams.push(parseInt(req.query.offset) || 0); //offset inParams.push(parseInt(req.query.limit) || 0); //Limit const params = [inParams]; const assets = []; let recordsArray = []; let attributes = []; let bounds = []; let images = []; odooClient2.execute_kw( "pos.order.line", "search", params, async function (err, ids) { if (err) { console.log(err); return res .status(500) .json({ error: "Search Error: " + err.message }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs // inParamsRead.push([ // "id", // "name", // ]); const paramsRead = [inParamsRead]; odooClient2.execute_kw( "pos.order.line", "read", paramsRead, async function (err2, records) { if (err2) { console.log(err2); return res .status(500) .json({ error: "Read Error: " + err2.message }); } else { recordsArray = records; res.json(recordsArray); } let pendingRequests = records.length; } ); } ); }); } catch (error) { console.error("Error:", error); res.status(500).json({ error: "Data Fetch Error: " + error.message }); } }); app.get("/get-stages", async (req, res) => { try { odooClient2.connect(async function (err) { if (err) { console.log(err); return res .status(500) .json({ error: "Connection Error: " + err.message }); } console.log("Connected to Odoo server."); // Fetch asset IDs const inParams = []; inParams.push([["name", "!=", false]]); inParams.push(parseInt(req.query.offset) || 0); inParams.push(parseInt(req.query.limit) || 0); const params = [inParams]; const assets = []; let recordsArray = []; let attributes = []; let bounds = []; let images = []; odooClient2.execute_kw( "kds.stages", "search", params, async function (err, ids) { if (err) { console.log(err); return res .status(500) .json({ error: "Search Error: " + err.message }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs // inParamsRead.push([ // "id", // "name", // ]); const paramsRead = [inParamsRead]; odooClient2.execute_kw( "kds.stages", "read", paramsRead, async function (err2, records) { if (err2) { console.log(err2); return res .status(500) .json({ error: "Read Error: " + err2.message }); } else { recordsArray = records; res.json(recordsArray); } let pendingRequests = records.length; } ); } ); }); } catch (error) { console.error("Error:", error); res.status(500).json({ error: "Data Fetch Error: " + error.message }); } }); app.post('/update-order-state', async (req, res) => { const { id, state } = req.body; if (!id || !state) { return res.status(400).json({ error: 'Order ID and state are required.' }); } try { odooClient2.connect(function (err) { if (err) { console.log(err); return res.status(500).json({ error: 'Connection Error: ' + err.message }); } console.log('Connected to Odoo server.'); const inParams = []; inParams.push([['id', '=', id]]); const params = [inParams]; odooClient2.execute_kw('pos.order', 'search', params, function (err, orderIds) { if (err) { console.log(err); return res.status(500).json({ error: 'Search Error: ' + err.message }); } if (orderIds.length === 0) { return res.status(404).json({ error: 'Order not found.' }); } const inParamsUpdate = []; inParamsUpdate.push(orderIds); inParamsUpdate.push({ state: state }); const paramsUpdate = [inParamsUpdate]; odooClient2.execute_kw('pos.order', 'write', paramsUpdate, function (err2, result) { if (err2) { console.log(err2); return res.status(500).json({ error: 'Update Error: ' + err2.message }); } if (result) { return res.json({ success: true, message: `Order ID ${id} updated to state: ${state}` }); } else { return res.status(500).json({ error: 'Failed to update order state.' }); } }); }); }); } catch (error) { console.error('Error:', error); return res.status(500).json({ error: 'Update Error: ' + error.message }); } }); app.get("/get-tables", async (req, res) => { try { odooClient2.connect(async function (err) { if (err) { console.log(err); return res .status(500) .json({ error: "Connection Error: " + err.message }); } console.log("Connected to Odoo server."); // Fetch asset IDs const inParams = []; inParams.push([["name", "!=", false]]); inParams.push(parseInt(req.query.offset) || 0); inParams.push(parseInt(req.query.limit) || 0); const params = [inParams]; const assets = []; let recordsArray = []; let attributes = []; let bounds = []; let images = []; odooClient2.execute_kw( "restaurant.table", "search", params, async function (err, ids) { if (err) { console.log(err); return res .status(500) .json({ error: "Search Error: " + err.message }); } if (ids.length === 0) { return res.json([]); // No assets found } // Fetch asset records const inParamsRead = []; inParamsRead.push(ids); // IDs // inParamsRead.push([ // "id", // "name", // ]); const paramsRead = [inParamsRead]; odooClient2.execute_kw( "restaurant.table", "read", paramsRead, async function (err2, records) { if (err2) { console.log(err2); return res .status(500) .json({ error: "Read Error: " + err2.message }); } else { recordsArray = records; res.json(recordsArray); } let pendingRequests = records.length; } ); } ); }); } catch (error) { console.error("Error:", error); res.status(500).json({ error: "Data Fetch Error: " + error.message }); } }); app.post('/create-asset-bounds', async (req, res) => { try { const postData = req.body; if (!postData || postData.length === 0) { return res.status(200).json({ error: 'No data provided.' }); } const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Basic ')) { return res.status(400).json({ error: 'Authorization header is missing or invalid.' }); } const base64Credentials = authHeader.split(' ')[1]; const decodedCredentials = Buffer.from(base64Credentials, 'base64').toString('ascii'); // safer than `atob` const [email, password] = decodedCredentials.split(':'); if (!email || !password) { return res.status(400).json({ error: 'Invalid credentials format.' }); } const odooClient = new Odoo({ url: "http://192.168.50.15:8070", db: "gis.pivi.com.ph", username: email, password: password }); odooClient.connect(async function (err) { if (err) { console.log(err); return res.status(500).json({ error: 'Connection Error: ' + err.message }); } console.log('Connected to Odoo server.'); // Use Promise.all to wait for all async operations to finish try { const createdIds = await Promise.all( postData.map(async (data, index) => { const { asset, name, longitude, latitude } = data; if (!asset || !name || !longitude || !latitude) { throw new Error(`Missing required fields in entry ${index + 1}`); } const params = [ { asset: asset, name: name, longitude: longitude, latitude: latitude, } ]; // Return a promise for each create operation return new Promise((resolve, reject) => { odooClient.execute_kw('pivi_assets.bounds', 'create', [params], function (err2, id) { if (err2) { console.log('Create Error:', err2); return reject(new Error('Create Error: ' + err2.message)); } resolve(id); }); }); }) ); return res.json({ success: true, createdIds }); } catch (error) { return res.status(500).json({ error: error.message }); } }); } catch (error) { console.error('Error:', error); return res.status(500).json({ error: 'Server Error: ' + error.message }); } }); app.post('/odoo-webhook', (req, res) => { const newOrder = req.body; console.log('New POS order received:', newOrder); // Process the order data as needed // For example, send it to a WebSocket, log it, or store it in a database res.status(200).send('Webhook received'); }); app.delete('/delete-asset-bounds', async (req, res) => { try { const assetId = req.query.asset; console.log(assetId) if (!assetId) { return res.status(400).json({ error: 'Asset ID is required.' }); } const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Basic ')) { return res.status(400).json({ error: 'Authorization header is missing or invalid.' }); } const base64Credentials = authHeader.split(' ')[1]; const decodedCredentials = atob(base64Credentials); const [email, password] = decodedCredentials.split(':'); if (!email || !password) { return res.status(400).json({ error: 'Invalid credentials format.' }); } // console.log(email,password) const odooClient = new Odoo({ url: "http://192.168.50.15:8070", db: "gis.pivi.com.ph", username: email, password: password }); odooClient.connect(function (err) { if (err) { console.log(err); return res.status(500).json({ error: 'Connection Error: ' + err.message }); } console.log('Connected to Odoo server.'); const inParams = []; inParams.push([['id', '=', assetId]]); const searchParamsAsset = [inParams]; // const searchParamsAsset = [ // [['id', '=', assetId]] // ]; odooClient.execute_kw('pivi_assets.pivi_assets', 'search', searchParamsAsset, function (err2, assetIds) { if (err2) { console.log(assetIds+" id") console.log('Search Error:', err2); return res.status(500).json({ error: 'Search Asset Error: ' + err2.message }); } if (assetIds.length === 0) { return res.status(404).json({ error: 'Asset not found.' }); } odooClient.execute_kw('pivi_assets.pivi_assets', 'read', [assetIds], function (err3, assets) { if (err3) { console.log('Read Error:', err3); return res.status(500).json({ error: 'Read Error: ' + err3.message }); } const assetName = assets[0].name; // const searchParamsBounds = [ // [['asset', '=', assetName]] // ]; const inParams = []; inParams.push([['asset', '=', assetName]]); const searchParamsBounds = [inParams]; odooClient.execute_kw('pivi_assets.bounds', 'search', searchParamsBounds, function (err4, boundIds) { if (err4) { console.log('Search Bounds Error:', err4); return res.status(500).json({ error: 'Search Bounds Error: ' + err4.message }); } if (boundIds.length === 0) { return res.status(200).json({ error: 'No bounds found for this asset.' }); } odooClient.execute_kw('pivi_assets.bounds', 'read', [[boundIds]], function (err5, bounds) { if (err5) { console.log('Read Bounds Error:', err5); return res.status(500).json({ error: 'Read Bounds Error: ' + err5.message }); } const deletedIds = []; bounds.forEach((bound, index) => { const boundId = bound.id; odooClient.execute_kw('pivi_assets.bounds', 'unlink', [[boundId]], function (err6) { if (err6) { console.log('Unlink Error:', err6); return res.status(500).json({ error: 'Unlink Error: ' + err6.message }); } deletedIds.push(boundId); if (deletedIds.length === bounds.length) { return res.json({ success: true, deletedIds }); } }); }); }); }); }); }); }); } catch (error) { console.error('Error:', error); return res.status(500).json({ error: 'Server Error: ' + error.message }); } }); // function fetchOdooData(model, method, params) { // return new Promise((resolve, reject) => { // odooClient.execute_kw(model, method, params, (err, data) => { // if (err) return reject(err); // resolve(data); // }); // }); // } /* MONGOOSE SETUP */ const PORT = process.env.PORT || 3002; // mongoose // .connect(process.env.MONGO_URL, { // useNewUrlParser: true, // useUnifiedTopology: true, // }) // .then(() => { // app.listen(PORT, () => console.log(`Server Port: ${PORT}`)); // // /* ADD DATA ONE TIME */ // }) // .catch((error) => console.log(`${error} did not connect`)); mongoose .connect(process.env.DATABASE_URL) .then(() => { app.listen(PORT, () => console.log(`Server Port: ${PORT}`)); // /* ADD DATA ONE TIME */ }) .catch((error) => console.log(`${error} did not connect`));