Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -101,15 +101,19 @@ func GetAccounts(ctx context.Context) ([]models.Account, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(acc.AccountCode) >= 4 {
|
||||
acc.DisplayCode =
|
||||
strings.TrimSpace(acc.AccountCode[:3] + " " + acc.AccountCode[3:])
|
||||
} else {
|
||||
acc.DisplayCode = acc.AccountCode
|
||||
}
|
||||
acc.DisplayCode = formatAccountDisplayCode(acc.AccountCode)
|
||||
|
||||
accounts = append(accounts, acc)
|
||||
}
|
||||
|
||||
return accounts, rows.Err()
|
||||
}
|
||||
|
||||
func formatAccountDisplayCode(code string) string {
|
||||
trimmed := strings.TrimSpace(code)
|
||||
runes := []rune(trimmed)
|
||||
if len(runes) <= 3 {
|
||||
return trimmed
|
||||
}
|
||||
return strings.TrimSpace(string(runes[:3]) + " " + string(runes[3:]))
|
||||
}
|
||||
|
||||
@@ -15,15 +15,16 @@ import (
|
||||
)
|
||||
|
||||
type mkCariBakiyeLine struct {
|
||||
CurrAccTypeCode int
|
||||
CariKodu string
|
||||
CariDoviz string
|
||||
SirketKodu int
|
||||
PislemTipi string
|
||||
YerelBakiye float64
|
||||
Bakiye float64
|
||||
VadeGun float64
|
||||
VadeBelgeGun float64
|
||||
CurrAccTypeCode int
|
||||
CariKodu string
|
||||
CariDoviz string
|
||||
SirketKodu int
|
||||
PislemTipi string
|
||||
ParasalIslemTipi string
|
||||
YerelBakiye float64
|
||||
Bakiye float64
|
||||
VadeGun float64
|
||||
VadeBelgeGun float64
|
||||
}
|
||||
|
||||
type cariMeta struct {
|
||||
@@ -181,13 +182,13 @@ func GetCustomerBalanceList(ctx context.Context, params models.CustomerBalanceLi
|
||||
}
|
||||
|
||||
usd := toUSD(ln.Bakiye, curr, usdTry, rateMap)
|
||||
|
||||
switch strings.TrimSpace(ln.PislemTipi) {
|
||||
case "1_2":
|
||||
add12, add13 := resolveBalanceBuckets(ln)
|
||||
if add12 {
|
||||
row.Bakiye12 += ln.Bakiye
|
||||
row.TLBakiye12 += ln.YerelBakiye
|
||||
row.USDBakiye12 += usd
|
||||
case "1_3":
|
||||
}
|
||||
if add13 {
|
||||
row.Bakiye13 += ln.Bakiye
|
||||
row.TLBakiye13 += ln.YerelBakiye
|
||||
row.USDBakiye13 += usd
|
||||
@@ -319,13 +320,14 @@ func loadBalanceLines(ctx context.Context, selectedDate, cariSearch string) ([]m
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
queryTemplate := `
|
||||
SELECT
|
||||
CurrAccTypeCode,
|
||||
CariKodu,
|
||||
CariDoviz,
|
||||
SirketKodu,
|
||||
PislemTipi,
|
||||
%s
|
||||
YerelBakiye,
|
||||
Bakiye,
|
||||
CAST(0 AS DECIMAL(18,4)) AS Vade_Gun,
|
||||
@@ -333,13 +335,33 @@ func loadBalanceLines(ctx context.Context, selectedDate, cariSearch string) ([]m
|
||||
FROM dbo.MK_CARI_BAKIYE_LIST(@SonTarih)
|
||||
WHERE (@CariSearch = '' OR CariKodu LIKE '%%' + @CariSearch + '%%')
|
||||
AND %s
|
||||
`, piyasaScope)
|
||||
`
|
||||
|
||||
rows, err := db.MssqlDB.QueryContext(ctx, query,
|
||||
sql.Named("SonTarih", selectedDate),
|
||||
sql.Named("CariSearch", strings.TrimSpace(cariSearch)),
|
||||
selectParasalCandidates := make([]string, 0, 7)
|
||||
if expr := strings.TrimSpace(resolveParasalIslemSelectExpr(ctx, "SELECT * FROM dbo.MK_CARI_BAKIYE_LIST('2000-01-01')")); expr != "" {
|
||||
selectParasalCandidates = append(selectParasalCandidates, expr)
|
||||
}
|
||||
selectParasalCandidates = append(selectParasalCandidates,
|
||||
"CAST(ATAtt01 AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST(ParasalIslemTipi AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST(ParislemTipi AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST(ParIslemTipi AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST('' AS varchar(16)) AS ParasalIslemTipi,",
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
var rows *sql.Rows
|
||||
for i, sel := range selectParasalCandidates {
|
||||
query := fmt.Sprintf(queryTemplate, sel, piyasaScope)
|
||||
rows, err = db.MssqlDB.QueryContext(ctx, query,
|
||||
sql.Named("SonTarih", selectedDate),
|
||||
sql.Named("CariSearch", strings.TrimSpace(cariSearch)),
|
||||
)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if i < len(selectParasalCandidates)-1 && isInvalidColumnError(err) {
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("MK_CARI_BAKIYE_LIST query error: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
@@ -353,6 +375,7 @@ func loadBalanceLines(ctx context.Context, selectedDate, cariSearch string) ([]m
|
||||
&r.CariDoviz,
|
||||
&r.SirketKodu,
|
||||
&r.PislemTipi,
|
||||
&r.ParasalIslemTipi,
|
||||
&r.YerelBakiye,
|
||||
&r.Bakiye,
|
||||
&r.VadeGun,
|
||||
@@ -648,7 +671,7 @@ func buildFilters(params models.CustomerBalanceListParams) balanceFilters {
|
||||
piyasa: parseCSVSet(params.Piyasa),
|
||||
temsilci: parseCSVSet(params.Temsilci),
|
||||
riskDurumu: parseCSVSet(params.RiskDurumu),
|
||||
islemTipi: parseCSVSet(params.IslemTipi),
|
||||
islemTipi: parseIslemTipiSet(params.IslemTipi),
|
||||
ulke: parseCSVSet(params.Ulke),
|
||||
il: parseCSVSet(params.Il),
|
||||
ilce: parseCSVSet(params.Ilce),
|
||||
@@ -707,6 +730,28 @@ func parseCSVSet(v string) map[string]struct{} {
|
||||
return out
|
||||
}
|
||||
|
||||
func parseIslemTipiSet(v string) map[string]struct{} {
|
||||
raw := parseCSVSet(v)
|
||||
if len(raw) == 0 {
|
||||
return raw
|
||||
}
|
||||
|
||||
out := make(map[string]struct{}, 2)
|
||||
for token := range raw {
|
||||
switch strings.ToLower(strings.TrimSpace(token)) {
|
||||
case "1_2", "prbr_1_2", "usd_1_2", "try_1_2", "tl_1_2", "usd_bakiye_1_2", "tl_bakiye_1_2":
|
||||
out["1_2"] = struct{}{}
|
||||
case "1_3", "prbr_1_3", "usd_1_3", "try_1_3", "tl_1_3", "usd_bakiye_1_3", "tl_bakiye_1_3":
|
||||
out["1_3"] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(out) == 0 {
|
||||
return raw
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func getAuthorizedPiyasaCodes(ctx context.Context) ([]string, error) {
|
||||
claims, ok := auth.GetClaimsFromContext(ctx)
|
||||
if !ok || claims == nil {
|
||||
@@ -794,3 +839,181 @@ func firstNonEmpty(v ...string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func isInvalidColumnError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
msg := strings.ToLower(err.Error())
|
||||
return strings.Contains(msg, "invalid column name")
|
||||
}
|
||||
|
||||
func shouldSkipBalanceLine(ln mkCariBakiyeLine) bool {
|
||||
add12, add13 := resolveBalanceBuckets(ln)
|
||||
p := strings.TrimSpace(ln.PislemTipi)
|
||||
if p == "1_2" {
|
||||
return !add12
|
||||
}
|
||||
if p == "1_3" {
|
||||
return !add13
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func resolveBalanceBuckets(ln mkCariBakiyeLine) (add12 bool, add13 bool) {
|
||||
p := strings.TrimSpace(ln.PislemTipi)
|
||||
t := normalizeParasalIslemTipi(ln.ParasalIslemTipi)
|
||||
switch t {
|
||||
case "1":
|
||||
return true, true
|
||||
case "2", "1_2":
|
||||
return true, false
|
||||
case "3", "1_3":
|
||||
return false, true
|
||||
}
|
||||
|
||||
// Parasal tip yoksa eski davranis: PislemTipi'ne gore ayir.
|
||||
if p == "1_2" {
|
||||
return true, false
|
||||
}
|
||||
if p == "1_3" {
|
||||
return false, true
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func normalizeParasalIslemTipi(v string) string {
|
||||
s := strings.TrimSpace(v)
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
lower := strings.ToLower(s)
|
||||
compact := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(lower, " ", ""), "-", "_"), "/", "_")
|
||||
if strings.Contains(compact, "1_2") {
|
||||
return "1_2"
|
||||
}
|
||||
if strings.Contains(compact, "1_3") {
|
||||
return "1_3"
|
||||
}
|
||||
|
||||
// "1,2" / "1,3" gibi liste formatlarini dogrudan yakala.
|
||||
tokenized := strings.NewReplacer(" ", "", ";", ",", "|", ",", "/", ",", "-", ",", "_", ",").Replace(lower)
|
||||
parts := strings.Split(tokenized, ",")
|
||||
has1 := false
|
||||
has2 := false
|
||||
has3 := false
|
||||
for _, p := range parts {
|
||||
t := strings.TrimSpace(p)
|
||||
switch t {
|
||||
case "1":
|
||||
has1 = true
|
||||
case "2":
|
||||
has2 = true
|
||||
case "3":
|
||||
has3 = true
|
||||
}
|
||||
}
|
||||
if has1 && has2 {
|
||||
return "1_2"
|
||||
}
|
||||
if has1 && has3 {
|
||||
return "1_3"
|
||||
}
|
||||
if has2 && !has1 && !has3 {
|
||||
return "2"
|
||||
}
|
||||
if has3 && !has1 && !has2 {
|
||||
return "3"
|
||||
}
|
||||
if has1 && !has2 && !has3 {
|
||||
return "1"
|
||||
}
|
||||
|
||||
// "2.00", "2,00", " 2 " gibi varyasyonlari tek tipe indir.
|
||||
s = strings.ReplaceAll(s, ",", ".")
|
||||
if n, err := strconv.ParseFloat(s, 64); err == nil {
|
||||
return strconv.Itoa(int(n))
|
||||
}
|
||||
|
||||
// Metinsel geldiyse ilk rakam bloğunu al.
|
||||
start := -1
|
||||
end := -1
|
||||
for i, r := range s {
|
||||
if r >= '0' && r <= '9' {
|
||||
if start == -1 {
|
||||
start = i
|
||||
}
|
||||
end = i
|
||||
continue
|
||||
}
|
||||
if start != -1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if start == -1 || end < start {
|
||||
return s
|
||||
}
|
||||
return s[start : end+1]
|
||||
}
|
||||
|
||||
func resolveParasalIslemSelectExpr(ctx context.Context, sampleQuery string) string {
|
||||
sampleQuery = strings.TrimSpace(sampleQuery)
|
||||
if sampleQuery == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
metaQuery := `
|
||||
SELECT name
|
||||
FROM sys.dm_exec_describe_first_result_set(@tsql, NULL, 0)
|
||||
WHERE error_number IS NULL
|
||||
AND name IS NOT NULL
|
||||
`
|
||||
rows, err := db.MssqlDB.QueryContext(ctx, metaQuery, sql.Named("tsql", sampleQuery))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type candidate struct {
|
||||
key string
|
||||
expr string
|
||||
}
|
||||
priority := []candidate{
|
||||
{key: "ata tt01", expr: "CAST(%s AS varchar(16)) AS ParasalIslemTipi,"},
|
||||
{key: "atatt01", expr: "CAST(%s AS varchar(16)) AS ParasalIslemTipi,"},
|
||||
{key: "parasalislemtipi", expr: "CAST(%s AS varchar(16)) AS ParasalIslemTipi,"},
|
||||
{key: "parislemtipi", expr: "CAST(%s AS varchar(16)) AS ParasalIslemTipi,"},
|
||||
{key: "parislemtur", expr: "CAST(%s AS varchar(16)) AS ParasalIslemTipi,"},
|
||||
}
|
||||
|
||||
available := make(map[string]string)
|
||||
for rows.Next() {
|
||||
var col sql.NullString
|
||||
if err := rows.Scan(&col); err != nil {
|
||||
return ""
|
||||
}
|
||||
name := strings.TrimSpace(col.String)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
normalized := strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(name, "_", ""), " ", ""))
|
||||
available[normalized] = name
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, c := range priority {
|
||||
key := strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(c.key, "_", ""), " ", ""))
|
||||
if col, ok := available[key]; ok {
|
||||
return fmt.Sprintf(c.expr, quoteSQLIdent(col))
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func quoteSQLIdent(ident string) string {
|
||||
return "[" + strings.ReplaceAll(strings.TrimSpace(ident), "]", "]]") + "]"
|
||||
}
|
||||
|
||||
@@ -137,13 +137,13 @@ func GetStatementAgingBalanceList(ctx context.Context, params models.CustomerBal
|
||||
|
||||
usd := toUSD(ln.Bakiye, curr, usdTry, rateMap)
|
||||
tl := toTRY(ln.Bakiye, curr, rateMap)
|
||||
|
||||
switch strings.TrimSpace(ln.PislemTipi) {
|
||||
case "1_2":
|
||||
add12, add13 := resolveBalanceBuckets(ln)
|
||||
if add12 {
|
||||
row.Bakiye12 += ln.Bakiye
|
||||
row.TLBakiye12 += tl
|
||||
row.USDBakiye12 += usd
|
||||
case "1_3":
|
||||
}
|
||||
if add13 {
|
||||
row.Bakiye13 += ln.Bakiye
|
||||
row.TLBakiye13 += tl
|
||||
row.USDBakiye13 += usd
|
||||
@@ -187,13 +187,14 @@ func loadAgingBalanceLines(ctx context.Context, cariSearch string) ([]mkCariBaki
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
queryTemplate := `
|
||||
SELECT
|
||||
CurrAccTypeCode,
|
||||
CariKodu = LTRIM(RTRIM(CariKodu)),
|
||||
CariDoviz = LTRIM(RTRIM(CariDoviz)),
|
||||
SirketKodu,
|
||||
PislemTipi,
|
||||
%s
|
||||
YerelBakiye = CAST(0 AS DECIMAL(18,2)),
|
||||
Bakiye,
|
||||
Vade_Gun,
|
||||
@@ -202,10 +203,30 @@ func loadAgingBalanceLines(ctx context.Context, cariSearch string) ([]mkCariBaki
|
||||
WHERE (@CariSearch = '' OR LTRIM(RTRIM(CariKodu)) LIKE '%%' + @CariSearch + '%%')
|
||||
AND %s
|
||||
ORDER BY CariKodu, CariDoviz, PislemTipi
|
||||
`, piyasaScope)
|
||||
`
|
||||
|
||||
rows, err := db.MssqlDB.QueryContext(ctx, query, sql.Named("CariSearch", strings.TrimSpace(cariSearch)))
|
||||
if err != nil {
|
||||
selectParasalCandidates := make([]string, 0, 7)
|
||||
if expr := strings.TrimSpace(resolveParasalIslemSelectExpr(ctx, "SELECT * FROM dbo.CARI_BAKIYE_GUN_CACHE")); expr != "" {
|
||||
selectParasalCandidates = append(selectParasalCandidates, expr)
|
||||
}
|
||||
selectParasalCandidates = append(selectParasalCandidates,
|
||||
"CAST(ATAtt01 AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST(ParasalIslemTipi AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST(ParislemTipi AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST(ParIslemTipi AS varchar(16)) AS ParasalIslemTipi,",
|
||||
"CAST('' AS varchar(16)) AS ParasalIslemTipi,",
|
||||
)
|
||||
|
||||
var rows *sql.Rows
|
||||
for i, sel := range selectParasalCandidates {
|
||||
query := fmt.Sprintf(queryTemplate, sel, piyasaScope)
|
||||
rows, err = db.MssqlDB.QueryContext(ctx, query, sql.Named("CariSearch", strings.TrimSpace(cariSearch)))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if i < len(selectParasalCandidates)-1 && isInvalidColumnError(err) {
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("CARI_BAKIYE_GUN_CACHE query error: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
@@ -219,6 +240,7 @@ func loadAgingBalanceLines(ctx context.Context, cariSearch string) ([]mkCariBaki
|
||||
&r.CariDoviz,
|
||||
&r.SirketKodu,
|
||||
&r.PislemTipi,
|
||||
&r.ParasalIslemTipi,
|
||||
&r.YerelBakiye,
|
||||
&r.Bakiye,
|
||||
&r.VadeGun,
|
||||
|
||||
@@ -23,7 +23,10 @@ SELECT
|
||||
a.ItemCode AS Urun_Kodu,
|
||||
a.ColorCode AS Urun_Rengi,
|
||||
SUM(a.Qty1) AS Toplam_Adet,
|
||||
SUM(ABS(a.Doc_Price)) AS Toplam_Fiyat,
|
||||
CAST(
|
||||
SUM(a.Qty1 * ABS(a.Doc_Price)) / NULLIF(SUM(a.Qty1), 0)
|
||||
AS numeric(18,2)
|
||||
) AS Toplam_Fiyat,
|
||||
CAST(SUM(a.Qty1 * ABS(a.Doc_Price)) AS numeric(18,2)) AS Toplam_Tutar
|
||||
FROM AllInvoicesWithAttributes a
|
||||
LEFT JOIN prItemAttribute AnaGrup
|
||||
|
||||
Reference in New Issue
Block a user