No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Órdenes de compra

20/27
Recursos

Aportes 24

Preguntas 7

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Les dejo el código de order.model, orders.router, order.schema y order.service:
.
order.model
.

const ORDER_TABLE = 'orders';

const OrderSchema = {
	id: {
		allowNull: false,
		autoIncrement: true,
		primaryKey: true,
		type: DataTypes.INTEGER,
	},
	customerId: {
		field: 'customer_id',
		allowNull: false,
		type: DataTypes.INTEGER,
		References: {
			model: CUSTOMER_TABLE,
			key: 'id',
		},
		onUpdate: 'CASCADE',
		onDelete: 'SET NULL',
	},
	createdAt: {
		allowNull: false,
		type: DataTypes.DATE,
		field: 'created_at',
		defaultValue: Sequelize.NOW,
	},
};

class Order extends Model {
	static associate(models) {
		this.belongsTo(models.Customer, {
			as: 'customer',
		});
	}

	static config(sequelize) {
		return {
			sequelize,
			tableName: ORDER_TABLE,
			modelName: 'Order',
			timestamps: false,
		};
	}
}

module.exports = { Order, OrderSchema, ORDER_TABLE };

.
orders.router
.

const express = require('express');

const OrderService = require('../services/order.service');
const validatorHandler = require('../middlewares/validator.handler');
const {
	getOrderSchema,
	createOrderSchema,
} = require('../schemas/order.schema');

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

router.get(
	'/:id',
	validatorHandler(getOrderSchema, 'params'),
	async (req, res, next) => {
		try {
			const { id } = req.params;
			const order = await service.findOne(id);
			res.json(order);
		} catch (error) {
			next(error);
		}
	}
);

router.post(
	'/',
	validatorHandler(createOrderSchema, 'body'),
	async (req, res, next) => {
		try {
			const body = req.body;
			const newOrder = await service.create(body);
			res.status(201).json({ newOrder });
		} catch (error) {
			next(error);
		}
	}
);

module.exports = router;

.
order.service
.

const boom = require('@hapi/boom');

const { models } = require('./../libs/sequelize');

class OrderService {
	constructor() {
	}

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

	async find() {
		return [];
	}

	async findOne(id) {
		const order = await models.Order.findByPk(id, {
			include: [
				{
					association: 'customer',
					include: ['user'],
				},
			],
		});
		return order;
	}

	async update(id, changes) {
		return {
			id,
			changes,
		};
	}

	async delete(id) {
		return { id };
	}
}

module.exports = OrderService;

.
order.schema
.

const Joi = require('joi');

const id = Joi.number().integer()
const customerId = Joi.number().integer();


const getOrderSchema = Joi.object({
	id: id.required(),
})

const createOrderSchema = Joi.object({
	customerId: customerId.required(),
});

module.exports = {
	getOrderSchema,
	createOrderSchema
}

Otra forma de sintaxis que permite hacer lo mismo, pero que habilita opciones para hacer un poco mas complejas las consultas.

Con esta forma de sintaxis podemos agregar elementos como: attributes para seleccionar los campos que deseamos del objeto y no todos, where para filtrar el contenido, order para ordenar, entre otros que pueden ver en la documentación.

Una nota importante es que el alías debe llamarse igual que el atributo que obtendrá el objeto definido en el esquema del modelo.

const data = await models.Profile.findByPk(id, {
  include: [
    { 
      model: models.User, 
      as: 'user',
      attributes: ['id', 'email']
    },
    { 
      model: models.ProfileCourse, 
      as: 'profiles_courses', 
      attributes: ['id'],
      include: [
        { 
          model: models.Course, 
          as: 'course', 
          attributes: ['name'],
          where: { name: 'Frontend JavaScript' }
        }
      ]
    }
  ]
});

Hecho!

Un producto puede pertenecer a muchas ordenes de compra, y una orden de compra puede tener muchos productos.

Cuando se tiene una relación muchos a muchos, por detrás se tiene una tabla ternaria. En BD se usa una join table, una clase intermedia que conecta dos tablas con relación muchos a muchos.

Para este caso se va requerir la tabla orders (ordenes de compra), esta estará ligada a un cliente. La join table serian los items que estarán ligados a una orden y producto.

La tabla order tiene que ser una relación uno a muchos ya que un cliente puede tener muchas ordenes y una orden un cliente.

Para tener un anidamiento “más profundo”, se debe especificar de la siguiente manera en el servicio order.service.js (order → customer → user):

async findOne(id) {
    const order = await models.Order.findByPk(id, {
      include: [
        {
          association: 'customer',
          include: ['user'],
        },
      ],
    });
    return order;
  }

Con esto hecho, el resultado del request mostrará los datos del cliente y del usuario. Es decir, estamos diciendo que customer traiga su propia asociación la cual es user.

