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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,6 @@
basePath: /api/v1 basePath: /api/v1
definitions: definitions:
gin.H: api-service_internal_models.AggregateData:
additionalProperties: {}
type: object
models.AggregateData:
properties: properties:
by_dinas: by_dinas:
additionalProperties: additionalProperties:
@@ -30,7 +27,7 @@ definitions:
updated_today: updated_today:
type: integer type: integer
type: object type: object
models.ErrorResponse: api-service_internal_models.ErrorResponse:
properties: properties:
code: code:
type: integer type: integer
@@ -41,68 +38,7 @@ definitions:
timestamp: timestamp:
type: string type: string
type: object type: object
models.Flag: api-service_internal_models.MetaResponse:
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:
properties: properties:
current_page: current_page:
type: integer type: integer
@@ -119,33 +55,44 @@ definitions:
total_pages: total_pages:
type: integer type: integer
type: object type: object
models.NullableInt32: api-service_internal_models.NullableInt32:
properties: properties:
int32: int32:
type: integer type: integer
valid: valid:
type: boolean type: boolean
type: object type: object
models.Penjamin: api-service_internal_models_auth.LoginRequest:
properties: properties:
keterangan: password:
type: string type: string
suplesi: username:
$ref: '#/definitions/models.Suplesi'
tglKejadian:
type: string
type: object
models.Poli:
properties:
eksekutif:
type: string
tujuan:
type: string type: string
required: required:
- eksekutif - password
- tujuan - username
type: object 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: properties:
date_created: date_created:
$ref: '#/definitions/sql.NullTime' $ref: '#/definitions/sql.NullTime'
@@ -172,7 +119,7 @@ definitions:
satuan_overtime: satuan_overtime:
$ref: '#/definitions/sql.NullString' $ref: '#/definitions/sql.NullString'
sort: sort:
$ref: '#/definitions/models.NullableInt32' $ref: '#/definitions/api-service_internal_models.NullableInt32'
status: status:
type: string type: string
tarif: tarif:
@@ -190,7 +137,7 @@ definitions:
user_updated: user_updated:
$ref: '#/definitions/sql.NullString' $ref: '#/definitions/sql.NullString'
type: object type: object
models.RetribusiCreateRequest: api-service_internal_models_retribusi.RetribusiCreateRequest:
properties: properties:
dinas: dinas:
maxLength: 255 maxLength: 255
@@ -247,41 +194,41 @@ definitions:
required: required:
- status - status
type: object type: object
models.RetribusiCreateResponse: api-service_internal_models_retribusi.RetribusiCreateResponse:
properties: properties:
data: data:
$ref: '#/definitions/models.Retribusi' $ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
message: message:
type: string type: string
type: object type: object
models.RetribusiDeleteResponse: api-service_internal_models_retribusi.RetribusiDeleteResponse:
properties: properties:
id: id:
type: string type: string
message: message:
type: string type: string
type: object type: object
models.RetribusiGetByIDResponse: api-service_internal_models_retribusi.RetribusiGetByIDResponse:
properties: properties:
data: data:
$ref: '#/definitions/models.Retribusi' $ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
message: message:
type: string type: string
type: object type: object
models.RetribusiGetResponse: api-service_internal_models_retribusi.RetribusiGetResponse:
properties: properties:
data: data:
items: items:
$ref: '#/definitions/models.Retribusi' $ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
type: array type: array
message: message:
type: string type: string
meta: meta:
$ref: '#/definitions/models.MetaResponse' $ref: '#/definitions/api-service_internal_models.MetaResponse'
summary: summary:
$ref: '#/definitions/models.AggregateData' $ref: '#/definitions/api-service_internal_models.AggregateData'
type: object type: object
models.RetribusiUpdateRequest: api-service_internal_models_retribusi.RetribusiUpdateRequest:
properties: properties:
dinas: dinas:
maxLength: 255 maxLength: 255
@@ -338,44 +285,18 @@ definitions:
required: required:
- status - status
type: object type: object
models.RetribusiUpdateResponse: api-service_internal_models_retribusi.RetribusiUpdateResponse:
properties: properties:
data: data:
$ref: '#/definitions/models.Retribusi' $ref: '#/definitions/api-service_internal_models_retribusi.Retribusi'
message: message:
type: string type: string
type: object type: object
models.Rujukan: api-service_internal_models_vclaim.SepPostRequest:
properties:
asalRujukan:
type: string
noRujukan:
type: string
ppkRujukan:
type: string
tglRujukan:
type: string
required:
- asalRujukan
- noRujukan
- ppkRujukan
- tglRujukan
type: object type: object
models.SepPostRequest: api-service_internal_models_vclaim.SepPutRequest:
properties:
tsep:
$ref: '#/definitions/models.TSepPost'
required:
- tsep
type: object type: object
models.SepPutRequest: api-service_internal_models_vclaim.SepResponse:
properties:
tsep:
$ref: '#/definitions/models.TSepPut'
required:
- tsep
type: object
models.SepResponse:
properties: properties:
data: data:
additionalProperties: true additionalProperties: true
@@ -383,134 +304,113 @@ definitions:
message: message:
type: string type: string
type: object type: object
models.Skdp: gin.H:
properties: additionalProperties: {}
kodeDPJP:
type: string
noSurat:
type: string
required:
- kodeDPJP
- noSurat
type: object type: object
models.Suplesi: internal_models_surkon.ErrorResponse:
properties: properties:
lokasiLaka: code:
$ref: '#/definitions/models.LokasiLaka'
noSepSuplesi:
type: string type: string
suplesi: details:
type: string
message:
type: string type: string
type: object type: object
models.TSepPost: models.ResponseMetadata:
properties: properties:
assesmentPel: request_id:
type: string type: string
timestamp:
type: string
version:
type: string
type: object
models.SpriPost:
properties:
catatan: catatan:
maxLength: 200
type: string type: string
cob:
$ref: '#/definitions/models.Flag'
diagAwal:
type: string
dpjpLayan:
type: string
flagProcedure:
type: string
jaminan:
$ref: '#/definitions/models.Jaminan'
jnsPelayanan: jnsPelayanan:
enum:
- "1"
- "2"
type: string type: string
katarak:
$ref: '#/definitions/models.Flag'
kdPenunjang:
type: string
klsRawat:
$ref: '#/definitions/models.KlsRawatPost'
noKartu: noKartu:
description: Core BPJS fields - customize based on your specific requirements
maxLength: 13
minLength: 13
type: string type: string
noMR:
type: string
noTelp:
type: string
poli:
$ref: '#/definitions/models.Poli'
ppkPelayanan: ppkPelayanan:
type: string type: string
rujukan: tglLayanan:
$ref: '#/definitions/models.Rujukan'
skdp:
$ref: '#/definitions/models.Skdp'
tglSep:
description: yyyy-MM-dd
type: string
tujuanKunj:
type: string type: string
user: user:
type: string type: string
required: required:
- cob
- diagAwal
- jaminan
- jnsPelayanan - jnsPelayanan
- katarak
- klsRawat
- noKartu - noKartu
- noMR
- poli
- ppkPelayanan - ppkPelayanan
- rujukan - tglLayanan
- skdp
- tglSep
- user - user
type: object 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: properties:
catatan: catatan:
type: string maxLength: 200
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:
type: string type: string
id: id:
type: string type: string
role: jnsPelayanan:
enum:
- "1"
- "2"
type: string 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: string
type: object type: object
sql.NullString: sql.NullString:
@@ -554,14 +454,14 @@ paths:
name: login name: login
required: true required: true
schema: schema:
$ref: '#/definitions/models.LoginRequest' $ref: '#/definitions/api-service_internal_models_auth.LoginRequest'
produces: produces:
- application/json - application/json
responses: responses:
"200": "200":
description: OK description: OK
schema: schema:
$ref: '#/definitions/models.TokenResponse' $ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400": "400":
description: Bad request description: Bad request
schema: schema:
@@ -586,7 +486,7 @@ paths:
"200": "200":
description: OK description: OK
schema: schema:
$ref: '#/definitions/models.User' $ref: '#/definitions/api-service_internal_models_auth.User'
"401": "401":
description: Unauthorized description: Unauthorized
schema: schema:
@@ -618,7 +518,7 @@ paths:
"200": "200":
description: OK description: OK
schema: schema:
$ref: '#/definitions/models.TokenResponse' $ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400": "400":
description: Bad request description: Bad request
schema: schema:
@@ -725,19 +625,19 @@ paths:
"200": "200":
description: Retribusi deleted successfully description: Retribusi deleted successfully
schema: schema:
$ref: '#/definitions/models.RetribusiDeleteResponse' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiDeleteResponse'
"400": "400":
description: Invalid ID format description: Invalid ID format
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"404": "404":
description: Retribusi not found description: Retribusi not found
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500": "500":
description: Internal server error description: Internal server error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Delete retribusi summary: Delete retribusi
tags: tags:
- retribusi - retribusi
@@ -757,19 +657,19 @@ paths:
"200": "200":
description: Success response description: Success response
schema: schema:
$ref: '#/definitions/models.RetribusiGetByIDResponse' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiGetByIDResponse'
"400": "400":
description: Invalid ID format description: Invalid ID format
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"404": "404":
description: Retribusi not found description: Retribusi not found
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500": "500":
description: Internal server error description: Internal server error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get Retribusi by ID summary: Get Retribusi by ID
tags: tags:
- retribusi - retribusi
@@ -788,26 +688,26 @@ paths:
name: request name: request
required: true required: true
schema: schema:
$ref: '#/definitions/models.RetribusiUpdateRequest' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiUpdateRequest'
produces: produces:
- application/json - application/json
responses: responses:
"200": "200":
description: Retribusi updated successfully description: Retribusi updated successfully
schema: schema:
$ref: '#/definitions/models.RetribusiUpdateResponse' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiUpdateResponse'
"400": "400":
description: Bad request or validation error description: Bad request or validation error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"404": "404":
description: Retribusi not found description: Retribusi not found
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500": "500":
description: Internal server error description: Internal server error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Update retribusi summary: Update retribusi
tags: tags:
- retribusi - retribusi
@@ -854,15 +754,15 @@ paths:
"200": "200":
description: Success response description: Success response
schema: schema:
$ref: '#/definitions/models.RetribusiGetResponse' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiGetResponse'
"400": "400":
description: Bad request description: Bad request
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500": "500":
description: Internal server error description: Internal server error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get retribusi with pagination and optional aggregation summary: Get retribusi with pagination and optional aggregation
tags: tags:
- retribusi - retribusi
@@ -876,22 +776,22 @@ paths:
name: request name: request
required: true required: true
schema: schema:
$ref: '#/definitions/models.RetribusiCreateRequest' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiCreateRequest'
produces: produces:
- application/json - application/json
responses: responses:
"201": "201":
description: Retribusi created successfully description: Retribusi created successfully
schema: schema:
$ref: '#/definitions/models.RetribusiCreateResponse' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiCreateResponse'
"400": "400":
description: Bad request or validation error description: Bad request or validation error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500": "500":
description: Internal server error description: Internal server error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Create retribusi summary: Create retribusi
tags: tags:
- retribusi - retribusi
@@ -929,15 +829,15 @@ paths:
"200": "200":
description: Success response description: Success response
schema: schema:
$ref: '#/definitions/models.RetribusiGetResponse' $ref: '#/definitions/api-service_internal_models_retribusi.RetribusiGetResponse'
"400": "400":
description: Bad request description: Bad request
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"500": "500":
description: Internal server error description: Internal server error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get retribusi with dynamic filtering summary: Get retribusi with dynamic filtering
tags: tags:
- retribusi - retribusi
@@ -957,14 +857,152 @@ paths:
"200": "200":
description: Statistics data description: Statistics data
schema: schema:
$ref: '#/definitions/models.AggregateData' $ref: '#/definitions/api-service_internal_models.AggregateData'
"500": "500":
description: Internal server error description: Internal server error
schema: schema:
$ref: '#/definitions/models.ErrorResponse' $ref: '#/definitions/api-service_internal_models.ErrorResponse'
summary: Get retribusi statistics summary: Get retribusi statistics
tags: tags:
- retribusi - 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: /api/v1/token/generate:
post: post:
consumes: consumes:
@@ -976,14 +1014,14 @@ paths:
name: token name: token
required: true required: true
schema: schema:
$ref: '#/definitions/models.LoginRequest' $ref: '#/definitions/api-service_internal_models_auth.LoginRequest'
produces: produces:
- application/json - application/json
responses: responses:
"200": "200":
description: OK description: OK
schema: schema:
$ref: '#/definitions/models.TokenResponse' $ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400": "400":
description: Bad request description: Bad request
schema: schema:
@@ -1020,7 +1058,7 @@ paths:
"200": "200":
description: OK description: OK
schema: schema:
$ref: '#/definitions/models.TokenResponse' $ref: '#/definitions/api-service_internal_models_auth.TokenResponse'
"400": "400":
description: Bad request description: Bad request
schema: schema:
@@ -1041,14 +1079,14 @@ paths:
name: request name: request
required: true required: true
schema: schema:
$ref: '#/definitions/models.SepPostRequest' $ref: '#/definitions/api-service_internal_models_vclaim.SepPostRequest'
produces: produces:
- application/json - application/json
responses: responses:
"200": "200":
description: SEP created successfully description: SEP created successfully
schema: schema:
$ref: '#/definitions/models.SepResponse' $ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400": "400":
description: Invalid request description: Invalid request
schema: schema:
@@ -1070,14 +1108,14 @@ paths:
name: request name: request
required: true required: true
schema: schema:
$ref: '#/definitions/models.SepPutRequest' $ref: '#/definitions/api-service_internal_models_vclaim.SepPutRequest'
produces: produces:
- application/json - application/json
responses: responses:
"200": "200":
description: SEP updated successfully description: SEP updated successfully
schema: schema:
$ref: '#/definitions/models.SepResponse' $ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400": "400":
description: Invalid request description: Invalid request
schema: schema:
@@ -1111,7 +1149,7 @@ paths:
"200": "200":
description: SEP deleted successfully description: SEP deleted successfully
schema: schema:
$ref: '#/definitions/models.SepResponse' $ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400": "400":
description: Invalid request description: Invalid request
schema: schema:
@@ -1139,7 +1177,7 @@ paths:
"200": "200":
description: Data SEP retrieved successfully description: Data SEP retrieved successfully
schema: schema:
$ref: '#/definitions/models.SepResponse' $ref: '#/definitions/api-service_internal_models_vclaim.SepResponse'
"400": "400":
description: Invalid request description: Invalid request
schema: 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 + `" "` + modelsImportPath + `"
services "` + data.ModuleName + `/internal/services/bpjs" services "` + data.ModuleName + `/internal/services/bpjs"
"` + data.ModuleName + `/pkg/logger" "` + data.ModuleName + `/pkg/logger"
"` + data.ModuleName + `/pkg/validator"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
@@ -170,7 +169,7 @@ type ` + data.Name + `HandlerConfig struct {
// New` + data.Name + `Handler creates a new optimized ` + data.Name + `Handler // New` + data.Name + `Handler creates a new optimized ` + data.Name + `Handler
func New` + data.Name + `Handler(cfg *` + data.Name + `HandlerConfig) *` + data.Name + `Handler { func New` + data.Name + `Handler(cfg *` + data.Name + `HandlerConfig) *` + data.Name + `Handler {
return &` + data.Name + `Handler{ return &` + data.Name + `Handler{
service: services.NewService(cfg.BpjsConfig), service: services.NewService(*cfg.BpjsConfig),
validator: cfg.Validator, validator: cfg.Validator,
logger: cfg.Logger, logger: cfg.Logger,
config: cfg.BpjsConfig, config: cfg.BpjsConfig,
@@ -493,7 +492,7 @@ func (h *` + data.Name + `Handler) Delete` + data.Name + `(c *gin.Context) {
defer cancel() defer cancel()
var rawResponse models.BpjsRawResponse 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{}{ h.logger.Error("Failed to delete ` + data.Name + `", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
"request_id": requestID, "request_id": requestID,
@@ -810,7 +809,7 @@ type BpjsRawResponse struct {
// ` + data.Name + ` POST Request Structure with Enhanced Validation // ` + data.Name + ` POST Request Structure with Enhanced Validation
type ` + data.Name + `PostRequest struct { type ` + data.Name + `PostRequest struct {
BaseRequest 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 { 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 // ` + data.Name + ` PUT Request Structure with Enhanced Validation
type ` + data.Name + `PutRequest struct { type ` + data.Name + `PutRequest struct {
BaseRequest 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 { 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 // ` + data.Name + ` DELETE Request Structure with Enhanced Validation
type ` + data.Name + `DeleteRequest struct { type ` + data.Name + `DeleteRequest struct {
BaseRequest 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 { type ` + data.Name + `DeleteData struct {