add product implemented
parent
f69931a78b
commit
549280324a
@ -0,0 +1,38 @@
|
||||
class ProductsHandler {
|
||||
constructor(service, validator) {
|
||||
this._service = service;
|
||||
this._validator = validator;
|
||||
|
||||
this.postProductHandler = this.postProductHandler.bind(this);
|
||||
}
|
||||
|
||||
async postProductHandler(request, h) {
|
||||
try {
|
||||
this._validator.validatePostProductPayload(request.payload);
|
||||
|
||||
const { companyId } = request.auth.credentials;
|
||||
const {
|
||||
name, description, price, cost, stock, category_id: categoryId,
|
||||
} = request.payload;
|
||||
|
||||
const productId = await this._service.addProduct({
|
||||
name, description, price, cost, stock, categoryId, companyId,
|
||||
});
|
||||
|
||||
const response = h.response({
|
||||
status: 'success',
|
||||
message: 'Product berhasil ditambahkan',
|
||||
data: {
|
||||
productId,
|
||||
name,
|
||||
},
|
||||
});
|
||||
response.code(201);
|
||||
return response;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ProductsHandler;
|
@ -0,0 +1,11 @@
|
||||
const ProductsHandler = require('./handler');
|
||||
const routes = require('./routes');
|
||||
|
||||
module.exports = {
|
||||
name: 'products',
|
||||
version: '1.0.0',
|
||||
register: async (server, { service, validator }) => {
|
||||
const productsHandler = new ProductsHandler(service, validator);
|
||||
server.route(routes(productsHandler));
|
||||
},
|
||||
};
|
@ -0,0 +1,44 @@
|
||||
const routes = (handler) => [
|
||||
{
|
||||
method: 'POST',
|
||||
path: '/products',
|
||||
handler: handler.postProductHandler,
|
||||
options: {
|
||||
auth: 'kasiraja_jwt',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// method: 'GET',
|
||||
// path: '/users',
|
||||
// handler: handler.getUsersHandler,
|
||||
// options: {
|
||||
// auth: 'kasiraja_jwt',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// method: 'GET',
|
||||
// path: '/users/{id}',
|
||||
// handler: handler.getUserByIdHandler,
|
||||
// options: {
|
||||
// auth: 'kasiraja_jwt',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// method: 'PUT',
|
||||
// path: '/users/{id}',
|
||||
// handler: handler.putUsersHandler,
|
||||
// options: {
|
||||
// auth: 'kasiraja_jwt',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// method: 'DELETE',
|
||||
// path: '/users/{id}',
|
||||
// handler: handler.deleteUsersHandler,
|
||||
// options: {
|
||||
// auth: 'kasiraja_jwt',
|
||||
// },
|
||||
// },
|
||||
];
|
||||
|
||||
module.exports = routes;
|
@ -0,0 +1,133 @@
|
||||
const { Pool } = require('pg');
|
||||
const uuid = require('uuid-random');
|
||||
const { validateUuid } = require('../../utils');
|
||||
const NotFoundError = require('../../exceptions/NotFoundError');
|
||||
const InvariantError = require('../../exceptions/InvariantError');
|
||||
|
||||
class ProductsService {
|
||||
constructor() {
|
||||
this._pool = new Pool();
|
||||
}
|
||||
|
||||
async getProducts(companyId, { startDate, endDate }) {
|
||||
const query = {
|
||||
text: `SELECT
|
||||
name, description, price, cost
|
||||
FROM products
|
||||
WHERE company_id = $1 AND created_at BETWEEN $2 AND $3`,
|
||||
values: [companyId, startDate, endDate],
|
||||
};
|
||||
|
||||
const results = await this._pool.query(query);
|
||||
|
||||
return results.rows;
|
||||
}
|
||||
|
||||
async getProduct({ productId, companyId }) {
|
||||
validateUuid(productId);
|
||||
|
||||
const query = {
|
||||
text: `SELECT
|
||||
product.name, product.description, price, cost, cost_average, categories.name as category_name, stocks.stock
|
||||
FROM products
|
||||
LEFT JOIN stocks.product_id ON products.id
|
||||
LEFT JOIN categories ON categories.id = products.category_id
|
||||
WHERE products.id = $1 AND products.company_id = $2`,
|
||||
values: [productId, companyId],
|
||||
};
|
||||
|
||||
const result = await this._pool.query(query);
|
||||
|
||||
if (result.rowCount < 1) {
|
||||
throw new NotFoundError('Product tidak ditemukan');
|
||||
}
|
||||
|
||||
return result.rows[0];
|
||||
}
|
||||
|
||||
async addProduct({
|
||||
name, description, price, cost, stock, categoryId, companyId,
|
||||
}) {
|
||||
const productId = uuid();
|
||||
const stockId = uuid();
|
||||
|
||||
const productQuery = {
|
||||
text: `INSERT INTO products(id, name, description, price, cost, category_id, company_id, unit_id)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, (SELECT id FROM units WHERE company_id = $7 LIMIT 1))`,
|
||||
values: [productId, name, description, price, cost, categoryId, companyId],
|
||||
};
|
||||
|
||||
// update stock default warehouse default office
|
||||
const stockQuery = {
|
||||
text: `INSERT INTO
|
||||
stocks(id, product_id, stock, warehouse_id, sale, purchase)
|
||||
VALUES
|
||||
($1, $2, $3, (
|
||||
SELECT id FROM warehouses WHERE office_id =
|
||||
(SELECT id FROM offices WHERE company_id = $4 LIMIT 1)
|
||||
LIMIT 1),
|
||||
0, 0)`,
|
||||
values: [stockId, productId, stock, companyId],
|
||||
};
|
||||
|
||||
try {
|
||||
await this._pool.query('BEGIN');
|
||||
await this._pool.query(productQuery);
|
||||
await this._pool.query(stockQuery);
|
||||
await this._pool.query('COMMIT');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
await this._pool.query('ROLLBACK');
|
||||
throw new InvariantError('Product gagal ditambahkan');
|
||||
}
|
||||
|
||||
return productId;
|
||||
}
|
||||
|
||||
async updateProduct(productId, {
|
||||
name, description, price, cost, stock, categoryId,
|
||||
}) {
|
||||
validateUuid(productId);
|
||||
|
||||
const productQuery = {
|
||||
text: `UPDATE products SET
|
||||
name = $1, description = $2, price = $3,
|
||||
cost = $4, category_id = $5
|
||||
WHERE id = $6`,
|
||||
values: [name, description, price, cost, categoryId, productId],
|
||||
};
|
||||
|
||||
// update stock all warehouses
|
||||
const stockQuery = {
|
||||
text: 'UPDATE stocks SET stock = $1 WHERE product_id = $2',
|
||||
values: [stock, productId],
|
||||
};
|
||||
|
||||
try {
|
||||
await this._pool.query('BEGIN');
|
||||
await this._pool.query(productQuery);
|
||||
await this._pool.query(stockQuery);
|
||||
await this._pool.query('COMMIT');
|
||||
} catch (err) {
|
||||
await this._pool.query('ROLLBACK');
|
||||
throw new InvariantError('Product gagal diubah');
|
||||
}
|
||||
}
|
||||
|
||||
async deleteProduct(productId) {
|
||||
validateUuid(productId);
|
||||
const query = {
|
||||
text: 'DELETE FROM products WHERE id = $1',
|
||||
values: [productId],
|
||||
};
|
||||
|
||||
const result = await this._pool.query(query);
|
||||
|
||||
if (result.rowCount < 1) {
|
||||
throw new NotFoundError('Product tidak ditemukan');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ProductsService;
|
@ -0,0 +1,25 @@
|
||||
const { PostProductPayloadSchema, PutProductPayloadSchema, GetProductsPayloadSchema } = require('./schema');
|
||||
const InvariantError = require('../../exceptions/InvariantError');
|
||||
|
||||
const ProductsValidator = {
|
||||
validatePostProductPayload: (payload) => {
|
||||
const validationResult = PostProductPayloadSchema.validate(payload);
|
||||
if (validationResult.error) {
|
||||
throw new InvariantError(validationResult.error.message);
|
||||
}
|
||||
},
|
||||
validatePutProductPayload: (payload) => {
|
||||
const validationResult = PutProductPayloadSchema.validate(payload);
|
||||
if (validationResult.error) {
|
||||
throw new InvariantError(validationResult.error.message);
|
||||
}
|
||||
},
|
||||
validateGetProductsPayload: (payload) => {
|
||||
const validationResult = GetProductsPayloadSchema.validate(payload);
|
||||
if (validationResult.error) {
|
||||
throw new InvariantError(validationResult.error.message);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ProductsValidator;
|
@ -0,0 +1,26 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const PostProductPayloadSchema = Joi.object({
|
||||
name: Joi.string().required(),
|
||||
description: Joi.string(),
|
||||
cost: Joi.number().required(),
|
||||
price: Joi.number().required(),
|
||||
stock: Joi.number().required(),
|
||||
category_id: Joi.string().guid().required(),
|
||||
});
|
||||
|
||||
const PutProductPayloadSchema = Joi.object({
|
||||
name: Joi.string().required(),
|
||||
description: Joi.string(),
|
||||
cost: Joi.number().required(),
|
||||
price: Joi.number().required(),
|
||||
stock: Joi.number().required(),
|
||||
category_id: Joi.string().guid().required(),
|
||||
});
|
||||
|
||||
const GetProductsPayloadSchema = Joi.object({
|
||||
startDate: Joi.date().required(),
|
||||
endDate: Joi.date().required(),
|
||||
});
|
||||
|
||||
module.exports = { PostProductPayloadSchema, PutProductPayloadSchema, GetProductsPayloadSchema };
|
Loading…
Reference in New Issue