Creo que estaría muy bueno si nos presentaran un modelado de datos físico. Hice uno para poder visualizar lo que estamos haciendo. Aún no está terminado pero se los comparto. Lo hice con Lucidchart. ![](https://static.platzi.com/media/user_upload/Captura%20de%20pantalla%202023-09-25%20a%20la%28s%29%2015.23.58-374a5e60-0103-4856-998c-1dedf8776235.jpg)

crazy ese findone 🖖

Eso de que devuelva la info relacionada esta hermoso!

Si alguien quiere excluir algunos atributos , puede haccerlo con el siguiente cosigo en el servicio

async find() {
  try {
    const data = await models.Reserva.findAll({
      include: [{
        model: models.Usuario, // Nombre del modelo Usuario
        as: 'reservas_usuario', // Alias de la relación en el modelo Reserva
        attributes: {
          exclude: ['createdAt', 'contraseniaUsuario']
        },
      }],
      attributes: {
        exclude: ['createdAt'], // Excluir createdAt del modelo Reserva
      },
    });
    return data;
  } catch (error) {
    throw boom.badImplementation('Error al encontrar las reservas', error);
  }
}

Reto de agregar un status a las ordenes
Para este reto creo que pueden haber distintas soluciones pero siempre habra la mejor en cuanto a rendimiento por lo que si sientes que tienes una buena solución para este reto o sabes que mi código puede ser optimizado sientete libre de comentar y aconsejar para aprender todos 😃.
.
.
Modelo de orders
Lo primero que hay que hacer es agregar el status al modelo de orders, a continuación dejo el código.
En este caso el valor lo defini como un integer debidoa que quiero que sean números y dependiendo el número representar un status u otro, más adelante mostrare eso más detalladamente.

const OrderSchema = {
  id: {
    allowNull: false,
    primaryKey: true,
    autoIncrement: true,
    type: DataTypes.INTEGER
  },
  status: {
    allowNull: false,
    type: DataTypes.INTEGER,
    defaultValue: 0
  },
  customerId: {
    field: 'customer_id',
    allowNull: false,
    type: DataTypes.INTEGER,
    references: {
      model: CUSTOMER_TABLE,
      key: 'id'
    },
    onUpdate: 'CASCADE',
    onDelete: 'SET NULL'
  },
  createdAt: {
    field: 'created_at',
    allowNull: false,
    type: DataTypes.DATE,
    defaultValue: Sequelize.NOW
  }
}

class Order extends Model {
  static associate(models) {
    this.belongsTo(models.Customer, {
        as: 'customer'
      })
  }

  static config(sequelize) {
    return {
      sequelize,
      tableName: ORDER_TABLE,
      modelName: 'Order',
      timestamps: false
    }
  }
}

Generar migración para la nueva columna del modelo

'use strict';

const { ORDER_TABLE, OrderSchema } = require('../models/order.model')

module.exports = {
  async up (queryInterface) {
    await queryInterface.addColumn(ORDER_TABLE, 'status', OrderSchema.status)
  },

  async down (queryInterface) {
    await queryInterface.removeColumn(ORDER_TABLE, 'status')
  }
};

Agregar el status al schema para validarlo
.
Algo que considero muy importante es no olvidar agregar el status a nuestro validador de datos con el schema de joi.

const joi = require('joi');

const id = joi.number().integer();
const customerId = joi.number().integer();
const status = joi.number().integer();

const getOrderSchema = joi.object({
  id: id.required()
})

const createOrderSchema = joi.object({
  customerId: customerId.required(),
  status
})

const updateOrderSchema = joi.object({
  id: id.required(),
  customerId,
  status
})

module.exports = {
  getOrderSchema,
  createOrderSchema,
  updateOrderSchema
}

Obtener el status
Obtener el status es una tarea muy simple y sencilla, lo que debemos hacer es tomar una calculadora y sacar la distancia de la luna al sol y del sol a la tierra con ello podrémos establecer la formula para nuestros estatus…
No, solo era broma jajaja… Ahora simplemente vamos al servicio de las ordenes y con un switch seleccionamos que status tendrá cada orden, todo esto dentro del metodo find y findOne. En mi caso solo lo hice en el find.

  async find() {
    const orders = await models.Order.findAll({
      include: [
        {
          association: 'customer',
          include: ['user']
        }
      ]
    })

    orders.forEach(order => {
      switch(order.status) {
        case 0:
          order.status = 'Preparando el producto'
          break;

        case 1:
          order.status = 'Producto en camino'
          break;

        case 2:
          order.status = 'Producto entegado :)'
          break;
      }
    })

    return orders
  }

Este curso es genial 😄!.
Lo de retornar la información relacionada es muy útil. Hubiera querido saberlo antes, en lugar de hacer milagros para obtener lo mismo 😂.

Hasta ahora ¿quien no se ha equivocado y no ha tenido que parchear la database? jaja

EndPoint que devuelve asociaciones anidadas. entity.findByPk(id, { include: [ association: 'entity1.2', include:'entity1.3'']}

Revisen varias veces antes de hacer la migracion si hicieron copy&paste porque puede darles problemas como a mi a

Un error me hizo revertir la migracion de tabla orders, configure mal en el index de models una linea por copiar y pegar

Order.init(OrderSchema, Product.config(sequelize));

ese error no me dejaba hacer el post a la tabla ordenes ya que quedó mal configurada

Se me rompio todo :'(
Media hora buscando un error. Y es que escribí `references` en lugar de `References` 🤡
Me parece que para algunos estudiantes puede ser algo avanzado entender estos conceptos de bases de datos con solo el código. Se podría dar al inicio del curso un modelo con todas las entidades y las relaciones que se van a trabajar. Esto ayudaría un montón.
Para este endpoint quería dar de manera opcional si se anidaban los datos del usuario en la orden, por lo tanto usando `req.query` se le puede indicar a la API si debe dar los datos adicionales o no, así me quedó el código: `routes/order.js` ```js router.get("/:id",    validationMiddleware(getOrderSchema, "params"),    validationMiddleware(getOrderQuerySchema, "query"),    async (*req*, *res*, *next*) => {        try {            const { id } = *req*.params;            const { userInfo } = *req*.query;            const resultOrder = await service.findOrderById(id, userInfo);            *res*.status(201).json(resultOrder);        } catch (error) {            next(error);        }    } ``` `services/orders.js` ```js ... let findOptions = { include: \['customer'] };        if (*userInfo*) {            findOptions = {                include: \[{                    association: 'customer',                    include: \['user']                }]            };        }         const resultOrder = await models.Order.findByPk(*id*, findOptions); ... ```
Una de las cosas que noté de los Schemas que estamos creando en el curso, es que para las foreign keys le estamos indicando a la DB que si la fila que se está referenciando es eliminada, ponga un NULL en la referencia, pero esto no lo puede hacer porque estamos usando el constraint NOT NULL. Por esto mismo en vez de poner un CASCADE opté por usar un SET DEFAULT y asignar el 0 como valor por defecto, de esa manera no se borran registros que podríamos llegar a necesitar pero borramos la relación con el usuario.
Super poderoso.

Comparto código de findOne

async findOne(id){
    const order = await models.Order.findByPk(id,{
      include: [
        {
          association: 'customer',
          include: ['user']
        }
      ]
    });

    if (!order) {
      throw boom.notFound('product not found');
    }
    return order;
  }

Sarpado!
No puedo creer lo que estamos desarrollando, al empezar nunca pense que podria crear algo como esto tan llevaderamente (no creo que sea facil, pero se “siente” facil al seguir las clases)
Gracias Platzi!

Les comparto el model y schema con el campo status

const ORDER_TABLE = 'orders';

const OrderSchema = {
  id: {
    allowNull: false,
    autoIncrement: true,
    primaryKey: true,
    type: DataTypes.INTEGER
  },
  customerId: {
    field: 'customer_id',
    allowNull: true,
    type: DataTypes.INTEGER,
    references: {
      model: CUSTOMER_TABLE,
      key: 'id'
    },
    onUpdate: 'CASCADE',
    onDelete: 'SET NULL'
  },
  status: {
    allowNull: false,
    type: DataTypes.STRING,
    defaultValue: 'paid',
    validate: {
      isIn: [['paid', 'shipped', 'delivered']]
    }
  },
  createdAt: {
    allowNull: false,
    type: DataTypes.DATE,
    field: 'created_at',
    defaultValue: Sequelize.NOW
  }
}

class Order extends Model {
  static associate(models){
    this.belongsTo(models.Customer, {
      as: 'customer',
    })
  }
  static config(sequelize){
    return{
      sequelize,
      tableName: ORDER_TABLE,
      modelName: 'Order',
      timestamps: false,
    }
  }
}

module.exports = { Order, OrderSchema, ORDER_TABLE };
const Joi = require('joi');

const id = Joi.number().integer();
const customerId = Joi.number().integer();
const status = Joi.string().valid('paid', 'shipped', 'delivered')

const getOrderSchema = Joi.object({
  id: id.required(),
});

const createOrderSchema = Joi.object({
  customerId: customerId.required(),
  status: status.required()
});

const updateOrderSchema = Joi.object({
  customerId,
  status
});

module.exports = { getOrderSchema, createOrderSchema, updateOrderSchema };

De momento solo se realizó la relación ordenes de compra, clientes y usuarios.