From 9a2481be092a1f93d58aaaa8d0bbbf5aae9c3922 Mon Sep 17 00:00:00 2001 From: pahmiudahgede Date: Mon, 5 May 2025 18:56:48 +0700 Subject: [PATCH] feat: company profile feature --- dto/company_profile_dto.go | 65 +++++++ internal/handler/company_profile_handler.go | 100 +++++++++++ internal/repositories/company_profile_repo.go | 78 +++++++++ internal/services/company_profile_service.go | 163 ++++++++++++++++++ internal/services/identitycard_service.go | 15 +- model/company_profile_model.go | 11 +- presentation/auth/auth_admin_route.go | 2 +- presentation/company_profile_route.go | 27 +++ presentation/identitycard_route.go | 3 +- router/setup_routes.go.go | 3 +- 10 files changed, 457 insertions(+), 10 deletions(-) create mode 100644 dto/company_profile_dto.go create mode 100644 internal/handler/company_profile_handler.go create mode 100644 internal/repositories/company_profile_repo.go create mode 100644 internal/services/company_profile_service.go create mode 100644 presentation/company_profile_route.go diff --git a/dto/company_profile_dto.go b/dto/company_profile_dto.go new file mode 100644 index 0000000..dacd91d --- /dev/null +++ b/dto/company_profile_dto.go @@ -0,0 +1,65 @@ +package dto + +import ( + "strings" +) + +type ResponseCompanyProfileDTO struct { + ID string `json:"id"` + UserID string `json:"userId"` + CompanyName string `json:"company_name"` + CompanyAddress string `json:"company_address"` + CompanyPhone string `json:"company_phone"` + CompanyEmail string `json:"company_email"` + CompanyLogo string `json:"company_logo,omitempty"` + CompanyWebsite string `json:"company_website,omitempty"` + TaxID string `json:"taxId,omitempty"` + FoundedDate string `json:"founded_date,omitempty"` + CompanyType string `json:"company_type,omitempty"` + CompanyDescription string `json:"company_description"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` +} + +type RequestCompanyProfileDTO struct { + CompanyName string `json:"company_name"` + CompanyAddress string `json:"company_address"` + CompanyPhone string `json:"company_phone"` + CompanyEmail string `json:"company_email"` + CompanyLogo string `json:"company_logo,omitempty"` + CompanyWebsite string `json:"company_website,omitempty"` + TaxID string `json:"taxId,omitempty"` + FoundedDate string `json:"founded_date,omitempty"` + CompanyType string `json:"company_type,omitempty"` + CompanyDescription string `json:"company_description"` +} + +func (r *RequestCompanyProfileDTO) ValidateCompanyProfileInput() (map[string][]string, bool) { + errors := make(map[string][]string) + + if strings.TrimSpace(r.CompanyName) == "" { + errors["company_Name"] = append(errors["company_name"], "Company name is required") + } + + if strings.TrimSpace(r.CompanyAddress) == "" { + errors["company_Address"] = append(errors["company_address"], "Company address is required") + } + + if strings.TrimSpace(r.CompanyPhone) == "" { + errors["company_Phone"] = append(errors["company_phone"], "Company phone is required") + } + + if strings.TrimSpace(r.CompanyEmail) == "" { + errors["company_Email"] = append(errors["company_email"], "Company email is required") + } + + if strings.TrimSpace(r.CompanyDescription) == "" { + errors["company_Description"] = append(errors["company_description"], "Company description is required") + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} diff --git a/internal/handler/company_profile_handler.go b/internal/handler/company_profile_handler.go new file mode 100644 index 0000000..2d8d7aa --- /dev/null +++ b/internal/handler/company_profile_handler.go @@ -0,0 +1,100 @@ +package handler + +import ( + "fmt" + "rijig/dto" + "rijig/internal/services" + "rijig/utils" + + "github.com/gofiber/fiber/v2" +) + +type CompanyProfileHandler struct { + companyProfileService services.CompanyProfileService +} + +func NewCompanyProfileHandler(service services.CompanyProfileService) *CompanyProfileHandler { + return &CompanyProfileHandler{ + companyProfileService: service, + } +} + +func (h *CompanyProfileHandler) CreateCompanyProfile(c *fiber.Ctx) error { + userID, ok := c.Locals("userID").(string) + if !ok || userID == "" { + return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") + } + + var requestDTO dto.RequestCompanyProfileDTO + if err := c.BodyParser(&requestDTO); err != nil { + return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid input data"}}) + } + + companyProfileResponse, err := h.companyProfileService.CreateCompanyProfile(userID, &requestDTO) + if err != nil { + return utils.ErrorResponse(c, fmt.Sprintf("Failed to create company profile: %v", err)) + } + + return utils.SuccessResponse(c, companyProfileResponse, "Company profile created successfully") +} + +func (h *CompanyProfileHandler) GetCompanyProfileByID(c *fiber.Ctx) error { + id := c.Params("company_id") + + companyProfileResponse, err := h.companyProfileService.GetCompanyProfileByID(id) + if err != nil { + return utils.ErrorResponse(c, fmt.Sprintf("Failed to fetch company profile: %v", err)) + } + + return utils.SuccessResponse(c, companyProfileResponse, "Company profile fetched successfully") +} + +func (h *CompanyProfileHandler) GetCompanyProfilesByUserID(c *fiber.Ctx) error { + userID, ok := c.Locals("userID").(string) + if !ok || userID == "" { + return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") + } + + companyProfilesResponse, err := h.companyProfileService.GetCompanyProfilesByUserID(userID) + if err != nil { + return utils.ErrorResponse(c, fmt.Sprintf("Failed to fetch company profiles: %v", err)) + } + + return utils.NonPaginatedResponse(c, companyProfilesResponse, len(companyProfilesResponse), "Company profiles fetched successfully") +} + +func (h *CompanyProfileHandler) UpdateCompanyProfile(c *fiber.Ctx) error { + userID, ok := c.Locals("userID").(string) + if !ok || userID == "" { + return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") + } + + id := c.Params("company_id") + + var requestDTO dto.RequestCompanyProfileDTO + if err := c.BodyParser(&requestDTO); err != nil { + return utils.ValidationErrorResponse(c, map[string][]string{"body": {"Invalid input data"}}) + } + + companyProfileResponse, err := h.companyProfileService.UpdateCompanyProfile(id, &requestDTO) + if err != nil { + return utils.ErrorResponse(c, fmt.Sprintf("Failed to update company profile: %v", err)) + } + + return utils.SuccessResponse(c, companyProfileResponse, "Company profile updated successfully") +} + +func (h *CompanyProfileHandler) DeleteCompanyProfile(c *fiber.Ctx) error { + userID, ok := c.Locals("userID").(string) + if !ok || userID == "" { + return utils.GenericResponse(c, fiber.StatusUnauthorized, "Unauthorized: User session not found") + } + id := c.Params("company_id") + + err := h.companyProfileService.DeleteCompanyProfile(id) + if err != nil { + return utils.ErrorResponse(c, fmt.Sprintf("Failed to delete company profile: %v", err)) + } + + return utils.SuccessResponse(c, nil, "Company profile deleted successfully") +} diff --git a/internal/repositories/company_profile_repo.go b/internal/repositories/company_profile_repo.go new file mode 100644 index 0000000..bf0d4ea --- /dev/null +++ b/internal/repositories/company_profile_repo.go @@ -0,0 +1,78 @@ +package repositories + +import ( + "fmt" + "rijig/model" + + "gorm.io/gorm" +) + +type CompanyProfileRepository interface { + CreateCompanyProfile(companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) + GetCompanyProfileByID(id string) (*model.CompanyProfile, error) + GetCompanyProfilesByUserID(userID string) ([]model.CompanyProfile, error) + UpdateCompanyProfile(id string, companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) + DeleteCompanyProfile(id string) error +} + +type companyProfileRepository struct { + DB *gorm.DB +} + +func NewCompanyProfileRepository(db *gorm.DB) CompanyProfileRepository { + return &companyProfileRepository{ + DB: db, + } +} + +func (r *companyProfileRepository) CreateCompanyProfile(companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) { + err := r.DB.Create(companyProfile).Error + if err != nil { + return nil, fmt.Errorf("failed to create company profile: %v", err) + } + return companyProfile, nil +} + +func (r *companyProfileRepository) GetCompanyProfileByID(id string) (*model.CompanyProfile, error) { + var companyProfile model.CompanyProfile + err := r.DB.Preload("User").First(&companyProfile, "id = ?", id).Error + if err != nil { + if err == gorm.ErrRecordNotFound { + return nil, fmt.Errorf("company profile with ID %s not found", id) + } + return nil, fmt.Errorf("error fetching company profile: %v", err) + } + return &companyProfile, nil +} + +func (r *companyProfileRepository) GetCompanyProfilesByUserID(userID string) ([]model.CompanyProfile, error) { + var companyProfiles []model.CompanyProfile + err := r.DB.Preload("User").Where("user_id = ?", userID).Find(&companyProfiles).Error + if err != nil { + return nil, fmt.Errorf("error fetching company profiles for userID %s: %v", userID, err) + } + return companyProfiles, nil +} + +func (r *companyProfileRepository) UpdateCompanyProfile(id string, companyProfile *model.CompanyProfile) (*model.CompanyProfile, error) { + var existingProfile model.CompanyProfile + err := r.DB.First(&existingProfile, "id = ?", id).Error + if err != nil { + return nil, fmt.Errorf("company profile not found: %v", err) + } + + err = r.DB.Model(&existingProfile).Updates(companyProfile).Error + if err != nil { + return nil, fmt.Errorf("failed to update company profile: %v", err) + } + + return &existingProfile, nil +} + +func (r *companyProfileRepository) DeleteCompanyProfile(id string) error { + err := r.DB.Delete(&model.CompanyProfile{}, "id = ?", id).Error + if err != nil { + return fmt.Errorf("failed to delete company profile: %v", err) + } + return nil +} diff --git a/internal/services/company_profile_service.go b/internal/services/company_profile_service.go new file mode 100644 index 0000000..6c2714b --- /dev/null +++ b/internal/services/company_profile_service.go @@ -0,0 +1,163 @@ +package services + +import ( + "fmt" + "rijig/dto" + "rijig/internal/repositories" + "rijig/model" + "rijig/utils" +) + +type CompanyProfileService interface { + CreateCompanyProfile(userID string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) + GetCompanyProfileByID(id string) (*dto.ResponseCompanyProfileDTO, error) + GetCompanyProfilesByUserID(userID string) ([]dto.ResponseCompanyProfileDTO, error) + UpdateCompanyProfile(id string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) + DeleteCompanyProfile(id string) error +} + +type companyProfileService struct { + companyProfileRepo repositories.CompanyProfileRepository +} + +func NewCompanyProfileService(companyProfileRepo repositories.CompanyProfileRepository) CompanyProfileService { + return &companyProfileService{ + companyProfileRepo: companyProfileRepo, + } +} + +func FormatResponseCompanyProfile(companyProfile *model.CompanyProfile) (*dto.ResponseCompanyProfileDTO, error) { + + createdAt, _ := utils.FormatDateToIndonesianFormat(companyProfile.CreatedAt) + updatedAt, _ := utils.FormatDateToIndonesianFormat(companyProfile.UpdatedAt) + + responseDTO := &dto.ResponseCompanyProfileDTO{ + ID: companyProfile.ID, + UserID: companyProfile.UserID, + CompanyName: companyProfile.CompanyName, + CompanyAddress: companyProfile.CompanyAddress, + CompanyPhone: companyProfile.CompanyPhone, + CompanyEmail: companyProfile.CompanyEmail, + CompanyLogo: companyProfile.CompanyLogo, + CompanyWebsite: companyProfile.CompanyWebsite, + TaxID: companyProfile.TaxID, + FoundedDate: companyProfile.FoundedDate, + CompanyType: companyProfile.CompanyType, + CompanyDescription: companyProfile.CompanyDescription, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + } + + return responseDTO, nil +} + +func (s *companyProfileService) CreateCompanyProfile(userID string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) { + + errors, valid := request.ValidateCompanyProfileInput() + if !valid { + return nil, fmt.Errorf("validation failed: %v", errors) + } + + companyProfile := &model.CompanyProfile{ + UserID: userID, + CompanyName: request.CompanyName, + CompanyAddress: request.CompanyAddress, + CompanyPhone: request.CompanyPhone, + CompanyEmail: request.CompanyEmail, + CompanyLogo: request.CompanyLogo, + CompanyWebsite: request.CompanyWebsite, + TaxID: request.TaxID, + FoundedDate: request.FoundedDate, + CompanyType: request.CompanyType, + CompanyDescription: request.CompanyDescription, + } + + createdCompanyProfile, err := s.companyProfileRepo.CreateCompanyProfile(companyProfile) + if err != nil { + return nil, fmt.Errorf("failed to create company profile: %v", err) + } + + responseDTO, err := FormatResponseCompanyProfile(createdCompanyProfile) + if err != nil { + return nil, fmt.Errorf("failed to format company profile response: %v", err) + } + + return responseDTO, nil +} + +func (s *companyProfileService) GetCompanyProfileByID(id string) (*dto.ResponseCompanyProfileDTO, error) { + + companyProfile, err := s.companyProfileRepo.GetCompanyProfileByID(id) + if err != nil { + return nil, fmt.Errorf("error retrieving company profile by ID: %v", err) + } + + responseDTO, err := FormatResponseCompanyProfile(companyProfile) + if err != nil { + return nil, fmt.Errorf("error formatting company profile response: %v", err) + } + + return responseDTO, nil +} + +func (s *companyProfileService) GetCompanyProfilesByUserID(userID string) ([]dto.ResponseCompanyProfileDTO, error) { + + companyProfiles, err := s.companyProfileRepo.GetCompanyProfilesByUserID(userID) + if err != nil { + return nil, fmt.Errorf("error retrieving company profiles by userID: %v", err) + } + + var responseDTOs []dto.ResponseCompanyProfileDTO + for _, companyProfile := range companyProfiles { + responseDTO, err := FormatResponseCompanyProfile(&companyProfile) + if err != nil { + return nil, fmt.Errorf("error formatting company profile response: %v", err) + } + responseDTOs = append(responseDTOs, *responseDTO) + } + + return responseDTOs, nil +} + +func (s *companyProfileService) UpdateCompanyProfile(id string, request *dto.RequestCompanyProfileDTO) (*dto.ResponseCompanyProfileDTO, error) { + + errors, valid := request.ValidateCompanyProfileInput() + if !valid { + return nil, fmt.Errorf("validation failed: %v", errors) + } + + companyProfile := &model.CompanyProfile{ + CompanyName: request.CompanyName, + CompanyAddress: request.CompanyAddress, + CompanyPhone: request.CompanyPhone, + CompanyEmail: request.CompanyEmail, + CompanyLogo: request.CompanyLogo, + CompanyWebsite: request.CompanyWebsite, + TaxID: request.TaxID, + FoundedDate: request.FoundedDate, + CompanyType: request.CompanyType, + CompanyDescription: request.CompanyDescription, + } + + updatedCompanyProfile, err := s.companyProfileRepo.UpdateCompanyProfile(id, companyProfile) + if err != nil { + return nil, fmt.Errorf("failed to update company profile: %v", err) + } + + responseDTO, err := FormatResponseCompanyProfile(updatedCompanyProfile) + if err != nil { + return nil, fmt.Errorf("failed to format company profile response: %v", err) + } + + return responseDTO, nil +} + +func (s *companyProfileService) DeleteCompanyProfile(id string) error { + + err := s.companyProfileRepo.DeleteCompanyProfile(id) + if err != nil { + return fmt.Errorf("failed to delete company profile: %v", err) + } + + return nil +} diff --git a/internal/services/identitycard_service.go b/internal/services/identitycard_service.go index b5e653b..f6b62ff 100644 --- a/internal/services/identitycard_service.go +++ b/internal/services/identitycard_service.go @@ -22,11 +22,13 @@ type IdentityCardService interface { type identityCardService struct { identityCardRepo repositories.IdentityCardRepository + userRepo repositories.UserProfileRepository } -func NewIdentityCardService(identityCardRepo repositories.IdentityCardRepository) IdentityCardService { +func NewIdentityCardService(identityCardRepo repositories.IdentityCardRepository, userRepo repositories.UserProfileRepository) IdentityCardService { return &identityCardService{ identityCardRepo: identityCardRepo, + userRepo: userRepo, } } @@ -156,6 +158,17 @@ func (s *identityCardService) CreateIdentityCard(userID string, request *dto.Req return nil, fmt.Errorf("failed to create identity card: %v", err) } + user, err := s.userRepo.FindByID(userID) + if err != nil { + return nil, fmt.Errorf("failde to fint user: %v", err) + } + + user.RegistrationStatus = "onreview" + + err = s.userRepo.Update(user) + if err != nil { + return nil, fmt.Errorf("failed to update user: %v", err) + } idcardResponseDTO, _ := FormatResponseIdentityCars(identityCard) return idcardResponseDTO, nil diff --git a/model/company_profile_model.go b/model/company_profile_model.go index 521185a..915652e 100644 --- a/model/company_profile_model.go +++ b/model/company_profile_model.go @@ -12,13 +12,12 @@ type CompanyProfile struct { CompanyAddress string `gorm:"not null" json:"company_address"` CompanyPhone string `gorm:"not null" json:"company_phone"` CompanyEmail string `gorm:"not null" json:"company_email"` - CompanyLogo string `gorm:"not null" json:"company_logo"` - CompanyWebsite string `json:"company_website"` - TaxID string `json:"tax_id"` - FoundedDate time.Time `json:"founded_date"` - CompanyType string `gorm:"not null" json:"company_type"` + CompanyLogo string `json:"company_logo,omitempty"` + CompanyWebsite string `json:"company_website,omitempty"` + TaxID string `json:"tax_id,omitempty"` + FoundedDate string `json:"founded_date,omitempty"` + CompanyType string `json:"company_type,omitempty"` CompanyDescription string `gorm:"type:text" json:"company_description"` - CompanyStatus string `gorm:"not null" json:"company_status"` CreatedAt time.Time `gorm:"default:current_timestamp" json:"created_at"` UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updated_at"` } diff --git a/presentation/auth/auth_admin_route.go b/presentation/auth/auth_admin_route.go index 07f3324..f77535e 100644 --- a/presentation/auth/auth_admin_route.go +++ b/presentation/auth/auth_admin_route.go @@ -13,7 +13,7 @@ import ( "github.com/gofiber/fiber/v2" ) -func AdminAuthRouter(api fiber.Router) { +func AuthAdminRouter(api fiber.Router) { secretKey := os.Getenv("SECRET_KEY") if secretKey == "" { log.Fatal("SECRET_KEY is not set in the environment variables") diff --git a/presentation/company_profile_route.go b/presentation/company_profile_route.go new file mode 100644 index 0000000..013a463 --- /dev/null +++ b/presentation/company_profile_route.go @@ -0,0 +1,27 @@ +package presentation + +import ( + "rijig/config" + "rijig/internal/handler" + "rijig/internal/repositories" + "rijig/internal/services" + "rijig/middleware" + + "github.com/gofiber/fiber/v2" +) + +func CompanyProfileRouter(api fiber.Router) { + + companyProfileRepo := repositories.NewCompanyProfileRepository(config.DB) + companyProfileService := services.NewCompanyProfileService(companyProfileRepo) + companyProfileHandler := handler.NewCompanyProfileHandler(companyProfileService) + + companyProfileAPI := api.Group("/company-profile") + companyProfileAPI.Use(middleware.AuthMiddleware) + + companyProfileAPI.Post("/create", companyProfileHandler.CreateCompanyProfile) + companyProfileAPI.Get("/get/:company_id", companyProfileHandler.GetCompanyProfileByID) + companyProfileAPI.Get("/get", companyProfileHandler.GetCompanyProfilesByUserID) + companyProfileAPI.Put("/update/:company_id", companyProfileHandler.UpdateCompanyProfile) + companyProfileAPI.Delete("/delete/:company_id", companyProfileHandler.DeleteCompanyProfile) +} diff --git a/presentation/identitycard_route.go b/presentation/identitycard_route.go index dfb187d..d77b848 100644 --- a/presentation/identitycard_route.go +++ b/presentation/identitycard_route.go @@ -13,7 +13,8 @@ import ( func IdentityCardRouter(api fiber.Router) { identityCardRepo := repositories.NewIdentityCardRepository(config.DB) - identityCardService := services.NewIdentityCardService(identityCardRepo) + userRepo := repositories.NewUserProfileRepository(config.DB) + identityCardService := services.NewIdentityCardService(identityCardRepo, userRepo) identityCardHandler := handler.NewIdentityCardHandler(identityCardService) identityCardApi := api.Group("/identitycard") diff --git a/router/setup_routes.go.go b/router/setup_routes.go.go index 8846a88..998a2dd 100644 --- a/router/setup_routes.go.go +++ b/router/setup_routes.go.go @@ -18,12 +18,13 @@ func SetupRoutes(app *fiber.App) { // || auth router || // // presentation.AuthRouter(api) - presentationn.AdminAuthRouter(api) + presentationn.AuthAdminRouter(api) presentationn.AuthPengelolaRouter(api) presentationn.AuthPengepulRouter(api) presentationn.AuthMasyarakatRouter(api) // || auth router || // presentation.IdentityCardRouter(api) + presentation.CompanyProfileRouter(api) presentation.UserProfileRouter(api) presentation.UserPinRouter(api)