+ Querid@ ${user.name}, +
+ +Tu proyecto se ha creado con éxito. Esto es un gran paso hacia la realización de tu visión.!
+Si deseas realizar cambios o actualizar la información de tu proyecto, puedes hacerlo desde tu panel de control
+No dudes en ponerte en contacto con nuestro equipo de soporte si necesitas ayuda o tienes preguntas adicionales.
+¡Gracias por ser parte de nuestra comunidad y por compartir tu proyecto con nosotros!
+Saludos,
+El equipo de ProJunity
+@2023 ProJunity. Todos los derechos reservados.
+ ` + sendEmail(userMail, subject, text, html) + + res.status(200).json(newProject); console.log(newProject); } catch (error) { res.status(500).json(error.message); diff --git a/server/src/controllers/mailer.js b/server/src/controllers/mailer.js new file mode 100644 index 0000000..bdbdfbc --- /dev/null +++ b/server/src/controllers/mailer.js @@ -0,0 +1,35 @@ +const nodemailer = require('nodemailer'); + +const { + MAIL_USERNAME, + MAIL_PASSWORD +} = process.env + +const transporter = nodemailer.createTransport({ + host: "smtp.gmail.com", + port:465, + secure:true, + auth:{ + user: MAIL_USERNAME, + pass: MAIL_PASSWORD + } +}); + +const sendEmail = async(to, subject, text, html)=>{ + const mailOptions={ + from: MAIL_USERNAME, + to, + subject, + text, + html + }; + + try{ + await transporter.sendMail(mailOptions); + console.log(`Correo electrónico enviado a ${to}`); + }catch (error){ + console.log("Error al enviar el correo electrónico", error); + } +} + +module.exports = {sendEmail} diff --git a/server/src/controllers/mercadopago.js b/server/src/controllers/mercadopago.js index 2bfd658..918a3b6 100644 --- a/server/src/controllers/mercadopago.js +++ b/server/src/controllers/mercadopago.js @@ -7,67 +7,50 @@ const { projects } = require("../utils/index.js"); // Configura las credenciales de MercadoPago const paymenntsControllers = { - // Función para crear una preferencia de pago en MercadoPago - createPaymentPreference: async function (req, res) { - // const { items, payer, concepto, status } = req.body; + + // Función para crear una preferencia de pago en MercadoPago + createPaymentPreference: async function(req, res ) { + mercadopago.configure({ access_token: MP_TOKEN, }); - //const id_orden= 1 - const orderNumber = await Payments.findAll({ - attributes: [Sequelize.fn("max", Sequelize.col("orderNumber"))], - raw: true, - }); - compra = req.body; - items = compra.map((item) => { - return { - buyer: item.buyer, - id: item.id, - title: item.title, - currency_id: "ARS", - unit_price: Number(item.unit_price), - quantity: 1, - }; - }); - /* [ - { - buyer:compra[0].UserId, - id:compra[0].projectId, - title: compra[0].title, - currency_id: 'ARS', - unit_price:Number(compra[0].unit_price), - quantity: 1, - - }, - { - buyer:compra[1].UserId, - id:compra[1].projectId, - title: compra[1].title, - currency_id: 'ARS', - unit_price:Number(compra[1].unit_price), - quantity: 1, - -}, -{ - buyer:compra[2].UserId, - id:compra[2].projectId, - title: compra[2].title, - currency_id: 'ARS', - unit_price:Number(compra[2].unit_price), - quantity: 1, - -}, - ]*/ -console.log(items); + + const lastOrderNumber = await Payments.findAll({ + attributes: [Sequelize.fn('max', Sequelize.col('orderNumber'))], + raw: true + }) + + const orderNumber = lastOrderNumber[0].max+1 + let items = req.body + for (let i in items) { + const createOrder = await Payments.create({ + paymentAmount: items[i].unit_price, + orderNumber: orderNumber, + product: items[i].id, + buyer: items[i].buyer, + concept: items[i].concept? items[i].concept : 'venta', //venta, donacion o devolucion + status: items[i].status? items[i].status : 'processing', + }) + } + + const totalPrecio = req.body.reduce((acumulador, producto) => + acumulador + parseFloat(producto.unit_price), 0); + const preference = { items, - total_amount: 1, - external_reference: `${orderNumber[0].max + 1}`, + total_amount: totalPrecio, + external_reference : `${orderNumber}`, + payer: await Users.findOne({ + where: {id: items[0].buyer}, + attributes: ['name', 'email'], + raw: true + }), + back_urls: { - success: "http://localhost:3001/createPayment/succes", - pending: `${CLIENT_HOST}/error`, - failure: `${CLIENT_HOST}/pending`, + success: "https://proj-unity.vercel.app", + pending: `${DB_HOST}/error`, + failure: `${DB_HOST}/pending`, }, notification_url: "https://3eb3-181-29-72-133.ngrok.io/webhook", auto_return: "approved", @@ -83,67 +66,71 @@ console.log(items); 0 ); - console.log(items); - - const orderDb = await Payments.create({ - paymentId: global.id, - status: "created", - orderNumber: orderNumber[0].max + 1, - buyer: 1, - projects: 1, - paymentAmount: totalPrecio, - }); + for (let i in projects) { + await Payments.update( + { + paymentId: global.id, + status:"created", + }, + { + where: { + orderNumber: orderNumber, + product: projects[i].id + } + }); + } + const queryOrder = await Payments.findAll({where: {orderNumber: orderNumber}, raw: true}) + let itemsDb = [] + for (let i in queryOrder) { + let { product, paymentAmount} = queryOrder[i] + let productName = await Projects.findOne({where: {id: product}, attributes: ['name'], raw: true}) + itemsDb = [ + ...itemsDb, + { + id: product, + title: productName.name, + unit_price: paymentAmount, + quantity: 1 + } + ] + } - // console.log(orderDb) - res.json({ - id: global.id, - init_point: response.body.init_point, - orderDb, - }); - } catch (error) { - console.log(error); - } + res.json({id: global.id, init_point: response.body.init_point, itemsDb}) + + } catch (error) { + console.log(error); + } }, - // falta relacionar las nuevas compras con projectId y userId - - // const items = [ - // { - // id: projectId, - // title: title, - // unit_price:Number(unit_price), - // quantity: 1 - // }, - // ] - // const totalPrecio = items.reduce((acumulador, producto) => - // acumulador + parseFloat(producto.unit_price), 0); - - // res.json({ - // id_mercadopago: global.id, - // init_point: response.body.init_point, - // items: response.body.items, - // back_urls: response.body.back_urls, - // total_amount:totalPrecio - // }); - - getOrdenId: async function (req, res) { - try { - const { id } = req.params; - const payment = await paymentsServices.paymentId(id); - res.status(200).json(payment); + getOrdenId: async function(req, res){ + try { + const {id} = req.params + const payment = await paymentsServices.paymentId(id); + res.status(200).json(payment); } catch (error) { - res.status(500).json(error.message); + res.status(500).json(error.message); } }, - getAllPayment: async function (req, res) { + getAllPayment: async function(req, res){ try { - const paymentsData = req.body; - const allPayments = await paymentsServices.allPayments(paymentsData); - res.status(200).json(allPayments); + const { desde, hasta } = req.query + const currentTime = new Date() + let fechaDesde = desde? desde.split('-') : []; + fechaDesde.length !== 3? + fechaDesde = new Date(currentTime.getFullYear(),currentTime.getMonth(),1,0,0,0) + : fechaDesde = new Date(parseInt(desde[0]),parseInt(desde[1])-1,parseInt(desde[2]),0,0,0); //<<--- si no esta definida la fecha desde, se define por defecto desde el primero del corriente mes + + let fechaHasta = hasta? hasta.split('-') : []; + fechaHasta.length !== 3? + fechaHasta = currentTime + : fechaHasta = new Date(parseInt(hasta[0]),parseInt(hasta[1])-1,parseInt(hasta[2]),0,0,0); + + const allPayments = await paymentsServices.allPayments({...req.query, desde: fechaDesde, hasta: fechaHasta}); + res.status(200).json(allPayments) } catch (error) { - res.status(500).json(error.message); + res.status(500).json(error.message) } - }, + } }; - -module.exports = paymenntsControllers; + +module.exports = paymenntsControllers diff --git a/server/src/controllers/projects.js b/server/src/controllers/projects.js index 8ddc612..ec26703 100644 --- a/server/src/controllers/projects.js +++ b/server/src/controllers/projects.js @@ -52,6 +52,15 @@ const projectControllers = { } }, + getDeletedProjects: async function (req, res) { + try { + const deletedProjects = await Services.getDeletedProjects(); + res.status(200).json(deletedProjects); + } catch (error) { + res.status(500).json(error.message); + } +}, + restoreProject: async function (req, res) { try { const projectId = req.params.id; @@ -63,4 +72,4 @@ const projectControllers = { }, }; -module.exports = projectControllers; +module.exports = projectControllers; \ No newline at end of file diff --git a/server/src/controllers/users.js b/server/src/controllers/users.js index c940df9..83cf00e 100644 --- a/server/src/controllers/users.js +++ b/server/src/controllers/users.js @@ -1,19 +1,49 @@ const Service = require('../services').userServices; +const {sendEmail} = require("./mailer"); const userControllers = { getUsers: async function (req,res) { try { - const { name } = req.query - const Users = await Service.allUsers(name) + const { name, deleted } = req.query + const Users = await Service.allUsers({name, deleted}) res.status(200).json(Users) } catch (error) { res.status(500).json(error.message) } }, + getUserById: async function(req,res) { + try { + const {id} = req.params; + const User = await Service.userById(id) + if (User) { + res.status(200).json(User) + } + } catch (error) { + res.status(500).json(error.message) + } + }, postUser: async function (req,res) { try { const Users = await Service.createUser(req.body) if (Users.id) { + + const userMail = Users.email + const subject = "Usuario creado con éxito ✔ 😉"; + const text = `Querid@ ${Users.name} Tu proyecto se ha creado con éxito. Felicitaciones y gracias por hacer de nuestra comunidad un lugar mejor! ` + const html = `+ Querid@ ${Users.name}, +
+ +Muchas gracias por formar parte de nuestra comunidad. Esperamos que disfrutes de tu experiencia en nuestro sitio.
+Te recordamos que podés ingresar a tu cuenta con tu email y la contraseña que elegiste al registrarte.
+¡Te esperamos pronto!
+Saludos,
+El equipo de ProJunity
+@2023 ProJunity. Todos los derechos reservados.
+ ` + sendEmail(userMail, subject, text, html) + res.status(201).json(Users); } else { res.status(400).json({ type: "error", response: "Algo falló" }); @@ -28,7 +58,7 @@ const userControllers = { try { const userId = req.params.id; - const result = await Service.deleteUser(userId); + const result = await Service.deleteUserbyId(userId); res.status(200).json(result); } catch (error) { @@ -38,8 +68,8 @@ const userControllers = { restoreUser : async function (req, res) { try{ - const userId = req.params.id; - const result = await Service.restoreUsers(userId); + const {id} = req.params; + const result = await Service.restoreUsers(id); res.status(200).json(result); }catch(error){ res.status(500).json(error.message); @@ -47,4 +77,4 @@ const userControllers = { } } -module.exports = userControllers \ No newline at end of file +module.exports = userControllers diff --git a/server/src/db.js b/server/src/db.js index b9ea458..51dc766 100644 --- a/server/src/db.js +++ b/server/src/db.js @@ -12,10 +12,10 @@ const { -/* const sequelize = new Sequelize(`postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}/projunity`, { - logging: false, - native: false, - }); */ +// const sequelize = new Sequelize(`postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}/projunity`, { +// logging: false, +// native: false, +// }); const sequelize = new Sequelize(DEPLOY, { logging: false, diff --git a/server/src/models/user.js b/server/src/models/user.js index 41b870c..d7b0c6f 100644 --- a/server/src/models/user.js +++ b/server/src/models/user.js @@ -61,4 +61,4 @@ module.exports = (sequelize) => { paranoid: true, freezeTableName: true }); -}; \ No newline at end of file +}; diff --git a/server/src/routes/auth.js b/server/src/routes/auth.js index a3bba29..ba3a1d5 100644 --- a/server/src/routes/auth.js +++ b/server/src/routes/auth.js @@ -12,6 +12,12 @@ const salt = process.env.SALT_KEY; const JWT_KEY = process.env.JWT_KEY; +const { + + GITHUB_CB_URL +} = process.env; + + function encryptionPassword(password) { var key = pbkdf2.pbkdf2Sync( password, salt, 36000, 64, 'sha256' @@ -167,8 +173,9 @@ router.get('/auth/github/callback', passport.authenticate('github', { failureRedirect: '/login' }), (req,res,next) => { const token = jwt.sign({id: req.user.id}, JWT_KEY, {expiresIn: 60 * 60 * 24 * 1000}) req.logIn(req.user, function(err) { - if (err) return next(err); ; - res.redirect(`http://localhost:3000?token=${token}`) + if (err) return next(err); + console.log('res redirect ', req); + res.redirect(`https://proj-unity.vercel.app?token=${token}`) }); }, ); @@ -181,13 +188,11 @@ router.get('/profile', async (req, res) => { res.status(401).send({ error: "NotAuthorized" }) } else { req.user = data - Users.findOne({ where: {id: req.user.id}, attributes: {exclude: ['password']}, raw: true }).then((user) => { - console.log("user auth es", user) res.status(200).json(user) }); } @@ -195,7 +200,6 @@ router.get('/profile', async (req, res) => { }) - router.get('/logout', function(req, res) { if(req.isAuthenticated()){ req.logOut(function(err) { @@ -207,4 +211,4 @@ router.get('/logout', function(req, res) { } }); -module.exports = router \ No newline at end of file +module.exports = router diff --git a/server/src/routes/index.js b/server/src/routes/index.js index aca2724..ae5fe2b 100644 --- a/server/src/routes/index.js +++ b/server/src/routes/index.js @@ -33,20 +33,20 @@ function isAuthorized(req, res, next) { router.get("/", isAuthenticated); +router.route('/users/:id') + .get(Controller.getUserById) + .delete(isAuthenticated, isAuthorized, Controller.deleteUser); -router.delete('/users/:id',isAuthenticated, isAuthorized, Controller.deleteUser) +router.put('/users/restore/:id',isAuthenticated, isAuthorized, Controller.restoreUser); -router.put('/users/restore/:id',isAuthenticated, isAuthorized, Controller.restoreUser) - -router.get('/users/:id/dashboard', Controller.getUserDashboard) +router.get('/users/:id/dashboard', Controller.getUserDashboard); router.post("/sign-up", Controller.postUser); router.route('/users') .get(Controller.getUsers); -/* router.post('/sign-up', Controller.postUser); */ router.get( "/usertypes", @@ -65,16 +65,12 @@ router router .route("/projects/:id") + .get(Controller.getProjectsID) .put(Controller.putProjects) - .delete( Controller.deleteProject) + .delete( Controller.deleteProject); router.put('/projects/restore/:id', Controller.restoreProject) - - -router.get('/projects/:id', Controller.getProjectsID); - - router.get("/categories", Controller.getCategories); router.get("/tags", Controller.getTags); @@ -95,13 +91,11 @@ router router.get("/payment/:id", Controller.getOrdenId); router.get("/payment",Controller.getAllPayment) router -.route("/createPayment/succes") +.route("/payment/succes") .get((req, res)=> { - res.send("PAGO REALIZADO CON EXITO") + res.redirect('https://proj-unity.vercel.app/') + //res.send('PAGO REALIZADO CON EXITO') }) module.exports = router; - - - diff --git a/server/src/services/Users.js b/server/src/services/Users.js index f447744..4b85a9f 100644 --- a/server/src/services/Users.js +++ b/server/src/services/Users.js @@ -20,191 +20,149 @@ function encryptionPassword(password) { } const userServices = { - allUsers: async function (name) { - try { - if (name) { - const response = await Users.findAll({ - where: { - name: { [Op.iLike]: `%${name}%` }, - [Op.or]: [{ name: { [Op.iLike]: `${name}%` } }], - [Op.and]: [{ active: "true" }], - }, - attributes: [ - "id", - "name", - "email", - "image", - "twitterUser", - "emailUser", - "githubUser", - "linkedinUser", - "role", - ], - }); - return response; - } else { - const response = await Users.findAll({ - where: { active: "true" }, - attributes: [ - "id", - "name", - "email", - "image", - "twitterUser", - "emailUser", - "githubUser", - "linkedinUser", - "role", - ], - }); - return response; - } - } catch (error) { - return error; - } - }, - createUser: async function (userData) { - try { - const { - name, - email, - password, - image, - twitterUser, - emailUser, - githubUser, - linkedinUser, - role, - } = userData; + allUsers: async function (queryParams) { + try{ + const { name, deleted } = queryParams - if ( - !name || - !email || - !password /* || !image || !twitterUser || !emailUser || !githubUser <<== MODIFIQUE ESTO PARA PODER CREAR USUARIOS */ || - !role - ) { - throw Error(`Missing some data`); - } else { - if (image) { - const uploadedImage = await cloudinary.uploader.upload(image); + const response = await Users.findAll({ + where: name? { + name: { [Op.iLike]: `%${name}%` }, + [Op.or]: [{ name: { [Op.iLike]: `${name}%` } }], + } : null, + paranoid: deleted? false : true, + attributes: {exclude: ['password']}, + }) + return response + } catch (error) { + return error } - - const [newUser, created] = await Users.findOrCreate({ - where: { email: email }, - defaults: { - name, - password: encryptionPassword(password), - image: null, - /* image, */ - twitterUser, - emailUser, - githubUser, - role, - linkedinUser, - }, + }, + userById: async function(id) { + try { + const userId = await Users.findOne({ + where: {id: id}, + attributes: {exclude: ['password']} }); - if (created) { - let { - id, - name, - email, - image, - twitterUser, - emailUser, - githubUser, - linkedinUser, - role, - } = newUser; - return { - id, - name, - email, - image, - twitterUser, - emailUser, - githubUser, - linkedinUser, - role, - }; + if (userId) { + return userId } else { - throw Error("El email de usuario ya existe"); + return 'User not Found' } + } catch (error) { + return error } - } catch (error) { - return error; - } - }, + }, + createUser: async function (userData) { + try { + const { name, email, password, image, twitterUser, emailUser, githubUser, linkedinUser, role} = userData - updateUser: async function (userData, res) { - try { - const { - id, - name, - email, - password, - image, - twitterUser, - emailUser, - githubUser, - linkedinUser, - roleId, - } = userData; - // find the user by ID - const user = await Users.findByPk(id); - if (!user) { - throw new Error("User not found"); - } - // update the user data - user.name = name || user.name; - user.email = email || user.email; - user.password = password ? encryptionPassword(password) : user.password; - user.twitterUser = twitterUser || user.twitterUser; - user.emailUser = emailUser || user.emailUser; - user.githubUser = githubUser || user.githubUser; - user.linkedinUser = linkedinUser || user.linkedinUser; - user.roleId = roleId || user.roleId; - - // upload the image to Cloudinary - if (image) { - const uploadedImage = await cloudinary.uploader.upload(image); - user.image = uploadedImage.secure_url; - } + if ( !name || !email || !password /* || !image || !twitterUser || !emailUser || !githubUser <<== MODIFIQUE ESTO PARA PODER CREAR USUARIOS */ || !role) { - // save the changes - await user.save(); + throw Error(`Missing some data`) + } else { + let uploadedImage; + if (image) { + uploadedImage = await cloudinary.uploader.upload(image); + } + const [newUser, created] = await Users.findOrCreate({ + where: {email: email}, + defaults: { + name, + email, + password: encryptionPassword(password), + image: uploadedImage? uploadedImage.secure_url : null, + twitterUser, + emailUser, + githubUser, + role, + linkedinUser + } + }) + if (created) { + let { id, name, email, image, twitterUser,emailUser, githubUser, linkedinUser, role } = newUser + return { id, name, email, image, twitterUser, emailUser, githubUser, linkedinUser, role } + } else { + throw Error('El email de usuario ya existe') + } + } + } catch (error){ + return error + } + }, - // return the updated user object - res.status(200).json(user); - } catch (error) { - console.log(error); - return error; - } - }, - deleteUser: async function (userId) { - try { - const user = await Users.findByPk(userId); - if (!user) { - throw new Error("User not found"); - } - await user.destroy(); - return { message: "User deleted successfully" }; - } catch (error) { - throw new Error(error.message); - } - }, + updateUser: async function (userData, res){ + try { + const { id, name, email, password, image, twitterUser, emailUser, githubUser, linkedinUser, roleId} = userData + // find the user by ID + const user = await Users.findByPk(id); + if (!user) { + throw new Error("User not found"); + } + // update the user data + user.name = name || user.name; + user.email = email || user.email; + user.password = password ? encryptionPassword(password) : user.password; + user.twitterUser = twitterUser || user.twitterUser; + user.emailUser = emailUser || user.emailUser; + user.githubUser = githubUser || user.githubUser; + user.linkedinUser = linkedinUser || user.linkedinUser; + user.roleId = roleId || user.roleId; + + // upload the image to Cloudinary + if (image) { + const uploadedImage = await cloudinary.uploader.upload(image); + user.image = uploadedImage.secure_url; + } + + // save the changes + await user.save(); + + // return the updated user object + res.status(200).json(user); + } catch (error) { + console.log(error); + return error; + } + }, + deleteUserbyId: async function(userId) { + try { + const user = await Users.findByPk(userId); + if (!user) { + throw new Error('User not found'); + } + await user.destroy(); + return { message: 'User deleted successfully' }; + } catch (error) { + throw new Error(error.message); + } + }, + + getDeletedUsers: async function () { + try { + const deletedUsers = await Users.findAll({ + paranoid: false, + attributes: {exclude: ['password']} + }); + + return deletedUsers; + } catch (error) { + throw new Error(error.message); + } + }, - restoreUsers: async function (userId) { - try { - const user = await Users.findByPk(userId, { paranoid: false }); - if (!user) { - throw new Error("User not found"); - } - await user.restore(); - return { message: "User restored successfully" }; - } catch (error) { - throw new Error(error.message); - } - }, -}; + restoreUsers: async function(userId) { + try { + const user = await Users.findOne({where: {id: userId}, paranoid: false}); + if (!user) { + throw new Error('User not found'); + } + await user.restore(); + return { message: 'User restored successfully' }; + } catch (error) { + throw new Error(error.message); + } + }, + +} -module.exports = userServices; +module.exports = userServices diff --git a/server/src/services/payment.js b/server/src/services/payment.js index 656d1d5..d2dabf6 100644 --- a/server/src/services/payment.js +++ b/server/src/services/payment.js @@ -1,21 +1,45 @@ -const { Projects, Payments} = require('../db.js'); // Importa tus modelos de órdenes +const { Projects, Payments, Users} = require('../db.js'); // Importa tus modelos de órdenes const { Op, Sequelize } = require('sequelize'); -const Controllers = require("./index.js") +const {format} = require('date-fns'); +const Controllers = require("./index.js"); const paymentsServices = { allPayments: async function(query) { try { - const { paymentId, status, paymentAmount, projects, UserId } = query; - const payments = await Payments.findAll({ - - - }); - const orderNumber = await Payments.findAll({ - attributes: [Sequelize.fn('max', Sequelize.col('orderNumber'))], + let { paymentId, status, paymentAmount, projects, UserId, desde, hasta } = query; + + const {count, rows} = await Payments.findAndCountAll({ + where: { + createdAt: {[Op.between]: [desde, hasta]}, + }, + include: { + model: Users, + attributes: ['name'] + }, + attributes: ['id','paymentId','paymentAmount','status','concept','orderNumber','createdAt','product'], + order: [['createdAt', 'DESC']], raw: true - }) - + }); + const projectsName = await Projects.findAll({attributes: ['id','name']}) + + let payments = [] + for (let i in rows) { + payments = [ + ...payments, + { + id: rows[i].id, + paymentId: rows[i].paymentId, + paymentAmount: rows[i].paymentAmount, + status: rows[i].status, + concept: rows[i].concept, + orderNumber: rows[i].orderNumber, + product: projectsName.filter((x) => x.id === rows[i].product)[0].name, + buyer: rows[i]['User.name']? rows[i]['User.name'] : 'undefined', + createdAt: format(rows[i].createdAt, 'yyyy-MM-dd hh:mm') + } + ] + } return payments; } catch (error) { @@ -36,4 +60,4 @@ const paymentsServices = { }, // el create payment de mercado pago esta realizado desde /controllers/mercadopago.js }; -module.exports = paymentsServices; \ No newline at end of file +module.exports = paymentsServices; diff --git a/server/src/services/projects.js b/server/src/services/projects.js index 843e0ab..989e544 100644 --- a/server/src/services/projects.js +++ b/server/src/services/projects.js @@ -14,7 +14,7 @@ cloudinary.config({ const ProjectServices = { allProjects: async function (queryParams) { try { - const { name, category, tag, price, rating, username, id } = queryParams; + const { name, category, tag, price, rating, username, id, deleted } = queryParams; let condition = {}; id ? (condition = { @@ -62,84 +62,83 @@ const ProjectServices = { }) : null; rating - ? (condition = { - ...condition, - ratings: { - score: { - [Op.gte]: rating, - }, - // [Op.or]: [{ score: { [Op.eq]: score } }], + ? (condition = { + ...condition, + rating: { + score:{ + [Op.or]:{ + [Op.lt]: rating, + [Op.eq]: rating , + } }, - }) - : null; + }, + }) + : null; + username + ? (condition = { + ...condition, + users: { + name: { [Op.iLike]: `%${username}%` }, + [Op.or]: [{ name: { [Op.iLike]: `${username}%` } }] + } + }) + : null; - if (Object.keys(condition).length !== 0) { - const projectsFilter = await Projects.findAll({ - include: [ - { - model: Category, - attributes: ["name"], - where: condition.category, - through: { attributes: [] }, - }, - { - model: Tags, - attributes: ["name"], - where: condition.tag, - through: { attributes: [] }, - }, - { - model: Ratings, - attributes: ["score", "comment"], - where: condition.rating, - through: { attributes: [] }, - }, - { - model: Users, - attributes: ["id", "name", "email"], - where: condition.users, - through: { attributes: [] }, - }, - ], - where: condition.project, - }); - return projectsFilter; - } else { - const allProject = await Projects.findAll({ - include: [ - { - model: Category, - attributes: ["name"], - through: { attributes: [] }, - }, - { - model: Tags, - attributes: ["name"], - through: { attributes: [] }, - }, - { - model: Ratings, - attributes: ["score", "comment"], - through: { attributes: [] }, - }, - { - model: Users, - attributes: ["id", "name", "email"], - /* where: condition.users, */ - through: { attributes: [] }, - }, - ], - }); - return allProject; - } + condition.project = { + ...condition.project, + }; + + const projectsFilter = await Projects.findAll({ + include: [ + { + model: Category, + attributes: ["name"], + where: condition.category, + through: { attributes: [] }, + }, + { + model: Tags, + attributes: ["name"], + where: condition.tag, + through: { attributes: [] }, + }, + { + model: Ratings, + attributes: ["score", "comment"], + where: condition.rating, + through: { attributes:[] } , + }, + { + model: Comments, + attributes: ["id", "comment", "replyTo"], + through: { attributes: [] }, + }, + { + model: Ratings, + attributes: ["score", "comment"], + /* where: condition.rating, */ + through: { attributes: [] }, + }, + { + model: Users, + attributes: ['id','name','email','githubUser','twitterUser','linkedinUser'], + where: condition.users, + through: {attributes: []} + } + ], + where: condition.project, + paranoid: deleted? false : true + }); + return projectsFilter; } catch (error) { return error; } }, - projectId: async function (id) { + + getProjectsByID: async function (id) { try { const ProjectId = await Projects.findOne({ - where: { id: id }, + where: { id: id}, include: [ { model: Category, @@ -179,6 +178,7 @@ const ProjectServices = { return error; } }, + createProjects: async function (projectData) { try { const { @@ -315,19 +315,61 @@ const ProjectServices = { throw new Error("Project not found"); } await project.destroy(); - return { message: "Project deleted successfully" }; + return { message: 'Project deleted successfully' }; } catch (error) { throw new Error(error.message); } }, - restoreProjects: async function (projectId) { + + getDeletedProjects: async function () { + try { + const deletedProjects = await Projects.findAll({ + where: { paranoid: false }, + include: [ + { + model: Category, + attributes: ["name"], + through: { attributes: [] }, + }, + { + model: Tags, + attributes: ["name"], + through: { attributes: [] }, + }, + { + model: Comments, + attributes: ["id", "comment", "replyTo"], + through: { attributes: [] }, + }, + { + model: Ratings, + attributes: ["score", "comment"], + /* where: condition.rating, */ + through: { attributes: [] }, + }, + { + model: Users, + attributes: ["id", "name", "email"], + /* where: condition.users, */ + through: { attributes: [] }, + }, + ], + }); + + return deletedProjects; + } catch (error) { + return error; + } +}, + + restoreProjects: async function(projectId) { try { - const project = await Projects.findByPk(projectId, { paranoid: false }); + const project = await Projects.findByPk(projectId, {paranoid: false}); if (!project) { throw new Error("Project not found"); } await project.restore(); - return { message: "Project restored successfully" }; + return { message: 'Project restored successfully' }; } catch (error) { throw new Error(error.message); } diff --git a/server/src/services/userDashboard.js b/server/src/services/userDashboard.js index 1991afb..f7654df 100644 --- a/server/src/services/userDashboard.js +++ b/server/src/services/userDashboard.js @@ -1,6 +1,6 @@ const {Users, UserTypes, Projects, Payments, Ratings, ProjectUser} = require('../db'); const {Op, Sequelize} = require('sequelize'); -const {format} = require('date-fns') +const {format, addDays} = require('date-fns') const DashboardService = { Dashboard: async function (id, fecha) { @@ -134,7 +134,7 @@ const DashboardService = { return { totalProjects: totalProjects.count, activeSubscriptions: 75, - totalSales: `$${sales.valorizado - devoluciones.valorizado}`, + totalSales: sales.contador - devoluciones.contador, totalRevenue: `$${sales.valorizado - devoluciones.valorizado + donaciones.valorizado}`, averageSalesPerUser: await this.averageSales(id,fecha), activeProjects: count, @@ -161,6 +161,45 @@ const DashboardService = { return error } }, + userSalesDetail: async function (userId,desde,hasta) { + try { + const ProjectsIds = await Projects.findAll({ + include: { model: Users, where: {id: userId}, attributes: [] }, + attributes: ['id']}); + let userProducts = [] + for (let i in ProjectsIds) { userProducts.push(ProjectsIds[i].id)} + let dates = [] + //const hasta = new Date(fecha.getFullYear(),fecha.getMonth(),fecha.getDate()+30,0,0,0) + while (desde <= hasta) { + dates.push(desde) + desde = addDays(desde,1) + } + let ventas = [] + for (let i in dates) { + const data = await Payments.findAll({ + where: { + product: userProducts, + createdAt: dates[i], + status: 'completed', + concept: 'venta' + }, + attributes: [ + ['createdAt', 'fecha'], + [Sequelize.fn('count',Sequelize.col('product')),'proyectosVendidos'], + [Sequelize.fn('sum', Sequelize.col('paymentAmount')), 'ganancias'] + ], + group: ['fecha'], + raw: true + }); + data.length !== 0? + ventas.push({...data[0], fecha: format(data[0].fecha, 'yyyy-MM-dd')}) + : ventas.push({fecha: format(dates[i], 'yyyy-MM-dd'), proyectosVendidos: 0, ganancias: 0}); + } + return ventas + } catch (error) { + return error + } + }, userDonations: async function (userId,fecha) { try { let donations = [] @@ -345,9 +384,10 @@ const DashboardService = { [Sequelize.fn('count',Sequelize.col('paymentAmount')), 'Count'] ], //group: ['product'], - where: {createdAt: { - [Op.between]: [fecha, hasta] - }} + where: { + createdAt: {[Op.between]: [fecha, hasta]}, + status: 'completed' + } }) return data } catch (error) { @@ -427,4 +467,4 @@ const DashboardService = { } } -module.exports = DashboardService \ No newline at end of file +module.exports = DashboardService diff --git a/server/src/utils/projectsUser.json b/server/src/utils/projectsUser.json index 5ff5663..6ee7b8c 100644 --- a/server/src/utils/projectsUser.json +++ b/server/src/utils/projectsUser.json @@ -1,6 +1,10 @@ { "data": [ + { + "ProjectId": 5, + "UserId": 1 + }, { "ProjectId": 1, "UserId": 5 @@ -66,4 +70,4 @@ "UserId": 5 } ] - } \ No newline at end of file + } diff --git a/server/src/utils/users.json b/server/src/utils/users.json index 4ada1e3..eddf5f6 100644 --- a/server/src/utils/users.json +++ b/server/src/utils/users.json @@ -17,7 +17,7 @@ }, { "name": "Alexis", - "email": "Alexis@projunity.com", + "email": "draco_alexis@hotmail.com", "password": "projunity", "image": "https://www.spotteron.net/images/icons/user60.png", "githubUser": "dracoalex84",