Pembaruan

This commit is contained in:
2025-08-26 14:10:37 +07:00
parent f2dbbd165e
commit 7c16fd17f8
9 changed files with 1085 additions and 1931 deletions

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,6 @@
basePath: /api/v1
definitions:
gin.H:
additionalProperties: {}
type: object
models.AggregateData:
api-service_internal_models.AggregateData:
properties:
by_dinas:
additionalProperties:
@@ -30,7 +27,7 @@ definitions:
updated_today:
type: integer
type: object
models.ErrorResponse:
api-service_internal_models.ErrorResponse:
properties:
code:
type: integer
@@ -41,68 +38,7 @@ definitions:
timestamp:
type: string
type: object
models.Flag:
properties:
flag:
type: string
required:
- flag
type: object
models.Jaminan:
properties:
lakaLantas:
type: string
noLP:
type: string
penjamin:
$ref: '#/definitions/models.Penjamin'
required:
- lakaLantas
type: object
models.KlsRawatPost:
properties:
klsRawatHak:
type: string
klsRawatNaik:
type: string
pembiayaan:
type: string
penanggungJawab:
type: string
required:
- klsRawatHak
type: object
models.KlsRawatPut:
properties:
klsRawatHak:
type: string
klsRawatNaik:
type: string
pembiayaan:
type: string
penanggungJawab:
type: string
type: object
models.LoginRequest:
properties:
password:
type: string
username:
type: string
required:
- password
- username
type: object
models.LokasiLaka:
properties:
kdKabupaten:
type: string
kdKecamatan:
type: string
kdPropinsi:
type: string
type: object
models.MetaResponse:
api-service_internal_models.MetaResponse:
properties:
current_page:
type: integer
@@ -119,33 +55,44 @@ definitions:
total_pages:
type: integer
type: object
models.NullableInt32:
api-service_internal_models.NullableInt32:
properties:
int32:
type: integer
valid:
type: boolean
type: object
models.Penjamin:
api-service_internal_models_auth.LoginRequest:
properties:
keterangan:
password:
type: string
suplesi:
$ref: '#/definitions/models.Suplesi'
tglKejadian:
type: string
type: object
models.Poli:
properties:
eksekutif:
type: string
tujuan:
username:
type: string
required:
- eksekutif
- tujuan
- password
- username
type: object
models.Retribusi:
api-service_internal_models_auth.TokenResponse:
properties:
access_token:
type: string
expires_in:
type: integer
token_type:
type: string
type: object
api-service_internal_models_auth.User:
properties:
email:
type: string
id:
type: string
role:
type: string
username:
type: string
type: object
api-service_internal_models_retribusi.Retribusi:
properties:
date_created:
$ref: '#/definitions/sql.NullTime'
@@ -172,7 +119,7 @@ definitions:
satuan_overtime:
$ref: '#/definitions/sql.NullString'
sort:
$ref: '#/definitions/models.NullableInt32'
$ref: '#/definitions/api-service_internal_models.NullableInt32'
status:
type: string
tarif:
@@ -190,7 +137,7 @@ definitions:
user_updated:
$ref: '#/definitions/sql.NullString'
type: object
models.RetribusiCreateRequest:
api-service_internal_models_retribusi.RetribusiCreateRequest:
properties:
dinas:
maxLength: 255
@@ -247,41 +194,41 @@ definitions:
required:
- status
type: object
models.RetribusiCreateResponse:
api-service_internal_models_retribusi.RetribusiCreateResponse:
properties:
data:
$ref: '#/definitions/models.Retribusi'
$ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
message:
type: string
type: object
models.RetribusiDeleteResponse:
api-service_internal_models_retribusi.RetribusiDeleteResponse:
properties:
id:
type: string
message:
type: string
type: object
models.RetribusiGetByIDResponse:
api-service_internal_models_retribusi.RetribusiGetByIDResponse:
properties:
data:
$ref: '#/definitions/models.Retribusi'
$ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
message:
type: string
type: object
models.RetribusiGetResponse:
api-service_internal_models_retribusi.RetribusiGetResponse:
properties:
data:
items:
$ref: '#/definitions/models.Retribusi'
$ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
type: array
message:
type: string
meta:
$ref: '#/definitions/models.MetaResponse'
$ref: '#/definitions/api-service_internal_models.MetaResponse'
summary:
$ref: '#/definitions/models.AggregateData'
$ref: '#/definitions/api-service_internal_models.AggregateData'
type: object
models.RetribusiUpdateRequest:
api-service_internal_models_retribusi.RetribusiUpdateRequest:
properties:
dinas:
maxLength: 255
@@ -338,44 +285,18 @@ definitions:
required:
- status
type: object
models.RetribusiUpdateResponse:
api-service_internal_models_retribusi.RetribusiUpdateResponse:
properties:
data:
$ref: '#/definitions/models.Retribusi'
$ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
message:
type: string
type: object
models.Rujukan:
properties:
asalRujukan:
type: string
noRujukan:
type: string
ppkRujukan:
type: string
tglRujukan:
type: string
required:
- asalRujukan
- noRujukan
- ppkRujukan
- tglRujukan
api-service_internal_models_vclaim.SepPostRequest:
type: object
models.SepPostRequest:
properties:
tsep:
$ref: '#/definitions/models.TSepPost'
required:
- tsep
api-service_internal_models_vclaim.SepPutRequest:
type: object
models.SepPutRequest:
properties:
tsep:
$ref: '#/definitions/models.TSepPut'
required:
- tsep
type: object
models.SepResponse:
api-service_internal_models_vclaim.SepResponse:
properties:
data:
additionalProperties: true
@@ -383,134 +304,113 @@ definitions:
message:
type: string
type: object
models.Skdp:
properties:
kodeDPJP:
type: string
noSurat:
type: string
required:
- kodeDPJP
- noSurat
gin.H:
additionalProperties: {}
type: object
models.Suplesi:
internal_models_surkon.ErrorResponse:
properties:
lokasiLaka:
$ref: '#/definitions/models.LokasiLaka'
noSepSuplesi:
code:
type: string
suplesi:
details:
type: string
message:
type: string
type: object
models.TSepPost:
models.ResponseMetadata:
properties:
assesmentPel:
request_id:
type: string
timestamp:
type: string
version:
type: string
type: object
models.SpriPost:
properties:
catatan:
maxLength: 200
type: string
cob:
$ref: '#/definitions/models.Flag'
diagAwal:
type: string
dpjpLayan:
type: string
flagProcedure:
type: string
jaminan:
$ref: '#/definitions/models.Jaminan'
jnsPelayanan:
enum:
- "1"
- "2"
type: string
katarak:
$ref: '#/definitions/models.Flag'
kdPenunjang:
type: string
klsRawat:
$ref: '#/definitions/models.KlsRawatPost'
noKartu:
description: Core BPJS fields - customize based on your specific requirements
maxLength: 13
minLength: 13
type: string
noMR:
type: string
noTelp:
type: string
poli:
$ref: '#/definitions/models.Poli'
ppkPelayanan:
type: string
rujukan:
$ref: '#/definitions/models.Rujukan'
skdp:
$ref: '#/definitions/models.Skdp'
tglSep:
description: yyyy-MM-dd
type: string
tujuanKunj:
tglLayanan:
type: string
user:
type: string
required:
- cob
- diagAwal
- jaminan
- jnsPelayanan
- katarak
- klsRawat
- noKartu
- noMR
- poli
- ppkPelayanan
- rujukan
- skdp
- tglSep
- tglLayanan
- user
type: object
models.TSepPut:
models.SpriPostRequest:
properties:
request_id:
type: string
timestamp:
type: string
tsep:
$ref: '#/definitions/models.SpriPost'
required:
- tsep
type: object
models.SpriPut:
properties:
catatan:
type: string
cob:
$ref: '#/definitions/models.Flag'
diagAwal:
type: string
dpjpLayan:
type: string
jaminan:
$ref: '#/definitions/models.Jaminan'
katarak:
$ref: '#/definitions/models.Flag'
klsRawat:
$ref: '#/definitions/models.KlsRawatPut'
noMR:
type: string
noSep:
type: string
noTelp:
type: string
poli:
$ref: '#/definitions/models.Poli'
user:
type: string
required:
- noSep
- user
type: object
models.TokenResponse:
properties:
access_token:
type: string
expires_in:
type: integer
token_type:
type: string
type: object
models.User:
properties:
email:
maxLength: 200
type: string
id:
type: string
role:
jnsPelayanan:
enum:
- "1"
- "2"
type: string
username:
noKartu:
maxLength: 13
minLength: 13
type: string
ppkPelayanan:
type: string
tglLayanan:
type: string
user:
type: string
required:
- id
- user
type: object
models.SpriPutRequest:
properties:
request_id:
type: string
timestamp:
type: string
tsep:
$ref: '#/definitions/models.SpriPut'
required:
- tsep
type: object
models.SpriResponse:
properties:
data: {}
error:
$ref: '#/definitions/internal_models_surkon.ErrorResponse'
message:
type: string
metadata:
$ref: '#/definitions/models.ResponseMetadata'
status:
type: string
type: object
sql.NullString:
@@ -554,14 +454,14 @@ paths:
name: login
required: true
schema:
$ref: '#/definitions/models.LoginRequest'
$ref: '#/definitions/api-service_internal_models_auth.LoginRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/models.TokenResponse'
$ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400":
description: Bad request
schema:
@@ -586,7 +486,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/models.User'
$ref: '#/definitions/api-service_internal_models_auth.User'
"401":
description: Unauthorized
schema:
@@ -618,7 +518,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/models.TokenResponse'
$ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400":
description: Bad request
schema:
@@ -725,19 +625,19 @@ paths:
"200":
description: Retribusi deleted successfully
schema:
$ref: '#/definitions/models.RetribusiDeleteResponse'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiDeleteResponse'
"400":
description: Invalid ID format
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"404":
description: Retribusi not found
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Delete retribusi
tags:
- retribusi
@@ -757,19 +657,19 @@ paths:
"200":
description: Success response
schema:
$ref: '#/definitions/models.RetribusiGetByIDResponse'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiGetByIDResponse'
"400":
description: Invalid ID format
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"404":
description: Retribusi not found
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get Retribusi by ID
tags:
- retribusi
@@ -788,26 +688,26 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/models.RetribusiUpdateRequest'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiUpdateRequest'
produces:
- application/json
responses:
"200":
description: Retribusi updated successfully
schema:
$ref: '#/definitions/models.RetribusiUpdateResponse'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiUpdateResponse'
"400":
description: Bad request or validation error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"404":
description: Retribusi not found
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Update retribusi
tags:
- retribusi
@@ -854,15 +754,15 @@ paths:
"200":
description: Success response
schema:
$ref: '#/definitions/models.RetribusiGetResponse'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiGetResponse'
"400":
description: Bad request
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get retribusi with pagination and optional aggregation
tags:
- retribusi
@@ -876,22 +776,22 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/models.RetribusiCreateRequest'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiCreateRequest'
produces:
- application/json
responses:
"201":
description: Retribusi created successfully
schema:
$ref: '#/definitions/models.RetribusiCreateResponse'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiCreateResponse'
"400":
description: Bad request or validation error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Create retribusi
tags:
- retribusi
@@ -929,15 +829,15 @@ paths:
"200":
description: Success response
schema:
$ref: '#/definitions/models.RetribusiGetResponse'
$ref: '#/definitions/api-service_internal_models_retribusi.RetribusiGetResponse'
"400":
description: Bad request
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get retribusi with dynamic filtering
tags:
- retribusi
@@ -957,14 +857,152 @@ paths:
"200":
description: Statistics data
schema:
$ref: '#/definitions/models.AggregateData'
$ref: '#/definitions/api-service_internal_models.AggregateData'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.ErrorResponse'
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get retribusi statistics
tags:
- retribusi
/api/v1/surkon/spri:
post:
consumes:
- application/json
description: Create a new Spri in BPJS system with enhanced validation and logging
parameters:
- description: Spri creation request
in: body
name: request
required: true
schema:
$ref: '#/definitions/models.SpriPostRequest'
produces:
- application/json
responses:
"200":
description: Spri created successfully
schema:
$ref: '#/definitions/models.SpriResponse'
"400":
description: Bad request - validation error
schema:
$ref: '#/definitions/models.SpriResponse'
"422":
description: Unprocessable entity - business logic error
schema:
$ref: '#/definitions/models.SpriResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.SpriResponse'
summary: Create a new SPRI
tags:
- Surkon-Spri
put:
consumes:
- application/json
description: Update an existing Spri in BPJS system with enhanced validation
and logging
parameters:
- description: Spri update request
in: body
name: request
required: true
schema:
$ref: '#/definitions/models.SpriPutRequest'
produces:
- application/json
responses:
"200":
description: Spri updated successfully
schema:
$ref: '#/definitions/models.SpriResponse'
"400":
description: Bad request - validation error
schema:
$ref: '#/definitions/models.SpriResponse'
"422":
description: Unprocessable entity - business logic error
schema:
$ref: '#/definitions/models.SpriResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.SpriResponse'
summary: Update an existing SPRI
tags:
- Surkon-Spri
/api/v1/surkon/spri/{id}:
delete:
consumes:
- application/json
description: Delete a Spri by ID with enhanced validation and logging
parameters:
- description: Spri ID
in: path
name: id
required: true
type: string
- description: User identifier
in: query
name: user
required: true
type: string
produces:
- application/json
responses:
"200":
description: Spri deleted successfully
schema:
$ref: '#/definitions/models.SpriResponse'
"400":
description: Bad request - missing parameters
schema:
$ref: '#/definitions/models.SpriResponse'
"422":
description: Unprocessable entity - business logic error
schema:
$ref: '#/definitions/models.SpriResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.SpriResponse'
summary: Delete an existing SPRI
tags:
- Surkon-Spri
get:
consumes:
- application/json
description: Retrieve a Spri by ID with enhanced validation and logging
parameters:
- description: Spri ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: Data Spri retrieved successfully
schema:
$ref: '#/definitions/models.SpriResponse'
"400":
description: Bad request - invalid ID
schema:
$ref: '#/definitions/models.SpriResponse'
"404":
description: Spri not found
schema:
$ref: '#/definitions/models.SpriResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.SpriResponse'
summary: Get an existing SPRI
tags:
- Surkon-Spri
/api/v1/token/generate:
post:
consumes:
@@ -976,14 +1014,14 @@ paths:
name: token
required: true
schema:
$ref: '#/definitions/models.LoginRequest'
$ref: '#/definitions/api-service_internal_models_auth.LoginRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/models.TokenResponse'
$ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400":
description: Bad request
schema:
@@ -1020,7 +1058,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/models.TokenResponse'
$ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400":
description: Bad request
schema:
@@ -1041,14 +1079,14 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/models.SepPostRequest'
$ref: '#/definitions/api-service_internal_models_vclaim.SepPostRequest'
produces:
- application/json
responses:
"200":
description: SEP created successfully
schema:
$ref: '#/definitions/models.SepResponse'
$ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400":
description: Invalid request
schema:
@@ -1070,14 +1108,14 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/models.SepPutRequest'
$ref: '#/definitions/api-service_internal_models_vclaim.SepPutRequest'
produces:
- application/json
responses:
"200":
description: SEP updated successfully
schema:
$ref: '#/definitions/models.SepResponse'
$ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400":
description: Invalid request
schema:
@@ -1111,7 +1149,7 @@ paths:
"200":
description: SEP deleted successfully
schema:
$ref: '#/definitions/models.SepResponse'
$ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400":
description: Invalid request
schema:
@@ -1139,7 +1177,7 @@ paths:
"200":
description: Data SEP retrieved successfully
schema:
$ref: '#/definitions/models.SepResponse'
$ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400":
description: Invalid request
schema:

