Perbaikan Generete Satu Sehat

This commit is contained in:
2025-09-08 05:38:58 +07:00
parent 779bbc976c
commit 1bd951cd4c
7 changed files with 4816 additions and 6 deletions

View File

@@ -93,6 +93,8 @@ go run tools/bpjs/generate-handler.go services-config-bpjs.yaml vclaim
# 2. Test generate semua service
go run tools/bpjs/generate-handler.go services-config-bpjs.yaml
go run tools/satusehat/generate-satusehat-handler.go services-config-satusehat.yaml patient
```
### Method Tersedia

View File

@@ -0,0 +1,466 @@
// Package patient handles Patient services
// Generated on: 2025-09-07 17:42:51
package patient
import (
"api-service/internal/config"
models "api-service/internal/models/patient"
satusehat "api-service/internal/services/satusehat"
"api-service/pkg/logger"
"context"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
)
// Patient handles Patient services
type Patient struct {
satusehatService satusehat.SatuSehatService
validator *validator.Validate
logger logger.Logger
config *config.Config
}
// PatientConfig contains configuration for Patient
type PatientConfig struct {
Config *config.Config
Logger logger.Logger
Validator *validator.Validate
SatusehatService satusehat.SatuSehatService
}
// NewPatient creates a new Patient
func NewPatient(cfg PatientConfig) *Patient {
return &Patient{
satusehatService: cfg.SatusehatService,
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.Config,
}
}
// CreateBasic creates a new resource
// @Summary Create a new resource
// @Description Create a new resource in the system
// @Tags Patient
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param request body models.PatientCreateRequest true "Resource creation request"
// @Success 201 {object} models.PatientCreateRequest "Resource created successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router [post]
func (h *Patient) CreateBasic(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
h.logger.Info("Processing CreateBasic request", map[string]interface{}{
"request_id": requestID,
"endpoint": "",
})
// Bind and validate request body
var req models.PatientCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind request body", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponse{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// Validate request structure
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Request validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponse{
Status: "error",
Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
// Call SATUSEHAT service to create patient
resp := h.satusehatService.Post(ctx, "/Patient", req, &models.PatientResponse{})
response := models.PatientResponse{
BaseResponse: models.BaseResponse{
Status: "success",
Message: "Patient created successfully",
RequestID: requestID,
Data: resp,
},
}
h.logger.Info("Successfully created Basic", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusCreated, response)
}
// GetBasic retrieves a specific resource by ID
// @Summary Get a specific resource by ID
// @Description Retrieve a specific resource from the system
// @Tags Patient
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param id path string true "Resource ID"
// @Success 200 {object} models.PatientResponse "Resource retrieved successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 404 {object} models.ErrorResponse "Resource not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /:id [get]
func (h *Patient) GetBasic(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
id := c.Param("id")
if id == "" {
h.logger.Error("Missing required parameter id", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponse{
Status: "error",
Message: "Missing required parameter id",
RequestID: requestID,
})
return
}
h.logger.Info("Processing GetBasic request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/:id",
"id": id,
})
// Call SATUSEHAT service to get patient by ID
resp, err := h.satusehatService.GetResourceByID(ctx, "Patient", id)
if err != nil {
h.logger.Error("Failed to get patient via SATUSEHAT", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
"id": id,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponse{
Status: "error",
Message: "Failed to get patient: " + err.Error(),
RequestID: requestID,
})
return
}
response := models.PatientResponse{
BaseResponse: models.BaseResponse{
Status: "success",
Message: "Patient retrieved successfully",
RequestID: requestID,
Data: resp,
},
}
h.logger.Info("Successfully retrieved Basic", map[string]interface{}{
"request_id": requestID,
"id": id,
})
c.JSON(http.StatusOK, response)
}
// UpdateBasic updates an existing resource
// @Summary Update an existing resource
// @Description Update an existing resource in the system
// @Tags Patient
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param id path string true "Resource ID"
// @Param request body models.BasicUpdateRequest true "Resource update request"
// @Success 200 {object} models.PatientResponse "Resource updated successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 404 {object} models.ErrorResponse "Resource not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /:id [put]
func (h *Patient) UpdateBasic(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
id := c.Param("id")
if id == "" {
h.logger.Error("Missing required parameter id", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponse{
Status: "error",
Message: "Missing required parameter id",
RequestID: requestID,
})
return
}
h.logger.Info("Processing UpdateBasic request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/:id",
"id": id,
})
// Bind and validate request body
var req models.PatientUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Failed to bind request body", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponse{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// Validate request structure
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Request validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponse{
Status: "error",
Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
// Call SATUSEHAT service to update patient
resp := h.satusehatService.Put(ctx, "/Patient/"+id, req, &models.PatientResponse{})
response := models.PatientResponse{
BaseResponse: models.BaseResponse{
Status: "success",
Message: "Patient updated successfully",
RequestID: requestID,
Data: resp,
},
}
h.logger.Info("Successfully updated Basic", map[string]interface{}{
"request_id": requestID,
"id": id,
})
c.JSON(http.StatusOK, response)
}
func (h *Patient) DeleteBasic(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
id := c.Param("id")
if id == "" {
h.logger.Error("Missing required parameter id", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, models.ErrorResponse{
Status: "error",
Message: "Missing required parameter id",
RequestID: requestID,
})
return
}
h.logger.Info("Processing DeleteBasic request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/:id",
"id": id,
})
// Call SATUSEHAT service to delete patient
err := h.satusehatService.Delete(ctx, "/Patient/"+id, nil)
if err != nil {
h.logger.Error("Failed to delete patient via SATUSEHAT", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
"id": id,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponse{
Status: "error",
Message: "Failed to delete patient: " + err.Error(),
RequestID: requestID,
})
return
}
response := models.SuccessResponse{
Status: "success",
Message: "Patient deleted successfully",
RequestID: requestID,
}
h.logger.Info("Successfully deleted Patient", map[string]interface{}{
"request_id": requestID,
"id": id,
})
c.JSON(http.StatusOK, response)
}
// SearchBasic searches for resources
// @Summary Search for resources
// @Description Search for resources in the system
// @Tags Patient
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param query query string false "Search query"
// @Param limit query int false "Limit results" default(10)
// @Param offset query int false "Offset results" default(0)
// @Success 200 {object} models.BasicSearchResponse "Search results"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router [get]
func (h *Patient) SearchBasic(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
// Get query parameters
query := c.Query("query")
limit := 10
if l := c.Query("limit"); l != "" {
if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
limit = parsed
}
}
offset := 0
if o := c.Query("offset"); o != "" {
if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
offset = parsed
}
}
h.logger.Info("Processing SearchBasic request", map[string]interface{}{
"request_id": requestID,
"endpoint": "",
"query": query,
"limit": limit,
"offset": offset,
})
// Build search query for SATUSEHAT
endpoint := "/Patient"
if query != "" {
endpoint += "?name=" + query
}
if limit > 0 {
if query == "" {
endpoint += "?"
} else {
endpoint += "&"
}
endpoint += "_count=" + strconv.Itoa(limit)
}
// Call SATUSEHAT service to search patients
resp, err := h.satusehatService.GetRawResponse(ctx, endpoint)
if err != nil {
h.logger.Error("Failed to search patients via SATUSEHAT", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
"query": query,
})
c.JSON(http.StatusInternalServerError, models.ErrorResponse{
Status: "error",
Message: "Failed to search patients: " + err.Error(),
RequestID: requestID,
})
return
}
response := models.PatientSearchResponse{
BaseResponse: models.BaseResponse{
Status: "success",
Message: "Search completed successfully",
RequestID: requestID,
Data: resp,
},
}
h.logger.Info("Successfully completed search", map[string]interface{}{
"request_id": requestID,
"query": query,
"results": len(response.Data.Results),
})
c.JSON(http.StatusOK, response)
}

View File

@@ -0,0 +1,105 @@
package models
import (
"time"
"github.com/go-playground/validator/v10"
)
// BaseRequest contains common fields for all requests
type BaseRequest struct {
RequestID string `json:"request_id,omitempty"`
Timestamp time.Time `json:"timestamp,omitempty"`
}
// BaseResponse contains common fields for all responses
type BaseResponse struct {
Status string `json:"status"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
// ErrorResponse represents an error response
type ErrorResponse struct {
Status string `json:"status"`
Message string `json:"message"`
RequestID string `json:"request_id,omitempty"`
}
// SuccessResponse represents a success response
type SuccessResponse struct {
Status string `json:"status"`
Message string `json:"message"`
RequestID string `json:"request_id,omitempty"`
}
// SearchData contains search results
type SearchData struct {
Results []interface{} `json:"results"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
// Patient Models
// Generated at: 2025-09-07 17:42:51
// PatientCreateRequest represents a request to create a Patient
type PatientCreateRequest struct {
BaseRequest
// Add fields specific to Patient creation
Name string `json:"name" validate:"required"`
Description string `json:"description" validate:"omitempty"`
}
// PatientUpdateRequest represents a request to update a Patient
type PatientUpdateRequest struct {
BaseRequest
ID string `json:"id" validate:"required,uuid"`
Name string `json:"name" validate:"required"`
Description string `json:"description" validate:"omitempty"`
}
// PatientResponse represents a response for Patient operations
type PatientResponse struct {
BaseResponse
}
// PatientSearchResponse represents a response for Patient search
type PatientSearchResponse struct {
BaseResponse
Data SearchData `json:"data"`
}
// PatientData represents the data structure for Patient
type PatientData struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
// Validate validates the PatientCreateRequest
func (r *PatientCreateRequest) Validate() error {
validate := validator.New()
return validate.Struct(r)
}
// Validate validates the PatientUpdateRequest
func (r *PatientUpdateRequest) Validate() error {
validate := validator.New()
return validate.Struct(r)
}
// NewPatientData creates a new PatientData with default values
func NewPatientData(name, description string) *PatientData {
now := time.Now()
return &PatientData{
ID: "", // Will be set by the database
Name: name,
Description: description,
CreatedAt: now,
UpdatedAt: now,
}
}

View File

@@ -15,7 +15,7 @@ global:
services:
patient:
name: "Patient"
category: "fhir/patient"
category: "patient"
package: "patient"
description: "FHIR Patient resource management for Satu Sehat ecosystem"
base_url: "https://api-satusehat-stg.dto.kemkes.go.id/fhir-r4/v1"
@@ -53,7 +53,7 @@ services:
organization:
name: "Organization"
category: "fhir/organization"
category: "organization"
package: "organization"
description: "FHIR Organization resource management for Satu Sehat ecosystem"
base_url: "https://api-satusehat-stg.dto.kemkes.go.id/fhir-r4/v1"
@@ -90,7 +90,7 @@ services:
practitioner:
name: "Practitioner"
category: "fhir/practitioner"
category: "practitioner"
package: "practitioner"
description: "FHIR Practitioner resource management for Satu Sehat ecosystem"
base_url: "https://api-satusehat-stg.dto.kemkes.go.id/fhir-r4/v1"
@@ -127,7 +127,7 @@ services:
encounter:
name: "Encounter"
category: "fhir/encounter"
category: "encounter"
package: "encounter"
description: "FHIR Encounter resource management for Satu Sehat ecosystem"
base_url: "https://api-satusehat-stg.dto.kemkes.go.id/fhir-r4/v1"
@@ -163,7 +163,7 @@ services:
observation:
name: "Observation"
category: "fhir/observation"
category: "observation"
package: "observation"
description: "FHIR Observation resource management for Satu Sehat ecosystem"
base_url: "https://api-satusehat-stg.dto.kemkes.go.id/fhir-r4/v1"

View File

@@ -941,7 +941,7 @@ func (h *` + data.Name + `Handler) sendFhirErrorResponse(c *gin.Context, statusC
}},
}
c.JSON(statusCode, operationOutcome)
}
}a
func (h *` + data.Name + `Handler) sendFhirOperationOutcome(c *gin.Context, statusCode int, outcome models.FhirResponse, requestID string) {
c.JSON(statusCode, outcome)

File diff suppressed because it is too large Load Diff

2119
tools/satusehat/newgenerete Normal file

File diff suppressed because it is too large Load Diff