diff --git a/src/config/swagger.js b/src/config/swagger.js index 86dbb751..9799073e 100644 --- a/src/config/swagger.js +++ b/src/config/swagger.js @@ -16,7 +16,7 @@ exports.options = { // we have to run on this on swagger // host: "localhost:3000", //Devlopemnt host on lcoal - //host: "35.207.205.18:3000", //Production for swagger + host: "armintaaqua.com:3000", //Production for swagger schemes: ["http"], consumes: ["application/json"], produces: ["application/json"], diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index f7191dab..24117629 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -6080,171 +6080,70 @@ exports.updateHardwareList = async (req, reply) => { -// exports.assignCategorizeIssue = async (request, reply) => { -// const { supportId } = request.params; -// const { support_teamMemberId, category, masterHardwareId } = request.body; - -// if (!support_teamMemberId || !category || !masterHardwareId) { -// return reply.code(400).send({ -// error: 'support_teamMemberId, category, and masterHardwareId are required' -// }); -// } - -// const support = await Support.findOne({ supportId }); -// if (!support) { -// return reply.code(404).send({ error: 'Support record not found' }); -// } - -// const teamMembers = support.team_member?.team_member || []; -// const teamMember = teamMembers.find(m => m.support_teamMemberId === support_teamMemberId); - -// if (!teamMember) { -// return reply.code(400).send({ error: `Team member ID ${support_teamMemberId} not found` }); -// } - -// const assignedAt = moment().format("DD-MM-YYYY HH:mm:ss"); -// const assignmentCode = Math.floor(100000 + Math.random() * 900000).toString(); // random 6-digit code -// let assignedCount = 0; - -// support.categorizedIssues.forEach(issue => { -// if ( -// issue.masterHardwareId === masterHardwareId && -// issue.category === category -// ) { -// issue.assignedTo = { -// name: teamMember.name, -// support_teamMemberId: teamMember.support_teamMemberId, -// phone: teamMember.phone, -// email: teamMember.email, -// assignedAt: assignedAt, -// assignmentCode: assignmentCode // ← Add this field -// }; -// assignedCount++; -// } -// }); - -// if (assignedCount === 0) { -// return reply.code(404).send({ message: 'No matching issues found for assignment' }); -// } - -// await support.save(); - -// return reply.send({ -// message: `Assigned ${assignedCount} categorized issue(s) to ${teamMember.name}`, -// assignmentCode: assignmentCode, // ← Return the code in response -// assignedTo: { -// support_teamMemberId: teamMember.support_teamMemberId, -// name: teamMember.name, -// phone: teamMember.phone, -// email: teamMember.email, -// assignedAt: assignedAt, -// } -// }); -// }; - - exports.assignCategorizeIssue = async (request, reply) => { - try { - const { supportId } = request.params; - const { support_teamMemberId, quationId } = request.body; + const { supportId } = request.params; + const { support_teamMemberId, category, masterHardwareId } = request.body; - // Step 1: Validate input - if (!supportId || !support_teamMemberId || !quationId) { - return reply.code(400).send({ - error: 'supportId (path), support_teamMemberId, and quationId (body) are required' - }); - } + if (!support_teamMemberId || !category || !masterHardwareId) { + return reply.code(400).send({ + error: 'support_teamMemberId, category, and masterHardwareId are required' + }); + } - // Step 2: Find support record - const support = await Support.findOne({ supportId }); - if (!support) { - return reply.code(404).send({ error: 'Support record not found' }); - } + const support = await Support.findOne({ supportId }); + if (!support) { + return reply.code(404).send({ error: 'Support record not found' }); + } - // Step 3: Check team member exists - const teamMembers = support.team_member?.team_member || []; - const teamMember = teamMembers.find(m => m.support_teamMemberId === support_teamMemberId); + const teamMembers = support.team_member?.team_member || []; + const teamMember = teamMembers.find(m => m.support_teamMemberId === support_teamMemberId); - if (!teamMember) { - return reply.code(404).send({ error: `Team member ID ${support_teamMemberId} not found` }); - } + if (!teamMember) { + return reply.code(400).send({ error: `Team member ID ${support_teamMemberId} not found` }); + } - // Step 4: Assign all categorized issues - const assignedAt = moment().format("DD-MM-YYYY HH:mm:ss"); - const assignmentCode = Math.floor(100000 + Math.random() * 900000).toString(); // random 6-digit code - let assignedCount = 0; + const assignedAt = moment().format("DD-MM-YYYY HH:mm:ss"); +const assignmentCode = Math.floor(100000 + Math.random() * 900000).toString(); // random 6-digit code + let assignedCount = 0; - support.issues.forEach(issue => { + support.categorizedIssues.forEach(issue => { + if ( + issue.masterHardwareId === masterHardwareId && + issue.category === category + ) { issue.assignedTo = { name: teamMember.name, support_teamMemberId: teamMember.support_teamMemberId, phone: teamMember.phone, email: teamMember.email, assignedAt: assignedAt, - assignmentCode: assignmentCode, - quationId: quationId + assignmentCode: assignmentCode // ← Add this field }; assignedCount++; - }); - - if (assignedCount === 0) { - return reply.code(404).send({ message: 'No categorized issues found to assign' }); } + }); - // Step 5: Save support document - await support.save(); - - // Step 6: Update or create the Order document with assigned support team member - let order = await Order.findOne({ quatationId: quationId }); + if (assignedCount === 0) { + return reply.code(404).send({ message: 'No matching issues found for assignment' }); + } - if (!order) { - order = new Order({ - quatationId: quationId, - assignedTeamMembers: [], - quatation_status: "Assigned", - }); - } + await support.save(); - // Save the assigned support team member info - order.assignedSupportTeamMember = { + return reply.send({ + message: `Assigned ${assignedCount} categorized issue(s) to ${teamMember.name}`, + assignmentCode: assignmentCode, // ← Return the code in response + assignedTo: { support_teamMemberId: teamMember.support_teamMemberId, name: teamMember.name, phone: teamMember.phone, email: teamMember.email, assignedAt: assignedAt, - assignmentCode: assignmentCode, - quationId: quationId, - }; + } + }); +}; - await order.save(); - // Step 7: Return response - return reply.send({ - simplydata: { - error: false, - message: `Assigned ${assignedCount} categorized issue(s) to ${teamMember.name}`, - assignmentCode: assignmentCode, - assignedTo: { - support_teamMemberId: teamMember.support_teamMemberId, - name: teamMember.name, - phone: teamMember.phone, - email: teamMember.email, - assignedAt: assignedAt, - quationId: quationId - } - } - }); - } catch (error) { - console.error("Error assigning categorized issues:", error); - return reply.status(500).send({ - simplydata: { - error: true, - message: "Internal Server Error" - } - }); - } -}; exports.getCategorizedIssue = async (request, reply) => { diff --git a/src/index.js b/src/index.js index 24e5272d..4a657e28 100644 --- a/src/index.js +++ b/src/index.js @@ -969,163 +969,163 @@ const storage = new Storage({ // }); const fastifyMulter = require('fastify-multer'); const mime = require("mime-types"); -// const upload = fastifyMulter({ -// dest: 'uploads/', -// limits: { -// fieldNameSize: 100, -// fieldSize: 1000000, -// fields: 10, -// fileSize: 1000000000000000, -// files: 10, -// headerPairs: 2000 -// } -// }); - -// fastify.register(upload.contentParser); - -// fastify.post('/api/uploads_team_profile/:customerId', { -// preHandler: upload.single('file') -// }, async (request, reply) => { -// try { -// const { customerId } = request.params; -// const file = await request.file; // Uncomment this line -// const formData = new FormData(); -// formData.append('file', file); -// const bucketName = 'arminta_profile_pictures'; -// const filePath = `arminta_team_profiles/${file.originalname}`; - -// const fileBuffer = await fs.promises.readFile(file.path); - -// await storage.bucket(bucketName).file(filePath).save(fileBuffer); - -// // make file public -// await storage.bucket(bucketName).file(filePath).makePublic(); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; - -// // save in DB -// const picture = await TeamMemberProfilePicture.findOneAndUpdate( -// { customerId }, -// { picture: publicUrl }, -// { new: true, upsert: true } -// ); +const upload = fastifyMulter({ + dest: 'uploads/', + limits: { + fieldNameSize: 100, + fieldSize: 1000000, + fields: 10, + fileSize: 1000000000000000, + files: 10, + headerPairs: 2000 + } +}); -// return reply.send({ picture: publicUrl }); +fastify.register(upload.contentParser); -// } catch (err) { -// request.log.error(err); -// return reply.code(500).send({ error: 'Upload failed', details: err.message }); -// } -// }); +fastify.post('/api/uploads_team_profile/:customerId', { + preHandler: upload.single('file') +}, async (request, reply) => { + try { + const { customerId } = request.params; + const file = await request.file; // Uncomment this line + const formData = new FormData(); + formData.append('file', file); + const bucketName = 'arminta_profile_pictures'; + const filePath = `arminta_team_profiles/${file.originalname}`; -// fastify.post('/api/uploads_admin_profile/:customerId', { -// preHandler: upload.single('file') -// }, async (request, reply) => { -// try { -// const { customerId } = request.params; -// const file = await request.file; // Uncomment this line -// const formData = new FormData(); -// formData.append('file', file); -// const bucketName = 'arminta_profile_pictures'; -// const filePath = `arminta_team_profiles/${file.originalname}`; + const fileBuffer = await fs.promises.readFile(file.path); -// const fileBuffer = await fs.promises.readFile(file.path); + await storage.bucket(bucketName).file(filePath).save(fileBuffer); -// await storage.bucket(bucketName).file(filePath).save(fileBuffer); + // make file public + await storage.bucket(bucketName).file(filePath).makePublic(); + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// // make file public -// await storage.bucket(bucketName).file(filePath).makePublic(); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + // save in DB + const picture = await TeamMemberProfilePicture.findOneAndUpdate( + { customerId }, + { picture: publicUrl }, + { new: true, upsert: true } + ); -// // save in DB -// const picture = await AdminProfilePicture.findOneAndUpdate( -// { customerId }, -// { picture: publicUrl }, -// { new: true, upsert: true } -// ); + return reply.send({ picture: publicUrl }); -// return reply.send({ picture: publicUrl }); + } catch (err) { + request.log.error(err); + return reply.code(500).send({ error: 'Upload failed', details: err.message }); + } +}); -// } catch (err) { -// request.log.error(err); -// return reply.code(500).send({ error: 'Upload failed', details: err.message }); -// } -// }); +fastify.post('/api/uploads_admin_profile/:customerId', { + preHandler: upload.single('file') +}, async (request, reply) => { + try { + const { customerId } = request.params; + const file = await request.file; // Uncomment this line + const formData = new FormData(); + formData.append('file', file); + const bucketName = 'arminta_profile_pictures'; + const filePath = `arminta_team_profiles/${file.originalname}`; -// fastify.post("/api/uploads_installation_profile/:installationId", { -// preHandler: upload.single("file"), // your multer/fastify-multipart preHandler -// }, async (request, reply) => { -// try { -// const { installationId } = request.params; -// const file = request.file; // in fastify-multer this is set by preHandler + const fileBuffer = await fs.promises.readFile(file.path); -// if (!file) { -// return reply.code(400).send({ error: "No file uploaded (expected field name 'file')." }); -// } + await storage.bucket(bucketName).file(filePath).save(fileBuffer); -// // basic file validation -// const allowed = ["image/jpeg", "image/jpg", "image/png"]; -// if (!allowed.includes(file.mimetype)) { -// return reply.code(400).send({ error: "Only JPEG/PNG images are allowed." }); -// } + // make file public + await storage.bucket(bucketName).file(filePath).makePublic(); + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// const bucketName = "arminta_profile_pictures"; -// const ext = mime.extension(file.mimetype) || (file.originalname.split(".").pop() || "png"); -// const safeBase = path.parse(file.originalname).name.replace(/[^\w.-]/g, "_"); -// const filePath = `arminta_team_profiles/${safeBase}-${Date.now()}.${ext}`; + // save in DB + const picture = await AdminProfilePicture.findOneAndUpdate( + { customerId }, + { picture: publicUrl }, + { new: true, upsert: true } + ); -// // read temp file to buffer -// const fileBuffer = await fs.promises.readFile(file.path); + return reply.send({ picture: publicUrl }); -// // upload to GCS -// const bucket = storage.bucket(bucketName); -// const gcsFile = bucket.file(filePath); -// await gcsFile.save(fileBuffer, { -// resumable: false, -// contentType: file.mimetype, -// public: true, -// metadata: { cacheControl: "public, max-age=31536000" }, -// }); -// await gcsFile.makePublic(); + } catch (err) { + request.log.error(err); + return reply.code(500).send({ error: 'Upload failed', details: err.message }); + } +}); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; +fastify.post("/api/uploads_installation_profile/:installationId", { + preHandler: upload.single("file"), // your multer/fastify-multipart preHandler +}, async (request, reply) => { + try { + const { installationId } = request.params; + const file = request.file; // in fastify-multer this is set by preHandler -// // 1) Upsert installation profile picture collection -// await ProfilePictureInstall.findOneAndUpdate( -// { installationId }, -// { picture: publicUrl }, -// { new: true, upsert: true } -// ); + if (!file) { + return reply.code(400).send({ error: "No file uploaded (expected field name 'file')." }); + } -// // 2) Update department doc where departmentId === installationId -// const deptUpdate = await Deparments.findOneAndUpdate( -// { departmentId: installationId }, -// { picture: publicUrl }, -// { new: true } -// ); + // basic file validation + const allowed = ["image/jpeg", "image/jpg", "image/png"]; + if (!allowed.includes(file.mimetype)) { + return reply.code(400).send({ error: "Only JPEG/PNG images are allowed." }); + } -// // 3) (Optional) also save on the installation doc itself if you keep picture there -// // await Installations.findOneAndUpdate( -// // { installationId }, -// // { picture: publicUrl }, -// // { new: true } -// // ); - -// return reply.send({ -// installationId, -// picture: publicUrl, -// departmentUpdated: Boolean(deptUpdate), -// message: deptUpdate -// ? "Upload successful. Department picture updated." -// : "Upload successful. No department matched this installationId.", -// }); -// } catch (err) { -// request.log.error(err); -// return reply.code(500).send({ error: "Upload failed", details: err.message }); -// } finally { -// // best effort: clean up temp file if your preHandler writes to disk -// try { if (request.file?.path) await fs.promises.unlink(request.file.path); } catch {} -// } -// }); + const bucketName = "arminta_profile_pictures"; + const ext = mime.extension(file.mimetype) || (file.originalname.split(".").pop() || "png"); + const safeBase = path.parse(file.originalname).name.replace(/[^\w.-]/g, "_"); + const filePath = `arminta_team_profiles/${safeBase}-${Date.now()}.${ext}`; + + // read temp file to buffer + const fileBuffer = await fs.promises.readFile(file.path); + + // upload to GCS + const bucket = storage.bucket(bucketName); + const gcsFile = bucket.file(filePath); + await gcsFile.save(fileBuffer, { + resumable: false, + contentType: file.mimetype, + public: true, + metadata: { cacheControl: "public, max-age=31536000" }, + }); + await gcsFile.makePublic(); + + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + + // 1) Upsert installation profile picture collection + await ProfilePictureInstall.findOneAndUpdate( + { installationId }, + { picture: publicUrl }, + { new: true, upsert: true } + ); + + // 2) Update department doc where departmentId === installationId + const deptUpdate = await Deparments.findOneAndUpdate( + { departmentId: installationId }, + { picture: publicUrl }, + { new: true } + ); + + // 3) (Optional) also save on the installation doc itself if you keep picture there + // await Installations.findOneAndUpdate( + // { installationId }, + // { picture: publicUrl }, + // { new: true } + // ); + + return reply.send({ + installationId, + picture: publicUrl, + departmentUpdated: Boolean(deptUpdate), + message: deptUpdate + ? "Upload successful. Department picture updated." + : "Upload successful. No department matched this installationId.", + }); + } catch (err) { + request.log.error(err); + return reply.code(500).send({ error: "Upload failed", details: err.message }); + } finally { + // best effort: clean up temp file if your preHandler writes to disk + try { if (request.file?.path) await fs.promises.unlink(request.file.path); } catch {} + } +}); // fastify.post('/api/uploads_installation_profile/:installationId', { // preHandler: upload.single('file') @@ -1196,139 +1196,139 @@ const mime = require("mime-types"); // return reply.code(500).send({ error: 'Upload failed', details: err.message }); // } // }); -// fastify.post('/api/uploads_company_profile/:customerId', async (request, reply) => { -// try { -// const customerId = request.params.customerId; -// const data = await request.file(); - -// const bucketName = 'arminta_profile_pictures'; -// const filePath = `arminta_company_profiles/${data.filename}`; - -// const file = storage.bucket(bucketName).file(filePath); -// const writeStream = file.createWriteStream(); - -// data.file.pipe(writeStream); - -// await new Promise((resolve, reject) => { -// writeStream.on('finish', resolve); -// writeStream.on('error', reject); -// }); - -// // Make file public -// await file.makePublic(); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; - -// // Update DB with async/await -// const picture = await CompanyProfilePicture.findOneAndUpdate( -// { customerId }, -// { picture: publicUrl }, -// { new: true, upsert: true } -// ); +fastify.post('/api/uploads_company_profile/:customerId', async (request, reply) => { + try { + const customerId = request.params.customerId; + const data = await request.file(); -// reply.send({ picture: publicUrl }); -// } catch (err) { -// console.error(err); -// reply.code(500).send({ error: 'An error occurred', details: err.message }); -// } -// }); + const bucketName = 'arminta_profile_pictures'; + const filePath = `arminta_company_profiles/${data.filename}`; -// fastify.post("/api/uploads_installation_TeamMember_profile/:installationId/:teamMemberId", { -// preHandler: upload.single("file"), -// }, async (request, reply) => { -// try { -// const { installationId ,teamMemberId} = request.params; -// //const teamMemberId = request.body?.teamMemberId; // OPTIONAL -// const file = request.file; + const file = storage.bucket(bucketName).file(filePath); + const writeStream = file.createWriteStream(); -// if (!file) { -// return reply.code(400).send({ error: "No file uploaded (field name 'file')." }); -// } + data.file.pipe(writeStream); -// // Validate image type -// const allowed = ["image/jpeg", "image/jpg", "image/png"]; -// if (!allowed.includes(file.mimetype)) { -// return reply.code(400).send({ error: "Only JPEG/PNG images are allowed." }); -// } + await new Promise((resolve, reject) => { + writeStream.on('finish', resolve); + writeStream.on('error', reject); + }); -// // Build GCS path -// const ext = (mime.extension(file.mimetype) || path.extname(file.originalname).slice(1) || "png").toLowerCase(); -// const safeBase = path.parse(file.originalname).name.replace(/[^\w.-]/g, "_"); -// const filePath = `arminta_team_profiles/${safeBase}-${Date.now()}.${ext}`; -// const bucketName = "arminta_profile_pictures"; + // Make file public + await file.makePublic(); + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// // Upload -// const buffer = await fs.promises.readFile(file.path); -// const bucket = storage.bucket(bucketName); -// const gcsFile = bucket.file(filePath); -// await gcsFile.save(buffer, { -// resumable: false, -// public: true, -// contentType: file.mimetype, -// metadata: { cacheControl: "public, max-age=31536000" }, -// }); -// await gcsFile.makePublic(); + // Update DB with async/await + const picture = await CompanyProfilePicture.findOneAndUpdate( + { customerId }, + { picture: publicUrl }, + { new: true, upsert: true } + ); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + reply.send({ picture: publicUrl }); + } catch (err) { + console.error(err); + reply.code(500).send({ error: 'An error occurred', details: err.message }); + } +}); -// // Always upsert the installation-level picture doc -// await ProfilePictureInstallTeamMember.findOneAndUpdate( -// { installationId, teamMemberId }, -// { picture: publicUrl }, -// { new: true, upsert: true } -// ); +fastify.post("/api/uploads_installation_TeamMember_profile/:installationId/:teamMemberId", { + preHandler: upload.single("file"), +}, async (request, reply) => { + try { + const { installationId ,teamMemberId} = request.params; + //const teamMemberId = request.body?.teamMemberId; // OPTIONAL + const file = request.file; + if (!file) { + return reply.code(400).send({ error: "No file uploaded (field name 'file')." }); + } -// // Update department picture where departmentId === installationId -// const deptUpdate = await Deparments.findOneAndUpdate( -// { departmentId: installationId }, -// { picture: publicUrl }, -// { new: true } -// ); + // Validate image type + const allowed = ["image/jpeg", "image/jpg", "image/png"]; + if (!allowed.includes(file.mimetype)) { + return reply.code(400).send({ error: "Only JPEG/PNG images are allowed." }); + } -// let teamMemberUpdated = false; -// if (teamMemberId) { -// // 1) Upsert team-member picture collection -// await ProfilePictureInstallTeamMember.findOneAndUpdate( -// { teamMemberId }, -// { picture: publicUrl }, -// { new: true, upsert: true } -// ); + // Build GCS path + const ext = (mime.extension(file.mimetype) || path.extname(file.originalname).slice(1) || "png").toLowerCase(); + const safeBase = path.parse(file.originalname).name.replace(/[^\w.-]/g, "_"); + const filePath = `arminta_team_profiles/${safeBase}-${Date.now()}.${ext}`; + const bucketName = "arminta_profile_pictures"; + + // Upload + const buffer = await fs.promises.readFile(file.path); + const bucket = storage.bucket(bucketName); + const gcsFile = bucket.file(filePath); + await gcsFile.save(buffer, { + resumable: false, + public: true, + contentType: file.mimetype, + metadata: { cacheControl: "public, max-age=31536000" }, + }); + await gcsFile.makePublic(); + + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + + // Always upsert the installation-level picture doc + await ProfilePictureInstallTeamMember.findOneAndUpdate( + { installationId, teamMemberId }, + { picture: publicUrl }, + { new: true, upsert: true } +); + + + // Update department picture where departmentId === installationId + const deptUpdate = await Deparments.findOneAndUpdate( + { departmentId: installationId }, + { picture: publicUrl }, + { new: true } + ); + + let teamMemberUpdated = false; + if (teamMemberId) { + // 1) Upsert team-member picture collection + await ProfilePictureInstallTeamMember.findOneAndUpdate( + { teamMemberId }, + { picture: publicUrl }, + { new: true, upsert: true } + ); -// // 2) Update nested item inside Installations.team_member.team_member[] -// // Using arrayFilters to match the correct team member element -// const res = await Install.updateOne( -// { installationId }, -// { -// $set: { -// "team_member.team_member.$[tm].picture": publicUrl -// } -// }, -// { -// arrayFilters: [{ "tm.teamMemberId": teamMemberId }] -// } -// ); -// teamMemberUpdated = res.modifiedCount > 0; -// } + // 2) Update nested item inside Installations.team_member.team_member[] + // Using arrayFilters to match the correct team member element + const res = await Install.updateOne( + { installationId }, + { + $set: { + "team_member.team_member.$[tm].picture": publicUrl + } + }, + { + arrayFilters: [{ "tm.teamMemberId": teamMemberId }] + } + ); + teamMemberUpdated = res.modifiedCount > 0; + } -// return reply.send({ -// installationId, -// teamMemberId: teamMemberId || null, -// picture: publicUrl, -// departmentUpdated: Boolean(deptUpdate), -// teamMemberUpdated, -// message: teamMemberId -// ? (teamMemberUpdated -// ? "Upload successful. Installation + team member picture updated." -// : "Upload successful. Team member not found under this installation.") -// : "Upload successful. Installation picture updated.", -// }); -// } catch (err) { -// request.log.error(err); -// return reply.code(500).send({ error: "Upload failed", details: err.message }); -// } finally { -// try { if (request.file?.path) await fs.promises.unlink(request.file.path); } catch {} -// } -// }); + return reply.send({ + installationId, + teamMemberId: teamMemberId || null, + picture: publicUrl, + departmentUpdated: Boolean(deptUpdate), + teamMemberUpdated, + message: teamMemberId + ? (teamMemberUpdated + ? "Upload successful. Installation + team member picture updated." + : "Upload successful. Team member not found under this installation.") + : "Upload successful. Installation picture updated.", + }); + } catch (err) { + request.log.error(err); + return reply.code(500).send({ error: "Upload failed", details: err.message }); + } finally { + try { if (request.file?.path) await fs.promises.unlink(request.file.path); } catch {} + } +}); fastify.post('/api/uploads/:supplierId', async (request, reply) => { try { @@ -1383,59 +1383,59 @@ fastify.post('/api/uploads/:supplierId', async (request, reply) => { -// fastify.post('/api/uploads-user/:customerId', async (request, reply) => { -// try { -// const customerId = request.params.customerId; -// const data = await request.file(); +fastify.post('/api/uploads-user/:customerId', async (request, reply) => { + try { + const customerId = request.params.customerId; + const data = await request.file(); -// // Generate a unique file name + // Generate a unique file name -// const fileName = `${data.filename}`; + const fileName = `${data.filename}`; -// // Define the destination bucket and file path -// const bucketName = 'arminta_profile_pictures'; -// const filePath = `arminta_user_profiles/${fileName}`; + // Define the destination bucket and file path + const bucketName = 'arminta_profile_pictures'; + const filePath = `arminta_user_profiles/${fileName}`; -// // Create a write stream to the destination file in the bucket -// const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream(); + // Create a write stream to the destination file in the bucket + const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream(); -// // Pipe the file data to the write stream -// data.file.pipe(writeStream); + // Pipe the file data to the write stream + data.file.pipe(writeStream); -// writeStream.on('finish', async () => { -// try { -// // Make the uploaded file publicly accessible -// await storage.bucket(bucketName).file(filePath).makePublic(); - -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; - -// ProfilePicture.findOneAndUpdate( -// { customerId }, -// { picture: publicUrl }, -// { new: true, upsert: true }, -// (error, picture) => { -// if (error) { -// reply.code(500).send({ error: 'Failed to update database' }); -// } else { -// // Return the public URL -// reply.send({ picture: publicUrl }); -// } -// } -// ); -// } catch (error) { -// reply.code(500).send({ error: 'Failed to make file public' }); -// } -// }); + writeStream.on('finish', async () => { + try { + // Make the uploaded file publicly accessible + await storage.bucket(bucketName).file(filePath).makePublic(); + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// writeStream.on('error', (err) => { -// reply.code(500).send({ error: 'Failed to move file' }); -// }); -// } catch (err) { -// reply.code(500).send({ error: 'An error occurred' }); -// } -// }); + ProfilePicture.findOneAndUpdate( + { customerId }, + { picture: publicUrl }, + { new: true, upsert: true }, + (error, picture) => { + if (error) { + reply.code(500).send({ error: 'Failed to update database' }); + } else { + // Return the public URL + reply.send({ picture: publicUrl }); + } + } + ); + } catch (error) { + reply.code(500).send({ error: 'Failed to make file public' }); + } + }); + + + writeStream.on('error', (err) => { + reply.code(500).send({ error: 'Failed to move file' }); + }); + } catch (err) { + reply.code(500).send({ error: 'An error occurred' }); + } +}); // fastify.post("/api/uploads-electricty-work/:customerId/:installationId", async (request, reply) => { @@ -1495,59 +1495,59 @@ fastify.post('/api/uploads/:supplierId', async (request, reply) => { // } // }); -// fastify.post( -// "/api/uploads-electricty-work/:customerId/:installationId", -// { preHandler: upload.any() }, // allow multiple files -// async (request, reply) => { -// try { -// const { customerId, installationId } = request.params; -// const files = request.files; +fastify.post( + "/api/uploads-electricty-work/:customerId/:installationId", + { preHandler: upload.any() }, // allow multiple files + async (request, reply) => { + try { + const { customerId, installationId } = request.params; + const files = request.files; -// if (!files || files.length === 0) { -// return reply.code(400).send({ error: "No files uploaded" }); -// } + if (!files || files.length === 0) { + return reply.code(400).send({ error: "No files uploaded" }); + } -// const bucketName = "arminta_profile_pictures"; -// const publicUrls = []; + const bucketName = "arminta_profile_pictures"; + const publicUrls = []; -// for (const file of files) { -// const uniqueFileName = `${Date.now()}-${Math.random() -// .toString(36) -// .substring(7)}-${file.originalname}`; -// const filePath = `electricty_work_picture/${uniqueFileName}`; + for (const file of files) { + const uniqueFileName = `${Date.now()}-${Math.random() + .toString(36) + .substring(7)}-${file.originalname}`; + const filePath = `electricty_work_picture/${uniqueFileName}`; -// // ✅ Handle buffer vs path depending on multer storage -// const fileBuffer = file.buffer -// ? file.buffer // memoryStorage -// : await fs.promises.readFile(file.path); // diskStorage + // ✅ Handle buffer vs path depending on multer storage + const fileBuffer = file.buffer + ? file.buffer // memoryStorage + : await fs.promises.readFile(file.path); // diskStorage -// await storage.bucket(bucketName).file(filePath).save(fileBuffer); + await storage.bucket(bucketName).file(filePath).save(fileBuffer); -// await storage.bucket(bucketName).file(filePath).makePublic(); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// publicUrls.push(publicUrl); + await storage.bucket(bucketName).file(filePath).makePublic(); + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + publicUrls.push(publicUrl); -// console.log(`✅ Uploaded: ${publicUrl}`); -// } + console.log(`✅ Uploaded: ${publicUrl}`); + } -// // Update MongoDB -// const updatedRecord = await ElectrictyWorkPictures.findOneAndUpdate( -// { customerId, installationId }, -// { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, -// { new: true, upsert: true } -// ); + // Update MongoDB + const updatedRecord = await ElectrictyWorkPictures.findOneAndUpdate( + { customerId, installationId }, + { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, + { new: true, upsert: true } + ); -// return reply.send({ -// success: true, -// pictures: publicUrls, -// details: updatedRecord, -// }); -// } catch (err) { -// console.error("❌ Upload Error:", err); -// return reply.code(500).send({ error: "Upload failed", details: err.message }); -// } -// } -// ); + return reply.send({ + success: true, + pictures: publicUrls, + details: updatedRecord, + }); + } catch (err) { + console.error("❌ Upload Error:", err); + return reply.code(500).send({ error: "Upload failed", details: err.message }); + } + } +); // fastify.post("/api/uploads-manualTestVideo-work/:customerId/:installationId", async (request, reply) => { // try { @@ -1681,142 +1681,142 @@ fastify.post('/api/uploads/:supplierId', async (request, reply) => { // ); -// fastify.post( -// "/api/uploads-manualTestVideo-work/:customerId/:installationId", -// { preHandler: upload.any() }, // Multer saves files to "uploads/" -// async (request, reply) => { -// try { -// const { customerId, installationId } = request.params; -// const files = request.files; // Multer saves file info here - -// if (!files || files.length === 0) { -// return reply.code(400).send({ error: "No files uploaded" }); -// } +fastify.post( + "/api/uploads-manualTestVideo-work/:customerId/:installationId", + { preHandler: upload.any() }, // Multer saves files to "uploads/" + async (request, reply) => { + try { + const { customerId, installationId } = request.params; + const files = request.files; // Multer saves file info here -// const bucketName = "arminta_profile_pictures"; -// const publicUrls = []; + if (!files || files.length === 0) { + return reply.code(400).send({ error: "No files uploaded" }); + } -// for (const file of files) { -// const uniqueFileName = `${Date.now()}-${Math.random() -// .toString(36) -// .substring(7)}-${file.originalname}`; -// const filePath = `manual_test_video/${uniqueFileName}`; + const bucketName = "arminta_profile_pictures"; + const publicUrls = []; -// console.log(`Uploading video: ${file.path} → ${filePath}`); + for (const file of files) { + const uniqueFileName = `${Date.now()}-${Math.random() + .toString(36) + .substring(7)}-${file.originalname}`; + const filePath = `manual_test_video/${uniqueFileName}`; -// const gcsFile = storage.bucket(bucketName).file(filePath); -// const stream = gcsFile.createWriteStream({ -// metadata: { -// contentType: file.mimetype || "video/mp4", -// contentDisposition: "inline", -// }, -// resumable: false, -// }); + console.log(`Uploading video: ${file.path} → ${filePath}`); -// // Pipe from disk to GCS -// fs.createReadStream(file.path).pipe(stream); + const gcsFile = storage.bucket(bucketName).file(filePath); + const stream = gcsFile.createWriteStream({ + metadata: { + contentType: file.mimetype || "video/mp4", + contentDisposition: "inline", + }, + resumable: false, + }); -// await new Promise((resolve, reject) => { -// stream.on("finish", async () => { -// try { -// await gcsFile.makePublic(); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// publicUrls.push(publicUrl); -// console.log(`✅ Uploaded: ${publicUrl}`); -// resolve(); -// } catch (err) { -// reject(err); -// } -// }); -// stream.on("error", (err) => { -// console.error("Upload Error:", err); -// reject(err); -// }); -// }); + // Pipe from disk to GCS + fs.createReadStream(file.path).pipe(stream); + + await new Promise((resolve, reject) => { + stream.on("finish", async () => { + try { + await gcsFile.makePublic(); + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + publicUrls.push(publicUrl); + console.log(`✅ Uploaded: ${publicUrl}`); + resolve(); + } catch (err) { + reject(err); + } + }); + stream.on("error", (err) => { + console.error("Upload Error:", err); + reject(err); + }); + }); -// // optional: cleanup temp file -// fs.unlink(file.path, (err) => { -// if (err) console.error("Temp file cleanup failed:", err); -// }); -// } + // optional: cleanup temp file + fs.unlink(file.path, (err) => { + if (err) console.error("Temp file cleanup failed:", err); + }); + } -// // Update MongoDB -// const updatedRecord = await ManualTestVideo.findOneAndUpdate( -// { customerId, installationId }, -// { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, -// { new: true, upsert: true } -// ); + // Update MongoDB + const updatedRecord = await ManualTestVideo.findOneAndUpdate( + { customerId, installationId }, + { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, + { new: true, upsert: true } + ); -// return reply.send({ -// success: true, -// videos: publicUrls, -// details: updatedRecord, -// }); -// } catch (err) { -// console.error("Upload Error:", err); -// return reply -// .code(500) -// .send({ error: "Upload failed", details: err.message }); -// } -// } -// ); + return reply.send({ + success: true, + videos: publicUrls, + details: updatedRecord, + }); + } catch (err) { + console.error("Upload Error:", err); + return reply + .code(500) + .send({ error: "Upload failed", details: err.message }); + } + } +); -// fastify.post("/api/uploads-plumbing-work/:customerId/:installationId", async (request, reply) => { -// try { -// const { customerId, installationId } = request.params; -// const files = await request.files(); // Await files properly +fastify.post("/api/uploads-plumbing-work/:customerId/:installationId", async (request, reply) => { + try { + const { customerId, installationId } = request.params; + const files = await request.files(); // Await files properly -// if (!files || files.length === 0) { -// return reply.code(400).send({ error: "No files uploaded" }); -// } + if (!files || files.length === 0) { + return reply.code(400).send({ error: "No files uploaded" }); + } -// const bucketName = "arminta_profile_pictures"; -// const publicUrls = []; + const bucketName = "arminta_profile_pictures"; + const publicUrls = []; -// for await (const file of files) { -// const uniqueFileName = `${Date.now()}-${Math.random().toString(36).substring(7)}-${file.filename}`; -// const filePath = `plumbing_work_picture/${uniqueFileName}`; + for await (const file of files) { + const uniqueFileName = `${Date.now()}-${Math.random().toString(36).substring(7)}-${file.filename}`; + const filePath = `plumbing_work_picture/${uniqueFileName}`; -// console.log(`Uploading file: ${file.filename} → ${filePath}`); + console.log(`Uploading file: ${file.filename} → ${filePath}`); -// const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream(); + const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream(); -// file.file.pipe(writeStream); + file.file.pipe(writeStream); -// await new Promise((resolve, reject) => { -// writeStream.on("finish", async () => { -// try { -// await storage.bucket(bucketName).file(filePath).makePublic(); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// publicUrls.push(publicUrl); -// console.log(`File uploaded: ${publicUrl}`); -// resolve(); -// } catch (error) { -// console.error("Failed to make file public:", error); -// reject(error); -// } -// }); + await new Promise((resolve, reject) => { + writeStream.on("finish", async () => { + try { + await storage.bucket(bucketName).file(filePath).makePublic(); + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + publicUrls.push(publicUrl); + console.log(`File uploaded: ${publicUrl}`); + resolve(); + } catch (error) { + console.error("Failed to make file public:", error); + reject(error); + } + }); -// writeStream.on("error", (err) => { -// console.error("Failed to upload file:", err); -// reject(err); -// }); -// }); -// } + writeStream.on("error", (err) => { + console.error("Failed to upload file:", err); + reject(err); + }); + }); + } -// // Update MongoDB: Convert URLs to { url: "..." } objects -// const updatedRecord = await PlumbingWorkPictures.findOneAndUpdate( -// { customerId, installationId }, -// { $push: { pictureUrl: { $each: publicUrls.map(url => ({ url })) } } }, // Append new images -// { new: true, upsert: true } -// ); + // Update MongoDB: Convert URLs to { url: "..." } objects + const updatedRecord = await PlumbingWorkPictures.findOneAndUpdate( + { customerId, installationId }, + { $push: { pictureUrl: { $each: publicUrls.map(url => ({ url })) } } }, // Append new images + { new: true, upsert: true } + ); -// reply.send({ success: true, pictures: publicUrls, details: updatedRecord }); -// } catch (err) { -// console.error("Upload Error:", err); -// reply.code(500).send({ error: "An error occurred", details: err.message }); -// } -// }); + reply.send({ success: true, pictures: publicUrls, details: updatedRecord }); + } catch (err) { + console.error("Upload Error:", err); + reply.code(500).send({ error: "An error occurred", details: err.message }); + } +}); // fastify.post("/api/uploads-material-recieved/:customerId/:installationId", async (request, reply) => { // try { @@ -1988,61 +1988,61 @@ fastify.post('/api/uploads/:supplierId', async (request, reply) => { // }, // }); -// fastify.post( -// "/api/uploads-material-recieved/:customerId/:installationId", -// { preHandler: upload.any() }, // use 'files' field for multiple uploads -// async (request, reply) => { -// try { -// const { customerId, installationId } = request.params; -// const files = request.files; // multer-style files array +fastify.post( + "/api/uploads-material-recieved/:customerId/:installationId", + { preHandler: upload.any() }, // use 'files' field for multiple uploads + async (request, reply) => { + try { + const { customerId, installationId } = request.params; + const files = request.files; // multer-style files array -// if (!files || files.length === 0) { -// return reply.code(400).send({ error: "No files uploaded" }); -// } + if (!files || files.length === 0) { + return reply.code(400).send({ error: "No files uploaded" }); + } -// const bucketName = "arminta_profile_pictures"; -// const publicUrls = []; + const bucketName = "arminta_profile_pictures"; + const publicUrls = []; -// for (const file of files) { -// // Generate unique file name -// const uniqueFileName = `${Date.now()}-${Math.random() -// .toString(36) -// .substring(7)}-${file.originalname}`; -// const filePath = `plumbing_work_picture/${uniqueFileName}`; + for (const file of files) { + // Generate unique file name + const uniqueFileName = `${Date.now()}-${Math.random() + .toString(36) + .substring(7)}-${file.originalname}`; + const filePath = `plumbing_work_picture/${uniqueFileName}`; -// // Read file buffer -// const fileBuffer = await fs.promises.readFile(file.path); + // Read file buffer + const fileBuffer = await fs.promises.readFile(file.path); -// // Upload to GCS -// await storage.bucket(bucketName).file(filePath).save(fileBuffer); + // Upload to GCS + await storage.bucket(bucketName).file(filePath).save(fileBuffer); -// // Make file public -// await storage.bucket(bucketName).file(filePath).makePublic(); + // Make file public + await storage.bucket(bucketName).file(filePath).makePublic(); -// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; -// publicUrls.push(publicUrl); -// } + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + publicUrls.push(publicUrl); + } -// // Save/Update in DB -// const updatedRecord = await MaterialRecievedPictures.findOneAndUpdate( -// { customerId, installationId }, -// { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, // Append images -// { new: true, upsert: true } -// ); + // Save/Update in DB + const updatedRecord = await MaterialRecievedPictures.findOneAndUpdate( + { customerId, installationId }, + { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, // Append images + { new: true, upsert: true } + ); -// return reply.send({ -// success: true, -// pictures: publicUrls, -// details: updatedRecord, -// }); -// } catch (err) { -// request.log.error(err); -// return reply -// .code(500) -// .send({ error: "Upload failed", details: err.message }); -// } -// } -// ); + return reply.send({ + success: true, + pictures: publicUrls, + details: updatedRecord, + }); + } catch (err) { + request.log.error(err); + return reply + .code(500) + .send({ error: "Upload failed", details: err.message }); + } + } +); fastify.post("/api/installLogin", { schema: { description: "Login as Installation Manager", diff --git a/src/models/store.js b/src/models/store.js index 3d347141..a498237e 100644 --- a/src/models/store.js +++ b/src/models/store.js @@ -914,15 +914,6 @@ const orderSchema = new mongoose.Schema({ datetime: { type: String, default: null }, updated_at: { type: String, default: null }, assignedTeamMembers: [{ type: String }], - assignedSupportTeamMember: { - support_teamMemberId: { type: String }, - name: { type: String }, - phone: { type: String }, - email: { type: String }, - assignedAt: { type: String }, - assignmentCode: { type: String }, - quationId: { type: String }, - }, tankhardwareId: [{ type: String,default: null }], master_connections: [ { diff --git a/src/models/supplier.js b/src/models/supplier.js index 3aadd9ec..fc007b83 100644 --- a/src/models/supplier.js +++ b/src/models/supplier.js @@ -159,7 +159,6 @@ const supplierSchema = new mongoose.Schema( }); - const requestedSupplierSchema = new mongoose.Schema({ supplierId: String, diff --git a/src/models/tanks.js b/src/models/tanks.js index 4204f4ab..28a56a70 100644 --- a/src/models/tanks.js +++ b/src/models/tanks.js @@ -67,7 +67,6 @@ const tanksSchema = new mongoose.Schema({ slave_status:{ type: String, default: "working" }, slave_disconnected_time :{ type: String, default: null }, - connections: { source: { type: String }, inputConnections: [ @@ -242,7 +241,6 @@ const TankConsumptionSchema = mongoose.model("TankConsumptionSchema", tankconsum const TankConsumptionOriginalSchema = mongoose.model("TankConsumptionOriginalSchema", tankconsumptionoriginalSchema); - module.exports = { Tank, MotorData,IotData,TankWaterLevel,TankConsumptionSchema,TankConsumptionOriginalSchema,CustomerAutoPercentages } diff --git a/src/routes/installationRoute.js b/src/routes/installationRoute.js index dae4daca..7ab00c44 100644 --- a/src/routes/installationRoute.js +++ b/src/routes/installationRoute.js @@ -1325,8 +1325,8 @@ fastify.post( support_teamMemberId: { type: "string" }, // startDate: { type: "string" }, // endDate: { type: "string" }, - //category: { type: "string" }, - quationId: { type: "string" }, + category: { type: "string" }, + masterHardwareId: { type: "string" }, }, }, }, diff --git a/uploads/45246b640831a27395f9d1dfea1dd72d b/uploads/45246b640831a27395f9d1dfea1dd72d new file mode 100644 index 00000000..54f62aa4 Binary files /dev/null and b/uploads/45246b640831a27395f9d1dfea1dd72d differ diff --git a/uploads/955273029ffa0b831471711c8320d710 b/uploads/955273029ffa0b831471711c8320d710 new file mode 100644 index 00000000..dd973941 Binary files /dev/null and b/uploads/955273029ffa0b831471711c8320d710 differ diff --git a/uploads/986f0b7b4d59233ae60e99a873da1ba8 b/uploads/986f0b7b4d59233ae60e99a873da1ba8 new file mode 100644 index 00000000..dd973941 Binary files /dev/null and b/uploads/986f0b7b4d59233ae60e99a873da1ba8 differ diff --git a/uploads/9ff41d2544f312e3e471ec053b8bbcc9 b/uploads/9ff41d2544f312e3e471ec053b8bbcc9 new file mode 100644 index 00000000..54f62aa4 Binary files /dev/null and b/uploads/9ff41d2544f312e3e471ec053b8bbcc9 differ diff --git a/uploads/ae2e66bb5806eff227d85b57df4d28f7 b/uploads/ae2e66bb5806eff227d85b57df4d28f7 new file mode 100644 index 00000000..dd973941 Binary files /dev/null and b/uploads/ae2e66bb5806eff227d85b57df4d28f7 differ diff --git a/uploads/d09c81cf26a3ba3b463e7c65565e032b b/uploads/d09c81cf26a3ba3b463e7c65565e032b new file mode 100644 index 00000000..735faf85 Binary files /dev/null and b/uploads/d09c81cf26a3ba3b463e7c65565e032b differ diff --git a/uploads/d2bfa56b0d68f890ea38a77a907bc5b8 b/uploads/d2bfa56b0d68f890ea38a77a907bc5b8 new file mode 100644 index 00000000..735faf85 Binary files /dev/null and b/uploads/d2bfa56b0d68f890ea38a77a907bc5b8 differ