View File

@@ -1,533 +0,0 @@
package handlers
import (
"context"
"fmt"
"net/http"
"time"
"api-service/internal/config"
models "api-service/internal/models/antrol"
services "api-service/internal/services/bpjs"
"api-service/pkg/logger"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
// PesertaHandler handles peserta BPJS services with optimized error handling and logging
type PesertaHandler struct {
service services.VClaimService
validator *validator.Validate
logger logger.Logger
config *config.BpjsConfig
}
// HandlerConfig contains configuration for PesertaHandler
type PesertaHandlerConfig struct {
BpjsConfig *config.BpjsConfig
Logger logger.Logger
Validator *validator.Validate
}
// NewPesertaHandler creates a new optimized PesertaHandler
func NewPesertaHandler(cfg *PesertaHandlerConfig) *PesertaHandler {
return &PesertaHandler{
service: services.NewService(*cfg.BpjsConfig),
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.BpjsConfig,
}
}
// CreatePeserta creates a new Peserta with comprehensive error handling and validation
// @Summary Create a new PESERTA
// @Description Create a new Peserta in BPJS system with enhanced validation and logging
// @Tags Antrol-Peserta
// @Accept json
// @Produce json
// @Param request body models.PesertaPostRequest true "Peserta creation request"
// @Success 200 {object} models.PesertaResponse "Peserta created successfully"
// @Failure 400 {object} models.PesertaResponse "Bad request - validation error"
// @Failure 422 {object} models.PesertaResponse "Unprocessable entity - business logic error"
// @Failure 500 {object} models.PesertaResponse "Internal server error"
// @Router /api/v1/antrol/peserta [post]
func (h *PesertaHandler) CreatePeserta(c *gin.Context) {
requestID := uuid.New().String()
startTime := time.Now()
h.logger.Info("Creating Peserta", map[string]interface{}{
"request_id": requestID,
"timestamp": startTime,
})
var req models.PesertaPostRequest
req.RequestID = requestID
req.Timestamp = startTime
// Bind and validate JSON
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind JSON", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
h.sendErrorResponse(c, http.StatusBadRequest, "INVALID_REQUEST_FORMAT",
"Format request tidak valid", err.Error(), requestID)
return
}
// Custom validation
if err := req.Validate(); err != nil {
h.logger.Error("Custom validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
"Validasi gagal", err.Error(), requestID)
return
}
// Struct validation
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Struct validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
"Validasi struktur gagal", h.formatValidationError(err), requestID)
return
}
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
var rawResponse models.BpjsRawResponse
if err := h.service.Post(ctx, "PESERTA/2.0/insert", req, &rawResponse); err != nil {
h.logger.Error("Failed to call BPJS service", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
"endpoint": "PESERTA/2.0/insert",
})
statusCode, errorCode := h.categorizeError(err)
h.sendErrorResponse(c, statusCode, errorCode,
"Gagal membuat Peserta", err.Error(), requestID)
return
}
// Check BPJS response
if rawResponse.MetaData.Code != "200" {
h.logger.Warn("BPJS returned error", map[string]interface{}{
"bpjs_code": rawResponse.MetaData.Code,
"bpjs_message": rawResponse.MetaData.Message,
"request_id": requestID,
})
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
rawResponse.MetaData.Message, "", requestID)
return
}
duration := time.Since(startTime)
h.logger.Info("Peserta created successfully", map[string]interface{}{
"request_id": requestID,
"duration": duration.String(),
})
h.sendSuccessResponse(c, "Peserta berhasil dibuat", rawResponse.Response, requestID)
}
// UpdatePeserta updates an existing Peserta with comprehensive validation
// @Summary Update an existing PESERTA
// @Description Update an existing Peserta in BPJS system with enhanced validation and logging
// @Tags Antrol-Peserta
// @Accept json
// @Produce json
// @Param request body models.PesertaPutRequest true "Peserta update request"
// @Success 200 {object} models.PesertaResponse "Peserta updated successfully"
// @Failure 400 {object} models.PesertaResponse "Bad request - validation error"
// @Failure 422 {object} models.PesertaResponse "Unprocessable entity - business logic error"
// @Failure 500 {object} models.PesertaResponse "Internal server error"
// @Router /api/v1/antrol/peserta [put]
func (h *PesertaHandler) UpdatePeserta(c *gin.Context) {
requestID := uuid.New().String()
startTime := time.Now()
h.logger.Info("Updating Peserta", map[string]interface{}{
"request_id": requestID,
"timestamp": startTime,
})
var req models.PesertaPutRequest
req.RequestID = requestID
req.Timestamp = startTime
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind JSON for update", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
h.sendErrorResponse(c, http.StatusBadRequest, "INVALID_REQUEST_FORMAT",
"Format request tidak valid", err.Error(), requestID)
return
}
if err := req.Validate(); err != nil {
h.logger.Error("Update validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
"Validasi gagal", err.Error(), requestID)
return
}
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Struct validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
"Validasi struktur gagal", h.formatValidationError(err), requestID)
return
}
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
var rawResponse models.BpjsRawResponse
if err := h.service.Put(ctx, "PESERTA/2.0/update", req, &rawResponse); err != nil {
h.logger.Error("Failed to update Peserta", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
statusCode, errorCode := h.categorizeError(err)
h.sendErrorResponse(c, statusCode, errorCode,
"Gagal memperbarui Peserta", err.Error(), requestID)
return
}
if rawResponse.MetaData.Code != "200" {
h.logger.Warn("BPJS update returned error", map[string]interface{}{
"bpjs_code": rawResponse.MetaData.Code,
"bpjs_message": rawResponse.MetaData.Message,
"request_id": requestID,
})
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
rawResponse.MetaData.Message, "", requestID)
return
}
duration := time.Since(startTime)
h.logger.Info("Peserta updated successfully", map[string]interface{}{
"request_id": requestID,
"duration": duration.String(),
})
h.sendSuccessResponse(c, "Peserta berhasil diperbarui", rawResponse.Response, requestID)
}
// DeletePeserta deletes an existing Peserta with comprehensive validation
// @Summary Delete an existing PESERTA
// @Description Delete a Peserta by ID with enhanced validation and logging
// @Tags Antrol-Peserta
// @Accept json
// @Produce json
// @Param id path string true "Peserta ID"
// @Param user query string true "User identifier"
// @Success 200 {object} models.PesertaResponse "Peserta deleted successfully"
// @Failure 400 {object} models.PesertaResponse "Bad request - missing parameters"
// @Failure 422 {object} models.PesertaResponse "Unprocessable entity - business logic error"
// @Failure 500 {object} models.PesertaResponse "Internal server error"
// @Router /api/v1/antrol/peserta/{id} [delete]
func (h *PesertaHandler) DeletePeserta(c *gin.Context) {
requestID := uuid.New().String()
startTime := time.Now()
id := c.Param("id")
user := c.Query("user")
h.logger.Info("Deleting Peserta", map[string]interface{}{
"request_id": requestID,
"timestamp": startTime,
"id": id,
"user": user,
})
// Validate parameters
if id == "" {
h.sendErrorResponse(c, http.StatusBadRequest, "MISSING_PARAMETER",
"Parameter ID wajib diisi", "", requestID)
return
}
if user == "" {
h.sendErrorResponse(c, http.StatusBadRequest, "MISSING_PARAMETER",
"Parameter user wajib diisi", "", requestID)
return
}
req := models.PesertaDeleteRequest{
BaseRequest: models.BaseRequest{
RequestID: requestID,
Timestamp: startTime,
},
TPeserta: models.PesertaDeleteData{
ID: id,
User: user,
},
}
if err := req.Validate(); err != nil {
h.logger.Error("Delete validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
h.sendErrorResponse(c, http.StatusBadRequest, "VALIDATION_ERROR",
"Validasi gagal", err.Error(), requestID)
return
}
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
var rawResponse models.BpjsRawResponse
if err := h.service.Delete(ctx, "PESERTA/2.0/delete", req); err != nil {
h.logger.Error("Failed to delete Peserta", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
statusCode, errorCode := h.categorizeError(err)
h.sendErrorResponse(c, statusCode, errorCode,
"Gagal menghapus Peserta", err.Error(), requestID)
return
}
if rawResponse.MetaData.Code != "200" {
h.logger.Warn("BPJS delete returned error", map[string]interface{}{
"bpjs_code": rawResponse.MetaData.Code,
"bpjs_message": rawResponse.MetaData.Message,
"request_id": requestID,
"id": id,
})
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
rawResponse.MetaData.Message, "", requestID)
return
}
duration := time.Since(startTime)
h.logger.Info("Peserta deleted successfully", map[string]interface{}{
"request_id": requestID,
"duration": duration.String(),
"id": id,
})
h.sendSuccessResponse(c, "Peserta berhasil dihapus", rawResponse.Response, requestID)
}
// GetPeserta retrieves Peserta details with comprehensive error handling
// @Summary Get an existing PESERTA
// @Description Retrieve a Peserta by ID with enhanced validation and logging
// @Tags Antrol-Peserta
// @Accept json
// @Produce json
// @Param id path string true "Peserta ID"
// @Success 200 {object} models.PesertaResponse "Data Peserta retrieved successfully"
// @Failure 400 {object} models.PesertaResponse "Bad request - invalid ID"
// @Failure 404 {object} models.PesertaResponse "Peserta not found"
// @Failure 500 {object} models.PesertaResponse "Internal server error"
// @Router /api/v1/antrol/peserta/{id} [get]
func (h *PesertaHandler) GetPeserta(c *gin.Context) {
requestID := uuid.New().String()
startTime := time.Now()
id := c.Param("id")
h.logger.Info("Getting Peserta", map[string]interface{}{
"request_id": requestID,
"timestamp": startTime,
"id": id,
})
if id == "" {
h.sendErrorResponse(c, http.StatusBadRequest, "MISSING_PARAMETER",
"Parameter ID wajib diisi", "", requestID)
return
}
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
endpoint := fmt.Sprintf("PESERTA/%s", id)
var rawResponse models.BpjsRawResponse
if err := h.service.Get(ctx, endpoint, &rawResponse); err != nil {
h.logger.Error("Failed to get Peserta", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
"id": id,
})
statusCode, errorCode := h.categorizeError(err)
h.sendErrorResponse(c, statusCode, errorCode,
"Gagal mengambil data Peserta", err.Error(), requestID)
return
}
if rawResponse.MetaData.Code != "200" {
// Handle specific BPJS error codes
if rawResponse.MetaData.Code == "201" {
h.logger.Info("Peserta not found", map[string]interface{}{
"request_id": requestID,
"id": id,
})
h.sendErrorResponse(c, http.StatusNotFound, "DATA_NOT_FOUND",
"Data Peserta tidak ditemukan", rawResponse.MetaData.Message, requestID)
return
}
h.logger.Warn("BPJS get returned error", map[string]interface{}{
"bpjs_code": rawResponse.MetaData.Code,
"bpjs_message": rawResponse.MetaData.Message,
"request_id": requestID,
"id": id,
})
statusCode := h.mapBpjsCodeToHttpStatus(rawResponse.MetaData.Code)
h.sendErrorResponse(c, statusCode, rawResponse.MetaData.Code,
rawResponse.MetaData.Message, "", requestID)
return
}
duration := time.Since(startTime)
h.logger.Info("Peserta retrieved successfully", map[string]interface{}{
"request_id": requestID,
"duration": duration.String(),
"id": id,
})
h.sendSuccessResponse(c, "Data Peserta berhasil diambil", rawResponse.Response, requestID)
}
// Helper methods for PesertaHandler
func (h *PesertaHandler) sendSuccessResponse(c *gin.Context, message string, data interface{}, requestID string) {
response := models.PesertaResponse{
BaseResponse: models.BaseResponse{
Status: "success",
Message: message,
Data: data,
Metadata: &models.ResponseMetadata{
Timestamp: time.Now(),
Version: "2.0",
RequestID: requestID,
},
},
}
c.JSON(http.StatusOK, response)
}
func (h *PesertaHandler) sendErrorResponse(c *gin.Context, statusCode int, errorCode, message, details, requestID string) {
response := models.PesertaResponse{
BaseResponse: models.BaseResponse{
Status: "error",
Message: message,
Error: &models.ErrorResponse{
Code: errorCode,
Message: message,
Details: details,
},
Metadata: &models.ResponseMetadata{
Timestamp: time.Now(),
Version: "2.0",
RequestID: requestID,
},
},
}
c.JSON(statusCode, response)
}
func (h *PesertaHandler) formatValidationError(err error) string {
if validationErrors, ok := err.(validator.ValidationErrors); ok {
var messages []string
for _, e := range validationErrors {
switch e.Tag() {
case "required":
messages = append(messages, fmt.Sprintf("%s wajib diisi", e.Field()))
case "min":
messages = append(messages, fmt.Sprintf("%s minimal %s karakter", e.Field(), e.Param()))
case "max":
messages = append(messages, fmt.Sprintf("%s maksimal %s karakter", e.Field(), e.Param()))
case "oneof":
messages = append(messages, fmt.Sprintf("%s harus salah satu dari: %s", e.Field(), e.Param()))
default:
messages = append(messages, fmt.Sprintf("%s tidak valid", e.Field()))
}
}
return fmt.Sprintf("Validasi gagal: %v", messages)
}
return err.Error()
}
func (h *PesertaHandler) categorizeError(err error) (int, string) {
if err == nil {
return http.StatusOK, "SUCCESS"
}
errStr := err.Error()
if h.isTimeoutError(err) {
return http.StatusRequestTimeout, "REQUEST_TIMEOUT"
}
if h.isNetworkError(err) {
return http.StatusBadGateway, "NETWORK_ERROR"
}
if h.isAuthError(errStr) {
return http.StatusUnauthorized, "AUTH_ERROR"
}
return http.StatusInternalServerError, "INTERNAL_ERROR"
}
func (h *PesertaHandler) mapBpjsCodeToHttpStatus(bpjsCode string) int {
switch bpjsCode {
case "200":
return http.StatusOK
case "201":
return http.StatusNotFound
case "202":
return http.StatusBadRequest
case "400":
return http.StatusBadRequest
case "401":
return http.StatusUnauthorized
case "403":
return http.StatusForbidden
case "404":
return http.StatusNotFound
case "500":
return http.StatusInternalServerError
default:
return http.StatusUnprocessableEntity
}
}
func (h *PesertaHandler) isTimeoutError(err error) bool {
return err != nil && (err.Error() == "context deadline exceeded" ||
err.Error() == "timeout")
}
func (h *PesertaHandler) isNetworkError(err error) bool {
return err != nil && (err.Error() == "connection refused" ||
err.Error() == "no such host")
}
func (h *PesertaHandler) isAuthError(errStr string) bool {
return errStr == "unauthorized" || errStr == "invalid credentials"
}

