diff --git a/api/handlers/products/router.go b/api/handlers/products/router.go index f602b17..8e35fb3 100644 --- a/api/handlers/products/router.go +++ b/api/handlers/products/router.go @@ -1,14 +1,12 @@ package handler_products import ( - "log" "online-order/entity" "online-order/repository/product" "online-order/usecase/product" ) func NewProductRouters(server *entity.Routers) { - log.Printf("server: %v", server.ActiveBusiness) productRepo := repository_product.NewProductClient(server.Database, &server.ActiveBusiness) productService := service_product.NewProductService(productRepo) diff --git a/api/router.go b/api/router.go index 6a115c6..1dc5dc1 100644 --- a/api/router.go +++ b/api/router.go @@ -8,6 +8,7 @@ import ( handler_products "online-order/api/handlers/products" "online-order/api/middlewares" middlewares_log "online-order/api/middlewares/log" + "online-order/database/seeds" docs "online-order/docs" "online-order/ent" "online-order/entity" @@ -29,6 +30,9 @@ func Router(app *gin.Engine, db *ent.Client) { RestrictedApp: api_restricted, } + seeds.FillProductCategories(router) + seeds.FillProducts(router) + middlewares_log.SetOutputLogFile() logFile, _ := middlewares_log.OpenFile("storage/logs/request.log") diff --git a/database/seeds/fillTables.go b/database/seeds/fillTables.go new file mode 100644 index 0000000..ca0d011 --- /dev/null +++ b/database/seeds/fillTables.go @@ -0,0 +1,67 @@ +package seeds + +import ( + "log" + "online-order/entity" + repository_product "online-order/repository/product" + repository_product_category "online-order/repository/product_category" + service_product "online-order/usecase/product" + service_product_category "online-order/usecase/product_category" +) + +func fetchProductsFromJsonFile() *[]entity.ProductCreateUpdate { + file := CreateFile("database/seeds/resources/products.json") + pl := []entity.ProductCreateUpdate{} + + if err := file.ReadJson(&pl); err != nil { + log.Println("on FillProducts an error occured: ", err) + return nil + } + return &pl +} + +func fetchProductCategoriesFromJsonFile() *[]entity.ProductCategoryCreateUpdate { + file := CreateFile("database/seeds/resources/categories.json") + pl := []entity.ProductCategoryCreateUpdate{} + if err := file.ReadJson(&pl); err != nil { + log.Println("on FillProducts an error occured: ", err) + return nil + } + return &pl +} + +func FillProductCategories(server *entity.Routers) { + productCategories := fetchProductCategoriesFromJsonFile() + + activeBusiness := entity.ActiveBusiness{ + BusinessID: 1, + DomainID: 1, + Domain: "localhost", + } + + productCategoryRepo := repository_product_category.NewProductCategoryClient(server.Database, &activeBusiness) + + productCategoryService := service_product_category.NewProductCategoryService(productCategoryRepo) + + for _, item := range *productCategories { + productCategoryService.SyncWithSlug(item.Slug, &item) + } +} + +func FillProducts(server *entity.Routers) { + products := fetchProductsFromJsonFile() + + activeBusiness := entity.ActiveBusiness{ + BusinessID: 1, + DomainID: 1, + Domain: "localhost", + } + + productRepo := repository_product.NewProductClient(server.Database, &activeBusiness) + + productService := service_product.NewProductService(productRepo) + + for _, item := range *products { + productService.Create(&item) + } +} diff --git a/database/seeds/jsonHandler.go b/database/seeds/jsonHandler.go new file mode 100644 index 0000000..77c6684 --- /dev/null +++ b/database/seeds/jsonHandler.go @@ -0,0 +1,30 @@ +package seeds + +import ( + "encoding/json" + "io/ioutil" + "log" +) + +type file struct { + filePath string +} + +func CreateFile(filePath string) *file { + return &file{ + filePath: filePath, + } +} + +func (f file) ReadJson(obj interface{}) error { + if content, err := ioutil.ReadFile(f.filePath); err != nil { + log.Println("on ReadJson an error occured: ", err) + return err + } else { + if err := json.Unmarshal(content, &obj); err != nil { + log.Println("on ReadJson an error occured: ", err) + return err + } + } + return nil +} diff --git a/database/seeds/resources/categories.json b/database/seeds/resources/categories.json new file mode 100644 index 0000000..e6e03e9 --- /dev/null +++ b/database/seeds/resources/categories.json @@ -0,0 +1,34 @@ +[ + { + "id": 1, + "name": "Digital", + "slug": "digital", + "status": true, + "description": "digital", + "business_id": 1 + }, + { + "id": 2, + "name": "Washer", + "slug": "washer", + "status": true, + "description": "washer", + "business_id": 1 + }, + { + "id": 3, + "name": "Accessory", + "slug": "accessory", + "status": true, + "description": "accessory", + "business_id": 1 + }, + { + "id": 4, + "name": "Stationery", + "slug": "stationery", + "status": true, + "description": "stationery", + "business_id": 1 + } +] \ No newline at end of file diff --git a/database/seeds/resources/products.json b/database/seeds/resources/products.json new file mode 100644 index 0000000..2ba971a --- /dev/null +++ b/database/seeds/resources/products.json @@ -0,0 +1,98 @@ +[ + { + "name": "laptop", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "Asus Laptop", + "summary": "Asus Laptop", + "product_category_id": 1, + "business_id": 1, + "user_id": 1 + }, + { + "name": "Hair shampoo", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "Hair Shampoo", + "summary": "Hair Shampoo", + "product_category_id": 2, + "business_id": 1, + "user_id": 1 + }, + { + "name": "Body Shampoo", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "Body Shampoo", + "summary": "Body Shampoo", + "product_category_id": 2, + "business_id": 1, + "user_id": 1 + }, + { + "name": "camera", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "Sony Camera", + "summary": "Sony Camera", + "product_category_id": 1, + "business_id": 1, + "user_id": 1 + }, + { + "name": "sunglasses", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "zenit sunglasses", + "summary": "zenit sunglasses", + "product_category_id": 3, + "business_id": 1, + "user_id": 1 + }, + { + "name": "pen", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "Blue pen", + "summary": "Blue pen", + "product_category_id": 4, + "business_id": 1, + "user_id": 1 + }, + { + "name": "Black pen", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "black pen", + "summary": "black pen", + "product_category_id": 4, + "business_id": 1, + "user_id": 1 + }, + { + "name": "Red pen", + "price": 200, + "original_price": 300, + "quantity": 5, + "status": true, + "description": "red pen", + "summary": "black pen", + "product_category_id": 4, + "business_id": 1, + "user_id": 1 + } +] \ No newline at end of file diff --git a/domain/product_category.go b/domain/product_category.go new file mode 100644 index 0000000..d1aaceb --- /dev/null +++ b/domain/product_category.go @@ -0,0 +1,34 @@ +package domain + +import ( + "github.com/gin-gonic/gin" + "online-order/entity" +) + +type ProductCategoryRepository interface { + List() ([]*entity.ProductCategoryDisplay, error) + Create(p *entity.ProductCategoryCreateUpdate) error + GetByID(id int) (*entity.ProductCategoryDisplay, error) + GetBySlug(slug string) (*entity.ProductCategoryDisplay, error) + SearchProductCategory(identifier string) (*entity.ProductCategoryDisplay, error) + Update(p *entity.ProductCategoryCreateUpdate) error + Delete(id int) error +} + +type ProductCategoryService interface { + List() ([]*entity.ProductCategoryDisplay, error) + Create(u *entity.ProductCategoryCreateUpdate) error + GetByID(id int) (*entity.ProductCategoryDisplay, error) + GetBySlug(slug string) (*entity.ProductCategoryDisplay, error) + SyncWithSlug(slug string, p *entity.ProductCategoryCreateUpdate) error + SearchProductCategory(identifier string) (*entity.ProductCategoryDisplay, error) + Update(u *entity.ProductCategoryCreateUpdate) error + Delete(id int) error +} + +type ProductCategoryController interface { + listProductCategory(ctx *gin.Context) + getProductCategory(ctx *gin.Context) + updateProductCategory(ctx *gin.Context) + deleteProductCategory(ctx *gin.Context) +} diff --git a/entity/product.go b/entity/product.go index 9010a1a..86956de 100644 --- a/entity/product.go +++ b/entity/product.go @@ -6,20 +6,24 @@ import ( // use to display a product type ProductDisplay struct { - ID int `json:"id"` - Name string `json:"name"` - Description *string `json:"description"` - Price float64 `json:"price"` - OriginalPrice float64 `json:"original_price"` - Quantity int `json:"quantity"` - Status bool `json:"status"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID int `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + Summary *string `json:"summary"` + Price float64 `json:"price"` + OriginalPrice float64 `json:"original_price"` + Quantity int `json:"quantity"` + Status bool `json:"status"` + UserID int `json:"user_id"` + ProductCategoryID int `json:"product_category_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } // use to create or update a product type ProductCreateUpdate struct { ProductDisplay + BusinessID int `json:"business_id"` } // Func that will check non empty field on ProductDisplay and update product diff --git a/entity/product_category.go b/entity/product_category.go new file mode 100644 index 0000000..0a9d253 --- /dev/null +++ b/entity/product_category.go @@ -0,0 +1,50 @@ +package entity + +import ( + "time" +) + +// use to display a product +type ProductCategoryDisplay struct { + ID int `json:"id"` + Name string `json:"name"` + Slug string `json:"slug"` + Description *string `json:"description"` + Summary *string `json:"summary"` + Status bool `json:"status"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// use to create or update a product +type ProductCategoryCreateUpdate struct { + ProductCategoryDisplay + BusinessID int `json:"business_id"` +} + +// Func that will check non empty field on ProductDisplay and update product +func ValidateProductCategoryUpdate(product *ProductCategoryCreateUpdate, p *ProductCategoryDisplay) *ProductCategoryCreateUpdate { + product.ID = p.ID + product.Name = p.Name + product.Description = p.Description + product.Summary = p.Summary + product.Status = p.Status + product.CreatedAt = p.CreatedAt + product.UpdatedAt = p.UpdatedAt + + return product +} + +func ProductCategoryDisplayFormatter(product *ProductCategoryCreateUpdate) (p *ProductCategoryDisplay) { + p = &ProductCategoryDisplay{ + ID: product.ID, + Name: product.Name, + Description: product.Description, + Summary: product.Summary, + Status: product.Status, + CreatedAt: product.CreatedAt, + UpdatedAt: product.UpdatedAt, + } + + return +} diff --git a/repository/product/product.go b/repository/product/product.go index f017efd..cc93d18 100644 --- a/repository/product/product.go +++ b/repository/product/product.go @@ -19,16 +19,6 @@ func NewProductClient(client *ent.Client, activeBusiness *entity.ActiveBusiness) } } -//type ProductClient struct { -// client *ent.Client -//} -// -//func NewProductClient(client *ent.Client) *ProductClient { -// return &ProductClient{ -// client: client, -// } -//} - // List all products func (c *ProductClient) List() ([]*entity.ProductDisplay, error) { var u []*entity.ProductDisplay @@ -58,7 +48,10 @@ func (c *ProductClient) Create(p *entity.ProductCreateUpdate) error { SetNillableDescription(p.Description). SetPrice(p.Price). SetOriginalPrice(p.OriginalPrice). + SetNillableSummary(p.Summary). SetQuantity(p.Quantity). + SetProductCategoryID(p.ProductCategoryID). + SetUserID(p.UserID). SetStatus(p.Status). Save(ctx) diff --git a/repository/product_category/product_category.go b/repository/product_category/product_category.go new file mode 100644 index 0000000..ac6bad6 --- /dev/null +++ b/repository/product_category/product_category.go @@ -0,0 +1,162 @@ +package repository_product_category + +import ( + "context" + "online-order/ent" + "online-order/ent/productcategory" + "online-order/entity" +) + +type ProductCategoryClient struct { + client *ent.Client + activeBusiness *entity.ActiveBusiness +} + +func NewProductCategoryClient(client *ent.Client, activeBusiness *entity.ActiveBusiness) *ProductCategoryClient { + return &ProductCategoryClient{ + client: client, + activeBusiness: activeBusiness, + } +} + +// List all productCategories +func (c *ProductCategoryClient) List() ([]*entity.ProductCategoryDisplay, error) { + var u []*entity.ProductCategoryDisplay + ctx := context.Background() + + err := c.client.ProductCategory. + Query(). + Where(productcategory.BusinessID(c.activeBusiness.BusinessID)). + Select(productcategory.FieldID, productcategory.FieldName, productcategory.FieldDescription, productcategory.FieldStatus, productcategory.FieldCreatedAt, productcategory.FieldUpdatedAt). + Scan(ctx, &u) + + if err != nil { + return nil, err + } + + return u, nil +} + +// Create a productcategory +func (c *ProductCategoryClient) Create(p *entity.ProductCategoryCreateUpdate) error { + ctx := context.Background() + + resp, err := c.client.ProductCategory. + Create(). + SetName(p.Name). + SetSlug(p.Slug). + SetBusinessID(c.activeBusiness.BusinessID). + SetNillableDescription(p.Description). + SetStatus(p.Status). + Save(ctx) + + if err != nil { + return err + } + + p.ID = resp.ID + p.CreatedAt = resp.CreatedAt + p.UpdatedAt = resp.UpdatedAt + return nil +} + +func (c *ProductCategoryClient) GetByID(id int) (*entity.ProductCategoryDisplay, error) { + var p entity.ProductCategoryDisplay + ctx := context.Background() + + resp := c.client.ProductCategory. + Query(). + Where(productcategory.BusinessID(c.activeBusiness.BusinessID)). + Where(productcategory.ID(id)). + AllX(ctx) + + if len(resp) > 0 { + p.ID = resp[0].ID + p.Name = resp[0].Name + p.Description = resp[0].Description + p.Status = resp[0].Status + p.CreatedAt = resp[0].CreatedAt + p.UpdatedAt = resp[0].UpdatedAt + } else { + return nil, entity.ErrNotFound + } + + return &p, nil +} + +func (c *ProductCategoryClient) GetBySlug(slug string) (*entity.ProductCategoryDisplay, error) { + var p entity.ProductCategoryDisplay + ctx := context.Background() + + resp := c.client.ProductCategory. + Query(). + Where(productcategory.BusinessID(c.activeBusiness.BusinessID)). + Where(productcategory.Slug(slug)). + AllX(ctx) + + if len(resp) > 0 { + p.ID = resp[0].ID + p.Name = resp[0].Name + p.Description = resp[0].Description + p.Status = resp[0].Status + p.CreatedAt = resp[0].CreatedAt + p.UpdatedAt = resp[0].UpdatedAt + } else { + return nil, entity.ErrNotFound + } + + return &p, nil +} + +// Update productcategory information, except password +func (c *ProductCategoryClient) Update(p *entity.ProductCategoryCreateUpdate) error { + ctx := context.Background() + + _, err := c.client.ProductCategory.UpdateOneID(p.ID). + SetName(p.Name). + SetDescription(p.Name). + SetStatus(p.Status). + Save(ctx) + if err != nil { + return err + } + return nil +} + +// Update user information, except password +func (c *ProductCategoryClient) Delete(id int) error { + ctx := context.Background() + + err := c.client.ProductCategory. + DeleteOneID(id). + Exec(ctx) + return err +} + +// Search a user information by email or username +func (c *ProductCategoryClient) SearchProductCategory(identifier string) (*entity.ProductCategoryDisplay, error) { + var p entity.ProductCategoryDisplay + ctx := context.Background() + + resp := c.client.ProductCategory. + Query(). + Where(productcategory.BusinessID(c.activeBusiness.BusinessID)). + Where( + productcategory.NameContains(identifier), + ). + AllX(ctx) + + if len(resp) > 0 { + p.ID = resp[0].ID + p.Name = resp[0].Name + p.Description = resp[0].Description + p.Status = resp[0].Status + p.CreatedAt = resp[0].CreatedAt + p.UpdatedAt = resp[0].UpdatedAt + + } else { + return nil, entity.ErrNotFound + } + + return &p, nil +} diff --git a/usecase/product/service.go b/usecase/product/service.go index da06f47..1a22366 100644 --- a/usecase/product/service.go +++ b/usecase/product/service.go @@ -19,8 +19,8 @@ func (s *productservice) List() ([]*entity.ProductDisplay, error) { return s.repo.List() } -func (s *productservice) Create(u *entity.ProductCreateUpdate) error { - return s.repo.Create(u) +func (s *productservice) Create(p *entity.ProductCreateUpdate) error { + return s.repo.Create(p) } // Retrieve a product @@ -32,8 +32,8 @@ func (s *productservice) GetByID(id int) (*entity.ProductDisplay, error) { return u, nil } -func (s *productservice) Update(u *entity.ProductCreateUpdate) error { - return s.repo.Update(u) +func (s *productservice) Update(p *entity.ProductCreateUpdate) error { + return s.repo.Update(p) } func (s *productservice) SearchProduct(identifier string) (*entity.ProductDisplay, error) { diff --git a/usecase/product_category/service.go b/usecase/product_category/service.go new file mode 100644 index 0000000..f1a0ab5 --- /dev/null +++ b/usecase/product_category/service.go @@ -0,0 +1,65 @@ +package service_product_category + +import ( + "online-order/domain" + "online-order/entity" +) + +type productCategoryService struct { + repo domain.ProductCategoryRepository +} + +func NewProductCategoryService(r domain.ProductCategoryRepository) *productCategoryService { + return &productCategoryService{ + repo: r, + } +} + +func (s *productCategoryService) List() ([]*entity.ProductCategoryDisplay, error) { + return s.repo.List() +} + +func (s *productCategoryService) Create(u *entity.ProductCategoryCreateUpdate) error { + return s.repo.Create(u) +} + +// Retrieve a product +func (s *productCategoryService) GetByID(id int) (*entity.ProductCategoryDisplay, error) { + u, err := s.repo.GetByID(id) + if err != nil { + return &entity.ProductCategoryDisplay{}, entity.ErrNotFound + } + return u, nil +} + +func (s *productCategoryService) GetBySlug(slug string) (*entity.ProductCategoryDisplay, error) { + u, err := s.repo.GetBySlug(slug) + if err != nil { + return &entity.ProductCategoryDisplay{}, entity.ErrNotFound + } + return u, nil +} + +func (s *productCategoryService) Update(p *entity.ProductCategoryCreateUpdate) error { + return s.repo.Update(p) +} + +func (s *productCategoryService) SearchProduct(identifier string) (*entity.ProductCategoryDisplay, error) { + return s.repo.SearchProductCategory(identifier) +} + +func (s *productCategoryService) SyncWithSlug(slug string, p *entity.ProductCategoryCreateUpdate) error { + pc, _ := s.repo.GetBySlug(slug) + + if pc != nil { + p.ID = pc.ID + p.Slug = pc.Slug + return s.repo.Update(p) + } else { + return s.repo.Create(p) + } +} + +func (s *productCategoryService) Delete(id int) error { + return s.repo.Delete(id) +}