Files
bssapp/svc/queries/statement_aging_balance_list.go
2026-03-03 10:16:19 +03:00

245 lines
5.7 KiB
Go

package queries
import (
"bssapp-backend/models"
"context"
"database/sql"
"fmt"
"log"
"math"
"sort"
"strconv"
"strings"
"time"
"bssapp-backend/db"
)
func GetStatementAgingBalanceList(ctx context.Context, params models.CustomerBalanceListParams) ([]models.CustomerBalanceListRow, error) {
selectedDate := strings.TrimSpace(params.SelectedDate)
if selectedDate == "" {
selectedDate = time.Now().Format("2006-01-02")
}
lines, err := loadAgingBalanceLines(ctx, strings.TrimSpace(params.CariSearch))
if err != nil {
return nil, err
}
metaMap, err := loadCariMetaMap(ctx, lines)
if err != nil {
log.Printf("statement_aging_balance: cari meta query failed, fallback without meta: %v", err)
metaMap = map[string]cariMeta{}
}
masterMetaMap, err := loadMasterCariMetaMap(ctx, lines)
if err != nil {
log.Printf("statement_aging_balance: master cari meta query failed, fallback without master meta: %v", err)
masterMetaMap = map[string]masterCariMeta{}
}
companyMap, err := loadCompanyMap(ctx)
if err != nil {
return nil, err
}
glMap, err := loadGLAccountMap(ctx, lines)
if err != nil {
return nil, err
}
rateMap, err := loadNearestTryRates(ctx)
if err != nil {
return nil, err
}
usdTry := rateMap["USD"]
if usdTry <= 0 {
usdTry = 1
}
filters := buildFilters(params)
agg := make(map[string]*models.CustomerBalanceListRow, len(lines))
weightMap := make(map[string]float64, len(lines))
vadeSumMap := make(map[string]float64, len(lines))
vadeBelgeSumMap := make(map[string]float64, len(lines))
for _, ln := range lines {
cari := strings.TrimSpace(ln.CariKodu)
if cari == "" {
continue
}
curr := strings.ToUpper(strings.TrimSpace(ln.CariDoviz))
if curr == "" {
curr = "TRY"
}
meta := metaMap[metaKey(ln.CurrAccTypeCode, cari)]
meta.MuhasebeKodu = glMap[glKey(ln.CurrAccTypeCode, cari, ln.SirketKodu)]
meta.SirketDetay = companyMap[ln.SirketKodu]
master := deriveMasterCari(cari)
mm := masterMetaMap[master]
if strings.TrimSpace(mm.Kanal1) != "" {
meta.Kanal1 = mm.Kanal1
}
if strings.TrimSpace(mm.Piyasa) != "" {
meta.Piyasa = mm.Piyasa
}
if strings.TrimSpace(mm.Temsilci) != "" {
meta.Temsilci = mm.Temsilci
}
if strings.TrimSpace(mm.Ulke) != "" {
meta.Ulke = mm.Ulke
}
if strings.TrimSpace(mm.Il) != "" {
meta.Il = mm.Il
}
if strings.TrimSpace(mm.Ilce) != "" {
meta.Ilce = mm.Ilce
}
if strings.TrimSpace(mm.RiskDurumu) != "" {
meta.RiskDurumu = mm.RiskDurumu
}
if !filters.matchLine(ln.PislemTipi, meta) {
continue
}
key := strconv.Itoa(ln.CurrAccTypeCode) + "|" + cari + "|" + curr + "|" + strconv.Itoa(ln.SirketKodu)
row, ok := agg[key]
if !ok {
row = &models.CustomerBalanceListRow{
CariIlkGrup: meta.Kanal1,
Piyasa: meta.Piyasa,
Temsilci: meta.Temsilci,
Sirket: strconv.Itoa(ln.SirketKodu),
AnaCariKodu: master,
AnaCariAdi: firstNonEmpty(mm.CariDetay, meta.CariDetay),
CariKodu: cari,
CariDetay: meta.CariDetay,
CariTip: meta.CariTip,
Kanal1: meta.Kanal1,
Ozellik03: meta.RiskDurumu,
Ozellik05: meta.Ulke,
Ozellik06: meta.Il,
Ozellik07: meta.Ilce,
Il: meta.Il,
Ilce: meta.Ilce,
MuhasebeKodu: meta.MuhasebeKodu,
TC: meta.TC,
RiskDurumu: meta.RiskDurumu,
SirketDetay: meta.SirketDetay,
CariDoviz: curr,
}
agg[key] = row
}
usd := toUSD(ln.Bakiye, curr, usdTry, rateMap)
tl := toTRY(ln.Bakiye, curr, rateMap)
switch strings.TrimSpace(ln.PislemTipi) {
case "1_2":
row.Bakiye12 += ln.Bakiye
row.TLBakiye12 += tl
row.USDBakiye12 += usd
case "1_3":
row.Bakiye13 += ln.Bakiye
row.TLBakiye13 += tl
row.USDBakiye13 += usd
}
w := math.Abs(ln.Bakiye)
if w > 0 {
weightMap[key] += w
vadeSumMap[key] += (ln.VadeGun * w)
vadeBelgeSumMap[key] += (ln.VadeBelgeGun * w)
}
}
out := make([]models.CustomerBalanceListRow, 0, len(agg))
for k, v := range agg {
base := weightMap[k]
if base > 0 {
v.VadeGun = vadeSumMap[k] / base
v.VadeBelgeGun = vadeBelgeSumMap[k] / base
}
out = append(out, *v)
}
sort.Slice(out, func(i, j int) bool {
if out[i].AnaCariKodu == out[j].AnaCariKodu {
if out[i].CariKodu == out[j].CariKodu {
return out[i].CariDoviz < out[j].CariDoviz
}
return out[i].CariKodu < out[j].CariKodu
}
return out[i].AnaCariKodu < out[j].AnaCariKodu
})
_ = selectedDate
return out, nil
}
func loadAgingBalanceLines(ctx context.Context, cariSearch string) ([]mkCariBakiyeLine, error) {
query := `
SELECT
CurrAccTypeCode,
CariKodu = LTRIM(RTRIM(CariKodu)),
CariDoviz = LTRIM(RTRIM(CariDoviz)),
SirketKodu,
PislemTipi,
YerelBakiye = CAST(0 AS DECIMAL(18,2)),
Bakiye,
Vade_Gun,
Vade_BelgeTarihi_Gun
FROM dbo.CARI_BAKIYE_GUN_CACHE
WHERE (@CariSearch = '' OR LTRIM(RTRIM(CariKodu)) LIKE '%' + @CariSearch + '%')
ORDER BY CariKodu, CariDoviz, PislemTipi
`
rows, err := db.MssqlDB.QueryContext(ctx, query, sql.Named("CariSearch", strings.TrimSpace(cariSearch)))
if err != nil {
return nil, fmt.Errorf("CARI_BAKIYE_GUN_CACHE query error: %w", err)
}
defer rows.Close()
out := make([]mkCariBakiyeLine, 0, 4096)
for rows.Next() {
var r mkCariBakiyeLine
if err := rows.Scan(
&r.CurrAccTypeCode,
&r.CariKodu,
&r.CariDoviz,
&r.SirketKodu,
&r.PislemTipi,
&r.YerelBakiye,
&r.Bakiye,
&r.VadeGun,
&r.VadeBelgeGun,
); err != nil {
return nil, err
}
out = append(out, r)
}
if err := rows.Err(); err != nil {
return nil, err
}
return out, nil
}
func toTRY(amount float64, currency string, rateMap map[string]float64) float64 {
switch currency {
case "TRY":
return amount
case "":
return amount
default:
currTry := rateMap[currency]
if currTry <= 0 {
return 0
}
return amount * currTry
}
}