feat: add package base prices
This commit is contained in:
@@ -3,6 +3,7 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -82,6 +83,7 @@ type PaketLayanan struct {
|
||||
Jumlah string `json:"Jumlah"`
|
||||
JumlahHari int `json:"JumlahHari"`
|
||||
Harga string `json:"Harga"`
|
||||
HargaDasar string `json:"HargaDasar"`
|
||||
Diskon string `json:"Diskon"`
|
||||
TipeDiskon string `json:"TipeDiskon"`
|
||||
ShareRS string `json:"ShareRS"`
|
||||
@@ -97,6 +99,7 @@ type PaketOperasi struct {
|
||||
NamaKasusOperasi *string `json:"NamaKasusOperasi"`
|
||||
EstimasiWaktu string `json:"EstimasiWaktu"`
|
||||
Keterangan string `json:"Keterangan"`
|
||||
HargaDasar string `json:"HargaDasar"`
|
||||
}
|
||||
|
||||
type PaketItem struct {
|
||||
@@ -107,6 +110,7 @@ type PaketItem struct {
|
||||
Jumlah string `json:"Jumlah"`
|
||||
NamaSatuan *string `json:"NamaSatuan"`
|
||||
Harga string `json:"Harga"`
|
||||
HargaDasar string `json:"HargaDasar"`
|
||||
Diskon string `json:"Diskon"`
|
||||
TipeDiskon string `json:"TipeDiskon"`
|
||||
SubTotal string `json:"SubTotal"`
|
||||
@@ -118,6 +122,7 @@ type PaketKamar struct {
|
||||
NamaKelas *string `json:"NamaKelas"`
|
||||
Jumlah string `json:"Jumlah"`
|
||||
Harga string `json:"Harga"`
|
||||
HargaDasar string `json:"HargaDasar"`
|
||||
TipeDiskon string `json:"TipeDiskon"`
|
||||
Diskon float64 `json:"Diskon"`
|
||||
SubTotal string `json:"SubTotal"`
|
||||
@@ -238,14 +243,18 @@ func (r MySQLLayananRepository) GetPaket(ctx context.Context, id string) (*Paket
|
||||
result.TanggalBuat = laravelDateJSON(tanggalBuat)
|
||||
result.TanggalEdit = laravelDateJSON(tanggalEdit)
|
||||
|
||||
var err error
|
||||
if result.Layanan, err = r.paketLayanan(ctx, id); err != nil {
|
||||
tariffTable, err := r.activePaketTariffTable(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Operasi, err = r.paketOperasi(ctx, id); err != nil {
|
||||
pricing := newPaketBasePricing()
|
||||
if result.Layanan, err = r.paketLayanan(ctx, id, result.KelasID, tariffTable, pricing); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Item, err = r.paketItem(ctx, id); err != nil {
|
||||
if result.Item, err = r.paketItem(ctx, id, pricing); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Operasi, err = r.paketOperasi(ctx, id, pricing); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Kamar, err = r.paketKamar(ctx, id); err != nil {
|
||||
@@ -254,17 +263,85 @@ func (r MySQLLayananRepository) GetPaket(ctx context.Context, id string) (*Paket
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (r MySQLLayananRepository) paketLayanan(ctx context.Context, id string) ([]PaketLayanan, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
type paketBasePricing struct {
|
||||
layananByOperation map[string]float64
|
||||
itemByOperation map[string]float64
|
||||
}
|
||||
|
||||
func newPaketBasePricing() *paketBasePricing {
|
||||
return &paketBasePricing{
|
||||
layananByOperation: make(map[string]float64),
|
||||
itemByOperation: make(map[string]float64),
|
||||
}
|
||||
}
|
||||
|
||||
func (r MySQLLayananRepository) activePaketTariffTable(ctx context.Context) (string, error) {
|
||||
var periodID int64
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT PeriodeTarifID
|
||||
FROM periode_tarif
|
||||
WHERE DATE(TanggalBerlaku) <= CURRENT_DATE()
|
||||
AND DATE(TanggalBerakhir) >= CURRENT_DATE()
|
||||
AND NA = 'N'
|
||||
ORDER BY PeriodeTarifID DESC
|
||||
LIMIT 1`).Scan(&periodID)
|
||||
if err == sql.ErrNoRows {
|
||||
return "", nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tableName := "harga_layanan_" + strconv.FormatInt(periodID, 10)
|
||||
exists, err := r.tableExists(ctx, tableName)
|
||||
if err != nil || !exists {
|
||||
return "", err
|
||||
}
|
||||
return tableName, nil
|
||||
}
|
||||
|
||||
func (r MySQLLayananRepository) paketLayanan(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
classID string,
|
||||
tariffTable string,
|
||||
pricing *paketBasePricing,
|
||||
) ([]PaketLayanan, error) {
|
||||
basePriceSelect := "COALESCE(ml.DefaultHarga, 0)"
|
||||
args := make([]any, 0, 3)
|
||||
if tariffTable != "" {
|
||||
basePriceSelect = fmt.Sprintf(`COALESCE((
|
||||
SELECT tarif.Harga
|
||||
FROM %s tarif
|
||||
INNER JOIN layanandepartemen ld
|
||||
ON ld.LayananDepartemenID = tarif.LayananDepartemenID
|
||||
AND ld.NA = 'N'
|
||||
WHERE ld.LayananID = pl.LayananID
|
||||
AND tarif.KelasID IN (?, 'Default')
|
||||
AND tarif.NA = 'N'
|
||||
ORDER BY CASE
|
||||
WHEN tarif.KelasID = ? AND ld.DepartemenID <=> pl.DepartemenID THEN 1
|
||||
WHEN tarif.KelasID = ? THEN 2
|
||||
WHEN tarif.KelasID = 'Default' AND ld.DepartemenID <=> pl.DepartemenID THEN 3
|
||||
ELSE 4
|
||||
END, tarif.HargaLayananID
|
||||
LIMIT 1
|
||||
), ml.DefaultHarga, 0)`, tariffTable)
|
||||
args = append(args, classID, classID, classID)
|
||||
}
|
||||
args = append(args, id)
|
||||
query := fmt.Sprintf(`
|
||||
SELECT pl.PaketLayananID, pl.LayananID, ml.Nama, d.Nama,
|
||||
CAST(pl.Jumlah AS CHAR), pl.JumlahHari, CAST(pl.Harga AS CHAR),
|
||||
CAST(pl.Diskon AS CHAR), pl.TipeDiskon, CAST(pl.ShareRS AS CHAR),
|
||||
CAST(pl.ShareDokter AS CHAR), CAST(pl.Subtotal AS CHAR)
|
||||
CAST(pl.ShareDokter AS CHAR), CAST(pl.Subtotal AS CHAR),
|
||||
%s, CAST(pl.HeaderLayanan AS CHAR)
|
||||
FROM paket_layanan pl
|
||||
LEFT JOIN masterlayanan ml ON ml.LayananID = pl.LayananID
|
||||
LEFT JOIN departemen d ON d.DepartemenID = pl.DepartemenID AND d.NA = 'N'
|
||||
WHERE pl.PaketID = ? AND pl.NA = 'N'
|
||||
ORDER BY pl.PaketLayananID`, id)
|
||||
ORDER BY pl.PaketLayananID`, basePriceSelect)
|
||||
rows, err := r.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -274,25 +351,31 @@ func (r MySQLLayananRepository) paketLayanan(ctx context.Context, id string) ([]
|
||||
var item PaketLayanan
|
||||
var namaLayanan, namaDepartemen sql.NullString
|
||||
var harga, shareRS, shareDokter, subtotal string
|
||||
var basePrice float64
|
||||
var operationHeader sql.NullString
|
||||
if err := rows.Scan(
|
||||
&item.PaketLayananID, &item.LayananID, &namaLayanan, &namaDepartemen,
|
||||
&item.Jumlah, &item.JumlahHari, &harga, &item.Diskon, &item.TipeDiskon,
|
||||
&shareRS, &shareDokter, &subtotal,
|
||||
&shareRS, &shareDokter, &subtotal, &basePrice, &operationHeader,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item.NamaLayanan = nullStringPtr(namaLayanan)
|
||||
item.NamaDepartemen = nullStringPtr(namaDepartemen)
|
||||
item.Harga = phpNumberFormat(parseDecimal(harga), 0)
|
||||
item.HargaDasar = phpNumberFormat(basePrice, 0)
|
||||
item.ShareRS = phpNumberFormat(parseDecimal(shareRS), 2)
|
||||
item.ShareDokter = phpNumberFormat(parseDecimal(shareDokter), 0)
|
||||
item.Subtotal = phpNumberFormat(parseDecimal(subtotal), 0)
|
||||
if operationHeader.Valid {
|
||||
pricing.layananByOperation[operationHeader.String] += basePrice * parseDecimal(item.Jumlah)
|
||||
}
|
||||
result = append(result, item)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (r MySQLLayananRepository) paketOperasi(ctx context.Context, id string) ([]PaketOperasi, error) {
|
||||
func (r MySQLLayananRepository) paketOperasi(ctx context.Context, id string, pricing *paketBasePricing) ([]PaketOperasi, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT po.PaketOperasiHeaderID, mt.Nama, go.Nama, ja.Nama, ko.Nama,
|
||||
po.EstimasiWaktu, po.Keterangan
|
||||
@@ -321,19 +404,35 @@ func (r MySQLLayananRepository) paketOperasi(ctx context.Context, id string) ([]
|
||||
item.NamaGolongan = nullStringPtr(golongan)
|
||||
item.NamaJenisAnestesi = nullStringPtr(anestesi)
|
||||
item.NamaKasusOperasi = nullStringPtr(kasus)
|
||||
headerID := strconv.FormatInt(item.PaketOperasiHeaderID, 10)
|
||||
item.HargaDasar = phpNumberFormat(
|
||||
pricing.layananByOperation[headerID]+pricing.itemByOperation[headerID],
|
||||
2,
|
||||
)
|
||||
result = append(result, item)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (r MySQLLayananRepository) paketItem(ctx context.Context, id string) ([]PaketItem, error) {
|
||||
func (r MySQLLayananRepository) paketItem(ctx context.Context, id string, pricing *paketBasePricing) ([]PaketItem, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT pi.PaketItemID, pi.ItemID, mi.Nama, d.Nama, CAST(pi.Jumlah AS CHAR), s.Nama,
|
||||
CAST(pi.Harga AS CHAR), CAST(pi.Diskon AS CHAR), pi.TipeDiskon,
|
||||
pi.SatuanID, pi.SatuanDasarID,
|
||||
COALESCE((SELECT ks.NilaiKonversi FROM konversisatuan ks
|
||||
WHERE ks.ItemID = pi.ItemID AND ks.SatuanTujuan = pi.SatuanDasarID
|
||||
AND ks.SatuanAsal = pi.SatuanID AND ks.NA = 'N' LIMIT 1), 1)
|
||||
AND ks.SatuanAsal = pi.SatuanID AND ks.NA = 'N' LIMIT 1), 1),
|
||||
COALESCE(mi.HET, 'N'), COALESCE(mi.DefaultHarga, 0),
|
||||
COALESCE(mi.CostDasar, 0), COALESCE(mi.KategoriItemID, 0),
|
||||
(SELECT mo.Margin FROM margin_obat mo
|
||||
WHERE mo.Dari <= mi.CostDasar AND mo.Sampai >= mi.CostDasar
|
||||
AND mo.JenisReg = 'RJ' AND mo.NA = 'N' LIMIT 1),
|
||||
(SELECT ss.Value_ FROM sys_setting ss
|
||||
WHERE ss.Setting = 'Margin_RJ' AND ss.NA = 'N' LIMIT 1),
|
||||
(SELECT ma.Margin FROM margin_alkes ma
|
||||
WHERE ma.Dari <= mi.CostDasar AND ma.Sampai >= mi.CostDasar
|
||||
AND ma.NA = 'N' LIMIT 1),
|
||||
CAST(pi.HeaderID AS CHAR)
|
||||
FROM paket_item pi
|
||||
LEFT JOIN masteritem mi ON mi.ItemID = pi.ItemID AND mi.NA = 'N'
|
||||
LEFT JOIN departemen d ON d.DepartemenID = pi.DepartemenID AND d.NA = 'N'
|
||||
@@ -350,10 +449,17 @@ func (r MySQLLayananRepository) paketItem(ctx context.Context, id string) ([]Pak
|
||||
var namaItem, namaDepartemen, namaSatuan sql.NullString
|
||||
var harga, satuanID, satuanDasarID string
|
||||
var konversi float64
|
||||
var het string
|
||||
var defaultPrice, baseCost float64
|
||||
var categoryID int
|
||||
var medicineMargin, settingMargin, medicalSupplyMargin sql.NullFloat64
|
||||
var operationHeader sql.NullString
|
||||
if err := rows.Scan(
|
||||
&item.PaketItemID, &item.ItemID, &namaItem, &namaDepartemen, &item.Jumlah,
|
||||
&namaSatuan, &harga, &item.Diskon, &item.TipeDiskon,
|
||||
&satuanID, &satuanDasarID, &konversi,
|
||||
&het, &defaultPrice, &baseCost, &categoryID,
|
||||
&medicineMargin, &settingMargin, &medicalSupplyMargin, &operationHeader,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -370,7 +476,15 @@ func (r MySQLLayananRepository) paketItem(ctx context.Context, id string) ([]Pak
|
||||
konversi = 1
|
||||
}
|
||||
item.Harga = phpNumberFormat(hargaValue, 2)
|
||||
basePrice := paketItemBasePrice(
|
||||
het, defaultPrice, baseCost, categoryID,
|
||||
medicineMargin, settingMargin, medicalSupplyMargin,
|
||||
)
|
||||
item.HargaDasar = phpNumberFormat(basePrice, 2)
|
||||
item.SubTotal = phpNumberFormat((hargaValue-nDisc)*parseDecimal(item.Jumlah)*konversi, 2)
|
||||
if operationHeader.Valid {
|
||||
pricing.itemByOperation[operationHeader.String] += basePrice * parseDecimal(item.Jumlah) * konversi
|
||||
}
|
||||
result = append(result, item)
|
||||
}
|
||||
return result, rows.Err()
|
||||
@@ -379,7 +493,8 @@ func (r MySQLLayananRepository) paketItem(ctx context.Context, id string) ([]Pak
|
||||
func (r MySQLLayananRepository) paketKamar(ctx context.Context, id string) ([]PaketKamar, error) {
|
||||
rows, err := r.db.QueryContext(ctx, `
|
||||
SELECT pt.PaketTTID, d.Nama, k.Nama, CAST(pt.Jumlah AS CHAR),
|
||||
CAST(pt.Harga AS CHAR), pt.TipeDiskon, CAST(pt.Diskon AS CHAR)
|
||||
CAST(pt.Harga AS CHAR), pt.TipeDiskon, CAST(pt.Diskon AS CHAR),
|
||||
COALESCE(k.HargaTT, 0)
|
||||
FROM paket_tt pt
|
||||
LEFT JOIN departemen d ON d.DepartemenID = pt.DepartemenID AND d.NA = 'N'
|
||||
LEFT JOIN kelas k ON k.KelasID = pt.KelasID AND k.NA = 'N'
|
||||
@@ -394,9 +509,10 @@ func (r MySQLLayananRepository) paketKamar(ctx context.Context, id string) ([]Pa
|
||||
var item PaketKamar
|
||||
var namaDepartemen, namaKelas sql.NullString
|
||||
var harga, diskon string
|
||||
var basePrice float64
|
||||
if err := rows.Scan(
|
||||
&item.PaketTTID, &namaDepartemen, &namaKelas, &item.Jumlah,
|
||||
&harga, &item.TipeDiskon, &diskon,
|
||||
&harga, &item.TipeDiskon, &diskon, &basePrice,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -409,12 +525,40 @@ func (r MySQLLayananRepository) paketKamar(ctx context.Context, id string) ([]Pa
|
||||
item.Diskon = hargaValue * (diskonValue / 100)
|
||||
}
|
||||
item.Harga = phpNumberFormat(hargaValue, 2)
|
||||
item.HargaDasar = phpNumberFormat(basePrice, 2)
|
||||
item.SubTotal = phpNumberFormat((hargaValue-item.Diskon)*parseDecimal(item.Jumlah), 0)
|
||||
result = append(result, item)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func paketItemBasePrice(
|
||||
het string,
|
||||
defaultPrice float64,
|
||||
baseCost float64,
|
||||
categoryID int,
|
||||
medicineMargin sql.NullFloat64,
|
||||
settingMargin sql.NullFloat64,
|
||||
medicalSupplyMargin sql.NullFloat64,
|
||||
) float64 {
|
||||
if het == "Y" {
|
||||
return defaultPrice
|
||||
}
|
||||
|
||||
switch categoryID {
|
||||
case 1:
|
||||
margin := settingMargin.Float64
|
||||
if medicineMargin.Valid {
|
||||
margin = medicineMargin.Float64
|
||||
}
|
||||
return math.Round(baseCost + baseCost*margin/100)
|
||||
case 2:
|
||||
return math.Round(baseCost + baseCost*medicalSupplyMargin.Float64/100)
|
||||
default:
|
||||
return math.Round(defaultPrice)
|
||||
}
|
||||
}
|
||||
|
||||
func parseDecimal(value string) float64 {
|
||||
parsed, _ := strconv.ParseFloat(value, 64)
|
||||
return parsed
|
||||
|
||||
Reference in New Issue
Block a user