From 077ddffe122349860358cda8d008ee10f08c1dc5 Mon Sep 17 00:00:00 2001 From: vincenzo Date: Fri, 28 Apr 2023 20:02:37 -0300 Subject: [PATCH] feat: implement remove role - when delete one product should delete also data ProductWarehouse and Warehouse register --- .gitignore | 2 ++ .prettierrc | 2 +- .../product/createProductOperation.js | 29 +++++++++------ .../product/removeProductOperation.js | 36 +++++++++++++++++++ src/app/usecases/createProductUsecase.js | 10 ++++-- src/app/usecases/findProductBySkuUsecase.js | 6 ++++ .../findProductWarehouseByProductIdUsecase.js | 6 ++++ src/app/usecases/removeProductByIdUsecase.js | 6 ++++ src/app/usecases/removeProductBySkuUsecase.js | 6 ++++ .../removeProductWareseByProductIdUsecase.js | 6 ++++ .../usecases/removeWarehouseByIdUsecase.js | 6 ++++ src/infra/errors/BadRequestError.js | 7 ++++ src/infra/errors/Exceptions.js | 18 +++++++++- src/infra/errors/NotFoundError.js | 7 ++++ src/infra/repositories/Repository.js | 21 ++++++++--- .../repositories/product/ProductRepository.js | 15 ++++++++ .../ProductWarehouseMapper.js | 1 - .../ProductWarehouseRepository.js | 14 ++++++-- .../warehouse/WarehouseRepository.js | 5 +++ .../http/controllers/productController.js | 17 ++++++--- 20 files changed, 192 insertions(+), 28 deletions(-) create mode 100644 src/app/operations/product/removeProductOperation.js create mode 100644 src/app/usecases/findProductBySkuUsecase.js create mode 100644 src/app/usecases/findProductWarehouseByProductIdUsecase.js create mode 100644 src/app/usecases/removeProductByIdUsecase.js create mode 100644 src/app/usecases/removeProductBySkuUsecase.js create mode 100644 src/app/usecases/removeProductWareseByProductIdUsecase.js create mode 100644 src/app/usecases/removeWarehouseByIdUsecase.js create mode 100644 src/infra/errors/BadRequestError.js create mode 100644 src/infra/errors/NotFoundError.js diff --git a/.gitignore b/.gitignore index 6214c438..1bfbc0a5 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,5 @@ typings/ # DynamoDB Local files .dynamodb/ + +.vscode/ diff --git a/.prettierrc b/.prettierrc index e54965b1..4bd296ec 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "printWidth": 160, + "printWidth": 140, "singleQuote": true, "trailingComma": "none", "bracketSpacing": true, diff --git a/src/app/operations/product/createProductOperation.js b/src/app/operations/product/createProductOperation.js index cfb81f47..68400cdc 100644 --- a/src/app/operations/product/createProductOperation.js +++ b/src/app/operations/product/createProductOperation.js @@ -1,15 +1,22 @@ -module.exports = ({ createProductUsecase, createWarehouseUsecase, bindingProductWarehouse }) => ({ +module.exports = ({ createProductUsecase, createWarehouseUsecase, bindingProductWarehouse, removeProductByIdUsecase }) => ({ execute: async (data) => { - const { warehouse } = data; - const product = await createProductUsecase.execute(data); - if (!product) { - return; + let productId; + try { + const { warehouse } = data; + const product = await createProductUsecase.execute(data); + if (!product) { + return; + } + productId = product.id; + + if (warehouse) { + const warehouseCretead = await Promise.all(warehouse.map((element) => createWarehouseUsecase.execute(element))); + await bindingProductWarehouse.execute(productId, warehouseCretead); + } + return product; + } catch (error) { + await removeProductByIdUsecase.execute(productId); + return error; } - if (warehouse) { - const warehouseCretead = await Promise.all(warehouse.map((element) => createWarehouseUsecase.execute(element))); - // TODO: validate warehouseCreated - await bindingProductWarehouse.execute(product.id, warehouseCretead); - } - return product; } }); diff --git a/src/app/operations/product/removeProductOperation.js b/src/app/operations/product/removeProductOperation.js new file mode 100644 index 00000000..6ffde8b3 --- /dev/null +++ b/src/app/operations/product/removeProductOperation.js @@ -0,0 +1,36 @@ +module.exports = ({ + removeProductBySkuUsecase, + findProductBySkuUsecase, + removeWarehouseByIdUsecase, + findProductWarehouseByProductIdUsecase, + removeProductWareseByProductIdUsecase, + exceptions +}) => ({ + execute: async (data) => { + const product = await findProductBySkuUsecase.execute(data); + if (!product) { + throw exceptions.notFoundError('[findProductBySkuUsecase] product is not found'); + } + const { id, sku } = product; + const productWarehouse = await findProductWarehouseByProductIdUsecase.execute(id); + if (!productWarehouse || productWarehouse.length === 0) { + throw exceptions.notFoundError('[findProductWarehouseByProductIdUsecase] bind product and warehouse not found'); + } + const productWarehouseIsRemoved = await removeProductWareseByProductIdUsecase.execute(id); + if (!productWarehouseIsRemoved) { + throw exceptions.internalError('[removeProductWareseByProductIdUsecase]'); + } + + const productIsRemoved = await removeProductBySkuUsecase.execute(sku); + if (!productIsRemoved) { + throw exceptions.internalError('[removeProductBySkuUsecase]'); + } + + const warehouseIsRemoved = await Promise.all(productWarehouse.map((item) => removeWarehouseByIdUsecase.execute(item.warehouseId))); + if (!warehouseIsRemoved) { + throw exceptions.internalError('[removeWarehouseByIdUsecase]'); + } + + return productIsRemoved; + } +}); diff --git a/src/app/usecases/createProductUsecase.js b/src/app/usecases/createProductUsecase.js index 8cae9b3f..ca303980 100644 --- a/src/app/usecases/createProductUsecase.js +++ b/src/app/usecases/createProductUsecase.js @@ -1,6 +1,10 @@ -module.exports = ({ productRepository }) => ({ +module.exports = ({ productRepository, exceptions }) => ({ execute: async (data) => { - const response = await productRepository.create(data); - return response; + try { + const response = await productRepository.create(data); + return response; + } catch (error) { + throw exceptions.internalError(JSON.stringify(error.errors)); + } } }); diff --git a/src/app/usecases/findProductBySkuUsecase.js b/src/app/usecases/findProductBySkuUsecase.js new file mode 100644 index 00000000..c0110ccf --- /dev/null +++ b/src/app/usecases/findProductBySkuUsecase.js @@ -0,0 +1,6 @@ +module.exports = ({ productRepository }) => ({ + execute: async (data) => { + const response = await productRepository.findBySku(data); + return response; + } +}); diff --git a/src/app/usecases/findProductWarehouseByProductIdUsecase.js b/src/app/usecases/findProductWarehouseByProductIdUsecase.js new file mode 100644 index 00000000..2cedd20d --- /dev/null +++ b/src/app/usecases/findProductWarehouseByProductIdUsecase.js @@ -0,0 +1,6 @@ +module.exports = ({ productWarehouseRepository }) => ({ + execute: async (data) => { + const response = await productWarehouseRepository.findAllByProductId(data); + return response; + } +}); diff --git a/src/app/usecases/removeProductByIdUsecase.js b/src/app/usecases/removeProductByIdUsecase.js new file mode 100644 index 00000000..c05b713b --- /dev/null +++ b/src/app/usecases/removeProductByIdUsecase.js @@ -0,0 +1,6 @@ +module.exports = ({ productRepository }) => ({ + execute: async (data) => { + const response = await productRepository.removeById(data); + return response; + } +}); diff --git a/src/app/usecases/removeProductBySkuUsecase.js b/src/app/usecases/removeProductBySkuUsecase.js new file mode 100644 index 00000000..3e538735 --- /dev/null +++ b/src/app/usecases/removeProductBySkuUsecase.js @@ -0,0 +1,6 @@ +module.exports = ({ productRepository }) => ({ + execute: async (data) => { + const response = await productRepository.removeBySku(data); + return response; + } +}); diff --git a/src/app/usecases/removeProductWareseByProductIdUsecase.js b/src/app/usecases/removeProductWareseByProductIdUsecase.js new file mode 100644 index 00000000..6e314cf4 --- /dev/null +++ b/src/app/usecases/removeProductWareseByProductIdUsecase.js @@ -0,0 +1,6 @@ +module.exports = ({ productWarehouseRepository }) => ({ + execute: async (data) => { + const response = await productWarehouseRepository.removeByProductId(data); + return response; + } +}); diff --git a/src/app/usecases/removeWarehouseByIdUsecase.js b/src/app/usecases/removeWarehouseByIdUsecase.js new file mode 100644 index 00000000..0618d564 --- /dev/null +++ b/src/app/usecases/removeWarehouseByIdUsecase.js @@ -0,0 +1,6 @@ +module.exports = ({ warehouseRepository }) => ({ + execute: async (data) => { + const response = await warehouseRepository.removeById(data); + return response; + } +}); diff --git a/src/infra/errors/BadRequestError.js b/src/infra/errors/BadRequestError.js new file mode 100644 index 00000000..34a5affa --- /dev/null +++ b/src/infra/errors/BadRequestError.js @@ -0,0 +1,7 @@ +class BadRequestError extends Error { + constructor(details) { + super(`Bad Request ${details}`); + this.name = 'BadRequestError'; + } +} +module.exports = () => BadRequestError; diff --git a/src/infra/errors/Exceptions.js b/src/infra/errors/Exceptions.js index f4dd186b..02066e8c 100644 --- a/src/infra/errors/Exceptions.js +++ b/src/infra/errors/Exceptions.js @@ -1,9 +1,25 @@ -module.exports = ({ internalServerError: InternalServerError }) => ({ +module.exports = ({ internalServerError: InternalServerError, notFoundError: NotFoundError, badRequestError: BadRequestError }) => ({ internalError: (details) => { const error = new InternalServerError(details); return { status: 500, body: error.name }; + }, + + notFound: (details) => { + const error = new NotFoundError(details); + return { + status: 500, + body: error.name + }; + }, + + badRequest: (details) => { + const error = new BadRequestError(details); + return { + status: 500, + body: error.name + }; } }); diff --git a/src/infra/errors/NotFoundError.js b/src/infra/errors/NotFoundError.js new file mode 100644 index 00000000..e99dc67f --- /dev/null +++ b/src/infra/errors/NotFoundError.js @@ -0,0 +1,7 @@ +class NotFoundError extends Error { + constructor(details) { + super(`Not found ${details}`); + this.name = 'NotFoundError'; + } +} +module.exports = () => NotFoundError; diff --git a/src/infra/repositories/Repository.js b/src/infra/repositories/Repository.js index 95913df7..1f5e43b9 100644 --- a/src/infra/repositories/Repository.js +++ b/src/infra/repositories/Repository.js @@ -6,15 +6,26 @@ class Repository { } async create(domainEntity) { - const model = await new this.ResourceModel(this.ResourceMapper.toInputDatabase(domainEntity)); - const dbCreatedResource = await model.save(); + const resource = await new this.ResourceModel(this.ResourceMapper.toInputDatabase(domainEntity)); + const dbCreatedResource = await resource.save(); return this.ResourceMapper.toOutputDabase(dbCreatedResource); } + async findOne(query) { + const resource = await this.ResourceModel.findOne(query); + if (!resource) return resource; + return this.ResourceMapper.toOutputDabase(resource); + } + async findAll(query) { - const model = await this.ResourceModel.findAll(query); - if (!model) return model; - return model.map(this.ResourceMapper.toOutputDabase); + const resource = await this.ResourceModel.findAll(query); + if (!resource) return resource; + return resource.map(this.ResourceMapper.toOutputDabase); + } + + async remove(query) { + const resource = await this.ResourceModel.destroy(query); + return resource > 0; } } diff --git a/src/infra/repositories/product/ProductRepository.js b/src/infra/repositories/product/ProductRepository.js index d64a20a6..e4dac0a1 100644 --- a/src/infra/repositories/product/ProductRepository.js +++ b/src/infra/repositories/product/ProductRepository.js @@ -9,6 +9,21 @@ class ProductRepository extends Repository { Exceptions: exceptions }); } + + async findBySku(sku) { + const resource = await this.findOne({ where: { sku } }); + return resource; + } + + async removeById(productId) { + const resource = await this.remove({ where: { id: productId } }); + return resource; + } + + async removeBySku(sku) { + const resource = await this.remove({ where: { sku } }); + return resource; + } } module.exports = ProductRepository; diff --git a/src/infra/repositories/productWarehouse/ProductWarehouseMapper.js b/src/infra/repositories/productWarehouse/ProductWarehouseMapper.js index 949ccbd9..883f9ad4 100644 --- a/src/infra/repositories/productWarehouse/ProductWarehouseMapper.js +++ b/src/infra/repositories/productWarehouse/ProductWarehouseMapper.js @@ -2,7 +2,6 @@ const ProductWarehouseMapper = { toInputDatabase(entry) { - console.log(entry); return entry; }, toOutputDabase({ dataValues }) { diff --git a/src/infra/repositories/productWarehouse/ProductWarehouseRepository.js b/src/infra/repositories/productWarehouse/ProductWarehouseRepository.js index a9746a58..911b2297 100644 --- a/src/infra/repositories/productWarehouse/ProductWarehouseRepository.js +++ b/src/infra/repositories/productWarehouse/ProductWarehouseRepository.js @@ -1,6 +1,6 @@ const Repository = require('../Repository'); -class WarehouseRepository extends Repository { +class ProductWarehouseRepository extends Repository { constructor({ sequelize, productWarehouseMapper, exceptions }) { const { ProductWarehouse } = sequelize.models; super({ @@ -9,6 +9,16 @@ class WarehouseRepository extends Repository { Exceptions: exceptions }); } + + async findAllByProductId(productId) { + const resource = await this.findAll({ where: { productId } }); + return resource; + } + + async removeByProductId(productId) { + const resource = await this.remove({ where: { productId } }); + return resource; + } } -module.exports = WarehouseRepository; +module.exports = ProductWarehouseRepository; diff --git a/src/infra/repositories/warehouse/WarehouseRepository.js b/src/infra/repositories/warehouse/WarehouseRepository.js index 2c41a4be..7e38e3be 100644 --- a/src/infra/repositories/warehouse/WarehouseRepository.js +++ b/src/infra/repositories/warehouse/WarehouseRepository.js @@ -9,6 +9,11 @@ class WarehouseRepository extends Repository { Exceptions: exceptions }); } + + async removeById(id) { + const resource = await this.remove({ where: { id } }); + return resource; + } } module.exports = WarehouseRepository; diff --git a/src/interfaces/http/controllers/productController.js b/src/interfaces/http/controllers/productController.js index 5e4798be..6e93e236 100644 --- a/src/interfaces/http/controllers/productController.js +++ b/src/interfaces/http/controllers/productController.js @@ -1,18 +1,27 @@ const { Router } = require('express'); const Status = require('http-status'); -module.exports = ({ createProductOperation }) => ({ +module.exports = ({ createProductOperation, removeProductOperation }) => ({ create: async (req, res, next) => { try { const { body } = req; - const product = await createProductOperation.execute(body); - return res.status(Status.OK).json(product); + await createProductOperation.execute(body); + return res.status(Status.CREATED).end(); } catch (error) { next(error); } }, + removeBySku: async (req, res, next) => { + try { + const { sku } = req.params; + const responseOperation = await removeProductOperation.execute(typeof sku === 'string' ? Number(sku) : sku); + return res.status(Status.OK).json(responseOperation); + } catch (error) { + next(error); + } + }, get router() { - return Router().post('/', this.create); + return Router().post('/', this.create).delete('/sku/:sku', this.removeBySku); } });