feat: add package base prices
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"primaya-api/cpone-middleware/internal/repository"
|
"primaya-api/cpone-middleware/internal/repository"
|
||||||
@@ -97,8 +98,10 @@ func TestGetPaketResponseAndNotFoundParity(t *testing.T) {
|
|||||||
JumlahHari: 1, TotalHarga: "1550913.00", StatusID: 2, LoginBuat: "API_CRM",
|
JumlahHari: 1, TotalHarga: "1550913.00", StatusID: 2, LoginBuat: "API_CRM",
|
||||||
TanggalBuat: "2026-08-05T10:05:03.000000Z", LoginEdit: "API_CRM",
|
TanggalBuat: "2026-08-05T10:05:03.000000Z", LoginEdit: "API_CRM",
|
||||||
TanggalEdit: "2026-08-19T06:05:20.000000Z", NA: "N",
|
TanggalEdit: "2026-08-19T06:05:20.000000Z", NA: "N",
|
||||||
Layanan: []repository.PaketLayanan{}, Operasi: []repository.PaketOperasi{},
|
Layanan: []repository.PaketLayanan{{HargaDasar: "100,000"}},
|
||||||
Item: []repository.PaketItem{}, Kamar: []repository.PaketKamar{},
|
Operasi: []repository.PaketOperasi{{HargaDasar: "250,000.00"}},
|
||||||
|
Item: []repository.PaketItem{{HargaDasar: "50,000.00"}},
|
||||||
|
Kamar: []repository.PaketKamar{{HargaDasar: "200,000.00"}},
|
||||||
}
|
}
|
||||||
repo := &fakePaketRepository{detail: detail}
|
repo := &fakePaketRepository{detail: detail}
|
||||||
handler := Handler{paketRepo: repo}
|
handler := Handler{paketRepo: repo}
|
||||||
@@ -109,6 +112,16 @@ func TestGetPaketResponseAndNotFoundParity(t *testing.T) {
|
|||||||
if recorder.Code != http.StatusOK || repo.detailID != "DISP-260800002" {
|
if recorder.Code != http.StatusOK || repo.detailID != "DISP-260800002" {
|
||||||
t.Fatalf("status=%d id=%q body=%s", recorder.Code, repo.detailID, recorder.Body.String())
|
t.Fatalf("status=%d id=%q body=%s", recorder.Code, repo.detailID, recorder.Body.String())
|
||||||
}
|
}
|
||||||
|
for _, expected := range []string{
|
||||||
|
`"HargaDasar":"100,000"`,
|
||||||
|
`"HargaDasar":"250,000.00"`,
|
||||||
|
`"HargaDasar":"50,000.00"`,
|
||||||
|
`"HargaDasar":"200,000.00"`,
|
||||||
|
} {
|
||||||
|
if !strings.Contains(recorder.Body.String(), expected) {
|
||||||
|
t.Fatalf("response does not contain %s: %s", expected, recorder.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
notFoundHandler := Handler{paketRepo: &fakePaketRepository{}}
|
notFoundHandler := Handler{paketRepo: &fakePaketRepository{}}
|
||||||
notFoundRequest := httptest.NewRequest(http.MethodGet, "/api/cpone/paket/UNKNOWN", nil)
|
notFoundRequest := httptest.NewRequest(http.MethodGet, "/api/cpone/paket/UNKNOWN", nil)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -82,6 +83,7 @@ type PaketLayanan struct {
|
|||||||
Jumlah string `json:"Jumlah"`
|
Jumlah string `json:"Jumlah"`
|
||||||
JumlahHari int `json:"JumlahHari"`
|
JumlahHari int `json:"JumlahHari"`
|
||||||
Harga string `json:"Harga"`
|
Harga string `json:"Harga"`
|
||||||
|
HargaDasar string `json:"HargaDasar"`
|
||||||
Diskon string `json:"Diskon"`
|
Diskon string `json:"Diskon"`
|
||||||
TipeDiskon string `json:"TipeDiskon"`
|
TipeDiskon string `json:"TipeDiskon"`
|
||||||
ShareRS string `json:"ShareRS"`
|
ShareRS string `json:"ShareRS"`
|
||||||
@@ -97,6 +99,7 @@ type PaketOperasi struct {
|
|||||||
NamaKasusOperasi *string `json:"NamaKasusOperasi"`
|
NamaKasusOperasi *string `json:"NamaKasusOperasi"`
|
||||||
EstimasiWaktu string `json:"EstimasiWaktu"`
|
EstimasiWaktu string `json:"EstimasiWaktu"`
|
||||||
Keterangan string `json:"Keterangan"`
|
Keterangan string `json:"Keterangan"`
|
||||||
|
HargaDasar string `json:"HargaDasar"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaketItem struct {
|
type PaketItem struct {
|
||||||
@@ -107,6 +110,7 @@ type PaketItem struct {
|
|||||||
Jumlah string `json:"Jumlah"`
|
Jumlah string `json:"Jumlah"`
|
||||||
NamaSatuan *string `json:"NamaSatuan"`
|
NamaSatuan *string `json:"NamaSatuan"`
|
||||||
Harga string `json:"Harga"`
|
Harga string `json:"Harga"`
|
||||||
|
HargaDasar string `json:"HargaDasar"`
|
||||||
Diskon string `json:"Diskon"`
|
Diskon string `json:"Diskon"`
|
||||||
TipeDiskon string `json:"TipeDiskon"`
|
TipeDiskon string `json:"TipeDiskon"`
|
||||||
SubTotal string `json:"SubTotal"`
|
SubTotal string `json:"SubTotal"`
|
||||||
@@ -118,6 +122,7 @@ type PaketKamar struct {
|
|||||||
NamaKelas *string `json:"NamaKelas"`
|
NamaKelas *string `json:"NamaKelas"`
|
||||||
Jumlah string `json:"Jumlah"`
|
Jumlah string `json:"Jumlah"`
|
||||||
Harga string `json:"Harga"`
|
Harga string `json:"Harga"`
|
||||||
|
HargaDasar string `json:"HargaDasar"`
|
||||||
TipeDiskon string `json:"TipeDiskon"`
|
TipeDiskon string `json:"TipeDiskon"`
|
||||||
Diskon float64 `json:"Diskon"`
|
Diskon float64 `json:"Diskon"`
|
||||||
SubTotal string `json:"SubTotal"`
|
SubTotal string `json:"SubTotal"`
|
||||||
@@ -238,14 +243,18 @@ func (r MySQLLayananRepository) GetPaket(ctx context.Context, id string) (*Paket
|
|||||||
result.TanggalBuat = laravelDateJSON(tanggalBuat)
|
result.TanggalBuat = laravelDateJSON(tanggalBuat)
|
||||||
result.TanggalEdit = laravelDateJSON(tanggalEdit)
|
result.TanggalEdit = laravelDateJSON(tanggalEdit)
|
||||||
|
|
||||||
var err error
|
tariffTable, err := r.activePaketTariffTable(ctx)
|
||||||
if result.Layanan, err = r.paketLayanan(ctx, id); err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
if result.Kamar, err = r.paketKamar(ctx, id); err != nil {
|
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
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r MySQLLayananRepository) paketLayanan(ctx context.Context, id string) ([]PaketLayanan, error) {
|
type paketBasePricing struct {
|
||||||
rows, err := r.db.QueryContext(ctx, `
|
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,
|
SELECT pl.PaketLayananID, pl.LayananID, ml.Nama, d.Nama,
|
||||||
CAST(pl.Jumlah AS CHAR), pl.JumlahHari, CAST(pl.Harga AS CHAR),
|
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.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
|
FROM paket_layanan pl
|
||||||
LEFT JOIN masterlayanan ml ON ml.LayananID = pl.LayananID
|
LEFT JOIN masterlayanan ml ON ml.LayananID = pl.LayananID
|
||||||
LEFT JOIN departemen d ON d.DepartemenID = pl.DepartemenID AND d.NA = 'N'
|
LEFT JOIN departemen d ON d.DepartemenID = pl.DepartemenID AND d.NA = 'N'
|
||||||
WHERE pl.PaketID = ? AND pl.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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -274,25 +351,31 @@ func (r MySQLLayananRepository) paketLayanan(ctx context.Context, id string) ([]
|
|||||||
var item PaketLayanan
|
var item PaketLayanan
|
||||||
var namaLayanan, namaDepartemen sql.NullString
|
var namaLayanan, namaDepartemen sql.NullString
|
||||||
var harga, shareRS, shareDokter, subtotal string
|
var harga, shareRS, shareDokter, subtotal string
|
||||||
|
var basePrice float64
|
||||||
|
var operationHeader sql.NullString
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&item.PaketLayananID, &item.LayananID, &namaLayanan, &namaDepartemen,
|
&item.PaketLayananID, &item.LayananID, &namaLayanan, &namaDepartemen,
|
||||||
&item.Jumlah, &item.JumlahHari, &harga, &item.Diskon, &item.TipeDiskon,
|
&item.Jumlah, &item.JumlahHari, &harga, &item.Diskon, &item.TipeDiskon,
|
||||||
&shareRS, &shareDokter, &subtotal,
|
&shareRS, &shareDokter, &subtotal, &basePrice, &operationHeader,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
item.NamaLayanan = nullStringPtr(namaLayanan)
|
item.NamaLayanan = nullStringPtr(namaLayanan)
|
||||||
item.NamaDepartemen = nullStringPtr(namaDepartemen)
|
item.NamaDepartemen = nullStringPtr(namaDepartemen)
|
||||||
item.Harga = phpNumberFormat(parseDecimal(harga), 0)
|
item.Harga = phpNumberFormat(parseDecimal(harga), 0)
|
||||||
|
item.HargaDasar = phpNumberFormat(basePrice, 0)
|
||||||
item.ShareRS = phpNumberFormat(parseDecimal(shareRS), 2)
|
item.ShareRS = phpNumberFormat(parseDecimal(shareRS), 2)
|
||||||
item.ShareDokter = phpNumberFormat(parseDecimal(shareDokter), 0)
|
item.ShareDokter = phpNumberFormat(parseDecimal(shareDokter), 0)
|
||||||
item.Subtotal = phpNumberFormat(parseDecimal(subtotal), 0)
|
item.Subtotal = phpNumberFormat(parseDecimal(subtotal), 0)
|
||||||
|
if operationHeader.Valid {
|
||||||
|
pricing.layananByOperation[operationHeader.String] += basePrice * parseDecimal(item.Jumlah)
|
||||||
|
}
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
return result, rows.Err()
|
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, `
|
rows, err := r.db.QueryContext(ctx, `
|
||||||
SELECT po.PaketOperasiHeaderID, mt.Nama, go.Nama, ja.Nama, ko.Nama,
|
SELECT po.PaketOperasiHeaderID, mt.Nama, go.Nama, ja.Nama, ko.Nama,
|
||||||
po.EstimasiWaktu, po.Keterangan
|
po.EstimasiWaktu, po.Keterangan
|
||||||
@@ -321,19 +404,35 @@ func (r MySQLLayananRepository) paketOperasi(ctx context.Context, id string) ([]
|
|||||||
item.NamaGolongan = nullStringPtr(golongan)
|
item.NamaGolongan = nullStringPtr(golongan)
|
||||||
item.NamaJenisAnestesi = nullStringPtr(anestesi)
|
item.NamaJenisAnestesi = nullStringPtr(anestesi)
|
||||||
item.NamaKasusOperasi = nullStringPtr(kasus)
|
item.NamaKasusOperasi = nullStringPtr(kasus)
|
||||||
|
headerID := strconv.FormatInt(item.PaketOperasiHeaderID, 10)
|
||||||
|
item.HargaDasar = phpNumberFormat(
|
||||||
|
pricing.layananByOperation[headerID]+pricing.itemByOperation[headerID],
|
||||||
|
2,
|
||||||
|
)
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
return result, rows.Err()
|
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, `
|
rows, err := r.db.QueryContext(ctx, `
|
||||||
SELECT pi.PaketItemID, pi.ItemID, mi.Nama, d.Nama, CAST(pi.Jumlah AS CHAR), s.Nama,
|
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,
|
CAST(pi.Harga AS CHAR), CAST(pi.Diskon AS CHAR), pi.TipeDiskon,
|
||||||
pi.SatuanID, pi.SatuanDasarID,
|
pi.SatuanID, pi.SatuanDasarID,
|
||||||
COALESCE((SELECT ks.NilaiKonversi FROM konversisatuan ks
|
COALESCE((SELECT ks.NilaiKonversi FROM konversisatuan ks
|
||||||
WHERE ks.ItemID = pi.ItemID AND ks.SatuanTujuan = pi.SatuanDasarID
|
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
|
FROM paket_item pi
|
||||||
LEFT JOIN masteritem mi ON mi.ItemID = pi.ItemID AND mi.NA = 'N'
|
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'
|
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 namaItem, namaDepartemen, namaSatuan sql.NullString
|
||||||
var harga, satuanID, satuanDasarID string
|
var harga, satuanID, satuanDasarID string
|
||||||
var konversi float64
|
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(
|
if err := rows.Scan(
|
||||||
&item.PaketItemID, &item.ItemID, &namaItem, &namaDepartemen, &item.Jumlah,
|
&item.PaketItemID, &item.ItemID, &namaItem, &namaDepartemen, &item.Jumlah,
|
||||||
&namaSatuan, &harga, &item.Diskon, &item.TipeDiskon,
|
&namaSatuan, &harga, &item.Diskon, &item.TipeDiskon,
|
||||||
&satuanID, &satuanDasarID, &konversi,
|
&satuanID, &satuanDasarID, &konversi,
|
||||||
|
&het, &defaultPrice, &baseCost, &categoryID,
|
||||||
|
&medicineMargin, &settingMargin, &medicalSupplyMargin, &operationHeader,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -370,7 +476,15 @@ func (r MySQLLayananRepository) paketItem(ctx context.Context, id string) ([]Pak
|
|||||||
konversi = 1
|
konversi = 1
|
||||||
}
|
}
|
||||||
item.Harga = phpNumberFormat(hargaValue, 2)
|
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)
|
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)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
return result, rows.Err()
|
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) {
|
func (r MySQLLayananRepository) paketKamar(ctx context.Context, id string) ([]PaketKamar, error) {
|
||||||
rows, err := r.db.QueryContext(ctx, `
|
rows, err := r.db.QueryContext(ctx, `
|
||||||
SELECT pt.PaketTTID, d.Nama, k.Nama, CAST(pt.Jumlah AS CHAR),
|
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
|
FROM paket_tt pt
|
||||||
LEFT JOIN departemen d ON d.DepartemenID = pt.DepartemenID AND d.NA = 'N'
|
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'
|
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 item PaketKamar
|
||||||
var namaDepartemen, namaKelas sql.NullString
|
var namaDepartemen, namaKelas sql.NullString
|
||||||
var harga, diskon string
|
var harga, diskon string
|
||||||
|
var basePrice float64
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&item.PaketTTID, &namaDepartemen, &namaKelas, &item.Jumlah,
|
&item.PaketTTID, &namaDepartemen, &namaKelas, &item.Jumlah,
|
||||||
&harga, &item.TipeDiskon, &diskon,
|
&harga, &item.TipeDiskon, &diskon, &basePrice,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -409,12 +525,40 @@ func (r MySQLLayananRepository) paketKamar(ctx context.Context, id string) ([]Pa
|
|||||||
item.Diskon = hargaValue * (diskonValue / 100)
|
item.Diskon = hargaValue * (diskonValue / 100)
|
||||||
}
|
}
|
||||||
item.Harga = phpNumberFormat(hargaValue, 2)
|
item.Harga = phpNumberFormat(hargaValue, 2)
|
||||||
|
item.HargaDasar = phpNumberFormat(basePrice, 2)
|
||||||
item.SubTotal = phpNumberFormat((hargaValue-item.Diskon)*parseDecimal(item.Jumlah), 0)
|
item.SubTotal = phpNumberFormat((hargaValue-item.Diskon)*parseDecimal(item.Jumlah), 0)
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
return result, rows.Err()
|
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 {
|
func parseDecimal(value string) float64 {
|
||||||
parsed, _ := strconv.ParseFloat(value, 64)
|
parsed, _ := strconv.ParseFloat(value, 64)
|
||||||
return parsed
|
return parsed
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestPaketListWhereParity(t *testing.T) {
|
func TestPaketListWhereParity(t *testing.T) {
|
||||||
where, args := paketListWhere(PaketListParams{
|
where, args := paketListWhere(PaketListParams{
|
||||||
@@ -43,3 +46,51 @@ func TestLaravelDateJSONParity(t *testing.T) {
|
|||||||
t.Fatalf("zero date=%q", actual)
|
t.Fatalf("zero date=%q", actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPaketItemBasePriceFallbackParity(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
het string
|
||||||
|
defaultPrice float64
|
||||||
|
baseCost float64
|
||||||
|
categoryID int
|
||||||
|
medicine sql.NullFloat64
|
||||||
|
setting sql.NullFloat64
|
||||||
|
medicalSupply sql.NullFloat64
|
||||||
|
expected float64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "HET uses default price", het: "Y", defaultPrice: 1234.56,
|
||||||
|
expected: 1234.56,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "medicine uses tier margin", baseCost: 1000, categoryID: 1,
|
||||||
|
medicine: sql.NullFloat64{Float64: 12.5, Valid: true},
|
||||||
|
setting: sql.NullFloat64{Float64: 20, Valid: true}, expected: 1125,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "medicine falls back to system setting", baseCost: 1000, categoryID: 1,
|
||||||
|
setting: sql.NullFloat64{Float64: 20, Valid: true}, expected: 1200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "medical supply uses its margin", baseCost: 1000, categoryID: 2,
|
||||||
|
medicalSupply: sql.NullFloat64{Float64: 15, Valid: true}, expected: 1150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "other category uses rounded default", defaultPrice: 1234.56,
|
||||||
|
categoryID: 3, expected: 1235,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
actual := paketItemBasePrice(
|
||||||
|
test.het, test.defaultPrice, test.baseCost, test.categoryID,
|
||||||
|
test.medicine, test.setting, test.medicalSupply,
|
||||||
|
)
|
||||||
|
if actual != test.expected {
|
||||||
|
t.Fatalf("base price=%v want=%v", actual, test.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user