Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-02-27 11:47:51 +03:00
parent 15e51e9c39
commit 264f97a5c1
5 changed files with 265 additions and 212 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -12,9 +12,7 @@ import (
func GetStatements(params models.StatementParams) ([]models.StatementHeader, error) { func GetStatements(params models.StatementParams) ([]models.StatementHeader, error) {
// AccountCode normalize: "ZLA0127" → "ZLA 0127" // AccountCode normalize: "ZLA0127" → "ZLA 0127"
if len(params.AccountCode) == 7 && strings.ContainsAny(params.AccountCode, "0123456789") { params.AccountCode = normalizeMasterAccountCode(params.AccountCode)
params.AccountCode = params.AccountCode[:3] + " " + params.AccountCode[3:]
}
if strings.TrimSpace(params.LangCode) == "" { if strings.TrimSpace(params.LangCode) == "" {
params.LangCode = "TR" params.LangCode = "TR"
} }
@@ -58,7 +56,7 @@ HasMovement AS (
INNER JOIN CurrAccBookATAttributesFilter f INNER JOIN CurrAccBookATAttributesFilter f
ON f.CurrAccBookID = b.CurrAccBookID ON f.CurrAccBookID = b.CurrAccBookID
AND f.ATAtt01 IN (%s) 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 AND b.DocumentDate BETWEEN @startdate AND @enddate
) THEN 1 ELSE 0 END AS HasMov ) THEN 1 ELSE 0 END AS HasMov
), ),
@@ -80,7 +78,7 @@ Opening AS (
LEFT JOIN trCurrAccBookCurrency c LEFT JOIN trCurrAccBookCurrency c
ON c.CurrAccBookID = b.CurrAccBookID ON c.CurrAccBookID = b.CurrAccBookID
AND c.CurrencyCode = b.DocCurrencyCode AND c.CurrencyCode = b.DocCurrencyCode
WHERE b.CurrAccCode LIKE '%%' + @Carikod + '%%' WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
AND ( AND (
(hm.HasMov = 1 AND b.DocumentDate < @startdate) -- hareket varsa: klasik devir (hm.HasMov = 1 AND b.DocumentDate < @startdate) -- hareket varsa: klasik devir
OR (hm.HasMov = 0 AND b.DocumentDate <= @enddate) -- hareket yoksa: enddate itibariyle bakiye OR (hm.HasMov = 0 AND b.DocumentDate <= @enddate) -- hareket yoksa: enddate itibariyle bakiye
@@ -95,15 +93,16 @@ Opening AS (
========================================================= */ ========================================================= */
Movements AS ( Movements AS (
SELECT SELECT
@Carikod AS Cari_Kod, @Carikod AS Ana_Cari_Kod,
b.CurrAccCode AS Cari_Kod,
COALESCE( COALESCE(
(SELECT TOP 1 cd.CurrAccDescription (SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd FROM CurrDesc cd
WHERE cd.CurrAccCode = @Carikod), WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(b.CurrAccCode, ' ', '')),
(SELECT TOP 1 cd.CurrAccDescription (SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd FROM CurrDesc cd
WHERE cd.CurrAccCode LIKE '%%' + @Carikod + '%%' WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
ORDER BY cd.CurrAccCode) ORDER BY cd.CurrAccCode)
) AS Cari_Isim, ) AS Cari_Isim,
@@ -135,7 +134,7 @@ Movements AS (
ON c.CurrAccBookID = b.CurrAccBookID ON c.CurrAccBookID = b.CurrAccBookID
AND c.CurrencyCode = b.DocCurrencyCode 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 AND b.DocumentDate BETWEEN @startdate AND @enddate
) )
@@ -158,7 +157,7 @@ SELECT
FROM Movements m FROM Movements m
LEFT JOIN Opening o 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 AND o.Para_Birimi = m.Para_Birimi
UNION ALL UNION ALL
@@ -173,10 +172,10 @@ SELECT
COALESCE( COALESCE(
(SELECT TOP 1 cd.CurrAccDescription (SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd FROM CurrDesc cd
WHERE cd.CurrAccCode = @Carikod), WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(o.Cari_Kod, ' ', '')),
(SELECT TOP 1 cd.CurrAccDescription (SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd FROM CurrDesc cd
WHERE cd.CurrAccCode LIKE '%%' + @Carikod + '%%' WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
ORDER BY cd.CurrAccCode) ORDER BY cd.CurrAccCode)
) AS Cari_Isim, ) AS Cari_Isim,
@@ -241,3 +240,18 @@ ORDER BY
} }
return results, nil 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:]
}