perbaikan decript

This commit is contained in:
2025-09-02 19:14:05 +07:00
parent bd231b5919
commit bb5f3876ec
5 changed files with 320 additions and 130 deletions

View File

@@ -1,4 +1,3 @@
// Service: VClaim (vclaim) // Service: VClaim (vclaim)
// Description: BPJS VClaim service for eligibility and SEP management // Description: BPJS VClaim service for eligibility and SEP management
@@ -6,14 +5,14 @@ package peserta
import ( import (
"context" "context"
"strings" "encoding/json"
"net/http" "net/http"
"strings"
"time" "time"
"api-service/internal/config" "api-service/internal/config"
"api-service/internal/models" "api-service/internal/models"
"api-service/internal/models/vclaim/peserta" services "api-service/internal/services/bpjs"
"api-service/internal/services/bpjs"
"api-service/pkg/logger" "api-service/pkg/logger"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -21,6 +20,62 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
// PesertaData represents peserta information from BPJS
type PesertaData struct {
NoKartu string `json:"noKartu"`
NIK string `json:"nik"`
Nama string `json:"nama"`
Pisa string `json:"pisa"`
Sex string `json:"sex"`
TanggalLahir string `json:"tglLahir"`
TglCetakKartu string `json:"tglCetakKartu"`
TglTAT string `json:"tglTAT"`
TglTMT string `json:"tglTMT"`
StatusPeserta struct {
Kode string `json:"kode"`
Keterangan string `json:"keterangan"`
} `json:"statusPeserta"`
ProvUmum struct {
KdProvider string `json:"kdProvider"`
NmProvider string `json:"nmProvider"`
} `json:"provUmum"`
JenisPeserta struct {
Kode string `json:"kode"`
Keterangan string `json:"keterangan"`
} `json:"jenisPeserta"`
HakKelas struct {
Kode string `json:"kode"`
Keterangan string `json:"keterangan"`
} `json:"hakKelas"`
Umur struct {
UmurSekarang string `json:"umurSekarang"`
UmurSaatPelayanan string `json:"umurSaatPelayanan"`
} `json:"umur"`
Informasi struct {
Dinsos interface{} `json:"dinsos"`
ProlanisPRB string `json:"prolanisPRB"`
NoSKTM interface{} `json:"noSKTM"`
ESEP interface{} `json:"eSEP"`
} `json:"informasi"`
Cob struct {
NoAsuransi interface{} `json:"noAsuransi"`
NmAsuransi interface{} `json:"nmAsuransi"`
TglTMT interface{} `json:"tglTMT"`
TglTAT interface{} `json:"tglTAT"`
} `json:"cob"`
MR struct {
NoMR string `json:"noMR"`
NoTelepon string `json:"noTelepon"`
} `json:"mr,omitempty"`
}
// PesertaResponse represents peserta API response
type PesertaResponse struct {
models.BaseResponse
Data *PesertaData `json:"data,omitempty"`
MetaData interface{} `json:"metaData,omitempty"`
}
// VClaimHandler handles VClaim BPJS services // VClaimHandler handles VClaim BPJS services
type VClaimHandler struct { type VClaimHandler struct {
service services.VClaimService service services.VClaimService
@@ -46,16 +101,15 @@ func NewVClaimHandler(cfg VClaimHandlerConfig) *VClaimHandler {
} }
} }
// GetPesertaBynokartu godoc // GetPesertaBynokartu godoc
// @Summary Get PesertaBynokartu data // @Summary Get PesertaBynokartu data
// @Description Get participant eligibility information by card number // @Description Get participant eligibility information by card number
// @Tags Peserta // @Tags Peserta
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking" // @Param X-Request-ID header string false "Request ID for tracking"
// @Param nokartu path string true "nokartu" example("example_value") // @Param nokartu path string true "nokartu" example("example_value")
// @Success 200 {object} peserta.PesertaResponse "Successfully retrieved PesertaBynokartu data" // @Success 200 {object} peserta.PesertaResponse "Successfully retrieved PesertaBynokartu data"
// @Failure 400 {object} models.ErrorResponseBpjs "Bad request - invalid parameters" // @Failure 400 {object} models.ErrorResponseBpjs "Bad request - invalid parameters"
// @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized - invalid API credentials" // @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized - invalid API credentials"
@@ -73,25 +127,22 @@ func (h *VClaimHandler) GetPesertaBynokartu(c *gin.Context) {
c.Header("X-Request-ID", requestID) c.Header("X-Request-ID", requestID)
} }
h.logger.Info("Processing GetPesertaBynokartu request", map[string]interface{}{ h.logger.Info("Processing GetPesertaBynokartu request", map[string]interface{}{
"request_id": requestID, "request_id": requestID,
"endpoint": "/peserta/:nokartu", "nokartu": c.Param("nokartu"),
"tglsep": c.Param("tglsep"),
"nokartu": c.Param("nokartu"),
}) })
// Extract path parameters // Extract path parameters
nokartu := c.Param("nokartu") nokartu := c.Param("nokartu")
tglsep := c.Param("tglsep")
if nokartu == "" { if nokartu == "" {
h.logger.Error("Missing required parameter nokartu", map[string]interface{}{ h.logger.Error("Missing required parameter nokartu", map[string]interface{}{
"request_id": requestID, "request_id": requestID,
}) })
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{ c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error", Status: "error",
Message: "Missing required parameter nokartu", Message: "Missing required parameter nokartu",
@@ -99,24 +150,22 @@ func (h *VClaimHandler) GetPesertaBynokartu(c *gin.Context) {
}) })
return return
} }
// Call service method // Call service method
var response peserta.PesertaResponse var response PesertaResponse
endpoint := "/peserta/:nokartu" endpoint := "/Peserta/nokartu/:nokartu/tglSEP/:tglsep"
endpoint = strings.Replace(endpoint, ":nokartu", nokartu, 1) endpoint = strings.Replace(endpoint, ":nokartu", nokartu, 1)
endpoint = strings.Replace(endpoint, ":tglsep", tglsep, 1)
err := h.service.Get(ctx, endpoint, &response)
resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil { if err != nil {
h.logger.Error("Failed to get PesertaBynokartu", map[string]interface{}{ h.logger.Error("Failed to get PesertaBynokartu", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
"request_id": requestID, "request_id": requestID,
}) })
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{ c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error", Status: "error",
Message: "Internal server error", Message: "Internal server error",
@@ -125,29 +174,50 @@ func (h *VClaimHandler) GetPesertaBynokartu(c *gin.Context) {
return return
} }
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &PesertaData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if pesertaMap, exists := respMap["peserta"]; exists {
pesertaBytes, _ := json.Marshal(pesertaMap)
json.Unmarshal(pesertaBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields // Ensure response has proper fields
response.Status = "success" response.Status = "success"
response.RequestID = requestID response.RequestID = requestID
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }
// GetPesertaBynik godoc // GetPesertaBynik godoc
// @Summary Get PesertaBynik data // @Summary Get PesertaBynik data
// @Description Get participant eligibility information by NIK // @Description Get participant eligibility information by NIK
// @Tags Peserta // @Tags Peserta
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param X-Request-ID header string false "Request ID for tracking" // @Param X-Request-ID header string false "Request ID for tracking"
// @Param nik path string true "nik" example("example_value") // @Param nik path string true "nik" example("example_value")
// @Success 200 {object} peserta.PesertaResponse "Successfully retrieved PesertaBynik data" // @Success 200 {object} peserta.PesertaResponse "Successfully retrieved PesertaBynik data"
// @Failure 400 {object} models.ErrorResponseBpjs "Bad request - invalid parameters" // @Failure 400 {object} models.ErrorResponseBpjs "Bad request - invalid parameters"
// @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized - invalid API credentials" // @Failure 401 {object} models.ErrorResponseBpjs "Unauthorized - invalid API credentials"
@@ -165,25 +235,22 @@ func (h *VClaimHandler) GetPesertaBynik(c *gin.Context) {
c.Header("X-Request-ID", requestID) c.Header("X-Request-ID", requestID)
} }
h.logger.Info("Processing GetPesertaBynik request", map[string]interface{}{ h.logger.Info("Processing GetPesertaBynik request", map[string]interface{}{
"request_id": requestID, "request_id": requestID,
"endpoint": "/peserta/nik/:nik", "endpoint": "/peserta/nik/:nik",
"nik": c.Param("nik"), "nik": c.Param("nik"),
}) })
// Extract path parameters // Extract path parameters
nik := c.Param("nik") nik := c.Param("nik")
if nik == "" { if nik == "" {
h.logger.Error("Missing required parameter nik", map[string]interface{}{ h.logger.Error("Missing required parameter nik", map[string]interface{}{
"request_id": requestID, "request_id": requestID,
}) })
c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{ c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
Status: "error", Status: "error",
Message: "Missing required parameter nik", Message: "Missing required parameter nik",
@@ -191,24 +258,21 @@ func (h *VClaimHandler) GetPesertaBynik(c *gin.Context) {
}) })
return return
} }
// Call service method // Call service method
var response peserta.PesertaResponse var response PesertaResponse
endpoint := "/peserta/nik/:nik" endpoint := "/peserta/nik/:nik"
endpoint = strings.Replace(endpoint, ":nik", nik, 1) endpoint = strings.Replace(endpoint, ":nik", nik, 1)
err := h.service.Get(ctx, endpoint, &response) resp, err := h.service.GetRawResponse(ctx, endpoint)
if err != nil { if err != nil {
h.logger.Error("Failed to get PesertaBynik", map[string]interface{}{ h.logger.Error("Failed to get PesertaBynik", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
"request_id": requestID, "request_id": requestID,
}) })
c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{ c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
Status: "error", Status: "error",
Message: "Internal server error", Message: "Internal server error",
@@ -217,16 +281,37 @@ func (h *VClaimHandler) GetPesertaBynik(c *gin.Context) {
return return
} }
// Map the raw response
response.MetaData = resp.MetaData
if resp.Response != nil {
response.Data = &PesertaData{}
if respStr, ok := resp.Response.(string); ok {
// Decrypt the response string
consID, secretKey, _, tstamp, _ := h.config.SetHeader()
decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
if err != nil {
h.logger.Error("Failed to decrypt response", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
} else {
json.Unmarshal([]byte(decryptedResp), response.Data)
}
} else if respMap, ok := resp.Response.(map[string]interface{}); ok {
// Response is already unmarshaled JSON
if pesertaMap, exists := respMap["peserta"]; exists {
pesertaBytes, _ := json.Marshal(pesertaMap)
json.Unmarshal(pesertaBytes, response.Data)
} else {
// Try to unmarshal the whole response
respBytes, _ := json.Marshal(resp.Response)
json.Unmarshal(respBytes, response.Data)
}
}
}
// Ensure response has proper fields // Ensure response has proper fields
response.Status = "success" response.Status = "success"
response.RequestID = requestID response.RequestID = requestID
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }

View File

@@ -15,33 +15,50 @@ type PesertaRequest struct {
// PesertaData represents peserta information from BPJS // PesertaData represents peserta information from BPJS
type PesertaData struct { type PesertaData struct {
NoKartu string `json:"noKartu"` NoKartu string `json:"noKartu"`
NIK string `json:"nik"` NIK string `json:"nik"`
Nama string `json:"nama"` Nama string `json:"nama"`
Pisa string `json:"pisa"` Pisa string `json:"pisa"`
Sex string `json:"sex"` Sex string `json:"sex"`
TanggalLahir string `json:"tglLahir"` TanggalLahir string `json:"tglLahir"`
TelephoneMsisdn string `json:"tglTAT"` TglCetakKartu string `json:"tglCetakKartu"`
TelephoneAsat string `json:"tglTMT"` TglTAT string `json:"tglTAT"`
KodeCabang string `json:"kdCabang"` TglTMT string `json:"tglTMT"`
NamaCabang string `json:"nmCabang"` StatusPeserta struct {
KodeJenisPeserta string `json:"kdJnsPst"` Kode string `json:"kode"`
NamaJenisPeserta string `json:"nmJnsPst"` Keterangan string `json:"keterangan"`
KelasRawat string `json:"klsRawat"` } `json:"statusPeserta"`
Status string `json:"statusPeserta"` ProvUmum struct {
Aktif string `json:"aktif"` KdProvider string `json:"kdProvider"`
KeteranganAktif string `json:"ketAktif"` NmProvider string `json:"nmProvider"`
NoSKTM string `json:"noSKTM,omitempty"` } `json:"provUmum"`
NoKTP string `json:"noKtp"` JenisPeserta struct {
Asuransi string `json:"asuransi,omitempty"` Kode string `json:"kode"`
CoB string `json:"cob,omitempty"` Keterangan string `json:"keterangan"`
TunggakanIuran string `json:"tglTunggak,omitempty"` } `json:"jenisPeserta"`
MR struct { HakKelas struct {
NoMR string `json:"noMR"` Kode string `json:"kode"`
NamaMR string `json:"nmMR"` Keterangan string `json:"keterangan"`
Sex string `json:"sex"` } `json:"hakKelas"`
TglLahir string `json:"tglLahir"` Umur struct {
TglMeninggal string `json:"tglMeninggal,omitempty"` UmurSekarang string `json:"umurSekarang"`
UmurSaatPelayanan string `json:"umurSaatPelayanan"`
} `json:"umur"`
Informasi struct {
Dinsos interface{} `json:"dinsos"`
ProlanisPRB string `json:"prolanisPRB"`
NoSKTM interface{} `json:"noSKTM"`
ESEP interface{} `json:"eSEP"`
} `json:"informasi"`
Cob struct {
NoAsuransi interface{} `json:"noAsuransi"`
NmAsuransi interface{} `json:"nmAsuransi"`
TglTMT interface{} `json:"tglTMT"`
TglTAT interface{} `json:"tglTAT"`
} `json:"cob"`
MR struct {
NoMR string `json:"noMR"`
NoTelepon string `json:"noTelepon"`
} `json:"mr,omitempty"` } `json:"mr,omitempty"`
} }

View File

@@ -75,7 +75,7 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
Validator: nil, Validator: nil,
}) })
pesertaGroup := v1.Group("/peserta") pesertaGroup := v1.Group("/peserta")
pesertaGroup.GET("/peserta/:nokartu", pesertaHandler.GetPesertaBynokartu) pesertaGroup.GET("/peserta/:nokartu/tglSEP/:tglsep", pesertaHandler.GetPesertaBynokartu)
pesertaGroup.GET("/peserta/nik/:nik", pesertaHandler.GetPesertaBynik) pesertaGroup.GET("/peserta/nik/:nik", pesertaHandler.GetPesertaBynik)
// Sep routes // Sep routes

