package queries import ( "bssapp-backend/models" "bssapp-backend/utils" "context" "database/sql" "fmt" "strconv" "strings" "time" "unicode" ) func GetNextOnMLNoFrom100k(ctx context.Context, uretimDB *sql.DB) (int, error) { // nOnMLNo is NOT identity. Generate next number safely. // Requirement: always continue from MAX, but never below 100001. sqlText := ` SELECT ISNULL(MAX(M.nOnMLNo), 100000) + 1 AS NextNo FROM dbo.spUrtOnMLMas M WITH (UPDLOCK, HOLDLOCK) ` var next int if err := uretimDB.QueryRowContext(ctx, sqlText).Scan(&next); err != nil { return 0, err } if next < 100001 { next = 100001 } return next, nil } func GetOnMLMamulTuruNoByAciklama(ctx context.Context, tx *sql.Tx, sAciklama string) (int, error) { sAciklama = strings.TrimSpace(sAciklama) if sAciklama == "" { return 1, nil } var existing int err := tx.QueryRowContext(ctx, ` SELECT TOP 1 ISNULL(nMamulTuruNo, 0) FROM dbo.spUrtOnMLMamulTuru WITH (UPDLOCK, HOLDLOCK) WHERE LTRIM(RTRIM(ISNULL(sAciklama,''))) = @p1 ORDER BY nMamulTuruNo `, sAciklama).Scan(&existing) if err == sql.ErrNoRows { return 0, nil } if err != nil { return 0, err } return existing, nil } func LookupFirmaIDByKodu(ctx context.Context, uretimDB *sql.DB, firmaKodu string) (int, error) { firmaKodu = strings.TrimSpace(firmaKodu) if firmaKodu == "" { return 0, nil } sqlText := ` SELECT TOP 1 ISNULL(F.nFirmaID, 0) AS nFirmaID FROM dbo.tbFirma F WITH (NOLOCK) WHERE LTRIM(RTRIM(ISNULL(F.sKodu, ''))) = @p1 ORDER BY F.nFirmaID ` var id int if err := uretimDB.QueryRowContext(ctx, sqlText, firmaKodu).Scan(&id); err != nil { if err == sql.ErrNoRows { return 0, nil } return 0, err } return id, nil } type OnMLHeaderUpsertArgs struct { NOnMLNo int UrunKodu string UrunAdi string Tarihi time.Time NMamulTuruNo int NUrtReceteID sql.NullInt64 UretimSekliID sql.NullInt64 SAciklama sql.NullString NFirmaID int SUser string LTutarTL float64 LTutarUSD float64 LTutarEURO float64 SDovizCinsi string LTutarDoviz float64 } func UpsertOnMLHeader(tx *sql.Tx, ctx context.Context, args OnMLHeaderUpsertArgs) error { // Note: Many NOT NULL columns exist. We use dummy/system values as per business rules. sqlText := ` IF EXISTS (SELECT 1 FROM dbo.spUrtOnMLMas WITH (UPDLOCK, HOLDLOCK) WHERE nOnMLNo = @p1) BEGIN UPDATE dbo.spUrtOnMLMas SET UrunKodu = @p2, UrunAdi = @p3, Tarihi = @p4, nDonemNo = 1, nMamulTuruNo = @p16, nBolgeNo = 2, nZorlukNo = 1, bDurum = 1, lTutarTL = @p5, lTutarUSD = @p6, lTutarEURO = @p7, sDovizCinsi = @p8, lTutarDoviz = @p9, bSablon = 0, dteGuncellemeTarihi = GETDATE(), sGuncellemeKullaniciAdi = @p10, nUrtReceteID = @p11, sAciklama = @p12, lMasMiktar = 0, sRenk = NULLIF(LTRIM(RTRIM(@p13)), ''), nFirmaID = @p14, uretim_sekli_id = @p15 WHERE nOnMLNo = @p1 END ELSE BEGIN INSERT INTO dbo.spUrtOnMLMas ( nOnMLNo, UrunKodu, UrunAdi, Tarihi, nDonemNo, nMamulTuruNo, nBolgeNo, nZorlukNo, dteKayitTarihi, sKullaniciAdi, bDurum, lTutarTL, lTutarUSD, lTutarEURO, sDovizCinsi, lTutarDoviz, bSablon, dteGuncellemeTarihi, sGuncellemeKullaniciAdi, nUrtReceteID, sAciklama, lMasMiktar, nFirmaID, bVarsayilan, bOnay, bIptal, bRParcaTakip, uretim_sekli_id ) VALUES ( @p1, @p2, @p3, @p4, 1, @p16, 2, 1, GETDATE(), @p10, 1, @p5, @p6, @p7, @p8, @p9, 0, GETDATE(), @p10, @p11, @p12, 0, @p14, 0, 0, 0, 0, @p15 ) END ` _, err := tx.ExecContext( ctx, sqlText, args.NOnMLNo, strings.TrimSpace(args.UrunKodu), strings.TrimSpace(args.UrunAdi), args.Tarihi, args.LTutarTL, args.LTutarUSD, args.LTutarEURO, strings.TrimSpace(args.SDovizCinsi), args.LTutarDoviz, strings.TrimSpace(args.SUser), args.NUrtReceteID, args.SAciklama, "", // sRenk (header) currently not driven from UI args.NFirmaID, args.UretimSekliID, args.NMamulTuruNo, ) return err } // ============================================================ // V3 (Nebim) base price update // ============================================================ func UpsertV3ItemBasePriceUSD( ctx context.Context, mssqlDB *sql.DB, itemCode string, priceDate string, // YYYY-MM-DD priceUSD float64, user string, ) error { itemCode = strings.TrimSpace(itemCode) priceDate = strings.TrimSpace(priceDate) user = strings.TrimSpace(user) if mssqlDB == nil || itemCode == "" || priceDate == "" { return fmt.Errorf("missing params for base price upsert") } // 1. Find a CountryCode that is NOT yet used for this specific item in prItemBasePrice. // We query cdCountry for a code that has no matching entry in prItemBasePrice for this item. // We exclude 'TR' to keep the original record safe. var targetCountry string err := mssqlDB.QueryRowContext(ctx, ` SELECT TOP 1 C.CountryCode FROM dbo.cdCountry C WITH (NOLOCK) WHERE C.CountryCode <> 'TR' AND NOT EXISTS ( SELECT 1 FROM dbo.prItemBasePrice P WITH (NOLOCK) WHERE P.ItemTypeCode = 1 AND LTRIM(RTRIM(P.ItemCode)) = LTRIM(RTRIM(@p1)) AND P.BasePriceCode = 1 AND P.CountryCode = C.CountryCode ) ORDER BY NEWID() -- Randomly pick one of the available country codes `, itemCode).Scan(&targetCountry) if err != nil { if err == sql.ErrNoRows { // Fallback: If ALL countries are exhausted (unlikely), default to 'AD' as a last resort. targetCountry = "AD" } else { return fmt.Errorf("failed to find available country code: %w", err) } } appUser := user if strings.TrimSpace(appUser) == "" { appUser = "BSSAPP" } else { appUser = "BSSAPP:" + strings.TrimSpace(appUser) } sqlText := ` MERGE dbo.prItemBasePrice AS T USING ( SELECT @p1 AS ItemTypeCode, @p2 AS ItemCode, @p6 AS CountryCode, '' AS SeasonCode, 1 AS BasePriceCode, CONVERT(date, @p3, 23) AS PriceDate, 'USD' AS CurrencyCode ) AS S ON T.ItemTypeCode = S.ItemTypeCode AND LTRIM(RTRIM(T.ItemCode)) = LTRIM(RTRIM(S.ItemCode)) AND ISNULL(T.CountryCode,'') = S.CountryCode AND ISNULL(T.SeasonCode,'') = S.SeasonCode AND ISNULL(T.BasePriceCode,0) = S.BasePriceCode WHEN MATCHED THEN UPDATE SET PriceDate = S.PriceDate, CurrencyCode = S.CurrencyCode, Price = @p4, LastUpdatedUserName = @p5, LastUpdatedDate = GETDATE() WHEN NOT MATCHED THEN INSERT ( ItemTypeCode, ItemCode, CountryCode, SeasonCode, BasePriceCode, PriceDate, CurrencyCode, Price, CreatedUserName, CreatedDate, LastUpdatedUserName, LastUpdatedDate ) VALUES ( S.ItemTypeCode, S.ItemCode, S.CountryCode, S.SeasonCode, S.BasePriceCode, S.PriceDate, S.CurrencyCode, @p4, @p5, GETDATE(), @p5, GETDATE() ); ` _, err = mssqlDB.ExecContext(ctx, sqlText, 1, itemCode, priceDate, priceUSD, appUser, targetCountry) return err } func GetProductAnaAltGrupByUrunKodu(ctx context.Context, mssqlDB *sql.DB, urunKodu string) (urunAnaGrubu string, urunAltGrubu string, err error) { urunKodu = strings.TrimSpace(urunKodu) if mssqlDB == nil || urunKodu == "" { return "", "", nil } // Nebim V3: ProductFilterWithDescription exposes ProductAtt01Desc (ana grup) and ProductAtt02Desc (alt grup). sqlText := ` SELECT TOP 1 ISNULL(ProductAtt01Desc, '') AS UrunAnaGrubu, ISNULL(ProductAtt02Desc, '') AS UrunAltGrubu FROM ProductFilterWithDescription('TR') WHERE IsBlocked = 0 AND LTRIM(RTRIM(ProductCode)) = @p1 ORDER BY ProductCode; ` row := mssqlDB.QueryRowContext(ctx, sqlText, urunKodu) if err := row.Scan(&urunAnaGrubu, &urunAltGrubu); err != nil { if err == sql.ErrNoRows { return "", "", nil } return "", "", err } return urunAnaGrubu, urunAltGrubu, nil } func GetProductIlkAnaAltGrupByUrunKodu(ctx context.Context, mssqlDB *sql.DB, urunKodu string) (urunIlkGrubu string, urunAnaGrubu string, urunAltGrubu string, err error) { urunKodu = strings.TrimSpace(urunKodu) if mssqlDB == nil || urunKodu == "" { return "", "", "", nil } // Nebim V3: ProductFilterWithDescription exposes ProductAtt42Desc (ilk grup), ProductAtt01Desc (ana), ProductAtt02Desc (alt). sqlText := ` SELECT TOP 1 ISNULL(ProductAtt42Desc, '') AS UrunIlkGrubu, ISNULL(ProductAtt01Desc, '') AS UrunAnaGrubu, ISNULL(ProductAtt02Desc, '') AS UrunAltGrubu FROM ProductFilterWithDescription('TR') WHERE IsBlocked = 0 AND LTRIM(RTRIM(ProductCode)) = @p1 ORDER BY ProductCode; ` row := mssqlDB.QueryRowContext(ctx, sqlText, urunKodu) if err := row.Scan(&urunIlkGrubu, &urunAnaGrubu, &urunAltGrubu); err != nil { if err == sql.ErrNoRows { return "", "", "", nil } return "", "", "", err } return urunIlkGrubu, urunAnaGrubu, urunAltGrubu, nil } func GetProductionProductCostingAnaGrupOptions(ctx context.Context, mssqlDB *sql.DB, search string, limit int) (*sql.Rows, error) { search = strings.TrimSpace(search) if limit <= 0 { limit = 50 } searchLike := "%" + search + "%" sqlText := ` SELECT TOP (@p2) ISNULL(NULLIF(LTRIM(RTRIM(P.ProductAtt01Desc)), ''), '') AS UrunAnaGrubu FROM ProductFilterWithDescription('TR') AS P WHERE P.IsBlocked = 0 AND NULLIF(LTRIM(RTRIM(P.ProductAtt01Desc)), '') IS NOT NULL AND (@p1 = '' OR P.ProductAtt01Desc LIKE @p3) GROUP BY P.ProductAtt01Desc ORDER BY P.ProductAtt01Desc ` return mssqlDB.QueryContext(ctx, sqlText, search, limit, searchLike) } func GetProductionProductCostingAltGrupOptions(ctx context.Context, mssqlDB *sql.DB, urunAnaGrubu string, search string, limit int) (*sql.Rows, error) { urunAnaGrubu = strings.TrimSpace(urunAnaGrubu) search = strings.TrimSpace(search) if limit <= 0 { limit = 50 } searchLike := "%" + search + "%" sqlText := ` SELECT TOP (@p3) ISNULL(NULLIF(LTRIM(RTRIM(P.ProductAtt02Desc)), ''), '') AS UrunAltGrubu FROM ProductFilterWithDescription('TR') AS P WHERE P.IsBlocked = 0 AND NULLIF(LTRIM(RTRIM(P.ProductAtt02Desc)), '') IS NOT NULL AND (@p1 = '' OR LTRIM(RTRIM(P.ProductAtt01Desc)) = @p1) AND (@p2 = '' OR P.ProductAtt02Desc LIKE @p4) GROUP BY P.ProductAtt02Desc ORDER BY P.ProductAtt02Desc ` return mssqlDB.QueryContext(ctx, sqlText, urunAnaGrubu, search, limit, searchLike) } func GetProductionProductCostingAnaAltComboRows(ctx context.Context, mssqlDB *sql.DB, search string, limit int) (*sql.Rows, error) { search = strings.TrimSpace(search) if limit <= 0 { limit = 500 } if limit > 5000 { limit = 5000 } // For very short searches, avoid leading-wildcard LIKE which can be extremely expensive on MSSQL side. // Example: "ce" should match "CEKET%" cheaply vs "%ce%" scanning everything. searchLike := "%" + search + "%" if len([]rune(search)) > 0 && len([]rune(search)) < 3 { searchLike = search + "%" } sqlText := ` SELECT TOP (@p2) ISNULL(NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt42Desc))), ''), '') AS UrunIlkGrubu, ISNULL(NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt01Desc))), ''), '') AS UrunAnaGrubu, ISNULL(NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt02Desc))), ''), '') AS UrunAltGrubu FROM ProductFilterWithDescription('TR') AS P WHERE P.IsBlocked = 0 AND NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt42Desc))), '') IS NOT NULL AND NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt01Desc))), '') IS NOT NULL AND NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt02Desc))), '') IS NOT NULL AND ( @p1 = '' OR CONVERT(NVARCHAR(200), P.ProductAtt42Desc) LIKE @p3 OR CONVERT(NVARCHAR(200), P.ProductAtt01Desc) LIKE @p3 OR CONVERT(NVARCHAR(200), P.ProductAtt02Desc) LIKE @p3 ) GROUP BY CONVERT(NVARCHAR(200), P.ProductAtt42Desc), CONVERT(NVARCHAR(200), P.ProductAtt01Desc), CONVERT(NVARCHAR(200), P.ProductAtt02Desc) ORDER BY CONVERT(NVARCHAR(200), P.ProductAtt42Desc), CONVERT(NVARCHAR(200), P.ProductAtt02Desc), CONVERT(NVARCHAR(200), P.ProductAtt01Desc) ` return mssqlDB.QueryContext(ctx, sqlText, search, limit, searchLike) } func GetProductionProductCostingMTBolumOptions(ctx context.Context, uretimDB *sql.DB, search string, limit int) (*sql.Rows, error) { search = strings.TrimSpace(search) if limit <= 0 { limit = 50 } searchLike := "%" + search + "%" sqlText := ` SELECT TOP (@p2) ISNULL(B.nUrtMTBolumID, 0) AS nUrtMTBolumID, ISNULL(B.sAdi, '') AS sAdi FROM dbo.spUrtMTBolum B WITH (NOLOCK) WHERE ISNULL(B.bAktif, 0) = 1 AND ISNULL(B.nUrtTipiID, 0) = 1 AND (@p1 = '' OR ISNULL(B.sAdi, '') LIKE @p3 OR CONVERT(VARCHAR(32), ISNULL(B.nUrtMTBolumID, 0)) LIKE @p3) ORDER BY B.nUrtMTBolumID ` return uretimDB.QueryContext(ctx, sqlText, search, limit, searchLike) } // ============================================================ // Maliyet Parca Eslestirme (URETIM DB) // ============================================================ func ListProductionProductCostingParcaMappings(ctx context.Context, uretimDB *sql.DB, urunIlkGrubu string, urunAnaGrubu string, urunAltGrubu string, nUrtMTBolumID int, onlyActive *bool) (*sql.Rows, error) { urunIlkGrubu = strings.TrimSpace(urunIlkGrubu) urunAnaGrubu = strings.TrimSpace(urunAnaGrubu) urunAltGrubu = strings.TrimSpace(urunAltGrubu) sqlText := ` SELECT M.id, ISNULL(M.UrunIlkGrubu, '') AS UrunIlkGrubu, ISNULL(M.UrunAnaGrubu, '') AS UrunAnaGrubu, ISNULL(M.UrunAltGrubu, '') AS UrunAltGrubu, ISNULL(M.nUrtMTBolumID, 0) AS nUrtMTBolumID, ISNULL(B.sAdi, '') AS MTBolumAdi, ISNULL(H.HammaddeTurleri, '') AS HammaddeTurleri, CAST(CASE WHEN ISNULL(M.bAktif, 0) = 1 THEN 1 ELSE 0 END AS bit) AS bAktif, CONVERT(VARCHAR(16), M.dteIslemTarihi, 120) AS dteIslemTarihi, ISNULL(M.sKullaniciAdi, '') AS sKullaniciAdi FROM dbo.mk_MaliyetParcaEslestirme M WITH (NOLOCK) LEFT JOIN dbo.spUrtMTBolum B WITH (NOLOCK) ON B.nUrtMTBolumID = M.nUrtMTBolumID AND ISNULL(B.nUrtTipiID, 0) = 1 OUTER APPLY ( SELECT STUFF(( SELECT ',' + LTRIM(RTRIM(CONVERT(VARCHAR(32), X.nHammaddeTuruNo))) FROM dbo.mk_MaliyetParcaEslestirme_HammaddeTuru X WITH (NOLOCK) WHERE X.mapping_id = M.id ORDER BY X.nHammaddeTuruNo FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS HammaddeTurleri ) H WHERE (@p1 = '' OR LTRIM(RTRIM(M.UrunIlkGrubu)) = @p1) AND (@p2 = '' OR LTRIM(RTRIM(M.UrunAnaGrubu)) = @p2) AND (@p3 = '' OR LTRIM(RTRIM(M.UrunAltGrubu)) = @p3) AND (@p4 <= 0 OR M.nUrtMTBolumID = @p4) AND (@p5 IS NULL OR ISNULL(M.bAktif, 0) = @p5) ORDER BY M.UrunAltGrubu, M.UrunAnaGrubu, M.nUrtMTBolumID ` var activeParam any = nil if onlyActive != nil { if *onlyActive { activeParam = 1 } else { activeParam = 0 } } return uretimDB.QueryContext(ctx, sqlText, urunIlkGrubu, urunAnaGrubu, urunAltGrubu, nUrtMTBolumID, activeParam) } func UpsertProductionProductCostingParcaMapping(ctx context.Context, uretimDB *sql.DB, urunIlkGrubu string, urunAnaGrubu string, urunAltGrubu string, nUrtMTBolumID int, nHammaddeTurleri []int, bAktif bool, user string) (mappingID int, err error) { urunIlkGrubu = strings.TrimSpace(urunIlkGrubu) urunAnaGrubu = strings.TrimSpace(urunAnaGrubu) urunAltGrubu = strings.TrimSpace(urunAltGrubu) user = strings.TrimSpace(user) activeVal := 0 if bAktif { activeVal = 1 } tx, err := uretimDB.BeginTx(ctx, nil) if err != nil { return 0, err } defer func() { if err != nil { _ = tx.Rollback() } }() // 1) Upsert header row and get mapping id sqlText := ` DECLARE @id INT; SELECT TOP 1 @id = id FROM dbo.mk_MaliyetParcaEslestirme WITH (UPDLOCK, HOLDLOCK) WHERE LTRIM(RTRIM(UrunIlkGrubu)) = @p1 AND LTRIM(RTRIM(UrunAnaGrubu)) = @p2 AND LTRIM(RTRIM(UrunAltGrubu)) = @p3 AND nUrtMTBolumID = @p4; IF @id IS NULL BEGIN INSERT INTO dbo.mk_MaliyetParcaEslestirme (UrunIlkGrubu, UrunAnaGrubu, UrunAltGrubu, nUrtMTBolumID, bAktif, sKullaniciAdi, dteIslemTarihi) VALUES (@p1, @p2, @p3, @p4, @p5, NULLIF(@p6, ''), GETDATE()); SET @id = SCOPE_IDENTITY(); END ELSE BEGIN UPDATE dbo.mk_MaliyetParcaEslestirme SET bAktif = @p5, sKullaniciAdiDeg = NULLIF(@p6, ''), dteIslemTarihiDeg = GETDATE() WHERE id = @id; END SELECT @id; ` if err = tx.QueryRowContext(ctx, sqlText, urunIlkGrubu, urunAnaGrubu, urunAltGrubu, nUrtMTBolumID, activeVal, user).Scan(&mappingID); err != nil { return 0, err } // 2) Replace child rows if _, err = tx.ExecContext(ctx, `DELETE FROM dbo.mk_MaliyetParcaEslestirme_HammaddeTuru WHERE mapping_id = @p1;`, mappingID); err != nil { return 0, err } insertChild := `INSERT INTO dbo.mk_MaliyetParcaEslestirme_HammaddeTuru (mapping_id, nHammaddeTuruNo) VALUES (@p1, @p2);` seen := make(map[int]bool, len(nHammaddeTurleri)) for _, n := range nHammaddeTurleri { if n <= 0 { continue } if seen[n] { continue } seen[n] = true if _, err = tx.ExecContext(ctx, insertChild, mappingID, n); err != nil { return 0, err } } if err = tx.Commit(); err != nil { return 0, err } return mappingID, nil } type ProductionProductCostingInvalidHammaddeForPart struct { NHammaddeTuruNo int Aciklama string MTBolumID int } // FilterHammaddeTurleriForPart enforces spUrtOnMLHammaddeTuru.MTnUrtMTBolumID rules: // - If MTnUrtMTBolumID > 0, the hammadde type is allowed only for that part (nUrtMTBolumID). // - If MTnUrtMTBolumID is 0/NULL, it is considered global/unknown and allowed. func FilterHammaddeTurleriForPart( ctx context.Context, uretimDB *sql.DB, nUrtMTBolumID int, nHammaddeTurleri []int, ) (allowed []int, invalid []ProductionProductCostingInvalidHammaddeForPart, err error) { seen := make(map[int]bool, len(nHammaddeTurleri)) unique := make([]int, 0, len(nHammaddeTurleri)) for _, n := range nHammaddeTurleri { if n <= 0 || seen[n] { continue } seen[n] = true unique = append(unique, n) } if len(unique) == 0 { return []int{}, []ProductionProductCostingInvalidHammaddeForPart{}, nil } // Build IN list safely. ph := make([]string, 0, len(unique)) args := make([]any, 0, len(unique)) for i, n := range unique { ph = append(ph, fmt.Sprintf("@p%d", i+1)) args = append(args, n) } sqlText := fmt.Sprintf(` SELECT ISNULL(H.nHammaddeTuruNo, 0) AS nHammaddeTuruNo, ISNULL(H.sAciklama, '') AS sAciklama, ISNULL(H.MTnUrtMTBolumID, 0) AS MTnUrtMTBolumID FROM dbo.spUrtOnMLHammaddeTuru H WITH (NOLOCK) WHERE H.nHammaddeTuruNo IN (%s) `, strings.Join(ph, ",")) rows, qerr := uretimDB.QueryContext(ctx, sqlText, args...) if qerr != nil { return nil, nil, qerr } defer rows.Close() type meta struct { aciklama string mtBolumID int } metaByNo := map[int]meta{} for rows.Next() { var no int var aciklama string var mtBolum int if scanErr := rows.Scan(&no, &aciklama, &mtBolum); scanErr != nil { return nil, nil, scanErr } metaByNo[no] = meta{aciklama: strings.TrimSpace(aciklama), mtBolumID: mtBolum} } if rowsErr := rows.Err(); rowsErr != nil { return nil, nil, rowsErr } allowed = make([]int, 0, len(unique)) invalid = make([]ProductionProductCostingInvalidHammaddeForPart, 0) for _, n := range unique { m, ok := metaByNo[n] if !ok { // Unknown in lookup; allow (we can't validate). allowed = append(allowed, n) continue } if m.mtBolumID > 0 && nUrtMTBolumID > 0 && m.mtBolumID != nUrtMTBolumID { invalid = append(invalid, ProductionProductCostingInvalidHammaddeForPart{ NHammaddeTuruNo: n, Aciklama: m.aciklama, MTBolumID: m.mtBolumID, }) continue } allowed = append(allowed, n) } return allowed, invalid, nil } func SetProductionProductCostingParcaMappingActive(ctx context.Context, uretimDB *sql.DB, id int, bAktif bool, user string) error { user = strings.TrimSpace(user) activeVal := 0 if bAktif { activeVal = 1 } sqlText := ` UPDATE dbo.mk_MaliyetParcaEslestirme SET bAktif = @p2, sKullaniciAdiDeg = NULLIF(@p3, ''), dteIslemTarihiDeg = GETDATE() WHERE id = @p1; ` _, err := uretimDB.ExecContext(ctx, sqlText, id, activeVal, user) return err } func DeleteProductionProductCostingParcaMapping(ctx context.Context, uretimDB *sql.DB, id int) error { tx, err := uretimDB.BeginTx(ctx, nil) if err != nil { return err } defer func() { if err != nil { _ = tx.Rollback() } }() if _, err = tx.ExecContext(ctx, `DELETE FROM dbo.mk_MaliyetParcaEslestirme_HammaddeTuru WHERE mapping_id = @p1;`, id); err != nil { return err } if _, err = tx.ExecContext(ctx, `DELETE FROM dbo.mk_MaliyetParcaEslestirme WHERE id = @p1;`, id); err != nil { return err } return tx.Commit() } func GetProductionNoCostProducts( ctx context.Context, uretimDB *sql.DB, fromDate string, search string, ) (*sql.Rows, error) { fromDate = strings.TrimSpace(fromDate) if fromDate == "" { fromDate = "2025-06-01" } search = strings.TrimSpace(search) sqlText := ` SELECT CASE WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('N','X','S','O','I','K') THEN N'BAGGI URUN TARAFINDAN URETIME VERILEN' WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('P','F','M') THEN N'FASON ICIN URETILEN' ELSE N'Tanimsiz' END AS UretimSekli, RTRIM(CONVERT(VARCHAR(32), ISNULL(SonIsEmri.nUrtSiparisNo, 0))) AS nUrtSiparisNo, ISNULL(CONVERT(VARCHAR(10), SonIsEmri.dteIslemTarihi, 23), '') AS dteIslemTarihi, ISNULL(SonIsEmri.FirmaKodu, '') AS FirmaKodu, ISNULL(SonIsEmri.FirmaAdi, '') AS FirmaAdi, ISNULL(SonIsEmri.sVeren, '') AS SonIsEmriVeren, ISNULL(SonIsEmri.lMMiktar_G, 0) AS lMMiktar_G, LTRIM(RTRIM(R.sMModelKodu)) AS sMModelKodu, ISNULL(R.sKodu, '') AS sKodu, ISNULL(R.sAdi, '') AS sAdi, ISNULL(R.sKullaniciAdi, '') AS sKullaniciAdi, ISNULL(R.sKullaniciAdiGunc, '') AS sKullaniciAdiGunc FROM dbo.spUrtRecete R OUTER APPLY ( SELECT TOP 1 SD.nUrtSiparisID, SM.nUrtSiparisNo, SD.dteIslemTarihi, SD.lMMiktar_G, SM.sVeren, F.nFirmaID, F.sKodu AS FirmaKodu, F.sAciklama AS FirmaAdi FROM dbo.spUrtSiparisDet SD INNER JOIN dbo.spUrtSiparis SM ON SM.nUrtSiparisID = SD.nUrtSiparisID LEFT JOIN dbo.tbFirma F ON F.nFirmaID = SM.nFirmaID WHERE SD.nUrtReceteID = R.nUrtReceteID ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC ) SonIsEmri WHERE LTRIM(RTRIM(R.sMModelKodu)) <> '' AND LEN(LTRIM(RTRIM(R.sMModelKodu))) = 13 AND R.dteIslemTarihi > @p1 AND ( @p2 = '' OR LTRIM(RTRIM(R.sMModelKodu)) LIKE '%' + @p2 + '%' OR ISNULL(SonIsEmri.FirmaKodu, '') LIKE '%' + @p2 + '%' OR ISNULL(SonIsEmri.FirmaAdi, '') LIKE '%' + @p2 + '%' OR ISNULL(SonIsEmri.sVeren, '') LIKE '%' + @p2 + '%' ) AND NOT EXISTS ( SELECT 1 FROM dbo.spUrtOnMLMas M WHERE LTRIM(RTRIM(M.UrunKodu)) = LTRIM(RTRIM(R.sMModelKodu)) ) ORDER BY SonIsEmri.dteIslemTarihi DESC, LTRIM(RTRIM(R.sMModelKodu)) ASC ` return uretimDB.QueryContext(ctx, sqlText, fromDate, search) } func GetProductionHasCostProducts( ctx context.Context, uretimDB *sql.DB, search string, offset int, limit int, ) (*sql.Rows, error) { search = strings.TrimSpace(search) sqlText := ` WITH SonOnMaliyet AS ( SELECT M.*, ROW_NUMBER() OVER ( PARTITION BY LTRIM(RTRIM(M.UrunKodu)) ORDER BY M.Tarihi DESC, M.dteGuncellemeTarihi DESC, M.nOnMLNo DESC ) AS rn FROM dbo.spUrtOnMLMas M WHERE LTRIM(RTRIM(M.UrunKodu)) <> '' ), SonSiparis AS ( SELECT LTRIM(RTRIM(sMModelKodu)) AS UrunKodu, MAX(dteIslemTarihi) AS SonSiparisTarihi FROM dbo.spUrtSiparisDet GROUP BY LTRIM(RTRIM(sMModelKodu)) ) SELECT CASE WHEN LEFT(LTRIM(RTRIM(OM.UrunKodu)), 1) IN ('N','X','S','O','I','K') THEN N'BAGGI URUN TARAFINDAN URETIME VERILEN' WHEN LEFT(LTRIM(RTRIM(OM.UrunKodu)), 1) IN ('P','F','M') THEN N'FASON ICIN URETILEN' ELSE N'Tanimsiz' END AS UretimSekli, RTRIM(CONVERT(VARCHAR(32), ISNULL(OM.nOnMLNo, 0))) AS nOnMLNo, LTRIM(RTRIM(ISNULL(OM.UrunKodu, ''))) AS UrunKodu, ISNULL(OM.UrunAdi, '') AS UrunAdi, CONVERT(VARCHAR(10), OM.Tarihi, 23) AS Tarihi, CONVERT(VARCHAR(10), OM.dteKayitTarihi, 23) AS dteKayitTarihi, ISNULL(OM.sKullaniciAdi, '') AS sKullaniciAdi, ISNULL(OM.lTutarTL, 0) AS lTutarTL, ISNULL(OM.lTutarUSD, 0) AS lTutarUSD, ISNULL(OM.lTutarEURO, 0) AS lTutarEURO, CONVERT(VARCHAR(10), OM.dteGuncellemeTarihi, 23) AS dteGuncellemeTarihi, ISNULL(OM.sGuncellemeKullaniciAdi, '') AS sGuncellemeKullaniciAdi, RTRIM(CONVERT(VARCHAR(32), ISNULL(OM.nUrtReceteID, 0))) AS nUrtReceteID, ISNULL(OM.sAciklama, '') AS sAciklama, ISNULL(CONVERT(VARCHAR(10), SS.SonSiparisTarihi, 23), '') AS SonSiparisTarihi, CASE WHEN ISNULL(OM.lTutarUSD, 0) = 0 THEN N'GUNCELLEME GEREKIYOR' WHEN SS.SonSiparisTarihi IS NULL THEN N'SIPARIS YOK' WHEN SS.SonSiparisTarihi > OM.Tarihi THEN N'GUNCELLEME GEREKIYOR' ELSE N'GUNCEL' END AS MaliyetDurumu FROM SonOnMaliyet OM LEFT JOIN SonSiparis SS ON SS.UrunKodu = LTRIM(RTRIM(OM.UrunKodu)) WHERE OM.rn = 1 AND ( @p1 = '' OR RTRIM(CONVERT(VARCHAR(32), ISNULL(OM.nOnMLNo, 0))) LIKE '%' + @p1 + '%' OR LTRIM(RTRIM(OM.UrunKodu)) LIKE '%' + @p1 + '%' OR ISNULL(OM.UrunAdi, '') LIKE '%' + @p1 + '%' OR ISNULL(OM.sAciklama, '') LIKE '%' + @p1 + '%' ) ORDER BY SS.SonSiparisTarihi DESC, OM.nOnMLNo DESC OFFSET @p2 ROWS FETCH NEXT @p3 ROWS ONLY ` return uretimDB.QueryContext(ctx, sqlText, search, offset, limit) } func GetProductionHasCostHistoryByProductCode( ctx context.Context, uretimDB *sql.DB, productCode string, ) (*sql.Rows, error) { productCode = strings.TrimSpace(productCode) sqlText := ` SELECT RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nOnMLNo, 0))) AS nOnMLNo, LTRIM(RTRIM(ISNULL(M.UrunKodu, ''))) AS UrunKodu, ISNULL(M.UrunAdi, '') AS UrunAdi, CONVERT(VARCHAR(16), M.Tarihi, 120) AS Tarihi, ISNULL(M.sKullaniciAdi, '') AS sKullaniciAdi, ISNULL(M.lTutarUSD, 0) AS lTutarUSD, ISNULL(M.lTutarTL, 0) AS lTutarTL, ISNULL(M.lTutarEURO, 0) AS lTutarEURO, ISNULL(M.sDovizCinsi, '') AS sDovizCinsi, ISNULL(M.lTutarDoviz, 0) AS lTutarDoviz, CONVERT(VARCHAR(16), M.dteGuncellemeTarihi, 120) AS dteGuncellemeTarihi, ISNULL(M.sGuncellemeKullaniciAdi, '') AS sGuncellemeKullaniciAdi, RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nUrtReceteID, 0))) AS nUrtReceteID, ISNULL(M.sAciklama, '') AS sAciklama FROM dbo.spUrtOnMLMas M WHERE LTRIM(RTRIM(M.UrunKodu)) = @p1 ORDER BY M.Tarihi DESC, M.dteGuncellemeTarihi DESC, M.nOnMLNo DESC ` return uretimDB.QueryContext(ctx, sqlText, productCode) } func GetProductionHasCostDetailRowsByOnMLNo( ctx context.Context, uretimDB *sql.DB, nOnMLNo int, ) (*sql.Rows, error) { sqlText := ` SELECT -- Prefer the group label stored on the OnML detail row (D.sAciklama3), -- because some hammadde type master rows may have empty/legacy group labels. ISNULL(NULLIF(LTRIM(RTRIM(D.sAciklama3)), ''), ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ')) AS sAciklama3, SUM(ISNULL(D.lTutar, 0)) OVER ( PARTITION BY ISNULL(NULLIF(LTRIM(RTRIM(D.sAciklama3)), ''), ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ')) ) AS GroupTotalTutar, SUM(ISNULL(D.lMiktar, 0) * ISNULL(D.lDovizFiyati, 0)) OVER ( PARTITION BY ISNULL(NULLIF(LTRIM(RTRIM(D.sAciklama3)), ''), ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ')) ) AS GroupTotalUSDTutar, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLDetNo, 0))) AS nOnMLDetNo, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nHammaddeTuruNo, 0))) AS nHammaddeTuruNo, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nUrtMTBolumID, 0))) AS nUrtMTBolumID, -- Normalize code to variantless (tbStok.sModel) when D.sKodu is a variant-coded stock record. ISNULL(NULLIF(LTRIM(RTRIM(SX.sModel)), ''), ISNULL(D.sKodu, '')) AS sKodu, ISNULL(NULLIF(LTRIM(RTRIM(SX.sAciklama)), ''), ISNULL(D.sAciklama, '')) AS sAciklama, ISNULL(D.sRenk, '') AS sRenk, ISNULL(D.sBeden, '') AS sBeden, ISNULL(D.sAciklama2, '') AS sAciklama2, ISNULL(D.lMiktar, 0) AS lMiktar, ISNULL(D.lFiyat, 0) AS lFiyat, ISNULL(D.lTutar, 0) AS lTutar, ISNULL(D.sFiyatTipi, '') AS sFiyatTipi, ISNULL(D.sDovizCinsi, '') AS sDovizCinsi, ISNULL(D.lDovizKuru, 0) AS lDovizKuru, ISNULL(D.lDovizFiyati, 0) AS lDovizFiyati, D.fiyat_girilen AS fiyat_girilen, D.fiyat_doviz AS fiyat_doviz, CAST(CASE WHEN ISNULL(D.Maliyete_dahil, 0) = 1 THEN 1 ELSE 0 END AS bit) AS maliyete_dahil, D.cm_price_type_id AS cm_price_type_id, ISNULL(D.lMiktar, 0) * ISNULL(D.lDovizFiyati, 0) AS usdTutar, 0.0 AS eurTutar, 0.0 AS gbpTutar, ISNULL(D.sBirim, '') AS sBirim, ISNULL(T.sAciklama, '') AS sHammaddeTuruAdi, ISNULL(B.sAdi, '') AS sParcaAdi FROM dbo.spUrtOnMLMasDet D LEFT JOIN dbo.spUrtOnMLHammaddeTuru T ON T.nHammaddeTuruNo = D.nHammaddeTuruNo LEFT JOIN dbo.spUrtMTBolum B ON B.nUrtMTBolumID = D.nUrtMTBolumID OUTER APPLY ( SELECT TOP 1 LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) AS sModel, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sAciklama, '')))) AS sAciklama FROM dbo.tbStok S WITH (NOLOCK) WHERE LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) = LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(D.sKodu, '')))) ) SX WHERE D.nOnMLNo = @p1 ORDER BY GroupTotalTutar DESC, sAciklama3 ASC, ISNULL(D.lTutar, 0) DESC, D.nOnMLDetNo ASC ` return uretimDB.QueryContext(ctx, sqlText, nOnMLNo) } func GetProductionHasCostDetailHeaderByOnMLNo( ctx context.Context, uretimDB *sql.DB, nOnMLNo int, ) (*sql.Row, error) { sqlText := ` SELECT TOP 1 ISNULL(UF.UretimiYapanFirma, '') AS UretimiYapanFirma, ISNULL(UF.SonIsEmriVeren, '') AS SonIsEmriVeren, ISNULL(UF.FirmaKodu, '') AS FirmaKodu, ISNULL(UF.nFirmaID, 0) AS nFirmaID, RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nOnMLNo, 0))) AS nOnMLNo, LTRIM(RTRIM(ISNULL(M.UrunKodu, ''))) AS UrunKodu, ISNULL(M.UrunAdi, '') AS UrunAdi, RTRIM(CONVERT(VARCHAR(32), ISNULL(M.uretim_sekli_id, 0))) AS uretim_sekli_id, ISNULL(US.aciklama, '') AS uretim_sekli, CONVERT(VARCHAR(16), M.dteKayitTarihi, 120) AS dteKayitTarihi, ISNULL(M.sKullaniciAdi, '') AS sKullaniciAdi, ISNULL(M.lTutarTL, 0) AS lTutarTL, ISNULL(M.lTutarUSD, 0) AS lTutarUSD, ISNULL(M.lTutarEURO, 0) AS lTutarEURO, 0.0 AS lTutarGBP, ISNULL(M.sDovizCinsi, '') AS sDovizCinsi, ISNULL(M.lTutarDoviz, 0) AS lTutarDoviz, CONVERT(VARCHAR(16), M.dteGuncellemeTarihi, 120) AS dteGuncellemeTarihi, ISNULL(M.sGuncellemeKullaniciAdi, '') AS sGuncellemeKullaniciAdi, RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nUrtReceteID, 0))) AS nUrtReceteID FROM dbo.spUrtOnMLMas M LEFT JOIN dbo.mk_uretim_sekli US ON US.id = M.uretim_sekli_id OUTER APPLY ( SELECT TOP 1 ISNULL(F.sAciklama, '') AS UretimiYapanFirma, ISNULL(F.sKodu, '') AS FirmaKodu, ISNULL(F.nFirmaID, 0) AS nFirmaID, ISNULL(SM.sVeren, '') AS SonIsEmriVeren FROM dbo.spUrtSiparisDet SD INNER JOIN dbo.spUrtSiparis SM ON SM.nUrtSiparisID = SD.nUrtSiparisID LEFT JOIN dbo.tbFirma F ON F.nFirmaID = SM.nFirmaID WHERE LTRIM(RTRIM(SD.sMModelKodu)) = LTRIM(RTRIM(M.UrunKodu)) ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC ) UF WHERE M.nOnMLNo = @p1 ORDER BY M.nOnMLNo DESC ` return uretimDB.QueryRowContext(ctx, sqlText, nOnMLNo), nil } func GetProductionNoCostDetailHeaderByRecipeCode( ctx context.Context, uretimDB *sql.DB, recipeCode string, productCode string, ) (*sql.Row, error) { recipeCode = strings.TrimSpace(recipeCode) productCode = strings.TrimSpace(productCode) utils.SlogFromContext(ctx).With( "query", "production-product-costing.no-cost-detail-header", "recete_kodu", recipeCode, "urun_kodu", productCode, ).Info("query dispatch") sqlText := ` WITH RecipeMatch AS ( SELECT TOP 1 R.nUrtReceteID, LTRIM(RTRIM(ISNULL(R.sMModelKodu, ''))) AS UrunKodu, ISNULL(R.sAdi, '') AS UrunAdi, CONVERT(VARCHAR(16), R.dteIslemTarihi, 120) AS dteKayitTarihi, ISNULL(R.sKullaniciAdi, '') AS sKullaniciAdi, ISNULL(R.sKullaniciAdiGunc, '') AS sGuncellemeKullaniciAdi, CASE WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('N','X','S','O','I','K') THEN N'BAGGI URUN TARAFINDAN URETIME VERILEN' WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('P','F','M') THEN N'FASON ICIN URETILEN' ELSE N'Tanimsiz' END AS UretimSekli FROM dbo.spUrtRecete R WHERE LTRIM(RTRIM(ISNULL(R.sKodu, ''))) = @p1 AND (@p2 = '' OR LTRIM(RTRIM(ISNULL(R.sMModelKodu, ''))) = @p2) ORDER BY R.dteIslemTarihi DESC, R.nUrtReceteID DESC ) SELECT TOP 1 ISNULL(SonIsEmri.FirmaAdi, '') AS UretimiYapanFirma, ISNULL(SonIsEmri.SonIsEmriVeren, '') AS SonIsEmriVeren, ISNULL(SonIsEmri.FirmaKodu, '') AS FirmaKodu, ISNULL(SonIsEmri.nFirmaID, 0) AS nFirmaID, '' AS nOnMLNo, RM.UrunKodu, RM.UrunAdi, '' AS UretimSekliID, RM.UretimSekli, ISNULL(SonIsEmri.dteIslemTarihi, RM.dteKayitTarihi) AS dteKayitTarihi, RM.sKullaniciAdi, 0.0 AS lTutarTL, 0.0 AS lTutarUSD, 0.0 AS lTutarEURO, 0.0 AS lTutarGBP, 'USD' AS sDovizCinsi, 0.0 AS lTutarDoviz, '' AS dteGuncellemeTarihi, RM.sGuncellemeKullaniciAdi, RTRIM(CONVERT(VARCHAR(32), ISNULL(RM.nUrtReceteID, 0))) AS nUrtReceteID FROM RecipeMatch RM OUTER APPLY ( SELECT TOP 1 ISNULL(F.sAciklama, '') AS FirmaAdi, ISNULL(F.sKodu, '') AS FirmaKodu, ISNULL(F.nFirmaID, 0) AS nFirmaID, ISNULL(SM.sVeren, '') AS SonIsEmriVeren, CONVERT(VARCHAR(16), SD.dteIslemTarihi, 120) AS dteIslemTarihi FROM dbo.spUrtSiparisDet SD INNER JOIN dbo.spUrtSiparis SM ON SM.nUrtSiparisID = SD.nUrtSiparisID LEFT JOIN dbo.tbFirma F ON F.nFirmaID = SM.nFirmaID WHERE SD.nUrtReceteID = RM.nUrtReceteID ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC ) SonIsEmri ` return uretimDB.QueryRowContext(ctx, sqlText, recipeCode, productCode), nil } func GetProductionNoCostDetailRowsByRecipeCode( ctx context.Context, uretimDB *sql.DB, recipeCode string, productCode string, ) (*sql.Rows, error) { recipeCode = strings.TrimSpace(recipeCode) productCode = strings.TrimSpace(productCode) logger := utils.SlogFromContext(ctx).With( "query", "production-product-costing.no-cost-detail-rows", "recete_kodu", recipeCode, "urun_kodu", productCode, ) logger.Info("query dispatch") sqlText := ` WITH RecipeMatch AS ( SELECT TOP 1 R.nUrtReceteID FROM dbo.spUrtRecete R WHERE LTRIM(RTRIM(ISNULL(R.sKodu, ''))) = @p1 AND (@p2 = '' OR LTRIM(RTRIM(ISNULL(R.sMModelKodu, ''))) = @p2) ORDER BY R.dteIslemTarihi DESC, R.nUrtReceteID DESC ), HammaddeTekil AS ( SELECT -- Group label: DT/TP/CM2/FABRIC... Prefer sAciklama3, then sAciklama2. Never fall back to sAciklama (name). COALESCE(NULLIF(LTRIM(RTRIM(HT.sAciklama3)), ''), NULLIF(LTRIM(RTRIM(HT.sAciklama2)), ''), N'TANIMSIZ') AS sAciklama3, ISNULL(HT.nHammaddeTuruNo, 0) AS nHammaddeTuruNoSort, RTRIM(CONVERT(VARCHAR(32), ISNULL(HT.nHammaddeTuruNo, 0))) AS nHammaddeTuruNo, -- Match URETIM's sp_pUrtOnMaliyetRecetedenKop behavior: use model code + color code instead of variant stock code. ISNULL(S.sModel, ISNULL(S.sKodu, '')) AS sKodu, ISNULL(S.sAciklama, '') AS sAciklama, ISNULL(S.sRenk, '') AS sRenk, ISNULL(HT.sAciklama, '') AS sHammaddeTuruAdi, ISNULL(S.sBirimCinsi1, '') AS sBirim, ISNULL(RMik.lHMiktar, 0) AS lMiktar, ISNULL(HT.MTnUrtMTBolumID, 0) AS MTnUrtMTBolumID, RTRIM(CONVERT(VARCHAR(32), ISNULL(HT.MTnUrtMTBolumID, 0))) AS nUrtMTBolumID, ISNULL(B.sAdi, '') AS sParcaAdi, ROW_NUMBER() OVER ( PARTITION BY HT.nHammaddeTuruNo ORDER BY ISNULL(S.sModel, ISNULL(S.sKodu, '')) ) AS rn, ROW_NUMBER() OVER ( ORDER BY HT.nHammaddeTuruNo, ISNULL(S.sModel, ISNULL(S.sKodu, '')) ) AS rowNo FROM RecipeMatch R INNER JOIN dbo.spUrtRecMBolumMik RMik ON RMik.nUrtReceteID = R.nUrtReceteID LEFT JOIN dbo.tbStok S ON S.nStokID = RMik.nHStokID OUTER APPLY ( SELECT TOP 1 H.nHammaddeTuruNo, H.sAciklama, H.sAciklama2, H.sAciklama3, H.MTnUrtMTBolumID FROM dbo.spUrtOnMLHammaddeTuru H -- In our data, RMik.nUrtMBolumID carries the required hammadde type number (e.g. 900/901/3300), -- not a "bolum id". So match by hammadde type number. WHERE H.nHammaddeTuruNo = RMik.nUrtMBolumID ORDER BY CASE WHEN H.MTnUrtMTBolumID = RMik.nUrtMTBolumID THEN 0 ELSE 1 END, H.nHammaddeTuruNo ) HT LEFT JOIN dbo.spUrtMTBolum B WITH (NOLOCK) ON B.nUrtMTBolumID = HT.MTnUrtMTBolumID AND ISNULL(B.nUrtTipiID, 0) = 1 WHERE HT.nHammaddeTuruNo IS NOT NULL ) SELECT HT.sAciklama3, 0.0 AS GroupTotalTutar, 0.0 AS GroupTotalUSDTutar, '' AS nOnMLNo, RTRIM(CONVERT(VARCHAR(32), ISNULL(HT.rowNo, 0))) AS nOnMLDetNo, HT.nHammaddeTuruNo, HT.nUrtMTBolumID, HT.sKodu, HT.sAciklama, HT.sRenk AS sRenk, '' AS sBeden, '' AS sAciklama2, HT.lMiktar, 0.0 AS lFiyat, 0.0 AS lTutar, '' AS sFiyatTipi, 'USD' AS sDovizCinsi, 0.0 AS lDovizKuru, 0.0 AS lDovizFiyati, NULL AS fiyat_girilen, '' AS fiyat_doviz, CAST(1 AS bit) AS maliyete_dahil, NULL AS cm_price_type_id, 0.0 AS usdTutar, 0.0 AS eurTutar, 0.0 AS gbpTutar, HT.sBirim, HT.sHammaddeTuruAdi, HT.sParcaAdi AS sParcaAdi FROM HammaddeTekil HT WHERE HT.rn = 1 ORDER BY HT.nHammaddeTuruNoSort, HT.sKodu ` rows, err := uretimDB.QueryContext(ctx, sqlText, recipeCode, productCode) if err != nil { logger.Error("query error", "err", err) return nil, err } return rows, nil } func GetProductionTypes(ctx context.Context, uretimDB *sql.DB) (*sql.Rows, error) { sqlText := `SELECT id, aciklama FROM dbo.mk_uretim_sekli ORDER BY id` return uretimDB.QueryContext(ctx, sqlText) } func GetProductionHasCostDetailHammaddeTypeOptions( ctx context.Context, uretimDB *sql.DB, search string, limit int, group string, onlyActive *bool, ) (*sql.Rows, error) { search = strings.TrimSpace(search) group = strings.TrimSpace(group) if limit <= 0 { limit = 50 } searchLike := "%" + search + "%" sqlText := ` SELECT TOP (@p2) RTRIM(CONVERT(VARCHAR(32), ISNULL(T.nHammaddeTuruNo, 0))) AS nHammaddeTuruNo, ISNULL(T.sAciklama, '') AS sHammaddeTuruAdi, COALESCE(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), NULLIF(LTRIM(RTRIM(T.sAciklama2)), ''), N'TANIMSIZ') AS sAciklama3, ISNULL(T.MTnUrtMTBolumID, 0) AS mtUrtMTBolumID, ISNULL(B.sAdi, '') AS sParcaAdi FROM dbo.spUrtOnMLHammaddeTuru T WITH (NOLOCK) LEFT JOIN dbo.spUrtMTBolum B WITH (NOLOCK) ON B.nUrtMTBolumID = T.MTnUrtMTBolumID AND ISNULL(B.nUrtTipiID, 0) = 1 WHERE -- Active filtering: -- - By default, list active rows. -- - If searching by exact number, allow inactive too (legacy CM2 etc.). -- - If onlyActive flag is provided, honor it explicitly. ( (@p5 IS NULL AND (ISNULL(T.bAktif, 0) = 1 OR (@p1 <> '' AND RTRIM(CONVERT(VARCHAR(32), ISNULL(T.nHammaddeTuruNo, 0))) = @p1))) OR (@p5 IS NOT NULL AND ISNULL(T.bAktif, 0) = @p5) ) AND ( @p4 = '' OR COALESCE(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), NULLIF(LTRIM(RTRIM(T.sAciklama2)), ''), N'TANIMSIZ') = @p4 ) AND ( @p1 = '' OR RTRIM(CONVERT(VARCHAR(32), ISNULL(T.nHammaddeTuruNo, 0))) LIKE @p3 OR ISNULL(T.sAciklama, '') LIKE @p3 OR ISNULL(T.sAciklama2, '') LIKE @p3 OR ISNULL(T.sAciklama3, '') LIKE @p3 OR ISNULL(B.sAdi, '') LIKE @p3 ) ORDER BY CASE WHEN @p1 <> '' AND RTRIM(CONVERT(VARCHAR(32), ISNULL(T.nHammaddeTuruNo, 0))) = @p1 THEN 0 WHEN @p1 <> '' AND ISNULL(T.sAciklama, '') = @p1 THEN 1 ELSE 2 END, T.nHammaddeTuruNo ` return uretimDB.QueryContext(ctx, sqlText, search, limit, searchLike, group, onlyActive) } func GetProductionHammaddeByNos(ctx context.Context, uretimDB *sql.DB, nos []int) ([]models.ProductionProductCostingHammaddeByNosItem, error) { clean := make([]int, 0, len(nos)) seen := make(map[int]struct{}, len(nos)) for _, n := range nos { if n <= 0 { continue } if _, ok := seen[n]; ok { continue } seen[n] = struct{}{} clean = append(clean, n) } if len(clean) == 0 { return []models.ProductionProductCostingHammaddeByNosItem{}, nil } if len(clean) > 5000 { return nil, fmt.Errorf("too many nos") } valueRows := make([]string, 0, len(clean)) args := make([]any, 0, len(clean)) for i, n := range clean { valueRows = append(valueRows, "(@p"+strconv.Itoa(i+1)+")") args = append(args, n) } sqlText := ` WITH req(nHammaddeTuruNo) AS ( SELECT DISTINCT v.nHammaddeTuruNo FROM (VALUES ` + strings.Join(valueRows, ",") + `) v(nHammaddeTuruNo) ) SELECT ISNULL(T.nHammaddeTuruNo, 0) AS nHammaddeTuruNo, ISNULL(T.sAciklama, '') AS sAciklama, ISNULL(T.MTnUrtMTBolumID, 0) AS mtUrtMTBolumID, ISNULL(B.sAdi, '') AS sParcaAdi FROM dbo.spUrtOnMLHammaddeTuru T WITH (NOLOCK) INNER JOIN req R ON R.nHammaddeTuruNo = T.nHammaddeTuruNo LEFT JOIN dbo.spUrtMTBolum B WITH (NOLOCK) ON B.nUrtMTBolumID = T.MTnUrtMTBolumID AND ISNULL(B.nUrtTipiID, 0) = 1 WHERE ISNULL(T.bAktif, 0) = 1 ORDER BY T.nHammaddeTuruNo; ` rows, err := uretimDB.QueryContext(ctx, sqlText, args...) if err != nil { return nil, err } defer rows.Close() out := make([]models.ProductionProductCostingHammaddeByNosItem, 0, len(clean)) for rows.Next() { var it models.ProductionProductCostingHammaddeByNosItem if err := rows.Scan(&it.NHammaddeTuruNo, &it.SAciklama, &it.MTUrtMTBolumID, &it.SParcaAdi); err != nil { return nil, err } out = append(out, it) } if err := rows.Err(); err != nil { return nil, err } return out, nil } // ============================================================ // Default quantities (URETIM): mk_MaliyetParcaEslestirme_vmiktarlar // ============================================================ func ListProductionProductCostingDefaultQtyRows(ctx context.Context, uretimDB *sql.DB, search string, limit int) (*sql.Rows, error) { search = strings.TrimSpace(search) if limit <= 0 { limit = 500 } if limit > 5000 { limit = 5000 } searchLike := "%" + search + "%" sqlText := ` SELECT TOP (@p3) ISNULL(V.nHammaddeTuruNo, 0) AS nHammaddeTuruNo, ISNULL(H.sAciklama, '') AS sAciklama, ISNULL(V.lDefaultMiktar, 0) AS lDefaultMiktar, CONVERT(VARCHAR(16), V.dteCalcTarihi, 120) AS dteCalcTarihi, -- We intentionally don't depend on mk_MaliyetParcaEslestirme_vmiktarlar.bAktif -- to keep this feature robust across schema changes; only active hammadde types are listed. CAST(1 AS bit) AS bAktif FROM dbo.mk_MaliyetParcaEslestirme_vmiktarlar V WITH (NOLOCK) LEFT JOIN dbo.spUrtOnMLHammaddeTuru H WITH (NOLOCK) ON H.nHammaddeTuruNo = V.nHammaddeTuruNo WHERE (@p1 = '' OR CONVERT(VARCHAR(32), ISNULL(V.nHammaddeTuruNo, 0)) LIKE @p2) AND ISNULL(H.bAktif, 0) = 1 ORDER BY V.nHammaddeTuruNo ASC ` return uretimDB.QueryContext(ctx, sqlText, search, searchLike, limit) } func UpsertProductionProductCostingDefaultQtyRow(ctx context.Context, uretimDB *sql.DB, nHammaddeTuruNo int, lDefaultMiktar float64, bAktif *bool) error { // NOTE: Legacy helper kept for backward-compat but now behaves as UPDATE-only. sqlText := ` UPDATE dbo.mk_MaliyetParcaEslestirme_vmiktarlar SET lDefaultMiktar = @p2, dteCalcTarihi = GETDATE() WHERE nHammaddeTuruNo = @p1; SELECT @@ROWCOUNT; ` var affected int if err := uretimDB.QueryRowContext(ctx, sqlText, nHammaddeTuruNo, lDefaultMiktar).Scan(&affected); err != nil { return err } if affected == 0 { return fmt.Errorf("default qty row not found: nHammaddeTuruNo=%d", nHammaddeTuruNo) } return nil } func RefreshProductionProductCostingDefaultQty(ctx context.Context, uretimDB *sql.DB, topN int) error { if topN <= 0 { topN = 10 } if topN > 50 { topN = 50 } sqlText := ` ;WITH ranked AS ( SELECT D.nHammaddeTuruNo, D.lMiktar, ROW_NUMBER() OVER ( PARTITION BY D.nHammaddeTuruNo ORDER BY ISNULL(M.Tarihi, '19000101') DESC, ISNULL(M.dteGuncellemeTarihi, '19000101') DESC, D.nOnMLNo DESC, D.dteIslemTarihi DESC, D.nOnMLDetNo DESC ) AS rn FROM dbo.spUrtOnMLMasDet D WITH (NOLOCK) INNER JOIN dbo.spUrtOnMLMas M WITH (NOLOCK) ON M.nOnMLNo = D.nOnMLNo WHERE ISNULL(D.lMiktar, 0) > 0 AND ISNULL(M.bIptal, 0) = 0 ), agg AS ( SELECT nHammaddeTuruNo, CAST(AVG(CAST(lMiktar AS float)) AS numeric(14,4)) AS lDefaultMiktar FROM ranked WHERE rn <= @p1 GROUP BY nHammaddeTuruNo ) MERGE dbo.mk_MaliyetParcaEslestirme_vmiktarlar AS T USING agg AS S ON T.nHammaddeTuruNo = S.nHammaddeTuruNo WHEN MATCHED THEN UPDATE SET T.lDefaultMiktar = S.lDefaultMiktar, T.dteCalcTarihi = GETDATE() WHEN NOT MATCHED THEN INSERT (nHammaddeTuruNo, lDefaultMiktar, dteCalcTarihi) VALUES (S.nHammaddeTuruNo, S.lDefaultMiktar, GETDATE()); ` _, err := uretimDB.ExecContext(ctx, sqlText, topN) return err } func CalcProductionProductCostingDefaultQtyFromLastOnML(ctx context.Context, uretimDB *sql.DB, nHammaddeTuruNo int, topN int) (float64, int, error) { if nHammaddeTuruNo <= 0 { return 0, 0, fmt.Errorf("nHammaddeTuruNo required") } if topN <= 0 { topN = 10 } if topN > 50 { topN = 50 } sqlText := ` ;WITH ranked AS ( SELECT TOP (@p2) ISNULL(D.lMiktar, 0) AS lMiktar FROM dbo.spUrtOnMLMasDet D WITH (NOLOCK) INNER JOIN dbo.spUrtOnMLMas M WITH (NOLOCK) ON M.nOnMLNo = D.nOnMLNo WHERE D.nHammaddeTuruNo = @p1 AND ISNULL(D.lMiktar, 0) > 0 ORDER BY ISNULL(M.Tarihi, M.dteKayitTarihi) DESC, D.nOnMLNo DESC, D.nOnMLDetNo DESC ) SELECT CAST(ISNULL(AVG(CAST(lMiktar AS DECIMAL(18,4))), 0) AS FLOAT) AS avgQty, COUNT(1) AS sampleCount FROM ranked; ` var avg float64 var cnt int if err := uretimDB.QueryRowContext(ctx, sqlText, nHammaddeTuruNo, topN).Scan(&avg, &cnt); err != nil { return 0, 0, err } return avg, cnt, nil } func LookupProductionProductCostingDefaultQtyByNos(ctx context.Context, uretimDB *sql.DB, nos []int) ([]struct { No int Aciklama string Qty float64 }, error) { clean := make([]int, 0, len(nos)) seen := make(map[int]struct{}, len(nos)) for _, n := range nos { if n <= 0 { continue } if _, ok := seen[n]; ok { continue } seen[n] = struct{}{} clean = append(clean, n) } if len(clean) == 0 { return []struct { No int Aciklama string Qty float64 }{}, nil } if len(clean) > 1000 { return nil, fmt.Errorf("too many hammadde nos") } valueRows := make([]string, 0, len(clean)) args := make([]any, 0, len(clean)) for i, n := range clean { valueRows = append(valueRows, "(@p"+strconv.Itoa(i+1)+")") args = append(args, n) } sqlText := ` WITH req(nHammaddeTuruNo) AS ( SELECT DISTINCT v.nHammaddeTuruNo FROM (VALUES ` + strings.Join(valueRows, ",") + `) v(nHammaddeTuruNo) ) SELECT ISNULL(V.nHammaddeTuruNo, 0) AS nHammaddeTuruNo, ISNULL(H.sAciklama, '') AS sAciklama, CAST(ISNULL(V.lDefaultMiktar, 0) AS FLOAT) AS lDefaultMiktar FROM req R INNER JOIN dbo.mk_MaliyetParcaEslestirme_vmiktarlar V WITH (NOLOCK) ON V.nHammaddeTuruNo = R.nHammaddeTuruNo INNER JOIN dbo.spUrtOnMLHammaddeTuru H WITH (NOLOCK) ON H.nHammaddeTuruNo = V.nHammaddeTuruNo WHERE ISNULL(H.bAktif, 0) = 1; ` rows, err := uretimDB.QueryContext(ctx, sqlText, args...) if err != nil { return nil, err } defer rows.Close() out := make([]struct { No int Aciklama string Qty float64 }, 0, len(clean)) for rows.Next() { var no int var aciklama sql.NullString var qty float64 if err := rows.Scan(&no, &aciklama, &qty); err != nil { return nil, err } if no > 0 && qty > 0 { out = append(out, struct { No int Aciklama string Qty float64 }{No: no, Aciklama: strings.TrimSpace(aciklama.String), Qty: qty}) } } if err := rows.Err(); err != nil { return nil, err } return out, nil } func LookupLastOnMLMasDetByHammaddeNos( ctx context.Context, uretimDB *sql.DB, nos []int, beforeDate string, // YYYY-MM-DD optional excludeOnMLNo int, nFirmaID int, onlyICode bool, limitPerType int, ) ([]models.ProductionProductCostingLastOnMLDetLookupItem, error) { if limitPerType <= 0 { limitPerType = 1 } if limitPerType > 1 { limitPerType = 1 } clean := make([]int, 0, len(nos)) seen := make(map[int]struct{}, len(nos)) for _, n := range nos { if n <= 0 { continue } if _, ok := seen[n]; ok { continue } seen[n] = struct{}{} clean = append(clean, n) } if len(clean) == 0 { return []models.ProductionProductCostingLastOnMLDetLookupItem{}, nil } if len(clean) > 500 { return nil, fmt.Errorf("too many hammadde nos") } valueRows := make([]string, 0, len(clean)) args := make([]any, 0, len(clean)+2) for i, n := range clean { valueRows = append(valueRows, "(@p"+strconv.Itoa(i+1)+")") args = append(args, n) } // extra params at the end args = append(args, strings.TrimSpace(beforeDate)) args = append(args, excludeOnMLNo) args = append(args, nFirmaID) if onlyICode { args = append(args, 1) } else { args = append(args, 0) } beforeParam := "@p" + strconv.Itoa(len(clean)+1) excludeParam := "@p" + strconv.Itoa(len(clean)+2) firmaParam := "@p" + strconv.Itoa(len(clean)+3) onlyIParam := "@p" + strconv.Itoa(len(clean)+4) sqlText := ` WITH req(nHammaddeTuruNo) AS ( SELECT DISTINCT v.nHammaddeTuruNo FROM (VALUES ` + strings.Join(valueRows, ",") + `) v(nHammaddeTuruNo) ), ranked AS ( SELECT D.nHammaddeTuruNo, LTRIM(RTRIM(ISNULL(D.sKodu, ''))) AS sKodu, LTRIM(RTRIM(ISNULL(D.sAciklama, ''))) AS sAciklama, LTRIM(RTRIM(ISNULL(D.sBirim, ''))) AS sBirim, LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) AS fiyat_doviz, CAST(ISNULL(D.fiyat_girilen, 0) AS FLOAT) AS fiyat_girilen, CAST(CASE WHEN ISNULL(` + firmaParam + `, 0) > 0 AND ISNULL(M.nFirmaID, 0) = ISNULL(` + firmaParam + `, 0) THEN 1 ELSE 0 END AS bit) AS is_same_firma, ROW_NUMBER() OVER ( PARTITION BY D.nHammaddeTuruNo ORDER BY CASE WHEN ISNULL(` + firmaParam + `, 0) > 0 AND ISNULL(M.nFirmaID, 0) = ISNULL(` + firmaParam + `, 0) THEN 0 ELSE 1 END, COALESCE(M.Tarihi, M.dteKayitTarihi) DESC, M.nOnMLNo DESC, D.nOnMLDetNo DESC ) AS rn FROM dbo.spUrtOnMLMasDet D WITH (NOLOCK) INNER JOIN dbo.spUrtOnMLMas M WITH (NOLOCK) ON M.nOnMLNo = D.nOnMLNo INNER JOIN req R ON R.nHammaddeTuruNo = D.nHammaddeTuruNo WHERE ISNULL(D.fiyat_girilen, 0) > 0 AND LTRIM(RTRIM(ISNULL(D.sKodu, ''))) <> '' AND (ISNULL(` + onlyIParam + `, 0) = 0 OR LTRIM(RTRIM(ISNULL(D.sKodu, ''))) LIKE 'I.%') AND (` + beforeParam + ` = '' OR CONVERT(date, COALESCE(M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, ` + beforeParam + `, 23)) AND (ISNULL(` + excludeParam + `, 0) <= 0 OR M.nOnMLNo <> ` + excludeParam + `) ) SELECT ISNULL(nHammaddeTuruNo, 0) AS nHammaddeTuruNo, ISNULL(sKodu, '') AS sKodu, ISNULL(sAciklama, '') AS sAciklama, ISNULL(sBirim, '') AS sBirim, ISNULL(fiyat_doviz, '') AS fiyat_doviz, ISNULL(fiyat_girilen, 0) AS fiyat_girilen, CAST(ISNULL(is_same_firma, 0) AS bit) AS is_same_firma FROM ranked WHERE rn = 1; ` rows, err := uretimDB.QueryContext(ctx, sqlText, args...) if err != nil { return nil, err } defer rows.Close() out := make([]models.ProductionProductCostingLastOnMLDetLookupItem, 0, len(clean)) for rows.Next() { var item models.ProductionProductCostingLastOnMLDetLookupItem if err := rows.Scan(&item.NHammaddeTuruNo, &item.SKodu, &item.SAciklama, &item.SBirim, &item.FiyatDoviz, &item.FiyatGirilen, &item.IsSameFirma); err != nil { return nil, err } out = append(out, item) } if err := rows.Err(); err != nil { return nil, err } return out, nil } func buildSQLServerFullTextPrefixQuery(search string) string { terms := strings.Fields(strings.TrimSpace(search)) parts := make([]string, 0, len(terms)) for _, term := range terms { cleaned := strings.Map(func(r rune) rune { if unicode.IsLetter(r) || unicode.IsDigit(r) { return r } return -1 }, term) if len([]rune(cleaned)) < 2 { continue } parts = append(parts, fmt.Sprintf("\"%s*\"", cleaned)) } return strings.Join(parts, " AND ") } func hasProductionHasCostDetailItemFullTextIndex( ctx context.Context, uretimDB *sql.DB, ) bool { var exists int err := uretimDB.QueryRowContext(ctx, ` SELECT CASE WHEN EXISTS ( SELECT 1 FROM sys.fulltext_indexes fi INNER JOIN sys.fulltext_index_columns fic ON fic.object_id = fi.object_id INNER JOIN sys.columns c ON c.object_id = fic.object_id AND c.column_id = fic.column_id WHERE fi.object_id = OBJECT_ID('dbo.tbStok') AND c.name = 'sAciklama' ) THEN 1 ELSE 0 END`).Scan(&exists) return err == nil && exists == 1 } func GetProductionHasCostDetailItemOptions( ctx context.Context, uretimDB *sql.DB, search string, limit int, ) (*sql.Rows, error) { search = strings.TrimSpace(search) if limit <= 0 { limit = 50 } if search == "" { return uretimDB.QueryContext(ctx, ` SELECT TOP (0) RTRIM(CONVERT(VARCHAR(32), ISNULL(S.nStokID, 0))) AS nStokID, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) AS sKodu, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sAciklama, '')))) AS sAciklama, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) AS sModel, LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(S.sBirimCinsi1, '')))) AS sBirim FROM dbo.tbStok S`) } searchExact := search searchPrefix := search + "%" searchLike := "%" + search + "%" searchLen := len([]rune(search)) numericStokID, numericErr := strconv.Atoi(search) hasNumericStokID := numericErr == nil fullTextSearch := buildSQLServerFullTextPrefixQuery(search) useFullText := searchLen >= 3 && fullTextSearch != "" && hasProductionHasCostDetailItemFullTextIndex(ctx, uretimDB) baseSelect := ` WITH c AS ( SELECT RTRIM(CONVERT(VARCHAR(32), ISNULL(S.nStokID, 0))) AS nStokID, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) AS sKodu, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sAciklama, '')))) AS sAciklama, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) AS sModel, LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(S.sBirimCinsi1, '')))) AS sBirim, CASE WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) = @p1 THEN 0 WHEN (@p5 = 1 AND S.nStokID = @p6) THEN 1 WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) = @p1 THEN 2 WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) LIKE @p3 THEN 3 WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) LIKE @p3 THEN 4 ELSE 5 END AS match_rank, ROW_NUMBER() OVER ( PARTITION BY LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) ORDER BY CASE WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) = @p1 THEN 0 WHEN (@p5 = 1 AND S.nStokID = @p6) THEN 1 WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) = @p1 THEN 2 WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) LIKE @p3 THEN 3 WHEN LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) LIKE @p3 THEN 4 ELSE 5 END, LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) ) AS rn FROM dbo.tbStok S WHERE (ISNULL(S.IsBlocked, 0) = 0) AND S.sModel LIKE '_.%%' AND ( (@p5 = 1 AND S.nStokID = @p6) OR S.sModel = @p1 OR S.sModel LIKE @p3 OR S.sKodu = @p1 OR S.sKodu LIKE @p3 OR %s ) ) SELECT TOP (@p2) nStokID, sKodu, sAciklama, sModel, sBirim FROM c WHERE rn = 1 ORDER BY match_rank, sModel, sKodu OPTION (RECOMPILE) ` if useFullText { sqlText := fmt.Sprintf(baseSelect, `CONTAINS(S.sAciklama, @p4)`) return uretimDB.QueryContext(ctx, sqlText, searchExact, limit, searchPrefix, fullTextSearch, hasNumericStokID, numericStokID) } sqlText := fmt.Sprintf(baseSelect, `(@p4 >= 3 AND S.sAciklama LIKE @p7)`) return uretimDB.QueryContext(ctx, sqlText, searchExact, limit, searchPrefix, searchLen, hasNumericStokID, numericStokID, searchLike) } func GetProductionHasCostDetailColorOptions( ctx context.Context, mssqlDB *sql.DB, modelCode string, search string, limit int, ) (*sql.Rows, error) { modelCode = strings.TrimSpace(modelCode) search = strings.TrimSpace(search) if limit <= 0 { limit = 50 } searchLike := "%" + search + "%" sqlText := ` WITH ColorSource AS ( SELECT DISTINCT LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(T.sRenk, '')))) AS ColorCode FROM dbo.tbStok T WHERE ISNULL(T.IsBlocked, 0) = 0 AND LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(T.sModel, '')))) = @p1 AND LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(T.sRenk, '')))) <> '' ) SELECT TOP (@p2) LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) AS colorCode, ISNULL(C.ColorDescription, '') AS colorDescription FROM ( SELECT ColorCode FROM ColorSource ) S OUTER APPLY ( SELECT TOP 1 ColorDescription FROM dbo.cdColorDesc CD WHERE CD.LangCode = 'TR' AND LTRIM(RTRIM(ISNULL(CD.ColorCode, ''))) = S.ColorCode ) C WHERE @p1 <> '' AND ( @p3 = '' OR LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) LIKE @p4 OR ISNULL(C.ColorDescription, '') LIKE @p4 ) ORDER BY CASE WHEN @p3 <> '' AND LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) = @p3 THEN 0 WHEN @p3 <> '' AND ISNULL(C.ColorDescription, '') = @p3 THEN 1 ELSE 2 END, LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) ` return mssqlDB.QueryContext(ctx, sqlText, modelCode, limit, search, searchLike) } func GetProductionHasCostDetailExchangeRatesByDate( ctx context.Context, mssqlDB *sql.DB, costDate string, ) (*sql.Row, error) { costDate = strings.TrimSpace(costDate) sqlText := ` DECLARE @targetDate date = ISNULL(CONVERT(date, NULLIF(@p1, ''), 23), CONVERT(date, GETDATE())) SELECT CONVERT(VARCHAR(10), @targetDate, 23) AS rateDate, ISNULL(( SELECT TOP 1 Rate FROM dbo.AllExchangeRates WHERE CurrencyCode = 'USD' AND RelationCurrencyCode = 'TRY' AND ExchangeTypeCode = 6 AND Rate > 0 AND CONVERT(date, [Date]) <= @targetDate ORDER BY CASE WHEN CONVERT(date, [Date]) = @targetDate THEN 0 ELSE 1 END, [Date] DESC ), 0) AS usdRate, ISNULL(( SELECT TOP 1 Rate FROM dbo.AllExchangeRates WHERE CurrencyCode = 'EUR' AND RelationCurrencyCode = 'TRY' AND ExchangeTypeCode = 6 AND Rate > 0 AND CONVERT(date, [Date]) <= @targetDate ORDER BY CASE WHEN CONVERT(date, [Date]) = @targetDate THEN 0 ELSE 1 END, [Date] DESC ), 0) AS eurRate, ISNULL(( SELECT TOP 1 Rate FROM dbo.AllExchangeRates WHERE CurrencyCode = 'GBP' AND RelationCurrencyCode = 'TRY' AND ExchangeTypeCode = 6 AND Rate > 0 AND CONVERT(date, [Date]) <= @targetDate ORDER BY CASE WHEN CONVERT(date, [Date]) = @targetDate THEN 0 ELSE 1 END, [Date] DESC ), 0) AS gbpRate ` return mssqlDB.QueryRowContext(ctx, sqlText, costDate), nil } func GetProductionHasCostLatestPurchasePriceForItem( ctx context.Context, mssqlDB *sql.DB, sKodu string, colorCode string, itemDim1Code string, costDate string, ) (*sql.Row, error) { sKodu = strings.TrimSpace(sKodu) colorCode = strings.TrimSpace(colorCode) itemDim1Code = strings.TrimSpace(itemDim1Code) costDate = strings.TrimSpace(costDate) sqlText := ` WITH BASE AS ( SELECT A.InvoiceDate, A.InvoiceNumber, A.ProcessCode, A.CurrAccTypeCode, A.CurrAccCode, A.ItemTypeCode, A.ItemCode, A.ColorCode, A.ItemDim1Code, A.Qty1, A.Doc_Price, A.Doc_Amount, A.Doc_CurrencyCode FROM AllInvoicesWithAttributes A WHERE A.ProcessCode IN ('BP') AND A.ATAtt01 IN (1, 2) AND A.CompanyCode IN (1, 2, 5) AND A.IsCompleted = 1 AND YEAR(A.InvoiceDate) >= 2022 AND LTRIM(RTRIM(A.ItemCode)) = @p1 AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p2, ''), 23)) ) SELECT TOP 1 'MAN' AS priceType, CONVERT(VARCHAR(16), B.InvoiceDate, 120) AS Tarih, ISNULL(B.InvoiceNumber, '') AS FaturaKodu, LTRIM(RTRIM(ISNULL(B.ItemCode, ''))) AS MasrafKodu, ISNULL(ID.ItemDescription, '') AS MasrafDetay, ISNULL(B.ColorCode, '') AS ColorCode, ISNULL(COL.ColorDescription, '') AS ColorDescription, ISNULL(B.ItemDim1Code, '') AS ItemDim1Code, ISNULL(DIM1.ItemDim1Description, '') AS ItemDim1Description, ISNULL(B.Doc_Price, 0) AS EvrakFiyat, ISNULL(B.Doc_CurrencyCode, '') AS EvrakDoviz FROM BASE B LEFT JOIN cdItem CI ON CI.ItemTypeCode = B.ItemTypeCode AND CI.ItemCode = B.ItemCode OUTER APPLY ( SELECT TOP 1 ItemDescription FROM cdItemDesc WHERE ItemTypeCode = B.ItemTypeCode AND ItemCode = B.ItemCode AND LangCode = 'TR' ) ID OUTER APPLY ( SELECT TOP 1 ItemDim1Description FROM cdItemDim1Desc WHERE ItemDim1Code = B.ItemDim1Code AND LangCode = 'TR' ) DIM1 OUTER APPLY ( SELECT TOP 1 ColorDescription FROM cdColorDesc WHERE ColorCode = B.ColorCode AND LangCode = 'TR' ) COL ORDER BY CASE WHEN @p3 <> '' AND LTRIM(RTRIM(ISNULL(B.ColorCode, ''))) = @p3 THEN 0 WHEN @p3 = '' THEN 0 ELSE 1 END, CASE WHEN @p4 <> '' AND LTRIM(RTRIM(ISNULL(B.ItemDim1Code, ''))) = @p4 THEN 0 WHEN @p4 = '' THEN 0 ELSE 1 END, B.InvoiceDate DESC, B.InvoiceNumber DESC ` return mssqlDB.QueryRowContext(ctx, sqlText, sKodu, costDate, colorCode, itemDim1Code), nil } func GetProductionHasCostPurchaseHistoryByExpenseCode( ctx context.Context, mssqlDB *sql.DB, sKodu string, costDate string, limit int, ) (*sql.Rows, error) { sKodu = strings.TrimSpace(sKodu) costDate = strings.TrimSpace(costDate) if limit <= 0 { limit = 250 } sqlText := ` WITH BASE AS ( SELECT A.InvoiceDate, A.InvoiceNumber, A.ProcessCode, A.CurrAccTypeCode, A.CurrAccCode, A.ItemTypeCode, A.ItemCode, A.ColorCode, A.ItemDim1Code, A.Qty1, A.Doc_Price, A.Doc_Amount, A.Doc_CurrencyCode FROM AllInvoicesWithAttributes A WHERE A.ProcessCode IN ('BP') AND A.ATAtt01 IN (1, 2) AND A.CompanyCode IN (1, 2, 5) AND A.IsCompleted = 1 AND YEAR(A.InvoiceDate) >= 2022 AND LTRIM(RTRIM(A.ItemCode)) = @p1 AND (ISNULL(A.Doc_Price, 0) > 0 OR ISNULL(A.Doc_Amount, 0) > 0) AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p2, ''), 23)) ) SELECT TOP (@p3) 'purchase' AS sourceType, 'MAN' AS priceType, CONVERT(VARCHAR(16), B.InvoiceDate, 120) AS Tarih, ISNULL(B.InvoiceNumber, '') AS FaturaKodu, ISNULL(B.CurrAccCode, '') AS FirmaKodu, ISNULL(CAD.CurrAccDescription, '') AS FirmaAciklama, LTRIM(RTRIM(ISNULL(B.ItemCode, ''))) AS MasrafKodu, ISNULL(ID.ItemDescription, '') AS MasrafDetay, ISNULL(B.ColorCode, '') AS ColorCode, ISNULL(COL.ColorDescription, '') AS ColorDescription, ISNULL(B.ItemDim1Code, '') AS ItemDim1Code, ISNULL(DIM1.ItemDim1Description, '') AS ItemDim1Description, ISNULL(B.Qty1, 0) AS Miktar, CASE WHEN B.ProcessCode = 'EP' THEN '' ELSE ISNULL(CI.UnitOfMeasureCode1, '') END AS BIRIM, ISNULL(B.Doc_Price, 0) AS EvrakFiyat, ISNULL(B.Doc_Amount, 0) AS EvrakTutar, ISNULL(B.Doc_CurrencyCode, '') AS EvrakDoviz FROM BASE B LEFT JOIN cdItem CI ON CI.ItemTypeCode = B.ItemTypeCode AND CI.ItemCode = B.ItemCode OUTER APPLY ( SELECT TOP 1 ItemDescription FROM cdItemDesc WHERE ItemTypeCode = B.ItemTypeCode AND ItemCode = B.ItemCode AND LangCode = 'TR' ) ID OUTER APPLY ( SELECT TOP 1 ItemDim1Description FROM cdItemDim1Desc WHERE ItemDim1Code = B.ItemDim1Code AND LangCode = 'TR' ) DIM1 OUTER APPLY ( SELECT TOP 1 ColorDescription FROM cdColorDesc WHERE ColorCode = B.ColorCode AND LangCode = 'TR' ) COL OUTER APPLY ( SELECT TOP 1 CurrAccDescription FROM cdCurrAccDesc WHERE CurrAccTypeCode = B.CurrAccTypeCode AND CurrAccCode = B.CurrAccCode AND LangCode = 'TR' ) CAD ORDER BY B.InvoiceDate DESC, B.InvoiceNumber DESC ` return mssqlDB.QueryContext(ctx, sqlText, sKodu, costDate, limit) } func GetProductionHasCostRecipeHistoryByExpenseCode( ctx context.Context, uretimDB *sql.DB, currentOnMLNo int, sKodu string, colorCode string, costDate string, limit int, ) (*sql.Rows, error) { sKodu = strings.TrimSpace(sKodu) colorCode = strings.TrimSpace(colorCode) costDate = strings.TrimSpace(costDate) if limit <= 0 { limit = 250 } sqlText := ` SELECT TOP (@p5) 'recipe' AS sourceType, ISNULL(NULLIF(LTRIM(RTRIM(D.sFiyatTipi)), ''), 'SAF') AS priceType, CONVERT(VARCHAR(16), COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo, ISNULL(UF.FirmaKodu, '') AS FirmaKodu, ISNULL(UF.FirmaAciklama, '') AS FirmaAciklama, ISNULL(D.sKodu, '') AS sKodu, ISNULL(D.sAciklama, '') AS sAciklama, ISNULL(D.sRenk, '') AS sRenk, ISNULL(D.lMiktar, 0) AS lMiktar, ISNULL(D.sBirim, '') AS sBirim, CASE WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) ELSE ISNULL(D.lDovizFiyati, 0) END AS lDovizFiyati, CASE WHEN ISNULL(D.lDovizTutari, 0) > 0 THEN ISNULL(D.lDovizTutari, 0) WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) * ISNULL(D.lMiktar, 0) ELSE ISNULL(D.lDovizFiyati, 0) * ISNULL(D.lMiktar, 0) END AS lDovizTutari, CASE WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz)) WHEN LTRIM(RTRIM(ISNULL(D.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(D.sDovizCinsi)) WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi)) ELSE 'USD' END AS USD, ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'DUMMY') AS DUMMY FROM dbo.spUrtOnMLMasDet D INNER JOIN dbo.spUrtOnMLMas M ON M.nOnMLNo = D.nOnMLNo LEFT JOIN dbo.spUrtOnMLHammaddeTuru T ON T.nHammaddeTuruNo = D.nHammaddeTuruNo OUTER APPLY ( SELECT TOP 1 ISNULL(F.sKodu, '') AS FirmaKodu, ISNULL(F.sAciklama, '') AS FirmaAciklama FROM dbo.spUrtSiparisDet SD INNER JOIN dbo.spUrtSiparis SM ON SM.nUrtSiparisID = SD.nUrtSiparisID LEFT JOIN dbo.tbFirma F ON F.nFirmaID = SM.nFirmaID WHERE ( (ISNULL(M.nUrtReceteID, 0) > 0 AND SD.nUrtReceteID = M.nUrtReceteID) OR (ISNULL(M.nUrtReceteID, 0) <= 0 AND LTRIM(RTRIM(ISNULL(SD.sMModelKodu, ''))) = LTRIM(RTRIM(ISNULL(M.UrunKodu, '')))) ) AND SD.dteIslemTarihi <= COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC ) UF WHERE LTRIM(RTRIM(D.sKodu)) = @p1 AND (@p2 <= 0 OR D.nOnMLNo <> @p2) AND ( ISNULL(D.fiyat_girilen, 0) > 0 OR ISNULL(D.lDovizFiyati, 0) > 0 OR ISNULL(D.lDovizTutari, 0) > 0 ) AND ( NULLIF(@p3, '') IS NULL OR CONVERT(date, COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p3, ''), 23) ) ORDER BY CASE WHEN @p4 <> '' AND LTRIM(RTRIM(ISNULL(D.sRenk, ''))) = @p4 THEN 0 WHEN @p4 = '' THEN 0 ELSE 1 END, COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) DESC, D.nOnMLNo DESC, D.nOnMLDetNo DESC ` return uretimDB.QueryContext(ctx, sqlText, sKodu, currentOnMLNo, costDate, colorCode, limit) } func BuildProductionHasCostSimilarCodePrefix(sKodu string) string { normalizedCode := strings.ToUpper(strings.TrimSpace(sKodu)) if normalizedCode == "" { return "" } runes := []rune(normalizedCode) if len(runes) <= 4 { return normalizedCode } if len(runes) >= 5 && len(runes) > 1 && runes[1] == '.' { return string(runes[:5]) } return string(runes[:4]) } func GetProductionHasCostPurchaseHistoryByCodePrefix( ctx context.Context, mssqlDB *sql.DB, sKoduPrefix string, costDate string, limit int, ) (*sql.Rows, error) { sKoduPrefix = strings.TrimSpace(sKoduPrefix) costDate = strings.TrimSpace(costDate) if limit <= 0 { limit = 250 } sqlText := ` WITH BASE AS ( SELECT A.InvoiceDate, A.InvoiceNumber, A.ProcessCode, A.CurrAccTypeCode, A.CurrAccCode, A.ItemTypeCode, A.ItemCode, A.ColorCode, A.ItemDim1Code, A.Qty1, A.Doc_Price, A.Doc_Amount, A.Doc_CurrencyCode FROM AllInvoicesWithAttributes A WHERE A.ProcessCode IN ('BP') AND A.ATAtt01 IN (1, 2) AND A.CompanyCode IN (1, 2, 5) AND A.IsCompleted = 1 AND YEAR(A.InvoiceDate) >= 2022 AND NULLIF(@p1, '') IS NOT NULL AND LTRIM(RTRIM(A.ItemCode)) LIKE @p1 + '%' AND (ISNULL(A.Doc_Price, 0) > 0 OR ISNULL(A.Doc_Amount, 0) > 0) AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p2, ''), 23)) ) SELECT TOP (@p3) 'purchase' AS sourceType, 'BNZ' AS priceType, CONVERT(VARCHAR(16), B.InvoiceDate, 120) AS Tarih, ISNULL(B.InvoiceNumber, '') AS FaturaKodu, ISNULL(B.CurrAccCode, '') AS FirmaKodu, ISNULL(CAD.CurrAccDescription, '') AS FirmaAciklama, LTRIM(RTRIM(ISNULL(B.ItemCode, ''))) AS MasrafKodu, ISNULL(ID.ItemDescription, '') AS MasrafDetay, ISNULL(B.ColorCode, '') AS ColorCode, ISNULL(COL.ColorDescription, '') AS ColorDescription, ISNULL(B.ItemDim1Code, '') AS ItemDim1Code, ISNULL(DIM1.ItemDim1Description, '') AS ItemDim1Description, ISNULL(B.Qty1, 0) AS Miktar, CASE WHEN B.ProcessCode = 'EP' THEN '' ELSE ISNULL(CI.UnitOfMeasureCode1, '') END AS BIRIM, ISNULL(B.Doc_Price, 0) AS EvrakFiyat, ISNULL(B.Doc_Amount, 0) AS EvrakTutar, ISNULL(B.Doc_CurrencyCode, '') AS EvrakDoviz FROM BASE B LEFT JOIN cdItem CI ON CI.ItemTypeCode = B.ItemTypeCode AND CI.ItemCode = B.ItemCode OUTER APPLY ( SELECT TOP 1 ItemDescription FROM cdItemDesc WHERE ItemTypeCode = B.ItemTypeCode AND ItemCode = B.ItemCode AND LangCode = 'TR' ) ID OUTER APPLY ( SELECT TOP 1 ItemDim1Description FROM cdItemDim1Desc WHERE ItemDim1Code = B.ItemDim1Code AND LangCode = 'TR' ) DIM1 OUTER APPLY ( SELECT TOP 1 ColorDescription FROM cdColorDesc WHERE ColorCode = B.ColorCode AND LangCode = 'TR' ) COL OUTER APPLY ( SELECT TOP 1 CurrAccDescription FROM cdCurrAccDesc WHERE CurrAccTypeCode = B.CurrAccTypeCode AND CurrAccCode = B.CurrAccCode AND LangCode = 'TR' ) CAD ORDER BY B.InvoiceDate DESC, B.InvoiceNumber DESC ` return mssqlDB.QueryContext(ctx, sqlText, sKoduPrefix, costDate, limit) } func GetProductionHasCostOnMLHistoryByCodePrefix( ctx context.Context, uretimDB *sql.DB, sKoduPrefix string, costDate string, limit int, ) (*sql.Rows, error) { sKoduPrefix = strings.TrimSpace(sKoduPrefix) costDate = strings.TrimSpace(costDate) if limit <= 0 { limit = 250 } sqlText := ` SELECT TOP (@p3) 'recipe' AS sourceType, 'BNZ' AS priceType, CONVERT(VARCHAR(16), COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo, ISNULL(UF.FirmaKodu, '') AS FirmaKodu, ISNULL(UF.FirmaAciklama, '') AS FirmaAciklama, ISNULL(D.sKodu, '') AS sKodu, ISNULL(D.sAciklama, '') AS sAciklama, ISNULL(D.sRenk, '') AS sRenk, ISNULL(D.lMiktar, 0) AS lMiktar, ISNULL(D.sBirim, '') AS sBirim, CASE WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) ELSE ISNULL(D.lDovizFiyati, 0) END AS lDovizFiyati, CASE WHEN ISNULL(D.lDovizTutari, 0) > 0 THEN ISNULL(D.lDovizTutari, 0) WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) * ISNULL(D.lMiktar, 0) ELSE ISNULL(D.lDovizFiyati, 0) * ISNULL(D.lMiktar, 0) END AS lDovizTutari, CASE WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz)) WHEN LTRIM(RTRIM(ISNULL(D.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(D.sDovizCinsi)) WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi)) ELSE 'USD' END AS USD, ISNULL(NULLIF(LTRIM(RTRIM(D.sAciklama3)), ''), N'DUMMY') AS DUMMY FROM dbo.spUrtOnMLMasDet D INNER JOIN dbo.spUrtOnMLMas M ON M.nOnMLNo = D.nOnMLNo OUTER APPLY ( SELECT TOP 1 ISNULL(F.sKodu, '') AS FirmaKodu, ISNULL(F.sAciklama, '') AS FirmaAciklama FROM dbo.spUrtSiparisDet SD INNER JOIN dbo.spUrtSiparis SM ON SM.nUrtSiparisID = SD.nUrtSiparisID LEFT JOIN dbo.tbFirma F ON F.nFirmaID = SM.nFirmaID WHERE ( (ISNULL(M.nUrtReceteID, 0) > 0 AND SD.nUrtReceteID = M.nUrtReceteID) OR (ISNULL(M.nUrtReceteID, 0) <= 0 AND LTRIM(RTRIM(ISNULL(SD.sMModelKodu, ''))) = LTRIM(RTRIM(ISNULL(M.UrunKodu, '')))) ) AND SD.dteIslemTarihi <= COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC ) UF WHERE NULLIF(@p1, '') IS NOT NULL AND LTRIM(RTRIM(ISNULL(D.sKodu, ''))) LIKE @p1 + '%' AND ( ISNULL(D.fiyat_girilen, 0) > 0 OR ISNULL(D.lDovizFiyati, 0) > 0 OR ISNULL(D.lDovizTutari, 0) > 0 ) AND ( NULLIF(@p2, '') IS NULL OR CONVERT(date, COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p2, ''), 23) ) ORDER BY COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) DESC, D.nOnMLNo DESC, D.nOnMLDetNo DESC ` return uretimDB.QueryContext(ctx, sqlText, sKoduPrefix, costDate, limit) } func GetProductionHasCostOnMLHistoryByHammaddeTuruNo( ctx context.Context, uretimDB *sql.DB, nHammaddeTuruNo string, costDate string, limit int, ) (*sql.Rows, error) { nHammaddeTuruNo = strings.TrimSpace(nHammaddeTuruNo) costDate = strings.TrimSpace(costDate) if limit <= 0 { limit = 250 } sqlText := ` SELECT TOP (@p3) 'recipe' AS sourceType, 'BNZ' AS priceType, CONVERT(VARCHAR(16), COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo, ISNULL(UF.FirmaKodu, '') AS FirmaKodu, ISNULL(UF.FirmaAciklama, '') AS FirmaAciklama, ISNULL(D.sKodu, '') AS sKodu, ISNULL(D.sAciklama, '') AS sAciklama, ISNULL(D.sRenk, '') AS sRenk, ISNULL(D.lMiktar, 0) AS lMiktar, ISNULL(D.sBirim, '') AS sBirim, CASE WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) ELSE ISNULL(D.lDovizFiyati, 0) END AS lDovizFiyati, CASE WHEN ISNULL(D.lDovizTutari, 0) > 0 THEN ISNULL(D.lDovizTutari, 0) WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) * ISNULL(D.lMiktar, 0) ELSE ISNULL(D.lDovizFiyati, 0) * ISNULL(D.lMiktar, 0) END AS lDovizTutari, CASE WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz)) WHEN LTRIM(RTRIM(ISNULL(D.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(D.sDovizCinsi)) WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi)) ELSE 'USD' END AS USD, ISNULL(NULLIF(LTRIM(RTRIM(D.sAciklama3)), ''), N'DUMMY') AS DUMMY FROM dbo.spUrtOnMLMasDet D INNER JOIN dbo.spUrtOnMLMas M ON M.nOnMLNo = D.nOnMLNo OUTER APPLY ( SELECT TOP 1 ISNULL(F.sKodu, '') AS FirmaKodu, ISNULL(F.sAciklama, '') AS FirmaAciklama FROM dbo.spUrtSiparisDet SD INNER JOIN dbo.spUrtSiparis SM ON SM.nUrtSiparisID = SD.nUrtSiparisID LEFT JOIN dbo.tbFirma F ON F.nFirmaID = SM.nFirmaID WHERE ( (ISNULL(M.nUrtReceteID, 0) > 0 AND SD.nUrtReceteID = M.nUrtReceteID) OR (ISNULL(M.nUrtReceteID, 0) <= 0 AND LTRIM(RTRIM(ISNULL(SD.sMModelKodu, ''))) = LTRIM(RTRIM(ISNULL(M.UrunKodu, '')))) ) AND SD.dteIslemTarihi <= COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC ) UF WHERE D.nHammaddeTuruNo = @p1 AND ISNULL(D.fiyat_girilen, 0) > 0 AND ( NULLIF(@p2, '') IS NULL OR CONVERT(date, COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p2, ''), 23) ) ORDER BY COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) DESC, D.nOnMLNo DESC, D.nOnMLDetNo DESC ` return uretimDB.QueryContext(ctx, sqlText, nHammaddeTuruNo, costDate, limit) } func GetProductionHasCostSimilarItemHistory( ctx context.Context, mssqlDB *sql.DB, uretimDB *sql.DB, nHammaddeTuruNo string, costDate string, limit int, ) ([]any, error) { if limit <= 0 { limit = 50 } // 1. Satinalma (V3) tarafini sorgula - Simdilik V3 tarafi icin hammadde turu eslestirmesi belirsiz oldugundan pasif /* v3Sql := ` SELECT TOP (@p2) 'purchase' AS sourceType, 'BNZ' AS priceType, CONVERT(VARCHAR(16), A.InvoiceDate, 120) AS Tarih, ISNULL(A.InvoiceNumber, '') AS FaturaKodu, LTRIM(RTRIM(ISNULL(A.ItemCode, ''))) AS MasrafKodu, ISNULL(ID.ItemDescription, '') AS MasrafDetay, ISNULL(A.ColorCode, '') AS ColorCode, ISNULL(A.Qty1, 0) AS Miktar, ISNULL(CI.UnitOfMeasureCode1, '') AS BIRIM, ISNULL(A.Doc_Price, 0) AS EvrakFiyat, ISNULL(A.Doc_CurrencyCode, '') AS EvrakDoviz FROM AllInvoicesWithAttributes A LEFT JOIN cdItem CI ON CI.ItemTypeCode = A.ItemTypeCode AND CI.ItemCode = A.ItemCode OUTER APPLY ( SELECT TOP 1 ItemDescription FROM cdItemDesc WHERE ItemTypeCode = A.ItemTypeCode AND ItemCode = A.ItemCode AND LangCode = 'TR' ) ID WHERE A.ProcessCode IN ('BP') AND A.ATAtt01 IN (1, 2) AND A.CompanyCode IN (1, 2, 5) AND A.IsCompleted = 1 AND YEAR(A.InvoiceDate) >= 2023 AND (NULLIF(@p1, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p1, ''), 23)) AND EXISTS ( -- Hammadde turu eslestirmesi (V3 tarafindaki karsiligi varsa) SELECT 1 FROM cdItem WHERE ItemCode = A.ItemCode ) ORDER BY A.InvoiceDate DESC ` */ // 2. Uretim (Recete) tarafini sorgula uretimSql := ` SELECT TOP (@p3) 'recipe' AS sourceType, 'BNZ' AS priceType, CONVERT(VARCHAR(16), ISNULL(M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi, RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo, ISNULL(D.sKodu, '') AS sKodu, ISNULL(D.sAciklama, '') AS sAciklama, ISNULL(D.sRenk, '') AS sRenk, ISNULL(D.lMiktar, 0) AS lMiktar, ISNULL(D.sBirim, '') AS sBirim, ISNULL(D.lDovizFiyati, 0) AS lDovizFiyati, CASE WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz)) WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi)) ELSE 'USD' END AS USD FROM dbo.spUrtOnMLMasDet D INNER JOIN dbo.spUrtOnMLMas M ON M.nOnMLNo = D.nOnMLNo WHERE D.nHammaddeTuruNo = @p1 AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, ISNULL(M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p2, ''), 23)) ORDER BY ISNULL(M.Tarihi, M.dteKayitTarihi) DESC ` // Not: nHammaddeTuruNo parametresine gore sadece Reçete tarafı şu an doğrudan filtrelenebiliyor. // V3 tarafı için ItemTypeCode veya özel bir grup kodu gerekebilir. // Kullanıcının talebi üzerine Reçete (URETIM) odaklı sorguyu önceliklendiriyoruz. rows, err := uretimDB.QueryContext(ctx, uretimSql, nHammaddeTuruNo, costDate, limit) if err != nil { return nil, err } defer rows.Close() var results []any for rows.Next() { // Basit bir map veya struct ile dondurebiliriz var row struct { SourceType string `json:"sourceType"` PriceType string `json:"priceType"` Tarih string `json:"Tarih"` EvrakKodu string `json:"EvrakKodu"` Kod string `json:"Kod"` Aciklama string `json:"Aciklama"` Renk string `json:"Renk"` Miktar float64 `json:"Miktar"` Birim string `json:"Birim"` Fiyat float64 `json:"Fiyat"` Doviz string `json:"Doviz"` } if err := rows.Scan( &row.SourceType, &row.PriceType, &row.Tarih, &row.EvrakKodu, &row.Kod, &row.Aciklama, &row.Renk, &row.Miktar, &row.Birim, &row.Fiyat, &row.Doviz, ); err == nil { results = append(results, row) } } return results, nil }