View File

@@ -1,164 +0,0 @@
package handlers
import (
"context"
"fmt"
"net/http"
"time"
"api-service/internal/config"
models "api-service/internal/models/vclaim"
services "api-service/internal/services/bpjs"
"github.com/gin-gonic/gin"
)
// PesertaHandler handles peserta BPJS services
type PesertaHandler struct {
service services.VClaimService
}
// NewPesertaHandler creates a new PesertaHandler
func NewPesertaHandler(cfg config.BpjsConfig) *PesertaHandler {
return &PesertaHandler{
service: services.NewService(cfg),
}
}
// CreatePeserta godoc
// @Summary Create a new PESERTA
// @Description Create a new Peserta in BPJS system
// @Tags vclaim-peserta
// @Accept json
// @Produce json
// @Param request body models.PesertaPostRequest true "Peserta creation request"
// @Success 200 {object} models.PesertaResponse "Peserta created successfully"
// @Failure 400 {object} gin.H "Invalid request"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /api/v1/vclaim/peserta [post]
func (h *PesertaHandler) CreatePeserta(c *gin.Context) {
var req models.PesertaPostRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body", "message": err.Error()})
return
}
ctx, cancel := context.WithTimeout(c, 30*time.Second)
defer cancel()
var result map[string]interface{}
if err := h.service.Post(ctx, "PESERTA/2.0/insert", req, &result); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "create failed", "message": err.Error()})
return
}
c.JSON(http.StatusOK, models.PesertaResponse{
Message: "Peserta berhasil dibuat",
Data: result,
})
}
// UpdatePeserta godoc
// @Summary Update an existing PESERTA
// @Description Update an existing Peserta in BPJS system
// @Tags vclaim-peserta
// @Accept json
// @Produce json
// @Param request body models.PesertaPutRequest true "Peserta update request"
// @Success 200 {object} models.PesertaResponse "Peserta updated successfully"
// @Failure 400 {object} gin.H "Invalid request"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /api/v1/vclaim/peserta [put]
func (h *PesertaHandler) UpdatePeserta(c *gin.Context) {
var req models.PesertaPutRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body", "message": err.Error()})
return
}
ctx, cancel := context.WithTimeout(c, 30*time.Second)
defer cancel()
var result map[string]interface{}
if err := h.service.Put(ctx, "PESERTA/2.0/update", req, &result); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "update failed", "message": err.Error()})
return
}
c.JSON(http.StatusOK, models.PesertaResponse{
Message: "Peserta berhasil diperbarui",
Data: result,
})
}
// DeletePeserta godoc
// @Summary Delete an existing PESERTA
// @Description Delete a Peserta by ID
// @Tags vclaim-peserta
// @Accept json
// @Produce json
// @Param id path string true "Peserta ID"
// @Param user query string true "User"
// @Success 200 {object} models.PesertaResponse "Peserta deleted successfully"
// @Failure 400 {object} gin.H "Invalid request"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /api/v1/vclaim/peserta/{id} [delete]
func (h *PesertaHandler) DeletePeserta(c *gin.Context) {
id := c.Param("id")
user := c.Query("user")
if id == "" || user == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "id & user required"})
return
}
body := models.PesertaDeleteRequest{}
body.TPeserta.ID = id
body.TPeserta.User = user
ctx, cancel := context.WithTimeout(c, 30*time.Second)
defer cancel()
if err := h.service.Delete(ctx, "PESERTA/2.0/delete", body); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "delete failed", "message": err.Error()})
return
}
c.JSON(http.StatusOK, models.PesertaResponse{
Message: "Peserta berhasil dihapus",
Data: nil,
})
}
// GetPeserta godoc
// @Summary Get an existing PESERTA
// @Description Retrieve a Peserta by ID
// @Tags vclaim-peserta
// @Accept json
// @Produce json
// @Param id path string true "Peserta ID"
// @Success 200 {object} models.PesertaResponse "Data Peserta retrieved successfully"
// @Failure 400 {object} gin.H "Invalid request"
// @Failure 500 {object} gin.H "Internal server error"
// @Router /api/v1/vclaim/peserta/{id} [get]
func (h *PesertaHandler) GetPeserta(c *gin.Context) {
id := c.Param("id")
if id == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "id required"})
return
}
ctx, cancel := context.WithTimeout(c, 30*time.Second)
defer cancel()
endpoint := fmt.Sprintf("PESERTA/%s", id)
var result map[string]interface{}
if err := h.service.Get(ctx, endpoint, &result); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "fetch failed", "message": err.Error()})
return
}
c.JSON(http.StatusOK, models.PesertaResponse{
Message: "Data Peserta berhasil diambil",
Data: result,
})
}

