add product implemented

pull/1/head
Aji Kamaludin 3 years ago
parent f69931a78b
commit 549280324a
No known key found for this signature in database
GPG Key ID: 670E1F26AD5A8099

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

@ -25,12 +25,18 @@ const RegistrationsValidator = require('./validator/registration');
const units = require('./api/units');
const UnitsService = require('./services/postgres/UnitsService');
// products
const products = require('./api/products');
const ProductsService = require('./services/postgres/ProductsService');
const ProductsValidator = require('./validator/products');
const init = async () => {
// instances
const usersService = new UsersService();
const authenticationsService = new AuthenticationsService();
const registrationsService = new RegistrationsService(usersService);
const unitsService = new UnitsService();
const productsService = new ProductsService();
// server
const server = Hapi.server({
@ -127,6 +133,13 @@ const init = async () => {
service: unitsService,
},
},
{
plugin: products,
options: {
service: productsService,
validator: ProductsValidator,
},
},
]);
await server.start();

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

@ -12,37 +12,44 @@ class RegistrationService {
async registerStore({ name, email, password }) {
await this._userService.verifyNewEmail({ email });
const companyId = uuid();
const officeId = uuid();
const warehouseId = uuid();
const unitId = uuid();
const hashedPassword = await bcrypt.hash(password, 12);
const createCompanyQuery = {
text: 'INSERT INTO companies(id, name) VALUES ($1, $2)',
values: [companyId, name],
};
const createOfficeQuery = {
text: 'INSERT INTO offices(id, name, company_id) VALUES ($1, $2, $3)',
values: [officeId, `office-${name}`, companyId],
};
const createWarehouseQuery = {
text: 'INSERT INTO warehouses(id, name, office_id) VALUES ($1, $2, $3)',
values: [warehouseId, `warehouse-${name}`, officeId],
};
const createUserQuery = {
text: 'INSERT INTO users(id, name, email, password, role, company_id) VALUES ((select uuid_generate_v4()), $1, $2, $3, $4, $5)',
values: [name, email, hashedPassword, 'admin', companyId],
};
const createUnitQuery = {
text: 'INSERT INTO units(id, name, company_id) VALUES ($1, $2, $3)',
values: [unitId, 'Buah', companyId],
};
try {
await this._pool.query('BEGIN');
const companyId = uuid();
const officeId = uuid();
const warehouseId = uuid();
const hashedPassword = await bcrypt.hash(password, 12);
const createCompanyQuery = {
text: 'INSERT INTO companies(id, name) VALUES ($1, $2)',
values: [companyId, name],
};
const createOfficeQuery = {
text: 'INSERT INTO offices(id, name, company_id) VALUES ($1, $2, $3)',
values: [officeId, name, companyId],
};
const createWarehouseQuery = {
text: 'INSERT INTO warehouses(id, name, office_id) VALUES ($1, $2, $3)',
values: [warehouseId, name, officeId],
};
const createUserQuery = {
text: 'INSERT INTO users(id, name, email, password, role, company_id) VALUES ((select uuid_generate_v4()), $1, $2, $3, $4, $5)',
values: [name, email, hashedPassword, 'admin', companyId],
};
await this._pool.query(createCompanyQuery);
await this._pool.query(createOfficeQuery);
await this._pool.query(createWarehouseQuery);
await this._pool.query(createUserQuery);
await this._pool.query(createUnitQuery);
await this._pool.query('COMMIT');
} catch (err) {
await this._pool.query('ROLLBACK');

@ -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…
Cancel
Save