382 lines
14 KiB
Go
382 lines
14 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-sql-driver/mysql"
|
|
)
|
|
|
|
type TarifKerjasamaListParams struct {
|
|
Search string
|
|
PerusahaanID string
|
|
TarifID *int64
|
|
Page int
|
|
PerPage int
|
|
}
|
|
|
|
type TarifKerjasamaDetailParams struct {
|
|
GroupTarifID *int64
|
|
Active string
|
|
EffectiveDate string
|
|
}
|
|
|
|
type TarifKerjasamaPage struct {
|
|
Items []TarifKerjasamaSummary
|
|
Total int
|
|
}
|
|
|
|
type TarifKerjasamaSummary struct {
|
|
PerusahaanTarifID int64 `json:"PerusahaanTarifID"`
|
|
PerusahaanID string `json:"PerusahaanID"`
|
|
KodePerusahaan *string `json:"KodePerusahaan"`
|
|
NamaPerusahaan string `json:"NamaPerusahaan"`
|
|
PIC *string `json:"PIC"`
|
|
Alamat *string `json:"Alamat"`
|
|
Telepon *string `json:"Telepon"`
|
|
Email *string `json:"Email"`
|
|
JumlahGroupTarif int `json:"JumlahGroupTarif"`
|
|
}
|
|
|
|
type TarifKerjasamaDetail struct {
|
|
TarifKerjasamaSummary
|
|
GroupTarif []TarifKerjasamaGroup `json:"GroupTarif"`
|
|
}
|
|
|
|
type TarifKerjasamaGroup struct {
|
|
GroupTarifID int64 `json:"GroupTarifID"`
|
|
PerusahaanTarifID int64 `json:"PerusahaanTarifID"`
|
|
NamaGroupTarif string `json:"NamaGroupTarif"`
|
|
TanggalBerlaku string `json:"TanggalBerlaku"`
|
|
TanggalBerakhir string `json:"TanggalBerakhir"`
|
|
PeriodeTarifID *int64 `json:"PeriodeTarifID"`
|
|
KelasDefault *string `json:"KelasDefault"`
|
|
SemuaLayanan *string `json:"SemuaLayanan"`
|
|
DiskonSemuaLayananRJ *float64 `json:"DiskonSemuaLayananRJ"`
|
|
DiskonSemuaLayananRI *float64 `json:"DiskonSemuaLayananRI"`
|
|
Keterangan *string `json:"Keterangan"`
|
|
NA string `json:"NA"`
|
|
Aktif bool `json:"Aktif"`
|
|
JumlahLayanan int `json:"JumlahLayanan"`
|
|
Layanan []TarifKerjasamaLayanan `json:"Layanan"`
|
|
}
|
|
|
|
type TarifKerjasamaLayanan struct {
|
|
LayananID *string `json:"LayananID"`
|
|
NamaLayanan *string `json:"NamaLayanan"`
|
|
JenisLayananID *string `json:"JenisLayananID"`
|
|
NamaJenisLayanan *string `json:"NamaJenisLayanan"`
|
|
JumlahDetail int `json:"JumlahDetail"`
|
|
Detail []TarifKerjasamaLayananDetail `json:"Detail"`
|
|
}
|
|
|
|
type TarifKerjasamaLayananDetail struct {
|
|
TarifLayananID int64 `json:"TarifLayananID"`
|
|
KelasID *string `json:"KelasID"`
|
|
NamaKelas *string `json:"NamaKelas"`
|
|
Harga float64 `json:"Harga"`
|
|
TipeDiskonRJ *string `json:"TipeDiskonRJ"`
|
|
DiskonRJ float64 `json:"DiskonRJ"`
|
|
TipeDiskonRI *string `json:"TipeDiskonRI"`
|
|
DiskonRI float64 `json:"DiskonRI"`
|
|
TipeShare *string `json:"TipeShare"`
|
|
ShareDokter float64 `json:"ShareDokter"`
|
|
ShareRS float64 `json:"ShareRS"`
|
|
ShareExternal float64 `json:"ShareExternal"`
|
|
ShareLain float64 `json:"ShareLain"`
|
|
AsalTarif *string `json:"AsalTarif"`
|
|
}
|
|
|
|
func (r MySQLLayananRepository) ListTarifKerjasama(ctx context.Context, params TarifKerjasamaListParams) (TarifKerjasamaPage, error) {
|
|
where, args := tarifKerjasamaListWhere(params)
|
|
var total int
|
|
countQuery := `SELECT COUNT(*) FROM perusahaan_tarif pt
|
|
INNER JOIN perusahaan p ON p.PerusahaanID = pt.PerusahaanID ` + where
|
|
if err := r.db.QueryRowContext(ctx, countQuery, args...).Scan(&total); err != nil {
|
|
return TarifKerjasamaPage{}, err
|
|
}
|
|
|
|
query := `SELECT pt.Perusahaan_TarifID, pt.PerusahaanID, p.KodePerusahaan,
|
|
p.Nama, pt.PenanggungJawab, p.Alamat, pt.TeleponPenanggungJawab,
|
|
pt.EmailPenanggungJawab,
|
|
COALESCE(pg.JumlahGroupTarif, 0)
|
|
FROM perusahaan_tarif pt
|
|
INNER JOIN perusahaan p ON p.PerusahaanID = pt.PerusahaanID
|
|
LEFT JOIN (
|
|
SELECT Perusahaan_TarifID, COUNT(*) AS JumlahGroupTarif
|
|
FROM perusahaan_grouptarif
|
|
WHERE NA = 'N'
|
|
GROUP BY Perusahaan_TarifID
|
|
) pg ON pg.Perusahaan_TarifID = pt.Perusahaan_TarifID ` + where + `
|
|
ORDER BY p.Nama, pt.Perusahaan_TarifID
|
|
LIMIT ? OFFSET ?`
|
|
queryArgs := append(append([]any{}, args...), params.PerPage, (params.Page-1)*params.PerPage)
|
|
rows, err := r.db.QueryContext(ctx, query, queryArgs...)
|
|
if err != nil {
|
|
return TarifKerjasamaPage{}, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
items := make([]TarifKerjasamaSummary, 0)
|
|
for rows.Next() {
|
|
item, err := scanTarifKerjasamaSummary(rows)
|
|
if err != nil {
|
|
return TarifKerjasamaPage{}, err
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return TarifKerjasamaPage{}, err
|
|
}
|
|
return TarifKerjasamaPage{Items: items, Total: total}, nil
|
|
}
|
|
|
|
func tarifKerjasamaListWhere(params TarifKerjasamaListParams) (string, []any) {
|
|
conditions := []string{"p.NA = 'N'"}
|
|
args := make([]any, 0, 6)
|
|
if params.Search != "" {
|
|
like := "%" + params.Search + "%"
|
|
conditions = append(conditions, `(p.Nama LIKE ? OR p.KodePerusahaan LIKE ?
|
|
OR pt.PerusahaanID LIKE ? OR pt.PenanggungJawab LIKE ?)`)
|
|
args = append(args, like, like, like, like)
|
|
}
|
|
if params.PerusahaanID != "" {
|
|
conditions = append(conditions, "pt.PerusahaanID = ?")
|
|
args = append(args, params.PerusahaanID)
|
|
}
|
|
if params.TarifID != nil {
|
|
conditions = append(conditions, "pt.Perusahaan_TarifID = ?")
|
|
args = append(args, *params.TarifID)
|
|
}
|
|
return "WHERE " + strings.Join(conditions, " AND "), args
|
|
}
|
|
|
|
func (r MySQLLayananRepository) GetTarifKerjasama(ctx context.Context, id int64, params TarifKerjasamaDetailParams) (*TarifKerjasamaDetail, error) {
|
|
row := r.db.QueryRowContext(ctx, `SELECT pt.Perusahaan_TarifID, pt.PerusahaanID,
|
|
p.KodePerusahaan, p.Nama, pt.PenanggungJawab, p.Alamat,
|
|
pt.TeleponPenanggungJawab, pt.EmailPenanggungJawab, 0
|
|
FROM perusahaan_tarif pt
|
|
INNER JOIN perusahaan p ON p.PerusahaanID = pt.PerusahaanID
|
|
WHERE pt.Perusahaan_TarifID = ? AND p.NA = 'N' LIMIT 1`, id)
|
|
master, err := scanTarifKerjasamaSummary(row)
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
groups, err := r.tarifKerjasamaGroups(ctx, id, params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
master.JumlahGroupTarif = len(groups)
|
|
return &TarifKerjasamaDetail{TarifKerjasamaSummary: master, GroupTarif: groups}, nil
|
|
}
|
|
|
|
func scanTarifKerjasamaSummary(row rowScanner) (TarifKerjasamaSummary, error) {
|
|
var item TarifKerjasamaSummary
|
|
var kode, pic, alamat, telepon, email sql.NullString
|
|
err := row.Scan(&item.PerusahaanTarifID, &item.PerusahaanID, &kode,
|
|
&item.NamaPerusahaan, &pic, &alamat, &telepon, &email, &item.JumlahGroupTarif)
|
|
item.KodePerusahaan = nullStringPtr(kode)
|
|
item.PIC = nullStringPtr(pic)
|
|
item.Alamat = nullStringPtr(alamat)
|
|
item.Telepon = nullStringPtr(telepon)
|
|
item.Email = nullStringPtr(email)
|
|
return item, err
|
|
}
|
|
|
|
func (r MySQLLayananRepository) tarifKerjasamaGroups(ctx context.Context, id int64, params TarifKerjasamaDetailParams) ([]TarifKerjasamaGroup, error) {
|
|
if params.Active == "" {
|
|
params.Active = "N"
|
|
}
|
|
conditions := []string{"pg.Perusahaan_TarifID = ?", "pg.NA = ?"}
|
|
args := []any{id, params.Active}
|
|
if params.GroupTarifID != nil {
|
|
conditions = append(conditions, "pg.GroupTarifID = ?")
|
|
args = append(args, *params.GroupTarifID)
|
|
}
|
|
if params.EffectiveDate != "" {
|
|
conditions = append(conditions, "DATE(pg.TanggalBerlaku) <= ?", "DATE(pg.TanggalBerakhir) >= ?")
|
|
args = append(args, params.EffectiveDate, params.EffectiveDate)
|
|
}
|
|
|
|
query := `SELECT pg.GroupTarifID, pg.Perusahaan_TarifID, pg.Keterangan,
|
|
CAST(pg.TanggalBerlaku AS CHAR), CAST(pg.TanggalBerakhir AS CHAR),
|
|
pg.PeriodeTarifID, pg.KelasDefault, pg.SemuaLayanan,
|
|
CAST(pg.HargaLayanan AS CHAR), CAST(pg.HargaLayananRI AS CHAR), pg.NA
|
|
FROM perusahaan_grouptarif pg WHERE ` + strings.Join(conditions, " AND ") + `
|
|
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()
|
|
|
|
groups := make([]TarifKerjasamaGroup, 0)
|
|
for rows.Next() {
|
|
var group TarifKerjasamaGroup
|
|
var keterangan, kelasDefault, semuaLayanan, hargaRJ, hargaRI sql.NullString
|
|
var periodeTarifID sql.NullInt64
|
|
if err := rows.Scan(
|
|
&group.GroupTarifID, &group.PerusahaanTarifID, &keterangan,
|
|
&group.TanggalBerlaku, &group.TanggalBerakhir, &periodeTarifID,
|
|
&kelasDefault, &semuaLayanan, &hargaRJ, &hargaRI, &group.NA,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
group.Keterangan = nullStringPtr(keterangan)
|
|
group.KelasDefault = nullStringPtr(kelasDefault)
|
|
group.SemuaLayanan = nullStringPtr(semuaLayanan)
|
|
group.PeriodeTarifID = nullInt64Ptr(periodeTarifID)
|
|
group.DiskonSemuaLayananRJ = nullDecimalPtr(hargaRJ)
|
|
group.DiskonSemuaLayananRI = nullDecimalPtr(hargaRI)
|
|
group.NamaGroupTarif = "Group Tarif " + strconv.FormatInt(group.GroupTarifID, 10)
|
|
if group.Keterangan != nil && *group.Keterangan != "" {
|
|
group.NamaGroupTarif = *group.Keterangan
|
|
}
|
|
group.Aktif = group.NA == "N"
|
|
groups = append(groups, group)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
_ = rows.Close()
|
|
return nil, err
|
|
}
|
|
if err := rows.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for index := range groups {
|
|
groups[index].Layanan, err = r.tarifKerjasamaLayanan(ctx, groups[index].GroupTarifID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
groups[index].JumlahLayanan = len(groups[index].Layanan)
|
|
}
|
|
return groups, nil
|
|
}
|
|
|
|
type tarifKerjasamaLayananRow struct {
|
|
TarifLayananID int64
|
|
LayananID sql.NullString
|
|
NamaLayanan sql.NullString
|
|
JenisLayananID sql.NullString
|
|
NamaJenis sql.NullString
|
|
KelasID sql.NullString
|
|
NamaKelas sql.NullString
|
|
Harga sql.NullString
|
|
TipeDiskonRJ sql.NullString
|
|
DiskonRJ sql.NullString
|
|
TipeDiskonRI sql.NullString
|
|
DiskonRI sql.NullString
|
|
TipeShare sql.NullString
|
|
ShareDokter sql.NullString
|
|
ShareRS sql.NullString
|
|
ShareExternal sql.NullString
|
|
ShareLain sql.NullString
|
|
AsalTarif sql.NullString
|
|
}
|
|
|
|
func (r MySQLLayananRepository) tarifKerjasamaLayanan(ctx context.Context, groupID int64) ([]TarifKerjasamaLayanan, error) {
|
|
tableName := "perusahaan_tarif_layanan_" + strconv.FormatInt(groupID, 10)
|
|
query := fmt.Sprintf(`SELECT tarif.TarifLayananID, CAST(tarif.LayananID AS CHAR),
|
|
layanan.Nama, CAST(tarif.JenisLayananID AS CHAR), jenis.Nama,
|
|
CAST(tarif.KelasID AS CHAR), 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.LayananID, tarif.KelasID`, tableName)
|
|
rows, err := r.db.QueryContext(ctx, query)
|
|
if err != nil {
|
|
if isMySQLMissingTable(err) {
|
|
return []TarifKerjasamaLayanan{}, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
flatRows := make([]tarifKerjasamaLayananRow, 0)
|
|
for rows.Next() {
|
|
var row tarifKerjasamaLayananRow
|
|
if err := rows.Scan(
|
|
&row.TarifLayananID, &row.LayananID, &row.NamaLayanan,
|
|
&row.JenisLayananID, &row.NamaJenis, &row.KelasID, &row.NamaKelas,
|
|
&row.Harga, &row.TipeDiskonRJ, &row.DiskonRJ, &row.TipeDiskonRI,
|
|
&row.DiskonRI, &row.TipeShare, &row.ShareDokter, &row.ShareRS,
|
|
&row.ShareExternal, &row.ShareLain, &row.AsalTarif,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
flatRows = append(flatRows, row)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return groupTarifKerjasamaLayanan(flatRows), nil
|
|
}
|
|
|
|
func isMySQLMissingTable(err error) bool {
|
|
var mysqlError *mysql.MySQLError
|
|
return errors.As(err, &mysqlError) && mysqlError.Number == 1146
|
|
}
|
|
|
|
func groupTarifKerjasamaLayanan(rows []tarifKerjasamaLayananRow) []TarifKerjasamaLayanan {
|
|
result := make([]TarifKerjasamaLayanan, 0)
|
|
indexes := make(map[string]int)
|
|
for _, row := range rows {
|
|
key := row.LayananID.String + "\x1f" + row.JenisLayananID.String
|
|
index, exists := indexes[key]
|
|
if !exists {
|
|
index = len(result)
|
|
indexes[key] = index
|
|
result = append(result, TarifKerjasamaLayanan{
|
|
LayananID: nullStringPtr(row.LayananID), NamaLayanan: nullStringPtr(row.NamaLayanan),
|
|
JenisLayananID: nullStringPtr(row.JenisLayananID), NamaJenisLayanan: nullStringPtr(row.NamaJenis),
|
|
Detail: make([]TarifKerjasamaLayananDetail, 0),
|
|
})
|
|
}
|
|
namaKelas := row.NamaKelas
|
|
if !namaKelas.Valid || namaKelas.String == "" {
|
|
namaKelas = row.KelasID
|
|
}
|
|
result[index].Detail = append(result[index].Detail, TarifKerjasamaLayananDetail{
|
|
TarifLayananID: row.TarifLayananID, KelasID: nullStringPtr(row.KelasID),
|
|
NamaKelas: nullStringPtr(namaKelas), Harga: decimalValue(row.Harga),
|
|
TipeDiskonRJ: nullStringPtr(row.TipeDiskonRJ), DiskonRJ: decimalValue(row.DiskonRJ),
|
|
TipeDiskonRI: nullStringPtr(row.TipeDiskonRI), DiskonRI: decimalValue(row.DiskonRI),
|
|
TipeShare: nullStringPtr(row.TipeShare), ShareDokter: decimalValue(row.ShareDokter),
|
|
ShareRS: decimalValue(row.ShareRS), ShareExternal: decimalValue(row.ShareExternal),
|
|
ShareLain: decimalValue(row.ShareLain), AsalTarif: nullStringPtr(row.AsalTarif),
|
|
})
|
|
result[index].JumlahDetail = len(result[index].Detail)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func nullDecimalPtr(value sql.NullString) *float64 {
|
|
if !value.Valid {
|
|
return nil
|
|
}
|
|
parsed := decimalValue(value)
|
|
return &parsed
|
|
}
|
|
|
|
func decimalValue(value sql.NullString) float64 {
|
|
if !value.Valid {
|
|
return 0
|
|
}
|
|
parsed, _ := strconv.ParseFloat(value.String, 64)
|
|
return parsed
|
|
}
|