From 37890cd69a9d2fcf212420115c427655ea92395a Mon Sep 17 00:00:00 2001 From: Meninjar Mulyono Date: Wed, 20 Aug 2025 19:44:35 +0700 Subject: [PATCH] Perbaikan tool generete --- tools/generate-bpjs-handler.go | 927 ++++++++++++++++----------------- tools/generate-handler.go | 5 +- 2 files changed, 443 insertions(+), 489 deletions(-) diff --git a/tools/generate-bpjs-handler.go b/tools/generate-bpjs-handler.go index 8ff8d92b..c3e5ac1d 100644 --- a/tools/generate-bpjs-handler.go +++ b/tools/generate-bpjs-handler.go @@ -10,115 +10,104 @@ import ( // BpjsHandlerData contains template data for BPJS handler generation type BpjsHandlerData struct { - Name string - NameLower string - NamePlural string - ModuleName string - Category string - HasGet bool - HasGetByID bool - HasPost bool - HasPut bool - HasDelete bool - HasStats bool - HasFilter bool - Timestamp string - Endpoints []BpjsEndpoint -} - -// BpjsEndpoint represents a BPJS API endpoint configuration -type BpjsEndpoint struct { - Name string - Method string - Path string - Description string - Parameters []EndpointParam -} - -// EndpointParam represents an endpoint parameter -type EndpointParam struct { - Name string - Type string - Required bool - Description string - Location string // "path", "query", "body" + Name string + NameLower string + NameUpper string + Category string + CategoryPath string + ModuleName string + HasGet bool + HasPost bool + HasPut bool + HasDelete bool + GetEndpoint string + PostEndpoint string + PutEndpoint string + DeleteEndpoint string + Timestamp string } func main() { if len(os.Args) < 2 { fmt.Println("Usage: go run generate-bpjs-handler.go [category/]entity [methods]") - fmt.Println("Example: go run generate-bpjs-handler.go reference/peserta get getbyid") - fmt.Println("Example: go run generate-bpjs-handler.go peserta get getbyid") + fmt.Println("Examples:") + fmt.Println(" go run generate-bpjs-handler.go vclaim/peserta get post put delete") + fmt.Println(" go run generate-bpjs-handler.go eclaim/sep get post") + fmt.Println(" go run generate-bpjs-handler.go peserta get") os.Exit(1) } - // Parse entity input (could be "entity" or "category/entity") - entityInput := os.Args[1] - var category, entityName string - - if strings.Contains(entityInput, "/") { - parts := strings.Split(entityInput, "/") - if len(parts) != 2 { - fmt.Println("Invalid format. Use: category/entity or entity") - os.Exit(1) - } - category = parts[0] - entityName = strings.Title(parts[1]) // PascalCase entity name - } else { - category = "" - entityName = strings.Title(entityInput) // PascalCase entity name - } - + // Parse entity path (could be "entity" or "category/entity") + entityPath := os.Args[1] methods := []string{} if len(os.Args) > 2 { methods = os.Args[2:] } else { // Default methods if none specified - methods = []string{"get", "getbyid"} + methods = []string{"get", "post", "put", "delete"} } + // Parse category and entity + var category, entityName string + if strings.Contains(entityPath, "/") { + parts := strings.Split(entityPath, "/") + if len(parts) != 2 { + fmt.Println("❌ Error: Invalid path format. Use 'category/entity' or just 'entity'") + os.Exit(1) + } + category = parts[0] + entityName = parts[1] + } else { + category = "" + entityName = entityPath + } + + // Format names + entityName = strings.Title(entityName) // PascalCase entity name entityLower := strings.ToLower(entityName) - entityPlural := entityLower + "s" + entityUpper := strings.ToUpper(entityName) + data := BpjsHandlerData{ - Name: entityName, - NameLower: entityLower, - NamePlural: entityPlural, - ModuleName: "api-service", - Category: category, - Timestamp: time.Now().Format("2006-01-02 15:04:05"), + Name: entityName, + NameLower: entityLower, + NameUpper: entityUpper, + Category: category, + CategoryPath: category, + ModuleName: "api-service", + Timestamp: time.Now().Format("2006-01-02 15:04:05"), } - // Set methods based on arguments + // Set methods and endpoints based on arguments for _, m := range methods { switch strings.ToLower(m) { case "get": data.HasGet = true - case "getbyid": - data.HasGetByID = true + data.GetEndpoint = fmt.Sprintf("/%s/{id}", entityUpper) case "post": data.HasPost = true + data.PostEndpoint = fmt.Sprintf("/%s/2.0/insert", entityUpper) case "put": data.HasPut = true + data.PutEndpoint = fmt.Sprintf("/%s/2.0/update", entityUpper) case "delete": data.HasDelete = true - case "stats": - data.HasStats = true + data.DeleteEndpoint = fmt.Sprintf("/%s/2.0/delete", entityUpper) } } - // Define default endpoints based on entity - data.Endpoints = generateDefaultEndpoints(data) - - // Create directories based on category + // Create directories with dynamic logic (sama seperti generate-handler.go) var handlerDir, modelDir string if category != "" { - handlerDir = filepath.Join("internal", "handlers", "bpjs", category) - modelDir = filepath.Join("internal", "models", "bpjs", category) + // Dengan kategori: internal/handlers/category/ + handlerDir = filepath.Join("internal", "handlers", category) + modelDir = filepath.Join("internal", "models", category) } else { - handlerDir = filepath.Join("internal", "handlers", "bpjs", entityLower) - modelDir = filepath.Join("internal", "models", "bpjs", entityLower) + // Tanpa kategori: langsung internal/handlers/ + handlerDir = filepath.Join("internal", "handlers") + modelDir = filepath.Join("internal", "models") } + // Create directories for _, d := range []string{handlerDir, modelDir} { if err := os.MkdirAll(d, 0755); err != nil { panic(err) @@ -138,77 +127,16 @@ func main() { fmt.Printf("📁 Model: %s\n", filepath.Join(modelDir, entityLower+".go")) } -// generateDefaultEndpoints creates default endpoints based on entity type -func generateDefaultEndpoints(data BpjsHandlerData) []BpjsEndpoint { - endpoints := []BpjsEndpoint{} - - switch data.NameLower { - case "peserta": - endpoints = append(endpoints, BpjsEndpoint{ - Name: "GetByNIK", - Method: "GET", - Path: "/Peserta/nik/%s/tglSEP/%s", - Description: "Get participant data by NIK and service date", - Parameters: []EndpointParam{ - {Name: "nik", Type: "string", Required: true, Description: "NIK KTP", Location: "path"}, - {Name: "tglSEP", Type: "string", Required: true, Description: "Service date (yyyy-MM-dd)", Location: "path"}, - }, - }) - - case "poli": - endpoints = append(endpoints, BpjsEndpoint{ - Name: "GetAll", - Method: "GET", - Path: "/referensi/poli", - Description: "Get all poli reference data", - Parameters: []EndpointParam{}, - }) - - case "diagnosa": - endpoints = append(endpoints, BpjsEndpoint{ - Name: "GetAll", - Method: "GET", - Path: "/referensi/diagnosa", - Description: "Get all diagnosa reference data", - Parameters: []EndpointParam{}, - }) - - case "provider": - endpoints = append(endpoints, BpjsEndpoint{ - Name: "GetByJenis", - Method: "GET", - Path: "/referensi/faskes/%s/%s", - Description: "Get provider data by type and level", - Parameters: []EndpointParam{ - {Name: "jnsFaskes", Type: "string", Required: true, Description: "Jenis Faskes (1=Faskes 1, 2=Faskes 2)", Location: "path"}, - {Name: "kdFaskes", Type: "string", Required: true, Description: "Kode Faskes", Location: "path"}, - }, - }) - - default: - // Generic endpoint - endpoints = append(endpoints, BpjsEndpoint{ - Name: "GetAll", - Method: "GET", - Path: fmt.Sprintf("/referensi/%s", data.NameLower), - Description: fmt.Sprintf("Get all %s reference data", data.NameLower), - Parameters: []EndpointParam{}, - }) - } - - return endpoints -} - -// ================= BPJS HANDLER GENERATION ===================== +// ================= HANDLER GENERATION ===================== func generateBpjsHandlerFile(data BpjsHandlerData, handlerDir string) { - // Determine import path based on category - // var modelsImportPath string - // if data.Category != "" { - // modelsImportPath = `models "` + data.ModuleName + `/internal/models/bpjs/` + data.Category + `"` - // } else { - // modelsImportPath = `models "` + data.ModuleName + `/internal/models/bpjs/` + data.NameLower + `"` - // } + // Build import path based on category (sama seperti generate-handler.go) + var modelsImportPath string + if data.Category != "" { + modelsImportPath = data.ModuleName + "/internal/models/" + data.Category + } else { + modelsImportPath = data.ModuleName + "/internal/models" + } handlerContent := `package handlers @@ -217,367 +145,354 @@ import ( "fmt" "net/http" "time" + "` + data.ModuleName + `/internal/config" + models "` + modelsImportPath + `" services "` + data.ModuleName + `/internal/services/bpjs" + "github.com/gin-gonic/gin" ) -// ` + data.Name + `Handler handles BPJS ` + data.NameLower + ` operations +// ` + data.Name + `Handler handles ` + data.NameLower + ` BPJS services type ` + data.Name + `Handler struct { - bpjsService services.VClaimService + service services.VClaimService } -// New` + data.Name + `Handler creates a new ` + data.Name + `Handler instance +// New` + data.Name + `Handler creates a new ` + data.Name + `Handler func New` + data.Name + `Handler(cfg config.BpjsConfig) *` + data.Name + `Handler { return &` + data.Name + `Handler{ - bpjsService: services.NewService(cfg), + service: services.NewService(cfg), } }` - // Add methods based on endpoints - for _, endpoint := range data.Endpoints { - handlerContent += generateBpjsEndpointMethod(data, endpoint) + // Add methods based on flags + if data.HasPost { + handlerContent += generateBpjsCreateMethod(data) } - // Add helper methods - handlerContent += generateBpjsHelperMethods(data) + if data.HasPut { + handlerContent += generateBpjsUpdateMethod(data) + } + + if data.HasDelete { + handlerContent += generateBpjsDeleteMethod(data) + } + + if data.HasGet { + handlerContent += generateBpjsGetMethod(data) + } writeFile(filepath.Join(handlerDir, data.NameLower+".go"), handlerContent) } -func generateBpjsEndpointMethod(data BpjsHandlerData, endpoint BpjsEndpoint) string { - methodName := endpoint.Name - - // Generate parameter extraction - paramExtraction := "" - paramValidation := "" - pathParams := []string{} - - for _, param := range endpoint.Parameters { - if param.Location == "path" { - paramExtraction += "\t" + param.Name + ` := c.Param("` + param.Name + `")` + "\n" - pathParams = append(pathParams, param.Name) - - if param.Required { - paramValidation += ` - if ` + param.Name + ` == "" { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "` + strings.Title(param.Name) + ` parameter is required", - "message": "` + param.Description + ` tidak boleh kosong", - }) - return - } -` - } - - // Add date validation if parameter contains date - if strings.Contains(param.Name, "tgl") || strings.Contains(param.Name, "date") { - paramValidation += ` - // Validate date format - if _, err := time.Parse("2006-01-02", ` + param.Name + `); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "Invalid date format", - "message": "Format tanggal harus yyyy-MM-dd", - }) - return - } -` - } - } - } - - // Generate endpoint URL building - endpointURL := endpoint.Path - if len(pathParams) > 0 { - endpointURL = `fmt.Sprintf("` + endpoint.Path + `", ` + strings.Join(pathParams, ", ") + `)` - } else { - endpointURL = `"` + endpoint.Path + `"` - } - - // Generate route path for documentation - routePath := endpoint.Path - for _, param := range endpoint.Parameters { - if param.Location == "path" { - routePath = strings.Replace(routePath, "%s", "{"+param.Name+"}", 1) - } - } - - // Generate category prefix for router documentation - categoryPrefix := "" +func generateBpjsCreateMethod(data BpjsHandlerData) string { + // Build route path based on category (dynamic, tidak hardcode bpjs/) + var routePath string if data.Category != "" { - categoryPrefix = "/" + data.Category + routePath = data.Category + "/" + data.NameLower + } else { + routePath = data.NameLower } - swaggerParams := generateSwaggerParams(endpoint.Parameters) + // Tag untuk swagger + var tagName string + if data.Category != "" { + tagName = data.Category + "-" + data.NameLower + } else { + tagName = data.NameLower + } return ` -// ` + methodName + ` godoc -// @Summary ` + endpoint.Description + ` -// @Description ` + endpoint.Description + ` -// @Tags bpjs` + categoryPrefix + ` +// Create` + data.Name + ` godoc +// @Summary Create a new ` + data.NameUpper + ` +// @Description Create a new ` + data.Name + ` in BPJS system +// @Tags ` + tagName + ` // @Accept json -// @Produce json` + swaggerParams + ` -// @Success 200 {object} models.` + data.Name + `Response "Success response" -// @Failure 400 {object} map[string]interface{} "Bad request" -// @Failure 404 {object} map[string]interface{} "Data not found" -// @Failure 500 {object} map[string]interface{} "Internal server error" -// @Router /api/v1/bpjs` + categoryPrefix + routePath + ` [` + strings.ToLower(endpoint.Method) + `] -func (h *` + data.Name + `Handler) ` + methodName + `(c *gin.Context) { -` + paramExtraction + paramValidation + ` - // Create context with timeout - ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second) +// @Produce json +// @Param request body models.` + data.Name + `PostRequest true "` + data.Name + ` creation request" +// @Success 200 {object} models.` + data.Name + `Response "` + data.Name + ` created successfully" +// @Failure 400 {object} gin.H "Invalid request" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /api/v1/` + routePath + ` [post] +func (h *` + data.Name + `Handler) Create` + data.Name + `(c *gin.Context) { + var req models.` + data.Name + `PostRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body", "message": err.Error()}) + return + } + + ctx, cancel := context.WithTimeout(c, 30*time.Second) defer cancel() - // Build endpoint URL - endpoint := ` + endpointURL + ` - - // Call BPJS service var result map[string]interface{} - if err := h.bpjsService.Get(ctx, endpoint, &result); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{ - "error": "Failed to fetch ` + data.NameLower + ` data", - "message": err.Error(), - }) + if err := h.service.Post(ctx, "` + data.PostEndpoint + `", req, &result); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "create failed", "message": err.Error()}) return } - // Return successful response - c.JSON(http.StatusOK, gin.H{ - "message": "Data ` + data.NameLower + ` berhasil diambil", - "data": result, + c.JSON(http.StatusOK, models.` + data.Name + `Response{ + Message: "` + data.Name + ` berhasil dibuat", + Data: result, }) -} -` +}` } -func generateSwaggerParams(params []EndpointParam) string { - result := "" - for _, param := range params { - required := "false" - if param.Required { - required = "true" - } - result += ` -// @Param ` + param.Name + ` ` + param.Location + ` ` + param.Type + ` ` + required + ` "` + param.Description + `"` +func generateBpjsUpdateMethod(data BpjsHandlerData) string { + var routePath string + if data.Category != "" { + routePath = data.Category + "/" + data.NameLower + } else { + routePath = data.NameLower } - return result -} -func generateBpjsHelperMethods(data BpjsHandlerData) string { - handlerName := data.Name + var tagName string + if data.Category != "" { + tagName = data.Category + "-" + data.NameLower + } else { + tagName = data.NameLower + } return ` -// Helper methods for error handling and response formatting - -// handleBPJSError handles BPJS service errors and returns appropriate HTTP responses -func (h *` + handlerName + `Handler) handleBPJSError(c *gin.Context, err error, operation string) { - c.JSON(http.StatusInternalServerError, gin.H{ - "error": fmt.Sprintf("Failed to %s", operation), - "message": err.Error(), - }) -} - -// validateDateFormat validates if the date string is in yyyy-MM-dd format -func (h *` + handlerName + `Handler) validateDateFormat(dateStr string) error { - _, err := time.Parse("2006-01-02", dateStr) - return err -} - -// buildSuccessResponse builds a standardized success response -func (h *` + handlerName + `Handler) buildSuccessResponse(message string, data interface{}) gin.H { - return gin.H{ - "message": message, - "data": data, +// Update` + data.Name + ` godoc +// @Summary Update an existing ` + data.NameUpper + ` +// @Description Update an existing ` + data.Name + ` in BPJS system +// @Tags ` + tagName + ` +// @Accept json +// @Produce json +// @Param request body models.` + data.Name + `PutRequest true "` + data.Name + ` update request" +// @Success 200 {object} models.` + data.Name + `Response "` + data.Name + ` updated successfully" +// @Failure 400 {object} gin.H "Invalid request" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /api/v1/` + routePath + ` [put] +func (h *` + data.Name + `Handler) Update` + data.Name + `(c *gin.Context) { + var req models.` + data.Name + `PutRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body", "message": err.Error()}) + return } -} -` + + ctx, cancel := context.WithTimeout(c, 30*time.Second) + defer cancel() + + var result map[string]interface{} + if err := h.service.Put(ctx, "` + data.PutEndpoint + `", req, &result); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "update failed", "message": err.Error()}) + return + } + + c.JSON(http.StatusOK, models.` + data.Name + `Response{ + Message: "` + data.Name + ` berhasil diperbarui", + Data: result, + }) +}` } -// ================= BPJS MODEL GENERATION ===================== +func generateBpjsDeleteMethod(data BpjsHandlerData) string { + var routePath string + if data.Category != "" { + routePath = data.Category + "/" + data.NameLower + } else { + routePath = data.NameLower + } + + var tagName string + if data.Category != "" { + tagName = data.Category + "-" + data.NameLower + } else { + tagName = data.NameLower + } + + return ` + +// Delete` + data.Name + ` godoc +// @Summary Delete an existing ` + data.NameUpper + ` +// @Description Delete a ` + data.Name + ` by ID +// @Tags ` + tagName + ` +// @Accept json +// @Produce json +// @Param id path string true "` + data.Name + ` ID" +// @Param user query string true "User" +// @Success 200 {object} models.` + data.Name + `Response "` + data.Name + ` deleted successfully" +// @Failure 400 {object} gin.H "Invalid request" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /api/v1/` + routePath + `/{id} [delete] +func (h *` + data.Name + `Handler) Delete` + data.Name + `(c *gin.Context) { + id := c.Param("id") + user := c.Query("user") + if id == "" || user == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "id & user required"}) + return + } + + body := models.` + data.Name + `DeleteRequest{} + body.T` + data.Name + `.ID = id + body.T` + data.Name + `.User = user + + ctx, cancel := context.WithTimeout(c, 30*time.Second) + defer cancel() + + if err := h.service.Delete(ctx, "` + data.DeleteEndpoint + `", body); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "delete failed", "message": err.Error()}) + return + } + + c.JSON(http.StatusOK, models.` + data.Name + `Response{ + Message: "` + data.Name + ` berhasil dihapus", + Data: nil, + }) +}` +} + +func generateBpjsGetMethod(data BpjsHandlerData) string { + var routePath string + if data.Category != "" { + routePath = data.Category + "/" + data.NameLower + } else { + routePath = data.NameLower + } + + var tagName string + if data.Category != "" { + tagName = data.Category + "-" + data.NameLower + } else { + tagName = data.NameLower + } + + return ` + +// Get` + data.Name + ` godoc +// @Summary Get an existing ` + data.NameUpper + ` +// @Description Retrieve a ` + data.Name + ` by ID +// @Tags ` + tagName + ` +// @Accept json +// @Produce json +// @Param id path string true "` + data.Name + ` ID" +// @Success 200 {object} models.` + data.Name + `Response "Data ` + data.Name + ` retrieved successfully" +// @Failure 400 {object} gin.H "Invalid request" +// @Failure 500 {object} gin.H "Internal server error" +// @Router /api/v1/` + routePath + `/{id} [get] +func (h *` + data.Name + `Handler) Get` + data.Name + `(c *gin.Context) { + id := c.Param("id") + if id == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "id required"}) + return + } + + ctx, cancel := context.WithTimeout(c, 30*time.Second) + defer cancel() + + endpoint := fmt.Sprintf("` + strings.Replace(data.GetEndpoint, "{id}", "%s", 1) + `", id) + var result map[string]interface{} + if err := h.service.Get(ctx, endpoint, &result); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "fetch failed", "message": err.Error()}) + return + } + + c.JSON(http.StatusOK, models.` + data.Name + `Response{ + Message: "Data ` + data.Name + ` berhasil diambil", + Data: result, + }) +}` +} + +// ================= MODEL GENERATION ===================== func generateBpjsModelFile(data BpjsHandlerData, modelDir string) { modelContent := `package models -// ` + data.Name + `Response represents the response structure for BPJS ` + data.NameLower + ` data +// ` + data.Name + ` BPJS Models +// Generated at: ` + data.Timestamp + ` +// Category: ` + data.Category + ` + +// Common Response Structure type ` + data.Name + `Response struct { Message string ` + "`json:\"message\"`" + ` - Data map[string]interface{} ` + "`json:\"data\"`" + ` + Data map[string]interface{} ` + "`json:\"data,omitempty\"`" + ` } -// ` + data.Name + `RawResponse represents the raw response structure from BPJS API type ` + data.Name + `RawResponse struct { MetaData struct { Code string ` + "`json:\"code\"`" + ` Message string ` + "`json:\"message\"`" + ` } ` + "`json:\"metaData\"`" + ` Response interface{} ` + "`json:\"response\"`" + ` -} -` +}` - // Add entity-specific models - switch data.NameLower { - case "peserta": - modelContent += generatePesertaModels() - case "poli": - modelContent += generatePoliModels() - case "diagnosa": - modelContent += generateDiagnosaModels() - case "provider": - modelContent += generateProviderModels() + if data.HasPost { + modelContent += ` + +// ` + data.Name + ` POST Request Structure +type ` + data.Name + `PostRequest struct { + T` + data.Name + ` ` + data.Name + `Post ` + "`json:\"t_" + data.NameLower + "\" binding:\"required\"`" + ` +} + +type ` + data.Name + `Post struct { + // Add your specific fields here based on BPJS API requirements + NoKartu string ` + "`json:\"noKartu\" binding:\"required\"`" + ` + TglLayanan string ` + "`json:\"tglLayanan\" binding:\"required\"`" + ` + JnsPelayanan string ` + "`json:\"jnsPelayanan\" binding:\"required\"`" + ` + User string ` + "`json:\"user\" binding:\"required\"`" + ` +}` } - // Add common request/response models - modelContent += generateCommonBpjsModels(data) + if data.HasPut { + modelContent += ` + +// ` + data.Name + ` PUT Request Structure +type ` + data.Name + `PutRequest struct { + T` + data.Name + ` ` + data.Name + `Put ` + "`json:\"t_" + data.NameLower + "\" binding:\"required\"`" + ` +} + +type ` + data.Name + `Put struct { + ID string ` + "`json:\"id\" binding:\"required\"`" + ` + NoKartu string ` + "`json:\"noKartu\"`" + ` + TglLayanan string ` + "`json:\"tglLayanan\"`" + ` + JnsPelayanan string ` + "`json:\"jnsPelayanan\"`" + ` + User string ` + "`json:\"user\" binding:\"required\"`" + ` +}` + } + + if data.HasDelete { + modelContent += ` + +// ` + data.Name + ` DELETE Request Structure +type ` + data.Name + `DeleteRequest struct { + T` + data.Name + ` struct { + ID string ` + "`json:\"id\" binding:\"required\"`" + ` + User string ` + "`json:\"user\" binding:\"required\"`" + ` + } ` + "`json:\"t_" + data.NameLower + "\" binding:\"required\"`" + ` +}` + } + + // Add helper structures + modelContent += ` + +// Common Helper Structures +type Flag struct { + Flag string ` + "`json:\"flag\" binding:\"required\"`" + ` +} + +type Poli struct { + Tujuan string ` + "`json:\"tujuan\"`" + ` + Eksekutif string ` + "`json:\"eksekutif\" binding:\"required\"`" + ` +} + +// Validation helpers +func IsValidStatus(status string) bool { + validStatuses := []string{"active", "inactive", "pending", "processed"} + for _, v := range validStatuses { + if v == status { + return true + } + } + return false +}` writeFile(filepath.Join(modelDir, data.NameLower+".go"), modelContent) } -func generatePesertaModels() string { - return ` - -// PesertaRequest represents the request structure for BPJS participant search -type PesertaRequest struct { - NIK string ` + "`json:\"nik\" binding:\"required\"`" + ` - TglSEP string ` + "`json:\"tglSEP\" binding:\"required\"`" + ` -} - -// PesertaData represents the participant data structure -type PesertaData struct { - NoKartu string ` + "`json:\"noKartu\"`" + ` - NIK string ` + "`json:\"nik\"`" + ` - Nama string ` + "`json:\"nama\"`" + ` - Pisa string ` + "`json:\"pisa\"`" + ` - Sex string ` + "`json:\"sex\"`" + ` - TglLahir string ` + "`json:\"tglLahir\"`" + ` - Pob string ` + "`json:\"pob\"`" + ` - KdProvider string ` + "`json:\"kdProvider\"`" + ` - NmProvider string ` + "`json:\"nmProvider\"`" + ` - KelasRawat string ` + "`json:\"kelasRawat\"`" + ` - Keterangan string ` + "`json:\"keterangan\"`" + ` - NoTelepon string ` + "`json:\"noTelepon\"`" + ` - Alamat string ` + "`json:\"alamat\"`" + ` - KdPos string ` + "`json:\"kdPos\"`" + ` - Pekerjaan string ` + "`json:\"pekerjaan\"`" + ` - StatusKawin string ` + "`json:\"statusKawin\"`" + ` - TglCetakKartu string ` + "`json:\"tglCetakKartu\"`" + ` - TglTAT string ` + "`json:\"tglTAT\"`" + ` - TglTMT string ` + "`json:\"tglTMT\"`" + ` - ProvUmum struct { - KdProvider string ` + "`json:\"kdProvider\"`" + ` - NmProvider string ` + "`json:\"nmProvider\"`" + ` - } ` + "`json:\"provUmum\"`" + ` - JenisPeserta struct { - KdJenisPeserta string ` + "`json:\"kdJenisPeserta\"`" + ` - NmJenisPeserta string ` + "`json:\"nmJenisPeserta\"`" + ` - } ` + "`json:\"jenisPeserta\"`" + ` - KelasTanggungan struct { - KdKelas string ` + "`json:\"kdKelas\"`" + ` - NmKelas string ` + "`json:\"nmKelas\"`" + ` - } ` + "`json:\"kelasTanggungan\"`" + ` - Informasi struct { - Dinsos string ` + "`json:\"dinsos\"`" + ` - NoSKTM string ` + "`json:\"noSKTM\"`" + ` - ProlanisPRB string ` + "`json:\"prolanisPRB\"`" + ` - } ` + "`json:\"informasi\"`" + ` - Cob struct { - NoAsuransi string ` + "`json:\"noAsuransi\"`" + ` - NmAsuransi string ` + "`json:\"nmAsuransi\"`" + ` - TglTAT string ` + "`json:\"tglTAT\"`" + ` - TglTMT string ` + "`json:\"tglTMT\"`" + ` - } ` + "`json:\"cob\"`" + ` - HakKelas struct { - Kode string ` + "`json:\"kode\"`" + ` - Nama string ` + "`json:\"nama\"`" + ` - } ` + "`json:\"hakKelas\"`" + ` - Mr struct { - NoMR string ` + "`json:\"noMR\"`" + ` - NoTelepon string ` + "`json:\"noTelepon\"`" + ` - } ` + "`json:\"mr\"`" + ` - ProvRujuk struct { - KdProvider string ` + "`json:\"kdProvider\"`" + ` - NmProvider string ` + "`json:\"nmProvider\"`" + ` - } ` + "`json:\"provRujuk\"`" + ` - StatusPeserta struct { - Kode string ` + "`json:\"kode\"`" + ` - Nama string ` + "`json:\"nama\"`" + ` - } ` + "`json:\"statusPeserta\"`" + ` -}` -} - -func generatePoliModels() string { - return ` - -// PoliData represents the poli reference data structure -type PoliData struct { - KdPoli string ` + "`json:\"kdPoli\"`" + ` - NmPoli string ` + "`json:\"nmPoli\"`" + ` -} - -// PoliListResponse represents the response structure for poli list -type PoliListResponse struct { - List []PoliData ` + "`json:\"list\"`" + ` -}` -} - -func generateDiagnosaModels() string { - return ` - -// DiagnosaData represents the diagnosa reference data structure -type DiagnosaData struct { - KdDiag string ` + "`json:\"kdDiag\"`" + ` - NmDiag string ` + "`json:\"nmDiag\"`" + ` -} - -// DiagnosaListResponse represents the response structure for diagnosa list -type DiagnosaListResponse struct { - Diagnosa []DiagnosaData ` + "`json:\"diagnosa\"`" + ` -}` -} - -func generateProviderModels() string { - return ` - -// ProviderData represents the provider reference data structure -type ProviderData struct { - KdProvider string ` + "`json:\"kdProvider\"`" + ` - NmProvider string ` + "`json:\"nmProvider\"`" + ` - JnsFaskes string ` + "`json:\"jnsFaskes\"`" + ` - Alamat string ` + "`json:\"alamat\"`" + ` - NoTelp string ` + "`json:\"noTelp\"`" + ` -} - -// ProviderListResponse represents the response structure for provider list -type ProviderListResponse struct { - Faskes []ProviderData ` + "`json:\"faskes\"`" + ` -}` -} - -func generateCommonBpjsModels(data BpjsHandlerData) string { - return ` - -// ErrorResponse represents error response structure -type ErrorResponse struct { - Error string ` + "`json:\"error\"`" + ` - Message string ` + "`json:\"message\"`" + ` - Code int ` + "`json:\"code,omitempty\"`" + ` -} - -// BPJSMetaData represents BPJS API metadata structure -type BPJSMetaData struct { - Code string ` + "`json:\"code\"`" + ` - Message string ` + "`json:\"message\"`" + ` -} - -// ` + data.Name + `Filter represents filter parameters for ` + data.NameLower + ` queries -type ` + data.Name + `Filter struct { - NIK *string ` + "`form:\"nik\" json:\"nik,omitempty\"`" + ` - TglSEP *string ` + "`form:\"tglSEP\" json:\"tglSEP,omitempty\"`" + ` -} -` -} - // ================= ROUTES GENERATION ===================== func updateBpjsRoutesFile(data BpjsHandlerData) { @@ -592,55 +507,72 @@ func updateBpjsRoutesFile(data BpjsHandlerData) { routesContent := string(content) - // Determine import path based on category - var importPath string + // Build import path berdasarkan category (sama seperti generate-handler.go) + var importPath, importAlias string if data.Category != "" { - importPath = data.ModuleName + "/internal/handlers/bpjs/" + data.Category + importPath = fmt.Sprintf("%s/internal/handlers/%s", data.ModuleName, data.Category) + importAlias = data.NameLower + "Handlers" } else { - importPath = data.ModuleName + "/internal/handlers/bpjs/" + data.NameLower + importPath = fmt.Sprintf("%s/internal/handlers", data.ModuleName) + importAlias = data.NameLower + "Handlers" } - // Add import - importPattern := `bpjs` + strings.Title(data.NameLower) + `Handlers "` + importPath + `"` - + // Check and add import + importPattern := fmt.Sprintf("%s \"%s\"", importAlias, importPath) if !strings.Contains(routesContent, importPattern) { - importToAdd := "\t" + `bpjs` + strings.Title(data.NameLower) + `Handlers "` + importPath + `"` + importToAdd := fmt.Sprintf("\t%s \"%s\"", importAlias, importPath) if strings.Contains(routesContent, "import (") { routesContent = strings.Replace(routesContent, "import (", "import (\n"+importToAdd, 1) } } - // Generate routes - newRoutes := "\t\t// BPJS " + data.Name + " endpoints\n" - newRoutes += "\t\tbpjs" + strings.Title(data.NameLower) + "Handler := bpjs" + strings.Title(data.NameLower) + "Handlers.New" + data.Name + "Handler(cfg.Bpjs)\n" + // Build routes + newRoutes := fmt.Sprintf("\t\t// %s endpoints\n", data.Name) + if data.Category != "" { + newRoutes = fmt.Sprintf("\t\t// %s %s endpoints\n", data.Category, data.Name) + } + newRoutes += fmt.Sprintf("\t\t%sHandler := %s.New%sHandler(config.LoadConfig().Bpjs)\n", + data.NameLower, importAlias, data.Name) - // Add routes based on endpoints - for _, endpoint := range data.Endpoints { - routePath := endpoint.Path - for _, param := range endpoint.Parameters { - if param.Location == "path" { - routePath = strings.Replace(routePath, "%s", ":"+param.Name, 1) - } - } + // Build route paths berdasarkan category (dynamic, tidak hardcode) + var routePath string + if data.Category != "" { + routePath = data.Category + "/" + data.NameLower + } else { + routePath = data.NameLower + } - methodName := endpoint.Name - routePrefix := "/bpjs" - if data.Category != "" { - routePrefix = "/bpjs/" + data.Category - } + if data.HasGet { + newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/:id\", %sHandler.Get%s)\n", + routePath, data.NameLower, data.Name) + } - newRoutes += "\t\tv1." + strings.ToUpper(endpoint.Method) + `("` + routePrefix + routePath + `", bpjs` + strings.Title(data.NameLower) + "Handler." + methodName + ")\n" + if data.HasPost { + newRoutes += fmt.Sprintf("\t\tv1.POST(\"/%s\", %sHandler.Create%s)\n", + routePath, data.NameLower, data.Name) + } + + if data.HasPut { + newRoutes += fmt.Sprintf("\t\tv1.PUT(\"/%s\", %sHandler.Update%s)\n", + routePath, data.NameLower, data.Name) + } + + if data.HasDelete { + newRoutes += fmt.Sprintf("\t\tv1.DELETE(\"/%s/:id\", %sHandler.Delete%s)\n", + routePath, data.NameLower, data.Name) } newRoutes += "\n" + + // Insert routes insertMarker := "\t\tprotected := v1.Group(\"/\")" if strings.Contains(routesContent, insertMarker) { - if !strings.Contains(routesContent, "New"+data.Name+"Handler") { + if !strings.Contains(routesContent, fmt.Sprintf("New%sHandler", data.Name)) { routesContent = strings.Replace(routesContent, insertMarker, newRoutes+insertMarker, 1) } else { - fmt.Printf("✅ Routes for BPJS %s already exist, skipping...\n", data.Name) + fmt.Printf("✅ Routes for %s already exist, skipping...\n", data.Name) return } } @@ -650,31 +582,53 @@ func updateBpjsRoutesFile(data BpjsHandlerData) { return } - fmt.Printf("✅ Updated routes.go with BPJS %s endpoints\n", data.Name) + if data.Category != "" { + fmt.Printf("✅ Updated routes.go with %s %s endpoints\n", data.Category, data.Name) + } else { + fmt.Printf("✅ Updated routes.go with %s endpoints\n", data.Name) + } } func printBpjsRoutesSample(data BpjsHandlerData) { - fmt.Printf(` -// BPJS %s endpoints -bpjs%sHandler := bpjs%sHandlers.New%sHandler(cfg.Bpjs) -`, data.Name, strings.Title(data.NameLower), strings.Title(data.NameLower), data.Name) - - for _, endpoint := range data.Endpoints { - routePath := endpoint.Path - for _, param := range endpoint.Parameters { - if param.Location == "path" { - routePath = strings.Replace(routePath, "%s", ":"+param.Name, 1) - } - } - - routePrefix := "/bpjs" - if data.Category != "" { - routePrefix = "/bpjs/" + data.Category - } - - fmt.Printf("\tv1.%s(\"%s%s\", bpjs%sHandler.%s)\n", - strings.ToUpper(endpoint.Method), routePrefix, routePath, strings.Title(data.NameLower), endpoint.Name) + var importAlias string + if data.Category != "" { + importAlias = data.NameLower + "Handlers" + } else { + importAlias = data.NameLower + "Handlers" } + + var routePath string + if data.Category != "" { + routePath = data.Category + "/" + data.NameLower + } else { + routePath = data.NameLower + } + + if data.Category != "" { + fmt.Printf(` +// %s %s endpoints +%sHandler := %s.New%sHandler(config.LoadConfig().Bpjs) +`, data.Category, data.Name, data.NameLower, importAlias, data.Name) + } else { + fmt.Printf(` +// %s endpoints +%sHandler := %s.New%sHandler(config.LoadConfig().Bpjs) +`, data.Name, data.NameLower, importAlias, data.Name) + } + + if data.HasGet { + fmt.Printf("\tv1.GET(\"/%s/:id\", %sHandler.Get%s)\n", routePath, data.NameLower, data.Name) + } + if data.HasPost { + fmt.Printf("\tv1.POST(\"/%s\", %sHandler.Create%s)\n", routePath, data.NameLower, data.Name) + } + if data.HasPut { + fmt.Printf("\tv1.PUT(\"/%s\", %sHandler.Update%s)\n", routePath, data.NameLower, data.Name) + } + if data.HasDelete { + fmt.Printf("\tv1.DELETE(\"/%s/:id\", %sHandler.Delete%s)\n", routePath, data.NameLower, data.Name) + } + fmt.Println() } @@ -685,5 +639,6 @@ func writeFile(filename, content string) { fmt.Printf("❌ Error creating file %s: %v\n", filename, err) return } + fmt.Printf("✅ Generated: %s\n", filename) } diff --git a/tools/generate-handler.go b/tools/generate-handler.go index b3ac31f5..9cc26372 100644 --- a/tools/generate-handler.go +++ b/tools/generate-handler.go @@ -31,9 +31,8 @@ func main() { if len(os.Args) < 2 { fmt.Println("Usage: go run generate-handler.go [category/]entity [methods]") fmt.Println("Examples:") - fmt.Println(" go run generate-handler.go product get post") - fmt.Println(" go run generate-handler.go reference/peserta get post put delete") - fmt.Println(" go run generate-handler.go master/wilayah get") + fmt.Println(" go run generate-handler.go product get post put delete") + fmt.Println(" go run generate-handler.go product get post put delete stats") os.Exit(1) }