diff --git a/documents/postman-collection/KasirAja API.postman_collection.json b/documents/postman-collection/KasirAja API.postman_collection.json index b4468d4..799bdd3 100644 --- a/documents/postman-collection/KasirAja API.postman_collection.json +++ b/documents/postman-collection/KasirAja API.postman_collection.json @@ -22,8 +22,8 @@ "pm.test('test is ok!', () => {", " const responseJson = pm.response.json();", "", - " pm.expect(responseJson).to.haveOwnProperty('status');", - " pm.expect(responseJson.status).to.equals('Ok!');", + " pm.expect(responseJson).to.haveOwnProperty('data');", + " pm.expect(responseJson.data.status).to.equals('Ok!');", " // pm.environment.get('songId')", " pm.environment.set('status', responseJson.status);", "})" @@ -403,7 +403,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{host}}/users?startDate={{currentdate}}&endDate={{futuredate}}", + "raw": "{{host}}/users?q=e&p=1", "host": [ "{{host}}" ], @@ -412,12 +412,12 @@ ], "query": [ { - "key": "startDate", - "value": "{{currentdate}}" + "key": "q", + "value": "e" }, { - "key": "endDate", - "value": "{{futuredate}}" + "key": "p", + "value": "1" } ] } @@ -690,7 +690,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{host}}/units?startDate={{currentdate}}&endDate={{futuredate}}", + "raw": "{{host}}/units?q=e&page=1", "host": [ "{{host}}" ], @@ -699,12 +699,12 @@ ], "query": [ { - "key": "startDate", - "value": "{{currentdate}}" + "key": "q", + "value": "e" }, { - "key": "endDate", - "value": "{{futuredate}}" + "key": "page", + "value": "1" } ] } @@ -977,7 +977,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{host}}/categories?startDate={{currentdate}}&endDate={{futuredate}}", + "raw": "{{host}}/categories?page=1&q=m", "host": [ "{{host}}" ], @@ -986,12 +986,12 @@ ], "query": [ { - "key": "startDate", - "value": "{{currentdate}}" + "key": "page", + "value": "1" }, { - "key": "endDate", - "value": "{{futuredate}}" + "key": "q", + "value": "m" } ] } @@ -1292,7 +1292,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{host}}/products?startDate={{currentdate}}&endDate={{futuredate}}&withStock=true", + "raw": "{{host}}/products?page=1&q=e&withStock=true", "host": [ "{{host}}" ], @@ -1301,12 +1301,12 @@ ], "query": [ { - "key": "startDate", - "value": "{{currentdate}}" + "key": "page", + "value": "1" }, { - "key": "endDate", - "value": "{{futuredate}}" + "key": "q", + "value": "e" }, { "key": "withStock", diff --git a/src/api/categories/handler.js b/src/api/categories/handler.js index 25e138c..90bd702 100644 --- a/src/api/categories/handler.js +++ b/src/api/categories/handler.js @@ -39,14 +39,12 @@ class CategoriesHandler { async getCategoriesHandler(request) { try { const { companyId } = request.auth.credentials; - const { startDate, endDate } = request.query; - const categories = await this._service.getCategories(companyId, { startDate, endDate }); + const { page, q } = request.query; + const { categories, meta } = await this._service.getCategories(companyId, { page, q }); return { status: 'success', - data: { - categories, - }, + data: { categories, meta }, }; } catch (error) { return error; diff --git a/src/api/products/handler.js b/src/api/products/handler.js index 6796c20..8c115cd 100644 --- a/src/api/products/handler.js +++ b/src/api/products/handler.js @@ -40,17 +40,17 @@ class ProductsHandler { async getProductsHandler(request) { try { - this._validator.validateGetProductsPayload(request.query); const { companyId } = request.auth.credentials; - const { startDate, endDate, withStock } = request.query; - const products = await this._service.getProducts(companyId, { - startDate, endDate, withStock, + const { page, q, withStock } = request.query; + const { products, meta } = await this._service.getProducts(companyId, { + page, q, withStock, }); return { status: 'success', data: { products, + meta, }, }; } catch (error) { diff --git a/src/api/units/handler.js b/src/api/units/handler.js index 6cc46a0..366c1b0 100644 --- a/src/api/units/handler.js +++ b/src/api/units/handler.js @@ -36,13 +36,14 @@ class UnitsHandler { async getUnitsHandler(request) { try { const { companyId } = request.auth.credentials; - const { startDate, endDate } = request.query; - const units = await this._service.getUnits(companyId, { startDate, endDate }); + const { page, q } = request.query; + const { units, meta } = await this._service.getUnits(companyId, { page, q }); return { status: 'success', data: { units, + meta, }, }; } catch (error) { diff --git a/src/api/units/routes.js b/src/api/units/routes.js index 1dba5eb..078cba8 100644 --- a/src/api/units/routes.js +++ b/src/api/units/routes.js @@ -29,11 +29,11 @@ const routes = (handler) => [ validate: { validator: Joi, query: { - startDate: Joi.date().required(), - endDate: Joi.date().required(), + page: Joi.string().allow(''), + q: Joi.string().allow(''), }, failAction: () => { - throw new InvariantError('startDate and endDate is required'); + throw new InvariantError('params is required'); }, }, }, diff --git a/src/api/users/handler.js b/src/api/users/handler.js index 0e0f163..0455f64 100644 --- a/src/api/users/handler.js +++ b/src/api/users/handler.js @@ -12,15 +12,15 @@ class UsersHandler { async getUsersHandler(request) { try { - this._validator.validateGetUsersPayload(request.query); const { companyId } = request.auth.credentials; - const { startDate, endDate } = request.query; - const users = await this._service.getUsers(companyId, { startDate, endDate }); + const { page, q } = request.query; + const { users, meta } = await this._service.getUsers(companyId, { page, q }); return { status: 'success', data: { users, + meta, }, }; } catch (error) { diff --git a/src/services/postgres/CategoriesService.js b/src/services/postgres/CategoriesService.js index 3069886..4e282d1 100644 --- a/src/services/postgres/CategoriesService.js +++ b/src/services/postgres/CategoriesService.js @@ -8,15 +8,40 @@ class CategoriesService { this._pool = new Pool(); } - async getCategories(companyId, { startDate, endDate }) { + async getCategories(companyId, { page = 1, limit = 10, q = null }) { + const recordsQuery = await this._pool.query(` + SELECT count(id) as total + FROM categories + WHERE + company_id = '${companyId}' + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + `); + + const { total } = recordsQuery.rows[0]; + + const totalPages = Math.ceil(total / limit); + const offsets = limit * (page - 1); + const query = { - text: 'SELECT id, name, description FROM categories WHERE company_id = $1 AND created_at::DATE BETWEEN $2 AND $3', - values: [companyId, startDate, endDate], + text: ` + SELECT id, name, description + FROM categories + WHERE company_id = $1 + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + LIMIT $2 OFFSET $3`, + values: [companyId, limit, offsets], }; - const results = await this._pool.query(query); + const { rows } = await this._pool.query(query); - return results.rows; + return { + categories: rows, + meta: { + totalPages, + total, + page, + }, + }; } async getCategoryById(categoryId) { diff --git a/src/services/postgres/ProductsService.js b/src/services/postgres/ProductsService.js index 6ed7ca0..b4a0c91 100644 --- a/src/services/postgres/ProductsService.js +++ b/src/services/postgres/ProductsService.js @@ -9,13 +9,30 @@ class ProductsService { this._pool = new Pool(); } - async getProducts(companyId, { startDate, endDate, withStock }) { + async getProducts(companyId, { + page = 1, q = null, withStock, limit = 10, + }) { + const recordsQuery = await this._pool.query(` + SELECT count(id) as total + FROM products + WHERE + company_id = '${companyId}' + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + `); + + const { total } = recordsQuery.rows[0]; + + const totalPages = Math.ceil(total / limit); + const offsets = limit * (page - 1); + let query = { text: `SELECT id, name, description, price, cost FROM products - WHERE company_id = $1 AND created_at::DATE BETWEEN $2 AND $3`, - values: [companyId, startDate, endDate], + WHERE company_id = $1 + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + LIMIT $2 OFFSET $3`, + values: [companyId, limit, offsets], }; if (withStock && withStock === 'true') { @@ -24,14 +41,23 @@ class ProductsService { name, description, price, cost, stock FROM products LEFT JOIN stocks ON stocks.product_id = products.id - WHERE company_id = $1 AND products.created_at BETWEEN $2 AND $3`, - values: [companyId, startDate, endDate], + WHERE company_id = $1 + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + LIMIT $2 OFFSET $3`, + values: [companyId, limit, offsets], }; } - const results = await this._pool.query(query); + const { rows } = await this._pool.query(query); - return results.rows; + return { + products: rows, + meta: { + totalPages, + total, + page, + }, + }; } async getProductById({ productId, companyId }) { diff --git a/src/services/postgres/UnitsService.js b/src/services/postgres/UnitsService.js index d6ad8c1..aecbe65 100644 --- a/src/services/postgres/UnitsService.js +++ b/src/services/postgres/UnitsService.js @@ -8,15 +8,38 @@ class UnitsService { this._pool = new Pool(); } - async getUnits(companyId, { startDate, endDate }) { + async getUnits(companyId, { page = 1, q = null, limit = 10 }) { + const recordsQuery = await this._pool.query(` + SELECT count(id) as total + FROM units + WHERE + company_id = '${companyId}' + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + `); + + const { total } = recordsQuery.rows[0]; + + const totalPages = Math.ceil(total / limit); + const offsets = limit * (page - 1); + const query = { - text: 'SELECT id, name, description FROM units WHERE company_id = $1 AND created_at::DATE BETWEEN $2 AND $3', - values: [companyId, startDate, endDate], + text: ` + SELECT id, name, description FROM units WHERE company_id = $1 + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + LIMIT $2 OFFSET $3`, + values: [companyId, limit, offsets], }; - const results = await this._pool.query(query); + const { rows } = await this._pool.query(query); - return results.rows; + return { + units: rows, + meta: { + totalPages, + total, + page, + }, + }; } async getUnitById(unitId) { diff --git a/src/services/postgres/UsersService.js b/src/services/postgres/UsersService.js index 1e0e5f3..0aceb09 100644 --- a/src/services/postgres/UsersService.js +++ b/src/services/postgres/UsersService.js @@ -63,16 +63,38 @@ class UsersService { return id; } - async getUsers(companyId, { startDate, endDate }) { - // TODO: implement pagination leter + async getUsers(companyId, { page = 1, q = null, limit = 10 }) { + const recordsQuery = await this._pool.query(` + SELECT count(id) as total + FROM users + WHERE + company_id = '${companyId}' + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + `); + + const { total } = recordsQuery.rows[0]; + + const totalPages = Math.ceil(total / limit); + const offsets = limit * (page - 1); + const query = { - text: 'SELECT name, email, role FROM users WHERE company_id = $1 AND created_at::DATE BETWEEN $2 AND $3', - values: [companyId, startDate, endDate], + text: ` + SELECT name, email, role FROM users WHERE company_id = $1 + ${q !== null ? `AND name ILIKE '%${q}%'` : ''} + LIMIT $2 OFFSET $3`, + values: [companyId, limit, offsets], }; - const result = await this._pool.query(query); + const { rows } = await this._pool.query(query); - return result.rows; + return { + users: rows, + meta: { + totalPages, + total, + page, + }, + }; } async getUserById({ userId, companyId }) { diff --git a/src/validator/products/index.js b/src/validator/products/index.js index d36aaa6..92960c6 100644 --- a/src/validator/products/index.js +++ b/src/validator/products/index.js @@ -1,4 +1,4 @@ -const { PostProductPayloadSchema, PutProductPayloadSchema, GetProductsPayloadSchema } = require('./schema'); +const { PostProductPayloadSchema, PutProductPayloadSchema } = require('./schema'); const InvariantError = require('../../exceptions/InvariantError'); const ProductsValidator = { @@ -14,12 +14,6 @@ const ProductsValidator = { 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; diff --git a/src/validator/products/schema.js b/src/validator/products/schema.js index ca10314..7cdd8a5 100644 --- a/src/validator/products/schema.js +++ b/src/validator/products/schema.js @@ -18,10 +18,4 @@ const PutProductPayloadSchema = Joi.object({ category_id: Joi.string().guid().required(), }); -const GetProductsPayloadSchema = Joi.object({ - startDate: Joi.date().required(), - endDate: Joi.date().required(), - withStock: Joi.boolean().allow(''), -}); - -module.exports = { PostProductPayloadSchema, PutProductPayloadSchema, GetProductsPayloadSchema }; +module.exports = { PostProductPayloadSchema, PutProductPayloadSchema }; diff --git a/src/validator/users/index.js b/src/validator/users/index.js index c09fffa..5326e52 100644 --- a/src/validator/users/index.js +++ b/src/validator/users/index.js @@ -1,4 +1,4 @@ -const { PostUserPayloadSchema, PutUserPayloadSchema, GetUsersPayloadSchema } = require('./schema'); +const { PostUserPayloadSchema, PutUserPayloadSchema } = require('./schema'); const InvariantError = require('../../exceptions/InvariantError'); const UsersValidator = { @@ -14,12 +14,6 @@ const UsersValidator = { throw new InvariantError(validationResult.error.message); } }, - validateGetUsersPayload: (payload) => { - const validationResult = GetUsersPayloadSchema.validate(payload); - if (validationResult.error) { - throw new InvariantError(validationResult.error.message); - } - }, }; module.exports = UsersValidator; diff --git a/src/validator/users/schema.js b/src/validator/users/schema.js index bfa51f4..335c9ed 100644 --- a/src/validator/users/schema.js +++ b/src/validator/users/schema.js @@ -12,9 +12,4 @@ const PutUserPayloadSchema = Joi.object({ password: Joi.string().allow(''), }); -const GetUsersPayloadSchema = Joi.object({ - startDate: Joi.date().required(), - endDate: Joi.date().required(), -}); - -module.exports = { PostUserPayloadSchema, PutUserPayloadSchema, GetUsersPayloadSchema }; +module.exports = { PostUserPayloadSchema, PutUserPayloadSchema };