Clear generete structur bpjsAll

This commit is contained in:
2025-09-07 11:04:37 +07:00
parent b438fd8dd4
commit 779bbc976c
16 changed files with 13084 additions and 4378 deletions

View File

@@ -134,7 +134,8 @@ make build # Build production
### Update Swagger ### Update Swagger
```bash ```bash
swag init -g cmd/api/main.go --parseDependency --parseInternal swag init -g cmd/api/main.go --parseDependency --parseInternal # Alternative Kedua
swag init -g cmd/api/main.go -o docs/
``` ```
## 🔧 Environment Variables ## 🔧 Environment Variables

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,291 @@
// Package peserta handles Peserta BPJS services
// Generated on: 2025-09-07 11:01:18
package handlers
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"
"api-service/internal/config"
"api-service/internal/models"
"api-service/internal/models/vclaim/peserta"
"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
type PesertaHandler struct {
service services.VClaimService
validator *validator.Validate
logger logger.Logger
config config.BpjsConfig
}
// PesertaHandlerConfig contains configuration for PesertaHandler
type PesertaHandlerConfig struct {
BpjsConfig config.BpjsConfig
Logger logger.Logger
Validator *validator.Validate
}
// NewPesertaHandler creates a new PesertaHandler
func NewPesertaHandler(cfg PesertaHandlerConfig) *PesertaHandler {
return &PesertaHandler{
service: services.NewService(cfg.BpjsConfig),
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.BpjsConfig,
}
}
// GetBynik godoc
// @Summary Get Bynik data
// @Description Get participant eligibility information by NIK
// @Tags Peserta
// @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} peserta.PesertaResponse "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 /Peserta/nik/:nik [get]
func (h *PesertaHandler) GetBynik(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)
}
h.logger.Info("Processing GetBynik request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/peserta/nik/:nik",
"nik": c.Param("nik"),
})
// Extract path parameters
nik := c.Param("nik")
if nik == "" {
h.logger.Error("Missing required parameter nik", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Missing required parameter nik",
RequestID: requestID,
})
return
}
// Call service method
var response peserta.PesertaResponse
endpoint := "/peserta/nik/:nik"
endpoint = strings.Replace(endpoint, ":nik", nik, 1)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil {
h.logger.Error("Failed to get Bynik", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &peserta.PesertaData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["peserta"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
c.JSON(http.StatusOK, response)
}
// GetBynokartu godoc
// @Summary Get Bynokartu data
// @Description Get participant eligibility information by card number
// @Tags Peserta
// @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} peserta.PesertaResponse "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 /Peserta/nokartu/:nokartu [get]
func (h *PesertaHandler) 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)
}
h.logger.Info("Processing GetBynokartu request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/peserta/:nokartu",
"nokartu": c.Param("nokartu"),
})
// Extract path parameters
nokartu := c.Param("nokartu")
if nokartu == "" {
h.logger.Error("Missing required parameter nokartu", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Missing required parameter nokartu",
RequestID: requestID,
})
return
}
// Call service method
var response peserta.PesertaResponse
endpoint := "/peserta/:nokartu"
endpoint = strings.Replace(endpoint, ":nokartu", nokartu, 1)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil {
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
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &peserta.PesertaData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["peserta"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
c.JSON(http.StatusOK, response)
}

View File

@@ -4,7 +4,7 @@ import (
"api-service/internal/config" "api-service/internal/config"
"api-service/internal/database" "api-service/internal/database"
models "api-service/internal/models" models "api-service/internal/models"
modelsretribusi "api-service/internal/models/retribusi" "api-service/internal/models/retribusi"
utils "api-service/internal/utils/filters" utils "api-service/internal/utils/filters"
"api-service/internal/utils/validation" "api-service/internal/utils/validation"
"api-service/pkg/logger" "api-service/pkg/logger"
@@ -73,7 +73,7 @@ func NewRetribusiHandler() *RetribusiHandler {
// @Param jenis query string false "Filter by jenis" // @Param jenis query string false "Filter by jenis"
// @Param dinas query string false "Filter by dinas" // @Param dinas query string false "Filter by dinas"
// @Param search query string false "Search in multiple fields" // @Param search query string false "Search in multiple fields"
// @Success 200 {object} modelsretribusi.RetribusiGetResponse "Success response" // @Success 200 {object} retribusi.RetribusiGetResponse "Success response"
// @Failure 400 {object} models.ErrorResponse "Bad request" // @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 500 {object} models.ErrorResponse "Internal server error" // @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /api/v1/retribusis [get] // @Router /api/v1/retribusis [get]
@@ -102,7 +102,7 @@ func (h *RetribusiHandler) GetRetribusi(c *gin.Context) {
// Execute concurrent operations // Execute concurrent operations
var ( var (
retribusis []modelsretribusi.Retribusi retribusis []retribusi.Retribusi
total int total int
aggregateData *models.AggregateData aggregateData *models.AggregateData
wg sync.WaitGroup wg sync.WaitGroup
@@ -165,7 +165,7 @@ func (h *RetribusiHandler) GetRetribusi(c *gin.Context) {
// Build response // Build response
meta := h.calculateMeta(limit, offset, total) meta := h.calculateMeta(limit, offset, total)
response := modelsretribusi.RetribusiGetResponse{ response := retribusi.RetribusiGetResponse{
Message: "Data retribusi berhasil diambil", Message: "Data retribusi berhasil diambil",
Data: retribusis, Data: retribusis,
Meta: meta, Meta: meta,
@@ -185,7 +185,7 @@ func (h *RetribusiHandler) GetRetribusi(c *gin.Context) {
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path string true "Retribusi ID (UUID)" // @Param id path string true "Retribusi ID (UUID)"
// @Success 200 {object} modelsretribusi.RetribusiGetByIDResponse "Success response" // @Success 200 {object} retribusi.RetribusiGetByIDResponse "Success response"
// @Failure 400 {object} models.ErrorResponse "Invalid ID format" // @Failure 400 {object} models.ErrorResponse "Invalid ID format"
// @Failure 404 {object} models.ErrorResponse "Retribusi not found" // @Failure 404 {object} models.ErrorResponse "Retribusi not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error" // @Failure 500 {object} models.ErrorResponse "Internal server error"
@@ -208,7 +208,7 @@ func (h *RetribusiHandler) GetRetribusiByID(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second) ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second)
defer cancel() defer cancel()
retribusi, err := h.getRetribusiByID(ctx, dbConn, id) dataretribusi, err := h.getRetribusiByID(ctx, dbConn, id)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
h.respondError(c, "Retribusi not found", err, http.StatusNotFound) h.respondError(c, "Retribusi not found", err, http.StatusNotFound)
@@ -218,9 +218,9 @@ func (h *RetribusiHandler) GetRetribusiByID(c *gin.Context) {
return return
} }
response := modelsretribusi.RetribusiGetByIDResponse{ response := retribusi.RetribusiGetByIDResponse{
Message: "Retribusi details retrieved successfully", Message: "Retribusi details retrieved successfully",
Data: retribusi, Data: dataretribusi,
} }
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
@@ -237,7 +237,7 @@ func (h *RetribusiHandler) GetRetribusiByID(c *gin.Context) {
// @Param sort query string false "Sort fields (e.g., sort=date_created,-Jenis)" // @Param sort query string false "Sort fields (e.g., sort=date_created,-Jenis)"
// @Param limit query int false "Limit" default(10) // @Param limit query int false "Limit" default(10)
// @Param offset query int false "Offset" default(0) // @Param offset query int false "Offset" default(0)
// @Success 200 {object} modelsretribusi.RetribusiGetResponse "Success response" // @Success 200 {object} retribusi.RetribusiGetResponse "Success response"
// @Failure 400 {object} models.ErrorResponse "Bad request" // @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 500 {object} models.ErrorResponse "Internal server error" // @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /api/v1/retribusis/dynamic [get] // @Router /api/v1/retribusis/dynamic [get]
@@ -270,7 +270,7 @@ func (h *RetribusiHandler) GetRetribusiDynamic(c *gin.Context) {
// Build response // Build response
meta := h.calculateMeta(dynamicQuery.Limit, dynamicQuery.Offset, total) meta := h.calculateMeta(dynamicQuery.Limit, dynamicQuery.Offset, total)
response := modelsretribusi.RetribusiGetResponse{ response := retribusi.RetribusiGetResponse{
Message: "Data retribusi berhasil diambil", Message: "Data retribusi berhasil diambil",
Data: retribusis, Data: retribusis,
Meta: meta, Meta: meta,
@@ -280,7 +280,7 @@ func (h *RetribusiHandler) GetRetribusiDynamic(c *gin.Context) {
} }
// fetchRetribusisDynamic executes dynamic query // fetchRetribusisDynamic executes dynamic query
func (h *RetribusiHandler) fetchRetribusisDynamic(ctx context.Context, dbConn *sql.DB, query utils.DynamicQuery) ([]modelsretribusi.Retribusi, int, error) { func (h *RetribusiHandler) fetchRetribusisDynamic(ctx context.Context, dbConn *sql.DB, query utils.DynamicQuery) ([]retribusi.Retribusi, int, error) {
// Setup query builder // Setup query builder
builder := utils.NewQueryBuilder("data_retribusi"). builder := utils.NewQueryBuilder("data_retribusi").
SetColumnMapping(map[string]string{ SetColumnMapping(map[string]string{
@@ -319,7 +319,7 @@ func (h *RetribusiHandler) fetchRetribusisDynamic(ctx context.Context, dbConn *s
// Execute concurrent queries // Execute concurrent queries
var ( var (
retribusis []modelsretribusi.Retribusi retribusis []retribusi.Retribusi
total int total int
wg sync.WaitGroup wg sync.WaitGroup
errChan = make(chan error, 2) errChan = make(chan error, 2)
@@ -364,7 +364,7 @@ func (h *RetribusiHandler) fetchRetribusisDynamic(ctx context.Context, dbConn *s
} }
defer rows.Close() defer rows.Close()
var results []modelsretribusi.Retribusi var results []retribusi.Retribusi
for rows.Next() { for rows.Next() {
retribusi, err := h.scanRetribusi(rows) retribusi, err := h.scanRetribusi(rows)
if err != nil { if err != nil {
@@ -484,7 +484,7 @@ func (h *RetribusiHandler) SearchRetribusiAdvanced(c *gin.Context) {
// Build response // Build response
meta := h.calculateMeta(query.Limit, query.Offset, total) meta := h.calculateMeta(query.Limit, query.Offset, total)
response := modelsretribusi.RetribusiGetResponse{ response := retribusi.RetribusiGetResponse{
Message: fmt.Sprintf("Search results for '%s'", searchQuery), Message: fmt.Sprintf("Search results for '%s'", searchQuery),
Data: retribusis, Data: retribusis,
Meta: meta, Meta: meta,
@@ -499,13 +499,13 @@ func (h *RetribusiHandler) SearchRetribusiAdvanced(c *gin.Context) {
// @Tags Retribusi // @Tags Retribusi
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param request body modelsretribusi.RetribusiCreateRequest true "Retribusi creation request" // @Param request body retribusi.RetribusiCreateRequest true "Retribusi creation request"
// @Success 201 {object} modelsretribusi.RetribusiCreateResponse "Retribusi created successfully" // @Success 201 {object} retribusi.RetribusiCreateResponse "Retribusi created successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request or validation error" // @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
// @Failure 500 {object} models.ErrorResponse "Internal server error" // @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /api/v1/retribusis [post] // @Router /api/v1/retribusis [post]
func (h *RetribusiHandler) CreateRetribusi(c *gin.Context) { func (h *RetribusiHandler) CreateRetribusi(c *gin.Context) {
var req modelsretribusi.RetribusiCreateRequest var req retribusi.RetribusiCreateRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
h.respondError(c, "Invalid request body", err, http.StatusBadRequest) h.respondError(c, "Invalid request body", err, http.StatusBadRequest)
@@ -533,15 +533,15 @@ func (h *RetribusiHandler) CreateRetribusi(c *gin.Context) {
return return
} }
retribusi, err := h.createRetribusi(ctx, dbConn, &req) dataretribusi, err := h.createRetribusi(ctx, dbConn, &req)
if err != nil { if err != nil {
h.logAndRespondError(c, "Failed to create retribusi", err, http.StatusInternalServerError) h.logAndRespondError(c, "Failed to create retribusi", err, http.StatusInternalServerError)
return return
} }
response := modelsretribusi.RetribusiCreateResponse{ response := retribusi.RetribusiCreateResponse{
Message: "Retribusi berhasil dibuat", Message: "Retribusi berhasil dibuat",
Data: retribusi, Data: dataretribusi,
} }
c.JSON(http.StatusCreated, response) c.JSON(http.StatusCreated, response)
@@ -554,8 +554,8 @@ func (h *RetribusiHandler) CreateRetribusi(c *gin.Context) {
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path string true "Retribusi ID (UUID)" // @Param id path string true "Retribusi ID (UUID)"
// @Param request body modelsretribusi.RetribusiUpdateRequest true "Retribusi update request" // @Param request body retribusi.RetribusiUpdateRequest true "Retribusi update request"
// @Success 200 {object} modelsretribusi.RetribusiUpdateResponse "Retribusi updated successfully" // @Success 200 {object} retribusi.RetribusiUpdateResponse "Retribusi updated successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request or validation error" // @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
// @Failure 404 {object} models.ErrorResponse "Retribusi not found" // @Failure 404 {object} models.ErrorResponse "Retribusi not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error" // @Failure 500 {object} models.ErrorResponse "Internal server error"
@@ -569,7 +569,7 @@ func (h *RetribusiHandler) UpdateRetribusi(c *gin.Context) {
return return
} }
var req modelsretribusi.RetribusiUpdateRequest var req retribusi.RetribusiUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
h.respondError(c, "Invalid request body", err, http.StatusBadRequest) h.respondError(c, "Invalid request body", err, http.StatusBadRequest)
return return
@@ -593,7 +593,7 @@ func (h *RetribusiHandler) UpdateRetribusi(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second) ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second)
defer cancel() defer cancel()
retribusi, err := h.updateRetribusi(ctx, dbConn, &req) dataretribusi, err := h.updateRetribusi(ctx, dbConn, &req)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
h.respondError(c, "Retribusi not found", err, http.StatusNotFound) h.respondError(c, "Retribusi not found", err, http.StatusNotFound)
@@ -603,9 +603,9 @@ func (h *RetribusiHandler) UpdateRetribusi(c *gin.Context) {
return return
} }
response := modelsretribusi.RetribusiUpdateResponse{ response := retribusi.RetribusiUpdateResponse{
Message: "Retribusi berhasil diperbarui", Message: "Retribusi berhasil diperbarui",
Data: retribusi, Data: dataretribusi,
} }
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
@@ -618,7 +618,7 @@ func (h *RetribusiHandler) UpdateRetribusi(c *gin.Context) {
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path string true "Retribusi ID (UUID)" // @Param id path string true "Retribusi ID (UUID)"
// @Success 200 {object} modelsretribusi.RetribusiDeleteResponse "Retribusi deleted successfully" // @Success 200 {object} retribusi.RetribusiDeleteResponse "Retribusi deleted successfully"
// @Failure 400 {object} models.ErrorResponse "Invalid ID format" // @Failure 400 {object} models.ErrorResponse "Invalid ID format"
// @Failure 404 {object} models.ErrorResponse "Retribusi not found" // @Failure 404 {object} models.ErrorResponse "Retribusi not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error" // @Failure 500 {object} models.ErrorResponse "Internal server error"
@@ -651,7 +651,7 @@ func (h *RetribusiHandler) DeleteRetribusi(c *gin.Context) {
return return
} }
response := modelsretribusi.RetribusiDeleteResponse{ response := retribusi.RetribusiDeleteResponse{
Message: "Retribusi berhasil dihapus", Message: "Retribusi berhasil dihapus",
ID: id, ID: id,
} }
@@ -693,7 +693,7 @@ func (h *RetribusiHandler) GetRetribusiStats(c *gin.Context) {
} }
// Get retribusi by ID // Get retribusi by ID
func (h *RetribusiHandler) getRetribusiByID(ctx context.Context, dbConn *sql.DB, id string) (*modelsretribusi.Retribusi, error) { func (h *RetribusiHandler) getRetribusiByID(ctx context.Context, dbConn *sql.DB, id string) (*retribusi.Retribusi, error) {
query := ` query := `
SELECT SELECT
id, status, sort, user_created, date_created, user_updated, date_updated, id, status, sort, user_created, date_created, user_updated, date_updated,
@@ -705,7 +705,7 @@ func (h *RetribusiHandler) getRetribusiByID(ctx context.Context, dbConn *sql.DB,
row := dbConn.QueryRowContext(ctx, query, id) row := dbConn.QueryRowContext(ctx, query, id)
var retribusi modelsretribusi.Retribusi var retribusi retribusi.Retribusi
err := row.Scan( err := row.Scan(
&retribusi.ID, &retribusi.Status, &retribusi.Sort, &retribusi.UserCreated, &retribusi.ID, &retribusi.Status, &retribusi.Sort, &retribusi.UserCreated,
&retribusi.DateCreated, &retribusi.UserUpdated, &retribusi.DateUpdated, &retribusi.DateCreated, &retribusi.UserUpdated, &retribusi.DateUpdated,
@@ -723,7 +723,7 @@ func (h *RetribusiHandler) getRetribusiByID(ctx context.Context, dbConn *sql.DB,
} }
// Create retribusi // Create retribusi
func (h *RetribusiHandler) createRetribusi(ctx context.Context, dbConn *sql.DB, req *modelsretribusi.RetribusiCreateRequest) (*modelsretribusi.Retribusi, error) { func (h *RetribusiHandler) createRetribusi(ctx context.Context, dbConn *sql.DB, req *retribusi.RetribusiCreateRequest) (*retribusi.Retribusi, error) {
id := uuid.New().String() id := uuid.New().String()
now := time.Now() now := time.Now()
@@ -747,7 +747,7 @@ func (h *RetribusiHandler) createRetribusi(ctx context.Context, dbConn *sql.DB,
req.RekeningPokok, req.RekeningDenda, req.Uraian1, req.Uraian2, req.Uraian3, req.RekeningPokok, req.RekeningDenda, req.Uraian1, req.Uraian2, req.Uraian3,
) )
var retribusi modelsretribusi.Retribusi var retribusi retribusi.Retribusi
err := row.Scan( err := row.Scan(
&retribusi.ID, &retribusi.Status, &retribusi.Sort, &retribusi.UserCreated, &retribusi.ID, &retribusi.Status, &retribusi.Sort, &retribusi.UserCreated,
&retribusi.DateCreated, &retribusi.UserUpdated, &retribusi.DateUpdated, &retribusi.DateCreated, &retribusi.UserUpdated, &retribusi.DateUpdated,
@@ -765,7 +765,7 @@ func (h *RetribusiHandler) createRetribusi(ctx context.Context, dbConn *sql.DB,
} }
// Update retribusi // Update retribusi
func (h *RetribusiHandler) updateRetribusi(ctx context.Context, dbConn *sql.DB, req *modelsretribusi.RetribusiUpdateRequest) (*modelsretribusi.Retribusi, error) { func (h *RetribusiHandler) updateRetribusi(ctx context.Context, dbConn *sql.DB, req *retribusi.RetribusiUpdateRequest) (*retribusi.Retribusi, error) {
now := time.Now() now := time.Now()
query := ` query := `
@@ -788,7 +788,7 @@ func (h *RetribusiHandler) updateRetribusi(ctx context.Context, dbConn *sql.DB,
req.RekeningPokok, req.RekeningDenda, req.Uraian1, req.Uraian2, req.Uraian3, req.RekeningPokok, req.RekeningDenda, req.Uraian1, req.Uraian2, req.Uraian3,
) )
var retribusi modelsretribusi.Retribusi var retribusi retribusi.Retribusi
err := row.Scan( err := row.Scan(
&retribusi.ID, &retribusi.Status, &retribusi.Sort, &retribusi.UserCreated, &retribusi.ID, &retribusi.Status, &retribusi.Sort, &retribusi.UserCreated,
&retribusi.DateCreated, &retribusi.UserUpdated, &retribusi.DateUpdated, &retribusi.DateCreated, &retribusi.UserUpdated, &retribusi.DateUpdated,
@@ -889,7 +889,7 @@ func (h *RetribusiHandler) parsePaginationParams(c *gin.Context) (int, int, erro
} }
// Build WHERE clause dengan filter parameters // Build WHERE clause dengan filter parameters
func (h *RetribusiHandler) buildWhereClause(filter modelsretribusi.RetribusiFilter) (string, []interface{}) { func (h *RetribusiHandler) buildWhereClause(filter retribusi.RetribusiFilter) (string, []interface{}) {
conditions := []string{"status != 'deleted'"} conditions := []string{"status != 'deleted'"}
args := []interface{}{} args := []interface{}{}
paramCount := 1 paramCount := 1
@@ -950,8 +950,8 @@ func (h *RetribusiHandler) buildWhereClause(filter modelsretribusi.RetribusiFilt
} }
// Optimized scanning function yang menggunakan sql.Null* types langsung // Optimized scanning function yang menggunakan sql.Null* types langsung
func (h *RetribusiHandler) scanRetribusi(rows *sql.Rows) (modelsretribusi.Retribusi, error) { func (h *RetribusiHandler) scanRetribusi(rows *sql.Rows) (retribusi.Retribusi, error) {
var retribusi modelsretribusi.Retribusi var retribusi retribusi.Retribusi
return retribusi, rows.Scan( return retribusi, rows.Scan(
&retribusi.ID, &retribusi.ID,
@@ -979,8 +979,8 @@ func (h *RetribusiHandler) scanRetribusi(rows *sql.Rows) (modelsretribusi.Retrib
} }
// Parse filter parameters dari query string // Parse filter parameters dari query string
func (h *RetribusiHandler) parseFilterParams(c *gin.Context) modelsretribusi.RetribusiFilter { func (h *RetribusiHandler) parseFilterParams(c *gin.Context) retribusi.RetribusiFilter {
filter := modelsretribusi.RetribusiFilter{} filter := retribusi.RetribusiFilter{}
if status := c.Query("status"); status != "" { if status := c.Query("status"); status != "" {
if models.IsValidStatus(status) { if models.IsValidStatus(status) {
@@ -1021,7 +1021,7 @@ func (h *RetribusiHandler) parseFilterParams(c *gin.Context) modelsretribusi.Ret
} }
// Get comprehensive aggregate data dengan filter support // Get comprehensive aggregate data dengan filter support
func (h *RetribusiHandler) getAggregateData(ctx context.Context, dbConn *sql.DB, filter modelsretribusi.RetribusiFilter) (*models.AggregateData, error) { func (h *RetribusiHandler) getAggregateData(ctx context.Context, dbConn *sql.DB, filter retribusi.RetribusiFilter) (*models.AggregateData, error) {
aggregate := &models.AggregateData{ aggregate := &models.AggregateData{
ByStatus: make(map[string]int), ByStatus: make(map[string]int),
ByDinas: make(map[string]int), ByDinas: make(map[string]int),
@@ -1211,7 +1211,7 @@ func (h *RetribusiHandler) getAggregateData(ctx context.Context, dbConn *sql.DB,
} }
// Get total count dengan filter support // Get total count dengan filter support
func (h *RetribusiHandler) getTotalCount(ctx context.Context, dbConn *sql.DB, filter modelsretribusi.RetribusiFilter, total *int) error { func (h *RetribusiHandler) getTotalCount(ctx context.Context, dbConn *sql.DB, filter retribusi.RetribusiFilter, total *int) error {
whereClause, args := h.buildWhereClause(filter) whereClause, args := h.buildWhereClause(filter)
countQuery := fmt.Sprintf(`SELECT COUNT(*) FROM data_retribusi WHERE %s`, whereClause) countQuery := fmt.Sprintf(`SELECT COUNT(*) FROM data_retribusi WHERE %s`, whereClause)
@@ -1223,7 +1223,7 @@ func (h *RetribusiHandler) getTotalCount(ctx context.Context, dbConn *sql.DB, fi
} }
// Enhanced fetchRetribusis dengan filter support // Enhanced fetchRetribusis dengan filter support
func (h *RetribusiHandler) fetchRetribusis(ctx context.Context, dbConn *sql.DB, filter modelsretribusi.RetribusiFilter, limit, offset int) ([]modelsretribusi.Retribusi, error) { func (h *RetribusiHandler) fetchRetribusis(ctx context.Context, dbConn *sql.DB, filter retribusi.RetribusiFilter, limit, offset int) ([]retribusi.Retribusi, error) {
whereClause, args := h.buildWhereClause(filter) whereClause, args := h.buildWhereClause(filter)
// Build the main query with pagination // Build the main query with pagination
@@ -1249,7 +1249,7 @@ func (h *RetribusiHandler) fetchRetribusis(ctx context.Context, dbConn *sql.DB,
defer rows.Close() defer rows.Close()
// Pre-allocate slice dengan kapasitas yang tepat // Pre-allocate slice dengan kapasitas yang tepat
retribusis := make([]modelsretribusi.Retribusi, 0, limit) retribusis := make([]retribusi.Retribusi, 0, limit)
for rows.Next() { for rows.Next() {
retribusi, err := h.scanRetribusi(rows) retribusi, err := h.scanRetribusi(rows)
@@ -1293,7 +1293,7 @@ func (h *RetribusiHandler) calculateMeta(limit, offset, total int) models.MetaRe
} }
// validateRetribusiSubmission performs validation for duplicate entries and daily submission limits // validateRetribusiSubmission performs validation for duplicate entries and daily submission limits
func (h *RetribusiHandler) validateRetribusiSubmission(ctx context.Context, dbConn *sql.DB, req *modelsretribusi.RetribusiCreateRequest) error { func (h *RetribusiHandler) validateRetribusiSubmission(ctx context.Context, dbConn *sql.DB, req *retribusi.RetribusiCreateRequest) error {
// Import the validation utility // Import the validation utility
validator := validation.NewDuplicateValidator(dbConn) validator := validation.NewDuplicateValidator(dbConn)
@@ -1316,7 +1316,7 @@ func (h *RetribusiHandler) validateRetribusiSubmission(ctx context.Context, dbCo
} }
// Example usage of the validation utility with custom configuration // Example usage of the validation utility with custom configuration
func (h *RetribusiHandler) validateWithCustomConfig(ctx context.Context, dbConn *sql.DB, req *modelsretribusi.RetribusiCreateRequest) error { func (h *RetribusiHandler) validateWithCustomConfig(ctx context.Context, dbConn *sql.DB, req *retribusi.RetribusiCreateRequest) error {
// Create validator instance // Create validator instance
validator := validation.NewDuplicateValidator(dbConn) validator := validation.NewDuplicateValidator(dbConn)

View File

@@ -0,0 +1,885 @@
// Package rujukan handles Rujukan BPJS services
// Generated on: 2025-09-07 11:01:18
package handlers
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"
"api-service/internal/config"
"api-service/internal/models"
"api-service/internal/models/vclaim/rujukan"
"api-service/internal/services/bpjs"
"api-service/pkg/logger"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
// RujukanHandler handles Rujukan BPJS services
type RujukanHandler struct {
service services.VClaimService
validator *validator.Validate
logger logger.Logger
config config.BpjsConfig
}
// RujukanHandlerConfig contains configuration for RujukanHandler
type RujukanHandlerConfig struct {
BpjsConfig config.BpjsConfig
Logger logger.Logger
Validator *validator.Validate
}
// NewRujukanHandler creates a new RujukanHandler
func NewRujukanHandler(cfg RujukanHandlerConfig) *RujukanHandler {
return &RujukanHandler{
service: services.NewService(cfg.BpjsConfig),
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.BpjsConfig,
}
}
// CreateRujukan godoc
// @Summary Create new Rujukan
// @Description Create new Rujukan in BPJS system
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param request body rujukan.RujukanRequest true "Rujukan data"
// @Success 201 {object} rujukan.RujukanResponse "Successfully created Rujukan"
// @Failure 400 {object} models.ErrorResponseBpjs "Bad request"
// @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized"
// @Failure 409 {object} models.ErrorResponseBpjs "Conflict"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukan/:norujukan [post]
func (h *RujukanHandler) CreateRujukan(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)
}
h.logger.Info("Processing CreateRujukan request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukan",
})
// Bind and validate request body
var req rujukan.RujukanRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind request body", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// Validate request structure
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Request validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
// Call service method
var response rujukan.RujukanResponse
resp, err := h.service.PostRawResponse(ctx, "/Rujukan", req)
if err != nil {
h.logger.Error("Failed to create Rujukan", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
// Handle specific BPJS errors
if strings.Contains(err.Error(), "409") || strings.Contains(err.Error(), "conflict") {
c.JSON(http.StatusConflict, models.ErrorResponseBpjs{
Status: "error",
Message: "Rujukan already exists or conflict occurred",
RequestID: requestID,
})
return
}
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
h.logger.Info("Successfully created Rujukan", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusCreated, response)
}
// UpdateRujukan godoc
// @Summary Update existing Rujukan
// @Description Update existing Rujukan in BPJS system
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param request body rujukan.RujukanRequest true "Rujukan update data"
// @Success 200 {object} rujukan.RujukanResponse "Successfully updated Rujukan"
// @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 - Rujukan not found"
// @Failure 409 {object} models.ErrorResponseBpjs "Conflict - update conflict occurred"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukan/:norujukan [put]
func (h *RujukanHandler) UpdateRujukan(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)
}
h.logger.Info("Processing UpdateRujukan request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukan",
})
// Extract path parameters
// Bind and validate request body
var req rujukan.RujukanRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind request body", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// Validate request structure
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Request validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
// Call service method
var response rujukan.RujukanResponse
resp, err := h.service.PutRawResponse(ctx, "/Rujukan", req)
if err != nil {
h.logger.Error("Failed to update Rujukan", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
// Handle specific BPJS errors
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") {
c.JSON(http.StatusNotFound, models.ErrorResponseBpjs{
Status: "error",
Message: "Rujukan not found",
RequestID: requestID,
})
return
}
if strings.Contains(err.Error(), "409") || strings.Contains(err.Error(), "conflict") {
c.JSON(http.StatusConflict, models.ErrorResponseBpjs{
Status: "error",
Message: "Update conflict occurred",
RequestID: requestID,
})
return
}
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
h.logger.Info("Successfully updated Rujukan", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusOK, response)
}
// DeleteRujukan godoc
// @Summary Delete existing Rujukan
// @Description Delete existing Rujukan from BPJS system
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Success 200 {object} rujukan.RujukanResponse "Successfully deleted Rujukan"
// @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 - Rujukan not found"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukan/:norujukan [delete]
func (h *RujukanHandler) DeleteRujukan(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)
}
h.logger.Info("Processing DeleteRujukan request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukan",
})
// Extract path parameters
// Call service method
var response rujukan.RujukanResponse
resp, err := h.service.DeleteRawResponse(ctx, "/Rujukan")
if err != nil {
h.logger.Error("Failed to delete Rujukan", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
// Handle specific BPJS errors
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") {
c.JSON(http.StatusNotFound, models.ErrorResponseBpjs{
Status: "error",
Message: "Rujukan not found",
RequestID: requestID,
})
return
}
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
} else {
// For delete operations, sometimes there's no data in response
response.Data = nil
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
h.logger.Info("Successfully deleted Rujukan", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusOK, response)
}
// CreateRujukanbalik godoc
// @Summary Create new Rujukanbalik
// @Description Create new Rujukanbalik in BPJS system
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param request body rujukan.RujukanRequest true "Rujukanbalik data"
// @Success 201 {object} rujukan.RujukanResponse "Successfully created Rujukanbalik"
// @Failure 400 {object} models.ErrorResponseBpjs "Bad request"
// @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized"
// @Failure 409 {object} models.ErrorResponseBpjs "Conflict"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukanbalik/:norujukan [post]
func (h *RujukanHandler) CreateRujukanbalik(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)
}
h.logger.Info("Processing CreateRujukanbalik request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukanbalik",
})
// Bind and validate request body
var req rujukan.RujukanRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind request body", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// Validate request structure
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Request validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
// Call service method
var response rujukan.RujukanResponse
resp, err := h.service.PostRawResponse(ctx, "/Rujukanbalik", req)
if err != nil {
h.logger.Error("Failed to create Rujukanbalik", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
// Handle specific BPJS errors
if strings.Contains(err.Error(), "409") || strings.Contains(err.Error(), "conflict") {
c.JSON(http.StatusConflict, models.ErrorResponseBpjs{
Status: "error",
Message: "Rujukanbalik already exists or conflict occurred",
RequestID: requestID,
})
return
}
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
h.logger.Info("Successfully created Rujukanbalik", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusCreated, response)
}
// UpdateRujukanbalik godoc
// @Summary Update existing Rujukanbalik
// @Description Update existing Rujukanbalik in BPJS system
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param request body rujukan.RujukanRequest true "Rujukanbalik update data"
// @Success 200 {object} rujukan.RujukanResponse "Successfully updated Rujukanbalik"
// @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 - Rujukanbalik not found"
// @Failure 409 {object} models.ErrorResponseBpjs "Conflict - update conflict occurred"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukanbalik/:norujukan [put]
func (h *RujukanHandler) UpdateRujukanbalik(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)
}
h.logger.Info("Processing UpdateRujukanbalik request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukanbalik",
})
// Extract path parameters
// Bind and validate request body
var req rujukan.RujukanRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind request body", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// Validate request structure
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Request validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
// Call service method
var response rujukan.RujukanResponse
resp, err := h.service.PutRawResponse(ctx, "/Rujukanbalik", req)
if err != nil {
h.logger.Error("Failed to update Rujukanbalik", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
// Handle specific BPJS errors
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") {
c.JSON(http.StatusNotFound, models.ErrorResponseBpjs{
Status: "error",
Message: "Rujukanbalik not found",
RequestID: requestID,
})
return
}
if strings.Contains(err.Error(), "409") || strings.Contains(err.Error(), "conflict") {
c.JSON(http.StatusConflict, models.ErrorResponseBpjs{
Status: "error",
Message: "Update conflict occurred",
RequestID: requestID,
})
return
}
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
h.logger.Info("Successfully updated Rujukanbalik", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusOK, response)
}
// DeleteRujukanbalik godoc
// @Summary Delete existing Rujukanbalik
// @Description Delete existing Rujukanbalik from BPJS system
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Success 200 {object} rujukan.RujukanResponse "Successfully deleted Rujukanbalik"
// @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 - Rujukanbalik not found"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /Rujukanbalik/:norujukan [delete]
func (h *RujukanHandler) DeleteRujukanbalik(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)
}
h.logger.Info("Processing DeleteRujukanbalik request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukanbalik",
})
// Extract path parameters
// Call service method
var response rujukan.RujukanResponse
resp, err := h.service.DeleteRawResponse(ctx, "/Rujukanbalik")
if err != nil {
h.logger.Error("Failed to delete Rujukanbalik", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
// Handle specific BPJS errors
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") {
c.JSON(http.StatusNotFound, models.ErrorResponseBpjs{
Status: "error",
Message: "Rujukanbalik not found",
RequestID: requestID,
})
return
}
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
} else {
// For delete operations, sometimes there's no data in response
response.Data = nil
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
h.logger.Info("Successfully deleted Rujukanbalik", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusOK, response)
}

View File

@@ -0,0 +1,291 @@
// Package rujukan handles Search BPJS services
// Generated on: 2025-09-07 11:01:18
package handlers
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"
"api-service/internal/config"
"api-service/internal/models"
"api-service/internal/models/vclaim/rujukan"
"api-service/internal/services/bpjs"
"api-service/pkg/logger"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
// SearchHandler handles Search BPJS services
type SearchHandler struct {
service services.VClaimService
validator *validator.Validate
logger logger.Logger
config config.BpjsConfig
}
// SearchHandlerConfig contains configuration for SearchHandler
type SearchHandlerConfig struct {
BpjsConfig config.BpjsConfig
Logger logger.Logger
Validator *validator.Validate
}
// NewSearchHandler creates a new SearchHandler
func NewSearchHandler(cfg SearchHandlerConfig) *SearchHandler {
return &SearchHandler{
service: services.NewService(cfg.BpjsConfig),
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.BpjsConfig,
}
}
// GetBynorujukan godoc
// @Summary Get Bynorujukan data
// @Description Get rujukan by nomor rujukan
// @Tags Rujukan
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking"
// @Param norujukan path string true "norujukan" example("example_value")
// @Success 200 {object} rujukan.RujukanResponse "Successfully retrieved Bynorujukan 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 - Bynorujukan not found"
// @Failure 500 {object} models.ErrorResponseBpjs "Internal server error"
// @Router /bynorujukan/:norujukan [get]
func (h *SearchHandler) GetBynorujukan(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)
}
h.logger.Info("Processing GetBynorujukan request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukan/:norujukan",
"norujukan": c.Param("norujukan"),
})
// Extract path parameters
norujukan := c.Param("norujukan")
if norujukan == "" {
h.logger.Error("Missing required parameter norujukan", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Missing required parameter norujukan",
RequestID: requestID,
})
return
}
// Call service method
var response rujukan.RujukanResponse
endpoint := "/Rujukan/:norujukan"
endpoint = strings.Replace(endpoint, ":norujukan", norujukan, 1)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil {
h.logger.Error("Failed to get Bynorujukan", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
c.JSON(http.StatusOK, response)
}
// GetBynokartu godoc
// @Summary Get Bynokartu data
// @Description Get rujukan 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 /bynokartu/:nokartu [get]
func (h *SearchHandler) 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)
}
h.logger.Info("Processing GetBynokartu request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/Rujukan/:nokartu",
"nokartu": c.Param("nokartu"),
})
// Extract path parameters
nokartu := c.Param("nokartu")
if nokartu == "" {
h.logger.Error("Missing required parameter nokartu", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error",
Message: "Missing required parameter nokartu",
RequestID: requestID,
})
return
}
// Call service method
var response rujukan.RujukanResponse
endpoint := "/Rujukan/:nokartu"
endpoint = strings.Replace(endpoint, ":nokartu", nokartu, 1)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil {
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
}
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &rujukan.RujukanData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if dataMap, exists := respMap["rujukan"]; exists {
dataBytes, _ := json.Marshal(dataMap)
json.Unmarshal(dataBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
c.JSON(http.StatusOK, response)
}

View File

@@ -6,7 +6,7 @@ import (
"time" "time"
) )
// NullableInt32 is a custom type to replace sql.NullInt32 for swagger compatibility // NullableInt32 - your existing implementation
type NullableInt32 struct { type NullableInt32 struct {
Int32 int32 `json:"int32,omitempty"` Int32 int32 `json:"int32,omitempty"`
Valid bool `json:"valid"` Valid bool `json:"valid"`
@@ -31,6 +31,56 @@ func (n NullableInt32) Value() (driver.Value, error) {
return n.Int32, nil return n.Int32, nil
} }
// NullableString provides consistent nullable string handling
type NullableString struct {
String string `json:"string,omitempty"`
Valid bool `json:"valid"`
}
// Scan implements the sql.Scanner interface for NullableString
func (n *NullableString) Scan(value interface{}) error {
var ns sql.NullString
if err := ns.Scan(value); err != nil {
return err
}
n.String = ns.String
n.Valid = ns.Valid
return nil
}
// Value implements the driver.Valuer interface for NullableString
func (n NullableString) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return n.String, nil
}
// NullableTime provides consistent nullable time handling
type NullableTime struct {
Time time.Time `json:"time,omitempty"`
Valid bool `json:"valid"`
}
// Scan implements the sql.Scanner interface for NullableTime
func (n *NullableTime) Scan(value interface{}) error {
var nt sql.NullTime
if err := nt.Scan(value); err != nil {
return err
}
n.Time = nt.Time
n.Valid = nt.Valid
return nil
}
// Value implements the driver.Valuer interface for NullableTime
func (n NullableTime) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return n.Time, nil
}
// Metadata untuk pagination - dioptimalkan // Metadata untuk pagination - dioptimalkan
type MetaResponse struct { type MetaResponse struct {
Limit int `json:"limit"` Limit int `json:"limit"`

View File

@@ -1,8 +1,7 @@
package models package retribusi
import ( import (
"api-service/internal/models" "api-service/internal/models"
"database/sql"
"encoding/json" "encoding/json"
"time" "time"
) )
@@ -10,27 +9,27 @@ import (
// Retribusi represents the data structure for the retribusi table // Retribusi represents the data structure for the retribusi table
// with proper null handling and optimized JSON marshaling // with proper null handling and optimized JSON marshaling
type Retribusi struct { type Retribusi struct {
ID string `json:"id" db:"id"` ID string `json:"id" db:"id"`
Status string `json:"status" db:"status"` Status string `json:"status" db:"status"`
Sort models.NullableInt32 `json:"sort,omitempty" db:"sort"` Sort models.NullableInt32 `json:"sort,omitempty" db:"sort"`
UserCreated sql.NullString `json:"user_created,omitempty" db:"user_created"` UserCreated models.NullableString `json:"user_created,omitempty" db:"user_created"`
DateCreated sql.NullTime `json:"date_created,omitempty" db:"date_created"` DateCreated models.NullableTime `json:"date_created,omitempty" db:"date_created"`
UserUpdated sql.NullString `json:"user_updated,omitempty" db:"user_updated"` UserUpdated models.NullableString `json:"user_updated,omitempty" db:"user_updated"`
DateUpdated sql.NullTime `json:"date_updated,omitempty" db:"date_updated"` DateUpdated models.NullableTime `json:"date_updated,omitempty" db:"date_updated"`
Jenis sql.NullString `json:"jenis,omitempty" db:"Jenis"` Jenis models.NullableString `json:"jenis,omitempty" db:"Jenis"`
Pelayanan sql.NullString `json:"pelayanan,omitempty" db:"Pelayanan"` Pelayanan models.NullableString `json:"pelayanan,omitempty" db:"Pelayanan"`
Dinas sql.NullString `json:"dinas,omitempty" db:"Dinas"` Dinas models.NullableString `json:"dinas,omitempty" db:"Dinas"`
KelompokObyek sql.NullString `json:"kelompok_obyek,omitempty" db:"Kelompok_obyek"` KelompokObyek models.NullableString `json:"kelompok_obyek,omitempty" db:"Kelompok_obyek"`
KodeTarif sql.NullString `json:"kode_tarif,omitempty" db:"Kode_tarif"` KodeTarif models.NullableString `json:"kode_tarif,omitempty" db:"Kode_tarif"`
Tarif sql.NullString `json:"tarif,omitempty" db:"Tarif"` Tarif models.NullableString `json:"tarif,omitempty" db:"Tarif"`
Satuan sql.NullString `json:"satuan,omitempty" db:"Satuan"` Satuan models.NullableString `json:"satuan,omitempty" db:"Satuan"`
TarifOvertime sql.NullString `json:"tarif_overtime,omitempty" db:"Tarif_overtime"` TarifOvertime models.NullableString `json:"tarif_overtime,omitempty" db:"Tarif_overtime"`
SatuanOvertime sql.NullString `json:"satuan_overtime,omitempty" db:"Satuan_overtime"` SatuanOvertime models.NullableString `json:"satuan_overtime,omitempty" db:"Satuan_overtime"`
RekeningPokok sql.NullString `json:"rekening_pokok,omitempty" db:"Rekening_pokok"` RekeningPokok models.NullableString `json:"rekening_pokok,omitempty" db:"Rekening_pokok"`
RekeningDenda sql.NullString `json:"rekening_denda,omitempty" db:"Rekening_denda"` RekeningDenda models.NullableString `json:"rekening_denda,omitempty" db:"Rekening_denda"`
Uraian1 sql.NullString `json:"uraian_1,omitempty" db:"Uraian_1"` Uraian1 models.NullableString `json:"uraian_1,omitempty" db:"Uraian_1"`
Uraian2 sql.NullString `json:"uraian_2,omitempty" db:"Uraian_2"` Uraian2 models.NullableString `json:"uraian_2,omitempty" db:"Uraian_2"`
Uraian3 sql.NullString `json:"uraian_3,omitempty" db:"Uraian_3"` Uraian3 models.NullableString `json:"uraian_3,omitempty" db:"Uraian_3"`
} }
// Custom JSON marshaling untuk Retribusi agar NULL values tidak muncul di response // Custom JSON marshaling untuk Retribusi agar NULL values tidak muncul di response

View File

@@ -17,7 +17,7 @@ type RujukanData struct {
Keluhan string `json:"keluhan"` Keluhan string `json:"keluhan"`
NoKunjungan string `json:"noKunjungan"` NoKunjungan string `json:"noKunjungan"`
Pelayanan PelayananData `json:"pelayanan"` Pelayanan PelayananData `json:"pelayanan"`
Peserta PesertaData `json:"peserta"` Peserta DataPeserta `json:"peserta"`
PoliRujukan PoliRujukanData `json:"poliRujukan"` PoliRujukan PoliRujukanData `json:"poliRujukan"`
ProvPerujuk ProvPerujukData `json:"provPerujuk"` ProvPerujuk ProvPerujukData `json:"provPerujuk"`
TglKunjungan string `json:"tglKunjungan"` TglKunjungan string `json:"tglKunjungan"`
@@ -43,7 +43,7 @@ type ProvPerujukData struct {
Nama string `json:"nama"` Nama string `json:"nama"`
} }
type PesertaData struct { type DataPeserta struct {
NoKartu string `json:"noKartu"` NoKartu string `json:"noKartu"`
NIK string `json:"nik"` NIK string `json:"nik"`
Nama string `json:"nama"` Nama string `json:"nama"`

View File

@@ -5,12 +5,15 @@ import (
"api-service/internal/database" "api-service/internal/database"
authHandlers "api-service/internal/handlers/auth" authHandlers "api-service/internal/handlers/auth"
healthcheckHandlers "api-service/internal/handlers/healthcheck" healthcheckHandlers "api-service/internal/handlers/healthcheck"
pesertaHandlers "api-service/internal/handlers/peserta"
retribusiHandlers "api-service/internal/handlers/retribusi" retribusiHandlers "api-service/internal/handlers/retribusi"
rujukanHandlers "api-service/internal/handlers/rujukan"
"api-service/internal/middleware" "api-service/internal/middleware"
services "api-service/internal/services/auth" services "api-service/internal/services/auth"
"api-service/pkg/logger" "api-service/pkg/logger"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
swaggerFiles "github.com/swaggo/files" swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger" ginSwagger "github.com/swaggo/gin-swagger"
) )
@@ -42,7 +45,19 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
sistem.GET("/health", healthCheckHandler.CheckHealth) sistem.GET("/health", healthCheckHandler.CheckHealth)
// Swagger UI route // Swagger UI route
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) router.GET("/swagger/*any", ginSwagger.WrapHandler(
swaggerFiles.Handler, // Models configuration
ginSwagger.DefaultModelsExpandDepth(-1), // Hide models completely
// ginSwagger.DefaultModelExpandDepth(0), // Keep individual models collapsed
// General UI configuration
// ginSwagger.DocExpansion("none"), // Collapse all sections
ginSwagger.DeepLinking(true), // Enable deep linking
// ginSwagger.PersistAuthorization(true), // Persist auth between refreshes
// // Optional: Custom title
// ginSwagger.InstanceName("API Service v1.0.0"),
))
// API v1 group // API v1 group
v1 := router.Group("/api/v1") v1 := router.Group("/api/v1")
@@ -66,37 +81,39 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
// ============= PUBLISHED ROUTES =============================================== // ============= PUBLISHED ROUTES ===============================================
// // Rujukan routes // Participant eligibility information (peserta) routes
// rujukanHandler := rujukan.NewVClaimHandler(rujukan.VClaimHandlerConfig{ pesertaHandler := pesertaHandlers.NewPesertaHandler(pesertaHandlers.PesertaHandlerConfig{
// BpjsConfig: cfg.Bpjs, BpjsConfig: cfg.Bpjs,
// Logger: *logger.Default(), Logger: *logger.Default(),
// Validator: nil, Validator: validator.New(),
// }) })
// rujukanGroup := v1.Group("/rujukan") pesertaGroup := v1.Group("/peserta")
// rujukanGroup.GET("/nokartu/:nokartu", rujukanHandler.GetRujukanBynokartu) pesertaGroup.GET("/Peserta/nokartu/:nokartu", pesertaHandler.GetBynokartu)
// rujukanGroup.GET("/norujukan/:norujukan", rujukanHandler.GetRujukanBynorujukan) pesertaGroup.GET("/Peserta/nik/:nik", pesertaHandler.GetBynik)
// // Peserta routes // Rujukan management endpoints (rujukan) routes
// pesertaHandler := peserta.NewVClaimHandler(peserta.VClaimHandlerConfig{ rujukanHandler := rujukanHandlers.NewRujukanHandler(rujukanHandlers.RujukanHandlerConfig{
// BpjsConfig: cfg.Bpjs, BpjsConfig: cfg.Bpjs,
// Logger: *logger.Default(), Logger: *logger.Default(),
// Validator: nil, Validator: validator.New(),
// }) })
// pesertaGroup := v1.Group("/peserta") rujukanGroup := v1.Group("/rujukan")
// pesertaGroup.GET("/nokartu/:nokartu/tglSEP/:tglsep", pesertaHandler.GetPesertaBynokartu) rujukanGroup.POST("/Rujukan/:norujukan", rujukanHandler.CreateRujukan)
// pesertaGroup.GET("/nik/:nik/tglSEP/:tglsep", pesertaHandler.GetPesertaBynik) rujukanGroup.PUT("/Rujukan/:norujukan", rujukanHandler.UpdateRujukan)
rujukanGroup.DELETE("/Rujukan/:norujukan", rujukanHandler.DeleteRujukan)
rujukanGroup.POST("/Rujukanbalik/:norujukan", rujukanHandler.CreateRujukanbalik)
rujukanGroup.PUT("/Rujukanbalik/:norujukan", rujukanHandler.UpdateRujukanbalik)
rujukanGroup.DELETE("/Rujukanbalik/:norujukan", rujukanHandler.DeleteRujukanbalik)
// // Sep routes // Search for rujukan endpoints (search) routes
// sepHandler := sep.NewVClaimHandler(sep.VClaimHandlerConfig{ searchHandler := rujukanHandlers.NewSearchHandler(rujukanHandlers.SearchHandlerConfig{
// BpjsConfig: cfg.Bpjs, BpjsConfig: cfg.Bpjs,
// Logger: *logger.Default(), Logger: *logger.Default(),
// Validator: nil, Validator: validator.New(),
// }) })
// sepGroup := v1.Group("/sep") searchGroup := v1.Group("/search")
// sepGroup.GET("/sep/:nosep", sepHandler.GetSepSep) searchGroup.GET("/bynorujukan/:norujukan", searchHandler.GetBynorujukan)
// sepGroup.POST("/sep", sepHandler.CreateSepSep) searchGroup.GET("/bynokartu/:nokartu", searchHandler.GetBynokartu)
// sepGroup.PUT("/sep/:nosep", sepHandler.UpdateSepSep)
// sepGroup.DELETE("/sep/:nosep", sepHandler.DeleteSepSep)
// // Retribusi endpoints // // Retribusi endpoints
// retribusiHandler := retribusiHandlers.NewRetribusiHandler() // retribusiHandler := retribusiHandlers.NewRetribusiHandler()

View File

@@ -19,12 +19,22 @@ services:
description: "Participant eligibility information" description: "Participant eligibility information"
handler_folder: "peserta" handler_folder: "peserta"
handler_file: "peserta.go" handler_file: "peserta.go"
handler_name: "Peserta"
functions: functions:
bynokartu: bynokartu:
methods: ["GET"] methods: ["GET"]
path: "/peserta/:nokartu" path: "/peserta/:nokartu"
get_routes: "/Peserta/nokartu/:nokartu"
# post_routes: "/Peserta/nokartu/:nokartu"
# put_routes: "/Peserta/nokartu/:nokartu"
# delete_routes: "/Peserta/nokartu/:nokartu"
get_path: "/peserta/:nokartu"
# post_path: "/peserta"
# put_path: "/peserta/:nokartu"
# delete_path: "/peserta/:nokartu"
model: "PesertaRequest" model: "PesertaRequest"
response_model: "PesertaResponse" response_model: "PesertaResponse"
request_model: "RujukanRequest"
description: "Get participant eligibility information by card number" description: "Get participant eligibility information by card number"
summary: "Get Participant Info by No Kartu" summary: "Get Participant Info by No Kartu"
tags: ["Peserta"] tags: ["Peserta"]
@@ -35,8 +45,17 @@ services:
bynik: bynik:
methods: ["GET"] methods: ["GET"]
path: "/peserta/nik/:nik" path: "/peserta/nik/:nik"
get_routes: "/Peserta/nik/:nik"
# post_routes: "/Peserta/nik/:nik"
# put_routes: "/Peserta/nik/:nik"
# delete_routes: "/Peserta/nik/:nik"
get_path: "/peserta/nik/:nik"
# post_path: "/peserta"
# put_path: "/peserta/nik/:nik"
# delete_path: "/peserta/nik/:nik"
model: "PesertaRequest" model: "PesertaRequest"
response_model: "PesertaResponse" response_model: "PesertaResponse"
request_model: "PesertaRequest"
description: "Get participant eligibility information by NIK" description: "Get participant eligibility information by NIK"
summary: "Get Participant Info by NIK" summary: "Get Participant Info by NIK"
tags: ["Peserta"] tags: ["Peserta"]
@@ -48,23 +67,42 @@ services:
description: "Rujukan management endpoints" description: "Rujukan management endpoints"
handler_folder: "rujukan" handler_folder: "rujukan"
handler_file: "rujukan.go" handler_file: "rujukan.go"
handler_name: "Rujukan"
functions: functions:
rujukan: rujukan:
methods: ["POST", "PUT", "DELETE"] methods: ["POST", "PUT", "DELETE"]
path: "/Rujukan" path: "/Rujukan"
# get_routes: "/Rujukan/:norujukan"
post_routes: "/Rujukan/:norujukan"
put_routes: "/Rujukan/:norujukan"
delete_routes: "/Rujukan/:norujukan"
# get_path: "/Rujukan/:norujukan"
post_path: "/Rujukan"
put_path: "/Rujukan/:norujukan"
delete_path: "/Rujukan/:norujukan"
model: "RujukanRequest" model: "RujukanRequest"
response_model: "RujukanResponse" response_model: "RujukanResponse"
request_model: "RujukanRequest"
description: "Manage rujukan" description: "Manage rujukan"
summary: "Rujukan Management" summary: "Rujukan Management"
tags: ["Rujukan"] tags: ["Rujukan"]
require_auth: true require_auth: true
cache_enabled: true cache_enabled: true
cache_ttl: 180 cache_ttl: 180
rujukan: rujukanbalik:
methods: ["GET"] methods: ["POST", "PUT", "DELETE"]
path: "/Rujukan" path: "/Rujukanbalik"
# get_routes: "/Rujukanbalik/:norujukan"
post_routes: "/Rujukanbalik/:norujukan"
put_routes: "/Rujukanbalik/:norujukan"
delete_routes: "/Rujukanbalik/:norujukan"
# get_path: "/Rujukanbalik/:norujukan"
post_path: "/Rujukanbalik"
put_path: "/Rujukanbalik/:norujukan"
delete_path: "/Rujukanbalik/:norujukan"
model: "RujukanRequest" model: "RujukanRequest"
response_model: "RujukanResponse" response_model: "RujukanResponse"
request_model: "RujukanRequest"
description: "Manage rujukan" description: "Manage rujukan"
summary: "Rujukan Management" summary: "Rujukan Management"
tags: ["Rujukan"] tags: ["Rujukan"]
@@ -76,12 +114,22 @@ services:
description: "Search for rujukan endpoints" description: "Search for rujukan endpoints"
handler_folder: "rujukan" handler_folder: "rujukan"
handler_file: "search.go" handler_file: "search.go"
handler_name: "Search"
functions: functions:
bynorujukan: bynorujukan:
methods: ["GET"] methods: ["GET"]
path: "/Rujukan/:norujukan" path: "/Rujukan/:norujukan"
get_routes: "/bynorujukan/:norujukan"
# post_routes: "/bynorujukan/:norujukan"
# put_routes: "/bynorujukan/:norujukan"
# delete_routes: "/bynorujukan/:norujukan"
get_path: "/Rujukan/:norujukan"
# post_path: "/Rujukan"
# put_path: "/Rujukan/:norujukan"
# delete_path: "/Rujukan/:norujukan"
model: "RujukanRequest" model: "RujukanRequest"
response_model: "RujukanResponse" response_model: "RujukanResponse"
request_model: "RujukanRequest"
description: "Get rujukan by nomor rujukan" description: "Get rujukan by nomor rujukan"
summary: "Rujukan Management" summary: "Rujukan Management"
tags: ["Rujukan"] tags: ["Rujukan"]
@@ -92,11 +140,21 @@ services:
bynokartu: bynokartu:
methods: ["GET"] methods: ["GET"]
path: "/Rujukan/:nokartu" path: "/Rujukan/:nokartu"
get_routes: "/bynokartu/:nokartu"
# post_routes: "/bynokartu/:nokartu"
# put_routes: "/bynokartu/:nokartu"
# delete_routes: "/bynokartu/:nokartu"
get_path: "/Rujukan/:nokartu"
# post_path: "/Rujukan"
# put_path: "/Rujukan/:nokartu"
# delete_path: "/Rujukan/:nokartu"
model: "RujukanRequest" model: "RujukanRequest"
response_model: "RujukanResponse" response_model: "RujukanResponse"
request_model: "RujukanRequest"
description: "Get rujukan by card number" description: "Get rujukan by card number"
summary: "Rujukan Management" summary: "Rujukan Management"
tags: ["Rujukan"] tags: ["Rujukan"]
require_auth: true require_auth: true
cache_enabled: true cache_enabled: true
cache_ttl: 300 cache_ttl: 300

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3230
tools/bpjs/newgenerete Normal file

File diff suppressed because it is too large Load Diff