feat: require hospital code and add company APIs

This commit is contained in:
2026-08-28 10:30:08 +07:00
parent a59b2c6443
commit 8dd880003d
17 changed files with 867 additions and 142 deletions

View File

@@ -0,0 +1,71 @@
package repository
import (
"context"
"database/sql"
)
type LayananListParams struct {
Page int
PerPage int
}
type LayananPage struct {
Items []LayananDepartemen
Total int
}
type LayananDepartemen struct {
GroupLayananID *string `json:"GroupLayananID"`
Departemen *string `json:"Departemen"`
LayananDepartemenID int64 `json:"LayananDepartemenID"`
LayananID *string `json:"LayananID"`
NamaLayanan *string `json:"NamaLayanan"`
Harga *string `json:"Harga"`
}
func (r MySQLLayananRepository) ListLayanan(ctx context.Context, params LayananListParams) (LayananPage, error) {
var total int
if err := r.db.QueryRowContext(ctx, `
SELECT COUNT(*)
FROM layanandepartemen
WHERE NA = 'N' AND DepartemenID = 'MCU'
`).Scan(&total); err != nil {
return LayananPage{}, err
}
rows, err := r.db.QueryContext(ctx, `
SELECT ld.GroupLayananID, d.Nama, ld.LayananDepartemenID,
ld.LayananID, ml.Nama, CAST(ld.Harga AS CHAR)
FROM layanandepartemen ld
LEFT JOIN departemen d ON d.DepartemenID = ld.DepartemenID
LEFT JOIN masterlayanan ml ON ml.LayananID = ld.LayananID
WHERE ld.NA = 'N' AND ld.DepartemenID = 'MCU'
ORDER BY ld.TanggalBuat DESC
LIMIT ? OFFSET ?
`, params.PerPage, (params.Page-1)*params.PerPage)
if err != nil {
return LayananPage{}, err
}
defer rows.Close()
items := make([]LayananDepartemen, 0)
for rows.Next() {
var item LayananDepartemen
var groupLayananID, departemen, layananID, namaLayanan, harga sql.NullString
if err := rows.Scan(&groupLayananID, &departemen, &item.LayananDepartemenID,
&layananID, &namaLayanan, &harga); err != nil {
return LayananPage{}, err
}
item.GroupLayananID = nullStringPtr(groupLayananID)
item.Departemen = nullStringPtr(departemen)
item.LayananID = nullStringPtr(layananID)
item.NamaLayanan = nullStringPtr(namaLayanan)
item.Harga = nullStringPtr(harga)
items = append(items, item)
}
if err := rows.Err(); err != nil {
return LayananPage{}, err
}
return LayananPage{Items: items, Total: total}, nil
}

View File

