# Envanter (`App.Inventory`) > Menünün altındaki her dal bu dosyada bir bölümdür (`module-doc:section`); dosya ve bölümler ilk deploy'da otomatik açılır. `module-doc:todo` işaretli alt bölümleri modülü üreten kişi ya da AI doldurur (`lowcode.instructions.md` §0.13); MCP ile üretimde talep bu bölümler doldurulmadan Testing'e alınamaz. "Ek — Ekran envanteri" bölümü wizard dosyalarından üretilir, elle düzenlenmez. ## Tanımlamalar (`App.Inventory.Definitions`) ### 1. Amaç ve kapsam Envanterin ana verisi: ürün kartı (satış/masraf/satınalma bayrakları, mal/hizmet, envanter takibi ve yöntemi, nitelik–varyant, tedarikçi fiyatları, stok ve muhasebe bilgileri), ölçü birimine bağlı reçeteler (bileşen + operasyon; ürün ya da varyant bazında) ve çok seviyeli reçete patlatma raporu. İş merkezleri ve operasyonlar Üretim modülündedir ([App.Production.md](App.Production.md)). Kullanıcılar: stok, satınalma ve üretim planlama ekipleri. Stok hareketi, sipariş ve üretim emri bu dalın kapsamı dışındadır. ### 2. Analiz ve kararlar Onaylanan analiz (talep "Inventory -> Tanımlamalar"): - Menü `Envanter › Tanımlamalar`; ara menü kodu `App.Inventory.Definitions` (Satınalmadaki `App.Prc.Definitions` kalıbı). - Görsellerdeki Kategori ve Etiket alanları için Ürün Kategorileri ve İş Merkezi Etiketleri tanım ekranları eklendi. - İş Merkezi Etiketleri, İş Merkezleri ve Operasyonlar (alt formlarıyla) sonradan `Üretim › Tanımlamalar` altına taşındı: kod `App.Production.*`, tablo `Prd_T_*` (`App.Production.md` §2). - Ürün Türü yalnız Mal / Hizmet; Kombo yok. BoM Türü alanı yok (talep). - Vergiler oran (varsayılan %20), muhasebe hesapları serbest metin kod olarak tutulur (onaylı). - Varyantlar kalıcı tabloda tutulmaz: `VariantKey` = seçili nitelik değeri Id'lerinin, nitelik adı sırasıyla `|` birleşimi; aynı kombinasyon hep aynı anahtarı üretir. "Varyant Oluşturma = Asla" olan nitelik kartezyene girmez, Hemen/Dinamik aynı davranır (onaylı). - Haftalık çalışma saati ayardan (`%WeeklyWorkingTimeLimit%`) okunur, yoksa 40 (onaylı). - Reçete patlatmada alt reçete: önce bileşenin varyantına özel, yoksa genel; birden fazlaysa en eski oluşturulan. Üretimde verilen ek kararlar: - Query kaynağı türetilmiş tabloya (`FROM (…) AS "Q"`) sarıldığı için özyinelemeli CTE kullanılamaz. Varyant kartezyeni ürün başına en fazla **5 nitelik**, reçete patlatma en fazla **4 bileşen seviyesi** ile sabit derinlikli birleşimlerle kuruldu; derinlik sınırı döngü korumasıdır. - Genel Bakış'ta kök reçete satırının maliyeti boştur; maliyetler bileşen ve operasyon satırlarındadır. ### 3. Menü ve ekranlar `Envanter (App.Inventory) › Tanımlamalar (App.Inventory.Definitions)` altında sırasıyla: Ürün Kategorileri, Nitelikler, Ürünler, Ürün Varyantları, Reçeteler, Reçeteye Genel Bakış. Sekmeler (menüsüz alt formlar): - Nitelikler › Nitelik Değerleri - Reçeteler › Bileşenler, Operasyonlar, Diğer (aynı satır), Genel Bakış (menülü, Tree) - Ürünler › Genel Bilgi, Stok, Muhasebe (aynı satır), Nitelik & Varyantlar, Varyantlar (menülü, salt okunur), Satınalma, Reçeteler (menülü) ### 4. Veri modeli Tüm tablolar kiracı + tam audit + soft delete, anahtar `Id uniqueidentifier`. Birim kolonları `nvarchar(64)` → `Adm_T_Uom.Id`; tedarikçi → `Adm_T_Contact`; para birimi → `Sas_H_Currency`; menşe → `Sas_H_Country`; sorumlu → `AbpUsers`. | Tablo | İçerik | | --- | --- | | `Inv_T_ProductCategory` | Ad, üst kategori, aktif | | `Inv_T_Attribute` / `Inv_T_AttributeValue` | Nitelik (görünüm türü, varyant oluşturma) ve değerleri (serbest metin, ekstra fiyat, renk, sıra) | | `Inv_T_Product` | Ürün kartı ve Genel Bilgi/Stok/Muhasebe sekmelerinin alanları | | `Inv_T_ProductAttributeLine` | Ürün × nitelik, `ValueIds` (`|` ayrımlı değer Id) | | `Inv_T_ProductSupplier` | Tedarikçi, min. miktar, birim, fiyat, kur, teslim süresi, varyant | | `Inv_T_Bom` / `Inv_T_BomComponent` / `Inv_T_BomOperation` | Reçete başlığı (ürün, varyant, miktar, birim, planlama), bileşenler (operasyona bağlanabilir), operasyonlar (iş merkezi `Prd_T_WorkCenter`, operasyon `Prd_T_Operation`, süre) | ### 5. İş kuralları ve hesaplar - **Varyant satış fiyatı** = ürün satış fiyatı + seçili değerlerin ekstra fiyatları toplamı. - **Genel Bakış miktarı:** seviye k bileşen miktarı = üst miktar × bileşen miktarı ÷ alt reçete miktarı. - **Genel Bakış maliyeti:** bileşen maliyeti = miktar × ürün maliyeti. Operasyon süresi aynı oranla ölçeklenir; maliyet = süre ÷ 60 × iş merkezi saatlik maliyeti. Operasyonlar her seviyede "Operasyonlar" düğümünde toplanır. - **Ürün formu:** Hizmet seçilince envanter takibi kapanır ve kilitlenir. Takip yöntemi yalnız takip açıkken girilir; takip açılınca "Miktara göre" gelir. Satınalma birimi boşsa birimi izler. - **Reçete bileşeni:** ürün seçilince birim üründen dolar. - **Reçete operasyonu:** operasyon seçilince iş merkezi ve varsayılan süre dolar. - **Çoklu değer alanları** (`dxTagBox`) `|` ile ayrılmış metin kolonunda saklanır. ### 6. Yetki ve görünürlük İzin grubu `App.Inventory`. Her ekranın okuma yetkisi `App.Inventory.Definitions` altında; alt formların yetkisi bağlı oldukları listenin altındadır. Her listede `.Create/.Update/.Delete/.Export/.Import/.Note`. Yetkiler hiçbir role otomatik verilmez. Yeni sekmelerin yetkisi role verilmeden sekmeler boş görünür. Tüm ekranlar kiracı filtrelidir. ### 7. Entegrasyonlar Dış entegrasyon yok. Reçete operasyonları iş merkezi ve operasyonu Üretim modülünden okur; Üretim de ürün ve nitelik değerlerini buradan okur. Ölçü Birimleri, Kontaklar, Para Birimleri, Ülkeler ve Kullanıcılar yalnız lookup kaynağıdır. Satış ve satınalma sipariş ekranları ürünü `CanBeSold` / `CanBePurchased` ile süzecek; bu dalda sipariş ekranı yoktur. ### 8. Akış örneği 1. Nitelikler'de renk (kırmızı, mavi), malzeme (çelik, tahta), boyut (40x40, 80x100, 10x30) değerlerini gir. 2. Üretim › İş Merkezleri'nde "ram makinası"nın saatlik maliyetini gir. 3. Üretim › Operasyonlar'da "Apre"yi ram makinası, 60 dk olarak tanımla. 4. Ürünler'de "(40X40mm) Mamül Sepeti Üst Geçme Kepi" › Nitelik & Varyantlar sekmesine üç niteliği ekle. Varyantlar sekmesinde 12 kombinasyon görünür. 5. Reçeteler'de kep için 1 Adet reçete aç. Bileşenler'e 20 Adet AUTONİCS PR12-4DN Sensör, Operasyonlar'a Apre ekle. 6. Genel Bakış sekmesi ağacı ve maliyetleri gösterir. ### 9. Sık sorulanlar - **Varyant neden kayboldu?** Nitelik satırından değer ya da nitelik silinirse kombinasyon ve anahtarı değişir. O varyantı kullanan reçete ve tedarikçi satırlarının varyantı yeniden seçilmelidir. - **Genel Bakış'ta alt seviye görünmüyor?** Bileşenin aktif ve miktarı > 0 bir reçetesi olmalıdır. 4 seviyeden derin yapılar gösterilmez. - **Kaç nitelik desteklenir?** Ürün başına 5. Fazlası varyant listesine katılmaz. - **Form açılınca Aktif kutusu boş geliyor?** Form varsayılanları wizard deploy'unda yazılamadı (bkz. 10). Kayıtta kutu işaretlenmelidir; tablo varsayılanları yalnızca alan gönderilmezse uygulanır. ### 10. Dosyalar ve geri alma - **Tablolar:** `sql/object/Inv_T_*.sql` (9 tablo). - **Wizard'lar:** ProductCategory, Attribute, AttributeValue, ProductVariant, BomOverview, Bom, BomComponent, BomOperation, BomOther, Product, ProductGeneral, ProductAttributeLine, ProductSupplier, ProductStock, ProductAccounting (`.json`). - **Demo veri aynaları:** `data/App.Inventory.{ProductCategory,Attribute,Product}.json`. - **Geri alma:** Wizard Manager'da ana ekranlar (Product, Bom, Attribute) önce, alt formları sonra silinir. Tablolar ancak açık onayla `dropTables` ile düşürülür. - **Sorgu bağımlılığı:** Sorgular SQL Server'a özgüdür (`STRING_SPLIT`, `CONCAT_WS`, `STRING_AGG`, `CROSS APPLY`). - **Açık nokta:** Form varsayılanları (Aktif = true, Birim = Adet, Miktar = 1, Süre = 60, Kur = TRY) düz wizard biçimiyle dosyaya yazılmadı. ListForm düzenleyicisinden ya da `ListForm` bölümlü yeniden deploy ile eklenmelidir. ## Ek — Ekran envanteri (otomatik) > Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur. ### Tanımlamalar (`App.Inventory.Definitions`) #### Ürün Kategorileri — `App.Inventory.ProductCategory` | Özellik | Değer | | --- | --- | | Wizard | `wizard/ProductCategory.json` | | Yol | Liste (Wizard) | | Menü | `App.Inventory.Definitions` › `App.Inventory.ProductCategory` (sıra 1) | | Yetki | `App.Inventory.ProductCategory` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürün Kategorileri — ürünleri raporlama, filtreleme ve varsayılan muhasebe için gruplar (ör. Elektrik ve Elektronik Malzemeler, Mamuller). | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_ProductCategory` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart, Tree (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` | | Veri aynası | `data/App.Inventory.ProductCategory.json` | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `Name` | Ad | dxTextBox | ✓ | ✓ | | | `ParentId` | Üst Kategori | dxSelectBox | | ✓ | sorgu: Inv_T_ProductCategory | | `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | | #### Nitelikler — `App.Inventory.Attribute` | Özellik | Değer | | --- | --- | | Wizard | `wizard/Attribute.json` | | Yol | Liste (Wizard) | | Menü | `App.Inventory.Definitions` › `App.Inventory.Attribute` (sıra 2) | | Yetki | `App.Inventory.Attribute` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Nitelikler — varyant oluşturan ürün özellikleri (renk, malzeme, boyut). | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_Attribute` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Alt formlar | `App.Inventory.AttributeValue` (Id → AttributeId) | | Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` | | Veri aynası | `data/App.Inventory.Attribute.json` | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `Name` | Nitelik Adı | dxTextBox | ✓ | ✓ | | | `DisplayType` | Görünüm Türü | dxRadioGroup | ✓ | ✓ | liste: Radio, Pills, Select, Color, Multi, Image | | `VariantCreation` | Varyant Oluşturma | dxRadioGroup | ✓ | ✓ | liste: Always, Dynamic, Never | | `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | | #### Ürünler — `App.Inventory.Product` | Özellik | Değer | | --- | --- | | Wizard | `wizard/Product.json` | | Yol | Liste (Wizard) | | Menü | `App.Inventory.Definitions` › `App.Inventory.Product` (sıra 3) | | Yetki | `App.Inventory.Product` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürünler — satış, satınalma, stok ve üretimin ortak kullandığı ürün kartı. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_Product` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Alt formlar | `App.Inventory.ProductGeneral` (Id → Id), `App.Inventory.ProductAttributeLine` (Id → ProductId), `App.Inventory.ProductVariant` (Id → ProductId), `App.Inventory.ProductSupplier` (Id → ProductId), `App.Inventory.ProductStock` (Id → Id), `App.Inventory.ProductAccounting` (Id → Id), `App.Inventory.Bom` (Id → ProductId) | | Widget'lar | `App.Widget.Total`, `App.Widget.Saleable`, `App.Widget.Purchasable`, `App.Widget.Service` | | Form varsayılanları | IsActive=true, IsFavorite=false, CanBeSold=true, CanBeExpensed=false, CanBePurchased=false, IsFavorite=false, UomId=Adet, PurchaseUomId=Adet, SalesPrice=0, Cost=0, TrackInventory=true, TrackingMethod=Quantity, ProductType=Wares | | Veri aynası | `data/App.Inventory.Product.json` | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `Name` | Ürün Adı | dxTextBox | ✓ | ✓ | | | `IsFavorite` | Favori | dxCheckBox | | ✓ | | | `CanBeSold` | Satış | dxCheckBox | | ✓ | | | `CanBeExpensed` | Masraflar | dxCheckBox | | ✓ | | | `CanBePurchased` | Satınalma | dxCheckBox | | ✓ | | | `ProductType` | Ürün Türü | dxSelectBox | ✓ | ✓ | liste: Wares, Service · script | | `CategoryId` | Kategori | dxSelectBox | | ✓ | sorgu: Inv_T_ProductCategory | | `TrackInventory` | Envanter Takibi | dxCheckBox | | ✓ | script | | `TrackingMethod` | Takip Yöntemi | dxSelectBox | | ✓ | liste: Serial, Lot, Quantity | | `SalesPrice` | Satış Fiyatı | dxNumberBox | | ✓ | | | `Cost` | Maliyet | dxNumberBox | | ✓ | | | `InternalReference` | İç Referans | dxTextBox | | ✓ | | | `UomId` | Birim | dxSelectBox | ✓ | ✓ | sorgu: Adm_T_Uom · script | | `PurchaseUomId` | Satınalma Birimi | dxSelectBox | | ✓ | sorgu: Adm_T_Uom | | `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | | | `Image` | Resim | dxImageUpload | | ✓ | | #### Ürün Varyantları — `App.Inventory.ProductVariant` | Özellik | Değer | | --- | --- | | Wizard | `wizard/ProductVariant.json` | | Yol | Liste (Wizard) | | Menü | `App.Inventory.Definitions` › `App.Inventory.ProductVariant` (sıra 4) | | Yetki | `App.Inventory.ProductVariant` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürün Varyantları — üründe seçilen nitelik değerlerinin her kombinasyonu (ör. kırmızı · çelik · 40x40), salt okunur. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `SELECT CAST(p.Id AS nvarchar(36)) + ':' + CONCAT_WS('\|', l1.VId, l2.VId, l3.VId, l4.VId, l5.VId) AS [Key], p.Id AS ProductId, p.Name AS ProductName, CONCAT_WS('\|', l1.VId, l2.VId, l3.VId, l4.VId, l5.VId) AS VariantKey, CONCAT_WS(', ', l1.VName, l2.VName, l3.VName, l4.VName, l5.VName) AS VariantName, p.InternalReference, CAST(p.SalesPrice + ISNULL(l1.XP, 0) + ISNULL(l2.XP, 0) + ISNULL(l3.XP, 0) + ISNULL(l4.XP, 0) + ISNULL(l5.XP, 0) AS decimal(18,4)) AS SalesPrice, p.Cost, p.UomId, p.CategoryId, p.IsActive, p.TenantId, p.IsDeleted FROM Inv_T_Product p LEFT JOIN (SELECT x.ProductId, x.Rk, CAST(s.value AS nvarchar(36)) AS VId, av.Name AS VName, av.ExtraPrice AS XP FROM (SELECT pl.ProductId, pl.ValueIds, DENSE_RANK() OVER (PARTITION BY pl.ProductId ORDER BY a.Name, a.Id) AS Rk FROM Inv_T_ProductAttributeLine pl INNER JOIN Inv_T_Attribute a ON a.Id = pl.AttributeId AND a.IsDeleted = 'false' AND a.VariantCreation <> 'Never' WHERE pl.IsDeleted = 'false') x CROSS APPLY STRING_SPLIT(x.ValueIds, '\|') s INNER JOIN Inv_T_AttributeValue av ON CAST(av.Id AS nvarchar(36)) = s.value AND av.IsDeleted = 'false') l1 ON l1.ProductId = p.Id AND l1.Rk = 1 LEFT JOIN (SELECT x.ProductId, x.Rk, CAST(s.value AS nvarchar(36)) AS VId, av.Name AS VName, av.ExtraPrice AS XP FROM (SELECT pl.ProductId, pl.ValueIds, DENSE_RANK() OVER (PARTITION BY pl.ProductId ORDER BY a.Name, a.Id) AS Rk FROM Inv_T_ProductAttributeLine pl INNER JOIN Inv_T_Attribute a ON a.Id = pl.AttributeId AND a.IsDeleted = 'false' AND a.VariantCreation <> 'Never' WHERE pl.IsDeleted = 'false') x CROSS APPLY STRING_SPLIT(x.ValueIds, '\|') s INNER JOIN Inv_T_AttributeValue av ON CAST(av.Id AS nvarchar(36)) = s.value AND av.IsDeleted = 'false') l2 ON l2.ProductId = p.Id AND l2.Rk = 2 LEFT JOIN (SELECT x.ProductId, x.Rk, CAST(s.value AS nvarchar(36)) AS VId, av.Name AS VName, av.ExtraPrice AS XP FROM (SELECT pl.ProductId, pl.ValueIds, DENSE_RANK() OVER (PARTITION BY pl.ProductId ORDER BY a.Name, a.Id) AS Rk FROM Inv_T_ProductAttributeLine pl INNER JOIN Inv_T_Attribute a ON a.Id = pl.AttributeId AND a.IsDeleted = 'false' AND a.VariantCreation <> 'Never' WHERE pl.IsDeleted = 'false') x CROSS APPLY STRING_SPLIT(x.ValueIds, '\|') s INNER JOIN Inv_T_AttributeValue av ON CAST(av.Id AS nvarchar(36)) = s.value AND av.IsDeleted = 'false') l3 ON l3.ProductId = p.Id AND l3.Rk = 3 LEFT JOIN (SELECT x.ProductId, x.Rk, CAST(s.value AS nvarchar(36)) AS VId, av.Name AS VName, av.ExtraPrice AS XP FROM (SELECT pl.ProductId, pl.ValueIds, DENSE_RANK() OVER (PARTITION BY pl.ProductId ORDER BY a.Name, a.Id) AS Rk FROM Inv_T_ProductAttributeLine pl INNER JOIN Inv_T_Attribute a ON a.Id = pl.AttributeId AND a.IsDeleted = 'false' AND a.VariantCreation <> 'Never' WHERE pl.IsDeleted = 'false') x CROSS APPLY STRING_SPLIT(x.ValueIds, '\|') s INNER JOIN Inv_T_AttributeValue av ON CAST(av.Id AS nvarchar(36)) = s.value AND av.IsDeleted = 'false') l4 ON l4.ProductId = p.Id AND l4.Rk = 4 LEFT JOIN (SELECT x.ProductId, x.Rk, CAST(s.value AS nvarchar(36)) AS VId, av.Name AS VName, av.ExtraPrice AS XP FROM (SELECT pl.ProductId, pl.ValueIds, DENSE_RANK() OVER (PARTITION BY pl.ProductId ORDER BY a.Name, a.Id) AS Rk FROM Inv_T_ProductAttributeLine pl INNER JOIN Inv_T_Attribute a ON a.Id = pl.AttributeId AND a.IsDeleted = 'false' AND a.VariantCreation <> 'Never' WHERE pl.IsDeleted = 'false') x CROSS APPLY STRING_SPLIT(x.ValueIds, '\|') s INNER JOIN Inv_T_AttributeValue av ON CAST(av.Id AS nvarchar(36)) = s.value AND av.IsDeleted = 'false') l5 ON l5.ProductId = p.Id AND l5.Rk = 5` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✗ · düzenle ✗ · sil ✗ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `ProductId` | Ürün | dxSelectBox | | | sorgu: Inv_T_Product | | `InternalReference` | İç Referans | dxTextBox | | ✓ | | | `ProductName` | Adı | dxTextBox | | ✓ | | | `VariantName` | Varyant Değerleri | dxTextBox | | ✓ | | | `SalesPrice` | Satış Fiyatı | dxNumberBox | | ✓ | | | `Cost` | Maliyet | dxNumberBox | | ✓ | | | `UomId` | Birim | dxSelectBox | | ✓ | sorgu: Adm_T_Uom | | `CategoryId` | Kategori | dxSelectBox | | ✓ | sorgu: Inv_T_ProductCategory | | `IsActive` | Aktif | dxCheckBox | | ✓ | | | `IsDeleted` | Silindi | dxCheckBox | | | | #### Reçeteler — `App.Inventory.Bom` | Özellik | Değer | | --- | --- | | Wizard | `wizard/Bom.json` | | Yol | Liste (Wizard) | | Menü | `App.Inventory.Definitions` › `App.Inventory.Bom` (sıra 5) | | Yetki | `App.Inventory.Bom` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Reçeteler — bir ürünü üretmek için gereken hammadde, yarı mamul ve operasyonlar. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_Bom` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Alt formlar | `App.Inventory.BomComponent` (Id → BomId), `App.Inventory.BomOperation` (Id → BomId), `App.Inventory.BomOther` (Id → Id), `App.Inventory.BomOverview` (Id → BomId) | | Widget'lar | `App.Widget.Total`, `App.Widget.VariantBased`, `App.Widget.Active` | | Form varsayılanları | UomId=Adet, IsActive=true, Quantity=0 | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `ProductId` | Ürün | dxSelectBox | ✓ | ✓ | sorgu: Inv_T_Product | | `Reference` | Referans | dxTextBox | | ✓ | | | `VariantKey` | Ürün Varyantı | dxSelectBox | | ✓ | sorgu: Inv_T_Product (← ProductId) | | `Quantity` | Miktar | dxNumberBox | ✓ | ✓ | | | `UomId` | Birim | dxSelectBox | ✓ | ✓ | sorgu: Adm_T_Uom | | `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | | #### Reçeteye Genel Bakış — `App.Inventory.BomOverview` | Özellik | Değer | | --- | --- | | Wizard | `wizard/BomOverview.json` | | Yol | Liste (Wizard) | | Menü | `App.Inventory.Definitions` › `App.Inventory.BomOverview` (sıra 6) | | Yetki | `App.Inventory.BomOverview` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Reçeteye Genel Bakış — her aktif reçetenin çok seviyeli patlatılmış hali, ağaç olarak (salt okunur). | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) AS nvarchar(400)) AS NodeKey, CAST(NULL AS nvarchar(400)) AS ParentKey, b0.Id AS BomId, 0 AS NodeLevel, CAST('Product' AS nvarchar(20)) AS NodeType, CAST(p0.Name + ISNULL(' (' + (SELECT STRING_AGG(avn.Name, ', ') FROM STRING_SPLIT(b0.VariantKey, '\|') sn INNER JOIN Inv_T_AttributeValue avn ON CAST(avn.Id AS nvarchar(36)) = sn.value) + ')', '') AS nvarchar(400)) AS Name, CAST(b0.Quantity AS decimal(18,4)) AS Quantity, CAST(u0.Name AS nvarchar(64)) AS UomName, CAST(NULL AS decimal(18,4)) AS Cost, b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_Product p0 ON p0.Id = b0.ProductId LEFT JOIN Adm_T_Uom u0 ON u0.Id = b0.UomId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 1, 'Component', CAST(p1.Name + ISNULL(' (' + (SELECT STRING_AGG(avn.Name, ', ') FROM STRING_SPLIT(c1.VariantKey, '\|') sn INNER JOIN Inv_T_AttributeValue avn ON CAST(avn.Id AS nvarchar(36)) = sn.value) + ')', '') AS nvarchar(400)), CAST(c1.Quantity AS decimal(18,4)), u1.Name, CAST(c1.Quantity * p1.Cost AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' INNER JOIN Inv_T_Product p1 ON p1.Id = c1.ProductId LEFT JOIN Adm_T_Uom u1 ON u1.Id = c1.UomId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 2, 'Component', CAST(p2.Name + ISNULL(' (' + (SELECT STRING_AGG(avn.Name, ', ') FROM STRING_SPLIT(c2.VariantKey, '\|') sn INNER JOIN Inv_T_AttributeValue avn ON CAST(avn.Id AS nvarchar(36)) = sn.value) + ')', '') AS nvarchar(400)), CAST(c1.Quantity * c2.Quantity / b1.Quantity AS decimal(18,4)), u2.Name, CAST(c1.Quantity * c2.Quantity / b1.Quantity * p2.Cost AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomComponent c2 ON c2.BomId = b1.Id AND c2.IsDeleted = 'false' INNER JOIN Inv_T_Product p2 ON p2.Id = c2.ProductId LEFT JOIN Adm_T_Uom u2 ON u2.Id = c2.UomId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/C' + CAST(c3.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 3, 'Component', CAST(p3.Name + ISNULL(' (' + (SELECT STRING_AGG(avn.Name, ', ') FROM STRING_SPLIT(c3.VariantKey, '\|') sn INNER JOIN Inv_T_AttributeValue avn ON CAST(avn.Id AS nvarchar(36)) = sn.value) + ')', '') AS nvarchar(400)), CAST(c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity AS decimal(18,4)), u3.Name, CAST(c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity * p3.Cost AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomComponent c2 ON c2.BomId = b1.Id AND c2.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c2.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c2.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c2.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b2 INNER JOIN Inv_T_BomComponent c3 ON c3.BomId = b2.Id AND c3.IsDeleted = 'false' INNER JOIN Inv_T_Product p3 ON p3.Id = c3.ProductId LEFT JOIN Adm_T_Uom u3 ON u3.Id = c3.UomId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/C' + CAST(c3.Id AS nvarchar(36)) + '/C' + CAST(c4.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/C' + CAST(c3.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 4, 'Component', CAST(p4.Name + ISNULL(' (' + (SELECT STRING_AGG(avn.Name, ', ') FROM STRING_SPLIT(c4.VariantKey, '\|') sn INNER JOIN Inv_T_AttributeValue avn ON CAST(avn.Id AS nvarchar(36)) = sn.value) + ')', '') AS nvarchar(400)), CAST(c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity * c4.Quantity / b3.Quantity AS decimal(18,4)), u4.Name, CAST(c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity * c4.Quantity / b3.Quantity * p4.Cost AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomComponent c2 ON c2.BomId = b1.Id AND c2.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c2.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c2.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c2.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b2 INNER JOIN Inv_T_BomComponent c3 ON c3.BomId = b2.Id AND c3.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c3.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c3.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c3.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b3 INNER JOIN Inv_T_BomComponent c4 ON c4.BomId = b3.Id AND c4.IsDeleted = 'false' INNER JOIN Inv_T_Product p4 ON p4.Id = c4.ProductId LEFT JOIN Adm_T_Uom u4 ON u4.Id = c4.UomId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 1, 'OperationGroup', 'Operasyonlar', CAST(SUM(o.DurationMin) AS decimal(18,4)), 'Dakika', CAST(SUM(o.DurationMin / 60 * w.CostPerHour) AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomOperation o ON o.BomId = b0.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 GROUP BY b0.Id, b0.TenantId, b0.IsDeleted UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/OPS/O' + CAST(o.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), b0.Id, 2, 'Operation', op.Name + ' - ' + w.Name, CAST(o.DurationMin AS decimal(18,4)), 'Dakika', CAST(o.DurationMin / 60 * w.CostPerHour AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomOperation o ON o.BomId = b0.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_Operation op ON op.Id = o.OperationId INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 2, 'OperationGroup', 'Operasyonlar', CAST(SUM(o.DurationMin * c1.Quantity / b1.Quantity) AS decimal(18,4)), 'Dakika', CAST(SUM(o.DurationMin * c1.Quantity / b1.Quantity / 60 * w.CostPerHour) AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomOperation o ON o.BomId = b1.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 GROUP BY b0.Id, b0.TenantId, b0.IsDeleted, c1.Id UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/OPS/O' + CAST(o.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), b0.Id, 3, 'Operation', op.Name + ' - ' + w.Name, CAST(o.DurationMin * c1.Quantity / b1.Quantity AS decimal(18,4)), 'Dakika', CAST(o.DurationMin * c1.Quantity / b1.Quantity / 60 * w.CostPerHour AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomOperation o ON o.BomId = b1.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_Operation op ON op.Id = o.OperationId INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 3, 'OperationGroup', 'Operasyonlar', CAST(SUM(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity / b2.Quantity) AS decimal(18,4)), 'Dakika', CAST(SUM(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity / b2.Quantity / 60 * w.CostPerHour) AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomComponent c2 ON c2.BomId = b1.Id AND c2.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c2.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c2.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c2.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b2 INNER JOIN Inv_T_BomOperation o ON o.BomId = b2.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 GROUP BY b0.Id, b0.TenantId, b0.IsDeleted, c1.Id, c2.Id UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/OPS/O' + CAST(o.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), b0.Id, 4, 'Operation', op.Name + ' - ' + w.Name, CAST(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity / b2.Quantity AS decimal(18,4)), 'Dakika', CAST(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity / b2.Quantity / 60 * w.CostPerHour AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomComponent c2 ON c2.BomId = b1.Id AND c2.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c2.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c2.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c2.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b2 INNER JOIN Inv_T_BomOperation o ON o.BomId = b2.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_Operation op ON op.Id = o.OperationId INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/C' + CAST(c3.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/C' + CAST(c3.Id AS nvarchar(36)) AS nvarchar(400)), b0.Id, 4, 'OperationGroup', 'Operasyonlar', CAST(SUM(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity / b3.Quantity) AS decimal(18,4)), 'Dakika', CAST(SUM(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity / b3.Quantity / 60 * w.CostPerHour) AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomComponent c2 ON c2.BomId = b1.Id AND c2.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c2.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c2.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c2.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b2 INNER JOIN Inv_T_BomComponent c3 ON c3.BomId = b2.Id AND c3.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c3.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c3.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c3.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b3 INNER JOIN Inv_T_BomOperation o ON o.BomId = b3.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1 GROUP BY b0.Id, b0.TenantId, b0.IsDeleted, c1.Id, c2.Id, c3.Id UNION ALL SELECT CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/C' + CAST(c3.Id AS nvarchar(36)) + '/OPS/O' + CAST(o.Id AS nvarchar(36)) AS nvarchar(400)), CAST('B' + CAST(b0.Id AS nvarchar(36)) + '/C' + CAST(c1.Id AS nvarchar(36)) + '/C' + CAST(c2.Id AS nvarchar(36)) + '/C' + CAST(c3.Id AS nvarchar(36)) + '/OPS' AS nvarchar(400)), b0.Id, 5, 'Operation', op.Name + ' - ' + w.Name, CAST(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity / b3.Quantity AS decimal(18,4)), 'Dakika', CAST(o.DurationMin * c1.Quantity * c2.Quantity / b1.Quantity * c3.Quantity / b2.Quantity / b3.Quantity / 60 * w.CostPerHour AS decimal(18,4)), b0.TenantId, b0.IsDeleted FROM Inv_T_Bom b0 INNER JOIN Inv_T_BomComponent c1 ON c1.BomId = b0.Id AND c1.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c1.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c1.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c1.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b1 INNER JOIN Inv_T_BomComponent c2 ON c2.BomId = b1.Id AND c2.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c2.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c2.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c2.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b2 INNER JOIN Inv_T_BomComponent c3 ON c3.BomId = b2.Id AND c3.IsDeleted = 'false' CROSS APPLY (SELECT TOP 1 bb.Id, bb.Quantity FROM Inv_T_Bom bb WHERE bb.ProductId = c3.ProductId AND bb.IsDeleted = 'false' AND bb.IsActive = 1 AND bb.Quantity > 0 AND (bb.VariantKey IS NULL OR bb.VariantKey = '' OR bb.VariantKey = c3.VariantKey) ORDER BY CASE WHEN bb.VariantKey = c3.VariantKey THEN 0 ELSE 1 END, bb.CreationTime) b3 INNER JOIN Inv_T_BomOperation o ON o.BomId = b3.Id AND o.IsDeleted = 'false' INNER JOIN Prd_T_Operation op ON op.Id = o.OperationId INNER JOIN Prd_T_WorkCenter w ON w.Id = o.WorkCenterId WHERE b0.IsDeleted = 'false' AND b0.IsActive = 1` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart, Tree (açılış tree) | | Düzenleme | ekle ✗ · düzenle ✗ · sil ✗ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `ParentKey` | Üst Düğüm | dxTextBox | | | | | `Name` | Ürün | dxTextBox | | ✓ | | | `Quantity` | Miktar | dxNumberBox | | ✓ | | | `UomName` | Birim | dxTextBox | | ✓ | | | `Cost` | Maliyet | dxNumberBox | | ✓ | | | `NodeType` | Satır Türü | dxSelectBox | | ✓ | liste: Product, Component, OperationGroup, Operation | | `NodeLevel` | Seviye | dxNumberBox | | ✓ | | | `BomId` | Reçete | dxTextBox | | | | | `IsDeleted` | Silindi | dxCheckBox | | | | #### Nitelik Değerleri — `App.Inventory.AttributeValue` | Özellik | Değer | | --- | --- | | Wizard | `wizard/AttributeValue.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.AttributeValue` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Nitelik Değerleri — bir niteliğin alabileceği değerler (ör. renk: kırmızı, mavi; boyut: 40x40). | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_AttributeValue` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Form varsayılanları | IsCustom=false, IsActive=true | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `AttributeId` | Nitelik | dxSelectBox | | | sorgu: Inv_T_Attribute | | `Name` | Değer | dxTextBox | ✓ | ✓ | | | `IsCustom` | Serbest Metin | dxCheckBox | | ✓ | | | `ExtraPrice` | Varsayılan Ekstra Fiyat | dxNumberBox | | ✓ | | | `ColorCode` | Renk Kodu | dxColorBox | | ✓ | | | `SortOrder` | Sıra | dxNumberBox | | ✓ | | | `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | | #### Bileşenler — `App.Inventory.BomComponent` | Özellik | Değer | | --- | --- | | Wizard | `wizard/BomComponent.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.BomComponent` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Reçete Bileşenleri — reçetenin tükettiği hammadde ve yarı mamuller. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_BomComponent` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `BomId` | Reçete | dxTextBox | | | | | `ProductId` | Komponent | dxSelectBox | ✓ | ✓ | sorgu: Inv_T_Product · script | | `VariantKey` | Bileşen Varyantı | dxSelectBox | | ✓ | sorgu: Inv_T_Product (← ProductId) | | `Quantity` | Miktar | dxNumberBox | ✓ | ✓ | | | `UomId` | Birim | dxSelectBox | ✓ | ✓ | sorgu: Adm_T_Uom | | `BomOperationId` | Operasyonda Tüketilenler | dxSelectBox | | ✓ | sorgu: Inv_T_BomOperation (← BomId) | | `SortOrder` | Sıra | dxNumberBox | | ✓ | | #### Operasyonlar — `App.Inventory.BomOperation` | Özellik | Değer | | --- | --- | | Wizard | `wizard/BomOperation.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.BomOperation` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Reçete Operasyonları — reçetenin üretim adımları ve süreleri. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_BomOperation` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `BomId` | Reçete | dxTextBox | | | | | `OperationId` | Operasyon | dxSelectBox | ✓ | ✓ | sorgu: Prd_T_Operation · script | | `WorkCenterId` | İş Merkezi | dxSelectBox | ✓ | ✓ | sorgu: Prd_T_WorkCenter | | `DurationMin` | Süre (dakika) | dxNumberBox | ✓ | ✓ | | | `SortOrder` | Sıra | dxNumberBox | | ✓ | | #### Diğer — `App.Inventory.BomOther` | Özellik | Değer | | --- | --- | | Wizard | `wizard/BomOther.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.BomOther` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Reçete Diğer Ayarlar — reçetenin üretim hazırlığı ve planlama parametreleri. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_Bom` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✗ · düzenle ✓ · sil ✗ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `ReadyToProduce` | Üretim Hazırlığı | dxRadioGroup | ✓ | ✓ | liste: AllAvailable, FirstOperation | | `ProductionLeadDays` | Üretim Akış Zamanı (gün) | dxNumberBox | | ✓ | | | `FlexibleConsumption` | Esnek Tüketim | dxRadioGroup | ✓ | ✓ | liste: Allowed, Warning, Blocked | | `PreparationDays` | Üretim Siparişi Hazırlama Günleri | dxNumberBox | | ✓ | | | `BatchSize` | Parti Büyüklüğü | dxNumberBox | | ✓ | | #### Genel Bilgi — `App.Inventory.ProductGeneral` | Özellik | Değer | | --- | --- | | Wizard | `wizard/ProductGeneral.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.ProductGeneral` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürün Genel Bilgi — ürünün vergi, barkod, satınalma kontrol ve iç not bilgileri. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_Product` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✗ · düzenle ✓ · sil ✗ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `SalesTaxRate` | Satış Vergisi (%) | dxNumberBox | ✓ | ✓ | | | `PurchaseTaxRate` | Satınalma Vergisi (%) | dxNumberBox | ✓ | ✓ | | | `Barcode` | Barkod | dxTextBox | | ✓ | | | `PurchaseControlPolicy` | Kontrol Kuralı | dxRadioGroup | ✓ | ✓ | liste: Ordered, Received | | `PurchaseDescription` | Satınalma Açıklaması | dxTextArea | | ✓ | | | `InternalNotes` | İç Notlar | dxTextArea | | ✓ | | #### Nitelik & Varyantlar — `App.Inventory.ProductAttributeLine` | Özellik | Değer | | --- | --- | | Wizard | `wizard/ProductAttributeLine.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.ProductAttributeLine` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürün Nitelik & Varyantlar — ürünün nitelikleri ve bu ürün için kullanılan değerler. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_ProductAttributeLine` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `ProductId` | Ürün | dxTextBox | | | | | `AttributeId` | Nitelik | dxSelectBox | ✓ | ✓ | sorgu: Inv_T_Attribute | | `ValueIds` | Değerler | dxTagBox | ✓ | ✓ | sorgu: Inv_T_AttributeValue (← AttributeId) | #### Satınalma — `App.Inventory.ProductSupplier` | Özellik | Değer | | --- | --- | | Wizard | `wizard/ProductSupplier.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.ProductSupplier` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürün Tedarikçi Fiyatları — ürünün hangi tedarikçiden hangi bedele alındığı. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_ProductSupplier` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `ProductId` | Ürün | dxTextBox | | | | | `ContactId` | Tedarikçi | dxSelectBox | ✓ | ✓ | sorgu: Adm_T_Contact | | `VariantKey` | Ürün Varyantı | dxSelectBox | | ✓ | sorgu: Inv_T_Product (← ProductId) | | `MinQuantity` | Miktar | dxNumberBox | ✓ | ✓ | | | `UomId` | Birim | dxSelectBox | | ✓ | sorgu: Adm_T_Uom | | `Price` | Birim Fiyat | dxNumberBox | ✓ | ✓ | | | `CurrencyId` | Kur | dxSelectBox | | ✓ | sorgu: Sas_H_Currency | | `LeadTimeDays` | Teslim Süresi (gün) | dxNumberBox | | ✓ | | #### Stok — `App.Inventory.ProductStock` | Özellik | Değer | | --- | --- | | Wizard | `wizard/ProductStock.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.ProductStock` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürün Stok — ürünün lojistik ve izlenebilirlik bilgileri. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_Product` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✗ · düzenle ✓ · sil ✗ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `ResponsibleUserId` | Sorumlu | dxSelectBox | | ✓ | sorgu: AbpUsers | | `LotValuation` | Lot/Seri Bazında Değerleme | dxCheckBox | | ✓ | | | `Weight` | Ağırlık (kg) | dxNumberBox | | ✓ | | | `CustomLotSerial` | Özel Lot/Seri | dxTextBox | | ✓ | | | `Volume` | Hacim (m³) | dxNumberBox | | ✓ | | | `GtipCode` | GTİP Kodu | dxTextBox | | ✓ | | | `OriginCountryId` | Malların Menşei | dxSelectBox | | ✓ | sorgu: Sas_H_Country | | `ReceiptNote` | Alım İçin Açıklama | dxTextArea | | ✓ | | | `DeliveryNote` | Teslimatlar İçin Açıklama | dxTextArea | | ✓ | | | `InternalTransferNote` | İç Transferler İçin Açıklama | dxTextArea | | ✓ | | #### Muhasebe — `App.Inventory.ProductAccounting` | Özellik | Değer | | --- | --- | | Wizard | `wizard/ProductAccounting.json` | | Yol | Liste (Wizard) | | Menü | Menüsüz (alt form) | | Yetki | `App.Inventory.ProductAccounting` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | Açıklama | Ürün Muhasebe — ürünün maliyet ve gelir hesapları. | | Geliştirme talebi | Inventory -> Tanımlamalar | | Kaynak | `Inv_T_Product` · filtre `"IsDeleted" = 'false'` | | Görünümler | Grid, Card, Pivot, Chart (açılış grid) | | Düzenleme | ekle ✗ · düzenle ✓ · sil ✗ · popup | | Kapsam | Kiracı | | Alan | Başlık | Editör | Zorunlu | Formda | Kaynak | | --- | --- | --- | --- | --- | --- | | `IncomeAccount` | Gelir Hesabı | dxTextBox | | ✓ | | | `ExpenseAccount` | Gider Hesabı | dxTextBox | | ✓ | |