Files
bssapp/svc/queries/statement_header.go
2026-04-16 15:18:44 +03:00

300 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package queries
import (
"bssapp-backend/db"
"bssapp-backend/internal/i18n"
"bssapp-backend/models"
"context"
"database/sql"
"fmt"
"strings"
)
// Ana tabloyu getiren fonksiyon (Vue header tablosu için)
func GetStatements(ctx context.Context, params models.StatementParams) ([]models.StatementHeader, error) {
// AccountCode normalize: "ZLA0127" → "ZLA 0127"
params.AccountCode = normalizeMasterAccountCode(params.AccountCode)
params.LangCode = i18n.NormalizeLangCode(params.LangCode)
// 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
}
quoted = append(quoted, fmt.Sprintf("'%s'", strings.ReplaceAll(v, "'", "''")))
}
if len(quoted) > 0 {
parislemFilter = strings.Join(quoted, ",")
}
}
customerPiyasaInClause, err := resolvePiyasaScopeInClause(ctx, "PF.CustomerAtt01")
if err != nil {
return nil, err
}
vendorPiyasaInClause, err := resolvePiyasaScopeInClause(ctx, "VF.VendorAtt01")
if err != nil {
return nil, err
}
piyasaScope := fmt.Sprintf(`
(
(b.CurrAccTypeCode = 3 AND EXISTS (
SELECT 1
FROM CustomerAttributesFilter PF WITH (NOLOCK)
WHERE (PF.CurrAccCode = b.CurrAccCode OR LEFT(PF.CurrAccCode, 8) = LEFT(b.CurrAccCode, 8))
AND %s
))
OR
(b.CurrAccTypeCode = 1 AND EXISTS (
SELECT 1
FROM (
SELECT
CurrAccCode,
VendorAtt01 = MAX(CASE WHEN AttributeTypeCode = 1 THEN AttributeCode END)
FROM prCurrAccAttribute WITH (NOLOCK)
WHERE CurrAccTypeCode = 1
GROUP BY CurrAccCode
) VF
WHERE (VF.CurrAccCode = b.CurrAccCode OR LEFT(VF.CurrAccCode, 8) = LEFT(b.CurrAccCode, 8))
AND %s
))
)`, customerPiyasaInClause, vendorPiyasaInClause)
query := fmt.Sprintf(`
;WITH CurrDesc AS (
SELECT
CurrAccCode,
MAX(CurrAccDescription) AS CurrAccDescription
FROM cdCurrAccDesc
WHERE LangCode = @LangCode
GROUP BY CurrAccCode
),
/* =========================================================
✅ Bu aralıkta hareket var mı?
Varsa : Devir = startdate öncesi
Yoksa : Devir = enddate dahil (enddate itibariyle bakiye)
========================================================= */
HasMovement AS (
SELECT
CASE WHEN EXISTS (
SELECT 1
FROM trCurrAccBook b
INNER JOIN CurrAccBookATAttributesFilter f
ON f.CurrAccBookID = b.CurrAccBookID
AND f.ATAtt01 IN (%s)
WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = LEFT(REPLACE(@Carikod, ' ', ''), 7)
AND b.DocumentDate BETWEEN @startdate AND @enddate
AND %s
) THEN 1 ELSE 0 END AS HasMov
),
/* =========================================================
✅ Opening (Devir) — TEK CARİ KOD ALTINDA KONSOLİDE
Cari_Kod = @Carikod (sabit)
========================================================= */
Opening AS (
SELECT
@Carikod AS Cari_Kod,
b.DocCurrencyCode AS Para_Birimi,
SUM(ISNULL(c.Debit,0) - ISNULL(c.Credit,0)) AS Devir_Bakiyesi
FROM trCurrAccBook b
CROSS JOIN HasMovement hm
INNER JOIN CurrAccBookATAttributesFilter f2
ON f2.CurrAccBookID = b.CurrAccBookID
AND f2.ATAtt01 IN (%s)
LEFT JOIN trCurrAccBookCurrency c
ON c.CurrAccBookID = b.CurrAccBookID
AND c.CurrencyCode = b.DocCurrencyCode
WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = LEFT(REPLACE(@Carikod, ' ', ''), 7)
AND @ExcludeOpening = 0
AND %s
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
)
GROUP BY b.DocCurrencyCode
),
/* =========================================================
✅ Hareketler (Movements) — TEK CARİ KOD ALTINDA KONSOLİDE
Cari_Kod = @Carikod (sabit)
Running sadece aralıktaki hareketlerden gelir.
========================================================= */
Movements AS (
SELECT
@Carikod AS Ana_Cari_Kod,
b.CurrAccCode AS Cari_Kod,
COALESCE(
(SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd
WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(b.CurrAccCode, ' ', '')),
(SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd
WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
ORDER BY cd.CurrAccCode)
) 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,
ISNULL(c.Debit,0) AS Borc,
ISNULL(c.Credit,0) AS Alacak,
SUM(ISNULL(c.Debit,0) - ISNULL(c.Credit,0))
OVER (
PARTITION BY b.DocCurrencyCode
ORDER BY b.DocumentDate, b.CurrAccBookID
) AS Hareket_Bakiyesi,
f.ATAtt01 AS Parislemtipi
FROM trCurrAccBook b
INNER JOIN CurrAccBookATAttributesFilter f
ON f.CurrAccBookID = b.CurrAccBookID
AND f.ATAtt01 IN (%s)
LEFT JOIN trCurrAccBookCurrency c
ON c.CurrAccBookID = b.CurrAccBookID
AND c.CurrencyCode = b.DocCurrencyCode
WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = LEFT(REPLACE(@Carikod, ' ', ''), 7)
AND %s
AND b.DocumentDate BETWEEN @startdate AND @enddate
)
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,
/* ✅ Bakiye = Devir + Aralıktaki Running */
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.Ana_Cari_Kod
AND o.Para_Birimi = m.Para_Birimi
UNION ALL
/* =========================================================
✅ Devir Satırı (kur bazında) — Opening'den gelir
Hareket varsa: startdate öncesi
Hareket yoksa: enddate itibariyle bakiye
========================================================= */
SELECT
o.Cari_Kod,
COALESCE(
(SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd
WHERE REPLACE(cd.CurrAccCode, ' ', '') = REPLACE(o.Cari_Kod, ' ', '')),
(SELECT TOP 1 cd.CurrAccDescription
FROM CurrDesc cd
WHERE LEFT(REPLACE(cd.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
ORDER BY cd.CurrAccCode)
) AS Cari_Isim,
CONVERT(varchar(10), @startdate, 23) AS Belge_Tarihi,
CONVERT(varchar(10), @startdate, 23) AS Vade_Tarihi,
'Baslangic_devir' AS Belge_No,
CASE WHEN @LangCode = 'EN' THEN 'Opening' ELSE 'Devir' END AS Islem_Tipi,
CASE WHEN @LangCode = 'EN' THEN 'Opening Balance' ELSE 'Devir Bakiyesi' END AS Aciklama,
o.Para_Birimi,
CASE WHEN o.Devir_Bakiyesi >= 0 THEN o.Devir_Bakiyesi ELSE 0 END AS Borc,
CASE WHEN o.Devir_Bakiyesi < 0 THEN ABS(o.Devir_Bakiyesi) ELSE 0 END AS Alacak,
o.Devir_Bakiyesi AS Bakiye,
CAST(NULL AS varchar(32)) AS Parislemler
FROM Opening o
ORDER BY
Para_Birimi,
Belge_Tarihi;
`,
parislemFilter, // HasMovement ATAtt01
piyasaScope, // HasMovement piyasa scope
parislemFilter, // Opening ATAtt01
piyasaScope, // Opening piyasa scope
parislemFilter, // Movements ATAtt01
piyasaScope, // Movements piyasa scope
)
rows, err := db.MssqlDB.QueryContext(ctx, query,
sql.Named("startdate", params.StartDate),
sql.Named("enddate", params.EndDate),
sql.Named("Carikod", params.AccountCode),
sql.Named("LangCode", params.LangCode),
sql.Named("ExcludeOpening", params.ExcludeOpening),
)
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
}
func normalizeMasterAccountCode(code string) string {
code = strings.ToUpper(strings.TrimSpace(code))
if code == "" {
return code
}
noSpace := strings.ReplaceAll(code, " ", "")
r := []rune(noSpace)
if len(r) < 7 {
return code
}
main := r[:7]
return string(main[:3]) + " " + string(main[3:])
}