View File

@@ -2,49 +2,110 @@ package services
import ( import (
helper "api-service/internal/helpers/bpjs" helper "api-service/internal/helpers/bpjs"
"bytes"
"compress/gzip"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"errors" "errors"
"io"
lzstring "github.com/daku10/go-lz-string" "log"
) )
func min(a, b int) int {
if a < b {
return a
}
return b
}
// ResponseVclaim decrypts the encrypted response from VClaim API // ResponseVclaim decrypts the encrypted response from VClaim API
func ResponseVclaim(encrypted string, key string) (string, error) { func ResponseVclaim(encrypted string, key string) (string, error) {
log.Println("ResponseVclaim: Starting decryption process")
log.Printf("ResponseVclaim: Encrypted string: %s", encrypted)
// Pad the base64 string if needed
if len(encrypted)%4 != 0 {
padding := (4 - len(encrypted)%4) % 4
for i := 0; i < padding; i++ {
encrypted += "="
}
log.Printf("ResponseVclaim: Padded encrypted string: %s", encrypted)
}
cipherText, err := base64.StdEncoding.DecodeString(encrypted) cipherText, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil { if err != nil {
log.Printf("ResponseVclaim: Failed to decode base64: %v", err)
return "", err return "", err
} }
log.Printf("ResponseVclaim: Base64 decoded successfully, length: %d", len(cipherText))
hash := sha256.Sum256([]byte(key)) hash := sha256.Sum256([]byte(key))
block, err := aes.NewCipher(hash[:]) block, err := aes.NewCipher(hash[:])
if err != nil { if err != nil {
log.Printf("ResponseVclaim: Failed to create AES cipher: %v", err)
return "", err return "", err
} }
if len(cipherText) < aes.BlockSize { if len(cipherText) < aes.BlockSize {
log.Println("ResponseVclaim: CipherText too short")
return "", errors.New("cipherText too short") return "", errors.New("cipherText too short")
} }
iv := hash[:aes.BlockSize] iv := hash[:aes.BlockSize]
if len(cipherText)%aes.BlockSize != 0 { if len(cipherText)%aes.BlockSize != 0 {
log.Println("ResponseVclaim: CipherText not multiple of block size")
return "", errors.New("cipherText is not a multiple of the block size") return "", errors.New("cipherText is not a multiple of the block size")
} }
mode := cipher.NewCBCDecrypter(block, iv) mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(cipherText, cipherText) mode.CryptBlocks(cipherText, cipherText)
log.Println("ResponseVclaim: AES decryption completed")
// cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize) // cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)
cipherText = helper.RemovePKCS7Padding(cipherText) cipherText = helper.RemovePKCS7Padding(cipherText)
data, err := lzstring.DecompressFromEncodedURIComponent(string(cipherText)) log.Printf("ResponseVclaim: PKCS7 padding removed, length: %d", len(cipherText))
// data, err := helper.DecompressFromEncodedUriComponent(string(cipherText))
var data string
// Try gzip decompression first
reader, err := gzip.NewReader(bytes.NewReader(cipherText))
if err != nil { if err != nil {
return "", err log.Printf("ResponseVclaim: Gzip decompression failed: %v, trying LZ-string decompression", err)
// Try lz-string decompression using helper function
data, err := helper.StringDecrypt(key, string(cipherText))
if err != nil || len(data) == 0 {
log.Printf("ResponseVclaim: Helper StringDecrypt failed or empty: %v, trying without decompression", err)
// Try without decompression
data = string(cipherText)
log.Printf("ResponseVclaim: Using decrypted data without decompression, data length: %d", len(data))
} else {
log.Printf("ResponseVclaim: Helper StringDecrypt successful, data length: %d, data: %s", len(data), data[:min(100, len(data))])
}
} else {
defer reader.Close()
decompressed, err := io.ReadAll(reader)
if err != nil {
log.Printf("ResponseVclaim: Failed to read gzip decompressed data: %v, trying LZ-string decompression", err)
// Try lz-string decompression using helper function
data, err := helper.StringDecrypt(key, string(cipherText))
if err != nil || len(data) == 0 {
log.Printf("ResponseVclaim: Helper StringDecrypt failed or empty: %v, using data without decompression", err)
data = string(cipherText)
log.Printf("ResponseVclaim: Using decrypted data without decompression, data length: %d", len(data))
} else {
log.Printf("ResponseVclaim: Helper StringDecrypt successful, data length: %d", len(data))
}
} else {
data = string(decompressed)
log.Printf("ResponseVclaim: Gzip decompression successful, data length: %d", len(data))
}
} }
log.Printf("ResponseVclaim: Final data length: %d, data: %s", len(data), data[:min(100, len(data))])
log.Println("ResponseVclaim: Decryption process completed successfully")
return data, nil return data, nil
} }