View File

@@ -1,197 +0,0 @@
package models
import (
"encoding/json"
"fmt"
"time"
)
// Peserta BPJS Models with Enhanced Validation
// Generated at: 2025-08-24 20:09:32
// Category: antrol
// Base request/response structures
type BaseRequest struct {
RequestID string `json:"request_id,omitempty"`
Timestamp time.Time `json:"timestamp,omitempty"`
}
type BaseResponse struct {
Status string `json:"status"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
Error *ErrorResponse `json:"error,omitempty"`
Metadata *ResponseMetadata `json:"metadata,omitempty"`
}
type ErrorResponse struct {
Code string `json:"code"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
}
type ResponseMetadata struct {
Timestamp time.Time `json:"timestamp"`
Version string `json:"version"`
RequestID string `json:"request_id,omitempty"`
}
// Peserta Response Structure
type PesertaResponse struct {
BaseResponse
}
// BPJS Raw Response Structure
type BpjsRawResponse struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
Response interface{} `json:"response"`
}
// Peserta POST Request Structure with Enhanced Validation
type PesertaPostRequest struct {
BaseRequest
TPeserta PesertaPost `json:"t_sep" binding:"required" validate:"required"`
}
type PesertaPost struct {
// Core BPJS fields - customize based on your specific requirements
NoKartu string `json:"noKartu" binding:"required" validate:"required,min=13,max=13"`
TglLayanan string `json:"tglLayanan" binding:"required" validate:"required"`
JnsPelayanan string `json:"jnsPelayanan" binding:"required" validate:"required,oneof=1 2"`
PpkPelayanan string `json:"ppkPelayanan" binding:"required" validate:"required"`
Catatan string `json:"catatan" validate:"omitempty,max=200"`
User string `json:"user" binding:"required" validate:"required"`
}
// Validate validates the PesertaPostRequest
func (r *PesertaPostRequest) Validate() error {
if r.TPeserta.NoKartu == "" {
return fmt.Errorf("nomor kartu tidak boleh kosong")
}
if len(r.TPeserta.NoKartu) != 13 {
return fmt.Errorf("nomor kartu harus 13 digit")
}
if _, err := time.Parse("2006-01-02", r.TPeserta.TglLayanan); err != nil {
return fmt.Errorf("format tanggal layanan tidak valid, gunakan yyyy-MM-dd")
}
return nil
}
// ToJSON converts struct to JSON string
func (r *PesertaPostRequest) ToJSON() (string, error) {
data, err := json.Marshal(r)
return string(data), err
}
// Peserta PUT Request Structure with Enhanced Validation
type PesertaPutRequest struct {
BaseRequest
TPeserta PesertaPut `json:"t_sep" binding:"required" validate:"required"`
}
type PesertaPut struct {
ID string `json:"id" binding:"required" validate:"required"`
NoKartu string `json:"noKartu" validate:"omitempty,min=13,max=13"`
TglLayanan string `json:"tglLayanan" validate:"omitempty"`
JnsPelayanan string `json:"jnsPelayanan" validate:"omitempty,oneof=1 2"`
PpkPelayanan string `json:"ppkPelayanan" validate:"omitempty"`
Catatan string `json:"catatan" validate:"omitempty,max=200"`
User string `json:"user" binding:"required" validate:"required"`
}
// Validate validates the PesertaPutRequest
func (r *PesertaPutRequest) Validate() error {
if r.TPeserta.ID == "" {
return fmt.Errorf("ID tidak boleh kosong")
}
if r.TPeserta.NoKartu != "" && len(r.TPeserta.NoKartu) != 13 {
return fmt.Errorf("nomor kartu harus 13 digit")
}
return nil
}
// ToJSON converts struct to JSON string
func (r *PesertaPutRequest) ToJSON() (string, error) {
data, err := json.Marshal(r)
return string(data), err
}
// Peserta DELETE Request Structure with Enhanced Validation
type PesertaDeleteRequest struct {
BaseRequest
TPeserta PesertaDeleteData `json:"t_sep" binding:"required" validate:"required"`
}
type PesertaDeleteData struct {
ID string `json:"id" binding:"required" validate:"required"`
User string `json:"user" binding:"required" validate:"required"`
}
// Validate validates the PesertaDeleteRequest
func (r *PesertaDeleteRequest) Validate() error {
if r.TPeserta.ID == "" {
return fmt.Errorf("ID tidak boleh kosong")
}
if r.TPeserta.User == "" {
return fmt.Errorf("User tidak boleh kosong")
}
return nil
}
// ToJSON converts struct to JSON string
func (r *PesertaDeleteRequest) ToJSON() (string, error) {
data, err := json.Marshal(r)
return string(data), err
}
// Common Helper Structures for BPJS
type Flag struct {
Flag string `json:"flag" binding:"required" validate:"required,oneof=0 1"`
}
type Poli struct {
Tujuan string `json:"tujuan" binding:"required" validate:"required"`
Eksekutif string `json:"eksekutif" binding:"required" validate:"required,oneof=0 1"`
}
type KlsRawat struct {
KlsRawatHak string `json:"klsRawatHak" binding:"required" validate:"required,oneof=1 2 3"`
KlsRawatNaik string `json:"klsRawatNaik" validate:"omitempty,oneof=1 2 3 4 5 6 7"`
Pembiayaan string `json:"pembiayaan" validate:"omitempty,oneof=1 2 3"`
PenanggungJawab string `json:"penanggungJawab" validate:"omitempty,max=100"`
}
// Validation helper functions
func IsValidStatus(status string) bool {
validStatuses := []string{"active", "inactive", "pending", "processed"}
for _, v := range validStatuses {
if v == status {
return true
}
}
return false
}
func IsValidJnsPelayanan(jns string) bool {
return jns == "1" || jns == "2" // 1: rawat jalan, 2: rawat inap
}
func IsValidKlsRawat(kls string) bool {
validKelas := []string{"1", "2", "3"}
for _, v := range validKelas {
if v == kls {
return true
}
}
return false
}