@@ -0,0 +1,290 @@
package repository
import (
"context"
"database/sql"
"fmt"
)
type PerusahaanListParams struct {
Search string
Page int
PerPage int
}
type PerusahaanPage struct {
Items []PerusahaanSummary
Total int
}
type PerusahaanSummary struct {
PerusahaanID string `json:"PerusahaanID"`
KodePerusahaan string `json:"KodePerusahaan"`
Nama string `json:"Nama"`
}
type PerusahaanDetail struct {
PerusahaanID string `json:"PerusahaanID"`
KodePerusahaan string `json:"KodePerusahaan"`
Nama string `json:"Nama"`
JenisPerusahaanID int64 `json:"JenisPerusahaanID"`
Penjamin string `json:"Penjamin"`
Asuransi string `json:"Asuransi"`
Provider string `json:"Provider"`
COB string `json:"COB"`
MataUangID string `json:"MataUangID"`
Penanggungjawab *string `json:"Penanggungjawab"`
TeleponPenanggungjawab *string `json:"TeleponPenanggungjawab"`
EmailPenanggungjawab *string `json:"EmailPenanggungjawab"`
Alamat *string `json:"Alamat"`
Kota *string `json:"Kota"`
KodePos *string `json:"KodePos"`
Propinsi *string `json:"Propinsi"`
Negara *string `json:"Negara"`
Telepon *string `json:"Telepon"`
Fax *string `json:"Fax"`
Email *string `json:"Email"`
Website *string `json:"Website"`
NamaBank *string `json:"NamaBank"`
NamaRekening *string `json:"NamaRekening"`
NomerRekening *string `json:"nomerRekening"`
DefaultLamaPembayaran int64 `json:"DefaultLamaPembayaran"`
DefaultDiskon string `json:"DefaultDiskon"`
PPN string `json:"ppn"`
Catatan *string `json:"Catatan"`
NPWP *string `json:"NPWP"`
FlagDiskon string `json:"FlagDiskon"`
VerifikasiBilling string `json:"VerifikasiBilling"`
PICMarketing *string `json:"PIC_Marketing"`
NA string `json:"NA"`
}
type PerusahaanGroupTarifDetail struct {
PerusahaanID string `json:"PerusahaanID"`
KodePerusahaan string `json:"KodePerusahaan"`
NamaPerusahaan string `json:"NamaPerusahaan"`
GroupTarif []PerusahaanGroupTarif `json:"GroupTarif"`
}
type PerusahaanGroupTarif struct {
GroupTarifID int64 `json:"GroupTarifID"`
NamaGroupTarif string `json:"NamaGroupTarif"`
TanggalBerlaku string `json:"TanggalBerlaku"`
TanggalBerakhir string `json:"TanggalBerakhir"`
PeriodeTarifID int64 `json:"PeriodeTarifID"`
Keterangan string `json:"Keterangan"`
DetailLayanan []PerusahaanGroupTarifLayanan `json:"DetailLayanan"`
}
type PerusahaanGroupTarifLayanan struct {
TarifLayananID int64 `json:"TarifLayananID"`
LayananID string `json:"LayananID"`
NamaLayanan *string `json:"NamaLayanan"`
JenisLayananID int64 `json:"JenisLayananID"`
NamaJenisLayanan *string `json:"NamaJenisLayanan"`
Kelas string `json:"Kelas"`
NamaKelas string `json:"NamaKelas"`
Harga string `json:"Harga"`
TipeDiskonRJ string `json:"TipeDiskonRJ"`
DiskonRJ string `json:"DiskonRJ"`
TipeDiskonRI string `json:"TipeDiskonRI"`
DiskonRI string `json:"DiskonRI"`
TipeShare string `json:"TipeShare"`
ShareDokter string `json:"ShareDokter"`
ShareRS string `json:"ShareRS"`
ShareExt string `json:"ShareExt"`
ShareLain string `json:"ShareLain"`
AsalTarif string `json:"AsalTarif"`
}
func (r MySQLLayananRepository) ListPerusahaan(ctx context.Context, params PerusahaanListParams) (PerusahaanPage, error) {
where := "WHERE NA = 'N'"
args := make([]any, 0, 5)
if params.Search != "" {
where += " AND (Nama LIKE ? OR KodePerusahaan LIKE ? OR PerusahaanID LIKE ?)"
like := "%" + params.Search + "%"
args = append(args, like, like, like)
}
var total int
if err := r.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM perusahaan "+where, args...).Scan(&total); err != nil {
return PerusahaanPage{}, err
}
queryArgs := append(append([]any{}, args...), params.PerPage, (params.Page-1)*params.PerPage)
rows, err := r.db.QueryContext(ctx, `SELECT PerusahaanID, KodePerusahaan, Nama
FROM perusahaan `+where+` ORDER BY Nama LIMIT ? OFFSET ?`, queryArgs...)
if err != nil {
return PerusahaanPage{}, err
}
defer rows.Close()
items := make([]PerusahaanSummary, 0)
for rows.Next() {
var item PerusahaanSummary
if err := rows.Scan(&item.PerusahaanID, &item.KodePerusahaan, &item.Nama); err != nil {
return PerusahaanPage{}, err
}
items = append(items, item)
}
if err := rows.Err(); err != nil {
return PerusahaanPage{}, err
}
return PerusahaanPage{Items: items, Total: total}, nil
}
func (r MySQLLayananRepository) GetPerusahaan(ctx context.Context, id string) (*PerusahaanDetail, error) {
row := r.db.QueryRowContext(ctx, `SELECT PerusahaanID, KodePerusahaan, Nama, JenisPerusahaanID,
Penjamin, Asuransi, Provider, COB, MataUangID, Penanggungjawab, TeleponPenanggungjawab,
EmailPenanggungjawab, Alamat, Kota, KodePos, Propinsi, Negara, Telepon, Fax, Email,
Website, NamaBank, NamaRekening, NomerRekening, DefaultLamaPembayaran,
CAST(DefaultDiskon AS CHAR), CAST(ppn AS CHAR), Catatan, NPWP, FlagDiskon,
VerifikasiBilling, PIC_Marketing, NA
FROM perusahaan WHERE NA = 'N' AND (PerusahaanID = ? OR KodePerusahaan = ?) LIMIT 1`, id, id)
detail, err := scanPerusahaanDetail(row)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
return &detail, nil
}
func (r MySQLLayananRepository) GetPerusahaanGroupTarif(ctx context.Context, id, groupTarifID string) (*PerusahaanGroupTarifDetail, error) {
var result PerusahaanGroupTarifDetail
err := r.db.QueryRowContext(ctx, `SELECT PerusahaanID, KodePerusahaan, Nama FROM perusahaan
WHERE NA = 'N' AND (PerusahaanID = ? OR KodePerusahaan = ?) LIMIT 1`, id, id).
Scan(&result.PerusahaanID, &result.KodePerusahaan, &result.NamaPerusahaan)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
query := `SELECT pg.GroupTarifID, CAST(pg.TanggalBerlaku AS CHAR), CAST(pg.TanggalBerakhir AS CHAR),
pg.PeriodeTarifID, pg.Keterangan
FROM perusahaan_grouptarif pg
INNER JOIN perusahaan_tarif pt ON pt.Perusahaan_TarifID = pg.Perusahaan_TarifID
WHERE pt.PerusahaanID = ? AND pg.NA = 'N'
AND CURDATE() BETWEEN pg.TanggalBerlaku AND pg.TanggalBerakhir`
args := []any{result.PerusahaanID}
if groupTarifID != "" {
query += " AND pg.GroupTarifID = ?"
args = append(args, groupTarifID)
}
query += " ORDER BY pg.TanggalBerlaku DESC, pg.GroupTarifID DESC"
rows, err := r.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
result.GroupTarif = make([]PerusahaanGroupTarif, 0)
for rows.Next() {
var group PerusahaanGroupTarif
if err := rows.Scan(&group.GroupTarifID, &group.TanggalBerlaku, &group.TanggalBerakhir,
&group.PeriodeTarifID, &group.Keterangan); err != nil {
return nil, err
}
if group.Keterangan != "" {
group.NamaGroupTarif = group.Keterangan
} else {
group.NamaGroupTarif = fmt.Sprintf("Group Tarif %d", group.GroupTarifID)
}
group.DetailLayanan, err = r.perusahaanGroupTarifLayanan(ctx, group.GroupTarifID)
if err != nil {
return nil, err
}
result.GroupTarif = append(result.GroupTarif, group)
}
if err := rows.Err(); err != nil {
return nil, err
}
return &result, nil
}
func (r MySQLLayananRepository) perusahaanGroupTarifLayanan(ctx context.Context, groupTarifID int64) ([]PerusahaanGroupTarifLayanan, error) {
tableName := fmt.Sprintf("perusahaan_tarif_layanan_%d", groupTarifID)
exists, err := r.tableExists(ctx, tableName)
if err != nil {
return nil, err
}
if !exists {
return []PerusahaanGroupTarifLayanan{}, nil
}
query := fmt.Sprintf(`SELECT tarif.TarifLayananID, tarif.LayananID, layanan.Nama,
tarif.JenisLayananID, jenis.Nama, tarif.KelasID, kelas.Nama,
CAST(tarif.Harga AS CHAR), tarif.TipeDiskon, CAST(tarif.Diskon AS CHAR),
tarif.TipeDiskonRI, CAST(tarif.DiskonRI AS CHAR), tarif.TipeShare,
CAST(tarif.ShareDokter AS CHAR), CAST(tarif.ShareRS AS CHAR),
CAST(tarif.ShareExternal AS CHAR), CAST(tarif.ShareLain AS CHAR), tarif.AsalTarif
FROM %s tarif
LEFT JOIN masterlayanan layanan ON layanan.LayananID = tarif.LayananID
LEFT JOIN jenislayanan jenis ON jenis.JenisLayananID = tarif.JenisLayananID
LEFT JOIN kelas kelas ON kelas.KelasID = tarif.KelasID
WHERE tarif.NA = 'N'
ORDER BY layanan.Nama, tarif.KelasID`, tableName)
rows, err := r.db.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer rows.Close()
result := make([]PerusahaanGroupTarifLayanan, 0)
for rows.Next() {
var item PerusahaanGroupTarifLayanan
var namaLayanan, namaJenisLayanan, namaKelas sql.NullString
if err := rows.Scan(&item.TarifLayananID, &item.LayananID, &namaLayanan,
&item.JenisLayananID, &namaJenisLayanan, &item.Kelas, &namaKelas,
&item.Harga, &item.TipeDiskonRJ, &item.DiskonRJ, &item.TipeDiskonRI,
&item.DiskonRI, &item.TipeShare, &item.ShareDokter, &item.ShareRS,
&item.ShareExt, &item.ShareLain, &item.AsalTarif); err != nil {
return nil, err
}
item.NamaLayanan = nullStringPtr(namaLayanan)
item.NamaJenisLayanan = nullStringPtr(namaJenisLayanan)
if namaKelas.Valid && namaKelas.String != "" {
item.NamaKelas = namaKelas.String
} else {
item.NamaKelas = item.Kelas
}
result = append(result, item)
}
if err := rows.Err(); err != nil {
return nil, err
}
return result, nil
}
func scanPerusahaanDetail(row interface{ Scan(...any) error }) (PerusahaanDetail, error) {
var result PerusahaanDetail
var penanggungjawab, teleponPJ, emailPJ, alamat, kota, kodePos, propinsi, negara sql.NullString
var telepon, fax, email, website, namaBank, namaRekening, nomerRekening sql.NullString
var catatan, npwp, picMarketing sql.NullString
err := row.Scan(&result.PerusahaanID, &result.KodePerusahaan, &result.Nama,
&result.JenisPerusahaanID, &result.Penjamin, &result.Asuransi, &result.Provider,
&result.COB, &result.MataUangID, &penanggungjawab, &teleponPJ, &emailPJ,
&alamat, &kota, &kodePos, &propinsi, &negara, &telepon, &fax, &email, &website,
&namaBank, &namaRekening, &nomerRekening, &result.DefaultLamaPembayaran,
&result.DefaultDiskon, &result.PPN, &catatan, &npwp, &result.FlagDiskon,
&result.VerifikasiBilling, &picMarketing, &result.NA)
if err != nil {
return PerusahaanDetail{}, err
}
result.Penanggungjawab = nullStringPtr(penanggungjawab)
result.TeleponPenanggungjawab = nullStringPtr(teleponPJ)
result.EmailPenanggungjawab = nullStringPtr(emailPJ)
result.Alamat = nullStringPtr(alamat)
result.Kota = nullStringPtr(kota)
result.KodePos = nullStringPtr(kodePos)
result.Propinsi = nullStringPtr(propinsi)
result.Negara = nullStringPtr(negara)
result.Telepon = nullStringPtr(telepon)
result.Fax = nullStringPtr(fax)
result.Email = nullStringPtr(email)
result.Website = nullStringPtr(website)
result.NamaBank = nullStringPtr(namaBank)
result.NamaRekening = nullStringPtr(namaRekening)
result.NomerRekening = nullStringPtr(nomerRekening)
result.Catatan = nullStringPtr(catatan)
result.NPWP = nullStringPtr(npwp)
result.PICMarketing = nullStringPtr(picMarketing)
return result, nil
}