View File

@@ -10,6 +10,7 @@ import (
"time" "time"
"api-service/internal/config" "api-service/internal/config"
"api-service/internal/models/vclaim/peserta"
"github.com/mashingan/smapping" "github.com/mashingan/smapping"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@@ -198,41 +199,53 @@ func (s *Service) processResponse(res *http.Response) (*ResponDTOVclaim, error)
return finalResp, nil return finalResp, nil
} }
// Decrypt response // Try to unmarshal response as JSON first (in case it's not encrypted)
consID, secretKey, _, tstamp, _ := s.config.SetHeader() var tempResp interface{}
respDecrypt, err := ResponseVclaim(respMentah.Response, consID+secretKey+tstamp) if json.Unmarshal([]byte(respMentah.Response), &tempResp) == nil {
if err != nil { log.Debug().Msg("Response is valid JSON, not encrypted")
log.Error(). finalResp.Response = tempResp
Err(err). } else {
Str("meta_code", respMentah.MetaData.Code). log.Debug().Msg("Response is not valid JSON, trying to decrypt")
Msg("Failed to decrypt response") // Decrypt response
return nil, fmt.Errorf("failed to decrypt response: %w", err) consID, secretKey, _, tstamp, _ := s.config.SetHeader()
} respDecrypt, err := ResponseVclaim(respMentah.Response, consID+secretKey+tstamp)
if err != nil {
log.Debug(). log.Error().
Str("encrypted_length", fmt.Sprintf("%d bytes", len(respMentah.Response))).
Str("decrypted_length", fmt.Sprintf("%d bytes", len(respDecrypt))).
Msg("Response decrypted successfully")
// Unmarshal decrypted response
if respDecrypt != "" {
if err := json.Unmarshal([]byte(respDecrypt), &finalResp.Response); err != nil {
// If JSON unmarshal fails, store as string
log.Warn().
Err(err). Err(err).
Msg("Failed to unmarshal decrypted response, storing as string") Str("meta_code", respMentah.MetaData.Code).
finalResp.Response = respDecrypt Msg("Failed to decrypt response")
} else { return nil, fmt.Errorf("failed to decrypt response: %w", err)
log.Debug().Msg("Decrypted response unmarshaled successfully") }
// Use gjson to extract and log some metadata from the response if it's JSON log.Debug().
if jsonBytes, err := json.Marshal(finalResp.Response); err == nil { Str("encrypted_length", fmt.Sprintf("%d bytes", len(respMentah.Response))).
jsonStr := string(jsonBytes) Str("decrypted_length", fmt.Sprintf("%d bytes", len(respDecrypt))).
// Extract some common fields using gjson Msg("Response decrypted successfully")
if metaCode := gjson.Get(jsonStr, "metaData.code"); metaCode.Exists() {
log.Info(). log.Debug().
Str("response_meta_code", metaCode.String()). Str("decrypted_data", respDecrypt).
Msg("Final response metadata") Msg("Decrypted data")
// Unmarshal decrypted response
if respDecrypt != "" {
if err := json.Unmarshal([]byte(respDecrypt), &finalResp.Response); err != nil {
// If JSON unmarshal fails, store as string
log.Warn().
Err(err).
Msg("Failed to unmarshal decrypted response, storing as string")
finalResp.Response = respDecrypt
} else {
log.Debug().Msg("Decrypted response unmarshaled successfully")
// Use gjson to extract and log some metadata from the response if it's JSON
if jsonBytes, err := json.Marshal(finalResp.Response); err == nil {
jsonStr := string(jsonBytes)
// Extract some common fields using gjson
if metaCode := gjson.Get(jsonStr, "metaData.code"); metaCode.Exists() {
log.Info().
Str("response_meta_code", metaCode.String()).
Msg("Final response metadata")
}
} }
} }
} }
@@ -410,6 +423,20 @@ func mapToResult(resp *ResponDTOVclaim, result interface{}) error {
return fmt.Errorf("failed to unmarshal to result: %w", err) return fmt.Errorf("failed to unmarshal to result: %w", err)
} }
// Handle BPJS peserta response structure
if pesertaResp, ok := result.(*peserta.PesertaResponse); ok {
if resp.Response != nil {
if responseMap, ok := resp.Response.(map[string]interface{}); ok {
if pesertaMap, ok := responseMap["peserta"]; ok {
pesertaBytes, _ := json.Marshal(pesertaMap)
var pd peserta.PesertaData
json.Unmarshal(pesertaBytes, &pd)
pesertaResp.Data = &pd
}
}
}
}
return nil return nil
} }