View File

@@ -1,66 +0,0 @@
package models
// Peserta BPJS Models
// Generated at: 2025-08-24 16:39:05
// Category: vclaim
// Common Response Structure
type PesertaResponse struct {
Message string `json:"message"`
Data map[string]interface{} `json:"data,omitempty"`
}
type PesertaRawResponse struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
Response interface{} `json:"response"`
}
// Peserta POST Request Structure
type PesertaPostRequest struct {
TPeserta PesertaPost `json:"t_peserta" binding:"required"`
}
type PesertaPost struct {
// Add your specific fields here based on BPJS API requirements
NoKartu string `json:"noKartu" binding:"required"`
TglLayanan string `json:"tglLayanan" binding:"required"`
JnsPelayanan string `json:"jnsPelayanan" binding:"required"`
User string `json:"user" binding:"required"`
}
// Peserta PUT Request Structure
type PesertaPutRequest struct {
TPeserta PesertaPut `json:"t_peserta" binding:"required"`
}
type PesertaPut struct {
ID string `json:"id" binding:"required"`
NoKartu string `json:"noKartu"`
TglLayanan string `json:"tglLayanan"`
JnsPelayanan string `json:"jnsPelayanan"`
User string `json:"user" binding:"required"`
}
// Peserta DELETE Request Structure
type PesertaDeleteRequest struct {
TPeserta struct {
ID string `json:"id" binding:"required"`
User string `json:"user" binding:"required"`
} `json:"t_peserta" binding:"required"`
}
// Common Helper Structures
// Validation helpers
func IsValidStatus(status string) bool {
validStatuses := []string{"active", "inactive", "pending", "processed"}
for _, v := range validStatuses {
if v == status {
return true
}
}
return false
}

