159 lines
3.9 KiB
Go
159 lines
3.9 KiB
Go
package aplicare
|
|
|
|
import (
|
|
"api-service/internal/config"
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
type SyncResult struct {
|
|
RunAt string `json:"run_at"`
|
|
TotalRooms int `json:"total_rooms"`
|
|
Changed int `json:"changed"`
|
|
Posted int `json:"posted"`
|
|
Errors []string `json:"errors,omitempty"`
|
|
DryRun bool `json:"dry_run"`
|
|
}
|
|
|
|
type Syncer struct {
|
|
simrs *SimrsDB
|
|
bpjs *BpjsClient
|
|
statePath string
|
|
dryRun bool
|
|
}
|
|
|
|
func NewSyncer(simrs *SimrsDB, cfg *config.Config, statePath string, dryRun bool) *Syncer {
|
|
return &Syncer{
|
|
simrs: simrs,
|
|
bpjs: NewBpjsClient(cfg.Bpjs),
|
|
statePath: statePath,
|
|
dryRun: dryRun,
|
|
}
|
|
}
|
|
|
|
func (s *Syncer) Sync(ctx context.Context) (*SyncResult, error) {
|
|
result := &SyncResult{
|
|
RunAt: time.Now().Format(time.RFC3339),
|
|
DryRun: s.dryRun,
|
|
}
|
|
|
|
// 1. Baca dari SIMRS
|
|
ruangans, err := s.simrs.GetRuangan(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("baca m_ruang gagal: %w", err)
|
|
}
|
|
|
|
detailMap, err := s.simrs.GetBedDetails(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("baca m_detail gagal: %w", err)
|
|
}
|
|
|
|
// 2. Transform
|
|
beds := buildBedData(ruangans, detailMap)
|
|
result.TotalRooms = len(beds)
|
|
|
|
// 3. Diff vs state lama
|
|
oldState, err := LoadState(s.statePath)
|
|
if err != nil || oldState == nil {
|
|
oldState = &State{Rooms: make(map[string]RoomState)}
|
|
}
|
|
|
|
newState := ComputeDiff(oldState, beds)
|
|
changedBeds := GetChangedBeds(newState, beds)
|
|
result.Changed = len(changedBeds)
|
|
|
|
// 4. Dry run — tampilkan perubahan di terminal
|
|
if s.dryRun {
|
|
if len(changedBeds) == 0 {
|
|
fmt.Println("[DRY RUN] Tidak ada perubahan")
|
|
} else {
|
|
fmt.Printf("[DRY RUN] %d ruangan berubah:\n", len(changedBeds))
|
|
for _, bed := range changedBeds {
|
|
old := newState.Rooms[bed.KodeRuang].OldValue
|
|
fmt.Printf(" → %-30s | kelas: %-6s | kapasitas: %d | tersedia: %d → %d\n",
|
|
bed.NamaRuang,
|
|
bed.KodeKelas,
|
|
bed.Kapasitas,
|
|
old.Tersedia,
|
|
bed.Tersedia,
|
|
)
|
|
result.Posted++
|
|
}
|
|
}
|
|
if err := SaveState(s.statePath, newState); err != nil {
|
|
result.Errors = append(result.Errors, fmt.Sprintf("simpan state gagal: %v", err))
|
|
}
|
|
WriteBatchLog(result)
|
|
return result, nil
|
|
}
|
|
|
|
// 5. POST ke BPJS hanya yang berubah
|
|
if len(changedBeds) > 0 {
|
|
fmt.Printf("[SYNC] %d ruangan akan dikirim ke BPJS:\n", len(changedBeds))
|
|
}
|
|
|
|
for _, bed := range changedBeds {
|
|
if bed.Kapasitas == 0 {
|
|
continue
|
|
}
|
|
|
|
oldTersedia := newState.Rooms[bed.KodeRuang].OldValue.Tersedia
|
|
|
|
start := time.Now()
|
|
err := s.bpjs.PostKamar(ctx, bed)
|
|
elapsed := time.Since(start).Milliseconds()
|
|
|
|
if err != nil {
|
|
msg := fmt.Sprintf("POST %s gagal: %v", bed.KodeRuang, err)
|
|
result.Errors = append(result.Errors, msg)
|
|
fmt.Printf(" → %-30s | kelas: %-6s | tersedia: %d → %d | [GAGAL] %v\n",
|
|
bed.NamaRuang, bed.KodeKelas, oldTersedia, bed.Tersedia, err)
|
|
WriteLog(SyncLog{
|
|
KodeRuang: bed.KodeRuang,
|
|
NamaRuang: bed.NamaRuang,
|
|
KodeKelas: bed.KodeKelas,
|
|
Kapasitas: bed.Kapasitas,
|
|
Tersedia: bed.Tersedia,
|
|
Action: "post",
|
|
Status: "gagal",
|
|
Error: err.Error(),
|
|
ResponseMs: elapsed,
|
|
})
|
|
continue
|
|
}
|
|
|
|
fmt.Printf(" → %-30s | kelas: %-6s | tersedia: %d → %d | [SUKSES] %dms\n",
|
|
bed.NamaRuang, bed.KodeKelas, oldTersedia, bed.Tersedia, elapsed)
|
|
WriteLog(SyncLog{
|
|
KodeRuang: bed.KodeRuang,
|
|
NamaRuang: bed.NamaRuang,
|
|
KodeKelas: bed.KodeKelas,
|
|
Kapasitas: bed.Kapasitas,
|
|
Tersedia: bed.Tersedia,
|
|
Action: "post",
|
|
Status: "sukses",
|
|
ResponseMs: elapsed,
|
|
})
|
|
|
|
result.Posted++
|
|
|
|
if room, ok := newState.Rooms[bed.KodeRuang]; ok {
|
|
room.OldValue = room.NewValue
|
|
room.Changed = false
|
|
room.LastSynced = time.Now().Format(time.RFC3339)
|
|
newState.Rooms[bed.KodeRuang] = room
|
|
}
|
|
}
|
|
|
|
// 6. Simpan state
|
|
if err := SaveState(s.statePath, newState); err != nil {
|
|
result.Errors = append(result.Errors, fmt.Sprintf("simpan state gagal: %v", err))
|
|
}
|
|
|
|
// 7. Tulis ringkasan ke log
|
|
WriteBatchLog(result)
|
|
|
|
return result, nil
|
|
}
|