2 Commits

Author SHA1 Message Date
cc76c6d7b5 fitur rujukan 3 get di awal 2025-12-30 10:31:27 +07:00
cd2750d72b get rujukan by no kartu dan no rujukan 2025-12-24 15:11:59 +07:00
2 changed files with 353 additions and 19 deletions

View File

@@ -0,0 +1,320 @@
package handlers
import (
"context"
"encoding/json"
"net/http"
"strconv"
"strings"
"time"
"api-service/internal/config"
"api-service/internal/models"
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"
)
type RujukanHandler struct {
service services.VClaimService
validator *validator.Validate
logger logger.Logger
config config.BpjsConfig
}
type RujukanHandlerConfig struct {
Config *config.Config
Logger logger.Logger
Validator *validator.Validate
}
func NewRujukanHandler(cfg RujukanHandlerConfig) *RujukanHandler {
return &RujukanHandler{
service: services.NewService(cfg.Config.Bpjs),
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.Config.Bpjs,
}
}
// parseHTTPStatusCode extracts HTTP status code from error message
func parseHTTPStatusCode(errMsg string) int {
if strings.Contains(errMsg, "HTTP error:") {
parts := strings.Split(errMsg, "HTTP error:")
if len(parts) > 1 {
statusPart := strings.TrimSpace(parts[1])
if statusCode, err := strconv.Atoi(strings.Fields(statusPart)[0]); err == nil {
return statusCode
}
}
}
return 500 // Default to internal server error
}
func (h *RujukanHandler) isValidJSON(str string) bool {
var js interface{}
return json.Unmarshal([]byte(str), &js) == nil
}
// GetBynoRujukan godoc
// @Summary Get Bynik data
// @Description Get participant eligibility information by NIK
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param nik path string true "nik" example("example_value")
// @Success 200 {object} Rujukan.RujukanResponse "Successfully retrieved Bynik data"
// @Failure 400 {object} models.ErrorResponseBpjs "Bad request - invalid parameters"
// @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized - invalid API credentials"
// @Failure 404 {object} models.ErrorResponseBpjs "Not found - Bynik not found"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukan/nik/:nik [get]
func (h *RujukanHandler) GetByNomorRujukan(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
h.logger.Info("Processing GetByNomorRujukan request", map[string]interface{}{
"nomor_rujukan": requestID,
"endpoint": "/Rujukan/",
})
// Extract path parameters
nr := c.Param("nomorrujukan")
if nr == "" || nr == ":nr" {
h.logger.Error("Missing required parameter nik", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Parameter nomor rujukan Masih Kosong / Isi Dahulu nomor rujukan!",
RequestID: requestID,
})
return
}
endpoint := "/Rujukan/:nr"
endpoint = strings.Replace(endpoint, ":nr", nr, 1)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil {
// Check if error message contains 404 status code
if strings.Contains(err.Error(), "HTTP error: 404") {
h.logger.Error("nomor rujukan not found", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusNotFound, models.ErrorResponseBpjs{
Status: "error",
Message: "nomor rujukan not found",
RequestID: requestID,
})
return
}
h.logger.Error("Failed to get by nomor rujukan", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
statuscode, err := strconv.Atoi(resp.MetaData.Code)
c.JSON(statuscode, resp)
}
// GetBynokartu godoc
// @Summary Get Bynokartu data
// @Description Get participant eligibility information by card number
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param nokartu path string true "nokartu" example("example_value")
// @Success 200 {object} Rujukan.RujukanResponse "Successfully retrieved Bynokartu data"
// @Failure 400 {object} models.ErrorResponseBpjs "Bad request - invalid parameters"
// @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized - invalid API credentials"
// @Failure 404 {object} models.ErrorResponseBpjs "Not found - Bynokartu not found"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukan/nokartu/:nokartu [get]
func (h *RujukanHandler) GetBynokartu(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
// Extract path parameters
nokartu := c.Param("nokartu")
if nokartu == "" || nokartu == ":nokartu" {
h.logger.Error("Missing required parameter nokartu", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Parameter Nomor Kartu Bpjs Masih Kosong / Isi Dahulu Nomor Kartu!",
RequestID: requestID,
})
return
}
endpoint := "/Rujukan/nokartu/:nokartu"
endpoint = strings.Replace(endpoint, ":nokartu", nokartu, 1)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil {
if strings.Contains(err.Error(), "HTTP error: 404") {
h.logger.Error("rujukan by no kartu not found", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusNotFound, models.ErrorResponseBpjs{
Status: "error",
Message: "rujukan by no kartu",
RequestID: requestID,
})
return
}
h.logger.Error("Failed to get by no kartu", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
statuscode, err := strconv.Atoi(resp.MetaData.Code)
c.JSON(statuscode, resp)
}
// GetListBynokartu godoc
// @Summary Get Bynokartu data
// @Description Get participant eligibility information by card number
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param nokartu path string true "nokartu" example("example_value")
// @Success 200 {object} Rujukan.RujukanResponse "Successfully retrieved Bynokartu data"
// @Failure 400 {object} models.ErrorResponseBpjs "Bad request - invalid parameters"
// @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized - invalid API credentials"
// @Failure 404 {object} models.ErrorResponseBpjs "Not found - Bynokartu not found"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukan/nokartu/:nokartu [get]
func (h *RujukanHandler) GetListBynokartu(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
// Context Paramaeter
h.logger.Info("Processing GetBynokartu request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukan/nokartu/:nokartu/tglSEP/",
"nik": c.Param("nokartu"),
})
// Extract path parameters
nokartu := c.Param("nokartu")
if nokartu == "" || nokartu == ":nokartu" {
h.logger.Error("Missing required parameter nokartu", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Parameter Nomor Kartu Bpjs Masih Kosong / Isi Dahulu Nomor Kartu!",
RequestID: requestID,
})
return
}
endpoint := "/Rujukan/nokartu/:nokartu/tglSEP/"
endpoint = strings.Replace(endpoint, ":nokartu", nokartu, 1)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil {
// Check if error message contains 404 status code
if strings.Contains(err.Error(), "HTTP error: 404") {
h.logger.Error("ByNoKartu not found", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusNotFound, models.ErrorResponseBpjs{
Status: "error",
Message: "ByNoKartu not found",
RequestID: requestID,
})
return
}
h.logger.Error("Failed to get ByNoKartu", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
statuscode, err := strconv.Atoi(resp.MetaData.Code)
c.JSON(statuscode, resp)
}

View File

@@ -7,6 +7,7 @@ import (
healthcheckHandlers "api-service/internal/handlers/healthcheck"
pesertaHandlers "api-service/internal/handlers/peserta"
retribusiHandlers "api-service/internal/handlers/retribusi"
rujukanHandlers "api-service/internal/handlers/rujukan"
"api-service/internal/middleware"
services "api-service/internal/services/auth"
"api-service/pkg/logger"
@@ -144,30 +145,43 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
})
}
rujukanHandler := rujukanHandlers.NewRujukanHandler(rujukanHandlers.RujukanHandlerConfig{
Config: cfg,
Logger: *logger.Default(),
Validator: validator.New(),
})
rujukanGroup := v1.Group("/rujukan")
{
rujukanGroup.GET("/:nomorrujukan",rujukanHandler.GetByNomorRujukan)
rujukanGroup.GET("/nokartu/:nokartu",rujukanHandler.GetBynokartu)
rujukanGroup.GET("/list/:nokartu",rujukanHandler.GetListBynokartu)
}
// =============================================================================
// PROTECTED ROUTES (Authentication Required)
// =============================================================================
protected := v1.Group("/")
protected.Use(middleware.ConfigurableAuthMiddleware(cfg))
// Protected retribusi endpoints (Authentication Required)
protectedRetribusiGroup := protected.Group("/retribusi")
{
protectedRetribusiGroup.GET("", retribusiHandler.GetRetribusi)
protectedRetribusiGroup.GET("/dynamic", retribusiHandler.GetRetribusiDynamic)
protectedRetribusiGroup.GET("/search", retribusiHandler.SearchRetribusiAdvanced)
protectedRetribusiGroup.GET("/id/:id", retribusiHandler.GetRetribusiByID)
protectedRetribusiGroup.POST("", func(c *gin.Context) {
retribusiHandler.CreateRetribusi(c)
})
// protected := v1.Group("/")
// protected.Use(middleware.ConfigurableAuthMiddleware(cfg))
// // Protected retribusi endpoints (Authentication Required)
// protectedRetribusiGroup := protected.Group("/retribusi")
// {
// protectedRetribusiGroup.GET("", retribusiHandler.GetRetribusi)
// protectedRetribusiGroup.GET("/dynamic", retribusiHandler.GetRetribusiDynamic)
// protectedRetribusiGroup.GET("/search", retribusiHandler.SearchRetribusiAdvanced)
// protectedRetribusiGroup.GET("/id/:id", retribusiHandler.GetRetribusiByID)
// protectedRetribusiGroup.POST("", func(c *gin.Context) {
// retribusiHandler.CreateRetribusi(c)
// })
protectedRetribusiGroup.PUT("/id/:id", func(c *gin.Context) {
retribusiHandler.UpdateRetribusi(c)
})
// protectedRetribusiGroup.PUT("/id/:id", func(c *gin.Context) {
// retribusiHandler.UpdateRetribusi(c)
// })
protectedRetribusiGroup.DELETE("/id/:id", func(c *gin.Context) {
retribusiHandler.DeleteRetribusi(c)
})
}
// protectedRetribusiGroup.DELETE("/id/:id", func(c *gin.Context) {
// retribusiHandler.DeleteRetribusi(c)
// })
// }
return router
}