467 lines
12 KiB
Go
467 lines
12 KiB
Go
// 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)
|
|
}
|