feat: add lab package registration endpoint

This commit is contained in:
2026-08-23 21:32:46 +07:00
parent b497012de3
commit 3e5cae4287
9 changed files with 558 additions and 6 deletions

View File

@@ -19,6 +19,7 @@ type LayananRepository interface {
type LabRegistrationRepository interface {
RegisterLab(ctx context.Context, params repository.LabRegistrationParams) (repository.LabRegistrationOutcome, error)
AddLabServices(ctx context.Context, regID string, params repository.AddLabServicesParams) (repository.LabRegistrationOutcome, error)
AddLabPackage(ctx context.Context, regID string, params repository.AddLabPackageParams) (repository.LabRegistrationOutcome, error)
}
type PatientRepository interface {

View File

@@ -0,0 +1,84 @@
package http
import (
"net/http"
"regexp"
"strings"
"unicode/utf8"
"primaya-api/cpone-middleware/internal/repository"
)
var labIdentifier = regexp.MustCompile(`^[A-Za-z0-9-]+$`)
func (h Handler) AddLabPackage(w http.ResponseWriter, r *http.Request) {
regID := strings.TrimSpace(r.PathValue("regId"))
if regID == "" || utf8.RuneCountInString(regID) > 50 || !labIdentifier.MatchString(regID) {
writeLabResponse(w, http.StatusUnprocessableEntity, false, "validation_error", "Nomor registrasi laboratorium hanya boleh berisi huruf, angka, dan tanda hubung", nil)
return
}
payload, _ := decodeJSONObject(r)
params, message := validateAddLabPackage(payload)
if message != "" {
writeLabResponse(w, http.StatusUnprocessableEntity, false, "validation_error", message, nil)
return
}
outcome, err := h.labRepo.AddLabPackage(r.Context(), strings.ToUpper(regID), params)
if err != nil {
if validationMessage, ok := asValidationError(err); ok {
writeLabResponse(w, http.StatusUnprocessableEntity, false, "validation_error", validationMessage, nil)
return
}
writeLabResponse(w, http.StatusInternalServerError, false, "error", err.Error(), nil)
return
}
writeLabResponse(w, outcome.HTTPStatus, outcome.Success, outcome.Status, outcome.Message, outcome.Data)
}
func validateAddLabPackage(payload map[string]any) (repository.AddLabPackageParams, string) {
packageID, message := requiredString(payload, "paket_id", 50, "Paket ID wajib diisi")
if message != "" {
return repository.AddLabPackageParams{}, message
}
packageID = strings.ToUpper(strings.TrimSpace(packageID))
if !labIdentifier.MatchString(packageID) {
return repository.AddLabPackageParams{}, "Paket ID hanya boleh berisi huruf, angka, dan tanda hubung"
}
cito := false
if value, present := nullableValue(payload, "cito"); present {
var valid bool
cito, valid = parseLaravelBoolean(value)
if !valid {
return repository.AddLabPackageParams{}, "The cito field must be true or false."
}
}
markup := 0.0
if value, present := nullableValue(payload, "markup_cito"); present {
var valid bool
markup, valid = parseNumeric(value)
if !valid {
return repository.AddLabPackageParams{}, "The markup cito must be a number."
}
if markup < 0 || markup > 100 {
return repository.AddLabPackageParams{}, "The markup cito must be between 0 and 100."
}
}
if !cito {
markup = 0
}
notes, _, message := optionalString(payload, "catatan", 500)
if message != "" {
return repository.AddLabPackageParams{}, message
}
channel, present, message := optionalString(payload, "channel", 50)
if message != "" {
return repository.AddLabPackageParams{}, message
}
if !present {
channel = "CPONE"
}
return repository.AddLabPackageParams{
PackageID: packageID, Cito: cito, MarkupCito: markup,
Notes: strings.TrimSpace(notes), Channel: strings.ToUpper(strings.TrimSpace(channel)),
}, ""
}

View File

@@ -0,0 +1,50 @@
package http
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"primaya-api/cpone-middleware/internal/repository"
)
func TestAddLabPackageValidPayload(t *testing.T) {
repo := &fakeLabRegistrationRepository{outcome: repository.LabRegistrationOutcome{
HTTPStatus: 201, Success: true, Status: "package_added",
Message: "Paket dispenser berhasil ditambahkan ke registrasi laboratorium",
}}
handler := Handler{labRepo: repo}
request := httptest.NewRequest(http.MethodPost, "/packages", strings.NewReader(`{"paket_id":"disp-260800011","cito":true,"markup_cito":"10","catatan":" test ","channel":"cpone"}`))
request.SetPathValue("regId", "lab-2608210003")
recorder := httptest.NewRecorder()
handler.AddLabPackage(recorder, request)
if recorder.Code != http.StatusCreated {
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
}
if repo.regID != "LAB-2608210003" || repo.packageParams.PackageID != "DISP-260800011" || !repo.packageParams.Cito || repo.packageParams.MarkupCito != 10 || repo.packageParams.Notes != "test" || repo.packageParams.Channel != "CPONE" {
t.Fatalf("unexpected repository call: reg=%q params=%+v", repo.regID, repo.packageParams)
}
}
func TestAddLabPackageValidation(t *testing.T) {
tests := []struct{ name, regID, body, message string }{
{"invalid registration", "LAB/1", `{"paket_id":"DISP-1"}`, "Nomor registrasi laboratorium hanya boleh berisi huruf, angka, dan tanda hubung"},
{"missing package", "LAB-1", `{}`, "Paket ID wajib diisi"},
{"invalid package", "LAB-1", `{"paket_id":"DISP/1"}`, "Paket ID hanya boleh berisi huruf, angka, dan tanda hubung"},
{"invalid cito", "LAB-1", `{"paket_id":"DISP-1","cito":"true"}`, "The cito field must be true or false."},
{"invalid markup", "LAB-1", `{"paket_id":"DISP-1","markup_cito":101}`, "The markup cito must be between 0 and 100."},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
handler := Handler{labRepo: &fakeLabRegistrationRepository{}}
request := httptest.NewRequest(http.MethodPost, "/packages", strings.NewReader(test.body))
request.SetPathValue("regId", test.regID)
recorder := httptest.NewRecorder()
handler.AddLabPackage(recorder, request)
if recorder.Code != 422 || !strings.Contains(recorder.Body.String(), test.message) {
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
}
})
}
}

View File

@@ -13,11 +13,12 @@ import (
)
type fakeLabRegistrationRepository struct {
outcome repository.LabRegistrationOutcome
err error
params repository.LabRegistrationParams
addParams repository.AddLabServicesParams
regID string
outcome repository.LabRegistrationOutcome
err error
params repository.LabRegistrationParams
addParams repository.AddLabServicesParams
packageParams repository.AddLabPackageParams
regID string
}
func (f *fakeLabRegistrationRepository) RegisterLab(_ context.Context, params repository.LabRegistrationParams) (repository.LabRegistrationOutcome, error) {
@@ -31,6 +32,12 @@ func (f *fakeLabRegistrationRepository) AddLabServices(_ context.Context, regID
return f.outcome, f.err
}
func (f *fakeLabRegistrationRepository) AddLabPackage(_ context.Context, regID string, params repository.AddLabPackageParams) (repository.LabRegistrationOutcome, error) {
f.regID = regID
f.packageParams = params
return f.outcome, f.err
}
func TestRegisterLabValidPayloadAndResponseParity(t *testing.T) {
doctorID := "DR01"
registrationType := int64(3)