Compare commits
2 Commits
1ee0cfb7f2
...
181d53af45
| Author | SHA1 | Date | |
|---|---|---|---|
| 181d53af45 | |||
| 1d5bc309c0 |
15
README.md
15
README.md
@@ -23,6 +23,21 @@ Authorization: Bearer <your-secure-token>
|
||||
GET /api/cpone/tarif-kerjasama/{id}?group_tarif_id=&active=N&effective_date=2026-08-22
|
||||
Authorization: Bearer <your-secure-token>
|
||||
|
||||
GET /api/cpone/periode-tarif
|
||||
Authorization: Bearer <your-secure-token>
|
||||
X-RS-Code: <kode-rs>
|
||||
|
||||
Endpoint ini menampilkan seluruh periode tarif dari HIS dengan `NA = 'N'`.
|
||||
|
||||
GET /api/cpone/periode-tarif/{PeriodeTarifID}?search=&page=1
|
||||
Authorization: Bearer <your-secure-token>
|
||||
X-RS-Code: <kode-rs>
|
||||
|
||||
Endpoint ini mengambil detail seluruh tarif layanan dari tabel dinamis
|
||||
`harga_layanan_{PeriodeTarifID}` beserta layanan, departemen, dan kelas tarif.
|
||||
Parameter `search` mencari berdasarkan `LayananID` atau `NamaLayanan`; hasil
|
||||
dipaginasi 20 data per halaman.
|
||||
|
||||
GET /api/cpone/layanan-mapping-harga?periodeTarifID=10&layananID=6413,6414,1309
|
||||
Authorization: Bearer <your-secure-token>
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ func main() {
|
||||
mux.Handle("GET /api/cpone/perusahaan/{id}/group-tarif", protected(http.HandlerFunc(handler.GetPerusahaanGroupTarif)))
|
||||
mux.Handle("GET /api/cpone/tarif-kerjasama", protected(http.HandlerFunc(handler.ListTarifKerjasama)))
|
||||
mux.Handle("GET /api/cpone/tarif-kerjasama/{id}", protected(http.HandlerFunc(handler.GetTarifKerjasama)))
|
||||
mux.Handle("GET /api/cpone/periode-tarif", protected(http.HandlerFunc(handler.ListPeriodeTarif)))
|
||||
mux.Handle("GET /api/cpone/periode-tarif/{periodeTarifID}", protected(http.HandlerFunc(handler.ListPeriodeTarifLayanan)))
|
||||
mux.Handle("GET /api/cpone/layanan-mapping-harga", protected(http.HandlerFunc(handler.MappingHarga)))
|
||||
mux.Handle("POST /api/cpone/patients/medrec", protected(http.HandlerFunc(handler.StoreMedrec)))
|
||||
mux.Handle("POST /api/cpone/patients/lab-registration", protected(http.HandlerFunc(handler.RegisterLab)))
|
||||
|
||||
@@ -41,6 +41,14 @@ type TarifKerjasamaRepository interface {
|
||||
GetTarifKerjasama(ctx context.Context, id int64, params repository.TarifKerjasamaDetailParams) (*repository.TarifKerjasamaDetail, error)
|
||||
}
|
||||
|
||||
type PeriodeTarifRepository interface {
|
||||
ListPeriodeTarif(ctx context.Context) ([]repository.PeriodeTarif, error)
|
||||
}
|
||||
|
||||
type PeriodeTarifDetailRepository interface {
|
||||
ListPeriodeTarifLayanan(ctx context.Context, params repository.PeriodeTarifLayananListParams) (repository.PeriodeTarifLayananPage, error)
|
||||
}
|
||||
|
||||
type PerusahaanRepository interface {
|
||||
ListPerusahaan(ctx context.Context, params repository.PerusahaanListParams) (repository.PerusahaanPage, error)
|
||||
GetPerusahaan(ctx context.Context, id string) (*repository.PerusahaanDetail, error)
|
||||
@@ -48,13 +56,15 @@ type PerusahaanRepository interface {
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
layananRepo LayananRepository
|
||||
labRepo LabRegistrationRepository
|
||||
patientRepo PatientRepository
|
||||
labResultRepo LabResultRepository
|
||||
paketRepo PaketRepository
|
||||
tarifRepo TarifKerjasamaRepository
|
||||
perusahaanRepo PerusahaanRepository
|
||||
layananRepo LayananRepository
|
||||
labRepo LabRegistrationRepository
|
||||
patientRepo PatientRepository
|
||||
labResultRepo LabResultRepository
|
||||
paketRepo PaketRepository
|
||||
tarifRepo TarifKerjasamaRepository
|
||||
periodeTarifRepo PeriodeTarifRepository
|
||||
periodeTarifDetailRepo PeriodeTarifDetailRepository
|
||||
perusahaanRepo PerusahaanRepository
|
||||
}
|
||||
|
||||
type CPONERepository interface {
|
||||
@@ -64,13 +74,16 @@ type CPONERepository interface {
|
||||
LabResultRepository
|
||||
PaketRepository
|
||||
TarifKerjasamaRepository
|
||||
PeriodeTarifRepository
|
||||
PeriodeTarifDetailRepository
|
||||
PerusahaanRepository
|
||||
}
|
||||
|
||||
func NewHandler(repo CPONERepository) Handler {
|
||||
return Handler{
|
||||
layananRepo: repo, labRepo: repo, patientRepo: repo,
|
||||
labResultRepo: repo, paketRepo: repo, tarifRepo: repo, perusahaanRepo: repo,
|
||||
labResultRepo: repo, paketRepo: repo, tarifRepo: repo,
|
||||
periodeTarifRepo: repo, periodeTarifDetailRepo: repo, perusahaanRepo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +131,20 @@ func (h Handler) tarifRepository(ctx context.Context) TarifKerjasamaRepository {
|
||||
return h.tarifRepo
|
||||
}
|
||||
|
||||
func (h Handler) periodeTarifRepository(ctx context.Context) PeriodeTarifRepository {
|
||||
if repo, ok := selectedRepository(ctx); ok {
|
||||
return repo
|
||||
}
|
||||
return h.periodeTarifRepo
|
||||
}
|
||||
|
||||
func (h Handler) periodeTarifDetailRepository(ctx context.Context) PeriodeTarifDetailRepository {
|
||||
if repo, ok := selectedRepository(ctx); ok {
|
||||
return repo
|
||||
}
|
||||
return h.periodeTarifDetailRepo
|
||||
}
|
||||
|
||||
func (h Handler) perusahaanRepository(ctx context.Context) PerusahaanRepository {
|
||||
if repo, ok := selectedRepository(ctx); ok {
|
||||
return repo
|
||||
|
||||
29
internal/http/periode_tarif.go
Normal file
29
internal/http/periode_tarif.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"primaya-api/cpone-middleware/internal/repository"
|
||||
)
|
||||
|
||||
func (h Handler) ListPeriodeTarif(w http.ResponseWriter, r *http.Request) {
|
||||
items, err := h.periodeTarifRepository(r.Context()).ListPeriodeTarif(r.Context())
|
||||
if err != nil {
|
||||
WriteJSON(w, http.StatusInternalServerError, Response{
|
||||
Success: false,
|
||||
Message: "internal server error",
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if items == nil {
|
||||
items = []repository.PeriodeTarif{}
|
||||
}
|
||||
|
||||
WriteJSON(w, http.StatusOK, Response{
|
||||
Success: true,
|
||||
Message: "ok",
|
||||
Data: items,
|
||||
})
|
||||
}
|
||||
118
internal/http/periode_tarif_detail.go
Normal file
118
internal/http/periode_tarif_detail.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"primaya-api/cpone-middleware/internal/repository"
|
||||
)
|
||||
|
||||
const periodeTarifLayananPerPage = 20
|
||||
|
||||
type PeriodeTarifLayananPaginationResponse struct {
|
||||
CurrentPage int `json:"current_page"`
|
||||
Data []repository.PeriodeTarifLayanan `json:"data"`
|
||||
FirstPageURL string `json:"first_page_url"`
|
||||
From *int `json:"from"`
|
||||
LastPage int `json:"last_page"`
|
||||
LastPageURL string `json:"last_page_url"`
|
||||
Links map[string]any `json:"links"`
|
||||
NextPageURL *string `json:"next_page_url"`
|
||||
Total int `json:"total"`
|
||||
PerPage int `json:"per_page"`
|
||||
}
|
||||
|
||||
func (h Handler) ListPeriodeTarifLayanan(w http.ResponseWriter, r *http.Request) {
|
||||
rawID := strings.TrimSpace(r.PathValue("periodeTarifID"))
|
||||
if rawID == "" {
|
||||
rawID = strings.TrimSpace(r.PathValue("PeriodeTarifID"))
|
||||
}
|
||||
periodeTarifID, err := strconv.ParseInt(rawID, 10, 64)
|
||||
if err != nil || periodeTarifID < 1 {
|
||||
WriteJSON(w, http.StatusUnprocessableEntity, Response{
|
||||
Success: false,
|
||||
Message: "PeriodeTarifID harus berupa angka positif",
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
pageNumber := periodeTarifLayananPageNumber(r)
|
||||
search := strings.TrimSpace(r.URL.Query().Get("search"))
|
||||
page, err := h.periodeTarifDetailRepository(r.Context()).ListPeriodeTarifLayanan(r.Context(), repository.PeriodeTarifLayananListParams{
|
||||
PeriodeTarifID: periodeTarifID,
|
||||
Page: pageNumber,
|
||||
PerPage: periodeTarifLayananPerPage,
|
||||
Search: search,
|
||||
})
|
||||
if errors.Is(err, repository.ErrTarifTableNotFound) {
|
||||
WriteJSON(w, http.StatusNotFound, Response{
|
||||
Success: false,
|
||||
Message: "Tabel tarif tidak ditemukan: harga_layanan_" + strconv.FormatInt(periodeTarifID, 10),
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
WriteJSON(w, http.StatusInternalServerError, Response{
|
||||
Success: false,
|
||||
Message: "internal server error",
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if page.Items == nil {
|
||||
page.Items = []repository.PeriodeTarifLayanan{}
|
||||
}
|
||||
|
||||
lastPage := (page.Total + periodeTarifLayananPerPage - 1) / periodeTarifLayananPerPage
|
||||
if lastPage < 1 {
|
||||
lastPage = 1
|
||||
}
|
||||
var from *int
|
||||
if len(page.Items) > 0 {
|
||||
value := (pageNumber-1)*periodeTarifLayananPerPage + 1
|
||||
from = &value
|
||||
}
|
||||
var nextPageURL *string
|
||||
if pageNumber < lastPage {
|
||||
value := periodeTarifLayananPageURL(r, pageNumber+1)
|
||||
nextPageURL = &value
|
||||
}
|
||||
|
||||
WriteJSON(w, http.StatusOK, PeriodeTarifLayananPaginationResponse{
|
||||
CurrentPage: pageNumber, Data: page.Items, FirstPageURL: "", From: from,
|
||||
LastPage: lastPage, LastPageURL: "", Links: map[string]any{},
|
||||
NextPageURL: nextPageURL, Total: page.Total, PerPage: periodeTarifLayananPerPage,
|
||||
})
|
||||
}
|
||||
|
||||
func periodeTarifLayananPageNumber(r *http.Request) int {
|
||||
page, err := strconv.Atoi(r.URL.Query().Get("page"))
|
||||
if err != nil || page < 1 {
|
||||
return 1
|
||||
}
|
||||
return page
|
||||
}
|
||||
|
||||
func periodeTarifLayananPageURL(r *http.Request, page int) string {
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
if forwarded := r.Header.Get("X-Forwarded-Proto"); forwarded != "" {
|
||||
scheme = strings.TrimSpace(strings.Split(forwarded, ",")[0])
|
||||
}
|
||||
host := r.Host
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
query := r.URL.Query()
|
||||
query.Set("page", strconv.Itoa(page))
|
||||
query.Set("per_page", strconv.Itoa(periodeTarifLayananPerPage))
|
||||
return (&url.URL{Scheme: scheme, Host: host, Path: r.URL.Path, RawQuery: query.Encode()}).String()
|
||||
}
|
||||
113
internal/http/periode_tarif_detail_test.go
Normal file
113
internal/http/periode_tarif_detail_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"primaya-api/cpone-middleware/internal/repository"
|
||||
)
|
||||
|
||||
type fakePeriodeTarifDetailRepository struct {
|
||||
items []repository.PeriodeTarifLayanan
|
||||
err error
|
||||
id int64
|
||||
params repository.PeriodeTarifLayananListParams
|
||||
total int
|
||||
}
|
||||
|
||||
func (f *fakePeriodeTarifDetailRepository) ListPeriodeTarifLayanan(_ context.Context, params repository.PeriodeTarifLayananListParams) (repository.PeriodeTarifLayananPage, error) {
|
||||
f.id = params.PeriodeTarifID
|
||||
f.params = params
|
||||
total := f.total
|
||||
if total == 0 {
|
||||
total = len(f.items)
|
||||
}
|
||||
return repository.PeriodeTarifLayananPage{Items: f.items, Total: total}, f.err
|
||||
}
|
||||
|
||||
func TestListPeriodeTarifLayananReturnsRows(t *testing.T) {
|
||||
layananID, nama, departemen, kelas, namaKelas, harga := "6413", "Darah Lengkap", "LAB", "Default", "Default", "125000.00"
|
||||
repo := &fakePeriodeTarifDetailRepository{items: []repository.PeriodeTarifLayanan{{
|
||||
TarifLayananID: 10, LayananID: &layananID, NamaLayanan: &nama,
|
||||
LayananDepartemenID: 20, Departemen: &departemen, Kelas: kelas, NamaKelas: &namaKelas,
|
||||
Harga: &harga,
|
||||
}}}
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/cpone/periode-tarif/12?search=Darah&page=2", nil)
|
||||
request.SetPathValue("periodeTarifID", "12")
|
||||
|
||||
Handler{periodeTarifDetailRepo: repo}.ListPeriodeTarifLayanan(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK || repo.id != 12 {
|
||||
t.Fatalf("status=%d id=%d body=%s", recorder.Code, repo.id, recorder.Body.String())
|
||||
}
|
||||
for _, expected := range []string{
|
||||
`"LayananID":"6413"`, `"NamaLayanan":"Darah Lengkap"`,
|
||||
`"LayananDepartemenID":20`, `"Departemen":"LAB"`,
|
||||
`"Kelas":"Default"`, `"Harga":"125000.00"`,
|
||||
} {
|
||||
if !strings.Contains(recorder.Body.String(), expected) {
|
||||
t.Fatalf("response missing %s: %s", expected, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPeriodeTarifLayananUsesSearchAndPagination(t *testing.T) {
|
||||
repo := &fakePeriodeTarifDetailRepository{total: 41}
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "http://localhost/api/cpone/periode-tarif/12?search=Admin&page=1", nil)
|
||||
request.SetPathValue("periodeTarifID", "12")
|
||||
|
||||
Handler{periodeTarifDetailRepo: repo}.ListPeriodeTarifLayanan(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if repo.params.Page != 1 || repo.params.PerPage != periodeTarifLayananPerPage || repo.params.Search != "Admin" {
|
||||
t.Fatalf("params=%+v", repo.params)
|
||||
}
|
||||
for _, expected := range []string{
|
||||
`"current_page":1`, `"last_page":3`, `"per_page":20`, `"total":41`,
|
||||
`"next_page_url":"http://localhost/api/cpone/periode-tarif/12?page=2\u0026per_page=20\u0026search=Admin"`,
|
||||
} {
|
||||
if !strings.Contains(recorder.Body.String(), expected) {
|
||||
t.Fatalf("response missing %s: %s", expected, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPeriodeTarifLayananValidationAndMissingTable(t *testing.T) {
|
||||
for _, rawID := range []string{"", "abc", "0", "1.5"} {
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/cpone/periode-tarif/"+rawID, nil)
|
||||
request.SetPathValue("periodeTarifID", rawID)
|
||||
Handler{periodeTarifDetailRepo: &fakePeriodeTarifDetailRepository{}}.ListPeriodeTarifLayanan(recorder, request)
|
||||
if recorder.Code != http.StatusUnprocessableEntity {
|
||||
t.Fatalf("id=%q status=%d body=%s", rawID, recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/cpone/periode-tarif/12", nil)
|
||||
request.SetPathValue("periodeTarifID", "12")
|
||||
Handler{periodeTarifDetailRepo: &fakePeriodeTarifDetailRepository{err: repository.ErrTarifTableNotFound}}.
|
||||
ListPeriodeTarifLayanan(recorder, request)
|
||||
if recorder.Code != http.StatusNotFound || !strings.Contains(recorder.Body.String(), "harga_layanan_12") {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPeriodeTarifLayananInternalError(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/cpone/periode-tarif/12", nil)
|
||||
request.SetPathValue("periodeTarifID", "12")
|
||||
Handler{periodeTarifDetailRepo: &fakePeriodeTarifDetailRepository{err: errors.New("query failed")}}.
|
||||
ListPeriodeTarifLayanan(recorder, request)
|
||||
if recorder.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
72
internal/http/periode_tarif_test.go
Normal file
72
internal/http/periode_tarif_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"primaya-api/cpone-middleware/internal/repository"
|
||||
)
|
||||
|
||||
type fakePeriodeTarifRepository struct {
|
||||
items []repository.PeriodeTarif
|
||||
err error
|
||||
}
|
||||
|
||||
func (f *fakePeriodeTarifRepository) ListPeriodeTarif(_ context.Context) ([]repository.PeriodeTarif, error) {
|
||||
return f.items, f.err
|
||||
}
|
||||
|
||||
func (f *fakePeriodeTarifRepository) ListPeriodeTarifLayanan(_ context.Context, _ repository.PeriodeTarifLayananListParams) (repository.PeriodeTarifLayananPage, error) {
|
||||
return repository.PeriodeTarifLayananPage{}, f.err
|
||||
}
|
||||
|
||||
func TestListPeriodeTarifReturnsAvailablePeriods(t *testing.T) {
|
||||
keterangan := "Tarif Dasar 2026"
|
||||
repo := &fakePeriodeTarifRepository{items: []repository.PeriodeTarif{{
|
||||
PeriodeTarifID: 42, Keterangan: &keterangan,
|
||||
TanggalBerlaku: "2026-01-01", TanggalBerakhir: "2026-12-31",
|
||||
}}}
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/cpone/periode-tarif", nil)
|
||||
Handler{periodeTarifRepo: repo}.ListPeriodeTarif(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
for _, expected := range []string{
|
||||
`"success":true`, `"message":"ok"`, `"PeriodeTarifID":42`,
|
||||
`"Keterangan":"Tarif Dasar 2026"`, `"TanggalBerlaku":"2026-01-01"`,
|
||||
`"TanggalBerakhir":"2026-12-31"`,
|
||||
} {
|
||||
if !strings.Contains(recorder.Body.String(), expected) {
|
||||
t.Fatalf("response missing %s: %s", expected, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPeriodeTarifReturnsEmptyArray(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/cpone/periode-tarif", nil)
|
||||
Handler{periodeTarifRepo: &fakePeriodeTarifRepository{items: []repository.PeriodeTarif{}}}.
|
||||
ListPeriodeTarif(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), `"data":[]`) {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPeriodeTarifInternalError(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/cpone/periode-tarif", nil)
|
||||
Handler{periodeTarifRepo: &fakePeriodeTarifRepository{err: errors.New("query failed")}}.
|
||||
ListPeriodeTarif(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
@@ -146,8 +146,7 @@ func (r MySQLLayananRepository) ListPaket(ctx context.Context, params PaketListP
|
||||
|
||||
query := `
|
||||
SELECT ph.PaketID,
|
||||
(SELECT pch.KodeCorp FROM paket_corp_header pch
|
||||
WHERE pch.PaketID = ph.PaketID ORDER BY pch.TanggalBuat DESC LIMIT 1),
|
||||
NULL AS KodeCorp,
|
||||
ph.Nama, ph.JenisPaket, jp.Nama, ph.TotalHarga, ph.RI, ph.RJ,
|
||||
ph.MultiVisit, CAST(ph.TglDari AS CHAR), CAST(ph.TglSampai AS CHAR),
|
||||
ph.KelasID, ph.JumlahHari, ph.StatusID, ph.NA, ph.Keterangan
|
||||
|
||||
176
internal/repository/periode_tarif.go
Normal file
176
internal/repository/periode_tarif.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type PeriodeTarif struct {
|
||||
PeriodeTarifID int64 `json:"PeriodeTarifID"`
|
||||
Keterangan *string `json:"Keterangan"`
|
||||
TanggalBerlaku string `json:"TanggalBerlaku"`
|
||||
TanggalBerakhir string `json:"TanggalBerakhir"`
|
||||
}
|
||||
|
||||
func (r MySQLLayananRepository) ListPeriodeTarif(ctx context.Context) ([]PeriodeTarif, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT PeriodeTarifID, Keterangan,
|
||||
CAST(TanggalBerlaku AS CHAR), CAST(TanggalBerakhir AS CHAR)
|
||||
FROM periode_tarif
|
||||
WHERE NA = 'N'
|
||||
ORDER BY Keterangan ASC, PeriodeTarifID ASC
|
||||
`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
result := make([]PeriodeTarif, 0)
|
||||
for rows.Next() {
|
||||
var item PeriodeTarif
|
||||
var keterangan sql.NullString
|
||||
if err := rows.Scan(&item.PeriodeTarifID, &keterangan,
|
||||
&item.TanggalBerlaku, &item.TanggalBerakhir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item.Keterangan = nullStringPtr(keterangan)
|
||||
result = append(result, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type PeriodeTarifLayanan struct {
|
||||
TarifLayananID int64 `json:"TarifLayananID"`
|
||||
LayananID *string `json:"LayananID"`
|
||||
NamaLayanan *string `json:"NamaLayanan"`
|
||||
LayananDepartemenID int64 `json:"LayananDepartemenID"`
|
||||
Departemen *string `json:"Departemen"`
|
||||
Kelas string `json:"Kelas"`
|
||||
NamaKelas *string `json:"NamaKelas"`
|
||||
Harga *string `json:"Harga"`
|
||||
TipeShare *string `json:"TipeShare"`
|
||||
ShareDokter *string `json:"ShareDokter"`
|
||||
ShareRS *string `json:"ShareRS"`
|
||||
ShareExternal *string `json:"ShareExternal"`
|
||||
ShareLain *string `json:"ShareLain"`
|
||||
}
|
||||
|
||||
type PeriodeTarifLayananListParams struct {
|
||||
PeriodeTarifID int64
|
||||
Page int
|
||||
PerPage int
|
||||
Search string
|
||||
}
|
||||
|
||||
type PeriodeTarifLayananPage struct {
|
||||
Items []PeriodeTarifLayanan
|
||||
Total int
|
||||
}
|
||||
|
||||
func (r MySQLLayananRepository) ListPeriodeTarifLayanan(ctx context.Context, params PeriodeTarifLayananListParams) (PeriodeTarifLayananPage, error) {
|
||||
tableName := "harga_layanan_" + strconv.FormatInt(params.PeriodeTarifID, 10)
|
||||
exists, err := r.tableExists(ctx, tableName)
|
||||
if err != nil {
|
||||
return PeriodeTarifLayananPage{}, err
|
||||
}
|
||||
if !exists {
|
||||
return PeriodeTarifLayananPage{}, ErrTarifTableNotFound
|
||||
}
|
||||
|
||||
where := `
|
||||
WHERE tarif.NA = 'N'
|
||||
AND layanan_dept.NA = 'N'`
|
||||
args := make([]any, 0, 4)
|
||||
if params.Search != "" {
|
||||
where += `
|
||||
AND (layanan_dept.LayananID LIKE ? OR layanan.Nama LIKE ?)`
|
||||
like := "%" + params.Search + "%"
|
||||
args = append(args, like, like)
|
||||
}
|
||||
|
||||
countQuery := fmt.Sprintf(`
|
||||
SELECT COUNT(*)
|
||||
FROM %s AS tarif
|
||||
INNER JOIN layanandepartemen AS layanan_dept
|
||||
ON layanan_dept.LayananDepartemenID = tarif.LayananDepartemenID
|
||||
LEFT JOIN masterlayanan AS layanan
|
||||
ON layanan.LayananID = layanan_dept.LayananID
|
||||
%s
|
||||
`, tableName, where)
|
||||
var total int
|
||||
if err := r.db.QueryRowContext(ctx, countQuery, args...).Scan(&total); err != nil {
|
||||
return PeriodeTarifLayananPage{}, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
tarif.HargaLayananID,
|
||||
layanan_dept.LayananID,
|
||||
layanan.Nama,
|
||||
tarif.LayananDepartemenID,
|
||||
departemen.Nama,
|
||||
tarif.KelasID,
|
||||
kelas.Nama,
|
||||
CAST(tarif.Harga AS CHAR),
|
||||
tarif.ShareTipe,
|
||||
CAST(tarif.ShareDokter AS CHAR),
|
||||
CAST(tarif.ShareRS AS CHAR),
|
||||
CAST(tarif.ShareExternal AS CHAR),
|
||||
CAST(tarif.ShareLain AS CHAR)
|
||||
FROM %s AS tarif
|
||||
INNER JOIN layanandepartemen AS layanan_dept
|
||||
ON layanan_dept.LayananDepartemenID = tarif.LayananDepartemenID
|
||||
LEFT JOIN masterlayanan AS layanan
|
||||
ON layanan.LayananID = layanan_dept.LayananID
|
||||
LEFT JOIN departemen AS departemen
|
||||
ON departemen.DepartemenID = layanan_dept.DepartemenID
|
||||
LEFT JOIN kelas AS kelas
|
||||
ON kelas.KelasID = tarif.KelasID
|
||||
%s
|
||||
ORDER BY layanan.Nama, layanan_dept.LayananID, tarif.KelasID, tarif.HargaLayananID
|
||||
LIMIT ? OFFSET ?
|
||||
`, tableName, where)
|
||||
args = append(args, params.PerPage, (params.Page-1)*params.PerPage)
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return PeriodeTarifLayananPage{}, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
result := make([]PeriodeTarifLayanan, 0)
|
||||
for rows.Next() {
|
||||
var item PeriodeTarifLayanan
|
||||
var layananID, namaLayanan, departemen, namaKelas, harga sql.NullString
|
||||
var tipeShare, shareDokter, shareRS, shareExternal, shareLain sql.NullString
|
||||
if err := rows.Scan(
|
||||
&item.TarifLayananID, &layananID, &namaLayanan,
|
||||
&item.LayananDepartemenID, &departemen, &item.Kelas, &namaKelas,
|
||||
&harga, &tipeShare, &shareDokter, &shareRS, &shareExternal, &shareLain,
|
||||
); err != nil {
|
||||
return PeriodeTarifLayananPage{}, err
|
||||
}
|
||||
item.LayananID = nullStringPtr(layananID)
|
||||
item.NamaLayanan = nullStringPtr(namaLayanan)
|
||||
item.Departemen = nullStringPtr(departemen)
|
||||
item.NamaKelas = nullStringPtr(namaKelas)
|
||||
item.Harga = nullStringPtr(harga)
|
||||
item.TipeShare = nullStringPtr(tipeShare)
|
||||
item.ShareDokter = nullStringPtr(shareDokter)
|
||||
item.ShareRS = nullStringPtr(shareRS)
|
||||
item.ShareExternal = nullStringPtr(shareExternal)
|
||||
item.ShareLain = nullStringPtr(shareLain)
|
||||
result = append(result, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return PeriodeTarifLayananPage{}, err
|
||||
}
|
||||
|
||||
return PeriodeTarifLayananPage{Items: result, Total: total}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user