A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Obteniendo 贸rdenes del perfil

13/20
Recursos

Aportes 7

Preguntas 1

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Reto
En order.router.js
En el body se enviar铆a el sub del payload como body.

// POST
router.post('/',
  passport.authenticate('jwt', { session: false }),
  async (req, res, next) => {
    try {
      const body = {
        userId: req.user.sub
      }
      const newOrder = await service.create(body);
      res.status(201).json(newOrder);
    } catch (err) {
      next(err);
    }
  }
);

Luego en order.service.js Modificamos el create() para que la inserci贸n sea automatizada con solo enviar el sub o userId, hacemos una busqueda findOne al customer Where user .id sea igual a data.userId. Donde este se almacenar谩 en customer el cual tendremos que extraer el ID para enviarlo al create de order. Si no se encuentra se regresa un no encontrado.

async create(data) {
    const customer = await models.Customer.findOne({
      where: {
        '$user.id$': data.userId
      },
      include: ['user']
    })
    if (!customer) {
      throw boom.badRequest('Customer not found');
    }
    const newOrder = await models.Order.create({ customerId: customer.id });
    return newOrder;
  }

Para resolver el reto de crear la order sin neesidad de enviar el customerId en el body de la petici贸n hariamos lo siguente:

En order.router.js

router.post(
  '/',
  passport.authenticate('jwt', { session: false }),
  //validatorHandler(createOrderSchema, 'body'),
  async (req, res, next) => {
    try {
      const body = {
        userId: req.user.sub
      };
      const order = await service.create(body);
      res.status(201).json(order);
    } catch (error) {
      next(error);
    }
  }
);

Hay que eliminar el validator porque ahora no es necesario pasar en el body el customer id, pero se agrega el jwt validator

Luego en order.service.js

  async create(data) {
    // Accedemos al modelo Customer y usando where encadenamos hacia user
    const customer = await models.Customer.findAll({
      where: {
        '$user.id$': data.userId
      },
      include: ['user']
    });
    // Validamos que exista el customer
    if (!customer) {
      throw boom.notFound('Customer not found');
    }
    // Creamos un objeto con el customerId obtenido de la consulta
    const dataOrder = {
      customerId: customer[0].id
    };
    const newOrder = await models.Order.create(dataOrder);
    return newOrder;
  }

TRas un poco de depuraci贸n con este metodo vi que los resultados de la consulta llegan en un Array, si se canbia el FinAll por findOne en ese caso solo retorna un unico objeto y no haria falta usar el customer[0] sino directamente customer

Hola a todos.
Estaba recibiendo este error:

Y esto se remonta al curso pasado de 鈥淣ode con Postgres鈥 donde yo continue con mi progreso.
Si realizaba hacer un post de una orden o consultar todas las ordenes, me salia el mismo error.
Esto se corrige poniendo una condicional en el modelo de ordenes en el campo virtual total. Ponemos una condicional que diga si exista 鈥渋tems鈥 entonces que proceda con su respectiva validacion de 鈥渢his.items.length鈥

total: {
    type: DataTypes.VIRTUAL,
    get() {
      //Reviso si tenemos productos
      if(this.items) {
        console.log('existen items en la orden')
        if(this.items.length > 0) {
          return this.items.reduce((total, item) => {
            return total + (item.price * item.OrderProduct.amount)
          }, 0)
        }
        return 0
      }
    }
  }

Para poder ver las 贸rdenes de compra de un usuario podemos usar el token que tiene, obtener el sub y obtener la informaci贸n directamente sin necesidad de enviar el ID del usuario.

Se crea un nuevo m茅todo en el servicio orders, el m茅todo findByUser recibe el userId y realiza una consulta respecto a 茅ste donde se incluye la asociaci贸n de user y customer, y se desea obtener el id del customer ya que 煤nicamente se cuenta con el id de usuario, es por ello que se utiliza where: {'$customer.user.id$': userId}, es decir, le estamos diciendo a qu茅 asociaciones estamos haciendo la consulta.

M谩s informaci贸n sobre este tipo de consultas https://sequelize.org/master/manual/eager-loading.html#complex-where-clauses-at-the-top-level

