feat(cpone): migrate medrec endpoint
This commit is contained in:
230
internal/http/medrec.go
Normal file
230
internal/http/medrec.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"primaya-api/cpone-middleware/internal/repository"
|
||||
)
|
||||
|
||||
var (
|
||||
spaces = regexp.MustCompile(`\s+`)
|
||||
nonAlphaNumber = regexp.MustCompile(`[^A-Za-z0-9]`)
|
||||
nonDigit = regexp.MustCompile(`\D`)
|
||||
ktpNumber = regexp.MustCompile(`^\d{16}$`)
|
||||
emailAddress = regexp.MustCompile(`^[^\s@]+@[^\s@]+\.[^\s@]+$`)
|
||||
)
|
||||
|
||||
type MedrecResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data"`
|
||||
}
|
||||
|
||||
func (h Handler) StoreMedrec(w http.ResponseWriter, r *http.Request) {
|
||||
payload, _ := decodeJSONObject(r)
|
||||
params, message := validateMedrec(payload)
|
||||
if message != "" {
|
||||
writeMedrecResponse(w, http.StatusUnprocessableEntity, false, "validation_error", message, nil)
|
||||
return
|
||||
}
|
||||
|
||||
outcome, err := h.patientRepo.StoreMedrec(r.Context(), params)
|
||||
if err != nil {
|
||||
var validationErr repository.ValidationError
|
||||
if errors.As(err, &validationErr) {
|
||||
writeMedrecResponse(w, http.StatusUnprocessableEntity, false, "validation_error", validationErr.Message, nil)
|
||||
return
|
||||
}
|
||||
writeMedrecResponse(w, http.StatusInternalServerError, false, "error", err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
writeMedrecResponse(w, outcome.HTTPStatus, outcome.Success, outcome.Status, outcome.Message, outcome.Data)
|
||||
}
|
||||
|
||||
func validateMedrec(payload map[string]any) (repository.MedrecParams, string) {
|
||||
rs, message := requiredString(payload, "rs", 20, "Kode RS wajib diisi")
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
name, message := requiredString(payload, "nama", 255, "Nama pasien wajib diisi")
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
gender, message := requiredString(payload, "jenis_kelamin", 0, "Jenis kelamin wajib diisi")
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
if gender != "L" && gender != "P" && gender != "l" && gender != "p" {
|
||||
return repository.MedrecParams{}, "Jenis kelamin harus L atau P"
|
||||
}
|
||||
|
||||
dateOfBirth, message := requiredString(payload, "tgl_lahir", 0, "Tanggal lahir wajib diisi")
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
jakarta, err := time.LoadLocation("Asia/Jakarta")
|
||||
if err != nil {
|
||||
return repository.MedrecParams{}, err.Error()
|
||||
}
|
||||
birthDate, err := time.ParseInLocation("2006-01-02", dateOfBirth, jakarta)
|
||||
if err != nil || birthDate.Format("2006-01-02") != dateOfBirth {
|
||||
return repository.MedrecParams{}, "Tanggal lahir harus format Y-m-d"
|
||||
}
|
||||
now := time.Now().In(jakarta)
|
||||
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, jakarta)
|
||||
if birthDate.After(today) {
|
||||
return repository.MedrecParams{}, "Tanggal lahir tidak boleh lebih dari hari ini"
|
||||
}
|
||||
|
||||
identityType, present, message := optionalString(payload, "jenis_nomer_sosial", 20)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
if !present || identityType == "" {
|
||||
identityType = "KTP"
|
||||
}
|
||||
identityNumber, identityPresent, message := optionalString(payload, "nomer_sosial", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
nik, nikPresent, message := optionalString(payload, "nik", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
if !identityPresent || identityNumber == "" {
|
||||
if nikPresent {
|
||||
identityNumber = nik
|
||||
}
|
||||
}
|
||||
|
||||
phone, phonePresent, message := optionalString(payload, "telepon", 30)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
mobile, mobilePresent, message := optionalString(payload, "ponsel", 30)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
if !phonePresent && !mobilePresent {
|
||||
return repository.MedrecParams{}, "Telepon atau ponsel wajib diisi"
|
||||
}
|
||||
|
||||
email, _, message := optionalString(payload, "email", 255)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
if email != "" && !emailAddress.MatchString(strings.TrimSpace(email)) {
|
||||
return repository.MedrecParams{}, "The email must be a valid email address."
|
||||
}
|
||||
|
||||
placeOfBirth, message := optionalMedrecString(payload, "tempat_lahir", 100)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
address, message := optionalMedrecString(payload, "alamat", 500)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
province, message := optionalMedrecString(payload, "propinsi", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
city, message := optionalMedrecString(payload, "kabupaten", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
district, message := optionalMedrecString(payload, "kecamatan", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
village, message := optionalMedrecString(payload, "kelurahan", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
postalCode, message := optionalMedrecString(payload, "kode_pos", 20)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
companyID, message := optionalMedrecString(payload, "perusahaan_id", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
channel, channelPresent, message := optionalString(payload, "channel", 50)
|
||||
if message != "" {
|
||||
return repository.MedrecParams{}, message
|
||||
}
|
||||
if !channelPresent || channel == "" {
|
||||
channel = "CPONE"
|
||||
}
|
||||
|
||||
identityType = normalizeText(identityType)
|
||||
identityNumber = normalizeIdentity(identityNumber)
|
||||
if identityNumber == "" {
|
||||
return repository.MedrecParams{}, "NIK/nomer_sosial wajib diisi"
|
||||
}
|
||||
if identityType == "KTP" && !ktpNumber.MatchString(identityNumber) {
|
||||
return repository.MedrecParams{}, "NIK/KTP harus 16 digit angka"
|
||||
}
|
||||
|
||||
phone = normalizePhone(phone)
|
||||
mobile = normalizePhone(mobile)
|
||||
if phone == "" && mobile == "" {
|
||||
return repository.MedrecParams{}, "Telepon atau ponsel wajib diisi"
|
||||
}
|
||||
|
||||
return repository.MedrecParams{
|
||||
HospitalCode: normalizeText(rs),
|
||||
Name: normalizeName(name),
|
||||
Gender: normalizeText(gender),
|
||||
DateOfBirth: birthDate,
|
||||
IdentityType: identityType,
|
||||
IdentityNumber: identityNumber,
|
||||
Phone: phone,
|
||||
Mobile: mobile,
|
||||
Email: strings.ToLower(strings.TrimSpace(email)),
|
||||
PlaceOfBirth: normalizeName(placeOfBirth),
|
||||
Address: strings.TrimSpace(address),
|
||||
Province: strings.TrimSpace(province),
|
||||
City: strings.TrimSpace(city),
|
||||
District: strings.TrimSpace(district),
|
||||
Village: strings.TrimSpace(village),
|
||||
PostalCode: strings.TrimSpace(postalCode),
|
||||
CompanyID: strings.TrimSpace(companyID),
|
||||
Channel: normalizeText(channel),
|
||||
}, ""
|
||||
}
|
||||
|
||||
func optionalMedrecString(payload map[string]any, key string, maxLength int) (string, string) {
|
||||
value, _, message := optionalString(payload, key, maxLength)
|
||||
return value, message
|
||||
}
|
||||
|
||||
func normalizeName(value string) string {
|
||||
return strings.ToUpper(strings.TrimSpace(spaces.ReplaceAllString(value, " ")))
|
||||
}
|
||||
|
||||
func normalizeText(value string) string {
|
||||
return strings.ToUpper(strings.TrimSpace(value))
|
||||
}
|
||||
|
||||
func normalizeIdentity(value string) string {
|
||||
return strings.ToUpper(nonAlphaNumber.ReplaceAllString(value, ""))
|
||||
}
|
||||
|
||||
func normalizePhone(value string) string {
|
||||
phone := nonDigit.ReplaceAllString(value, "")
|
||||
if strings.HasPrefix(phone, "62") {
|
||||
return "0" + strings.TrimPrefix(phone, "62")
|
||||
}
|
||||
return phone
|
||||
}
|
||||
|
||||
func writeMedrecResponse(w http.ResponseWriter, statusCode int, success bool, status, message string, data any) {
|
||||
WriteJSON(w, statusCode, MedrecResponse{Success: success, Status: status, Message: message, Data: data})
|
||||
}
|
||||
Reference in New Issue
Block a user