Files
bssapp/svc/queries/production_product_costing.go
2026-05-15 19:43:53 +03:00

2553 lines
74 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package queries
import (
"bssapp-backend/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
ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ') AS sAciklama3,
SUM(ISNULL(D.lTutar, 0)) OVER (
PARTITION BY 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(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,
ISNULL(D.sKodu, '') AS sKodu,
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
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,
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.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,
) (*sql.Rows, error) {
search = strings.TrimSpace(search)
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
ISNULL(T.bAktif, 0) = 1
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)
}
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 := `
SELECT TOP (@p2)
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
WHERE
(ISNULL(S.IsBlocked, 0) = 0)
AND S.sModel LIKE '_.%%'
AND (
(@p5 = 1 AND S.nStokID = @p6)
OR S.sKodu = @p1
OR S.sKodu LIKE @p3
OR %s
)
ORDER BY
CASE
WHEN S.sKodu = @p1 THEN 0
WHEN (@p5 = 1 AND S.nStokID = @p6) THEN 1
WHEN S.sKodu LIKE @p3 THEN 2
ELSE 3
END,
S.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
}