574 lines
15 KiB
Go
574 lines
15 KiB
Go
// Code generated by generate-dynamic-handler.go; DO NOT EDIT.
|
|
// Generated at: 2025-08-28 14:59:09
|
|
// Service: VClaim (vclaim)
|
|
// Description: BPJS VClaim service for eligibility and SEP management
|
|
|
|
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"api-service/internal/config"
|
|
"api-service/internal/models/reference"
|
|
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"
|
|
)
|
|
|
|
// VClaimHandler handles VClaim BPJS services
|
|
type VClaimHandler struct {
|
|
service services.VClaimService
|
|
validator *validator.Validate
|
|
logger logger.Logger
|
|
config *config.BpjsConfig
|
|
}
|
|
|
|
// VClaimHandlerConfig contains configuration for VClaimHandler
|
|
type VClaimHandlerConfig struct {
|
|
BpjsConfig *config.BpjsConfig
|
|
Logger logger.Logger
|
|
Validator *validator.Validate
|
|
}
|
|
|
|
// NewVClaimHandler creates a new VClaimHandler
|
|
func NewVClaimHandler(cfg VClaimHandlerConfig) *VClaimHandler {
|
|
return &VClaimHandler{
|
|
service: services.NewService(*cfg.BpjsConfig),
|
|
validator: cfg.Validator,
|
|
logger: cfg.Logger,
|
|
config: cfg.BpjsConfig,
|
|
}
|
|
}
|
|
|
|
// GetPESERTA retrieves Peserta data
|
|
// @Summary Get Peserta data
|
|
// @Description Get participant eligibility information
|
|
// @Tags vclaim,peserta
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param nokartu path string true "Nokartu"
|
|
// @Success 200 {object} reference.PesertaResponse
|
|
// @Failure 400 {object} reference.ErrorResponse
|
|
// @Failure 500 {object} reference.ErrorResponse
|
|
// @Router /Peserta/:nokartu [get]
|
|
func (h *VClaimHandler) GetPESERTA(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)
|
|
}
|
|
// Authentication check
|
|
if err := h.authenticateRequest(c); err != nil {
|
|
h.logger.Error("Authentication failed", "error", err.Error(), "request_id", requestID)
|
|
c.JSON(http.StatusUnauthorized, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Authentication failed",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Extract path parameters
|
|
nokartu := c.Param("nokartu")
|
|
if nokartu == "" {
|
|
h.logger.Error("Missing required parameter: nokartu", "request_id", requestID)
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Missing required parameter: nokartu",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
// Check cache first
|
|
cacheKey := fmt.Sprintf("vclaim:peserta:%s", nokartu)
|
|
if cached, found := h.getCachedResponse(cacheKey); found {
|
|
h.logger.Info("Cache hit for GetPESERTA", "request_id", requestID, "cache_key", cacheKey)
|
|
c.Header("X-Cache", "HIT")
|
|
c.JSON(http.StatusOK, cached)
|
|
return
|
|
}
|
|
|
|
h.logger.Info("Processing GetPESERTA request",
|
|
"request_id", requestID,
|
|
"endpoint", "/Peserta/:nokartu",
|
|
"nokartu", nokartu)
|
|
|
|
// Call service method
|
|
result, err := h.service.GetPESERTA(ctx, nokartu)
|
|
|
|
if err != nil {
|
|
h.logger.Error("Failed to get Peserta",
|
|
"error", err.Error(),
|
|
"request_id", requestID)
|
|
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Internal server error",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Prepare response
|
|
response := reference.PesertaResponse{
|
|
Status: "success",
|
|
Data: result,
|
|
RequestID: requestID,
|
|
}
|
|
// Cache successful response
|
|
h.setCachedResponse(cacheKey, response, 300)
|
|
|
|
c.Header("X-Cache", "MISS")
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// GetSEP retrieves Sep data
|
|
// @Summary Get Sep data
|
|
// @Description Manage SEP (Surat Eligibilitas Peserta)
|
|
// @Tags vclaim,sep
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param nosep path string true "Nosep"
|
|
// @Success 200 {object} reference.SEPResponse
|
|
// @Failure 400 {object} reference.ErrorResponse
|
|
// @Failure 500 {object} reference.ErrorResponse
|
|
// @Router /SEP/:nosep [get]
|
|
func (h *VClaimHandler) GetSEP(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)
|
|
}
|
|
// Authentication check
|
|
if err := h.authenticateRequest(c); err != nil {
|
|
h.logger.Error("Authentication failed", "error", err.Error(), "request_id", requestID)
|
|
c.JSON(http.StatusUnauthorized, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Authentication failed",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Extract path parameters
|
|
nosep := c.Param("nosep")
|
|
if nosep == "" {
|
|
h.logger.Error("Missing required parameter: nosep", "request_id", requestID)
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Missing required parameter: nosep",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
// Check cache first
|
|
cacheKey := fmt.Sprintf("vclaim:sep:%s", nosep)
|
|
if cached, found := h.getCachedResponse(cacheKey); found {
|
|
h.logger.Info("Cache hit for GetSEP", "request_id", requestID, "cache_key", cacheKey)
|
|
c.Header("X-Cache", "HIT")
|
|
c.JSON(http.StatusOK, cached)
|
|
return
|
|
}
|
|
|
|
h.logger.Info("Processing GetSEP request",
|
|
"request_id", requestID,
|
|
"endpoint", "/SEP/:nosep",
|
|
"nosep", nosep)
|
|
|
|
// Call service method
|
|
result, err := h.service.GetSEP(ctx, nosep)
|
|
|
|
if err != nil {
|
|
h.logger.Error("Failed to get Sep",
|
|
"error", err.Error(),
|
|
"request_id", requestID)
|
|
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Internal server error",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Prepare response
|
|
response := reference.SEPResponse{
|
|
Status: "success",
|
|
Data: result,
|
|
RequestID: requestID,
|
|
}
|
|
// Cache successful response
|
|
h.setCachedResponse(cacheKey, response, 180)
|
|
|
|
c.Header("X-Cache", "MISS")
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// CreateSEP creates new Sep
|
|
// @Summary Create Sep
|
|
// @Description Manage SEP (Surat Eligibilitas Peserta)
|
|
// @Tags vclaim,sep
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param request body reference.SEPRequest true "Sep data"
|
|
// @Success 201 {object} reference.SEPResponse
|
|
// @Failure 400 {object} reference.ErrorResponse
|
|
// @Failure 500 {object} reference.ErrorResponse
|
|
// @Router /sep [post]
|
|
func (h *VClaimHandler) CreateSEP(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)
|
|
}
|
|
// Authentication check
|
|
if err := h.authenticateRequest(c); err != nil {
|
|
h.logger.Error("Authentication failed", "error", err.Error(), "request_id", requestID)
|
|
c.JSON(http.StatusUnauthorized, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Authentication failed",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
var req reference.SEPRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
h.logger.Error("Invalid request body",
|
|
"error", err.Error(),
|
|
"request_id", requestID)
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Invalid request body: " + err.Error(),
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Validate request
|
|
if err := h.validator.Struct(&req); err != nil {
|
|
h.logger.Error("Validation failed",
|
|
"error", err.Error(),
|
|
"request_id", requestID)
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Validation failed: " + err.Error(),
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
h.logger.Info("Processing CreateSEP request", "request_id", requestID)
|
|
|
|
// Call service method
|
|
result, err := h.service.CreateSEP(ctx, &req)
|
|
if err != nil {
|
|
h.logger.Error("Failed to create Sep",
|
|
"error", err.Error(),
|
|
"request_id", requestID)
|
|
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Internal server error",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
response := reference.SEPResponse{
|
|
Status: "success",
|
|
Data: result,
|
|
RequestID: requestID,
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, response)
|
|
}
|
|
|
|
// UpdateSEP updates existing Sep
|
|
// @Summary Update Sep
|
|
// @Description Manage SEP (Surat Eligibilitas Peserta)
|
|
// @Tags vclaim,sep
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param nosep path string true "Nosep"
|
|
// @Param request body reference.SEPRequest true "Sep data"
|
|
// @Success 200 {object} reference.SEPResponse
|
|
// @Failure 400 {object} reference.ErrorResponse
|
|
// @Failure 500 {object} reference.ErrorResponse
|
|
// @Router /sep/:nosep [put]
|
|
func (h *VClaimHandler) UpdateSEP(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)
|
|
}
|
|
|
|
// Extract path parameters
|
|
nosep := c.Param("nosep")
|
|
if nosep == "" {
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Missing required parameter: nosep",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
var req reference.SEPRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Invalid request body: " + err.Error(),
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
if err := h.validator.Struct(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Validation failed: " + err.Error(),
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
// Invalidate cache
|
|
cacheKey := fmt.Sprintf("vclaim:sep:%s", nosep)
|
|
h.invalidateCache(cacheKey)
|
|
|
|
// Call service method
|
|
result, err := h.service.UpdateSEP(ctx, nosep, &req)
|
|
|
|
if err != nil {
|
|
h.logger.Error("Failed to update Sep", "error", err.Error(), "request_id", requestID)
|
|
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Internal server error",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
response := reference.SEPResponse{
|
|
Status: "success",
|
|
Data: result,
|
|
RequestID: requestID,
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// DeleteSEP deletes existing Sep
|
|
// @Summary Delete Sep
|
|
// @Description Manage SEP (Surat Eligibilitas Peserta)
|
|
// @Tags vclaim,sep
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param nosep path string true "Nosep"
|
|
// @Success 200 {object} reference.BaseResponse
|
|
// @Failure 400 {object} reference.ErrorResponse
|
|
// @Failure 500 {object} reference.ErrorResponse
|
|
// @Router /sep/:nosep [delete]
|
|
func (h *VClaimHandler) DeleteSEP(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)
|
|
}
|
|
|
|
// Extract path parameters
|
|
nosep := c.Param("nosep")
|
|
if nosep == "" {
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Missing required parameter: nosep",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
// Invalidate cache
|
|
cacheKey := fmt.Sprintf("vclaim:sep:%s", nosep)
|
|
h.invalidateCache(cacheKey)
|
|
|
|
// Call service method
|
|
err := h.service.DeleteSEP(ctx, nosep)
|
|
|
|
if err != nil {
|
|
h.logger.Error("Failed to delete Sep", "error", err.Error(), "request_id", requestID)
|
|
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Internal server error",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
response := reference.BaseResponse{
|
|
Status: "success",
|
|
Message: "Sep deleted successfully",
|
|
RequestID: requestID,
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// GetRUJUKAN retrieves Rujukan data
|
|
// @Summary Get Rujukan data
|
|
// @Description Get referral information
|
|
// @Tags vclaim,rujukan
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param norujukan path string true "Norujukan"
|
|
// @Success 200 {object} reference.RujukanResponse
|
|
// @Failure 400 {object} reference.ErrorResponse
|
|
// @Failure 500 {object} reference.ErrorResponse
|
|
// @Router /rujukan/:norujukan [get]
|
|
func (h *VClaimHandler) GetRUJUKAN(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)
|
|
}
|
|
// Authentication check
|
|
if err := h.authenticateRequest(c); err != nil {
|
|
h.logger.Error("Authentication failed", "error", err.Error(), "request_id", requestID)
|
|
c.JSON(http.StatusUnauthorized, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Authentication failed",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Extract path parameters
|
|
norujukan := c.Param("norujukan")
|
|
if norujukan == "" {
|
|
h.logger.Error("Missing required parameter: norujukan", "request_id", requestID)
|
|
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Missing required parameter: norujukan",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
// Check cache first
|
|
cacheKey := fmt.Sprintf("vclaim:rujukan:%s", norujukan)
|
|
if cached, found := h.getCachedResponse(cacheKey); found {
|
|
h.logger.Info("Cache hit for GetRUJUKAN", "request_id", requestID, "cache_key", cacheKey)
|
|
c.Header("X-Cache", "HIT")
|
|
c.JSON(http.StatusOK, cached)
|
|
return
|
|
}
|
|
|
|
h.logger.Info("Processing GetRUJUKAN request",
|
|
"request_id", requestID,
|
|
"endpoint", "/rujukan/:norujukan",
|
|
"norujukan", norujukan)
|
|
|
|
// Call service method
|
|
result, err := h.service.GetRUJUKAN(ctx, norujukan)
|
|
|
|
if err != nil {
|
|
h.logger.Error("Failed to get Rujukan",
|
|
"error", err.Error(),
|
|
"request_id", requestID)
|
|
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
|
|
Status: "error",
|
|
Message: "Internal server error",
|
|
RequestID: requestID,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Prepare response
|
|
response := reference.RujukanResponse{
|
|
Status: "success",
|
|
Data: result,
|
|
RequestID: requestID,
|
|
}
|
|
// Cache successful response
|
|
h.setCachedResponse(cacheKey, response, 600)
|
|
|
|
c.Header("X-Cache", "MISS")
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// RegisterRoutes registers all VClaim routes
|
|
func (h *VClaimHandler) RegisterRoutes(router *gin.RouterGroup) {
|
|
|
|
router.GET("/Peserta/:nokartu", h.GetPESERTA)
|
|
|
|
router.GET("/SEP/:nosep", h.GetSEP)
|
|
router.POST("/sep", h.CreateSEP)
|
|
router.PUT("/sep/:nosep", h.UpdateSEP)
|
|
router.DELETE("/sep/:nosep", h.DeleteSEP)
|
|
|
|
router.GET("/rujukan/:norujukan", h.GetRUJUKAN)
|
|
|
|
}
|
|
|
|
// Helper methods
|
|
func (h *VClaimHandler) authenticateRequest(c *gin.Context) error {
|
|
token := c.GetHeader("Authorization")
|
|
if token == "" {
|
|
return fmt.Errorf("missing authorization header")
|
|
}
|
|
|
|
if strings.HasPrefix(token, "Bearer ") {
|
|
token = strings.TrimPrefix(token, "Bearer ")
|
|
}
|
|
|
|
return h.auth.ValidateToken(token)
|
|
}
|
|
func (h *VClaimHandler) getCachedResponse(key string) (interface{}, bool) {
|
|
if h.cache == nil {
|
|
return nil, false
|
|
}
|
|
return h.cache.Get(key)
|
|
}
|
|
|
|
func (h *VClaimHandler) setCachedResponse(key string, data interface{}, ttl int) {
|
|
if h.cache == nil {
|
|
return
|
|
}
|
|
h.cache.Set(key, data, time.Duration(ttl)*time.Second)
|
|
}
|
|
|
|
func (h *VClaimHandler) invalidateCache(key string) {
|
|
if h.cache == nil {
|
|
return
|
|
}
|
|
h.cache.Delete(key)
|
|
}
|