async findByUser(userId) {
    const orders = await models.Order.findAll({
      where: {
        '$customer.user.id$': userId,
      },
      include: [
        {
          association: 'customer',
          include: ['user'],
        },
      ],
    });
    return orders;
  }

Se crea un nuevo router profile.router.js, aqu铆 se obtiene el id del usuario que est谩 en este momento con sesi贸n (const orders = await service.findByUser(user.sub)), el id est谩 en el sub del payload. Es decir, ya no es necesario enviar el user id porque ya viene en el token y se va a obtener de ah铆.

const express = require('express');
const passport = require('passport');

const OrderService = require('../../services/order.service');

const router = express.Router();
const service = new OrderService();

router.get(
  '/my-orders',
  passport.authenticate('jwt', { session: false }),
  async (req, res, next) => {
    try {
      const user = req.user;
      const orders = await service.findByUser(user.sub);
      res.json(orders);
    } catch (error) {
      next(error);
    }
  }
);

module.exports = router;

Agregamos la nueva ruta a routes/index.js:

const express = require('express');

const productsRouter = require('./api/products.route');
const usersRouter = require('./api/users.router');
const categoriesRouter = require('./api/categories.route');
const orderRouter = require('./api/orders.router');
const customerRouter = require('./api/customer.route');
const authRouter = require('./api/auth.route');
const profileRouter = require('./api/profile.router');

function routerApi(app) {
  const router = express.Router();
  app.use('/api', router);
  router.use('/products', productsRouter);
  router.use('/users', usersRouter);
  router.use('/categories', categoriesRouter);
  router.use('/orders', orderRouter);
  router.use('/customers', customerRouter);
  router.use('/auth', authRouter);
  router.use('/profile', profileRouter);
}

module.exports = routerApi;

En mi caso enlace directamente la orden al usuario, pero yo creo que seg煤n la idea de negocio no deber铆a permitir crear ordenes si ya tiene una activa, en mi modelo puse un campo int para validar 0 creada, 1 cancelada, 3 pagada, por lo que en el servicio primero consulto si cuenta con una orden creada para permitir crear mas ordenes鈥!

  // Crea una Order y la retorna
  async create(user) {
    const body = {userId: user};
    if (await this.getOrderUserActive(user) !== 0) {
      throw boom.conflict('This user have a order pending..!')
    }
    console.log(body)
    const newOrder = await models.Order.create(body)
    return await this.getOne(newOrder.id);
  }

  // Verifica que el usuario no tenga ordenes activas
  async getOrderUserActive(user){
    const order = await models.Order.findAndCountAll({
      where: {
        user_id: user,
        state: 0
      }
    })
    return order.count
  }

Al momento de tomar el usuario del sub del JWT hay que recordar en el schema colocar que el user id es opcional o simplemente no usar el validador鈥!

RETO

order.router.js

router.post(
  '/',
  passport.authenticate('jwt', { session: false }),
  async (req, res, next) => {
    try {
      const body = { userId: req.user.sub };
      const newOrder = await service.create(body);
      res.status(201).json(newOrder);
    } catch (error) {
      next(error);
    }
  }
);

order.services.js

async create(data) {
    const customer = await models.Customer.findOne({
      where: {
        '$user.id$': data.userId,
      },
      include: ['user'],
    });

    data.customerId = customer.id;
    delete data.userId;

    const newOrder = await models.Order.create(data);
    return newOrder;
  }

Para el reto, creamos una nueva ruta, post:

router.post("/my-orders",
    passport.authenticate('jwt', { session: false }),
    async(req, res, next) => {
        const data = { id: req.user.sub }

        try {
            res.status(201).json(await service.createFromProfile(data));
        } catch (error) {
            next(error);
        }
    }
);

Para que esto funcione, necesitamos que el servicio tenga una nueva funci贸n:

   async createFromProfile(data) {
        const user = await service.findOne(data.id);
        const customerId = user.customer.id;
        return models.Order.create({ customerId });
    }


Y listo, con eso debe estar funcionando (: