From 264f97a5c1ae0fc993f954d5fa09767b37b98105 Mon Sep 17 00:00:00 2001 From: M_Kececi Date: Fri, 27 Feb 2026 11:47:51 +0300 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- svc/queries/account_balance_fast.go | 91 ++++++++++++ svc/queries/account_master.go | 79 +++++++++++ svc/queries/customer_balance_list.go | 200 --------------------------- svc/queries/fast_balance.go | 69 +++++++++ svc/queries/statement_header.go | 38 +++-- 5 files changed, 265 insertions(+), 212 deletions(-) create mode 100644 svc/queries/account_balance_fast.go create mode 100644 svc/queries/account_master.go delete mode 100644 svc/queries/customer_balance_list.go create mode 100644 svc/queries/fast_balance.go diff --git a/svc/queries/account_balance_fast.go b/svc/queries/account_balance_fast.go new file mode 100644 index 0000000..4152f9c --- /dev/null +++ b/svc/queries/account_balance_fast.go @@ -0,0 +1,91 @@ +package queries + +import ( + "bssapp-backend/models" + "context" +) + +func GetCustomerBalanceList( + ctx context.Context, + params models.CustomerBalanceListParams, +) ([]models.CustomerBalanceListRow, error) { + + //------------------------------------------------ + // 1️⃣ DATA ÇEK + //------------------------------------------------ + + balances, err := getFastBalances(ctx, params.SelectedDate) + if err != nil { + return nil, err + } + + masterMap, err := getCariMasterMap(ctx) + if err != nil { + return nil, err + } + + //------------------------------------------------ + // 2️⃣ MERGE + //------------------------------------------------ + + resultMap := make(map[string]*models.CustomerBalanceListRow) + + for _, b := range balances { + + key := b.CariKodu + "|" + b.CariDoviz + + r, ok := resultMap[key] + if !ok { + + r = &models.CustomerBalanceListRow{ + CariKodu: b.CariKodu, + CariDoviz: b.CariDoviz, + } + + // Master + if m, ok := masterMap[b.CariKodu]; ok { + + r.CariDetay = m.CariDetay + r.Piyasa = m.Piyasa + r.Temsilci = m.Temsilci + + r.Ozellik03 = m.Ozellik03 + r.Ozellik05 = m.Ozellik05 + r.Ozellik06 = m.Ozellik06 + r.Ozellik07 = m.Ozellik07 + r.CariIlkGrup = m.Ozellik08 + } + + resultMap[key] = r + } + + //------------------------------------------------ + // 3️⃣ TOPLA + //------------------------------------------------ + + if b.PislemTipi == "1_2" { + + r.Bakiye12 += b.Bakiye + r.TLBakiye12 += b.KurBakiye + r.USDBakiye12 += b.KurBakiye / b.UsdKur + + } else if b.PislemTipi == "1_3" { + + r.Bakiye13 += b.Bakiye + r.TLBakiye13 += b.KurBakiye + r.USDBakiye13 += b.KurBakiye / b.UsdKur + } + } + + //------------------------------------------------ + // 4️⃣ SLICE DÖN + //------------------------------------------------ + + out := make([]models.CustomerBalanceListRow, 0, len(resultMap)) + + for _, v := range resultMap { + out = append(out, *v) + } + + return out, nil +} diff --git a/svc/queries/account_master.go b/svc/queries/account_master.go new file mode 100644 index 0000000..fee80e0 --- /dev/null +++ b/svc/queries/account_master.go @@ -0,0 +1,79 @@ +package queries + +import ( + "bssapp-backend/db" + "context" +) + +type CariMasterRow struct { + CariKodu string + CariDetay string + Piyasa string + Temsilci string + Ozellik03 string + Ozellik05 string + Ozellik06 string + Ozellik07 string + Ozellik08 string +} + +func getCariMasterMap( + ctx context.Context, +) (map[string]CariMasterRow, error) { + + const q = ` + WITH CTE AS ( + SELECT + *, + rn = ROW_NUMBER() OVER ( + PARTITION BY LEFT(CariKodu,8) + ORDER BY CariKodu + ) + FROM dbo.MK_CARI_ILETISIM WITH(NOLOCK) + ) + SELECT + CariKodu, + CariDetay, + PIYASA, + CARI_TEMSILCI, + Ozellik03, + Ozellik05, + Ozellik06, + Ozellik07, + Ozellik08 + FROM CTE + WHERE rn=1 + ` + + rows, err := db.MssqlDB.QueryContext(ctx, q) + if err != nil { + return nil, err + } + defer rows.Close() + + out := make(map[string]CariMasterRow, 4096) + + for rows.Next() { + + var r CariMasterRow + + err := rows.Scan( + &r.CariKodu, + &r.CariDetay, + &r.Piyasa, + &r.Temsilci, + &r.Ozellik03, + &r.Ozellik05, + &r.Ozellik06, + &r.Ozellik07, + &r.Ozellik08, + ) + if err != nil { + return nil, err + } + + out[r.CariKodu] = r + } + + return out, nil +} diff --git a/svc/queries/customer_balance_list.go b/svc/queries/customer_balance_list.go deleted file mode 100644 index a6d1539..0000000 --- a/svc/queries/customer_balance_list.go +++ /dev/null @@ -1,200 +0,0 @@ -package queries - -import ( - "bssapp-backend/db" - "bssapp-backend/internal/authz" - "bssapp-backend/models" - "context" - "database/sql" - "fmt" - "strings" -) - -func GetCustomerBalanceList(ctx context.Context, params models.CustomerBalanceListParams) ([]models.CustomerBalanceListRow, error) { - // AuthZ bazli piyasa filtresi - piyasaFilter := authz.BuildMSSQLPiyasaFilter(ctx, "D.Ozellik01") - if strings.TrimSpace(piyasaFilter) == "" { - piyasaFilter = "1=1" - } - - // Dinamik WHERE insa et - where := make([]string, 0, 16) - where = append(where, "D.Islem_Tarihi < DATEADD(DAY, 1, @SecilenTarih)") - where = append(where, piyasaFilter) - - if params.CariIlkGrup != "" { - where = append(where, "D.Ozellik08 = @CariIlkGrup") - } - if params.Piyasa != "" { - where = append(where, "D.Ozellik01 = @Piyasa") - } - if params.Temsilci != "" { - where = append(where, "COALESCE(NULLIF(D.Ozellik02, ''), D.Ozellik09) = @Temsilci") - } - if params.RiskDurumu != "" { - where = append(where, "D.Ozellik03 = @RiskDurumu") - } - if params.IslemTipi != "" { - where = append(where, "D.PislemTipi = @IslemTipi") - } - if params.Ulke != "" { - where = append(where, "D.Ozellik05 = @Ulke") - } - whereSQL := strings.Join(where, "\n AND ") - cariSearchLike := "%" + strings.TrimSpace(params.CariSearch) + "%" - outerWhere := "1=1" - if strings.TrimSpace(params.CariSearch) != "" { - outerWhere = `(LEFT(B.CariKodu, 8) COLLATE Turkish_100_CI_AI LIKE @CariSearchLike - OR B.CariKodu COLLATE Turkish_100_CI_AI LIKE @CariSearchLike - OR B.CariDetay COLLATE Turkish_100_CI_AI LIKE @CariSearchLike - OR AC.ANA_CARI_ADI COLLATE Turkish_100_CI_AI LIKE @CariSearchLike)` - } - - const queryTemplate = ` -;WITH CTE_ANA_CARI AS ( - SELECT - ANA_CARI_KODU = LEFT(CariKodu, 8), - CariDetay, - rn = ROW_NUMBER() OVER ( - PARTITION BY LEFT(CariKodu, 8) - ORDER BY CariKodu - ) - FROM dbo.MK_CARI_ILETISIM WITH (NOLOCK) -), -ANA_CARI AS ( - SELECT - ANA_CARI_KODU, - CariDetay AS ANA_CARI_ADI - FROM CTE_ANA_CARI - WHERE rn = 1 -), -BASE AS ( - SELECT - D.SirketKodu, - D.SirketDetay, - D.CariKodu, - D.CariDetay, - D.CariDoviz, - D.Ozellik01, - D.Ozellik02, - D.Ozellik03, - D.Ozellik05, - D.Ozellik06, - D.Ozellik07, - D.Ozellik08, - D.Ozellik09, - D.PislemTipi, - D.Bakiye, - D.KurBakiye, - D.Son_Guncel_Kur - FROM dbo.DENEME02DENEME AS D WITH (NOLOCK) - WHERE %s -) -SELECT - B.Ozellik08 AS CARI_ILK_GRUP, - B.Ozellik01 AS PIYASA, - COALESCE(NULLIF(B.Ozellik02, ''), B.Ozellik09) AS Temsilci, - LEFT(B.SirketDetay, 10) AS Sirket, - LEFT(B.CariKodu, 8) AS ANA_CARI_KODU, - AC.ANA_CARI_ADI, - B.CariKodu, - B.CariDetay, - B.Ozellik03, - B.Ozellik05, - B.Ozellik06, - B.Ozellik07, - B.CariDoviz, - ISNULL(SUM(CASE WHEN B.PislemTipi = '1_2' THEN ISNULL(B.Bakiye, 0) ELSE 0 END), 0) AS Bakiye_1_2, - ISNULL(SUM(CASE WHEN B.PislemTipi = '1_2' THEN ISNULL(B.KurBakiye, 0) ELSE 0 END), 0) AS TL_Bakiye_1_2, - ISNULL( - SUM(CASE WHEN B.PislemTipi = '1_2' THEN ISNULL(B.KurBakiye, 0) ELSE 0 END) / NULLIF(MIN(B.Son_Guncel_Kur), 0), - 0 - ) AS USD_Bakiye_1_2, - ISNULL(SUM(CASE WHEN B.PislemTipi = '1_3' THEN ISNULL(B.Bakiye, 0) ELSE 0 END), 0) AS Bakiye_1_3, - ISNULL(SUM(CASE WHEN B.PislemTipi = '1_3' THEN ISNULL(B.KurBakiye, 0) ELSE 0 END), 0) AS TL_Bakiye_1_3, - ISNULL( - SUM(CASE WHEN B.PislemTipi = '1_3' THEN ISNULL(B.KurBakiye, 0) ELSE 0 END) / NULLIF(MIN(B.Son_Guncel_Kur), 0), - 0 - ) AS USD_Bakiye_1_3, - CAST(NULL AS int) AS Hesap_Alinmayan_Gun, - CAST(NULL AS varchar(32)) AS Kalan_Fatura_Ortalama_Vade_Tarihi -FROM BASE AS B -LEFT JOIN ANA_CARI AS AC - ON AC.ANA_CARI_KODU = LEFT(B.CariKodu, 8) -WHERE %s -GROUP BY - B.Ozellik08, - B.Ozellik01, - COALESCE(NULLIF(B.Ozellik02, ''), B.Ozellik09), - LEFT(B.SirketDetay, 10), - LEFT(B.CariKodu, 8), - AC.ANA_CARI_ADI, - B.CariKodu, - B.CariDetay, - B.Ozellik03, - B.Ozellik05, - B.Ozellik06, - B.Ozellik07, - B.CariDoviz -ORDER BY - LEFT(B.SirketDetay, 10), - B.CariKodu -OPTION (RECOMPILE); -` - query := fmt.Sprintf(queryTemplate, whereSQL, outerWhere) - - rows, err := db.MssqlDB.QueryContext( - ctx, - query, - sql.Named("SecilenTarih", params.SelectedDate), - sql.Named("CariIlkGrup", params.CariIlkGrup), - sql.Named("Piyasa", params.Piyasa), - sql.Named("Temsilci", params.Temsilci), - sql.Named("RiskDurumu", params.RiskDurumu), - sql.Named("IslemTipi", params.IslemTipi), - sql.Named("Ulke", params.Ulke), - sql.Named("CariSearchLike", cariSearchLike), - ) - if err != nil { - return nil, fmt.Errorf("MSSQL query error: %w", err) - } - defer rows.Close() - - out := make([]models.CustomerBalanceListRow, 0, 512) - - for rows.Next() { - var r models.CustomerBalanceListRow - if err := rows.Scan( - &r.CariIlkGrup, - &r.Piyasa, - &r.Temsilci, - &r.Sirket, - &r.AnaCariKodu, - &r.AnaCariAdi, - &r.CariKodu, - &r.CariDetay, - &r.Ozellik03, - &r.Ozellik05, - &r.Ozellik06, - &r.Ozellik07, - &r.CariDoviz, - &r.Bakiye12, - &r.TLBakiye12, - &r.USDBakiye12, - &r.Bakiye13, - &r.TLBakiye13, - &r.USDBakiye13, - &r.HesapAlinmayanGun, - &r.KalanFaturaOrtalamaVadeTarihi, - ); err != nil { - return nil, fmt.Errorf("row scan error: %w", err) - } - out = append(out, r) - } - - if err := rows.Err(); err != nil { - return nil, fmt.Errorf("rows iteration error: %w", err) - } - - return out, nil -} diff --git a/svc/queries/fast_balance.go b/svc/queries/fast_balance.go new file mode 100644 index 0000000..871dd0a --- /dev/null +++ b/svc/queries/fast_balance.go @@ -0,0 +1,69 @@ +package queries + +import ( + "bssapp-backend/db" + "context" + "database/sql" +) + +type FastBalanceRow struct { + CariKodu string + CariDoviz string + PislemTipi string + SirketKodu int + YerelBakiye float64 + Bakiye float64 + IslemTarihi string + IslemKur float64 + TLBakiye float64 + TLYerel float64 + GuncelKur float64 + KurBakiye float64 + UsdKur float64 +} + +func getFastBalances( + ctx context.Context, + date string, +) ([]FastBalanceRow, error) { + + rows, err := db.MssqlDB.QueryContext( + ctx, + `EXEC dbo.SP_CARI_BAKIYE_API_FAST @Tarih`, + sql.Named("Tarih", date), + ) + if err != nil { + return nil, err + } + defer rows.Close() + + out := make([]FastBalanceRow, 0, 4096) + + for rows.Next() { + + var r FastBalanceRow + + err := rows.Scan( + &r.CariKodu, + &r.CariDoviz, + &r.PislemTipi, + &r.SirketKodu, + &r.YerelBakiye, + &r.Bakiye, + &r.IslemTarihi, + &r.IslemKur, + &r.TLBakiye, + &r.TLYerel, + &r.GuncelKur, + &r.KurBakiye, + &r.UsdKur, + ) + if err != nil { + return nil, err + } + + out = append(out, r) + } + + return out, nil +} diff --git a/svc/queries/statement_header.go b/svc/queries/statement_header.go index e6d9a04..d9ad308 100644 --- a/svc/queries/statement_header.go +++ b/svc/queries/statement_header.go @@ -12,9 +12,7 @@ import ( func GetStatements(params models.StatementParams) ([]models.StatementHeader, error) { // AccountCode normalize: "ZLA0127" → "ZLA 0127" - if len(params.AccountCode) == 7 && strings.ContainsAny(params.AccountCode, "0123456789") { - params.AccountCode = params.AccountCode[:3] + " " + params.AccountCode[3:] - } + params.AccountCode = normalizeMasterAccountCode(params.AccountCode) if strings.TrimSpace(params.LangCode) == "" { params.LangCode = "TR" } @@ -58,7 +56,7 @@ HasMovement AS ( INNER JOIN CurrAccBookATAttributesFilter f ON f.CurrAccBookID = b.CurrAccBookID AND f.ATAtt01 IN (%s) - WHERE b.CurrAccCode LIKE '%%' + @Carikod + '%%' + WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '') AND b.DocumentDate BETWEEN @startdate AND @enddate ) THEN 1 ELSE 0 END AS HasMov ), @@ -80,7 +78,7 @@ Opening AS ( LEFT JOIN trCurrAccBookCurrency c ON c.CurrAccBookID = b.CurrAccBookID AND c.CurrencyCode = b.DocCurrencyCode - WHERE b.CurrAccCode LIKE '%%' + @Carikod + '%%' + WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '') AND ( (hm.HasMov = 1 AND b.DocumentDate < @startdate) -- hareket varsa: klasik devir OR (hm.HasMov = 0 AND b.DocumentDate <= @enddate) -- hareket yoksa: enddate itibariyle bakiye @@ -95,15 +93,16 @@ Opening AS ( ========================================================= */ Movements AS ( SELECT - @Carikod AS Cari_Kod, + @Carikod AS Ana_Cari_Kod, + b.CurrAccCode AS Cari_Kod, COALESCE( (SELECT TOP 1 cd.CurrAccDescription FROM CurrDesc cd - WHERE cd.CurrAccCode = @Carikod), + WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(b.CurrAccCode, ' ', '')), (SELECT TOP 1 cd.CurrAccDescription FROM CurrDesc cd - WHERE cd.CurrAccCode LIKE '%%' + @Carikod + '%%' + WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '') ORDER BY cd.CurrAccCode) ) AS Cari_Isim, @@ -135,7 +134,7 @@ Movements AS ( ON c.CurrAccBookID = b.CurrAccBookID AND c.CurrencyCode = b.DocCurrencyCode - WHERE b.CurrAccCode LIKE '%%' + @Carikod + '%%' + WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '') AND b.DocumentDate BETWEEN @startdate AND @enddate ) @@ -158,7 +157,7 @@ SELECT FROM Movements m LEFT JOIN Opening o - ON o.Cari_Kod = m.Cari_Kod + ON o.Cari_Kod = m.Ana_Cari_Kod AND o.Para_Birimi = m.Para_Birimi UNION ALL @@ -173,10 +172,10 @@ SELECT COALESCE( (SELECT TOP 1 cd.CurrAccDescription FROM CurrDesc cd - WHERE cd.CurrAccCode = @Carikod), + WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(o.Cari_Kod, ' ', '')), (SELECT TOP 1 cd.CurrAccDescription FROM CurrDesc cd - WHERE cd.CurrAccCode LIKE '%%' + @Carikod + '%%' + WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '') ORDER BY cd.CurrAccCode) ) AS Cari_Isim, @@ -241,3 +240,18 @@ ORDER BY } return results, nil } + +func normalizeMasterAccountCode(code string) string { + code = strings.ToUpper(strings.TrimSpace(code)) + if code == "" { + return code + } + + noSpace := strings.ReplaceAll(code, " ", "") + if len(noSpace) < 7 { + return code + } + + main := noSpace[:7] + return main[:3] + " " + main[3:] +}