package queries import ( "bssapp-backend/auth" "bssapp-backend/internal/authz" "context" "database/sql" "fmt" "strings" ) func resolvePiyasaWhere(ctx context.Context, pg *sql.DB) (string, error) { claims, ok := auth.GetClaimsFromContext(ctx) if !ok || claims == nil { return "", fmt.Errorf("unauthorized: claims not found") } if claims.IsAdmin() { return "1=1", nil } codes, err := authz.GetUserPiyasaCodes(pg, int(claims.ID)) if err != nil { return "", fmt.Errorf("piyasa codes load error: %w", err) } if len(codes) == 0 { return "1=0", nil } return authz.BuildINClause("UPPER(f2.CustomerAtt01)", codes), nil } func GetOrderListCloseReady( ctx context.Context, mssql *sql.DB, pg *sql.DB, search string, ) (*sql.Rows, error) { piyasaWhere, err := resolvePiyasaWhere(ctx, pg) if err != nil { return nil, err } baseQuery := fmt.Sprintf(` SELECT CAST(h.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID, ISNULL(h.OrderNumber, '') AS OrderNumber, CONVERT(varchar, h.OrderDate, 23) AS OrderDate, ISNULL(h.CurrAccCode, '') AS CurrAccCode, ISNULL(ca.CurrAccDescription, '') AS CurrAccDescription, ISNULL(mt.AttributeDescription, '') AS MusteriTemsilcisi, ISNULL(py.AttributeDescription, '') AS Piyasa, CONVERT(varchar, h.CreditableConfirmedDate,23) AS CreditableConfirmedDate, ISNULL(h.DocCurrencyCode,'TRY') AS DocCurrencyCode, ISNULL(l.TotalAmount,0) AS TotalAmount, CASE WHEN h.DocCurrencyCode = 'USD' THEN ISNULL(l.TotalAmount,0) WHEN h.DocCurrencyCode = 'TRY' AND usd.Rate > 0 THEN ISNULL(l.TotalAmount,0) / usd.Rate WHEN h.DocCurrencyCode IN ('EUR','GBP') AND cur.Rate > 0 AND usd.Rate > 0 THEN (ISNULL(l.TotalAmount,0) * cur.Rate) / usd.Rate ELSE 0 END AS TotalAmountUSD, ISNULL(l.PackedAmount,0) AS PackedAmount, CASE WHEN h.DocCurrencyCode = 'USD' THEN ISNULL(l.PackedAmount,0) WHEN h.DocCurrencyCode = 'TRY' AND usd.Rate > 0 THEN ISNULL(l.PackedTRY,0) / usd.Rate WHEN cur.Rate > 0 AND usd.Rate > 0 THEN (ISNULL(l.PackedAmount,0) * cur.Rate) / usd.Rate ELSE 0 END AS PackedUSD, CASE WHEN ISNULL(l.TotalAmount,0) > 0 THEN (ISNULL(l.PackedAmount,0) * 100.0) / NULLIF(l.TotalAmount,0) ELSE 0 END AS PackedRatePct, ISNULL(h.IsCreditableConfirmed,0) AS IsCreditableConfirmed, ISNULL(h.Description,'') AS Description, usd.Rate AS ExchangeRateUSD FROM dbo.trOrderHeader h JOIN ( SELECT l.OrderHeaderID, SUM(ISNULL(c.NetAmount,0)) AS TotalAmount, SUM( CASE WHEN ISNULL(c.CurrencyCode,'') = 'TRY' THEN ISNULL(c.NetAmount,0) ELSE 0 END ) AS TotalTRY, SUM( CASE WHEN ISNULL(l.IsClosed,0) = 1 THEN ISNULL(c.NetAmount,0) ELSE 0 END ) AS PackedAmount, SUM( CASE WHEN ISNULL(l.IsClosed,0) = 1 AND ISNULL(c.CurrencyCode,'') = 'TRY' THEN ISNULL(c.NetAmount,0) ELSE 0 END ) AS PackedTRY FROM dbo.trOrderLine l JOIN dbo.trOrderHeader h2 ON h2.OrderHeaderID = l.OrderHeaderID LEFT JOIN dbo.trOrderLineCurrency c ON c.OrderLineID = l.OrderLineID AND c.CurrencyCode = ISNULL(h2.DocCurrencyCode,'TRY') GROUP BY l.OrderHeaderID ) l ON l.OrderHeaderID = h.OrderHeaderID LEFT JOIN dbo.cdCurrAccDesc ca ON ca.CurrAccCode = h.CurrAccCode AND ca.LangCode = 'TR' LEFT JOIN dbo.CustomerAttributesFilter f ON f.CurrAccCode = h.CurrAccCode LEFT JOIN dbo.cdCurrAccAttributeDesc mt ON mt.CurrAccTypeCode = 3 AND mt.AttributeTypeCode = 2 AND mt.AttributeCode = f.CustomerAtt02 AND mt.LangCode = 'TR' LEFT JOIN dbo.cdCurrAccAttributeDesc py ON py.CurrAccTypeCode = 3 AND py.AttributeTypeCode = 1 AND py.AttributeCode = f.CustomerAtt01 AND py.LangCode = 'TR' OUTER APPLY ( SELECT TOP 1 Rate FROM dbo.AllExchangeRates WHERE CurrencyCode = 'USD' AND RelationCurrencyCode = 'TRY' AND ExchangeTypeCode = 6 AND Rate > 0 AND Date <= CAST(GETDATE() AS date) ORDER BY Date DESC ) usd OUTER APPLY ( SELECT TOP 1 Rate FROM dbo.AllExchangeRates WHERE CurrencyCode = h.DocCurrencyCode AND RelationCurrencyCode = 'TRY' AND ExchangeTypeCode = 6 AND Rate > 0 AND Date <= CAST(GETDATE() AS date) ORDER BY Date DESC ) cur WHERE ISNULL(h.IsCancelOrder,0) = 0 AND h.OrderTypeCode = 1 AND h.ProcessCode = 'WS' AND h.IsClosed = 0 AND ISNULL(l.TotalAmount,0) > 0 AND EXISTS ( SELECT 1 FROM dbo.CustomerAttributesFilter f2 WHERE f2.CurrAccCode = h.CurrAccCode AND %s ) `, piyasaWhere) if search != "" { baseQuery += ` AND EXISTS ( SELECT 1 FROM dbo.trOrderHeader h2 LEFT JOIN dbo.cdCurrAccDesc ca2 ON ca2.CurrAccCode = h2.CurrAccCode AND ca2.LangCode = 'TR' WHERE h2.OrderHeaderID = h.OrderHeaderID AND ( LOWER(REPLACE(REPLACE(h2.OrderNumber,'İ','I'),'ı','i')) COLLATE Latin1_General_CI_AI LIKE LOWER(@p1) OR LOWER(REPLACE(REPLACE(h2.CurrAccCode,'İ','I'),'ı','i')) COLLATE Latin1_General_CI_AI LIKE LOWER(@p1) OR LOWER(REPLACE(REPLACE(ca2.CurrAccDescription,'İ','I'),'ı','i')) COLLATE Latin1_General_CI_AI LIKE LOWER(@p1) OR LOWER(REPLACE(REPLACE(h2.Description,'İ','I'),'ı','i')) COLLATE Latin1_General_CI_AI LIKE LOWER(@p1) ) ) ` } baseQuery += ` ORDER BY h.CreatedDate DESC ` if search != "" { searchLike := fmt.Sprintf("%%%s%%", search) return mssql.Query(baseQuery, searchLike) } return mssql.Query(baseQuery) } func BulkCloseOrders( ctx context.Context, mssql *sql.DB, pg *sql.DB, orderNumbers []string, updatedBy string, ) (int64, error) { piyasaWhere, err := resolvePiyasaWhere(ctx, pg) if err != nil { return 0, err } clean := make([]string, 0, len(orderNumbers)) seen := make(map[string]struct{}) for _, n := range orderNumbers { n = strings.TrimSpace(n) if n == "" { continue } key := strings.ToUpper(n) if _, ok := seen[key]; ok { continue } seen[key] = struct{}{} clean = append(clean, n) } if len(clean) == 0 { return 0, fmt.Errorf("order_numbers is empty") } if strings.TrimSpace(updatedBy) == "" { updatedBy = "SYSTEM" } placeholders := make([]string, len(clean)) args := make([]any, 0, len(clean)+1) args = append(args, updatedBy) // @p1 for i, no := range clean { placeholders[i] = fmt.Sprintf("@p%d", i+2) args = append(args, no) } tx, err := mssql.BeginTx(ctx, nil) if err != nil { return 0, fmt.Errorf("begin tx failed: %w", err) } defer tx.Rollback() q := fmt.Sprintf(` UPDATE h SET h.IsClosed = 1, h.LastUpdatedDate = GETDATE(), h.LastUpdatedUserName = @p1 FROM dbo.trOrderHeader h WHERE h.IsClosed = 0 AND h.OrderNumber IN (%s) AND EXISTS ( SELECT 1 FROM dbo.CustomerAttributesFilter f2 WHERE f2.CurrAccCode = h.CurrAccCode AND %s ) AND EXISTS ( SELECT 1 FROM ( SELECT l.OrderHeaderID, SUM(ISNULL(c.NetAmount,0)) AS TotalAmount, SUM( CASE WHEN ISNULL(l.IsClosed,0) = 1 THEN ISNULL(c.NetAmount,0) ELSE 0 END ) AS PackedAmount FROM dbo.trOrderLine l JOIN dbo.trOrderHeader h2 ON h2.OrderHeaderID = l.OrderHeaderID LEFT JOIN dbo.trOrderLineCurrency c ON c.OrderLineID = l.OrderLineID AND c.CurrencyCode = ISNULL(h2.DocCurrencyCode,'TRY') GROUP BY l.OrderHeaderID ) t WHERE t.OrderHeaderID = h.OrderHeaderID AND t.TotalAmount > 0 ); `, strings.Join(placeholders, ","), piyasaWhere) res, err := tx.ExecContext(ctx, q, args...) if err != nil { return 0, fmt.Errorf("bulk close update failed: %w", err) } affected, err := res.RowsAffected() if err != nil { return 0, fmt.Errorf("rows affected read failed: %w", err) } if err := tx.Commit(); err != nil { return 0, fmt.Errorf("commit failed: %w", err) } return affected, nil }