No tienes acceso a esta clase

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

Órdenes de compra

20/27
Recursos

Aportes 13

Preguntas 6

Ordenar por:

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

o inicia sesión.

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
}

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.

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' }
        }
      ]
    }
  ]
});

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

crazy ese findone 🖖

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

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'']}

Eso de que devuelva la info relacionada esta hermoso!

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 };

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
  }

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