View File

@@ -1,34 +0,0 @@
package main
import (
"fmt"
"os"
)
func main() {
// Set environment variables for testing
os.Setenv("SWAGGER_TITLE", "My Custom API Service")
os.Setenv("SWAGGER_DESCRIPTION", "This is a custom API service for managing various resources")
os.Setenv("SWAGGER_VERSION", "2.0.0")
os.Setenv("SWAGGER_CONTACT_NAME", "Support Team")
os.Setenv("SWAGGER_CONTACT_URL", "https://mycompany.com/support")
os.Setenv("SWAGGER_CONTACT_EMAIL", "support@mycompany.com")
os.Setenv("SWAGGER_LICENSE_NAME", "MIT License")
os.Setenv("SWAGGER_LICENSE_URL", "https://opensource.org/licenses/MIT")
os.Setenv("SWAGGER_HOST", "api.mycompany.com:8080")
os.Setenv("SWAGGER_BASE_PATH", "/api/v2")
os.Setenv("SWAGGER_SCHEMES", "https")
fmt.Println("Environment variables set for Swagger documentation:")
fmt.Println("SWAGGER_TITLE:", os.Getenv("SWAGGER_TITLE"))
fmt.Println("SWAGGER_DESCRIPTION:", os.Getenv("SWAGGER_DESCRIPTION"))
fmt.Println("SWAGGER_VERSION:", os.Getenv("SWAGGER_VERSION"))
fmt.Println("SWAGGER_CONTACT_NAME:", os.Getenv("SWAGGER_CONTACT_NAME"))
fmt.Println("SWAGGER_HOST:", os.Getenv("SWAGGER_HOST"))
fmt.Println("SWAGGER_BASE_PATH:", os.Getenv("SWAGGER_BASE_PATH"))
fmt.Println("SWAGGER_SCHEMES:", os.Getenv("SWAGGER_SCHEMES"))
fmt.Println("\nTo test the Swagger generation, run:")
fmt.Println("swag init -g cmd/api/main.go --parseDependency --parseInternal")
fmt.Println("Then check docs/docs.go to see the updated values")
}

