From caf41e81e0eb97c7479016bd0cb5159818e353ee Mon Sep 17 00:00:00 2001 From: nochill Date: Thu, 16 Mar 2023 16:55:45 +0700 Subject: [PATCH] add product category --- api/product_category.go | 97 +++++++++++++++ api/product_category_test.go | 89 ++++++++++++++ api/server.go | 5 + db/migrations/000001_init_schema.up.sql | 2 + .../000003_create_product_categories.down.sql | 3 + .../000003_create_product_categories.up.sql | 8 ++ db/mock/store.go | 104 ++++++++++++++++ db/query/product_category.sql | 24 ++++ db/query/purchase_order.sql | 12 +- db/query/purchase_order_detail.sql | 7 +- db/sqlc/models.go | 26 ++-- db/sqlc/product_category.sql.go | 114 ++++++++++++++++++ db/sqlc/product_category_test.go | 72 +++++++++++ db/sqlc/products.sql.go | 15 ++- db/sqlc/purchase_order.sql.go | 66 ++++++++++ db/sqlc/purchase_order_detail.sql.go | 25 ++++ db/sqlc/querier.go | 7 ++ 17 files changed, 660 insertions(+), 16 deletions(-) create mode 100644 api/product_category.go create mode 100644 api/product_category_test.go create mode 100644 db/migrations/000003_create_product_categories.down.sql create mode 100644 db/migrations/000003_create_product_categories.up.sql create mode 100644 db/query/product_category.sql create mode 100644 db/sqlc/product_category.sql.go create mode 100644 db/sqlc/product_category_test.go diff --git a/api/product_category.go b/api/product_category.go new file mode 100644 index 0000000..096b713 --- /dev/null +++ b/api/product_category.go @@ -0,0 +1,97 @@ +package api + +import ( + "database/sql" + "net/http" + + db "git.nochill.in/nochill/naice_pos/db/sqlc" + "git.nochill.in/nochill/naice_pos/token" + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +type createProductCategoryRequest struct { + MerchantID uuid.UUID `json:"merchant_id" binding:"required"` + Name string `json:"name" binding:"required"` +} + +func (server *Server) createProductCategory(ctx *gin.Context) { + var req createProductCategoryRequest + + if err := ctx.ShouldBindJSON(&req); err != nil { + ctx.JSON(http.StatusBadRequest, errorResponse(err)) + return + } + + authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) + arg := db.CreateProductCategoryParams{ + MerchantID: authPayload.MerchantID, + Name: req.Name, + } + + ProductCategory, err := server.store.CreateProductCategory(ctx, arg) + if err != nil { + ctx.JSON(http.StatusInternalServerError, errorResponse(err)) + return + } + + ctx.JSON(http.StatusOK, ProductCategory) +} + +type listProductCategoriesRequest struct { + PageID int32 `form:"page_id" binding:"required,min=1"` + PageSize int32 `form:"page_size" binding:"required,min=5"` +} + +func (server *Server) listProductCategories(ctx *gin.Context) { + var req listProductCategoriesRequest + if err := ctx.ShouldBindQuery(&req); err != nil { + ctx.JSON(http.StatusBadRequest, errorResponse(err)) + return + } + + authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) + arg := db.ListProductCategoriesByMerchantIDParams{ + MerchantID: authPayload.MerchantID, + Limit: req.PageSize, + Offset: (req.PageID - 1) * req.PageSize, + } + + ProductCategories, err := server.store.ListProductCategoriesByMerchantID(ctx, arg) + if err != nil { + ctx.JSON(http.StatusInternalServerError, errorResponse(err)) + return + } + + ctx.JSON(http.StatusOK, ProductCategories) +} + +type updateProductCategoryRequest struct { + ProductCategoryID uuid.UUID `json:"ProductCategory_id" binding:"required"` + Name string `json:"name" binding:"required"` +} + +func (server *Server) updateProductCategory(ctx *gin.Context) { + var req updateProductCategoryRequest + if err := ctx.ShouldBindJSON(&req); err != nil { + ctx.JSON(http.StatusBadRequest, errorResponse(err)) + return + } + + arg := db.UpdateProductCategoryParams{ + ID: req.ProductCategoryID, + Name: req.Name, + } + + ProductCategory, err := server.store.UpdateProductCategory(ctx, arg) + if err != nil { + if err == sql.ErrNoRows { + ctx.JSON(http.StatusNotFound, errorResponse(err)) + return + } + ctx.JSON(http.StatusInternalServerError, errorResponse(err)) + return + } + + ctx.JSON(http.StatusOK, ProductCategory) +} diff --git a/api/product_category_test.go b/api/product_category_test.go new file mode 100644 index 0000000..69dd671 --- /dev/null +++ b/api/product_category_test.go @@ -0,0 +1,89 @@ +package api + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + mockdb "git.nochill.in/nochill/naice_pos/db/mock" + db "git.nochill.in/nochill/naice_pos/db/sqlc" + "git.nochill.in/nochill/naice_pos/token" + "git.nochill.in/nochill/naice_pos/util" + "github.com/gin-gonic/gin" + "github.com/golang/mock/gomock" + "github.com/google/uuid" + "github.com/stretchr/testify/require" +) + +func TestCreateProductCategory(t *testing.T) { + productCategory := createRandomProductCategory(t) + + testCases := []struct { + name string + body gin.H + setupAuth func(t *testing.T, request *http.Request, tokenMaker token.Maker) + buildStubs func(store *mockdb.MockStore) + checkResponse func(recorder *httptest.ResponseRecorder) + }{ + { + name: "OK", + body: gin.H{ + "name": productCategory.Name, + "merchant_id": productCategory.MerchantID, + }, + setupAuth: func(t *testing.T, request *http.Request, tokenMaker token.Maker) { + addAuthorization(t, request, tokenMaker, authorizationTypeBearer, util.RandomEmail(), "a848090f-0409-4386-9caa-929ae6874dbb", time.Minute) + }, + buildStubs: func(store *mockdb.MockStore) { + arg := db.CreateProductCategoryParams{ + MerchantID: uuid.MustParse("a848090f-0409-4386-9caa-929ae6874dbb"), + Name: productCategory.Name, + } + store.EXPECT(). + CreateProductCategory(gomock.Any(), gomock.Eq(arg)). + Times(1). + Return(productCategory, nil) + }, + checkResponse: func(recorder *httptest.ResponseRecorder) { + require.Equal(t, http.StatusOK, recorder.Code) + }, + }, + } + + for i := range testCases { + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + data, err := json.Marshal(tc.body) + require.NoError(t, err) + + store := mockdb.NewMockStore(ctrl) + tc.buildStubs(store) + + server := newTestServer(t, store) + recorder := httptest.NewRecorder() + + url := "/api/product/category" + request, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data)) + require.NoError(t, err) + + tc.setupAuth(t, request, server.tokenMaker) + server.router.ServeHTTP(recorder, request) + tc.checkResponse(recorder) + }) + } +} + +func createRandomProductCategory(t *testing.T) db.ProductCategory { + return db.ProductCategory{ + ID: uuid.New(), + MerchantID: uuid.MustParse("a848090f-0409-4386-9caa-929ae6874dbb"), + Name: util.RandomString(5), + } +} diff --git a/api/server.go b/api/server.go index d4a457a..51491a7 100644 --- a/api/server.go +++ b/api/server.go @@ -44,6 +44,11 @@ func (server *Server) getRoutes() { apiRoutes.PATCH("/products", server.updateProduct) apiRoutes.GET("/product/:id", server.getProduct) + apiRoutes.POST("/product/category", server.createProductCategory) + apiRoutes.GET("/product/categories", server.listProductCategories) + apiRoutes.PATCH("/product/category", server.updateProductCategory) + // apiRoutes.DELETE("/product/category/:id", server.) + apiRoutes.POST("/suppliers", server.createSupplier) apiRoutes.POST("/purchase-products", server.createPurchase) diff --git a/db/migrations/000001_init_schema.up.sql b/db/migrations/000001_init_schema.up.sql index 8a1eb8e..0e9a64c 100644 --- a/db/migrations/000001_init_schema.up.sql +++ b/db/migrations/000001_init_schema.up.sql @@ -16,6 +16,7 @@ CREATE TABLE merchants ( "created_at" timestamp default(now()), "updated_at" timestamp default(now()) ); + create table suppliers ( "id" uuid default gen_random_uuid() primary key not null, "index_id" bigserial not null, @@ -47,6 +48,7 @@ CREATE TABLE products ( "created_at" timestamp default(now()), "updated_at" timestamp default(now()) ); + CREATE TABLE purchase_order ( "id" uuid default gen_random_uuid() primary key not null, "supplier_id" uuid references "suppliers"("id") not null, diff --git a/db/migrations/000003_create_product_categories.down.sql b/db/migrations/000003_create_product_categories.down.sql new file mode 100644 index 0000000..4103e0c --- /dev/null +++ b/db/migrations/000003_create_product_categories.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE "products" DROP COLUMN "product_category_id"; + +DROP TABLE IF EXISTS product_categories; \ No newline at end of file diff --git a/db/migrations/000003_create_product_categories.up.sql b/db/migrations/000003_create_product_categories.up.sql new file mode 100644 index 0000000..fbc1582 --- /dev/null +++ b/db/migrations/000003_create_product_categories.up.sql @@ -0,0 +1,8 @@ +CREATE TABLE product_categories ( + "id" uuid default gen_random_uuid() primary key not null, + "merchant_id" uuid references "merchants"("id") not null, + "index_id" bigserial not null, + "name" varchar not null +); + +ALTER TABLE "products" ADD COLUMN "product_category_id" uuid NOT NULL DEFAULT gen_random_uuid(); \ No newline at end of file diff --git a/db/mock/store.go b/db/mock/store.go index 5fb5bb9..9fd5d4f 100644 --- a/db/mock/store.go +++ b/db/mock/store.go @@ -81,6 +81,21 @@ func (mr *MockStoreMockRecorder) CreateProduct(arg0, arg1 interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateProduct", reflect.TypeOf((*MockStore)(nil).CreateProduct), arg0, arg1) } +// CreateProductCategory mocks base method. +func (m *MockStore) CreateProductCategory(arg0 context.Context, arg1 db.CreateProductCategoryParams) (db.ProductCategory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateProductCategory", arg0, arg1) + ret0, _ := ret[0].(db.ProductCategory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateProductCategory indicates an expected call of CreateProductCategory. +func (mr *MockStoreMockRecorder) CreateProductCategory(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateProductCategory", reflect.TypeOf((*MockStore)(nil).CreateProductCategory), arg0, arg1) +} + // CreatePurchaseOrder mocks base method. func (m *MockStore) CreatePurchaseOrder(arg0 context.Context, arg1 db.CreatePurchaseOrderParams) (db.PurchaseOrder, error) { m.ctrl.T.Helper() @@ -214,6 +229,20 @@ func (mr *MockStoreMockRecorder) DeleteProduct(arg0, arg1 interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProduct", reflect.TypeOf((*MockStore)(nil).DeleteProduct), arg0, arg1) } +// DeleteProductCategory mocks base method. +func (m *MockStore) DeleteProductCategory(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteProductCategory", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteProductCategory indicates an expected call of DeleteProductCategory. +func (mr *MockStoreMockRecorder) DeleteProductCategory(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProductCategory", reflect.TypeOf((*MockStore)(nil).DeleteProductCategory), arg0, arg1) +} + // DeleteSupplier mocks base method. func (m *MockStore) DeleteSupplier(arg0 context.Context, arg1 uuid.UUID) error { m.ctrl.T.Helper() @@ -288,6 +317,36 @@ func (mr *MockStoreMockRecorder) GetProduct(arg0, arg1 interface{}) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProduct", reflect.TypeOf((*MockStore)(nil).GetProduct), arg0, arg1) } +// GetPurchaseOrderById mocks base method. +func (m *MockStore) GetPurchaseOrderById(arg0 context.Context, arg1 uuid.UUID) (db.PurchaseOrder, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPurchaseOrderById", arg0, arg1) + ret0, _ := ret[0].(db.PurchaseOrder) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPurchaseOrderById indicates an expected call of GetPurchaseOrderById. +func (mr *MockStoreMockRecorder) GetPurchaseOrderById(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPurchaseOrderById", reflect.TypeOf((*MockStore)(nil).GetPurchaseOrderById), arg0, arg1) +} + +// GetPurchaseOrderDetailsByPuchaseOrderId mocks base method. +func (m *MockStore) GetPurchaseOrderDetailsByPuchaseOrderId(arg0 context.Context, arg1 uuid.UUID) (db.PurchaseOrderDetail, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPurchaseOrderDetailsByPuchaseOrderId", arg0, arg1) + ret0, _ := ret[0].(db.PurchaseOrderDetail) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPurchaseOrderDetailsByPuchaseOrderId indicates an expected call of GetPurchaseOrderDetailsByPuchaseOrderId. +func (mr *MockStoreMockRecorder) GetPurchaseOrderDetailsByPuchaseOrderId(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPurchaseOrderDetailsByPuchaseOrderId", reflect.TypeOf((*MockStore)(nil).GetPurchaseOrderDetailsByPuchaseOrderId), arg0, arg1) +} + // GetSession mocks base method. func (m *MockStore) GetSession(arg0 context.Context, arg1 uuid.UUID) (db.UserSession, error) { m.ctrl.T.Helper() @@ -348,6 +407,21 @@ func (mr *MockStoreMockRecorder) GetUserById(arg0, arg1 interface{}) *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserById", reflect.TypeOf((*MockStore)(nil).GetUserById), arg0, arg1) } +// ListProductCategoriesByMerchantID mocks base method. +func (m *MockStore) ListProductCategoriesByMerchantID(arg0 context.Context, arg1 db.ListProductCategoriesByMerchantIDParams) ([]db.ProductCategory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListProductCategoriesByMerchantID", arg0, arg1) + ret0, _ := ret[0].([]db.ProductCategory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListProductCategoriesByMerchantID indicates an expected call of ListProductCategoriesByMerchantID. +func (mr *MockStoreMockRecorder) ListProductCategoriesByMerchantID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListProductCategoriesByMerchantID", reflect.TypeOf((*MockStore)(nil).ListProductCategoriesByMerchantID), arg0, arg1) +} + // ListProducts mocks base method. func (m *MockStore) ListProducts(arg0 context.Context, arg1 db.ListProductsParams) ([]db.Product, error) { m.ctrl.T.Helper() @@ -363,6 +437,21 @@ func (mr *MockStoreMockRecorder) ListProducts(arg0, arg1 interface{}) *gomock.Ca return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListProducts", reflect.TypeOf((*MockStore)(nil).ListProducts), arg0, arg1) } +// ListPurchaseOrderByMerchantId mocks base method. +func (m *MockStore) ListPurchaseOrderByMerchantId(arg0 context.Context, arg1 uuid.UUID) ([]db.PurchaseOrder, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListPurchaseOrderByMerchantId", arg0, arg1) + ret0, _ := ret[0].([]db.PurchaseOrder) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListPurchaseOrderByMerchantId indicates an expected call of ListPurchaseOrderByMerchantId. +func (mr *MockStoreMockRecorder) ListPurchaseOrderByMerchantId(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPurchaseOrderByMerchantId", reflect.TypeOf((*MockStore)(nil).ListPurchaseOrderByMerchantId), arg0, arg1) +} + // PurchaseOrderTx mocks base method. func (m *MockStore) PurchaseOrderTx(arg0 context.Context, arg1 db.PurchasoOrderTxParams) (db.PurchaseOrderTxResult, error) { m.ctrl.T.Helper() @@ -423,6 +512,21 @@ func (mr *MockStoreMockRecorder) UpdateProduct(arg0, arg1 interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProduct", reflect.TypeOf((*MockStore)(nil).UpdateProduct), arg0, arg1) } +// UpdateProductCategory mocks base method. +func (m *MockStore) UpdateProductCategory(arg0 context.Context, arg1 db.UpdateProductCategoryParams) (db.ProductCategory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateProductCategory", arg0, arg1) + ret0, _ := ret[0].(db.ProductCategory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateProductCategory indicates an expected call of UpdateProductCategory. +func (mr *MockStoreMockRecorder) UpdateProductCategory(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProductCategory", reflect.TypeOf((*MockStore)(nil).UpdateProductCategory), arg0, arg1) +} + // UpdateProductStock mocks base method. func (m *MockStore) UpdateProductStock(arg0 context.Context, arg1 db.UpdateProductStockParams) error { m.ctrl.T.Helper() diff --git a/db/query/product_category.sql b/db/query/product_category.sql new file mode 100644 index 0000000..8e3190e --- /dev/null +++ b/db/query/product_category.sql @@ -0,0 +1,24 @@ +-- name: CreateProductCategory :one +INSERT INTO product_categories ( + merchant_id, + name +) VALUES ( + $1, $2 +) +RETURNING *; + +-- name: ListProductCategoriesByMerchantID :many +SELECT * FROM product_categories +WHERE merchant_id = $1 +ORDER BY index_id +LIMIT $2 +OFFSET $3; + +-- name: UpdateProductCategory :one +UPDATE product_categories +SET name = $1 +WHERE id = $2 +RETURNING *; + +-- name: DeleteProductCategory :exec +DELETE FROM product_categories WHERE id = $1; \ No newline at end of file diff --git a/db/query/purchase_order.sql b/db/query/purchase_order.sql index ee7c5f1..e5f8ccf 100644 --- a/db/query/purchase_order.sql +++ b/db/query/purchase_order.sql @@ -10,4 +10,14 @@ INSERT INTO purchase_order ( ) VALUES ( $1, $2, $3, $4, $5, $6, $7 ) -RETURNING *; \ No newline at end of file +RETURNING *; + +-- name: GetPurchaseOrderById :one +SELECT * +FROM purchase_order +WHERE id = $1; + +-- name: ListPurchaseOrderByMerchantId :many +SELECT * +FROM purchase_order +WHERE merchant_id = $1; \ No newline at end of file diff --git a/db/query/purchase_order_detail.sql b/db/query/purchase_order_detail.sql index 53601e6..6c2a130 100644 --- a/db/query/purchase_order_detail.sql +++ b/db/query/purchase_order_detail.sql @@ -9,4 +9,9 @@ INSERT INTO purchase_order_detail ( ) VALUES ( $1, $2, $3, $4, $5, $6 ) -RETURNING *; \ No newline at end of file +RETURNING *; + +-- name: GetPurchaseOrderDetailsByPuchaseOrderId :one +SELECT * +FROM purchase_order_detail +WHERE purchase_order_id = $1; \ No newline at end of file diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 734a266..5c6d551 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -33,15 +33,23 @@ type Merchant struct { } type Product struct { - ID uuid.UUID `json:"id"` - MerchantID uuid.UUID `json:"merchant_id"` - IndexID int64 `json:"index_id"` - Name string `json:"name"` - SellingPrice float64 `json:"selling_price"` - PurchasePrice float64 `json:"purchase_price"` - Stock float64 `json:"stock"` - CreatedAt sql.NullTime `json:"created_at"` - UpdatedAt sql.NullTime `json:"updated_at"` + ID uuid.UUID `json:"id"` + MerchantID uuid.UUID `json:"merchant_id"` + IndexID int64 `json:"index_id"` + Name string `json:"name"` + SellingPrice float64 `json:"selling_price"` + PurchasePrice float64 `json:"purchase_price"` + Stock float64 `json:"stock"` + CreatedAt sql.NullTime `json:"created_at"` + UpdatedAt sql.NullTime `json:"updated_at"` + ProductCategoryID uuid.UUID `json:"product_category_id"` +} + +type ProductCategory struct { + ID uuid.UUID `json:"id"` + MerchantID uuid.UUID `json:"merchant_id"` + IndexID int64 `json:"index_id"` + Name string `json:"name"` } type PurchaseOrder struct { diff --git a/db/sqlc/product_category.sql.go b/db/sqlc/product_category.sql.go new file mode 100644 index 0000000..a9ca918 --- /dev/null +++ b/db/sqlc/product_category.sql.go @@ -0,0 +1,114 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.17.2 +// source: product_category.sql + +package db + +import ( + "context" + + "github.com/google/uuid" +) + +const createProductCategory = `-- name: CreateProductCategory :one +INSERT INTO product_categories ( + merchant_id, + name +) VALUES ( + $1, $2 +) +RETURNING id, merchant_id, index_id, name +` + +type CreateProductCategoryParams struct { + MerchantID uuid.UUID `json:"merchant_id"` + Name string `json:"name"` +} + +func (q *Queries) CreateProductCategory(ctx context.Context, arg CreateProductCategoryParams) (ProductCategory, error) { + row := q.db.QueryRowContext(ctx, createProductCategory, arg.MerchantID, arg.Name) + var i ProductCategory + err := row.Scan( + &i.ID, + &i.MerchantID, + &i.IndexID, + &i.Name, + ) + return i, err +} + +const deleteProductCategory = `-- name: DeleteProductCategory :exec +DELETE FROM product_categories WHERE id = $1 +` + +func (q *Queries) DeleteProductCategory(ctx context.Context, id uuid.UUID) error { + _, err := q.db.ExecContext(ctx, deleteProductCategory, id) + return err +} + +const listProductCategoriesByMerchantID = `-- name: ListProductCategoriesByMerchantID :many +SELECT id, merchant_id, index_id, name FROM product_categories +WHERE merchant_id = $1 +ORDER BY index_id +LIMIT $2 +OFFSET $3 +` + +type ListProductCategoriesByMerchantIDParams struct { + MerchantID uuid.UUID `json:"merchant_id"` + Limit int32 `json:"limit"` + Offset int32 `json:"offset"` +} + +func (q *Queries) ListProductCategoriesByMerchantID(ctx context.Context, arg ListProductCategoriesByMerchantIDParams) ([]ProductCategory, error) { + rows, err := q.db.QueryContext(ctx, listProductCategoriesByMerchantID, arg.MerchantID, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + items := []ProductCategory{} + for rows.Next() { + var i ProductCategory + if err := rows.Scan( + &i.ID, + &i.MerchantID, + &i.IndexID, + &i.Name, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateProductCategory = `-- name: UpdateProductCategory :one +UPDATE product_categories +SET name = $1 +WHERE id = $2 +RETURNING id, merchant_id, index_id, name +` + +type UpdateProductCategoryParams struct { + Name string `json:"name"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateProductCategory(ctx context.Context, arg UpdateProductCategoryParams) (ProductCategory, error) { + row := q.db.QueryRowContext(ctx, updateProductCategory, arg.Name, arg.ID) + var i ProductCategory + err := row.Scan( + &i.ID, + &i.MerchantID, + &i.IndexID, + &i.Name, + ) + return i, err +} diff --git a/db/sqlc/product_category_test.go b/db/sqlc/product_category_test.go new file mode 100644 index 0000000..923dc98 --- /dev/null +++ b/db/sqlc/product_category_test.go @@ -0,0 +1,72 @@ +package db + +import ( + "context" + "testing" + + "git.nochill.in/nochill/naice_pos/util" + "github.com/google/uuid" + "github.com/stretchr/testify/require" +) + +var merchantID = uuid.MustParse("a848090f-0409-4386-9caa-929ae6874dbb") + +func createRandomProductCategory(t *testing.T) ProductCategory { + arg := CreateProductCategoryParams{ + MerchantID: merchantID, + Name: util.RandomString(6), + } + + productCategory, err := testQueries.CreateProductCategory(context.Background(), arg) + require.NoError(t, err) + require.Equal(t, productCategory.Name, arg.Name) + + return productCategory +} + +func TestCreateProductCategory(t *testing.T) { + createRandomProductCategory(t) +} + +func TestListProductCategories(t *testing.T) { + tries := 5 + for i := 0; i < tries; i++ { + createRandomProductCategory(t) + } + + arg := ListProductCategoriesByMerchantIDParams{ + MerchantID: merchantID, + Limit: 5, + Offset: 0, + } + + listProductCategories, err := testQueries.ListProductCategoriesByMerchantID(context.Background(), arg) + require.NoError(t, err) + + for _, productCategory := range listProductCategories { + require.NotEmpty(t, productCategory) + require.Equal(t, merchantID, productCategory.MerchantID) + } +} + +func TestUpdateProductCategory(t *testing.T) { + productCategory := createRandomProductCategory(t) + + arg := UpdateProductCategoryParams{ + Name: util.RandomString(5), + ID: productCategory.ID, + } + + updatedProductCategory, err := testQueries.UpdateProductCategory(context.Background(), arg) + require.NoError(t, err) + + require.NotEqual(t, updatedProductCategory.Name, productCategory.Name) + require.Equal(t, arg.Name, updatedProductCategory.Name) +} + +func TestDeleteProductCategory(t *testing.T) { + productCategory := createRandomProductCategory(t) + + err := testQueries.DeleteProductCategory(context.Background(), productCategory.ID) + require.NoError(t, err) +} diff --git a/db/sqlc/products.sql.go b/db/sqlc/products.sql.go index e7ea1ce..01c1a3d 100644 --- a/db/sqlc/products.sql.go +++ b/db/sqlc/products.sql.go @@ -22,7 +22,7 @@ INSERT INTO products ( ) VALUES ( $1, $2, $3, $4, $5 ) -RETURNING id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at +RETURNING id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id ` type CreateProductParams struct { @@ -52,6 +52,7 @@ func (q *Queries) CreateProduct(ctx context.Context, arg CreateProductParams) (P &i.Stock, &i.CreatedAt, &i.UpdatedAt, + &i.ProductCategoryID, ) return i, err } @@ -66,7 +67,7 @@ func (q *Queries) DeleteProduct(ctx context.Context, id uuid.UUID) error { } const getProduct = `-- name: GetProduct :one -SELECT id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at FROM products +SELECT id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id FROM products WHERE id = $1 ` @@ -83,12 +84,13 @@ func (q *Queries) GetProduct(ctx context.Context, id uuid.UUID) (Product, error) &i.Stock, &i.CreatedAt, &i.UpdatedAt, + &i.ProductCategoryID, ) return i, err } const getStockForUpdateStock = `-- name: GetStockForUpdateStock :one -SELECT id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at FROM products +SELECT id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id FROM products WHERE id = $1 LIMIT 1 FOR NO KEY UPDATE @@ -107,12 +109,13 @@ func (q *Queries) GetStockForUpdateStock(ctx context.Context, id uuid.UUID) (Pro &i.Stock, &i.CreatedAt, &i.UpdatedAt, + &i.ProductCategoryID, ) return i, err } const listProducts = `-- name: ListProducts :many -SELECT id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at FROM products +SELECT id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id FROM products WHERE merchant_id = $1 ORDER BY index_id LIMIT $2 @@ -144,6 +147,7 @@ func (q *Queries) ListProducts(ctx context.Context, arg ListProductsParams) ([]P &i.Stock, &i.CreatedAt, &i.UpdatedAt, + &i.ProductCategoryID, ); err != nil { return nil, err } @@ -162,7 +166,7 @@ const updateProduct = `-- name: UpdateProduct :one UPDATE products SET name = $2, selling_price = $3, purchase_price = $4, updated_at = $5 WHERE id = $1 -RETURNING id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at +RETURNING id, merchant_id, index_id, name, selling_price, purchase_price, stock, created_at, updated_at, product_category_id ` type UpdateProductParams struct { @@ -192,6 +196,7 @@ func (q *Queries) UpdateProduct(ctx context.Context, arg UpdateProductParams) (P &i.Stock, &i.CreatedAt, &i.UpdatedAt, + &i.ProductCategoryID, ) return i, err } diff --git a/db/sqlc/purchase_order.sql.go b/db/sqlc/purchase_order.sql.go index c56de3e..e9bd5d4 100644 --- a/db/sqlc/purchase_order.sql.go +++ b/db/sqlc/purchase_order.sql.go @@ -63,3 +63,69 @@ func (q *Queries) CreatePurchaseOrder(ctx context.Context, arg CreatePurchaseOrd ) return i, err } + +const getPurchaseOrderById = `-- name: GetPurchaseOrderById :one +SELECT id, supplier_id, merchant_id, index_id, code, is_paid, total, paid_nominal, note, created_at, updated_at +FROM purchase_order +WHERE id = $1 +` + +func (q *Queries) GetPurchaseOrderById(ctx context.Context, id uuid.UUID) (PurchaseOrder, error) { + row := q.db.QueryRowContext(ctx, getPurchaseOrderById, id) + var i PurchaseOrder + err := row.Scan( + &i.ID, + &i.SupplierID, + &i.MerchantID, + &i.IndexID, + &i.Code, + &i.IsPaid, + &i.Total, + &i.PaidNominal, + &i.Note, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const listPurchaseOrderByMerchantId = `-- name: ListPurchaseOrderByMerchantId :many +SELECT id, supplier_id, merchant_id, index_id, code, is_paid, total, paid_nominal, note, created_at, updated_at +FROM purchase_order +WHERE merchant_id = $1 +` + +func (q *Queries) ListPurchaseOrderByMerchantId(ctx context.Context, merchantID uuid.UUID) ([]PurchaseOrder, error) { + rows, err := q.db.QueryContext(ctx, listPurchaseOrderByMerchantId, merchantID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []PurchaseOrder{} + for rows.Next() { + var i PurchaseOrder + if err := rows.Scan( + &i.ID, + &i.SupplierID, + &i.MerchantID, + &i.IndexID, + &i.Code, + &i.IsPaid, + &i.Total, + &i.PaidNominal, + &i.Note, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/db/sqlc/purchase_order_detail.sql.go b/db/sqlc/purchase_order_detail.sql.go index 2dee965..9cdcc87 100644 --- a/db/sqlc/purchase_order_detail.sql.go +++ b/db/sqlc/purchase_order_detail.sql.go @@ -59,3 +59,28 @@ func (q *Queries) CreatePurchaseOrderDetail(ctx context.Context, arg CreatePurch ) return i, err } + +const getPurchaseOrderDetailsByPuchaseOrderId = `-- name: GetPurchaseOrderDetailsByPuchaseOrderId :one +SELECT id, index_id, code, merchant_id, purchase_order_id, product_id, quantity, sub_total, product_price, created_at, updated_at +FROM purchase_order_detail +WHERE purchase_order_id = $1 +` + +func (q *Queries) GetPurchaseOrderDetailsByPuchaseOrderId(ctx context.Context, purchaseOrderID uuid.UUID) (PurchaseOrderDetail, error) { + row := q.db.QueryRowContext(ctx, getPurchaseOrderDetailsByPuchaseOrderId, purchaseOrderID) + var i PurchaseOrderDetail + err := row.Scan( + &i.ID, + &i.IndexID, + &i.Code, + &i.MerchantID, + &i.PurchaseOrderID, + &i.ProductID, + &i.Quantity, + &i.SubTotal, + &i.ProductPrice, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/querier.go b/db/sqlc/querier.go index fdc6368..f368ba9 100644 --- a/db/sqlc/querier.go +++ b/db/sqlc/querier.go @@ -14,6 +14,7 @@ type Querier interface { CreateCustomers(ctx context.Context, arg CreateCustomersParams) (Customer, error) CreateMerchant(ctx context.Context, arg CreateMerchantParams) (Merchant, error) CreateProduct(ctx context.Context, arg CreateProductParams) (Product, error) + CreateProductCategory(ctx context.Context, arg CreateProductCategoryParams) (ProductCategory, error) CreatePurchaseOrder(ctx context.Context, arg CreatePurchaseOrderParams) (PurchaseOrder, error) CreatePurchaseOrderDetail(ctx context.Context, arg CreatePurchaseOrderDetailParams) (PurchaseOrderDetail, error) CreateSession(ctx context.Context, arg CreateSessionParams) (UserSession, error) @@ -22,19 +23,25 @@ type Querier interface { CustomersList(ctx context.Context, arg CustomersListParams) ([]Customer, error) DeleteCustomer(ctx context.Context, id uuid.UUID) error DeleteProduct(ctx context.Context, id uuid.UUID) error + DeleteProductCategory(ctx context.Context, id uuid.UUID) error DeleteSupplier(ctx context.Context, id uuid.UUID) error GetMerchantById(ctx context.Context, id uuid.UUID) (Merchant, error) GetMerchantByUserId(ctx context.Context, ownerID uuid.UUID) (Merchant, error) GetPasswordByEmail(ctx context.Context, email string) (string, error) GetProduct(ctx context.Context, id uuid.UUID) (Product, error) + GetPurchaseOrderById(ctx context.Context, id uuid.UUID) (PurchaseOrder, error) + GetPurchaseOrderDetailsByPuchaseOrderId(ctx context.Context, purchaseOrderID uuid.UUID) (PurchaseOrderDetail, error) GetSession(ctx context.Context, id uuid.UUID) (UserSession, error) GetStockForUpdateStock(ctx context.Context, id uuid.UUID) (Product, error) GetUserByEmail(ctx context.Context, email string) (User, error) GetUserById(ctx context.Context, id uuid.UUID) (User, error) + ListProductCategoriesByMerchantID(ctx context.Context, arg ListProductCategoriesByMerchantIDParams) ([]ProductCategory, error) ListProducts(ctx context.Context, arg ListProductsParams) ([]Product, error) + ListPurchaseOrderByMerchantId(ctx context.Context, merchantID uuid.UUID) ([]PurchaseOrder, error) SuppliersList(ctx context.Context, arg SuppliersListParams) ([]Supplier, error) UpdateCustomer(ctx context.Context, id uuid.UUID) (Customer, error) UpdateProduct(ctx context.Context, arg UpdateProductParams) (Product, error) + UpdateProductCategory(ctx context.Context, arg UpdateProductCategoryParams) (ProductCategory, error) UpdateProductStock(ctx context.Context, arg UpdateProductStockParams) error UpdateSupplier(ctx context.Context, id uuid.UUID) (Supplier, error) }