pembaruhan swagger dan tool
This commit is contained in:
@@ -80,13 +80,13 @@ tools/generate.bat product get post put delete
|
|||||||
./tools/generate.sh product get post put delete
|
./tools/generate.sh product get post put delete
|
||||||
|
|
||||||
# Atau langsung dengan Go
|
# Atau langsung dengan Go
|
||||||
go run tools/generate-handler.go orders get post
|
go run tools/general/generate-handler.go orders get post
|
||||||
|
|
||||||
go run tools/generate-handler.go orders/product get post
|
go run tools/general/generate-handler.go orders/product get post
|
||||||
|
|
||||||
go run tools/generate-handler.go orders/order get post put delete dynamic search stats
|
go run tools/general/generate-handler.go orders/order get post put delete dynamic search stats
|
||||||
|
|
||||||
go run tools/generate-bpjs-handler.go reference/peserta get
|
go run tools/bpjs/generate-bpjs-handler.go reference/peserta get
|
||||||
```
|
```
|
||||||
|
|
||||||
### Method Tersedia
|
### Method Tersedia
|
||||||
|
|||||||
533
internal/handlers/antrol/peserta.go
Normal file
533
internal/handlers/antrol/peserta.go
Normal file
@@ -0,0 +1,533 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"api-service/internal/config"
|
||||||
|
models "api-service/internal/models/antrol"
|
||||||
|
services "api-service/internal/services/bpjs"
|
||||||
|
"api-service/pkg/logger"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PesertaHandler handles peserta BPJS services with optimized error handling and logging
|
||||||
|
type PesertaHandler struct {
|
||||||
|
service services.VClaimService
|
||||||
|
validator *validator.Validate
|
||||||
|
logger logger.Logger
|
||||||
|
config *config.BpjsConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerConfig contains configuration for PesertaHandler
|
||||||
|
type PesertaHandlerConfig struct {
|
||||||
|
BpjsConfig *config.BpjsConfig
|
||||||
|
Logger logger.Logger
|
||||||
|
Validator *validator.Validate
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPesertaHandler creates a new optimized PesertaHandler
|
||||||
|
func NewPesertaHandler(cfg *PesertaHandlerConfig) *PesertaHandler {
|
||||||
|
return &PesertaHandler{
|
||||||
|
service: services.NewService(*cfg.BpjsConfig),
|
||||||
|
validator: cfg.Validator,
|
||||||
|
logger: cfg.Logger,
|
||||||
|
config: cfg.BpjsConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatePeserta creates a new Peserta with comprehensive error handling and validation
|
||||||
|
// @Summary Create a new PESERTA
|
||||||
|
// @Description Create a new Peserta in BPJS system with enhanced validation and logging
|
||||||
|
// @Tags Antrol-Peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body models.PesertaPostRequest true "Peserta creation request"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Peserta created successfully"
|
||||||
|
// @Failure 400 {object} models.PesertaResponse "Bad request - validation error"
|
||||||
|
// @Failure 422 {object} models.PesertaResponse "Unprocessable entity - business logic error"
|
||||||
|
// @Failure 500 {object} models.PesertaResponse "Internal server error"
|
||||||
|
// @Router /api/v1/antrol/peserta [post]
|
||||||
|
func (h *PesertaHandler) CreatePeserta(c *gin.Context) {
|
||||||
|
requestID := uuid.New().String()
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
|
h.logger.Info("Creating Peserta", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"timestamp": startTime,
|
||||||
|
})
|
||||||
|
|
||||||
|
var req models.PesertaPostRequest
|
||||||
|
req.RequestID = requestID
|
||||||
|
req.Timestamp = startTime
|
||||||
|
|
||||||
|
// Bind and validate JSON
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
h.logger.Error("Failed to bind JSON", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "INVALID_REQUEST_FORMAT",
|
||||||
|
"Format request tidak valid", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom validation
|
||||||
|
if err := req.Validate(); err != nil {
|
||||||
|
h.logger.Error("Custom validation failed", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
|
||||||
|
"Validasi gagal", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct validation
|
||||||
|
if err := h.validator.Struct(&req); err != nil {
|
||||||
|
h.logger.Error("Struct validation failed", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
|
||||||
|
"Validasi struktur gagal", h.formatValidationError(err), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var rawResponse models.BpjsRawResponse
|
||||||
|
if err := h.service.Post(ctx, "PESERTA/2.0/insert", req, &rawResponse); err != nil {
|
||||||
|
h.logger.Error("Failed to call BPJS service", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
"endpoint": "PESERTA/2.0/insert",
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode, errorCode := h.categorizeError(err)
|
||||||
|
h.sendErrorResponse(c, statusCode, errorCode,
|
||||||
|
"Gagal membuat Peserta", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check BPJS response
|
||||||
|
if rawResponse.MetaData.Code != "200" {
|
||||||
|
h.logger.Warn("BPJS returned error", map[string]interface{}{
|
||||||
|
"bpjs_code": rawResponse.MetaData.Code,
|
||||||
|
"bpjs_message": rawResponse.MetaData.Message,
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
|
||||||
|
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
|
||||||
|
rawResponse.MetaData.Message, "", requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
h.logger.Info("Peserta created successfully", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"duration": duration.String(),
|
||||||
|
})
|
||||||
|
|
||||||
|
h.sendSuccessResponse(c, "Peserta berhasil dibuat", rawResponse.Response, requestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePeserta updates an existing Peserta with comprehensive validation
|
||||||
|
// @Summary Update an existing PESERTA
|
||||||
|
// @Description Update an existing Peserta in BPJS system with enhanced validation and logging
|
||||||
|
// @Tags Antrol-Peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body models.PesertaPutRequest true "Peserta update request"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Peserta updated successfully"
|
||||||
|
// @Failure 400 {object} models.PesertaResponse "Bad request - validation error"
|
||||||
|
// @Failure 422 {object} models.PesertaResponse "Unprocessable entity - business logic error"
|
||||||
|
// @Failure 500 {object} models.PesertaResponse "Internal server error"
|
||||||
|
// @Router /api/v1/antrol/peserta [put]
|
||||||
|
func (h *PesertaHandler) UpdatePeserta(c *gin.Context) {
|
||||||
|
requestID := uuid.New().String()
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
|
h.logger.Info("Updating Peserta", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"timestamp": startTime,
|
||||||
|
})
|
||||||
|
|
||||||
|
var req models.PesertaPutRequest
|
||||||
|
req.RequestID = requestID
|
||||||
|
req.Timestamp = startTime
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
h.logger.Error("Failed to bind JSON for update", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "INVALID_REQUEST_FORMAT",
|
||||||
|
"Format request tidak valid", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.Validate(); err != nil {
|
||||||
|
h.logger.Error("Update validation failed", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
|
||||||
|
"Validasi gagal", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.validator.Struct(&req); err != nil {
|
||||||
|
h.logger.Error("Struct validation failed", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
|
||||||
|
"Validasi struktur gagal", h.formatValidationError(err), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var rawResponse models.BpjsRawResponse
|
||||||
|
if err := h.service.Put(ctx, "PESERTA/2.0/update", req, &rawResponse); err != nil {
|
||||||
|
h.logger.Error("Failed to update Peserta", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode, errorCode := h.categorizeError(err)
|
||||||
|
h.sendErrorResponse(c, statusCode, errorCode,
|
||||||
|
"Gagal memperbarui Peserta", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rawResponse.MetaData.Code != "200" {
|
||||||
|
h.logger.Warn("BPJS update returned error", map[string]interface{}{
|
||||||
|
"bpjs_code": rawResponse.MetaData.Code,
|
||||||
|
"bpjs_message": rawResponse.MetaData.Message,
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
|
||||||
|
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
|
||||||
|
rawResponse.MetaData.Message, "", requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
h.logger.Info("Peserta updated successfully", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"duration": duration.String(),
|
||||||
|
})
|
||||||
|
|
||||||
|
h.sendSuccessResponse(c, "Peserta berhasil diperbarui", rawResponse.Response, requestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePeserta deletes an existing Peserta with comprehensive validation
|
||||||
|
// @Summary Delete an existing PESERTA
|
||||||
|
// @Description Delete a Peserta by ID with enhanced validation and logging
|
||||||
|
// @Tags Antrol-Peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Peserta ID"
|
||||||
|
// @Param user query string true "User identifier"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Peserta deleted successfully"
|
||||||
|
// @Failure 400 {object} models.PesertaResponse "Bad request - missing parameters"
|
||||||
|
// @Failure 422 {object} models.PesertaResponse "Unprocessable entity - business logic error"
|
||||||
|
// @Failure 500 {object} models.PesertaResponse "Internal server error"
|
||||||
|
// @Router /api/v1/antrol/peserta/{id} [delete]
|
||||||
|
func (h *PesertaHandler) DeletePeserta(c *gin.Context) {
|
||||||
|
requestID := uuid.New().String()
|
||||||
|
startTime := time.Now()
|
||||||
|
id := c.Param("id")
|
||||||
|
user := c.Query("user")
|
||||||
|
|
||||||
|
h.logger.Info("Deleting Peserta", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"timestamp": startTime,
|
||||||
|
"id": id,
|
||||||
|
"user": user,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Validate parameters
|
||||||
|
if id == "" {
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "MISSING_PARAMETER",
|
||||||
|
"Parameter ID wajib diisi", "", requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user == "" {
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "MISSING_PARAMETER",
|
||||||
|
"Parameter user wajib diisi", "", requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := models.PesertaDeleteRequest{
|
||||||
|
BaseRequest: models.BaseRequest{
|
||||||
|
RequestID: requestID,
|
||||||
|
Timestamp: startTime,
|
||||||
|
},
|
||||||
|
TPeserta: models.PesertaDeleteData{
|
||||||
|
ID: id,
|
||||||
|
User: user,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.Validate(); err != nil {
|
||||||
|
h.logger.Error("Delete validation failed", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
|
||||||
|
"Validasi gagal", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var rawResponse models.BpjsRawResponse
|
||||||
|
if err := h.service.Delete(ctx, "PESERTA/2.0/delete", req); err != nil {
|
||||||
|
h.logger.Error("Failed to delete Peserta", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode, errorCode := h.categorizeError(err)
|
||||||
|
h.sendErrorResponse(c, statusCode, errorCode,
|
||||||
|
"Gagal menghapus Peserta", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rawResponse.MetaData.Code != "200" {
|
||||||
|
h.logger.Warn("BPJS delete returned error", map[string]interface{}{
|
||||||
|
"bpjs_code": rawResponse.MetaData.Code,
|
||||||
|
"bpjs_message": rawResponse.MetaData.Message,
|
||||||
|
"request_id": requestID,
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
|
||||||
|
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
|
||||||
|
rawResponse.MetaData.Message, "", requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
h.logger.Info("Peserta deleted successfully", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"duration": duration.String(),
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
|
||||||
|
h.sendSuccessResponse(c, "Peserta berhasil dihapus", rawResponse.Response, requestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPeserta retrieves Peserta details with comprehensive error handling
|
||||||
|
// @Summary Get an existing PESERTA
|
||||||
|
// @Description Retrieve a Peserta by ID with enhanced validation and logging
|
||||||
|
// @Tags Antrol-Peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Peserta ID"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Data Peserta retrieved successfully"
|
||||||
|
// @Failure 400 {object} models.PesertaResponse "Bad request - invalid ID"
|
||||||
|
// @Failure 404 {object} models.PesertaResponse "Peserta not found"
|
||||||
|
// @Failure 500 {object} models.PesertaResponse "Internal server error"
|
||||||
|
// @Router /api/v1/antrol/peserta/{id} [get]
|
||||||
|
func (h *PesertaHandler) GetPeserta(c *gin.Context) {
|
||||||
|
requestID := uuid.New().String()
|
||||||
|
startTime := time.Now()
|
||||||
|
id := c.Param("id")
|
||||||
|
|
||||||
|
h.logger.Info("Getting Peserta", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"timestamp": startTime,
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
|
||||||
|
if id == "" {
|
||||||
|
h.sendErrorResponse(c, http.StatusBadRequest, "MISSING_PARAMETER",
|
||||||
|
"Parameter ID wajib diisi", "", requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
endpoint := fmt.Sprintf("PESERTA/%s", id)
|
||||||
|
var rawResponse models.BpjsRawResponse
|
||||||
|
|
||||||
|
if err := h.service.Get(ctx, endpoint, &rawResponse); err != nil {
|
||||||
|
h.logger.Error("Failed to get Peserta", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"request_id": requestID,
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode, errorCode := h.categorizeError(err)
|
||||||
|
h.sendErrorResponse(c, statusCode, errorCode,
|
||||||
|
"Gagal mengambil data Peserta", err.Error(), requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rawResponse.MetaData.Code != "200" {
|
||||||
|
// Handle specific BPJS error codes
|
||||||
|
if rawResponse.MetaData.Code == "201" {
|
||||||
|
h.logger.Info("Peserta not found", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
h.sendErrorResponse(c, http.StatusNotFound, "DATA_NOT_FOUND",
|
||||||
|
"Data Peserta tidak ditemukan", rawResponse.MetaData.Message, requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.logger.Warn("BPJS get returned error", map[string]interface{}{
|
||||||
|
"bpjs_code": rawResponse.MetaData.Code,
|
||||||
|
"bpjs_message": rawResponse.MetaData.Message,
|
||||||
|
"request_id": requestID,
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
|
||||||
|
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
|
||||||
|
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
|
||||||
|
rawResponse.MetaData.Message, "", requestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := time.Since(startTime)
|
||||||
|
h.logger.Info("Peserta retrieved successfully", map[string]interface{}{
|
||||||
|
"request_id": requestID,
|
||||||
|
"duration": duration.String(),
|
||||||
|
"id": id,
|
||||||
|
})
|
||||||
|
|
||||||
|
h.sendSuccessResponse(c, "Data Peserta berhasil diambil", rawResponse.Response, requestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods for PesertaHandler
|
||||||
|
func (h *PesertaHandler) sendSuccessResponse(c *gin.Context, message string, data interface{}, requestID string) {
|
||||||
|
response := models.PesertaResponse{
|
||||||
|
BaseResponse: models.BaseResponse{
|
||||||
|
Status: "success",
|
||||||
|
Message: message,
|
||||||
|
Data: data,
|
||||||
|
Metadata: &models.ResponseMetadata{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Version: "2.0",
|
||||||
|
RequestID: requestID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PesertaHandler) sendErrorResponse(c *gin.Context, statusCode int, errorCode, message, details, requestID string) {
|
||||||
|
response := models.PesertaResponse{
|
||||||
|
BaseResponse: models.BaseResponse{
|
||||||
|
Status: "error",
|
||||||
|
Message: message,
|
||||||
|
Error: &models.ErrorResponse{
|
||||||
|
Code: errorCode,
|
||||||
|
Message: message,
|
||||||
|
Details: details,
|
||||||
|
},
|
||||||
|
Metadata: &models.ResponseMetadata{
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
Version: "2.0",
|
||||||
|
RequestID: requestID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c.JSON(statusCode, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PesertaHandler) formatValidationError(err error) string {
|
||||||
|
if validationErrors, ok := err.(validator.ValidationErrors); ok {
|
||||||
|
var messages []string
|
||||||
|
for _, e := range validationErrors {
|
||||||
|
switch e.Tag() {
|
||||||
|
case "required":
|
||||||
|
messages = append(messages, fmt.Sprintf("%s wajib diisi", e.Field()))
|
||||||
|
case "min":
|
||||||
|
messages = append(messages, fmt.Sprintf("%s minimal %s karakter", e.Field(), e.Param()))
|
||||||
|
case "max":
|
||||||
|
messages = append(messages, fmt.Sprintf("%s maksimal %s karakter", e.Field(), e.Param()))
|
||||||
|
case "oneof":
|
||||||
|
messages = append(messages, fmt.Sprintf("%s harus salah satu dari: %s", e.Field(), e.Param()))
|
||||||
|
default:
|
||||||
|
messages = append(messages, fmt.Sprintf("%s tidak valid", e.Field()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Validasi gagal: %v", messages)
|
||||||
|
}
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PesertaHandler) categorizeError(err error) (int, string) {
|
||||||
|
if err == nil {
|
||||||
|
return http.StatusOK, "SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
errStr := err.Error()
|
||||||
|
|
||||||
|
if h.isTimeoutError(err) {
|
||||||
|
return http.StatusRequestTimeout, "REQUEST_TIMEOUT"
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.isNetworkError(err) {
|
||||||
|
return http.StatusBadGateway, "NETWORK_ERROR"
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.isAuthError(errStr) {
|
||||||
|
return http.StatusUnauthorized, "AUTH_ERROR"
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.StatusInternalServerError, "INTERNAL_ERROR"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PesertaHandler) mapBpjsCodeToHttpStatus(bpjsCode string) int {
|
||||||
|
switch bpjsCode {
|
||||||
|
case "200":
|
||||||
|
return http.StatusOK
|
||||||
|
case "201":
|
||||||
|
return http.StatusNotFound
|
||||||
|
case "202":
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case "400":
|
||||||
|
return http.StatusBadRequest
|
||||||
|
case "401":
|
||||||
|
return http.StatusUnauthorized
|
||||||
|
case "403":
|
||||||
|
return http.StatusForbidden
|
||||||
|
case "404":
|
||||||
|
return http.StatusNotFound
|
||||||
|
case "500":
|
||||||
|
return http.StatusInternalServerError
|
||||||
|
default:
|
||||||
|
return http.StatusUnprocessableEntity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PesertaHandler) isTimeoutError(err error) bool {
|
||||||
|
return err != nil && (err.Error() == "context deadline exceeded" ||
|
||||||
|
err.Error() == "timeout")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PesertaHandler) isNetworkError(err error) bool {
|
||||||
|
return err != nil && (err.Error() == "connection refused" ||
|
||||||
|
err.Error() == "no such host")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PesertaHandler) isAuthError(errStr string) bool {
|
||||||
|
return errStr == "unauthorized" || errStr == "invalid credentials"
|
||||||
|
}
|
||||||
164
internal/handlers/vclaim/peserta.go
Normal file
164
internal/handlers/vclaim/peserta.go
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"api-service/internal/config"
|
||||||
|
models "api-service/internal/models/vclaim"
|
||||||
|
services "api-service/internal/services/bpjs"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PesertaHandler handles peserta BPJS services
|
||||||
|
type PesertaHandler struct {
|
||||||
|
service services.VClaimService
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPesertaHandler creates a new PesertaHandler
|
||||||
|
func NewPesertaHandler(cfg config.BpjsConfig) *PesertaHandler {
|
||||||
|
return &PesertaHandler{
|
||||||
|
service: services.NewService(cfg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatePeserta godoc
|
||||||
|
// @Summary Create a new PESERTA
|
||||||
|
// @Description Create a new Peserta in BPJS system
|
||||||
|
// @Tags vclaim-peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body models.PesertaPostRequest true "Peserta creation request"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Peserta created successfully"
|
||||||
|
// @Failure 400 {object} gin.H "Invalid request"
|
||||||
|
// @Failure 500 {object} gin.H "Internal server error"
|
||||||
|
// @Router /api/v1/vclaim/peserta [post]
|
||||||
|
func (h *PesertaHandler) CreatePeserta(c *gin.Context) {
|
||||||
|
var req models.PesertaPostRequest
|
||||||
|
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.Post(ctx, "PESERTA/2.0/insert", req, &result); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "create failed", "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, models.PesertaResponse{
|
||||||
|
Message: "Peserta berhasil dibuat",
|
||||||
|
Data: result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePeserta godoc
|
||||||
|
// @Summary Update an existing PESERTA
|
||||||
|
// @Description Update an existing Peserta in BPJS system
|
||||||
|
// @Tags vclaim-peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body models.PesertaPutRequest true "Peserta update request"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Peserta updated successfully"
|
||||||
|
// @Failure 400 {object} gin.H "Invalid request"
|
||||||
|
// @Failure 500 {object} gin.H "Internal server error"
|
||||||
|
// @Router /api/v1/vclaim/peserta [put]
|
||||||
|
func (h *PesertaHandler) UpdatePeserta(c *gin.Context) {
|
||||||
|
var req models.PesertaPutRequest
|
||||||
|
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, "PESERTA/2.0/update", req, &result); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "update failed", "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, models.PesertaResponse{
|
||||||
|
Message: "Peserta berhasil diperbarui",
|
||||||
|
Data: result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePeserta godoc
|
||||||
|
// @Summary Delete an existing PESERTA
|
||||||
|
// @Description Delete a Peserta by ID
|
||||||
|
// @Tags vclaim-peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Peserta ID"
|
||||||
|
// @Param user query string true "User"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Peserta deleted successfully"
|
||||||
|
// @Failure 400 {object} gin.H "Invalid request"
|
||||||
|
// @Failure 500 {object} gin.H "Internal server error"
|
||||||
|
// @Router /api/v1/vclaim/peserta/{id} [delete]
|
||||||
|
func (h *PesertaHandler) DeletePeserta(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.PesertaDeleteRequest{}
|
||||||
|
body.TPeserta.ID = id
|
||||||
|
body.TPeserta.User = user
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(c, 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := h.service.Delete(ctx, "PESERTA/2.0/delete", body); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "delete failed", "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, models.PesertaResponse{
|
||||||
|
Message: "Peserta berhasil dihapus",
|
||||||
|
Data: nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPeserta godoc
|
||||||
|
// @Summary Get an existing PESERTA
|
||||||
|
// @Description Retrieve a Peserta by ID
|
||||||
|
// @Tags vclaim-peserta
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Peserta ID"
|
||||||
|
// @Success 200 {object} models.PesertaResponse "Data Peserta retrieved successfully"
|
||||||
|
// @Failure 400 {object} gin.H "Invalid request"
|
||||||
|
// @Failure 500 {object} gin.H "Internal server error"
|
||||||
|
// @Router /api/v1/vclaim/peserta/{id} [get]
|
||||||
|
func (h *PesertaHandler) GetPeserta(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("PESERTA/%s", 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.PesertaResponse{
|
||||||
|
Message: "Data Peserta berhasil diambil",
|
||||||
|
Data: result,
|
||||||
|
})
|
||||||
|
}
|
||||||
197
internal/models/antrol/peserta.go
Normal file
197
internal/models/antrol/peserta.go
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Peserta BPJS Models with Enhanced Validation
|
||||||
|
// Generated at: 2025-08-24 20:09:32
|
||||||
|
// Category: antrol
|
||||||
|
|
||||||
|
// Base request/response structures
|
||||||
|
type BaseRequest struct {
|
||||||
|
RequestID string `json:"request_id,omitempty"`
|
||||||
|
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseResponse struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data interface{} `json:"data,omitempty"`
|
||||||
|
Error *ErrorResponse `json:"error,omitempty"`
|
||||||
|
Metadata *ResponseMetadata `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Details string `json:"details,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseMetadata struct {
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
RequestID string `json:"request_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peserta Response Structure
|
||||||
|
type PesertaResponse struct {
|
||||||
|
BaseResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// BPJS Raw Response Structure
|
||||||
|
type BpjsRawResponse struct {
|
||||||
|
MetaData struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
} `json:"metaData"`
|
||||||
|
Response interface{} `json:"response"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peserta POST Request Structure with Enhanced Validation
|
||||||
|
type PesertaPostRequest struct {
|
||||||
|
BaseRequest
|
||||||
|
TPeserta PesertaPost `json:"t_sep" binding:"required" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PesertaPost struct {
|
||||||
|
// Core BPJS fields - customize based on your specific requirements
|
||||||
|
NoKartu string `json:"noKartu" binding:"required" validate:"required,min=13,max=13"`
|
||||||
|
TglLayanan string `json:"tglLayanan" binding:"required" validate:"required"`
|
||||||
|
JnsPelayanan string `json:"jnsPelayanan" binding:"required" validate:"required,oneof=1 2"`
|
||||||
|
PpkPelayanan string `json:"ppkPelayanan" binding:"required" validate:"required"`
|
||||||
|
Catatan string `json:"catatan" validate:"omitempty,max=200"`
|
||||||
|
User string `json:"user" binding:"required" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the PesertaPostRequest
|
||||||
|
func (r *PesertaPostRequest) Validate() error {
|
||||||
|
if r.TPeserta.NoKartu == "" {
|
||||||
|
return fmt.Errorf("nomor kartu tidak boleh kosong")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.TPeserta.NoKartu) != 13 {
|
||||||
|
return fmt.Errorf("nomor kartu harus 13 digit")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := time.Parse("2006-01-02", r.TPeserta.TglLayanan); err != nil {
|
||||||
|
return fmt.Errorf("format tanggal layanan tidak valid, gunakan yyyy-MM-dd")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON converts struct to JSON string
|
||||||
|
func (r *PesertaPostRequest) ToJSON() (string, error) {
|
||||||
|
data, err := json.Marshal(r)
|
||||||
|
return string(data), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peserta PUT Request Structure with Enhanced Validation
|
||||||
|
type PesertaPutRequest struct {
|
||||||
|
BaseRequest
|
||||||
|
TPeserta PesertaPut `json:"t_sep" binding:"required" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PesertaPut struct {
|
||||||
|
ID string `json:"id" binding:"required" validate:"required"`
|
||||||
|
NoKartu string `json:"noKartu" validate:"omitempty,min=13,max=13"`
|
||||||
|
TglLayanan string `json:"tglLayanan" validate:"omitempty"`
|
||||||
|
JnsPelayanan string `json:"jnsPelayanan" validate:"omitempty,oneof=1 2"`
|
||||||
|
PpkPelayanan string `json:"ppkPelayanan" validate:"omitempty"`
|
||||||
|
Catatan string `json:"catatan" validate:"omitempty,max=200"`
|
||||||
|
User string `json:"user" binding:"required" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the PesertaPutRequest
|
||||||
|
func (r *PesertaPutRequest) Validate() error {
|
||||||
|
if r.TPeserta.ID == "" {
|
||||||
|
return fmt.Errorf("ID tidak boleh kosong")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.TPeserta.NoKartu != "" && len(r.TPeserta.NoKartu) != 13 {
|
||||||
|
return fmt.Errorf("nomor kartu harus 13 digit")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON converts struct to JSON string
|
||||||
|
func (r *PesertaPutRequest) ToJSON() (string, error) {
|
||||||
|
data, err := json.Marshal(r)
|
||||||
|
return string(data), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peserta DELETE Request Structure with Enhanced Validation
|
||||||
|
type PesertaDeleteRequest struct {
|
||||||
|
BaseRequest
|
||||||
|
TPeserta PesertaDeleteData `json:"t_sep" binding:"required" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PesertaDeleteData struct {
|
||||||
|
ID string `json:"id" binding:"required" validate:"required"`
|
||||||
|
User string `json:"user" binding:"required" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the PesertaDeleteRequest
|
||||||
|
func (r *PesertaDeleteRequest) Validate() error {
|
||||||
|
if r.TPeserta.ID == "" {
|
||||||
|
return fmt.Errorf("ID tidak boleh kosong")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.TPeserta.User == "" {
|
||||||
|
return fmt.Errorf("User tidak boleh kosong")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON converts struct to JSON string
|
||||||
|
func (r *PesertaDeleteRequest) ToJSON() (string, error) {
|
||||||
|
data, err := json.Marshal(r)
|
||||||
|
return string(data), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common Helper Structures for BPJS
|
||||||
|
type Flag struct {
|
||||||
|
Flag string `json:"flag" binding:"required" validate:"required,oneof=0 1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Poli struct {
|
||||||
|
Tujuan string `json:"tujuan" binding:"required" validate:"required"`
|
||||||
|
Eksekutif string `json:"eksekutif" binding:"required" validate:"required,oneof=0 1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KlsRawat struct {
|
||||||
|
KlsRawatHak string `json:"klsRawatHak" binding:"required" validate:"required,oneof=1 2 3"`
|
||||||
|
KlsRawatNaik string `json:"klsRawatNaik" validate:"omitempty,oneof=1 2 3 4 5 6 7"`
|
||||||
|
Pembiayaan string `json:"pembiayaan" validate:"omitempty,oneof=1 2 3"`
|
||||||
|
PenanggungJawab string `json:"penanggungJawab" validate:"omitempty,max=100"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation helper functions
|
||||||
|
func IsValidStatus(status string) bool {
|
||||||
|
validStatuses := []string{"active", "inactive", "pending", "processed"}
|
||||||
|
for _, v := range validStatuses {
|
||||||
|
if v == status {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidJnsPelayanan(jns string) bool {
|
||||||
|
return jns == "1" || jns == "2" // 1: rawat jalan, 2: rawat inap
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidKlsRawat(kls string) bool {
|
||||||
|
validKelas := []string{"1", "2", "3"}
|
||||||
|
for _, v := range validKelas {
|
||||||
|
if v == kls {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
66
internal/models/vclaim/peserta.go
Normal file
66
internal/models/vclaim/peserta.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// Peserta BPJS Models
|
||||||
|
// Generated at: 2025-08-24 16:39:05
|
||||||
|
// Category: vclaim
|
||||||
|
|
||||||
|
// Common Response Structure
|
||||||
|
type PesertaResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data map[string]interface{} `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PesertaRawResponse struct {
|
||||||
|
MetaData struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
} `json:"metaData"`
|
||||||
|
Response interface{} `json:"response"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peserta POST Request Structure
|
||||||
|
type PesertaPostRequest struct {
|
||||||
|
TPeserta PesertaPost `json:"t_peserta" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PesertaPost 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peserta PUT Request Structure
|
||||||
|
type PesertaPutRequest struct {
|
||||||
|
TPeserta PesertaPut `json:"t_peserta" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PesertaPut 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peserta DELETE Request Structure
|
||||||
|
type PesertaDeleteRequest struct {
|
||||||
|
TPeserta struct {
|
||||||
|
ID string `json:"id" binding:"required"`
|
||||||
|
User string `json:"user" binding:"required"`
|
||||||
|
} `json:"t_peserta" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common Helper Structures
|
||||||
|
|
||||||
|
// Validation helpers
|
||||||
|
func IsValidStatus(status string) bool {
|
||||||
|
validStatuses := []string{"active", "inactive", "pending", "processed"}
|
||||||
|
for _, v := range validStatuses {
|
||||||
|
if v == status {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
644
tools/generate-bpjs-handler.go.backup
Normal file
644
tools/generate-bpjs-handler.go.backup
Normal file
@@ -0,0 +1,644 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BpjsHandlerData contains template data for BPJS handler generation
|
||||||
|
type BpjsHandlerData struct {
|
||||||
|
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("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 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", "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)
|
||||||
|
entityUpper := strings.ToUpper(entityName)
|
||||||
|
|
||||||
|
data := BpjsHandlerData{
|
||||||
|
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 and endpoints based on arguments
|
||||||
|
for _, m := range methods {
|
||||||
|
switch strings.ToLower(m) {
|
||||||
|
case "get":
|
||||||
|
data.HasGet = 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
|
||||||
|
data.DeleteEndpoint = fmt.Sprintf("/%s/2.0/delete", entityUpper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create directories with dynamic logic (sama seperti generate-handler.go)
|
||||||
|
var handlerDir, modelDir string
|
||||||
|
if category != "" {
|
||||||
|
// Dengan kategori: internal/handlers/category/
|
||||||
|
handlerDir = filepath.Join("internal", "handlers", category)
|
||||||
|
modelDir = filepath.Join("internal", "models", category)
|
||||||
|
} else {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate files
|
||||||
|
generateBpjsHandlerFile(data, handlerDir)
|
||||||
|
generateBpjsModelFile(data, modelDir)
|
||||||
|
updateBpjsRoutesFile(data)
|
||||||
|
|
||||||
|
fmt.Printf("✅ Successfully generated BPJS handler: %s\n", entityName)
|
||||||
|
if category != "" {
|
||||||
|
fmt.Printf("📁 Category: %s\n", category)
|
||||||
|
}
|
||||||
|
fmt.Printf("📁 Handler: %s\n", filepath.Join(handlerDir, entityLower+".go"))
|
||||||
|
fmt.Printf("📁 Model: %s\n", filepath.Join(modelDir, entityLower+".go"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= HANDLER GENERATION =====================
|
||||||
|
|
||||||
|
func generateBpjsHandlerFile(data BpjsHandlerData, handlerDir string) {
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"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 ` + data.NameLower + ` BPJS services
|
||||||
|
type ` + data.Name + `Handler struct {
|
||||||
|
service services.VClaimService
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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{
|
||||||
|
service: services.NewService(cfg),
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// Add methods based on flags
|
||||||
|
if data.HasPost {
|
||||||
|
handlerContent += generateBpjsCreateMethod(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.HasPut {
|
||||||
|
handlerContent += generateBpjsUpdateMethod(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.HasDelete {
|
||||||
|
handlerContent += generateBpjsDeleteMethod(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.HasGet {
|
||||||
|
handlerContent += generateBpjsGetMethod(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileBpjs(filepath.Join(handlerDir, data.NameLower+".go"), handlerContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateBpjsCreateMethod(data BpjsHandlerData) string {
|
||||||
|
// Build route path based on category (dynamic, tidak hardcode bpjs/)
|
||||||
|
var routePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
routePath = data.Category + "/" + data.NameLower
|
||||||
|
} else {
|
||||||
|
routePath = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag untuk swagger
|
||||||
|
var tagName string
|
||||||
|
if data.Category != "" {
|
||||||
|
tagName = data.Category + "-" + data.NameLower
|
||||||
|
} else {
|
||||||
|
tagName = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// @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()
|
||||||
|
|
||||||
|
var result map[string]interface{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, models.` + data.Name + `Response{
|
||||||
|
Message: "` + data.Name + ` berhasil dibuat",
|
||||||
|
Data: result,
|
||||||
|
})
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateBpjsUpdateMethod(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 `
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
})
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 + ` 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,omitempty\"`" + `
|
||||||
|
}
|
||||||
|
|
||||||
|
type ` + data.Name + `RawResponse struct {
|
||||||
|
MetaData struct {
|
||||||
|
Code string ` + "`json:\"code\"`" + `
|
||||||
|
Message string ` + "`json:\"message\"`" + `
|
||||||
|
} ` + "`json:\"metaData\"`" + `
|
||||||
|
Response interface{} ` + "`json:\"response\"`" + `
|
||||||
|
}`
|
||||||
|
|
||||||
|
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\"`" + `
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}`
|
||||||
|
|
||||||
|
writeFileBpjs(filepath.Join(modelDir, data.NameLower+".go"), modelContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= ROUTES GENERATION =====================
|
||||||
|
|
||||||
|
func updateBpjsRoutesFile(data BpjsHandlerData) {
|
||||||
|
routesFile := "internal/routes/v1/routes.go"
|
||||||
|
content, err := os.ReadFile(routesFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("⚠️ Could not read routes.go: %v\n", err)
|
||||||
|
fmt.Printf("📝 Please manually add these routes to your routes.go file:\n")
|
||||||
|
printBpjsRoutesSample(data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
routesContent := string(content)
|
||||||
|
|
||||||
|
// Build import path berdasarkan category (sama seperti generate-handler.go)
|
||||||
|
var importPath, importAlias string
|
||||||
|
if data.Category != "" {
|
||||||
|
importPath = fmt.Sprintf("%s/internal/handlers/%s", data.ModuleName, data.Category)
|
||||||
|
importAlias = data.NameLower + "Handlers"
|
||||||
|
} else {
|
||||||
|
importPath = fmt.Sprintf("%s/internal/handlers", data.ModuleName)
|
||||||
|
importAlias = data.NameLower + "Handlers"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and add import
|
||||||
|
importPattern := fmt.Sprintf("%s \"%s\"", importAlias, importPath)
|
||||||
|
if !strings.Contains(routesContent, importPattern) {
|
||||||
|
importToAdd := fmt.Sprintf("\t%s \"%s\"", importAlias, importPath)
|
||||||
|
if strings.Contains(routesContent, "import (") {
|
||||||
|
routesContent = strings.Replace(routesContent, "import (",
|
||||||
|
"import (\n"+importToAdd, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// Build route paths berdasarkan category (dynamic, tidak hardcode)
|
||||||
|
var routePath string
|
||||||
|
if data.Category != "" {
|
||||||
|
routePath = data.Category + "/" + data.NameLower
|
||||||
|
} else {
|
||||||
|
routePath = data.NameLower
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.HasGet {
|
||||||
|
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/:id\", %sHandler.Get%s)\n",
|
||||||
|
routePath, data.NameLower, data.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
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, fmt.Sprintf("New%sHandler", data.Name)) {
|
||||||
|
routesContent = strings.Replace(routesContent, insertMarker,
|
||||||
|
newRoutes+insertMarker, 1)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("✅ Routes for %s already exist, skipping...\n", data.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(routesFile, []byte(routesContent), 0644); err != nil {
|
||||||
|
fmt.Printf("Error writing routes.go: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= UTILITY FUNCTIONS =====================
|
||||||
|
|
||||||
|
func writeFileBpjs(filename, content string) {
|
||||||
|
if err := os.WriteFile(filename, []byte(content), 0644); err != nil {
|
||||||
|
fmt.Printf("❌ Error creating file %s: %v\n", filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("✅ Generated: %s\n", filename)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user