> 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.
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), çok seviyeli reçete patlatma raporu ve fiziksel stok yapısı: şubeye bağlı depolar, depolarda iç içe konumlar, şube/depo bazında operasyon türleri. İş merkezleri ve operasyonlar Üretim modülündedir ([App.Production.md](App.Production.md)). Kullanıcılar: stok, satınalma ve üretim planlama ekipleri. Stok hareketleri Operasyonlar, stok ve hareket listeleri doğrudan Envanter altındaki Stok ve Hareketler ekranlarıdır; sipariş ve üretim emri bu dalın kapsamı dışındadır.
- İş 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.
- Depolar, Konumlar, Operasyon Türleri üç ayrı liste ekranı; tablolar `Inv_T_Warehouse`, `Inv_T_Location`, `Inv_T_OperationType`.
- Şube platform şube filtresiyle değil kolonla tutulur (`IsBranch = false`, `BranchId` → `Sas_T_Branch`): talep Şube Adı'nı listede görünen, seçilen alan olarak istedi. Görsellerdeki "Firma" sütunu Şube'ye karşılık gelir.
- Konum ve Operasyon Türü'nde şube ayrıca tutulur ("şube ve depo bazında"); depo listesini süzer.
- Konumlar'da Malzeme Türü ve Depolama Kategorisi alınmadı (talepte yok, kaynak tablo yok). Operasyon Türü'nde yalnız Genel sekmesinin çekirdek alanları alındı; Donanım, Barkod Uygulaması, lot/seri, paket, iade türü, kart rengi kapsam dışı.
- Depolar demo verisi: görseldeki 4 depo (WH, GRP, IKT, KZL), ilk aktif şubeye (Branch1) bağlı (onaylı).
- 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.
- Depo kodu tekilliği `UQ_Inv_T_Warehouse_TenantId_Code` kısıtıyla sağlanır (ayrı InsertBefore kontrolü yazılmadı; aynı kod kaydedilirken veritabanı hatası döner).
-`Inv_T_Location`'da `WarehouseId`/`ParentId`/`DepartmentId` için FK yazılmadı: migrate scriptleri dosya adı sırasıyla çalışır ve `Inv_T_Location``Inv_T_Warehouse`'tan önce sıralanır. Bütünlük lookup'larla korunur; `Inv_T_OperationType` → `Inv_T_Location` FK'leri vardır.
| `Inv_T_OperationType` | Şube, depo, ad, tür (`Receipt`/`Delivery`/`InternalTransfer`/`Manufacturing`/`Repair`), numaratör (`SequenceName` → `Adm_T_Sequence.Name`; belge numarası buradan), barkod, kaynak ve hedef konum, aktif |
- **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.
İ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. Depolar, Konumlar ve Operasyon Türleri platform şube filtresi kullanmaz; kullanıcı yetkisi olan her ekranda kiracının tüm şubelerinin kayıtlarını görür.
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, Şubeler, Departmanlar ve Kullanıcılar yalnız lookup kaynağıdır. Satış ve satınalma sipariş ekranları ürünü `CanBeSold` / `CanBePurchased` ile süzecek; stok hareket belgeleri (Operasyonlar dalı) operasyon türünü, numaratörünü ve konumları bu daldan alır; ürünün Envanter Takibi ve Takip Yöntemi hareketin stoğa ve lota nasıl işleneceğini belirler.
8. Konumlar'da GRP için "Stock" kök konumunu, altına "ALDORA MOBİLYA G/Ç" (kod GRP ALD, departman, sorumlu), onun altına "ANA DEPO AB07" konumunu İç türüyle gir; ağaç üç seviye gösterir.
- **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?** Eski ürün ekranlarında form varsayılanları wizard deploy'unda yazılamadı (bkz. 10). Kayıtta kutu işaretlenmelidir. Depolar, Konumlar ve Operasyon Türleri'nde varsayılan tablodan okunur.
- **Depo seçimi boş geliyor?** Önce şube seçilmelidir; depo listesi şubeye göre süzülür ve yalnız aktif depolar gelir.
- **Aynı depo kodu kaydedilemiyor?** Depo kodu kiracı içinde tekildir; silinen (soft delete) bir deponun kodu da tekrar kullanılamaz.
- **Depo ya da konum silinebilir mi?** Konumu veya operasyon türü olan depoyu, alt konumu olan konumu silmeyin; pasife alın.
- **Demo veri aynaları:** `data/App.Inventory.{ProductCategory,Attribute,Product,Warehouse}.json`.
- **Geri alma:** Wizard Manager'da ana ekranlar (Product, Bom, Attribute) önce, alt formları sonra silinir. Depolar/Konumlar/Operasyon Türleri bağımsızdır; tablo düşürülecekse sıra OperationType → Location → Warehouse (FK). Tablolar ancak açık onayla `dropTables` ile düşürülür.
- **Açık nokta:** Eski ürün ekranlarının 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.
Depoya giren, depodan çıkan ve depo içinde taşınan malların belgeleri: Alımlar, Teslimatlar, İç Transferler; hepsinin belgeleri Envanter › Hareketler'de, ürün satırları Envanter › Ürün Hareketleri'nde salt okunur listelenir. Belgeler Tanımlamalar dalındaki Depolar, Konumlar ve Operasyon Türleri'ni kullanır; tamamlanan belge stoğu şube › depo › konum › ürün › lot bazında günceller (Envanter › Stok). Kullanıcılar: depo, satınalma ve sevkiyat ekipleri. Üretim (`Manufacturing`) ve Onarım türleri Üretim menüsünde ayrıca yapılacaktır; Toplu Transfer, Bakım Talebi, Ekipman, Satış Siparişi ve İzlenebilirlik raporu kapsam dışıdır.
### 2. Analiz ve kararlar
Onaylanan analiz (talep "Envanter giriş ve çıkışları"):
- Bütün operasyon türleri tek veri kaynağındadır: başlık `Inv_T_Transfer`, satır `Inv_T_TransferLine`, lot dağılımı`Inv_T_TransferLineLot`; tür `OperationKind` kolonuyla ayrılır. Her tür kendi ekranında (aynı tablo, `DefaultFilter` ile) yönetilir.
- Kısmi işlemde kalan, aynı türde yeni belgeye (backorder) geçer.
- Ek kapsam: İade, iç transferde kaynak depo onayı ve teslim, malzeme talebinden iç transfer, transfer fişi yazdırma.
- Belge numarası operasyon türünün numaratöründen gelir: `Inv_T_OperationType.SequencePrefix` kaldırıldı, yerine `SequenceName` (Diziler) geldi; demo operasyon türleri için `Inventory.IKT.*` numaratörleri eklendi.
- Lot/seri bu turdadır: hareket satırında Detaylar butonu lot dağılımını açar; çıkışta lot stoktan gelir, girişte yazılır; Lot/Seri Oluştur ve Otomatik Ata yardımcı butonlardır.
- Giriş ve çıkışın lot ekranı ayrıdır (kullanıcı kararı): stoğa giren satır (alım, teslimat iadesi) **Lot/Seri Numaraları**'nı açar, numara serbest yazılır; stoktan çıkan satır (teslimat, iç transfer, alım iadesi) **Stoktan Lot Seçimi**'ni açar: kaynak konumdaki bütün lotlar eldeki miktarıyla listelenir, Seç işaretlenince Seçilen Miktar eldeki miktarla dolar (EditorScript), azaltılabilir ama eldeki miktarı aşamaz; Değişiklikleri Kaydet ile yazılır (kullanıcı kararı: 100 lotu tek tek yazmak yerine işaretleyerek seçmek). Ayrım belgenin kaynak konumundan gelir (iç konum = stoktan) ve satırın `LotFromStock` kolonunda durur; Lot/Seri Oluştur yalnız giren, Otomatik Ata yalnız çıkan satırda görünür.
- Lot/seri takipli satırda lot girilmişse yapılan miktar lot toplamıdır (kullanıcı kararı: lot seçmek o kadar teslim etmektir); Recalc miktarı lotlardan yazar ve seçilen lotları satırın Lotlar kolonunda (Açıklama'nın sağı) listeler. Tamamlanmış/iptal belgenin miktarına dokunulmaz. Doğrula'nın eşitlik hatası iki miktarı da yazar.
- Ek Bilgi: nakliye bilgileri, sorumlu, proje; ayrı Not sekmesi. Ürün Teslimat Politikası yalnız Teslimatlar'dadır.
- Ürünün Envanter Takibi ve Takip Yöntemi belirleyicidir: takip kapalı ürün stoğa hiç işlenmez ve stok kontrolüne girmez; `Lot`/`Serial` üründe lot dağılımı zorunludur; `Quantity` üründe lot boş tutulur.
Üretimde verilen ek kararlar:
- Stok konum türüne göre işlenir: kaynak konum `Internal` ise stoktan düşer, hedef konum `Internal` ise stoğa eklenir. Tedarikçiler/Müşteriler gibi dış (`External`) konumlar stok tutmaz; alım türünün kaynağı ve teslimat türünün hedefi dış konumdur. Demo veride IKT deposuna "Tedarikçiler" ve "Müşteriler" dış konumları eklendi.
- Formda gösterilmeyen konum (alımın kaynağı, teslimatın hedefi) kayıtta her zaman operasyon türünden yazılır (iade belgesi hariç).
- İç transfer onaycısı kaynak konumun depo sorumlusudur (`Inv_T_Location.ResponsibleUserName`, kullanıcı adı — iş akışı onaycıyı adla eşlediği için Guid tutulmaz (kullanıcı kararı); kayıt sonrası`SourceApproverUserNames`'e kullanıcı adı yazılır). Sorumlu yoksa `ApprovalStatus` "Onay Gerekmez" olur ve akış beklenmez. Ekranda belge durumu (`Status`) ile onay durumu (`ApprovalStatus`) birlikte bulunur: tablo bütün türler için ortak olduğundan durum akış düğümü değil belge yaşam döngüsüdür (standing default 24'ten bilinçli sapma).
- Birim çevrimi `Inv_F_UomConvert` ile (Adm_T_Uom Type + Ratio, aynı kategori); stok ürünün biriminde, lot miktarı satırın biriminde tutulur.
- Transfer Fişi rapor şablonu (Raporlar kategorisi) satırları belgenin `LineSummary` kolonundan basar: DynamicReport yalnız kaydın alanlarını yer tutucu olarak doldurduğu için satır özeti başlıkta tutulur (`Inv_P_TransferRecalc`).
- Durum butonları satınalmadaki kalıpla çalışır: işlem gizli `PendingAction` alanına yazılır, kayıt sonrası yordam çalıştırır. Başlık kancaları`@PendingAction` kullanmaz; iş akışı güncellemesi yalnız akış alanlarını gönderir.
- Malzeme talebi kalemleri iç transfere yalnız Satınalma › Talepler › Planlama'daki İç Transfer kararıyla gelir (`Prc_P_MaterialRequestPlan`, [App.Prc.md](App.Prc.md)): aynı kaynak → hedef konum için onaya girmemiş taslak transfer varsa satır ona eklenir, yoksa kaynak deponun iç transfer türüyle yeni taslak açılır. İç Transferler'deki Talepten Aktar butonu ve Transfer Talep Kalemleri ekranı 2026-10-13'te kaldırıldı.
- Detaylar satınalmanın `PurchaseDocGrid` diyaloğunu kullanır (ekran `BaseId` ile süzülür; yeni lot satırına `BaseId` filtreden yazılır, `InsertCommand` tabloya yazar).
`Envanter (App.Inventory) › Operasyonlar (App.Inventory.Operations)`: Alımlar, Teslimatlar, İç Transferler. Bütün belgelerin listesi Hareketler (`App.Inventory.Transfer`) Operasyonlar dışında, doğrudan Envanter altındadır (Stok ve Hareketler bölümü).
Sekmeler (menüsüz alt formlar, üç belge ekranında ortak): Operasyonlar (`App.Inventory.TransferLine`), Ek Bilgi (`App.Inventory.TransferOther`, aynı satır), Not (`App.Inventory.TransferNote`, aynı satır); yalnız İç Transferler'de Onay ve Teslim (`App.Inventory.TransferApproval`, aynı satır, salt okunur).
Diyaloglar: Lot/Seri Numaraları (`App.Inventory.TransferLineLot`, giren satırın Detaylar'ı), Stoktan Lot Seçimi (`App.Inventory.TransferLineLotStock`, çıkan satırın Detaylar'ı).
Durum butonları satırdadır ve belgenin durumuna göre görünür (araç çubuğu butonu kayda göre gizlenemez): Yapılacak olarak işaretle (Taslak; iç transferde onay tamamlanmışsa — ve Bekleyen), Doğrula (Hazır), İptal Et (Taslak, Bekleyen, Hazır), İade Et (Tamamlandı), Yazdır (her durumda); İç Transferler'de ayrıca iş akışı butonları. Buton adları durum adlarıyla eşleşir: Yapılacak olarak işaretle › Hazır, Doğrula › Tamamlandı, İptal Et › İptal. Satır butonları (yalnız ürünün takip yöntemi Lot ya da Seri olan satırda görünür): Lot/Seri Oluştur, Otomatik Ata, Detaylar; görünürlük satırın `TrackingMethod` kolonundan okunur. Hareketler'de (`App.Inventory.Transfer`) satırda Detay (salt okunur başlık + Operasyonlar sekmesi), Not ve belgeyi kendi ekranında açan Aç vardır; Ürün Hareketleri'nde de Aç hareketin belgesini açar (`/admin/form/App.Inventory.{Receipt|Delivery|InternalTransfer}/@TransferId`).
| Yordamlar | `Inv_P_Transfer{AfterSave,SetStatus,CheckAvailability,Validate,Copy,Number,Recalc,FromPurchaseOrder,SupplierPrice,LineAfterSave,LineLotGenerate,LineLotAssign}` |
- **Yapılacak olarak işaretle** (taslak, satırlı, konumları dolu; iç transferde onaylı ya da Onay Gerekmez): dış konumdan girişte yapılan miktar talep kadar dolar ve belge Hazır olur. İç konumdan çıkışta satırlar ürün bazında sırayla stoktan karşılanır; tümü karşılanırsa Hazır, değilse Bekleyen. Teslimatta "Mümkün olduğunca kısa sürede" kısmi karşılamada da Hazır yapar, "Tüm ürünler hazır olduğunda" bütün satırları bekler.
- **Yapılacak olarak işaretle** (Bekleyen): aynı hesabı yeniden yapar; stok girdiyse belge Hazır olur.
- **Doğrula** (yalnız Hazır): yapılan miktarı olan satır şarttır; lot/seri takipli üründe lot toplamı yapılan miktara eşit, seride her seri 1 adet ve tekil olmalıdır; iç kaynakta stok (ürün × lot) yetmezse durur. Stok güncellenir, belge Tamamlandı olur, Geçerlilik Tarihi yazılır. Sipariş kaleminin `ReceivedQuantity`'si ve talep kaleminin `DeliveredQuantity`'si artar (iadede azalır); talep kalemi tam karşılanınca `Done` olur. Siparişten açılan alımda ürünün tedarikçi fiyat listesi siparişin birim fiyatı ve son alım tarihiyle yenilenir (`Inv_P_TransferSupplierPrice`; kural [App.Prc.md](App.Prc.md) Talepler bölümünde). Recalc ve İptal Et talep kaleminin satır durumunu plana eşler (`Prc_P_MaterialRequestItemSync`): transferle tamamen planlanmış kalem kapanır, transfer iptal edilir ya da satırı silinirse yeniden açılır ve miktar Planlama'ya döner. Talepten az yapılan satırların kalanı backorder belgesine geçer ve stok kontrolüyle Hazır/Bekleyen açılır.
- **İade Et** (Tamamlandı): kaynak/hedef yer değiştirmiş, yapılan miktarlar ve lotlarıyla taslak belge; iadeden backorder açılmaz.
- **İptal Et**: Tamamlandı ya da İptal dışındaki belgede. İptal edilmiş belge düzenlenemez; tamamlanmış ya da iptal edilmiş belgenin satırı ve lotu değiştirilemez. Yalnız elle açılmış taslak (siparişten, backorder ya da iadeden gelmeyen) silinebilir.
- **Lot/Seri Oluştur**: yalnız giriş satırında; lot takipte kalan miktar için `Inventory.LotNumber`'tan tek lot, seri takipte kalan her birim için `Inventory.SerialNumber`'dan seri (miktar tam sayı olmalı). **Otomatik Ata**: yalnız çıkış satırında; mevcut lotları siler, kaynak konumdaki lotları ilk giren ilk çıkar sırasıyla atar.
- **Satır**: ürün seçilince birim üründen gelir; yeni satırda talep 1, birim Adet. Ürün listesi aktif mal (`Wares`) ürünlerdir.
- **Ağırlık** = Σ ürün ağırlığı× miktar (yapılan, yoksa talep; ürün biriminde).
- **Siparişten alım**: Satınalma Siparişi onaylanınca (ya da tekliften onaylı açılınca) taslak alım açılır; ayrıntı [App.Prc.md](App.Prc.md) › Siparişler.
İzin grubu `App.Inventory`. Ekran yetkileri `App.Inventory.Operations` altında (Alımlar, Teslimatlar, İç Transferler); üç belge ekranının ortak sekmeleri (Transfer Satırları, Ek Bilgi, Not) da `App.Inventory.Operations` altındadır; Lot/Seri Numaraları Transfer Satırları'nın, Onay ve Teslim İç Transferler'in altındadır. Durum butonları ekranın `.Update`, satır butonları Transfer Satırları'nın `.Update`, Detaylar Lot/Seri Numaraları'nın okuma yetkisini ister. Belge ekranını kullanan role sekme ve diyalog yetkileri de verilmelidir. Yetkiler hiçbir role otomatik atanmaz. Kiracı kapsamlı; şube kolonla tutulur.
2. Yapılacak olarak işaretle: belge Hazır, yapılan 10. Satırda Lot/Seri Oluştur LOT000001 (10) üretir; Doğrula Ana Depo'ya 10 Adet LOT000001 ekler, P00012 kalemine Alınan 10 yazılır.
3. Teslimatlar'da 4 Adet sensör için belge açılır; Yapılacak olarak işaretle Hazır yapar, Otomatik Ata LOT000001 (4) atar, Doğrula stoğu 6'ya düşürür.
4. İç Transferler'de Ana Depo'dan (sorumlusu var) başka bir iç konuma 2 Adet; Onayla, sorumlu onaylar (belge kendiliğinden hazırlanır), lotlar seçilir, Doğrula; Onay ve Teslim sekmesinde onaylayan ve teslim alan görünür.
- **Belge Bekleyen'de kaldı?** Kaynak konumda yeterli stok yok; stok girdikten sonra Yapılacak olarak işaretle'ye basın. Teslimatta politika "Mümkün olduğunca kısa sürede" ise eldeki kısım gönderilir.
- **Doğrula "lot/seri miktarı eşit değil" diyor?** Ürün lot/seri takiplidir; satırdaki Detaylar'dan lot girin ya da Lot/Seri Oluştur (giriş) / Otomatik Ata (çıkış) kullanın.
- **İç transfer hazırlanamıyor?** Kaynak konumun sorumlusu varsa önce Onayla ile onay alınmalıdır; onay verilince belge kendiliğinden hazırlanır.
- **İç transferde sıra nedir?** Satırlar › Onayla › Kaynak Depo Onayı› (otomatik Yapılacak olarak işaretle) › lot seçimi › Doğrula. Onay stok hareketinden önce gelir, çünkü malın kaynak depodan çıkmasına verilen izindir (kullanıcı kararı: onay sonrası Yapılacak olarak işaretle otomatik). Otomatik Yapılacak olarak işaretle şartları sağlanmazsa (satır yok, konum kuralı) belge Taslak kalır ve Yapılacak olarak işaretle elle basılır.
- **İç transferde dış konum ya da aynı konum seçilemiyor?** İç transfer depo içinde taşımadır: Kaynak ve Hedef Konum listeleri yalnız iç konumları gösterir, hedef kaynaktan farklı olmalıdır (formda kural, Yapılacak olarak işaretle/Doğrula'da 50325 ve 50326). İade belgesi bu kuraldan muaftır; yanlışlıkla dış konuma yapılmış eski transfer İade Et ile geri alınır.
- **Seed verisi:** numaratörler `data/App.Definitions.Sequence.json` (`Inventory.IKT.*`, `Inventory.LotNumber`, `Inventory.SerialNumber`), dış konumlar `data/App.Inventory.Location.json`, operasyon türü bağları`data/App.Inventory.OperationType.json`, şablon `data/App.Reports.ReportTemplates.json` (Transfer Fişi).
- **Geri alma:** Wizard Manager'da önce belge ekranları, sonra sekmeler ve diyaloglar silinir; tablolar ancak açık onayla düşürülür (sıra: TransferLineLot → TransferLine → Transfer, Stock).
## Stok, Hareketler ve Ürün Hareketleri (`App.Inventory.Stock`, `App.Inventory.Transfer`, `App.Inventory.StockMove`)
### 1. Amaç ve kapsam
Stok bakiyesi ve bütün hareketlerin salt okunur listeleri: Stok (şube › depo › konum › ürün › lot) ve Hareketler (bütün operasyon türlerinin satırları ortak kolonlarla). Kullanıcılar: depo, satınalma, üretim planlama ve yönetim. Değerleme (maliyet) ve izlenebilirlik raporu kapsam dışıdır.
- Hareketler `Inv_V_StockMove` görünümüdür: satır başına bir kayıt, lot dağılımı varsa lot başına bir kayıt; bütün durumlar listelenir, stoğu yalnız Tamamlandı satırları değiştirir.
- Görünümler Grid, Card, Pivot, Chart; depo × ürün toplamı Pivot ile alınır.
### 3. Menü ve ekranlar
Ayrı bir Raporlama dalı yoktur (kullanıcı kararı): Stok (`App.Inventory.Stock`, sıra 3), Hareketler (`App.Inventory.Transfer`, sıra 4 — alım, teslimat ve iç transfer belgeleri; satırda Detay, Not ve belgeyi kendi ekranında açan Aç) ve Ürün Hareketleri (`App.Inventory.StockMove`, sıra 5 — ürün/lot satırları; satırda Aç) doğrudan `Envanter` altında, Operasyonlar'dan sonradır; hepsi salt okunur. Yetkiler aynı sırada `App.Inventory` kökündedir.
### 4. Veri modeli
`Inv_T_Stock` (Operasyonlar §4) ve `Inv_V_StockMove`: Id (lot ya da satır), TransferId, TransferNo, OperationKind, OperationTypeId, Status, MoveDate (geçerlilik, yoksa planlanan tarih), BranchId, WarehouseId, Source/DestinationLocationId, PartnerId, SourceDocument, ProductId, LotNo, DemandQuantity, Quantity, UomId.
### 5. İş kuralları ve hesaplar
- Stok miktarı ürünün birimindedir; hareket miktarı satırın (lotta lotun) birimindedir.
- Sıfıra inen stok satırı silinmez (Sıfır Stok kartı); yeniden girişte giriş tarihi yenilenir.
- Kartlar: Stok — Stoktaki Ürün, Stoktaki Lot, Sıfır Stok; Hareketler — Açık Alım, Açık Teslimat, Açık İç Transfer, Geciken; Ürün Hareketleri — Bugün Tamamlanan, Tamamlanan Giriş, Tamamlanan Çıkış, Açık Hareket.
### 6. Yetki ve görünürlük
İki ekranın yetkisi menüyle aynı sırada `App.Inventory` izin grubunun kökündedir (`App.Inventory.Stock` sıra 3, `App.Inventory.StockMove` sıra 4); yetkiler hiçbir role otomatik atanmaz. Kiracı kapsamlı.
### 7. Entegrasyonlar
Kaynak Operasyonlar dalının belgeleridir; lookup kaynakları Şubeler, Depolar, Konumlar, Ürünler, Ölçü Birimleri, Kontaklar.
### 8. Akış örneği
Operasyonlar §8'deki akıştan sonra Stok'ta Ana Depo / sensör / LOT000001 = 4 görünür; Ürün Hareketleri'nde IKT/IN/00001 (+10), teslimat (−4) ve iç transfer satırları listelenir.
### 9. Sık sorulanlar
- **Hareket listede ama stok değişmedi?** Hareket Tamamlandı değildir ya da ürünün envanter takibi kapalıdır.
- **Dış konum stokta yok mu?** Tedarikçiler/Müşteriler gibi dış konumlar stok tutmaz.
### 10. Dosyalar ve geri alma
Wizard'lar `Inventory_Stock.json`, `Inventory_StockMove.json`; nesneler `Inv_T_Stock`, `Inv_V_StockMove` (sql + postgres). Ekranlar Wizard Manager'dan silinir; tablo ve görünüm Operasyonlar'a bağlıdır.
| 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'` |
| Alt formlar | `App.Inventory.ProductGeneral` (Id → Id), `App.Inventory.ProductAttributeLine` (Id → ProductId), `App.Inventory.ProductSupplier` (Id → ProductId), `App.Inventory.ProductStock` (Id → Id), `App.Inventory.ProductAccounting` (Id → Id), `App.Inventory.Bom` (Id → ProductId) |
| 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'` |
| Alt formlar | `App.Inventory.BomComponent` (Id → BomId), `App.Inventory.BomOperation` (Id → BomId), `App.Inventory.BomOther` (Id → Id), `App.Inventory.BomOverview` (Id → BomId) |
| 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, CAST(NULL AS nvarchar(400)) AS ParentName 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, CAST((SELECT pp.Name + ISNULL(' (' + (SELECT STRING_AGG(avn.Name, ', ') FROM STRING_SPLIT(bp.VariantKey, '\|') sn INNER JOIN Inv_T_AttributeValue avn ON CAST(avn.Id AS nvarchar(36)) = sn.value) + ')', '') FROM Inv_T_Bom bp INNER JOIN Inv_T_Product pp ON pp.Id = bp.ProductId WHERE bp.Id = b0.Id) AS nvarchar(400)) 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, CAST((SELECT pp.Name + ISNULL(' (' + (SELECT STRING_AGG(avn.Name, ', ') FROM STRING_SPLIT(cp.VariantKey, '\|') sn INNER JOIN Inv_T_AttributeValue avn ON CAST(avn.Id AS nvarchar(36)) = sn.value) + ')', '') FROM Inv_T_BomComponent cp INNER JOIN Inv_T_Product pp ON pp.Id = cp.ProductId WHERE cp.Id = c1.Id) AS nvarchar(400)) 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.Quantit
| Alt formlar | `App.Inventory.TransferLine` (Id → TransferId), `App.Inventory.TransferOther` (Id → Id), `App.Inventory.TransferNote` (Id → Id), `App.Inventory.TransferApproval` (Id → Id) |
| Açıklama | Stoktan Lot Seçimi — stoktan çıkan satırın (teslimat, iç transfer, alım iadesi) kaynak konumundaki bütün lot/seriler; satırdaki Detaylar butonuyla açılır. |
| Açıklama | Ürün Hareketleri — alım, teslimat ve iç transferlerin bütün ürün satırları ortak kolonlarla; satırın lot dağılımı varsa lot başına bir satır (salt okunur). |