En este ejercicio vamos a trabajar con los productos de un almacén, para lo que crearemos las clases Category, Product y Store.
La guardaremos en el fichero category.class.js. Tendrá las siguientes propiedades:
- id (number)
- name
- description: opcional. Si no se pasa su descripción será 'No hay descripción'
Esta clase no tiene ningún método.
La guardaremos en el fichero product.class.js. Tendrá las siguientes propiedades:
- id (number)
- name
- category: el nº de su categoría
- price
- units: argumento opcional (si no le pasamos este parámetro al constructor su número por defecto será 0)
Esta clase tendrá los siguientes métodos:
productImport(): Number
- devuelve el importe total del producto (su precio multiplicado por el nº de unidades)
xxxx(): String
- (¿qué nombre le deberías dar a este método?): si se intenta imprimir el producto se mostrará su descripción, sus unidades entre paréntesis, su precio y el importe total (los € siempre con 2 decimales) como en el siguiente ejemplo:
TV Samsung MP45: 10 uds. x 235,95 €/u = 2359,50 €
Es el almacén de productos (podríamos tener más de uno) que guardaremos en store.class.js. Tendrá las propiedades:
- id: código numérico que nos pasan al crear el almacén
- name: nombre del almacén (texto)
- products: array de productos. No se le pasa al constructor sino que al crear un almacén se inicializa a un array vacío
- categories: array de categorías. No se le pasa, se inicializa vacío
La clase tendrá los métodos:
getCategoryById(id: Integer): Category
- recibe una id y devuelve su categoría. Si no existe lanzará una excepción
getCategoryByName(name: String): Category
- recibe un nombre y devuelve su categoría. Si no existe lanzará una excepción. No tendrá en cuenta la capitalización
getProductById(id: Integer): Product
- recibe como parámetro una id de producto y devuelve el producto del almacén que tiene dicha id (si no existe lanzará una excepción)
getProductsByCategory(id: Integer): Product[]
- recibe como parámetro una id de categoría y devuelve un array con los productos del almacén que tienen dicha categoría
addCategory(nombre: String [, descripcion: String]): Category
- recibe el nombre de la categoría y, opcionalmente, una descripción y devuelve el objeto Category creado. Crea un objeto de clase Category y lo añade al almacén (a categories). Como a la clase Category hay que pasarle una id haremos una función que la calcule buscando la máxima id de las categorías que hay en el almacén (debéis usar un reduce) y sumándole 1. Este método genera un error si
- no se le pasa un nombre
- ya existe una categoría con ese nombre
addProduct(payload: Object): Product
- addProduct: recibe como único parámetro un objeto con los datos del producto a añadir (propiedades name, category, price y, opcionalmente, units) y devuelve el objeto Product creado. Este método crea un nuevo producto (llamará al constructor de la clase Product) y lo añade al almacén. Como a la clase Product hay que pasarle una id haremos una función que la calcule buscando la máxima id de los productos que hay en el almacén (debéis usar un reduce) y sumándole 1. Este método genera un error si
- no se le pasa name
- no se le pasa category o no existe esa categoría
- no se le pasa price o no es un número positivo
- se le pasa units pero no es un número entero positivo
delCategory(id: Integer): Category
- recibe como parámetro la id de una categoría y, si no tiene productos, la elimina del almacén y devuelve la categoría eliminada. Genera un error si no existe la categoría o si tiene productos
delProduct(id: Integer): Product
- recibe como parámetro la id de un producto y, si no tiene unidades, lo elimina del almacén y devuelve el producto eliminado. Genera un error si no existe el producto o si sus unidades no están a 0
totalImport(): Number
- devuelve el valor total de los productos del almacén (su precio por sus uds). Para ello usa el método productImport de cada producto
orderByUnits(): Product[]
- devuelve el array de productos ordenado por unidades de forma descendente
orderByName(): Product[]
- devuelve el array de productos ordenado por el nombre del producto
underStock(units: Integer): Product[]
- recibe un nº de unidades y devuelve un array con los productos que tengan menos de dichas unidades
xxxx(): String
- (¿qué nombre le deberías dar a este método?): si se intenta imprimir el almacén devuelve una cadena con la id del almacén, el nº de productos y su importe total con 2 decimales, y debajo una lista con los datos de cada producto como en el siguiente ejemplo:
Almacén 1 => 2 productos: 2174,75 €
- TV Samsung MP45: 10 uds. x 235,95 €/u = 2359,50 €
- USB Kingston 16 GB: 100 uds. x 19,95 €/u = 1995,00 €
Recuerda que siempre que llames a una función que pueda generar un error debes hacer dicha llamada dentro de una sentencia try...catch
. Lo que hace index.js si captura un error es mostrarlo por consola con el comando console.error
.
Lo correcto es no tener todo el código en un único fichero javascript sino cada cosa en su fichero correspondiente. Así que dentro de la carpeta src/ crearemos los ficheros:
- product.class.js: la clase Product con sus propiedades y métodos
- store.class.js: la clase Store con sus propiedades y métodos
- index.js: el programa principal que crea el almacén, lo modifica (añade, elimina y modifica productos) y muestra por consola su contenido
En el index.html habría que enlazar los 3 ficheros en el orden correcto (productos, almacén y index para que desde index.js se pueda llamar a métodos de Store y desde store.js a métodos de Product). Como esto ya empieza a ser incómodo vamos a hacer uso de webpack para que empaquete todos nuestros ficheros javascript en un único fichero que se llamará ./dist/main.js y que será el único que enlazaremos en el index.html. Consulta cómo usar webpack para hacerlo.
Lo que habría que hacer (NO lo hagas porque ya tienes credo el package.json) es:
npm init
: inicializamos nuestro proyecto lo que creará el fichero package.json. Recuerda escribir jest cuando nos pregunte por los testsnpm i -D webpack webpack-cli
: instalamos webpack como dependencia de desarrollo (en la versión de producción no estará)
En este ejercicio ya tienes el package.json creado y configurado por lo que ya tienes lo anterior hecho.
Lo siguiente es hacer que se instalen las dependencias (npm install
). Una vez hecho:
- para pasar los test ejecuta
npm run test
- cuando quieras probarlo en el navegador ejecuta
npx webpack --mode=development
: esto crea el fichero dist/main.js (que es el que está enlazado en el index.html). En él webpack empaqueta el código de todos nuestros ficheros javascript. Deberás ejecutarlo cada vez que hagas cambios en tu código y quieras probarlos en el navegador.
Fijaos en el código que os paso. Para que la clase Store pueda usar los métodos de Product debemos hacer:
- añadir al final de product.class.js el código
module.exports = Product
. Esto hace accesible la clase a cualquier fichero que importe product.class.js. Es lo mismo que hacíamos en los ficheros functions.js de los ejercicios anteriores para que los tests pudieran acceder a sus funciones - añadir al principio de store.class.js el código
const Product = require('./product.class')
. Crea una variable Product que es la clase exportada en el otro fichero
Lo mismo tendréis que hacer para que_store.js_ pueda usar la clase Category y para que index.js pueda llamar a métodos de Store (exportar la clase en store.class e importar ese fichero en index).
En la carpeta test ya tienes hechos varios test que puedes pasar para comprobar tu código. Recuerda que simplemente debes hacer:
npm run test
Para probar que funciona en el navegador tienes en el fichero index.js el código necesario para:
- crear un almacén
- añadir una categoría y los siguientes 4 productos:
- 'TV Samsung MP45', 345.95 €, 3 uds.
- 'Ábaco de madera', 245.95 €
- 'impresora Epson LX-455', 45.95 €
- 'USB Kingston 16GB', 5.95 €, 45 uds.
- eliminar el USB
- mostrar por consola el almacén ordenado por existencias
- mostrar por consola los productos del almacén con menos de 10 unidades
Al abrir la página en el navegador la consola deberá mostrar lo siguiente:
LISTADO DEL ALMACÉN por existencias
- Ábaco de madera: 45 uds. x 245.95 €/u = 11067.75 €
- TV Samsung MP45: 3 uds. x 345.95 €/u = 1037.85 €
- impresora Epson LX-455: 0 uds. x 45.95 €/u = 0.00 €
LISTADO DEL ALMACÉN por nombre
- Ábaco de madera: 45 uds. x 245.95 €/u = 11067.75 €
- impresora Epson LX-455: 0 uds. x 45.95 €/u = 0.00 €
- TV Samsung MP45: 3 uds. x 345.95 €/u = 1037.85 €
LISTADO DE PRODUCTOS CON POCAS EXISTENCIAS
- impresora Epson LX-455: 0 uds. x 45.95 €/u = 0.00 €
- TV Samsung MP45: 3 uds. x 345.95 €/u = 1037.85 €
NOTA: cuando acabes tu práctica mira el código que genera webpack (dist/main.js). Ahora vuelve a generarlo pero esta vez para producción (--mode=production
) y fíjate de nuevo en el código del fichero.