Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -15,59 +14,34 @@ import (
|
||||
|
||||
func GetStatementAging(params models.StatementAgingParams) ([]map[string]interface{}, error) {
|
||||
accountCode := normalizeMasterAccountCode(params.AccountCode)
|
||||
if strings.TrimSpace(params.EndDate) == "" {
|
||||
return nil, fmt.Errorf("enddate is required")
|
||||
}
|
||||
|
||||
useType2, useType3 := resolveUseTypes(params.Parislemler)
|
||||
endDateText := strings.TrimSpace(params.EndDate)
|
||||
if endDateText == "" {
|
||||
endDateText = time.Now().Format("2006-01-02")
|
||||
rateMap, err := loadNearestTryRates(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endDate, _ := time.Parse("2006-01-02", endDateText)
|
||||
|
||||
cariFilter := ""
|
||||
if strings.TrimSpace(accountCode) != "" {
|
||||
cariFilter = strings.TrimSpace(accountCode)
|
||||
usdTry := rateMap["USD"]
|
||||
if usdTry <= 0 {
|
||||
usdTry = 1
|
||||
}
|
||||
|
||||
rows, err := db.MssqlDB.Query(`
|
||||
SELECT TOP (100)
|
||||
Cari8 = LEFT(LTRIM(RTRIM(CariKodu)), 8),
|
||||
CariDetay = LTRIM(RTRIM(CariKodu)),
|
||||
FaturaCari = LTRIM(RTRIM(CariKodu)),
|
||||
OdemeCari = LTRIM(RTRIM(CariKodu)),
|
||||
FaturaRef = CAST(NULL AS NVARCHAR(50)),
|
||||
OdemeRef = CAST(NULL AS NVARCHAR(50)),
|
||||
FaturaTarihi = CAST(NULL AS DATE),
|
||||
OdemeTarihi = CAST(NULL AS DATE),
|
||||
OdemeDocDate = CAST(NULL AS DATE),
|
||||
EslesenTutar = CAST(Bakiye AS DECIMAL(18,2)),
|
||||
GunSayisi = CAST(Vade_Gun AS DECIMAL(18,2)),
|
||||
GunSayisi_DocDate = CAST(Vade_BelgeTarihi_Gun AS DECIMAL(18,2)),
|
||||
Aciklama = CAST('AcikKalem' AS NVARCHAR(30)),
|
||||
DocCurrencyCode = LTRIM(RTRIM(CariDoviz)),
|
||||
PislemTipi,
|
||||
SirketKodu,
|
||||
CurrAccTypeCode,
|
||||
Bakiye,
|
||||
Vade_Gun,
|
||||
Vade_BelgeTarihi_Gun,
|
||||
SonTarih,
|
||||
HesaplamaTarihi
|
||||
FROM dbo.CARI_BAKIYE_GUN_CACHE
|
||||
WHERE
|
||||
(
|
||||
(@UseType2 = 1 AND PislemTipi = '1_2')
|
||||
OR
|
||||
(@UseType3 = 1 AND PislemTipi = '1_3')
|
||||
)
|
||||
AND (@CariFilter = '' OR LTRIM(RTRIM(CariKodu)) LIKE @CariFilter + '%')
|
||||
ORDER BY CariKodu, CariDoviz, PislemTipi;
|
||||
EXEC dbo.SP_FIFO_MATCH_FINAL
|
||||
@Cari8 = @Cari8,
|
||||
@SonTarih = @SonTarih,
|
||||
@UseType2 = @UseType2,
|
||||
@UseType3 = @UseType3;
|
||||
`,
|
||||
sql.Named("Cari8", accountCode),
|
||||
sql.Named("SonTarih", params.EndDate),
|
||||
sql.Named("UseType2", useType2),
|
||||
sql.Named("UseType3", useType3),
|
||||
sql.Named("CariFilter", cariFilter),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CARI_BAKIYE_GUN_CACHE query error: %w", err)
|
||||
return nil, fmt.Errorf("SP_FIFO_MATCH_FINAL query error: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -78,7 +52,6 @@ func GetStatementAging(params models.StatementAgingParams) ([]map[string]interfa
|
||||
|
||||
result := make([]map[string]interface{}, 0, 2048)
|
||||
cari8Set := make(map[string]struct{})
|
||||
currencySet := make(map[string]struct{})
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, len(columns))
|
||||
scanArgs := make([]interface{}, len(columns))
|
||||
@@ -108,11 +81,6 @@ func GetStatementAging(params models.StatementAgingParams) ([]map[string]interfa
|
||||
if cari8 != "" {
|
||||
cari8Set[cari8] = struct{}{}
|
||||
}
|
||||
curr := strings.ToUpper(strings.TrimSpace(asString(row["DocCurrencyCode"])))
|
||||
if curr != "" && curr != "TRY" {
|
||||
currencySet[curr] = struct{}{}
|
||||
}
|
||||
currencySet["USD"] = struct{}{}
|
||||
|
||||
result = append(result, row)
|
||||
}
|
||||
@@ -125,10 +93,6 @@ func GetStatementAging(params models.StatementAgingParams) ([]map[string]interfa
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rateSeriesByCurr, err := loadTryRateSeriesByCurrency(context.Background(), currencySet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range result {
|
||||
row := result[i]
|
||||
@@ -137,25 +101,13 @@ func GetStatementAging(params models.StatementAgingParams) ([]map[string]interfa
|
||||
if curr == "" {
|
||||
curr = "TRY"
|
||||
}
|
||||
aciklama := strings.ToUpper(strings.TrimSpace(asString(row["Aciklama"])))
|
||||
targetDate := endDate
|
||||
if aciklama != "ACIKKALEM" {
|
||||
if odemeTarihi, ok := parseDateOnly(asString(row["OdemeTarihi"])); ok {
|
||||
targetDate = odemeTarihi
|
||||
}
|
||||
}
|
||||
|
||||
tutar := asFloat64(row["EslesenTutar"])
|
||||
currTry := resolveTryRate(curr, targetDate, rateSeriesByCurr)
|
||||
usdTry := resolveTryRate("USD", targetDate, rateSeriesByCurr)
|
||||
tryTutar := toTRYByRate(tutar, curr, currTry)
|
||||
usdTutar := toUSDByRates(tutar, curr, currTry, usdTry)
|
||||
gunKur := usdRateInCurrency(curr, currTry, usdTry)
|
||||
usdTutar := toUSD(tutar, curr, usdTry, rateMap)
|
||||
|
||||
row["CariDetay"] = cariDetailMap[cari8]
|
||||
row["UsdTutar"] = round2(usdTutar)
|
||||
row["TryTutar"] = round2(tryTutar)
|
||||
row["GunKur"] = round6(gunKur)
|
||||
row["CurrencyTryRate"] = round6(rateMap[curr])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@@ -306,138 +258,3 @@ func round2(v float64) float64 {
|
||||
func round6(v float64) float64 {
|
||||
return math.Round(v*1_000_000) / 1_000_000
|
||||
}
|
||||
|
||||
type ratePoint struct {
|
||||
date time.Time
|
||||
rate float64
|
||||
}
|
||||
|
||||
func loadTryRateSeriesByCurrency(ctx context.Context, currencies map[string]struct{}) (map[string][]ratePoint, error) {
|
||||
if len(currencies) == 0 {
|
||||
return map[string][]ratePoint{}, nil
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT CurrencyCode, Rate, CAST([Date] AS date) AS RateDate
|
||||
FROM AllExchangeRates
|
||||
WHERE RelationCurrencyCode = 'TRY'
|
||||
AND ExchangeTypeCode = 6
|
||||
AND Rate > 0
|
||||
AND CurrencyCode IN (%s)
|
||||
`, quotedInList(currencies))
|
||||
|
||||
rows, err := db.MssqlDB.QueryContext(ctx, query)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aging currency series query error: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
out := make(map[string][]ratePoint, len(currencies))
|
||||
for rows.Next() {
|
||||
var code string
|
||||
var rate float64
|
||||
var dt time.Time
|
||||
if err := rows.Scan(&code, &rate, &dt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code = strings.ToUpper(strings.TrimSpace(code))
|
||||
out[code] = append(out[code], ratePoint{date: dt, rate: rate})
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for c := range out {
|
||||
sort.Slice(out[c], func(i, j int) bool { return out[c][i].date.Before(out[c][j].date) })
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func resolveTryRate(currency string, target time.Time, series map[string][]ratePoint) float64 {
|
||||
currency = strings.ToUpper(strings.TrimSpace(currency))
|
||||
if currency == "" || currency == "TRY" {
|
||||
return 1
|
||||
}
|
||||
points := series[currency]
|
||||
if len(points) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
best := points[0]
|
||||
bestDiff := absDurationDays(points[0].date.Sub(target))
|
||||
for i := 1; i < len(points); i++ {
|
||||
diff := absDurationDays(points[i].date.Sub(target))
|
||||
if diff < bestDiff || (diff == bestDiff && points[i].date.After(best.date)) {
|
||||
best = points[i]
|
||||
bestDiff = diff
|
||||
}
|
||||
}
|
||||
return best.rate
|
||||
}
|
||||
|
||||
func absDurationDays(d time.Duration) int64 {
|
||||
if d < 0 {
|
||||
d = -d
|
||||
}
|
||||
return int64(d.Hours() / 24)
|
||||
}
|
||||
|
||||
func parseDateOnly(v string) (time.Time, bool) {
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
return time.Time{}, false
|
||||
}
|
||||
t, err := time.Parse("2006-01-02", v)
|
||||
if err != nil {
|
||||
return time.Time{}, false
|
||||
}
|
||||
return t, true
|
||||
}
|
||||
|
||||
func toTRYByRate(amount float64, currency string, currTry float64) float64 {
|
||||
currency = strings.ToUpper(strings.TrimSpace(currency))
|
||||
if currency == "" || currency == "TRY" {
|
||||
return amount
|
||||
}
|
||||
if currTry <= 0 {
|
||||
return 0
|
||||
}
|
||||
return amount * currTry
|
||||
}
|
||||
|
||||
func toUSDByRates(amount float64, currency string, currTry, usdTry float64) float64 {
|
||||
currency = strings.ToUpper(strings.TrimSpace(currency))
|
||||
switch currency {
|
||||
case "USD":
|
||||
return amount
|
||||
case "", "TRY":
|
||||
if usdTry <= 0 {
|
||||
return 0
|
||||
}
|
||||
return amount / usdTry
|
||||
default:
|
||||
if currTry <= 0 || usdTry <= 0 {
|
||||
return 0
|
||||
}
|
||||
return (amount * currTry) / usdTry
|
||||
}
|
||||
}
|
||||
|
||||
// Returns X for "1 USD = X <currency>".
|
||||
func usdRateInCurrency(currency string, currTry, usdTry float64) float64 {
|
||||
currency = strings.ToUpper(strings.TrimSpace(currency))
|
||||
switch currency {
|
||||
case "", "USD":
|
||||
return 1
|
||||
case "TRY":
|
||||
if usdTry <= 0 {
|
||||
return 0
|
||||
}
|
||||
return usdTry
|
||||
default:
|
||||
if currTry <= 0 || usdTry <= 0 {
|
||||
return 0
|
||||
}
|
||||
return usdTry / currTry
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,38 @@ func GetStatements(ctx context.Context, params models.StatementParams) ([]models
|
||||
}
|
||||
}
|
||||
|
||||
piyasaScope, err := buildPiyasaExistsForCariCode(ctx, "b.CurrAccCode")
|
||||
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 (
|
||||
@@ -62,7 +90,7 @@ HasMovement AS (
|
||||
INNER JOIN CurrAccBookATAttributesFilter f
|
||||
ON f.CurrAccBookID = b.CurrAccBookID
|
||||
AND f.ATAtt01 IN (%s)
|
||||
WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
|
||||
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
|
||||
@@ -85,7 +113,8 @@ Opening AS (
|
||||
LEFT JOIN trCurrAccBookCurrency c
|
||||
ON c.CurrAccBookID = b.CurrAccBookID
|
||||
AND c.CurrencyCode = b.DocCurrencyCode
|
||||
WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
|
||||
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
|
||||
@@ -142,7 +171,7 @@ Movements AS (
|
||||
ON c.CurrAccBookID = b.CurrAccBookID
|
||||
AND c.CurrencyCode = b.DocCurrencyCode
|
||||
|
||||
WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = REPLACE(@Carikod, ' ', '')
|
||||
WHERE LEFT(REPLACE(b.CurrAccCode, ' ', ''), 7) = LEFT(REPLACE(@Carikod, ' ', ''), 7)
|
||||
AND %s
|
||||
AND b.DocumentDate BETWEEN @startdate AND @enddate
|
||||
)
|
||||
@@ -223,6 +252,7 @@ ORDER BY
|
||||
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)
|
||||
|
||||
@@ -70,7 +70,7 @@ LEFT JOIN cdItemAttributeDesc KisaKarDesc
|
||||
ON KisaKar.AttributeTypeCode = KisaKarDesc.AttributeTypeCode
|
||||
AND KisaKar.AttributeCode = KisaKarDesc.AttributeCode
|
||||
AND KisaKar.ItemTypeCode = KisaKarDesc.ItemTypeCode
|
||||
WHERE a.CurrAccCode LIKE @Carikod
|
||||
WHERE REPLACE(a.CurrAccCode, ' ', '') LIKE REPLACE(@Carikod, ' ', '') + '%%'
|
||||
AND a.InvoiceDate BETWEEN @StartDate AND @EndDate
|
||||
AND %s
|
||||
%s
|
||||
@@ -91,7 +91,7 @@ ORDER BY Belge_Tarihi, Belge_Ref_Numarasi, Urun_Kodu;`,
|
||||
)
|
||||
|
||||
rows, err := db.MssqlDB.QueryContext(ctx, query,
|
||||
sql.Named("Carikod", "%"+accountCode+"%"),
|
||||
sql.Named("Carikod", normalizeMasterAccountCode(accountCode)),
|
||||
sql.Named("StartDate", startDate),
|
||||
sql.Named("EndDate", endDate),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user