From 9e2ff76c3d52b670502969f07122b7465dcc46e5 Mon Sep 17 00:00:00 2001 From: pahmiudahgede Date: Wed, 7 May 2025 13:29:50 +0700 Subject: [PATCH] feat: add feature coverage area (uncompleted yet) --- config/database.go | 1 + dto/address_dto.go | 2 +- dto/coveragearea_dto.go | 34 ++++++ internal/handler/address_handler.go | 4 +- internal/handler/coveragearea_handler.go | 93 ++++++++++++++++ internal/repositories/coveragearea_repo.go | 69 ++++++++++++ internal/services/coveragearea_service.go | 124 +++++++++++++++++++++ model/coveragearea_model.go | 11 ++ presentation/coveragearea_route.go | 24 ++++ router/setup_routes.go.go | 1 + 10 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 dto/coveragearea_dto.go create mode 100644 internal/handler/coveragearea_handler.go create mode 100644 internal/repositories/coveragearea_repo.go create mode 100644 internal/services/coveragearea_service.go create mode 100644 model/coveragearea_model.go create mode 100644 presentation/coveragearea_route.go diff --git a/config/database.go b/config/database.go index 9f89033..263659e 100644 --- a/config/database.go +++ b/config/database.go @@ -62,6 +62,7 @@ func ConnectDatabase() { &model.InitialCoint{}, &model.About{}, &model.AboutDetail{}, + &model.CoverageArea{}, // =>Trash Model<= &model.TrashCategory{}, diff --git a/dto/address_dto.go b/dto/address_dto.go index eef67f0..bcf5400 100644 --- a/dto/address_dto.go +++ b/dto/address_dto.go @@ -26,7 +26,7 @@ type CreateAddressDTO struct { Geography string `json:"geography"` } -func (r *CreateAddressDTO) Validate() (map[string][]string, bool) { +func (r *CreateAddressDTO) ValidateAddress() (map[string][]string, bool) { errors := make(map[string][]string) if strings.TrimSpace(r.Province) == "" { diff --git a/dto/coveragearea_dto.go b/dto/coveragearea_dto.go new file mode 100644 index 0000000..3d1f46d --- /dev/null +++ b/dto/coveragearea_dto.go @@ -0,0 +1,34 @@ +package dto + +import "strings" + +type RequestCoverageArea struct { + Province string `json:"province"` + Regency string `json:"regency"` +} + +type ResponseCoverageArea struct { + ID string `json:"id"` + Province string `json:"province"` + Regency string `json:"regency"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` +} + +func (r *RequestCoverageArea) ValidateCoverageArea() (map[string][]string, bool) { + errors := make(map[string][]string) + + if strings.TrimSpace(r.Province) == "" { + errors["province"] = append(errors["province"], "nama provinsi harus diisi") + } + + if strings.TrimSpace(r.Regency) == "" { + errors["regency"] = append(errors["regency"], "nama regency harus diisi") + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} diff --git a/internal/handler/address_handler.go b/internal/handler/address_handler.go index 46a550d..de69c47 100644 --- a/internal/handler/address_handler.go +++ b/internal/handler/address_handler.go @@ -22,7 +22,7 @@ func (h *AddressHandler) CreateAddress(c *fiber.Ctx) error { return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) } - errors, valid := requestAddressDTO.Validate() + errors, valid := requestAddressDTO.ValidateAddress() if !valid { return utils.ValidationErrorResponse(c, errors) } @@ -67,7 +67,7 @@ func (h *AddressHandler) UpdateAddress(c *fiber.Ctx) error { return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid body"}}) } - errors, valid := addressDTO.Validate() + errors, valid := addressDTO.ValidateAddress() if !valid { return utils.ValidationErrorResponse(c, errors) } diff --git a/internal/handler/coveragearea_handler.go b/internal/handler/coveragearea_handler.go new file mode 100644 index 0000000..08cb17d --- /dev/null +++ b/internal/handler/coveragearea_handler.go @@ -0,0 +1,93 @@ +package handler + +import ( + "fmt" + "rijig/dto" + "rijig/internal/services" + "rijig/utils" + + "github.com/gofiber/fiber/v2" +) + +type CoverageAreaHandler struct { + service services.CoverageAreaService +} + +func NewCoverageAreaHandler(service services.CoverageAreaService) *CoverageAreaHandler { + return &CoverageAreaHandler{service: service} +} + +func (h *CoverageAreaHandler) CreateCoverageArea(c *fiber.Ctx) error { + var request dto.RequestCoverageArea + if err := c.BodyParser(&request); err != nil { + return utils.ValidationErrorResponse(c, map[string][]string{ + "body": {"Invalid request body"}, + }) + } + + errors, valid := request.ValidateCoverageArea() + if !valid { + return utils.ValidationErrorResponse(c, errors) + } + + response, err := h.service.CreateCoverageArea(request) + if err != nil { + return utils.InternalServerErrorResponse(c, fmt.Sprintf("Error creating coverage area: %v", err)) + } + + return utils.SuccessResponse(c, response, "Coverage area created successfully") +} + +func (h *CoverageAreaHandler) GetCoverageAreaByID(c *fiber.Ctx) error { + id := c.Params("id") + + response, err := h.service.GetCoverageAreaByID(id) + if err != nil { + return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Coverage area with ID %s not found", id)) + } + + return utils.SuccessResponse(c, response, "Coverage area found") +} + +func (h *CoverageAreaHandler) GetAllCoverageAreas(c *fiber.Ctx) error { + + response, err := h.service.GetAllCoverageAreas() + if err != nil { + return utils.InternalServerErrorResponse(c, "Error fetching coverage areas") + } + + return utils.SuccessResponse(c, response, "Coverage areas fetched successfully") +} + +func (h *CoverageAreaHandler) UpdateCoverageArea(c *fiber.Ctx) error { + id := c.Params("id") + var request dto.RequestCoverageArea + if err := c.BodyParser(&request); err != nil { + return utils.ValidationErrorResponse(c, map[string][]string{ + "body": {"Invalid request body"}, + }) + } + + errors, valid := request.ValidateCoverageArea() + if !valid { + return utils.ValidationErrorResponse(c, errors) + } + + response, err := h.service.UpdateCoverageArea(id, request) + if err != nil { + return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Coverage area with ID %s not found", id)) + } + + return utils.SuccessResponse(c, response, "Coverage area updated successfully") +} + +func (h *CoverageAreaHandler) DeleteCoverageArea(c *fiber.Ctx) error { + id := c.Params("id") + + err := h.service.DeleteCoverageArea(id) + if err != nil { + return utils.GenericResponse(c, fiber.StatusNotFound, fmt.Sprintf("Coverage area with ID %s not found", id)) + } + + return utils.GenericResponse(c, fiber.StatusOK, "Coverage area deleted successfully") +} diff --git a/internal/repositories/coveragearea_repo.go b/internal/repositories/coveragearea_repo.go new file mode 100644 index 0000000..1ddf70d --- /dev/null +++ b/internal/repositories/coveragearea_repo.go @@ -0,0 +1,69 @@ +package repositories + +import ( + "fmt" + "rijig/model" + + "gorm.io/gorm" +) + +type CoverageAreaRepository interface { + CreateCoverage(coverage *model.CoverageArea) error + FindCoverageById(id string) (*model.CoverageArea, error) + FindAllCoverage() ([]model.CoverageArea, error) + UpdateCoverage(id string, coverage *model.CoverageArea) error + DeleteCoverage(id string) error +} + +type coverageAreaRepository struct { + DB *gorm.DB +} + +func NewCoverageAreaRepository(db *gorm.DB) CoverageAreaRepository { + return &coverageAreaRepository{DB: db} +} + +func (r *coverageAreaRepository) CreateCoverage(coverage *model.CoverageArea) error { + if err := r.DB.Create(coverage).Error; err != nil { + return fmt.Errorf("failed to create coverage: %v", err) + } + return nil +} + +func (r *coverageAreaRepository) FindCoverageById(id string) (*model.CoverageArea, error) { + var coverage model.CoverageArea + err := r.DB.Where("id = ?", id).First(&coverage).Error + if err != nil { + if err == gorm.ErrRecordNotFound { + return nil, fmt.Errorf("coverage with ID %s not found", id) + } + return nil, fmt.Errorf("failed to fetch coverage by ID: %v", err) + } + return &coverage, nil +} + +func (r *coverageAreaRepository) FindAllCoverage() ([]model.CoverageArea, error) { + var coverage []model.CoverageArea + err := r.DB.Find(&coverage).Error + if err != nil { + return nil, fmt.Errorf("failed to fetch coverage: %v", err) + } + + return coverage, nil +} + +func (r *coverageAreaRepository) UpdateCoverage(id string, coverage *model.CoverageArea) error { + err := r.DB.Model(&model.CoverageArea{}).Where("id = ?", id).Updates(coverage).Error + if err != nil { + return fmt.Errorf("failed to update coverage: %v", err) + } + return nil +} + +func (r *coverageAreaRepository) DeleteCoverage(id string) error { + result := r.DB.Delete(&model.CoverageArea{}, "id = ?", id) + if result.Error != nil { + return fmt.Errorf("failed to delete coverage: %v", result.Error) + } + return nil +} diff --git a/internal/services/coveragearea_service.go b/internal/services/coveragearea_service.go new file mode 100644 index 0000000..f80faea --- /dev/null +++ b/internal/services/coveragearea_service.go @@ -0,0 +1,124 @@ +package services + +import ( + "fmt" + "log" + "rijig/dto" + "rijig/internal/repositories" + "rijig/model" + "rijig/utils" +) + +type CoverageAreaService interface { + CreateCoverageArea(request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) + GetCoverageAreaByID(id string) (*dto.ResponseCoverageArea, error) + GetAllCoverageAreas() ([]dto.ResponseCoverageArea, error) + UpdateCoverageArea(id string, request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) + DeleteCoverageArea(id string) error +} + +type coverageAreaService struct { + repo repositories.CoverageAreaRepository +} + +func NewCoverageAreaService(repo repositories.CoverageAreaRepository) CoverageAreaService { + return &coverageAreaService{repo: repo} +} + +func ConvertCoverageAreaToResponse(coverage *model.CoverageArea) *dto.ResponseCoverageArea { + createdAt, _ := utils.FormatDateToIndonesianFormat(coverage.CreatedAt) + updatedAt, _ := utils.FormatDateToIndonesianFormat(coverage.UpdatedAt) + + return &dto.ResponseCoverageArea{ + ID: coverage.ID, + Province: coverage.Province, + Regency: coverage.Regency, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + } +} + +func (s *coverageAreaService) CreateCoverageArea(request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) { + errors, valid := request.ValidateCoverageArea() + if !valid { + return nil, fmt.Errorf("validation errors: %v", errors) + } + + coverage := model.CoverageArea{ + Province: request.Province, + Regency: request.Regency, + } + + if err := s.repo.CreateCoverage(&coverage); err != nil { + return nil, fmt.Errorf("failed to create coverage area: %v", err) + } + + response := ConvertCoverageAreaToResponse(&coverage) + + return response, nil +} + +func (s *coverageAreaService) GetCoverageAreaByID(id string) (*dto.ResponseCoverageArea, error) { + coverage, err := s.repo.FindCoverageById(id) + if err != nil { + return nil, err + } + + response := ConvertCoverageAreaToResponse(coverage) + + return response, nil +} + +func (s *coverageAreaService) GetAllCoverageAreas() ([]dto.ResponseCoverageArea, error) { + coverageAreas, err := s.repo.FindAllCoverage() + if err != nil { + return nil, err + } + + var response []dto.ResponseCoverageArea + for _, coverage := range coverageAreas { + + response = append(response, *ConvertCoverageAreaToResponse(&coverage)) + } + + return response, nil +} + +func (s *coverageAreaService) UpdateCoverageArea(id string, request dto.RequestCoverageArea) (*dto.ResponseCoverageArea, error) { + + errors, valid := request.ValidateCoverageArea() + if !valid { + return nil, fmt.Errorf("validation errors: %v", errors) + } + + coverage, err := s.repo.FindCoverageById(id) + if err != nil { + return nil, fmt.Errorf("coverage area with ID %s not found: %v", id, err) + } + + coverage.Province = request.Province + coverage.Regency = request.Regency + + if err := s.repo.UpdateCoverage(id, coverage); err != nil { + return nil, fmt.Errorf("failed to update coverage area: %v", err) + } + + response := ConvertCoverageAreaToResponse(coverage) + + return response, nil +} + +func (s *coverageAreaService) DeleteCoverageArea(id string) error { + + coverage, err := s.repo.FindCoverageById(id) + if err != nil { + return fmt.Errorf("coverage area with ID %s not found: %v", id, err) + } + + if err := s.repo.DeleteCoverage(id); err != nil { + return fmt.Errorf("failed to delete coverage area: %v", err) + } + + log.Printf("Coverage area with ID %s successfully deleted", coverage.ID) + return nil +} diff --git a/model/coveragearea_model.go b/model/coveragearea_model.go new file mode 100644 index 0000000..4cff160 --- /dev/null +++ b/model/coveragearea_model.go @@ -0,0 +1,11 @@ +package model + +import "time" + +type CoverageArea struct { + ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"` + Province string `gorm:"not null" json:"province"` + Regency string `gorm:"not null" json:"regency"` + CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"` + UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"` +} diff --git a/presentation/coveragearea_route.go b/presentation/coveragearea_route.go new file mode 100644 index 0000000..aa91c14 --- /dev/null +++ b/presentation/coveragearea_route.go @@ -0,0 +1,24 @@ +package presentation + +import ( + "rijig/config" + "rijig/internal/handler" + "rijig/internal/repositories" + "rijig/internal/services" + + "github.com/gofiber/fiber/v2" +) + +func CoverageAreaRouter(api fiber.Router) { + coverageAreaRepo := repositories.NewCoverageAreaRepository(config.DB) + coverageAreaService := services.NewCoverageAreaService(coverageAreaRepo) + coverageAreaHandler := handler.NewCoverageAreaHandler(coverageAreaService) + + coverage := api.Group("/coveragearea") + + coverage.Post("/", coverageAreaHandler.CreateCoverageArea) + coverage.Get("/", coverageAreaHandler.GetAllCoverageAreas) + coverage.Get("/:id", coverageAreaHandler.GetCoverageAreaByID) + coverage.Put("/:id", coverageAreaHandler.UpdateCoverageArea) + coverage.Delete("/:id", coverageAreaHandler.DeleteCoverageArea) +} diff --git a/router/setup_routes.go.go b/router/setup_routes.go.go index a1f0305..f313766 100644 --- a/router/setup_routes.go.go +++ b/router/setup_routes.go.go @@ -36,6 +36,7 @@ func SetupRoutes(app *fiber.App) { presentation.InitialCointRoute(api) presentation.AboutRouter(api) presentation.TrashRouter(api) + presentation.CoverageAreaRouter(api) presentation.StoreRouter(api) presentation.ProductRouter(api) }