View File

@@ -145,7 +145,6 @@ import (
"` + modelsImportPath + `"
services "` + data.ModuleName + `/internal/services/bpjs"
"` + data.ModuleName + `/pkg/logger"
"` + data.ModuleName + `/pkg/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
@@ -170,7 +169,7 @@ type ` + data.Name + `HandlerConfig struct {
// New` + data.Name + `Handler creates a new optimized ` + data.Name + `Handler
func New` + data.Name + `Handler(cfg *` + data.Name + `HandlerConfig) *` + data.Name + `Handler {
return &` + data.Name + `Handler{
service: services.NewService(cfg.BpjsConfig),
service: services.NewService(*cfg.BpjsConfig),
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.BpjsConfig,
@@ -493,7 +492,7 @@ func (h *` + data.Name + `Handler) Delete` + data.Name + `(c *gin.Context) {
defer cancel()
var rawResponse models.BpjsRawResponse
if err := h.service.Delete(ctx, "` + data.DeleteEndpoint + `", req, &rawResponse); err != nil {
if err := h.service.Delete(ctx, "` + data.DeleteEndpoint + `", req); err != nil {
h.logger.Error("Failed to delete ` + data.Name + `", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
@@ -810,7 +809,7 @@ type BpjsRawResponse struct {
// ` + data.Name + ` POST Request Structure with Enhanced Validation
type ` + data.Name + `PostRequest struct {
BaseRequest
T` + data.Name + ` ` + data.Name + `Post ` + "`json:\"t` + data.NameLower + `\" binding:\"required\" validate:\"required\"`" + `
T` + data.Name + ` ` + data.Name + `Post ` + "`json:\"tsep\" binding:\"required\" validate:\"required\"`" + `
}
type ` + data.Name + `Post struct {
@@ -853,7 +852,7 @@ func (r *` + data.Name + `PostRequest) ToJSON() (string, error) {
// ` + data.Name + ` PUT Request Structure with Enhanced Validation
type ` + data.Name + `PutRequest struct {
BaseRequest
T` + data.Name + ` ` + data.Name + `Put ` + "`json:\"t` + data.NameLower + `\" binding:\"required\" validate:\"required\"`" + `
T` + data.Name + ` ` + data.Name + `Put ` + "`json:\"tsep\" binding:\"required\" validate:\"required\"`" + `
}
type ` + data.Name + `Put struct {
@@ -892,7 +891,7 @@ func (r *` + data.Name + `PutRequest) ToJSON() (string, error) {
// ` + data.Name + ` DELETE Request Structure with Enhanced Validation
type ` + data.Name + `DeleteRequest struct {
BaseRequest
T` + data.Name + ` ` + data.Name + `DeleteData ` + "`json:\"t` + data.NameLower + `\" binding:\"required\" validate:\"required\"`" + `
T` + data.Name + ` ` + data.Name + `DeleteData ` + "`json:\"tsep\" binding:\"required\" validate:\"required\"`" + `
}
type ` + data.Name + `DeleteData struct {