package queries import ( "bssapp-backend/db" "bssapp-backend/models" "database/sql" "fmt" "strings" ) // Ana tabloyu getiren fonksiyon (Vue header tablosu için) 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:] } // Parislemler []string → '1','2','3' parislemFilter := "''" if len(params.Parislemler) > 0 { quoted := make([]string, 0, len(params.Parislemler)) for _, v := range params.Parislemler { v = strings.TrimSpace(v) if v == "" { continue } // Escape tek tırnak to avoid malformed SQL when list is injected into IN (...). quoted = append(quoted, fmt.Sprintf("'%s'", strings.ReplaceAll(v, "'", "''"))) } if len(quoted) > 0 { parislemFilter = strings.Join(quoted, ",") } } query := fmt.Sprintf(` ;WITH Opening AS ( SELECT b.CurrAccCode AS Cari_Kod, b.DocCurrencyCode AS Para_Birimi, SUM(c.Debit - c.Credit) AS Devir_Bakiyesi FROM trCurrAccBook b LEFT JOIN trCurrAccBookCurrency c ON c.CurrAccBookID = b.CurrAccBookID AND c.CurrencyCode = b.DocCurrencyCode WHERE b.CurrAccCode LIKE '%%' + @Carikod + '%%' AND b.DocumentDate < @startdate AND EXISTS ( SELECT 1 FROM CurrAccBookATAttributesFilter f2 WHERE f2.CurrAccBookID = b.CurrAccBookID AND f2.ATAtt01 IN (%s) ) GROUP BY b.CurrAccCode, b.DocCurrencyCode ), Movements AS ( SELECT b.CurrAccCode AS Cari_Kod, d.CurrAccDescription AS Cari_Isim, CONVERT(varchar(10), b.DocumentDate, 23) AS Belge_Tarihi, CONVERT(varchar(10), b.DueDate, 23) AS Vade_Tarihi, b.RefNumber AS Belge_No, b.BaseApplicationCode AS Islem_Tipi, b.LineDescription AS Aciklama, b.DocCurrencyCode AS Para_Birimi, c.Debit AS Borc, c.Credit AS Alacak, SUM(c.Debit - c.Credit) OVER ( PARTITION BY b.CurrAccCode, c.CurrencyCode ORDER BY b.DocumentDate, b.CurrAccBookID ) AS Hareket_Bakiyesi, f.ATAtt01 AS Parislemtipi FROM trCurrAccBook b LEFT JOIN cdCurrAccDesc d ON b.CurrAccCode = d.CurrAccCode LEFT JOIN trCurrAccBookCurrency c ON b.CurrAccBookID = c.CurrAccBookID AND b.DocCurrencyCode = c.CurrencyCode LEFT JOIN CurrAccBookATAttributesFilter f ON b.CurrAccBookID = f.CurrAccBookID WHERE b.CurrAccCode LIKE '%%' + @Carikod + '%%' AND b.DocumentDate BETWEEN @startdate AND @enddate AND EXISTS ( SELECT 1 FROM CurrAccBookATAttributesFilter f2 WHERE f2.CurrAccBookID = b.CurrAccBookID AND f2.ATAtt01 IN (%s) ) ) SELECT m.Cari_Kod, m.Cari_Isim, m.Belge_Tarihi, m.Vade_Tarihi, m.Belge_No, m.Islem_Tipi, m.Aciklama, m.Para_Birimi, m.Borc, m.Alacak, ISNULL(o.Devir_Bakiyesi,0) + m.Hareket_Bakiyesi AS Bakiye, m.Parislemtipi AS Parislemler FROM Movements m LEFT JOIN Opening o ON o.Cari_Kod = m.Cari_Kod AND o.Para_Birimi = m.Para_Birimi UNION ALL /* ✅ Devir satırı sadece Opening’den */ SELECT o.Cari_Kod, d.CurrAccDescription, CONVERT(varchar(10), @startdate, 23), CONVERT(varchar(10), @startdate, 23), 'Baslangic_devir', 'Devir', 'Devir Bakiyesi', o.Para_Birimi, CASE WHEN o.Devir_Bakiyesi >= 0 THEN o.Devir_Bakiyesi ELSE 0 END, CASE WHEN o.Devir_Bakiyesi < 0 THEN ABS(o.Devir_Bakiyesi) ELSE 0 END, o.Devir_Bakiyesi, CAST(NULL AS varchar(32)) AS Parislemler FROM Opening o LEFT JOIN cdCurrAccDesc d ON d.CurrAccCode = o.Cari_Kod ORDER BY Para_Birimi, Belge_Tarihi; `, parislemFilter, parislemFilter, ) rows, err := db.MssqlDB.Query(query, sql.Named("startdate", params.StartDate), sql.Named("enddate", params.EndDate), sql.Named("Carikod", params.AccountCode), sql.Named("LangCode", params.LangCode), ) if err != nil { return nil, fmt.Errorf("MSSQL query error: %v", err) } defer rows.Close() var results []models.StatementHeader for rows.Next() { var r models.StatementHeader if err := rows.Scan( &r.CariKod, &r.CariIsim, &r.BelgeTarihi, &r.VadeTarihi, &r.BelgeNo, &r.IslemTipi, &r.Aciklama, &r.ParaBirimi, &r.Borc, &r.Alacak, &r.Bakiye, &r.Parislemler, ); err != nil { return nil, err } results = append(results, r) } return results, nil }