Performans 360
This commit is contained in:
parent
16fd5df0c7
commit
7ecb45a53f
138 changed files with 64724 additions and 239 deletions
3
.github/instructions/ai.instructions.md
vendored
3
.github/instructions/ai.instructions.md
vendored
|
|
@ -23,6 +23,7 @@ Companion documents (this file wins on conflict):
|
|||
| `dotnet.instructions.md` | Binding code standard for everything under `api/` |
|
||||
| `list.instructions.md` | Step-by-step procedure for adding a module / list through seeders |
|
||||
| `../../README.md` | Technical map: what exists, where it lives, how it is wired |
|
||||
| `../../configs/seeds/host/docs/modules/{Module}.md` | **How a generated module works**: discovery answers, approved recipe, screens, formulas, status rules, permissions, FAQ. Read it first when asked how a module/component behaves; write or update it with every module/component change (`lowcode.instructions.md` §0.13). Index: `README.md` §10.5 |
|
||||
| `../../CLAUDE.md` | Operating rules and standing defaults for AI agents in this repo |
|
||||
|
||||
---
|
||||
|
|
@ -624,6 +625,8 @@ A proposal is complete only if all are present:
|
|||
4. Menu-route-component mapping included.
|
||||
5. Validation checklist included.
|
||||
6. Risk/rollback notes included.
|
||||
7. Once produced, the module document `configs/seeds/{scope}/docs/modules/{Module}.md` is completed (analysis,
|
||||
decisions, behaviour) and indexed in `README.md` §10.5.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1266,7 +1266,7 @@ soneklerini alır.
|
|||
| **Dev Requests** | `App.DevRequests` | `Sas_H_DevRequest` | host | **Kanban/Todo düzeninin** referansı (`DefaultLayout: todo`): `Status`, `Priority`, `SortOrder`, `Tags`, `Assignees`, `SubTasks`, `Timesheets`; detayda `Description` yanında `Analysis` sekmesi (`AnalysisExpr`). MCP geliştirme döngüsünün kuyruğudur (`Backlog` → `Analysis` MCP analiz eder, `Ready to Start`'a kullanıcı alır; `Ready to Start` → `Testing`, `Staging`'e kullanıcı alır; araç çubuğunda DB Migrate butonu vardır — `UiEvalService.ApiDbMigrate()`, önce onay sorar, `App.Setup.Migrate`; yalnızca `start_dev_request` başlatır; açıklamadaki base64 görseller MCP'ye resim içeriği olarak gider, analiz `save_dev_request_analysis` ile yazılır, üretim notu `append_dev_request_note` ile `Analysis`'e eklenir — `Description` talebin yazıldığı hâliyle kalır; `lowcode.instructions.md` §0.11–§0.12). |
|
||||
| **Tenants** | `AbpTenantManagement.Tenants` | `AbpTenants` | host | Kiracı kaydı, bağlantı dizesi diyaloğu (`TenantsConnectionString`), alt form olarak şubeler; yazma `list-form-dynamic-api/tenant-*`. Ekranların `IsTenant` davranışının kaynağı. |
|
||||
| **Branches** | `App.Branches` | `Sas_T_Branch` | tenant | Şube listesi. Ekranı `IsBranch = true` yaparsan filtre bu tablodan gelir; `BranchSeed` diyaloğu şube verisini kurar. |
|
||||
| **Setting Definitions** | `App.SettingDefinitions` | `Sas_H_SettingDefinition` | host | Yeni uygulama ayarı: `Code`, `MainGroupKey`/`SubGroupKey`, `DataType`, `SelectOptions`, `DefaultValue`, `Providers`, `RequiredPermissionName`, `IsEncrypted`, `IsVisibleToClients`. Hazır tanımlar `data/App.SettingDefinitions.json`'dan gelir. Ayarlanabilir olması gereken değeri koda gömme. |
|
||||
| **Setting Definitions** | `App.SettingDefinitions` | `Sas_H_SettingDefinition` | host | Yeni uygulama ayarı: `Code`, `MainGroupKey`/`SubGroupKey`, `DataType`, `SelectOptions` (`List` tipinde değer → etiket; etiket dil anahtarıdır, Ayarlar ekranı `::` önekiyle çevirir, anahtar yoksa metin olduğu gibi görünür), `DefaultValue`, `Providers`, `RequiredPermissionName`, `IsEncrypted`, `IsVisibleToClients`. Hazır tanımlar `data/App.SettingDefinitions.json`'dan gelir. Ayarlanabilir olması gereken değeri koda gömme. |
|
||||
| **Languages › Language / Language Text** | `App.Languages.Language` · `.LanguageText` | `Sas_H_Language` · `Sas_H_LanguageKey` · `Sas_H_LanguageText` | host | Dil anahtarları. Üretilen her ekranın EN+TR metinleri buraya yazılır; ekran `data/App.Languages.{Language,LanguageText}.json` dosyalarına senkronlanır. Metin insert'i eksik `LanguageKey`'i de üretir, aynı kültür+kaynak+anahtar varsa eklemez. |
|
||||
| **Data Source** | `App.DataSource` | `Sas_H_DataSource` | host | `Code`, `DataSourceType`, `ConnectionString`. **İki tür kayıt bir arada:** elle tanımlanan host/harici bağlantılar ve `Code = tenant adı` olan otomatik tenant bağlantıları (Tenants ekranındaki bağlantı diyaloğu yönetir, elle dokunma). Varsayılan kaydı `HostDataSeeder` appsettings'teki bağlantı cümlesinden kurar. Çözüm kuralı `lowcode` §9.3.3. Bağlantı dizesi koda/JSON'a yazılmaz. |
|
||||
| **Background Workers › Recurring Jobs / Jobs** | `App.BackgroundWorkers.RecurringJobs` · `.Jobs` | `Sas_H_BackgroundWorker` · `Sas_H_BackgroundWorker_JobFlow` | host | Cron'lu işler ve çalıştırma geçmişi (`Tenant`, `ExecutionDate`, `Duration`, `Status`, `FailureReason`, `ExceptionDetails`). `WorkerType`/`Scope` değerleri §11'de; her kapsam ayrı bir Hangfire işidir, `Tenant` kolonu hangi kiracıda çalıştığını gösterir. Hazır işler (oturum temizliği, bildirim, yedek, şema sözlüğü) `data/App.BackgroundWorkers.RecurringJobs.json`'dan gelir. Ayrıntı: `lowcode` §9.10, `README.md` §14. |
|
||||
|
|
@ -1395,6 +1395,7 @@ listesinde `Hr` varsa görür (modül listesi boş kiracıda süzme yoktur — `
|
|||
| **Recruitment › Application** | `App.Hr.JobApplication` (alt formlar `App.Hr.Interview`, `App.Hr.JobOffer`) | `Hr_T_JobApplication` | tenant | Aday × ilan başvurusu (çift tekil). `Stage`: `Applied` → `Screening` → `Interview` → `Offer` → `Hired` / `Rejected`; **Todo (kanban) görünümü** aşama sütunlarıyla. Mülakat eklenince `Interview`, teklif eklenince `Offer`, teklif `Accepted` olunca `Hired`'a ilerler (after-command SQL, geri gitmez; insert sonrası komutlar yalnızca eklenen satıra `@Id` ile çalışır). `CandidateName`/`PostingTitle` kopyalanır (kanban başlığı). Ret sebebi yalnızca `Rejected` aşamasında düzenlenir. Alt form olduğu için widget yok. Wizard. |
|
||||
| **Recruitment › Interview** | `App.Hr.Interview` (alt form `App.Hr.InterviewScore`) | `Hr_T_Interview` · `Hr_T_InterviewScore` | tenant | Mülakat planlama: tür, başlangıç/bitiş (**Scheduler** görünümü), mülakatçı, durum, öneri. Kayıt eklenince mülakatçıya `IseAlimMulakatAtandi` bildirimi SQL ile yazılır (tipin `Custom` kuralları kanalı belirler, metin `App.Hr.Interview.Notification.*`). Puan alt formu kriter başına 1–5; `OverallScore` = Σ(puan × ağırlık) / Σ ağırlık, başvurunun `AverageScore`'u mülakatların ortalaması. Wizard. |
|
||||
| **Recruitment › Job Offer** | `App.Hr.JobOffer` | `Hr_T_JobOffer` | tenant | Teklif: `OfferNo` (`TKL-…`), başvuru seçilince pozisyon bilgileri ilandan `copy` ile dolar, brüt ücret + para birimi, yan haklar (`Hr_T_BenefitType` kodları), `Status` (`Draft`/`Sent`/`Accepted`/`Declined`/`Expired`, yanıt tarihi otomatik). İç onay **Grid Workflow** (Kadro Talebi ile aynı akış). Onaylı satırda **Teklif Mektubu** butonu (`DynamicReport`, `Raporlar` kategorisi). Wizard. |
|
||||
| **Performance Management** | `App.Hr.Performance` dalı (yalnız İK): `PerformancePeriod`, `PerformanceReview`, `PerformanceCalibration`, `DevelopmentPlan`; tanım `App.Hr.PerformanceRating` (İK › Tanımlar). Çalışana ait `MyPerformanceReview`, `TeamPerformanceReview`, `My360Feedback` menüsüzdür; Intranet › Dashboard'daki custom widget'lardan (`MyPerformanceWidget`, `TeamPerformanceWidget`, `My360FeedbackWidget`) açılır | `Hr_T_PerformanceRating` · `Hr_T_PerformancePeriod` · `Hr_T_PerformancePeriodSkill` · `Hr_T_PerformanceReview` · `Hr_T_PerformanceGoal` · `Hr_T_PerformanceCompetency` · `Hr_T_PerformanceFeedback` · `Hr_T_PerformanceFeedbackScore` · `Hr_T_DevelopmentPlan` | tenant | Dönem → değerlendirme (hedef KPI/OKR + yetkinlik `Hr_T_Skill`/`Hr_T_SkillLevel` + isteğe bağlı 360) → kalibrasyon → gelişim planı. **Aynı tabloya persona ekranları**: İK (tümü), çalışan (`EmployeeId = '@USERID'`), yönetici (`ManagerId = '@USERID'`), 360 değerlendiricisi (`ReviewerId = '@USERID'`); kilitli alanlar İK ekranının yetkisine bağlıdır (sunucu düşürür), satır sahipliği ve aşama kuralı `Hr_S_PerformanceGuard` (before-command). Hesap ve durum geçişi `Hr_S_PerformanceReviewRecalc` / `Hr_S_PerformanceReviewAfterSave`; tamamlanan değerlendirme `Adm_T_UserSkill`'e yazar. Widget'lar veriyi ekranın kendi sorgusundan (`list-form-select/select`) okur. Çalışma şekli ve kararlar: `configs/seeds/host/docs/modules/HrPerformance.md`. Wizard + Custom Component (pano kutusu). |
|
||||
| **Org Chart** | `App.Hr.OrgChart` · `/admin/organization` | `Hr_T_Department` · `Hr_T_JobPosition` | tenant | Departman/ünvan verisinin organizasyon şeması görünümü (özel React sayfası `hr/OrgChart`, veri `api/app/org-chart`). Menü ve route aynı yetkiyi ister. |
|
||||
| **Intranet › Announcement** | `App.Hr.Intranet.Announcement` (alt formlar Like/Comment) | `Hr_T_Announcement` · `Hr_T_AnnouncementLike` · `Hr_T_AnnouncementComment` | tenant | Duyuru + beğeni + yorum: **ana kayıt / alt etkileşim** kalıbının hazır örneği. |
|
||||
| **Intranet › Survey** | `App.Hr.Intranet.Survey` (alt form Question → Option; Response → Answer) | `Hr_T_Survey` · `Hr_T_SurveyQuestion` · `Hr_T_SurveyQuestionOption` · `Hr_T_SurveyResponse` · `Hr_T_SurveyAnswer` | tenant | Anket motoru; soru–seçenek–yanıt zinciri **iki seviyeli alt form** ihtiyacının referansıdır. |
|
||||
|
|
@ -1512,6 +1513,7 @@ alanları da doldurur (`lowcode` §0.9).
|
|||
| "izin türü, masraf türü, yan hak türü, vardiya, resmi tatil / çalışma takvimi" | İK › Definitions · İK › Work Calendar · İK › Shift | Var olan `Hr_T_WorkCalendar` / `Hr_T_LeaveType` / `Hr_T_ExpenseType` / `Hr_T_BenefitType` / `Hr_T_Shift` tablosuna lookup bağla; yenisini üretme |
|
||||
| "eğitim / katılımcı, araç / şoför / araç masrafı / araç çıkış-giriş, olay günlüğü, disiplin / tutanak / savunma / ihtar" | İK › Trainings · İK › Vehicles · İK › Event Log · İK › Disciplinary Case | Var olan `Hr_T_Training*` / `Hr_T_Vehicle*` / `Hr_T_Driver*` / `Hr_T_EventLog` / `Hr_T_Disciplinary*` ekranını genişlet ya da lookup bağla; paralel tablo üretme |
|
||||
| "işe alım, kadro talebi, ilan, aday / CV, mülakat, teklif" | İK › Recruitment | Var olan `Hr_T_StaffRequest` / `Hr_T_JobPosting` / `Hr_T_Candidate` / `Hr_T_JobApplication` / `Hr_T_Interview` / `Hr_T_JobOffer` ekranını genişlet; personel kullanıcısını BT elle açar, aday kaydına `UserId` ile bağlanır |
|
||||
| "performans değerlendirme, hedef / KPI / OKR, yetkinlik değerlendirmesi, 360, kalibrasyon, gelişim planı" | İK › Performance Management | Var olan `Hr_T_Performance*` / `Hr_T_DevelopmentPlan` ekranını genişlet; yeni persona ekranı aynı tabloya `DefaultFilter` + `Hr_S_PerformanceGuard` ile açılır (`configs/seeds/host/docs/modules/HrPerformance.md`) |
|
||||
| "yapay zekâ cevaplasın" | Saas › Definitions › AiBot | Bot tanımı; `/admin/ai` bu tanımı kullanır |
|
||||
|
||||
### 12.7 Canlı referans uygulamalar
|
||||
|
|
|
|||
83
.github/instructions/lowcode.instructions.md
vendored
83
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -53,6 +53,7 @@ configs/seeds/host/
|
|||
├── postgres/object|execute/… ← aynısının PostgreSQL diyalekti (hedef PG ise)
|
||||
├── crud/{EntityName}.json ← tablonun REST uçları
|
||||
├── wizard/{WizardName}.json ← ekran + menü + yetki + dil anahtarları (List yolunda sunucu yazar, §4.1)
|
||||
├── docs/modules/{Modül}.md ← modül dokümanı; iskelet + envanteri deploy yazar (§0.13)
|
||||
├── data/{ListFormCode}.json ← ekrandan girilen liste verisinin aynası (opsiyonel, §9.15)
|
||||
│ data/{ListFormCode}/{anahtar}.json ← aynı aynanın klasör modu (satır başına dosya)
|
||||
│ Custom Component'ler klasör modunda yaşar:
|
||||
|
|
@ -72,6 +73,7 @@ Tenant kapsamı isteniyorsa `host/` yerine `tenants/{tenantId}/`; iç düzen ayn
|
|||
| 5 | Alt ekranlar (varsa) | ek `wizard/…` dosyaları | Ana wizard'dan **önceki** `SeededAt` damgasını alır |
|
||||
| 6 | Liste verisi (isteniyorsa) | `data/{ListFormCode}.json` | Ekran ve tablo hazır olmalı; `ListForm.SeedFilePath` bu yolu gösterir (§9.15) |
|
||||
| 7 | SEO alanları (public yol ürettiysen) | Yolu tanımlayan satırın kendisi: `data/App.Menus.Routes.json` ya da `data/App.DeveloperKit.CustomComponents/{Id}.json` | Yolu üreten dosya yazıldıktan sonra; ziyaretçiye açık hiçbir yol metasız kalmaz (§0.9) |
|
||||
| 8 | Modül dokümanı | `docs/modules/{Modül}.md` (iskelet + envanteri deploy açar) + `README.md` §10.5 dizin satırı | Son adımdır; anlatım bölümleri doldurulur, MCP'de `save_module_doc` (§0.13) |
|
||||
|
||||
**`Wizard.SeededAt` bir bağımlılık aracıdır.** Dosya adı tarih taşımaz (`{WizardName}.json`);
|
||||
`WizardDataSeeder` `wizard/` klasörünü **`Wizard.SeededAt` damgasına göre sıralı** işler (eşitlikte
|
||||
|
|
@ -597,8 +599,9 @@ talebin metnini döndürür. Başlık birden fazla talebe uyuyorsa Id ister. `St
|
|||
| 1. Kuyruğu oku (yalnızca toplu) | `query_list` — `ListFormCode: App.DevRequests`, filtre `["Status","=","Ready to Start"]`, sıralama `SortOrder` | — |
|
||||
| 2. Talebi üstlen | `start_dev_request` — Id ya da tam başlık. Yarım kalmış talebe dönüşte `get_dev_request` | In Progress |
|
||||
| 3. Üret | Analizin **Üretim planı** sırayla, aynen uygulanır (aşağıdaki kurallar) → `create_table` / `deploy_wizard` / `save_component`; demo veri varsa `SeedData: true` + `seedRows` (§0.10.1); bu dosyanın kuralları aynen geçerlidir | — |
|
||||
| 4. Teslim | Sonuç kaydı + `update_row` → `Testing`. DB Migrate beklenmez; talep burada biter | Testing |
|
||||
| 5. Test | Kullanıcı DB Migrate çalıştırır, ekranı elle test eder ve talebi kendisi `Staging`'e alır (geri dönüşte `In Progress`). MCP bu adımı yapmaz | Staging |
|
||||
| 4. Doküman | `get_module_doc` → `module-doc:todo` bölümleri doldurulur → `save_module_doc` (§0.13); eksik doküman Testing'i engeller | — |
|
||||
| 5. Teslim | Sonuç kaydı + `update_row` → `Testing`. DB Migrate beklenmez; talep burada biter | Testing |
|
||||
| 6. Test | Kullanıcı DB Migrate çalıştırır, ekranı elle test eder ve talebi kendisi `Staging`'e alır (geri dönüşte `In Progress`). MCP bu adımı yapmaz | Staging |
|
||||
|
||||
**Sonuç kaydı** şema değiştirmeden mevcut alanlara yazılır:
|
||||
- `SubTasks` — her üretilen artefakt bir satır, `add_dev_request_subtasks` ile yalnızca başlık
|
||||
|
|
@ -802,6 +805,56 @@ Kısa ve karar odaklı yaz; talebi tekrar anlatma.
|
|||
ihtiyaç, §0.8, adıyla). Talebi daraltan geçici çözüm önerilmez; "Hayır" taşıyan talep yetenek
|
||||
eklenene kadar `Ready to Start`'a alınmaz.
|
||||
|
||||
### 0.13 Modül dokümanı — `configs/seeds/{kapsam}/docs/modules/{Modül}.md`
|
||||
|
||||
Üretilen her modül kendi çalışma şeklini bir md dosyasında taşır; "bu ekran nasıl çalışıyor / şu
|
||||
puan nereden geliyor" sorusu kod ve seed taranmadan bu dosyadan cevaplanır (MCP'de `get_module_doc`).
|
||||
Doküman **wizard'ın parçasıdır**: Wizard ekranından ya da MCP `deploy_wizard` ile üretilen her
|
||||
modülde sunucu onu kendisi açar ve güncel tutar; anlatım bölümlerini üreten kişi/AI doldurur.
|
||||
Wizard dışı (entity, özel React) modüller dokümanı elle yazar.
|
||||
|
||||
- **Yer:** kapsam seed klasörü — `configs/seeds/host/docs/modules/{Modül}.md` (kiracı kapsamında
|
||||
`tenants/{tenantId}/docs/modules`). Sunucu yalnızca seed köküne yazabildiği için depo kökünde
|
||||
değildir. Wizard export zip'i dokümanı taşır, import yazar (`docs/modules/*.md`).
|
||||
- **Hangi wizard hangi dokümana** (`ModuleDocCatalog`; wizard sözleşmesine alan eklenmez):
|
||||
1. Dokümanın ilk satırındaki beyan ekranı sahipleniyorsa o doküman:
|
||||
`<!-- module-doc: claims=App.Hr.CandidateSource, App.Hr.RejectionReason -->` (başka dalda
|
||||
duran tanım ekranları için).
|
||||
2. Menüsüz alt form, onu `SubForms` içinde taşıyan ekranın dokümanına gider.
|
||||
3. Üst menü zincirinde kökün altında bir dal varsa dal (`App.Hr › App.Hr.Performance › …` →
|
||||
`App.Hr.Performance`), yoksa ekranın kendi kodu. Ad koddan türer: `App.` atılır, noktalar
|
||||
silinir → `HrPerformance.md`.
|
||||
- **Otomatik kısım:** deploy (`ListFormWizardAppService.Create`), silme, tasarımcı kaydı
|
||||
(`WizardSeedSynchronizer`) ve import kapanışı `ModuleDocManager.RefreshAllAsync` çağırır:
|
||||
doküman yoksa iskelet açılır (bölümler `_Henüz yazılmadı._ <!-- module-doc:todo -->`),
|
||||
`<!-- module-doc:auto:begin -->` … `<!-- module-doc:auto:end -->` arasındaki **"Ek — Ekran
|
||||
envanteri"** wizard dosyalarından yeniden yazılır (menü, kaynak, görünümler, alt formlar,
|
||||
widget'lar, komutlar/prosedürler, varsayılanlar, alan tablosu). Envanter elle düzenlenmez.
|
||||
Wizard'ı kalmayan ve hiç yazılmamış iskelet silinir. Wizard'a yeni bir kayıt yolu eklenirse
|
||||
`RefreshAllAsync` çağrısı da eklenir.
|
||||
- **Elle/AI ile yazılan kısım:** aşağıdaki bölümler; doldurulan bölümden `module-doc:todo`
|
||||
işareti kaldırılır, boş kalacak bölüme "Yok." yazılır. MCP'de `save_module_doc` (dosyanın
|
||||
tamamı; envanter gönderilmez, sunucu ekler; beyan satırı korunur). Claude Code depoda dosyayı
|
||||
doğrudan yazar.
|
||||
- **Zorunluluk:** MCP döngüsünde talep `update_row` ile `Testing`'e alınırken talebin wizard'larının
|
||||
dokümanında `module-doc:todo` kalmışsa ya da doküman yoksa istek reddedilir
|
||||
(`IModuleDocAppService.GetIncompleteForDevRequestAsync`).
|
||||
- **Dizin:** `README.md` §10.5'e bir satır eklenir; README'de modül en fazla ilgili bölümde tek
|
||||
cümleyle anılıp dokümana bağlanır.
|
||||
- **Bölümler** (`ModuleDocRenderer.Sections`):
|
||||
1. **Amaç ve kapsam** — kim kullanır, hangi işi çözer.
|
||||
2. **Analiz ve kararlar** — keşif turunun cevapları (soru → seçilen seçenek → gerekçe) ya da
|
||||
MCP'de onaylanmış analiz, onaylanan tarif ve `(varsayılan)` kalan satırlar.
|
||||
3. **Menü ve ekranlar** — menü yolu, `ListFormCode`, persona (kim görür), alt formlar, görünümler, widget'lar.
|
||||
4. **Veri modeli** — tablolar, anahtar ilişkiler, lookup kaynakları, durum/enum değerleri.
|
||||
5. **İş kuralları ve hesaplar** — formüller, durum geçişleri, prosedürler ve hangi kancadan
|
||||
(`*BeforeCommand`/`*AfterCommand`) çağrıldıkları, `EditorScript`'ler.
|
||||
6. **Yetki ve görünürlük** — yetki kodları, önerilen rol dağılımı, satır süzmesi.
|
||||
7. **Entegrasyonlar** — bildirim tipleri/kuralları, zamanlanmış işler, diğer modüllere yazma/okuma.
|
||||
8. **Akış örneği** — uçtan uca bir senaryo (kim, hangi ekranda, ne yapar, sonuç ne olur).
|
||||
9. **Sık sorulanlar** — "X neden kilitli?", "Y nasıl hesaplanır?" gibi soru-cevaplar.
|
||||
10. **Dosyalar ve geri alma** — üretilen her seed/sql dosyası ve kaldırma yolu.
|
||||
|
||||
## 1. Hangi istek → hangi artefakt
|
||||
|
||||
| İstek | Üretilecek artefakt | Bölüm |
|
||||
|
|
@ -1158,7 +1211,7 @@ atanmaz (admin dahil); ekranı görecek roller yetkiyi rol ekranından alır.
|
|||
| `IsTenant` / `IsBranch` / `IsOrganizationUnit` | `[ListForm]` Otomatik kırılım filtresi. Tabloda `TenantId` varsa `IsTenant: true` **olmalı**. |
|
||||
| `AllowAdding` / `AllowUpdating` / `AllowDeleting` / `ConfirmDelete` | `[ListForm]` Toolbar ve satır aksiyonları (`EditingOptionDto`). |
|
||||
| `SeedData` | `[ListForm]` `true` ise `SeedFilePath = data/{ListFormCode}.json` ve `SeedSyncInsert/Update/Delete` açık üretilir; ekrandan girilen satır dosyaya yazılır, migrate geri yükler. Wizard ekranında sorulmaz; demo veri taşıyan MCP üretimi için (§0.10.1). Varsayılan `false`. |
|
||||
| `AllowDetail` | `[ListForm]` Satırda **Detay** düğmesi çıkar; `/admin/form/{ListFormCode}/{anahtar}` adresini yeni sekmede açar — aynı ekranın tek kayıtlık form görünümüdür. `KeyFieldName` boşsa çalışmaz. **`SubForms` doluysa cevaptan bağımsız `true` üretilir** (`ListFormWizardDto.BuildListForm`): wizard alt formları `Form` tipinde kurar ve sekmeler yalnızca Detay görünümünde açılır. Elle yazılan wizard dosyasında da alt formu olan ekranın `EditingOptionDto.AllowDetail` değeri `true` yazılır. |
|
||||
| `AllowDetail` | `[ListForm]` Satırda **Detay** düğmesi çıkar; `/admin/form/{ListFormCode}/{anahtar}` adresini yeni sekmede açar — aynı ekranın tek kayıtlık form görünümüdür. `KeyFieldName` boşsa çalışmaz. **`SubForms` doluysa cevaptan bağımsız `true` üretilir** (`ListFormWizardDto.BuildListForm`): wizard alt formları `Form` tipinde kurar ve sekmeler yalnızca Detay görünümünde açılır. Elle yazılan wizard dosyasında da alt formu olan ekranın `EditingOptionDto.AllowDetail` değeri `true` yazılır. **Alt formu olmayan listede `false` kalır** — MCP/AI üretiminde Detay düğmesi yalnızca `SubForms` taşıyan listeye açılır; kullanıcı açıkça istemedikçe tek tablolu liste ya da alt form ekranının kendisi (`PerformancePeriodSkill` gibi) Detay almaz. |
|
||||
| `DefaultLayout` | `[ListForm]` `"grid"`, `"card"`, `"pivot"`, `"chart"`, `"tree"`, `"gantt"`, `"scheduler"`, `"todo"`. |
|
||||
| `Grid` `Card` `Pivot` `Chart` `Tree` `Gantt` `Scheduler` `Todo` | `[ListForm]` Hangi görünümlerin açık olduğu (`LayoutDto`). **Liste ekranında `Grid`/`Card`/`Pivot`/`Chart` varsayılan `true`**, diğer dördü `false` (§9.8). Açtığın her görünümün option bloğunu da doldur. |
|
||||
|
||||
|
|
@ -1726,6 +1779,26 @@ ile ekler (§4.0). Sıra değerleri veritabanı ile dosyadaki satırların birle
|
|||
tanımlanmıştır. Anahtar yalnızca veritabanında varsa (seed dosyasında satırı yoksa) deploy onu
|
||||
veritabanındaki metniyle `App.Languages.LanguageText.json`'a taşır; sahipliğini almaz.
|
||||
|
||||
### 4.4.2 Ekran açıklaması — başlıktaki ⓘ (`DescTr` / `DescEn`)
|
||||
|
||||
Liste ekranının başlığının yanındaki bilgi simgesi `ListForm.Description` dil anahtarını
|
||||
(`{ListFormCode}.Desc`) bir diyalogda gösterir (`views/list/List.tsx` → `RichText`). Bu metin
|
||||
ekranın **kullanım kılavuzudur**; tek satırlık özet yetmez. Wizard ve MCP ile üretilen her liste
|
||||
ekranında (alt formlar dahil) `DescTr` ve `DescEn` şunları anlatır:
|
||||
|
||||
- İlk satır: ekranın adı ve ne işe yaradığı (tek cümle).
|
||||
- `Nerede:` menü yolu ya da hangi ekranın hangi sekmesi olduğu; kim kullanır.
|
||||
- `Alanlar:` ana alanlar madde olarak (`• Alan → açıklama`), lookup kaynağı ve değer listeleri.
|
||||
- `Otomatik:` numaratör, hesaplar, durum geçişleri, bildirimler, başka ekrana yazan komutlar.
|
||||
- `İlişkili:` / `Kullanıldığı yerler:` bağlı ekranlar; `Widget'lar:`; gerekiyorsa `Dikkat:`.
|
||||
|
||||
Biçim `RichText` sözleşmesidir (HTML yazılmaz): her satır bir blok, `• ` ile başlayan satırlar
|
||||
madde listesi, `Etiket: …` satırı kalın başlık, maddede `Ad → açıklama` kalıbı. Wizard ekranında
|
||||
alan çok satırlıdır. MCP `deploy_wizard` her iki dilde **en az 3 satır ve 150 karakter** olmayan
|
||||
açıklamayı reddeder (`McpErrorCodes.WizardDescriptionTooShort`). Metin değiştirildiğinde dil
|
||||
satırı `data/App.Languages.LanguageText.json`'a yazılır; kurulu ekranda yeni metin wizard
|
||||
yeniden deploy edilip (bekleyen kurulum) DB Migrate çalışınca gelir.
|
||||
|
||||
### 4.5 Güncelleme, idempotency ve silme semantiği
|
||||
|
||||
**Seeder idempotenttir — bir ekran zaten kuruluysa ve bekleyen kurulumu (`Pending`) yoksa dosya
|
||||
|
|
@ -4615,6 +4688,9 @@ tedarikçi lookup'ı + iki kademeli onay).
|
|||
veri aynası ve `InsertedRecords` içindeki kullanılmayan kayıtlar gider; tablo yalnızca
|
||||
onayda seçilirse (MCP: `dropTables: true`) scripti ve crud dosyasıyla düşer (§4.5).
|
||||
Dosyayı diskten silmek kayıtları temizlemez.
|
||||
- [ ] Modül dokümanı (`configs/seeds/{kapsam}/docs/modules/{Modül}.md`) yazıldı ya da güncellendi; analiz/kararlar,
|
||||
ekranlar, hesaplar ve yetkiler üretilen artefaktların gerçek adlarıyla yazılı, README §10.5
|
||||
dizininde satırı var (§0.13).
|
||||
|
||||
Prompt ile üretim yaptıysan ek olarak:
|
||||
|
||||
|
|
@ -4627,6 +4703,7 @@ Prompt ile üretim yaptıysan ek olarak:
|
|||
görünüm yalnızca istek onu açıkça dışarıda bıraktığı için kapalı (§9.8).
|
||||
- [ ] Açılan her görünümün zorunlu option alanı dolu (§9.8).
|
||||
- [ ] Alt form olarak üretilen her ekranda (menüsüz ya da menülü) `Widgets` boş (§4.6.1 istisna).
|
||||
- [ ] `AllowDetail: true` yalnızca `SubForms` taşıyan listede; alt formu olmayan liste ve alt form ekranının kendisi `false`.
|
||||
- [ ] Menüsüz alt formun yetkisi ana ekranın (ya da bağlı olduğu alt formun) yetkisinin altında;
|
||||
`Form` sekmesinin hedefi `AllowAdding` + `AllowUpdating` açık (§4.6).
|
||||
- [ ] List ekranında en az 3 kartlık `Widgets` var (istisna değilse); kiracı tablosunda her kart
|
||||
|
|
|
|||
49
README.md
49
README.md
|
|
@ -180,7 +180,7 @@ sozsoft-platform/
|
|||
│ ├── docker/ # Yerel geliştirme için veri katmanı compose dosyaları ve scriptler
|
||||
│ ├── deployment/ # Dev/Prod compose dosyaları, nginx/redis/turn konfigürasyonu, deploy scriptleri
|
||||
│ ├── seeds/ # Runtime'da düzenlenebilen seed'ler; CDN ile aynı kapsam düzeni
|
||||
│ │ # host/{crud,custom,wizard,sql,postgres}
|
||||
│ │ # host/{crud,custom,wizard,sql,postgres,docs/modules}
|
||||
│ │ # tenants/{tenantId}/{crud,custom,wizard,sql,postgres}
|
||||
│ │ # {sql|postgres}/{object,execute}
|
||||
│ └── ai/ # AI entegrasyonu (n8n akış tanımları, Ollama model kurulum notları)
|
||||
|
|
@ -556,10 +556,16 @@ görünümleri `/admin/form/{listFormCode}/:id`, grafik `/admin/chart/{listFormC
|
|||
Var olan bir ekranı düzenlemek için `/admin/listform/edit/{listFormCode}` — tüm JSON
|
||||
yapılandırması sekmeli bir editörde yönetilir (Veritabanı, Sütunlar, Filtreler, Düzenleme,
|
||||
Yetkiler, Alt Form, Pivot, Tree, Gantt, Scheduler, Todo, Widget, Workflow, Durum, Grafik sekmeleri).
|
||||
**Sütunlar** sekmesinde alanlar sürüklenerek sıralanır (`form-fields/fieldOrder.ts`): liste görünümünde
|
||||
`ListOrderNo` bütün alanlar arasında, form görünümünde `EditOrderNo` yalnızca aynı form grubundaki alanlar
|
||||
arasında yeniden 1'den dağıtılır; grup değiştirmek Options sekmesindedir. Kültür/rol/kullanıcı kayıtları kendi
|
||||
sırasını taşır, yalnızca değeri değişen alanlar kaydedilir. **Veritabanı** sekmesindeki varsayılan değer
|
||||
satırlarında alan adı Select Command kolonlarından seçilir ve `FieldDbType` kolon tipinden dolar; liste
|
||||
kısıtlamaz — sorgu tipli kaynağın kolonları katalogdan okunamadığı için ad elle de yazılabilir.
|
||||
|
||||
**Wizard File Manager** (`/admin/listform/wizardManager`; sihirbazın kendisi `/admin/listform/wizard`) üretilmiş seed dosyalarını yönetir:
|
||||
liste/kart görünümü arasında geçiş (tercih diğer listelerle aynı yerde, `admin.lists.states`
|
||||
altında saklanır), arama, düzenleme (dosyanın yerine geçen yeni bir çalıştırma), silme, veritabanı
|
||||
altında saklanır), arama, ağacın tümünü açma/daraltma (arama sırasında gruplar zaten açıktır), düzenleme (dosyanın yerine geçen yeni bir çalıştırma), silme, veritabanı
|
||||
migrate tetikleme, dışa aktarma ve içe aktarma. Liste, wizard'ın ilk deploy damgasına
|
||||
(`Wizard.SeededAt`) göre **tersine** sıralıdır — en son üretilen ekran en üstte durur; damgası
|
||||
okunamayan dosyalar sona düşer. Silme, bağlı wizard'ı olan dosyada reddedilir; onay diyaloğu önce
|
||||
|
|
@ -938,7 +944,9 @@ KVKK açık rızası zorunlu — tabloda `CHECK`) → başvuru (aşama kanbanı)
|
|||
ağırlıklı puan) → teklif (Grid Workflow onayı, teklif mektubu `DynamicReport`). Aday kaynağı, ret
|
||||
sebebi ve değerlendirme kriteri tanımları İK › Tanımlar (`App.Hr.Definitions`) altındadır. İşe alınan adayın
|
||||
kullanıcı (personel) kaydını BT elle açar; İK aday kaydını `UserId` ile o kullanıcıya bağlar. Ayrıntı:
|
||||
`lowcode-reference.instructions.md` §12.4.
|
||||
`lowcode-reference.instructions.md` §12.4. **Performans Yönetimi** (`App.Hr.Performance`) wizard +
|
||||
custom component ile üretilmiştir: İK menüsü şartları ve takibi taşır, çalışana ait listeler menüsüzdür ve
|
||||
Intranet panosundaki widget'lardan açılır; çalışma şekli [HrPerformance.md](configs/seeds/host/docs/modules/HrPerformance.md).
|
||||
|
||||
**Yetki kodları** `PlatformConsts.AppCodes` içinde merkezî olarak tanımlıdır ve
|
||||
`configs/seeds/host/data/Abp.Identity.Permissions.json` ile seed edilir (gruplar:
|
||||
|
|
@ -1028,7 +1036,7 @@ içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppSer
|
|||
| Aktivite ve denetim kaydı | `/admin/activityLog`, `/admin/changeLog` | Kullanıcı hareketleri ve ABP audit log detayı. |
|
||||
| Bildirimler | `/admin/profile/notification-settings`, bildirim ekranları | Kanal tercihleri ve bildirim oluşturma. |
|
||||
| Forum | `/admin/forum` | Forum kullanımı; yönetim `App.ForumManagement` altındaki ListForm ekranlarıyla yapılır. |
|
||||
| Intranet | Intranet dashboard ve widget'ları | Duyuru, anket, sosyal duvar, etkinlik. Hangi widget'ın hangi kolonda, hangi sırada ve hangi yetkiyle yayınlandığı `Sas_T_IntranetWidget` kaydından gelir; kayıtlar `configs/seeds/{kapsam}/data/App.DeveloperKit.IntranetWidgets.json` ile senkron tutulur. |
|
||||
| Intranet | Intranet dashboard ve widget'ları | Duyuru, anket, sosyal duvar, etkinlik; ayrıca İK modüllerinin çalışana ait özetleri (Performans Yönetimi: Performansım, Ekibimin Performansı, 360 Taleplerim — custom component). Hangi widget'ın hangi kolonda, hangi sırada ve hangi yetkiyle yayınlandığı `Sas_T_IntranetWidget` kaydından gelir; kayıtlar `configs/seeds/{kapsam}/data/App.DeveloperKit.IntranetWidgets.json` ile senkron tutulur. |
|
||||
| Video oda | `/admin/videoroom/*` | Oda listesi, detay, planlama, katılımcı ve ekran paylaşımı. |
|
||||
| Raporlar | `/admin/reports/:report/view|design/...` | DevExpress rapor görüntüleyici ve tasarımcı. `Raporlar` kategorisindeki şablon: `/admin/reports/DynamicReport/view/{ŞablonId}[/{ListFormCode}?recordId=...]` (§15). |
|
||||
| AI asistanı | `/admin/ai` | n8n webhook üzerinden sohbet arayüzü. |
|
||||
|
|
@ -1190,6 +1198,33 @@ Get/Save uçları ve DTO'ları, `TenantData.json` + `TenantDataSeeder`,
|
|||
`App.{Home,About,Services,Contact}` yetkileri ve `.Design` alt yetkileri, `/admin/public/*/designer`
|
||||
rota ve menüleri.
|
||||
|
||||
### 10.5. Modül dokümanları (`configs/seeds/host/docs/modules/`)
|
||||
|
||||
Konfigürasyonla üretilen her modülün çalışma şekli, keşif analizi ve kararları kendi dosyasındadır;
|
||||
"bu ekran nasıl çalışıyor?" sorusunun cevabı oradadır (MCP'de `get_module_doc`). Dokümanlar seed
|
||||
klasöründedir: wizard deploy'u (ekran ya da MCP) dosyayı yoksa açar ve sonundaki "Ek — Ekran
|
||||
envanteri"ni her deploy, silme, tasarımcı kaydı ve import'ta wizard dosyalarından yeniden yazar;
|
||||
anlatım bölümlerini üreten doldurur (MCP'de `save_module_doc`). Wizard export'u dokümanı taşır.
|
||||
Yeni modül bu tabloya bir satır ekler (`lowcode.instructions.md` §0.13). Liste ekranlarının
|
||||
başlığındaki ⓘ simgesi ise ekranın kendi ayrıntılı açıklamasını gösterir (`DescTr`/`DescEn`,
|
||||
`lowcode.instructions.md` §4.4.2).
|
||||
|
||||
| Modül | Menü | Doküman |
|
||||
| --- | --- | --- |
|
||||
| Performans Yönetimi | İK › Performans Yönetimi (`App.Hr.Performance`) | [HrPerformance.md](configs/seeds/host/docs/modules/HrPerformance.md) |
|
||||
| İşe Alım | İK › İşe Alım (`App.Hr.Recruitment`) | [HrRecruitment.md](configs/seeds/host/docs/modules/HrRecruitment.md) |
|
||||
| Eğitimler | İK › Eğitimler (`App.Hr.Trainings`) | [HrTrainings.md](configs/seeds/host/docs/modules/HrTrainings.md) |
|
||||
| Araçlar | İK › Araçlar (`App.Hr.Vehicles`) | [HrVehicles.md](configs/seeds/host/docs/modules/HrVehicles.md) |
|
||||
| Disiplin Dosyaları | İK › Disiplin Dosyaları (`App.Hr.DisciplinaryCase`) | [HrDisciplinaryCase.md](configs/seeds/host/docs/modules/HrDisciplinaryCase.md) |
|
||||
| Tanımlamalar (dizin + genel tanımlar) | İK › Tanımlamalar (`App.Hr.Definitions`) | [HrDefinitions.md](configs/seeds/host/docs/modules/HrDefinitions.md) |
|
||||
| Organizasyon ve Yetkinlik | İK › Departmanlar, Pozisyonlar, Yetenek Tipleri, Organizasyon Şeması | [HrOrganization.md](configs/seeds/host/docs/modules/HrOrganization.md) |
|
||||
| Çalışma Takvimi ve Vardiyalar | İK › Çalışma Takvimi, Vardiyalar | [HrWorkCalendar.md](configs/seeds/host/docs/modules/HrWorkCalendar.md) |
|
||||
| Sağlık Kartları | İK › Sağlık Kartları (`App.Hr.HealthCard`) | [HrHealthCard.md](configs/seeds/host/docs/modules/HrHealthCard.md) |
|
||||
| Ziyaretçiler | İK › Ziyaretçiler (`App.Hr.Visitor`) | [HrVisitor.md](configs/seeds/host/docs/modules/HrVisitor.md) |
|
||||
| Olay Günlüğü | İK › Olay Günlüğü (`App.Hr.EventLog`) | [HrEventLog.md](configs/seeds/host/docs/modules/HrEventLog.md) |
|
||||
| Personel Kaydı (özlük, sözleşme, eğitim, aile, mali bilgiler) | Kimlik › Kullanıcılar › detay | [HrPersonnel.md](configs/seeds/host/docs/modules/HrPersonnel.md) |
|
||||
| Intranet (pano, duyuru, anket, sosyal duvar, etkinlik, doküman, mesajlaşma) | İK › Intranet (`App.Hr.Intranet`) | [HrIntranet.md](configs/seeds/host/docs/modules/HrIntranet.md) |
|
||||
|
||||
---
|
||||
|
||||
## 11. Kimlik, Oturum ve Güvenlik
|
||||
|
|
@ -1478,13 +1513,14 @@ liste süzgeci ve çağrı kapısı aynı kuralı kullanır.
|
|||
| `add_dev_request_subtasks` | Talebin `SubTasks` listesine tamamlanmış satırlar ekler: model yalnızca başlığı verir, atanan kişi bağlanan kullanıcının adı (`userName`), bitiş tarihi bugün (`yyyy-MM-dd`) olarak sunucuda yazılır; var olan satırlar korunur. `.Write` + `App.DevRequests.Update` ister. |
|
||||
| `append_dev_request_note` | Talebin `Analysis` kolonunun sonuna HTML ekler (üretim sonuç notu); `Description` talebin yazıldığı hâliyle kalır. İkisi de `update_row` ile yazılmaz — açıklama base64 görsel taşır. `.Write` + `App.DevRequests.Update` ister. |
|
||||
| `list_components` / `get_component` / `save_component` / `delete_component` | Custom component'ler `ICustomComponentAppService` üzerinden; seed senkronu ve `DataSources` çözümü aynen çalışır. `save_component` ada göre ekler/günceller, tasarımcı belgesi (`Props.visualDesigner`, `sourceMode ≠ code`) taşıyan bileşene kod yazmayı reddeder — kod belgeden üretildiği için tasarımcıdaki ilk kayıtta ezilirdi. |
|
||||
| `get_module_doc` / `save_module_doc` | Modül dokümanı (`configs/seeds/{kapsam}/docs/modules/{Modül}.md`, `IModuleDocAppService`). Ad yerine ekran kodu ya da wizard dosya adı verilebilir. `save_module_doc` elle yazılan bölümleri kaydeder, "Ek — Ekran envanteri"ni sunucu üretir. Talebi `update_row` ile `Testing`'e almak, talebin wizard'larının dokümanı tamamlanmadan (dosya var, `module-doc:todo` kalmamış) reddedilir. Okuma `App.Listforms.Wizard`, yazma ayrıca `Wizards.Update` ister. |
|
||||
| `list_report_templates` / `get_report_template` / `save_report_category` / `save_report_template` / `delete_report_template` | Rapor kategorileri ve `DynamicReport` şablonları (`McpReportAppService`). Okuma depodan, ekranın okuma yetkisiyle yapılır. Yazma `App.Reports.Categories` / `App.Reports.ReportTemplates` ekranlarının C/U/D sözleşmesinden (`IListFormDataAppService`) geçer; seed senkronu aynen çalışır. Kayıt ada göre ekler/günceller. `listFormCode` verilirse HTML'deki `{{AlanAdi}}` yer tutucuları o ekranın alanlarına göre doğrulanır ve cevapta satır butonu (`rowButton`) döner (§15). |
|
||||
|
||||
**Timesheets.** Talebin `Timesheets` listesini sunucu doldurur (`IMcpDevRequestTimesheetRecorder`):
|
||||
`get_dev_request` / `start_dev_request` talebi kullanıcının etkin talebi yapar (dağıtık önbellek,
|
||||
`McpDevRequestActivityCacheItem`, 12 saat); sonraki her MCP yazma işlemi (`create_table`,
|
||||
`deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `save_report_category`,
|
||||
`save_report_template`, `delete_report_template`, satır araçları,
|
||||
`save_report_template`, `delete_report_template`, `save_module_doc`, satır araçları,
|
||||
`save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks`) o talebe bir satır
|
||||
ekler; talebi açan `start_dev_request` yazmaz. Açıklama `App.Mcp.Timesheet.*` anahtarından
|
||||
Türkçe üretilir, süre önceki satırdan ya da talebin açıldığı andan ölçülür (en az 1 dakika, saat
|
||||
|
|
@ -1541,7 +1577,7 @@ yetkisi yalnızca kapıdır. Bir çağrı üç katmandan geçer ve her katman ay
|
|||
| --- | --- | --- | --- |
|
||||
| `App.DeveloperKit.McpServers` | Host, kiracı | MCP Servers ekranını görme (`.Create/.Update/.Delete/.Export/.Import` ekran işlemleri) | `/mcp` ucuna erişim vermez |
|
||||
| `App.DeveloperKit.McpServers.Invoke` | Host, kiracı | `/mcp` bağlantısı ve bütün okuma araçları: `server_info`, `list_lists`, `describe_list`, `search_schema`, `query_list`; host'ta ayrıca `get_dev_guide`, `list_wizards`, `get_wizard`, `verify_wizard`, `get_dev_request`, `list_components`, `get_component` | Hiçbir şey yazmaz. Okuma da ekran yetkisine bağlıdır: `R` yetkisi olmayan liste görünmez, sorgulanamaz. Ham SQL (`run_select`, `list_queries`, `run_query`) ayrıca `App.SqlQueryManager` ister |
|
||||
| `App.DeveloperKit.McpServers.Write` | Host, kiracı | MCP üzerinden her değişiklik. **Kiracıda:** `insert_row`, `update_row`, `delete_row`. **Host'ta:** bunlara ek olarak `create_table`, `deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `save_report_category`, `save_report_template`, `delete_report_template`, `start_dev_request`, `save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks` | Kendi başına bir şey yazdırmaz: satır araçları ekranın `C`/`U`/`D` yetkisini, geliştirme araçları Wizard / Custom Components / SQL Query Manager / `App.DevRequests.Update` yetkisini ayrıca ister. Kiracıda geliştirme araçlarını **açmaz** — kiracı bağlamında bu araçlar yetkiden bağımsız kapalıdır (`McpToolNames.TenantTools`). `Invoke` olmadan işe yaramaz |
|
||||
| `App.DeveloperKit.McpServers.Write` | Host, kiracı | MCP üzerinden her değişiklik. **Kiracıda:** `insert_row`, `update_row`, `delete_row`. **Host'ta:** bunlara ek olarak `create_table`, `deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `save_report_category`, `save_report_template`, `delete_report_template`, `save_module_doc`, `start_dev_request`, `save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks` | Kendi başına bir şey yazdırmaz: satır araçları ekranın `C`/`U`/`D` yetkisini, geliştirme araçları Wizard / Custom Components / SQL Query Manager / `App.DevRequests.Update` yetkisini ayrıca ister. Kiracıda geliştirme araçlarını **açmaz** — kiracı bağlamında bu araçlar yetkiden bağımsız kapalıdır (`McpToolNames.TenantTools`). `Invoke` olmadan işe yaramaz |
|
||||
|
||||
**Araç → gereken yetkiler** (Invoke hepsinde aranır, tabloda tekrar yazılmadı)
|
||||
|
||||
|
|
@ -2050,6 +2086,7 @@ configs/seeds/
|
|||
│ │ # App.Hr.{Department,JobPosition}.json — İK departman → pozisyon (BranchId ile şubeye bağlı)
|
||||
│ │ # App.Hr.Intranet.*.json — İK › Intranet (duyuru, anket, sosyal akış, etkinlik)
|
||||
│ │ # App.Hr.{CandidateSource,RejectionReason,EvaluationCriterion}.json — İK › Tanımlar altındaki işe alım tanımları
|
||||
│ │ # App.Hr.PerformanceRating.json — İK › Tanımlar › Performans Dereceleri (5 kademeli ölçek)
|
||||
│ │ # App.Notifications.Notification{Templates,Types,Rules}.json — bildirim şablonu, tipi → kuralı
|
||||
│ │ # App.Languages.{Language,LanguageText}.json — dil → metin (eksik LanguageKey metinle üretilir)
|
||||
│ │ # App.SettingDefinitions.json, App.BackgroundWorkers.RecurringJobs.json — ayar tanımları, zamanlanmış işler
|
||||
|
|
|
|||
|
|
@ -55,6 +55,14 @@ public interface IMcpDevelopAppService : IApplicationService
|
|||
/// </summary>
|
||||
Task AddDevRequestSubTasksAsync(string request, List<string> titles);
|
||||
|
||||
/// <summary>Modul dokumanini adiyla ya da ait oldugu ekranin kodu/wizard dosyasiyla okur.</summary>
|
||||
Task<ModuleDocDto> GetModuleDocAsync(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Modul dokumaninin elle yazilan bolumlerini kaydeder; otomatik envanter sunucuda yeniden
|
||||
/// uretilir.
|
||||
/// </summary>
|
||||
Task<ModuleDocDto> SaveModuleDocAsync(string name, string content);
|
||||
|
||||
Task<List<McpComponentSummaryDto>> GetComponentsAsync(string? search);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -7,6 +8,7 @@ using Sozsoft.Mcp.Dtos;
|
|||
using Sozsoft.Mcp.Services;
|
||||
using Sozsoft.Platform;
|
||||
using Sozsoft.Platform.Enums;
|
||||
using Sozsoft.Platform.ListForms;
|
||||
using Sozsoft.Platform.ListForms.Select;
|
||||
using Volo.Abp;
|
||||
|
||||
|
|
@ -22,9 +24,13 @@ public class McpDataAppService(
|
|||
IMcpServerConfigProvider serverConfigProvider,
|
||||
IListFormDataAppService listFormDataAppService,
|
||||
IMcpListFormAccessFilter accessFilter,
|
||||
IMcpDevRequestTimesheetRecorder timesheetRecorder)
|
||||
IMcpDevRequestTimesheetRecorder timesheetRecorder,
|
||||
IModuleDocAppService moduleDocAppService)
|
||||
: McpAppService(serverConfigProvider), IMcpDataAppService
|
||||
{
|
||||
private const string DevRequestStatusField = "Status";
|
||||
private const string DevRequestTestingStatus = "Testing";
|
||||
|
||||
public async Task<McpWriteResultDto> InsertRowAsync(McpRowRequestDto input)
|
||||
{
|
||||
var request = await BuildRequestAsync(input, McpToolNames.InsertRow, AuthorizationTypeEnum.Create, requireKeys: false, requireValues: true);
|
||||
|
|
@ -37,6 +43,7 @@ public class McpDataAppService(
|
|||
public async Task<McpWriteResultDto> UpdateRowAsync(McpRowRequestDto input)
|
||||
{
|
||||
var request = await BuildRequestAsync(input, McpToolNames.UpdateRow, AuthorizationTypeEnum.Update, requireKeys: true, requireValues: true);
|
||||
await EnsureModuleDocsBeforeTestingAsync(input);
|
||||
var affected = await listFormDataAppService.PostUpdateAsync(request);
|
||||
await timesheetRecorder.RecordAsync(McpTimesheetTexts.UpdateRow, input.ListFormCode, string.Join(", ", input.Values.Keys));
|
||||
|
||||
|
|
@ -52,6 +59,39 @@ public class McpDataAppService(
|
|||
return new McpWriteResultDto { AffectedRows = affected };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gelistirme talebi Testing'e alinirken talebin urettigi wizard'larin modul dokumanlari tamam
|
||||
/// olmalidir (lowcode §0.13): dosya var ve doldurulmamis (<c>module-doc:todo</c>) bolum yok.
|
||||
/// Talebi Testing'e alan tek yol <c>update_row</c> oldugu icin kural burada uygulanir. Wizard
|
||||
/// okuma yetkisi olmayan kullanici wizard uretemeyecegi icin kontrol ona uygulanmaz.
|
||||
/// </summary>
|
||||
private async Task EnsureModuleDocsBeforeTestingAsync(McpRowRequestDto input)
|
||||
{
|
||||
if (!string.Equals(input.ListFormCode, PlatformConsts.AppCodes.DevRequests, StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
|
||||
var status = input.Values?.FirstOrDefault(v => string.Equals(v.Key, DevRequestStatusField, StringComparison.OrdinalIgnoreCase)).Value?.ToString();
|
||||
if (!string.Equals(status, DevRequestTestingStatus, StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
|
||||
if (!await AuthorizationService.IsGrantedAsync(PlatformConsts.AppCodes.Listforms.Wizard))
|
||||
return;
|
||||
|
||||
foreach (var key in input.Keys ?? [])
|
||||
{
|
||||
if (!Guid.TryParse(key?.ToString(), out var devRequestId))
|
||||
continue;
|
||||
|
||||
var incomplete = await moduleDocAppService.GetIncompleteForDevRequestAsync(devRequestId);
|
||||
if (incomplete.Count == 0)
|
||||
continue;
|
||||
|
||||
var detail = string.Join("; ", incomplete.Select(doc => $"{doc.Path} ({string.Join(", ", doc.MissingSections)})"));
|
||||
|
||||
throw new UserFriendlyException(L[McpErrorCodes.DevRequestModuleDocsIncomplete, detail]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Istegi ekranin bekledigi bicime cevirir. <c>Data</c> JSON metni olarak verilir; ayni
|
||||
/// bicim ekranin kopyalama yolunda da kullanilir.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ public class McpDevelopAppService(
|
|||
IRepository<PermissionDefinitionRecord, Guid> permissionRepository,
|
||||
IRepository<DevRequest, Guid> devRequestRepository,
|
||||
IMcpDevRequestTimesheetRecorder timesheetRecorder,
|
||||
IModuleDocAppService moduleDocAppService,
|
||||
IConfiguration configuration)
|
||||
: McpAppService(serverConfigProvider), IMcpDevelopAppService
|
||||
{
|
||||
|
|
@ -59,6 +60,10 @@ public class McpDevelopAppService(
|
|||
|
||||
private const string DevRequestUpdatePermission = PlatformConsts.AppCodes.DevRequests + ".Update";
|
||||
|
||||
/// <summary>Liste ekrani aciklamasinin (DescTr/DescEn) en az satir ve karakter sayisi.</summary>
|
||||
private const int MinDescriptionLines = 3;
|
||||
private const int MinDescriptionLength = 150;
|
||||
|
||||
/// <summary>Talep ekranindaki alt gorev tarih kutusunun okudugu bicim.</summary>
|
||||
private const string SubTaskDateFormat = "yyyy-MM-dd";
|
||||
|
||||
|
|
@ -207,6 +212,7 @@ public class McpDevelopAppService(
|
|||
|
||||
var wizard = ParseWizard(input.Wizard);
|
||||
wizard.EditFileName = string.IsNullOrWhiteSpace(input.ReplaceFileName) ? null : input.ReplaceFileName.Trim();
|
||||
EnsureDetailedDescription(wizard);
|
||||
|
||||
// Menu sirasi modelin karari degildir: yeni ekran kardeslerinin sonuna eklenir (deploy
|
||||
// bagimlilik sirasiyla yapildigi icin lookup kaynagi tuketen ekranin ustunde kalir),
|
||||
|
|
@ -252,6 +258,26 @@ public class McpDevelopAppService(
|
|||
return file;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Liste ekraninin aciklamasi basliktaki bilgi simgesinde (ⓘ) gosterilir ve ekranin kullanim
|
||||
/// kilavuzudur: ne ise yaradigi, menude/hangi ekranin sekmesinde durdugu, ana alanlari, otomatik
|
||||
/// hesaplar ve iliskili ekranlar (lowcode §4.4.2). Tek satirlik aciklama bu ihtiyaci karsilamadigi
|
||||
/// icin MCP deploy'u kisa aciklamayi reddeder.
|
||||
/// </summary>
|
||||
private void EnsureDetailedDescription(ListFormWizardDto wizard)
|
||||
{
|
||||
if (wizard.ComponentKind == WizardComponentKindEnum.Custom)
|
||||
return;
|
||||
|
||||
static bool IsDetailed(string? text) =>
|
||||
!string.IsNullOrWhiteSpace(text) &&
|
||||
text.Trim().Length >= MinDescriptionLength &&
|
||||
text.Split('\n').Count(line => !string.IsNullOrWhiteSpace(line)) >= MinDescriptionLines;
|
||||
|
||||
if (!IsDetailed(wizard.DescTr) || !IsDetailed(wizard.DescEn))
|
||||
throw new UserFriendlyException(L[McpErrorCodes.WizardDescriptionTooShort, MinDescriptionLines, MinDescriptionLength]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demo satirlarini okur ve ekranin alanlarina gore dogrular. Satirlar yalnizca SeedData acik
|
||||
/// liste ekraninda kabul edilir: migrate onlari ekranin veri dosyasindan ekler.
|
||||
|
|
@ -562,6 +588,22 @@ public class McpDevelopAppService(
|
|||
await timesheetRecorder.RecordAsync(McpTimesheetTexts.AddSubTasks, items.Count);
|
||||
}
|
||||
|
||||
public async Task<ModuleDocDto> GetModuleDocAsync(string name)
|
||||
{
|
||||
await EnsureToolAllowedAsync(McpToolNames.GetModuleDoc);
|
||||
return await moduleDocAppService.GetAsync(name);
|
||||
}
|
||||
|
||||
public async Task<ModuleDocDto> SaveModuleDocAsync(string name, string content)
|
||||
{
|
||||
await EnsureToolAllowedAsync(McpToolNames.SaveModuleDoc);
|
||||
|
||||
var doc = await moduleDocAppService.SaveAsync(new ModuleDocSaveInput { Name = name, Content = content });
|
||||
await timesheetRecorder.RecordAsync(McpTimesheetTexts.SaveModuleDoc, doc.Name);
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
private static McpDevRequestDto ToDto(DevRequest devRequest)
|
||||
{
|
||||
var (description, images) = McpDevRequestImages.Extract(devRequest.Description);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ public static class McpErrorCodes
|
|||
public const string DevRequestNoteRequired = Prefix + "DevRequestNoteRequired";
|
||||
public const string DevRequestSubTasksRequired = Prefix + "DevRequestSubTasksRequired";
|
||||
public const string DevRequestSubTasksInvalid = Prefix + "DevRequestSubTasksInvalid";
|
||||
public const string DevRequestModuleDocsIncomplete = Prefix + "DevRequestModuleDocsIncomplete";
|
||||
public const string WizardDescriptionTooShort = Prefix + "WizardDescriptionTooShort";
|
||||
public const string VisualDesignerComponent = Prefix + "VisualDesignerComponent";
|
||||
public const string ReportNameRequired = Prefix + "ReportNameRequired";
|
||||
public const string ReportHtmlRequired = Prefix + "ReportHtmlRequired";
|
||||
|
|
|
|||
|
|
@ -22,4 +22,5 @@ public static class McpTimesheetTexts
|
|||
public const string InsertRow = Prefix + "InsertRow";
|
||||
public const string UpdateRow = Prefix + "UpdateRow";
|
||||
public const string DeleteRow = Prefix + "DeleteRow";
|
||||
public const string SaveModuleDoc = Prefix + "SaveModuleDoc";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ public static class McpToolNames
|
|||
public const string SaveReportCategory = "save_report_category";
|
||||
public const string SaveReportTemplate = "save_report_template";
|
||||
public const string DeleteReportTemplate = "delete_report_template";
|
||||
public const string GetModuleDoc = "get_module_doc";
|
||||
public const string SaveModuleDoc = "save_module_doc";
|
||||
|
||||
/// <summary>
|
||||
/// Ekran, bilesen ve rapor sablonu gelistirme araclari; kiraci baglaminda hicbiri acilmaz. Okuyanlar
|
||||
|
|
@ -71,7 +73,9 @@ public static class McpToolNames
|
|||
GetReportTemplate,
|
||||
SaveReportCategory,
|
||||
SaveReportTemplate,
|
||||
DeleteReportTemplate
|
||||
DeleteReportTemplate,
|
||||
GetModuleDoc,
|
||||
SaveModuleDoc
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -126,6 +130,7 @@ public static class McpToolNames
|
|||
[SaveReportCategory] = PlatformConsts.AppCodes.DeveloperKits.McpServers.Write,
|
||||
[SaveReportTemplate] = PlatformConsts.AppCodes.DeveloperKits.McpServers.Write,
|
||||
[DeleteReportTemplate] = PlatformConsts.AppCodes.DeveloperKits.McpServers.Write,
|
||||
[SaveModuleDoc] = PlatformConsts.AppCodes.DeveloperKits.McpServers.Write,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -142,6 +147,8 @@ public static class McpToolNames
|
|||
[VerifyWizard] = [PlatformConsts.AppCodes.Listforms.Wizard],
|
||||
[DeployWizard] = [PlatformConsts.AppCodes.Listforms.Wizard],
|
||||
[DeleteWizard] = [PlatformConsts.AppCodes.Listforms.Wizard, PlatformConsts.AppCodes.Listforms.Wizards.Delete, PlatformConsts.AppCodes.SqlQueryManagers.Default],
|
||||
[GetModuleDoc] = [PlatformConsts.AppCodes.Listforms.Wizard],
|
||||
[SaveModuleDoc] = [PlatformConsts.AppCodes.Listforms.Wizard, PlatformConsts.AppCodes.Listforms.Wizards.Update],
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ internal static class McpServerInfoDefaults
|
|||
"write the analysis with save_dev_request_analysis, produce nothing and never touch Description; the user moves an approved analysis to Ready to Start. " +
|
||||
"Development requests (App.DevRequests) follow get_dev_guide section 0.11: claim each one with " +
|
||||
"start_dev_request, which only accepts requests in Ready to Start; images pasted into the request arrive as image content and are part of the request (layout and demo rows). " +
|
||||
"A request (Description) and its approved Analysis are its own brief: do not ask questions and do not wait for DB Migrate; deploy (demo rows go in deploy_wizard seedRows), move the request to Testing and finish. " +
|
||||
"A request (Description) and its approved Analysis are its own brief: do not ask questions and do not wait for DB Migrate; deploy (demo rows go in deploy_wizard seedRows), complete the module document with get_module_doc / save_module_doc (section 0.13), then move the request to Testing and finish. " +
|
||||
"When a tool reports a missing permission, tell the user which permission is missing and stop; " +
|
||||
"do not try to reach the same result through another tool.";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ public static class McpDevelopPrompts
|
|||
"Once get_dev_guide ile lowcode 0.11 bolumunu oku ve oradaki adimlari uygula. " +
|
||||
"Talebi start_dev_request ile ustlen. Arac reddederse (talep Ready to Start degil, bulunamadi ya da " +
|
||||
"birden fazla eslesme var) hicbir sey uretme, baska bir talebe gecme: nedenini bildir ve dur. " +
|
||||
"Talep (Description) ve onaylanmis analizi (Analysis) birlikte tarifin kendisidir: soru sorma, DB Migrate'i bekleme; talebi Testing'e alip bitir. " +
|
||||
"Talep (Description) ve onaylanmis analizi (Analysis) birlikte tarifin kendisidir: soru sorma, DB Migrate'i bekleme. " +
|
||||
"Testing'e almadan once uretilen modulun dokumanini get_module_doc ile oku, todo bolumlerini save_module_doc ile doldur (lowcode 0.13); sonra talebi Testing'e alip bitir. " +
|
||||
"Sonunda rapor ver: uretilen artefaktlar, talebin son durumu ve DB Migrate gerektigi.";
|
||||
|
||||
[McpServerPrompt(Name = McpPromptNames.ProcessReadyRequests)]
|
||||
|
|
@ -51,6 +52,7 @@ public static class McpDevelopPrompts
|
|||
=> "App.DevRequests kuyrugundaki Ready to Start taleplerini query_list ile SortOrder sirasiyla oku ve tek tek isle. " +
|
||||
"Once get_dev_guide ile lowcode 0.11 bolumunu oku ve oradaki adimlari uygula. " +
|
||||
"Her talebi start_dev_request ile ustlen; reddedilen talebi atla ve rapora yaz. " +
|
||||
"Talep (Description) ve onaylanmis analizi (Analysis) birlikte tarifin kendisidir: soru sorma, DB Migrate'i bekleme; her talebi Testing'e alip digerine gec. " +
|
||||
"Talep (Description) ve onaylanmis analizi (Analysis) birlikte tarifin kendisidir: soru sorma, DB Migrate'i bekleme. " +
|
||||
"Her talepte Testing'e almadan once modul dokumanini save_module_doc ile doldur (lowcode 0.13), sonra talebi Testing'e alip digerine gec. " +
|
||||
"Sonunda parti raporu ver: talep basina uretilen artefaktlar ve son durum; DB Migrate gerektigini tek satirda belirt.";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService)
|
|||
=> await developAppService.GetWizardAsync(fileName);
|
||||
|
||||
[McpServerTool(Name = McpToolNames.DeployWizard, Destructive = true, Idempotent = false)]
|
||||
[Description("Wizard'i deploy eder: ListForm ekrani (ComponentKind 0) ya da bir custom component'i menuye baglayan kayit (ComponentKind 1), yetkileri, dil anahtarlari ve menusu seed dosyalarina yazilir. Deploy veritabanina yazmaz: ekran, menu ve yetkiler kullanici Wizard Manager'da DB Migrate calistirinca olusur; cikistaki isPending true iken ekran henuz yoktur; migrate'i bekleme, isini bitir ve kullaniciya yalnizca DB Migrate calistirmasini soyle. Eksik modul, ust menu, izin grubu, yetki ve dil satirlari da deploy'da dosyalara yazilir ve migrate onlari dogru sirayla ekler; bunlarin veritabaninda olmamasi beklenen durumdur, uyari olarak raporlama ve kullanicidan elle eklemesini isteme. Ust menu zinciri istenen derinlikte kurulur: MenuParentCode ekranin dogrudan ust menusu, Menu.MenuParentPath onun ustundeki seviyeler (kokten asagi, her biri {Code, Icon, En, Tr}); eksik her seviye bir ustunun altina kurulur, var olana baglanilir. Liste ekraninda Grid, Card, Pivot ve Chart gorunumleri varsayilan aciktir (DefaultLayout grid); kullanici bir gorunumu istemedigini soylemedikce bu bayraklari false yazma. Hedef tablo onceden var olmalidir; yoksa once create_table ile olustur. Istek ornek/demo veri tasiyorsa (prompt'taki tablo/liste ya da ekran goruntusunde gorunen satirlar) SeedData true yaz ve satirlarin hepsini ayni cagrida seedRows ile gonder: satirlar ekranin data/{ListFormCode}.json dosyasina yazilir, migrate ekrani kurduktan sonra ekler. Satirlar icin migrate'i bekleyip insert_row kullanma. replaceFileName verilirse o wizard'in dosyalari yeniden yazilir, onceki kayitlarin yerini migrate'te yenileri alir; ekran wizard cevaplarindan yeniden turetildigi icin tasarimcida yapilmis ve wizard'da karsiligi olmayan ayarlar kaybolur. Ne yazacagini get_dev_guide 4. bolumunden ogren.")]
|
||||
[Description("Wizard'i deploy eder: ListForm ekrani (ComponentKind 0) ya da bir custom component'i menuye baglayan kayit (ComponentKind 1), yetkileri, dil anahtarlari ve menusu seed dosyalarina yazilir. Deploy veritabanina yazmaz: ekran, menu ve yetkiler kullanici Wizard Manager'da DB Migrate calistirinca olusur; cikistaki isPending true iken ekran henuz yoktur; migrate'i bekleme, isini bitir ve kullaniciya yalnizca DB Migrate calistirmasini soyle. Eksik modul, ust menu, izin grubu, yetki ve dil satirlari da deploy'da dosyalara yazilir ve migrate onlari dogru sirayla ekler; bunlarin veritabaninda olmamasi beklenen durumdur, uyari olarak raporlama ve kullanicidan elle eklemesini isteme. Ust menu zinciri istenen derinlikte kurulur: MenuParentCode ekranin dogrudan ust menusu, Menu.MenuParentPath onun ustundeki seviyeler (kokten asagi, her biri {Code, Icon, En, Tr}); eksik her seviye bir ustunun altina kurulur, var olana baglanilir. Liste ekraninda Grid, Card, Pivot ve Chart gorunumleri varsayilan aciktir (DefaultLayout grid); kullanici bir gorunumu istemedigini soylemedikce bu bayraklari false yazma. Hedef tablo onceden var olmalidir; yoksa once create_table ile olustur. Istek ornek/demo veri tasiyorsa (prompt'taki tablo/liste ya da ekran goruntusunde gorunen satirlar) SeedData true yaz ve satirlarin hepsini ayni cagrida seedRows ile gonder: satirlar ekranin data/{ListFormCode}.json dosyasina yazilir, migrate ekrani kurduktan sonra ekler. Satirlar icin migrate'i bekleyip insert_row kullanma. replaceFileName verilirse o wizard'in dosyalari yeniden yazilir, onceki kayitlarin yerini migrate'te yenileri alir; ekran wizard cevaplarindan yeniden turetildigi icin tasarimcida yapilmis ve wizard'da karsiligi olmayan ayarlar kaybolur. Liste ekraninda DescTr ve DescEn ayrintili olmali (en az 3 satir, 150 karakter): ekran basligindaki bilgi simgesinde gosterilir; ne ise yaradigi, menude nerede ya da hangi ekranin sekmesi oldugu, ana alanlar, otomatik hesaplar ve iliskili ekranlar yazilir (get_dev_guide 4.4.2); kisa aciklama reddedilir. Deploy modulun dokumanini (docs/modules) acar ya da envanterini yeniler; elle yazilan bolumleri save_module_doc ile doldur. Ne yazacagini get_dev_guide 4. bolumunden ogren.")]
|
||||
public async Task<WizardFileInfoDto?> DeployWizardAsync(
|
||||
[Description("Wizard JSON'u: seed dosyasi bicimi ({\"Wizard\": {...}}, get_wizard cikisi gibi) ya da duz wizard cevaplari. Enum alanlari sayi olarak yazilir.")]
|
||||
string wizard,
|
||||
|
|
@ -138,6 +138,22 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService)
|
|||
}
|
||||
|
||||
|
||||
[McpServerTool(Name = McpToolNames.GetModuleDoc, ReadOnly = true)]
|
||||
[Description("Modul dokumanini (docs/modules/{Modul}.md, seed klasoru) okur: nasil calistigi, analiz/kararlar, ekranlar, hesaplar, yetkiler ve otomatik 'Ek — Ekran envanteri'. isComplete false ise missingSections doldurulmamis bolumlerdir. 'Bu modul/ekran nasil calisiyor?' sorusunda once bunu oku. Ad yerine ekranin kodu (App.Hr.PerformanceReview) ya da wizard dosya adi da verilebilir; deploy_wizard dokumani yoksa iskeletini kendisi acar.")]
|
||||
public async Task<ModuleDocDto> GetModuleDocAsync(
|
||||
[Description("Dokuman adi (HrPerformance), ekran kodu ya da wizard dosya adi.")]
|
||||
string name)
|
||||
=> await developAppService.GetModuleDocAsync(name);
|
||||
|
||||
[McpServerTool(Name = McpToolNames.SaveModuleDoc, Destructive = true, Idempotent = true)]
|
||||
[Description("Modul dokumaninin elle yazilan bolumlerini kaydeder (Markdown, dosyanin tamami). Uretimin parcasidir: deploy_wizard'dan sonra once get_module_doc ile iskeleti oku, module-doc:todo isaretli her bolumu (Amac ve kapsam, Analiz ve kararlar — onaylanmis analiz ve kararlar, Menu ve ekranlar, Veri modeli, Is kurallari ve hesaplar, Yetki ve gorunurluk, Entegrasyonlar, Akis ornegi, Sik sorulanlar, Dosyalar ve geri alma) doldurup isaretleri kaldirarak gonder; bos kalacak bolume 'Yok.' yaz. 'Ek — Ekran envanteri' bolumunu gonderme, sunucu uretir. Ilk satirdaki '<!-- module-doc: claims=... -->' beyanini koru. Talep, dokumanlari tamamlanmadan update_row ile Testing'e alinamaz. Bolum standardi get_dev_guide lowcode 0.13.")]
|
||||
public async Task<ModuleDocDto> SaveModuleDocAsync(
|
||||
[Description("Dokuman adi (HrPerformance), ekran kodu ya da wizard dosya adi.")]
|
||||
string name,
|
||||
[Description("Dokumanin tamami, Markdown.")]
|
||||
string content)
|
||||
=> await developAppService.SaveModuleDocAsync(name, content);
|
||||
|
||||
/// <summary>
|
||||
/// Talep metni JSON olarak, gorseller ayri resim icerigi olarak doner; model resmi ancak bu
|
||||
/// bicimde gorur, base64 metni olarak goremez.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace Sozsoft.Platform.ListForms;
|
||||
|
||||
/// <summary>
|
||||
/// Modul dokumanlari (<c>docs/modules/{Modul}.md</c>, kapsam seed klasoru). Dokumanin elle ya da
|
||||
/// AI ile yazilan bolumleri kaydedilir; "Ek — Ekran envanteri" bolumu wizard dosyalarindan uretilir
|
||||
/// ve her deploy, silme, tasarimci kaydi ve import'ta yenilenir.
|
||||
/// </summary>
|
||||
public interface IModuleDocAppService : IApplicationService
|
||||
{
|
||||
/// <summary>Kapsamdaki butun modul dokumanlari ve bagli wizard'lari.</summary>
|
||||
Task<List<ModuleDocDto>> GetListAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Dokumani adiyla (<c>HrPerformance</c>) ya da ait oldugu ekranin kodu/wizard dosya adiyla
|
||||
/// (<c>App.Hr.PerformanceReview</c>, <c>PerformanceReview.json</c>) dondurur.
|
||||
/// </summary>
|
||||
Task<ModuleDocDto> GetAsync(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Dokumanin elle yazilan bolumlerini kaydeder; otomatik envanter bolumu girdiden atilir ve
|
||||
/// yeniden uretilir.
|
||||
/// </summary>
|
||||
Task<ModuleDocDto> SaveAsync(ModuleDocSaveInput input);
|
||||
|
||||
/// <summary>
|
||||
/// Talebe bagli wizard'larin dokumanlarindan eksik olanlar (dosya yok ya da doldurulmamis
|
||||
/// bolum var). Bos liste talebin dokumantasyonunun tamam oldugunu gosterir.
|
||||
/// </summary>
|
||||
Task<List<ModuleDocDto>> GetIncompleteForDevRequestAsync(Guid devRequestId);
|
||||
}
|
||||
|
||||
public class ModuleDocDto
|
||||
{
|
||||
/// <summary>Dosya adi, uzantisiz (<c>HrPerformance</c>).</summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Kapsam klasorune gore goreli yol (<c>docs/modules/HrPerformance.md</c>).</summary>
|
||||
public string Path { get; set; } = string.Empty;
|
||||
|
||||
public bool Exists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dosyada doldurulmamis bolum yoksa true. Otomatik acilan iskeletin bolumleri
|
||||
/// <c>module-doc:todo</c> isaretini tasir; isaret kalmayinca dokuman tamam sayilir.
|
||||
/// </summary>
|
||||
public bool IsComplete { get; set; }
|
||||
|
||||
/// <summary>Doldurulmamis bolum basliklari.</summary>
|
||||
public List<string> MissingSections { get; set; } = [];
|
||||
|
||||
/// <summary>Dokumana bagli ekran kodlari (wizard'larin ListFormCode / menu kodu).</summary>
|
||||
public List<string> Wizards { get; set; } = [];
|
||||
|
||||
/// <summary>Dosyanin tamami; listede doldurulmaz.</summary>
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
|
||||
public class ModuleDocSaveInput
|
||||
{
|
||||
/// <summary>Dokuman adi ya da ait oldugu ekranin kodu/wizard dosya adi.</summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Markdown. Otomatik envanter bolumu varsa yok sayilir.</summary>
|
||||
public string Content { get; set; } = string.Empty;
|
||||
}
|
||||
|
|
@ -58,6 +58,7 @@ public class ListFormWizardAppService(
|
|||
WizardRecordCleaner recordCleaner,
|
||||
WizardTableCleaner tableCleaner,
|
||||
WizardInstallationChecker installationChecker,
|
||||
ModuleDocManager moduleDocManager,
|
||||
ILogger<ListFormWizardAppService> logger
|
||||
) : PlatformAppService(), IListFormWizardAppService
|
||||
{
|
||||
|
|
@ -78,6 +79,7 @@ public class ListFormWizardAppService(
|
|||
private readonly WizardRecordCleaner _recordCleaner = recordCleaner;
|
||||
private readonly WizardTableCleaner _tableCleaner = tableCleaner;
|
||||
private readonly WizardInstallationChecker _installationChecker = installationChecker;
|
||||
private readonly ModuleDocManager _moduleDocManager = moduleDocManager;
|
||||
private readonly ILogger<ListFormWizardAppService> logger = logger;
|
||||
private readonly string cultureNameDefault = PlatformConsts.DefaultLanguage;
|
||||
|
||||
|
|
@ -138,6 +140,10 @@ public class ListFormWizardAppService(
|
|||
var devRequest = await ResolveDevRequestAsync(input.DevRequestId, previous);
|
||||
|
||||
await DeployWizardAsync(input, previous, editFileName, rows, devRequest);
|
||||
|
||||
// Modulun dokumani (docs/modules) deploy'un parcasidir: yoksa iskelet acilir, envanter
|
||||
// her deploy'da wizard dosyalarindan yeniden yazilir (lowcode §0.13).
|
||||
await _moduleDocManager.RefreshAllAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -1352,6 +1358,8 @@ public class ListFormWizardAppService(
|
|||
if (!isPending)
|
||||
await _languageTextAppService.ClearRedisCacheAsync();
|
||||
|
||||
await _moduleDocManager.RefreshAllAsync();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1757,6 +1765,7 @@ public class ListFormWizardAppService(
|
|||
SeedPathResolver.DataFolder,
|
||||
SeedPathResolver.SqlFolder,
|
||||
SeedPathResolver.PostgresFolder,
|
||||
SeedPathResolver.DocsFolder,
|
||||
];
|
||||
|
||||
/// <summary>SQL saglayici klasorlerinin altinda izin verilen script klasorleri.</summary>
|
||||
|
|
@ -2293,6 +2302,10 @@ public class ListFormWizardAppService(
|
|||
foreach (var relativePath in wizardFiles)
|
||||
result.AppliedWizards.Add(await MarkImportedWizardPendingAsync(scopeRoot, relativePath));
|
||||
|
||||
// Arsivle gelen dokumanin envanteri kaynak ortamin wizard'larini anlatir; hedefteki
|
||||
// wizard'lara gore yeniden yazilir.
|
||||
await _moduleDocManager.RefreshAllAsync();
|
||||
|
||||
DeleteImportSession(sessionPath);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -2735,8 +2748,16 @@ public class ListFormWizardAppService(
|
|||
|
||||
var isDataFolder = segments[0].Equals(SeedPathResolver.DataFolder, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var isDocsFolder = segments[0].Equals(SeedPathResolver.DocsFolder, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// sql/postgres altinda object|execute klasoru zorunludur; digerlerinde alt klasor yoktur.
|
||||
if (isScriptFolder)
|
||||
if (isDocsFolder)
|
||||
{
|
||||
// Yalnizca modul dokumanlari: docs/modules/{Modul}.md.
|
||||
if (segments.Length != 3 || !segments[1].Equals(SeedPathResolver.ModuleDocsFolder, StringComparison.OrdinalIgnoreCase))
|
||||
return null;
|
||||
}
|
||||
else if (isScriptFolder)
|
||||
{
|
||||
if (segments.Length != 3 || !ImportAllowedScriptFolders.Contains(segments[1], StringComparer.OrdinalIgnoreCase))
|
||||
return null;
|
||||
|
|
@ -2758,7 +2779,7 @@ public class ListFormWizardAppService(
|
|||
|
||||
var fileName = segments[^1];
|
||||
var extension = Path.GetExtension(fileName);
|
||||
var expectedExtension = isScriptFolder ? ".sql" : ".json";
|
||||
var expectedExtension = isScriptFolder ? ".sql" : isDocsFolder ? ".md" : ".json";
|
||||
|
||||
if (!extension.Equals(expectedExtension, StringComparison.OrdinalIgnoreCase))
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Volo.Abp;
|
||||
using static Sozsoft.Platform.PlatformConsts;
|
||||
|
||||
namespace Sozsoft.Platform.ListForms;
|
||||
|
||||
/// <summary>
|
||||
/// Modul dokumanlari wizard'larin parcasi sayilir: okumak Wizard ekraninin, yazmak wizard
|
||||
/// guncelleme yetkisini ister. Dosyalar kapsam seed klasorundedir (<c>docs/modules</c>).
|
||||
/// </summary>
|
||||
[Authorize(AppCodes.Listforms.Wizard)]
|
||||
public class ModuleDocAppService(ModuleDocManager manager) : PlatformAppService, IModuleDocAppService
|
||||
{
|
||||
public Task<List<ModuleDocDto>> GetListAsync() => manager.GetListAsync();
|
||||
|
||||
public Task<ModuleDocDto> GetAsync(string name) => manager.GetAsync(name);
|
||||
|
||||
[Authorize(AppCodes.Listforms.Wizards.Update)]
|
||||
public Task<ModuleDocDto> SaveAsync(ModuleDocSaveInput input)
|
||||
{
|
||||
Check.NotNull(input, nameof(input));
|
||||
return manager.SaveAsync(input.Name, input.Content);
|
||||
}
|
||||
|
||||
public Task<List<ModuleDocDto>> GetIncompleteForDevRequestAsync(Guid devRequestId) =>
|
||||
manager.GetIncompleteForDevRequestAsync(devRequestId);
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Sozsoft.Platform.Data.Seeds;
|
||||
|
||||
namespace Sozsoft.Platform.ListForms;
|
||||
|
||||
/// <summary>
|
||||
/// Bir kapsam klasorundeki wizard dosyalarini ve modul dokumanlarini okur; her wizard'in hangi
|
||||
/// dokumana ait oldugunu cozer. Kural, wizard sozlesmesine alan eklemeden menu agacindan cikar:
|
||||
/// <list type="number">
|
||||
/// <item>Bir dokuman ekranin kodunu basligindaki beyanla sahiplenmisse (<c>module-doc: claims=…</c>) o dokuman.</item>
|
||||
/// <item>Menusuz alt form, onu <c>SubForms</c> icinde tasiyan ekranin dokumanina gider.</item>
|
||||
/// <item>Ust menu zincirinde kokun altinda bir dal varsa (<c>App.Hr › App.Hr.Performance › …</c>)
|
||||
/// dalin kodu, yoksa (ekran dogrudan kokun altinda) ekranin kendi kodu.</item>
|
||||
/// </list>
|
||||
/// Dokuman adi koddan turer: bastaki <c>App.</c> atilir, noktalar silinir (<c>App.Hr.Performance</c> → <c>HrPerformance</c>).
|
||||
/// </summary>
|
||||
public sealed class ModuleDocCatalog
|
||||
{
|
||||
public const string AutoBegin = "<!-- module-doc:auto:begin -->";
|
||||
public const string AutoEnd = "<!-- module-doc:auto:end -->";
|
||||
|
||||
/// <summary>Doldurulmamis bolumun isareti; isaret kalmayan dokuman tamam sayilir.</summary>
|
||||
public const string TodoMarker = "<!-- module-doc:todo -->";
|
||||
|
||||
private static readonly Regex ClaimsPattern = new(@"<!--\s*module-doc:\s*claims=(?<codes>[^>]*?)\s*-->", RegexOptions.Compiled);
|
||||
private static readonly Regex NamePattern = new("^[A-Za-z0-9_-]+$", RegexOptions.Compiled);
|
||||
|
||||
private readonly Dictionary<string, string> claims = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private ModuleDocCatalog(string scopeRoot)
|
||||
{
|
||||
ScopeRoot = Path.GetFullPath(scopeRoot);
|
||||
DocsPath = Path.Combine(ScopeRoot, SeedPathResolver.DocsFolder, SeedPathResolver.ModuleDocsFolder);
|
||||
}
|
||||
|
||||
public string ScopeRoot { get; }
|
||||
|
||||
public string DocsPath { get; }
|
||||
|
||||
public List<(string FileName, WizardSeedFileDto Seed)> Wizards { get; } = [];
|
||||
|
||||
public static async Task<ModuleDocCatalog> LoadAsync(string scopeRoot)
|
||||
{
|
||||
var catalog = new ModuleDocCatalog(scopeRoot);
|
||||
|
||||
var wizardPath = Path.Combine(catalog.ScopeRoot, SeedPathResolver.WizardFolder);
|
||||
if (Directory.Exists(wizardPath))
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(wizardPath, "*.json").OrderBy(f => f, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
var seed = WizardSeedFileDto.FromSeedJson(await File.ReadAllTextAsync(file));
|
||||
if (seed?.Wizard != null)
|
||||
catalog.Wizards.Add((Path.GetFileName(file), seed));
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
// Bozuk wizard dosyasi dokumani etkilemez; wizard ekrani hatayi kendisi gosterir.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var name in catalog.ExistingDocNames())
|
||||
{
|
||||
var match = ClaimsPattern.Match(await File.ReadAllTextAsync(catalog.DocPath(name)));
|
||||
if (!match.Success)
|
||||
continue;
|
||||
|
||||
foreach (var code in match.Groups["codes"].Value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
||||
catalog.claims.TryAdd(code, name);
|
||||
}
|
||||
|
||||
return catalog;
|
||||
}
|
||||
|
||||
public IEnumerable<string> ExistingDocNames() =>
|
||||
Directory.Exists(DocsPath)
|
||||
? Directory.GetFiles(DocsPath, "*.md").Select(Path.GetFileNameWithoutExtension).OfType<string>()
|
||||
: [];
|
||||
|
||||
public string DocPath(string name) => Path.Combine(DocsPath, $"{name}.md");
|
||||
|
||||
public static string RelativePath(string name) => $"{SeedPathResolver.DocsFolder}/{SeedPathResolver.ModuleDocsFolder}/{name}.md";
|
||||
|
||||
public static bool IsValidName(string? name) => !string.IsNullOrWhiteSpace(name) && NamePattern.IsMatch(name);
|
||||
|
||||
/// <summary><c>App.Hr.Performance</c> → <c>HrPerformance</c>.</summary>
|
||||
public static string NameFromCode(string code)
|
||||
{
|
||||
var trimmed = code.Trim();
|
||||
if (trimmed.StartsWith("App.", StringComparison.OrdinalIgnoreCase))
|
||||
trimmed = trimmed[4..];
|
||||
|
||||
return string.Concat(trimmed.Where(char.IsLetterOrDigit));
|
||||
}
|
||||
|
||||
/// <summary>Wizard'in ait oldugu dokumanin adi.</summary>
|
||||
public string Resolve(ListFormWizardDto wizard) => Resolve(wizard, new HashSet<string>(StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
private string Resolve(ListFormWizardDto wizard, HashSet<string> visited)
|
||||
{
|
||||
var listFormCode = wizard.ResolveListFormCode();
|
||||
var menuCode = wizard.ResolveMenuCode();
|
||||
|
||||
if (claims.TryGetValue(listFormCode, out var claimed) || claims.TryGetValue(menuCode, out claimed))
|
||||
return claimed;
|
||||
|
||||
visited.Add(listFormCode);
|
||||
|
||||
if (!wizard.CreateMenu)
|
||||
{
|
||||
var parent = Wizards
|
||||
.Select(w => w.Seed.Wizard)
|
||||
.FirstOrDefault(w => !visited.Contains(w.ResolveListFormCode()) &&
|
||||
(w.SubForms ?? []).Any(s => string.Equals(s.Code, listFormCode, StringComparison.OrdinalIgnoreCase)));
|
||||
if (parent != null)
|
||||
return Resolve(parent, visited);
|
||||
}
|
||||
|
||||
return NameFromCode(BranchCode(wizard));
|
||||
}
|
||||
|
||||
/// <summary>Wizard'in dokumanini tasiyan menu dali: kokun altindaki ilk seviye ya da ekranin kendisi.</summary>
|
||||
public static string BranchCode(ListFormWizardDto wizard)
|
||||
{
|
||||
var chain = wizard.ResolveMenuParentChain();
|
||||
return chain.Count >= 2 ? chain[1].Code : wizard.ResolveMenuCode();
|
||||
}
|
||||
|
||||
/// <summary>Dokuman adlarina gore gruplanmis wizard'lar.</summary>
|
||||
public Dictionary<string, List<(string FileName, WizardSeedFileDto Seed)>> GroupByDoc() =>
|
||||
Wizards
|
||||
.GroupBy(w => Resolve(w.Seed.Wizard), StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(g => g.Key, g => g.ToList(), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Ad, var olan dokuman adi ya da bir wizard'a (dosya adi, ekran ya da menu kodu) isaret
|
||||
/// edebilir; ikincisinde wizard'in dokumani doner.
|
||||
/// </summary>
|
||||
public string? FindName(string? input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return null;
|
||||
|
||||
var value = input.Trim();
|
||||
if (value.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
|
||||
value = value[..^3];
|
||||
|
||||
var existing = ExistingDocNames().FirstOrDefault(n => string.Equals(n, value, StringComparison.OrdinalIgnoreCase));
|
||||
if (existing != null)
|
||||
return existing;
|
||||
|
||||
var wizard = Wizards.FirstOrDefault(w =>
|
||||
string.Equals(w.FileName, value, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(w.FileName, value + ".json", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(w.Seed.Wizard.WizardName, value, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(w.Seed.Wizard.ResolveListFormCode(), value, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(w.Seed.Wizard.ResolveMenuCode(), value, StringComparison.OrdinalIgnoreCase));
|
||||
if (wizard.Seed != null)
|
||||
return Resolve(wizard.Seed.Wizard);
|
||||
|
||||
return IsValidName(value) ? value : null;
|
||||
}
|
||||
|
||||
/// <summary>Otomatik envanter bolumu cikarilmis icerik.</summary>
|
||||
public static string StripAuto(string content)
|
||||
{
|
||||
var begin = content.IndexOf(AutoBegin, StringComparison.Ordinal);
|
||||
if (begin < 0)
|
||||
return content;
|
||||
|
||||
var end = content.IndexOf(AutoEnd, begin, StringComparison.Ordinal);
|
||||
var tail = end < 0 ? string.Empty : content[(end + AutoEnd.Length)..];
|
||||
|
||||
return content[..begin].TrimEnd() + tail;
|
||||
}
|
||||
|
||||
/// <summary>Doldurulmamis bolumlerin basliklari (<see cref="TodoMarker"/> tasiyan bolumler).</summary>
|
||||
public static List<string> MissingSections(string content)
|
||||
{
|
||||
var missing = new List<string>();
|
||||
string? heading = null;
|
||||
|
||||
foreach (var line in StripAuto(content).Split('\n'))
|
||||
{
|
||||
if (line.StartsWith("## ", StringComparison.Ordinal))
|
||||
heading = line[3..].Trim();
|
||||
else if (line.Contains(TodoMarker, StringComparison.Ordinal) && heading != null && !missing.Contains(heading))
|
||||
missing.Add(heading);
|
||||
}
|
||||
|
||||
return missing;
|
||||
}
|
||||
|
||||
/// <summary>Hicbir bolumu doldurulmamis (otomatik acildigi gibi duran) dokuman.</summary>
|
||||
public static bool IsUntouchedSkeleton(string content)
|
||||
{
|
||||
var sections = StripAuto(content).Split('\n').Count(l => l.StartsWith("## ", StringComparison.Ordinal));
|
||||
return sections > 0 && MissingSections(content).Count == sections;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sozsoft.Platform.Data.Seeds;
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Sozsoft.Platform.ListForms;
|
||||
|
||||
/// <summary>
|
||||
/// Modul dokumanlarinin dosya islemleri. Wizard deploy'u, silme, tasarimci senkronizasyonu ve
|
||||
/// import kapanisi <see cref="RefreshAllAsync"/> cagirir: wizard'i olan her dokumanin envanteri
|
||||
/// yeniden yazilir, dokumani olmayan modul icin iskelet acilir. Elle yazilan bolumlere dokunulmaz.
|
||||
/// </summary>
|
||||
public class ModuleDocManager(
|
||||
IConfiguration configuration,
|
||||
ICurrentTenant currentTenant,
|
||||
ILogger<ModuleDocManager> logger) : ITransientDependency
|
||||
{
|
||||
private static readonly UTF8Encoding Utf8NoBom = new(encoderShouldEmitUTF8Identifier: false);
|
||||
|
||||
private string ScopeRoot => Path.GetFullPath(SeedPathResolver.GetScopePath(configuration, currentTenant.Id));
|
||||
|
||||
public Task<ModuleDocCatalog> LoadCatalogAsync() => ModuleDocCatalog.LoadAsync(ScopeRoot);
|
||||
|
||||
/// <summary>
|
||||
/// Butun dokumanlarin envanterini yeniler. Hata deploy'u ya da kaydi durdurmaz; dokuman bir
|
||||
/// sonraki yenilemede duzelir.
|
||||
/// </summary>
|
||||
public async Task RefreshAllAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var catalog = await LoadCatalogAsync();
|
||||
var groups = catalog.GroupByDoc();
|
||||
var names = groups.Keys.Union(catalog.ExistingDocNames(), StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
foreach (var name in names)
|
||||
await RefreshAsync(catalog, name, groups.GetValueOrDefault(name) ?? []);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarning(ex, "Module docs could not be refreshed: {Message}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RefreshAsync(ModuleDocCatalog catalog, string name, List<(string FileName, WizardSeedFileDto Seed)> wizards)
|
||||
{
|
||||
if (!ModuleDocCatalog.IsValidName(name))
|
||||
return;
|
||||
|
||||
var path = catalog.DocPath(name);
|
||||
var existing = File.Exists(path) ? await File.ReadAllTextAsync(path) : null;
|
||||
|
||||
// Wizard'i olmayan elle yazilmis dokuman (entity tabanli modul) envanter tasimaz; ona dokunulmaz.
|
||||
if (existing == null && wizards.Count == 0)
|
||||
return;
|
||||
if (existing != null && wizards.Count == 0 && !existing.Contains(ModuleDocCatalog.AutoBegin, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
var manual = existing == null
|
||||
? Skeleton(wizards)
|
||||
: ModuleDocCatalog.StripAuto(Normalize(existing));
|
||||
|
||||
if (wizards.Count == 0 && ModuleDocCatalog.IsUntouchedSkeleton(manual))
|
||||
{
|
||||
// Wizard'i silinmis ve hic yazilmamis iskelet: geride bos dokuman birakilmaz.
|
||||
File.Delete(path);
|
||||
logger.LogInformation("Module doc removed (no wizards, never written): {Path}", path);
|
||||
return;
|
||||
}
|
||||
|
||||
var content = wizards.Count == 0
|
||||
? manual.TrimEnd() + "\n"
|
||||
: manual.TrimEnd() + "\n\n" + ModuleDocRenderer.Inventory(wizards);
|
||||
|
||||
if (existing != null && Normalize(existing) == content)
|
||||
return;
|
||||
|
||||
Directory.CreateDirectory(catalog.DocsPath);
|
||||
await File.WriteAllTextAsync(path, content, Utf8NoBom);
|
||||
logger.LogInformation("Module doc written: {Path}", path);
|
||||
}
|
||||
|
||||
private static string Skeleton(List<(string FileName, WizardSeedFileDto Seed)> wizards)
|
||||
{
|
||||
var branch = ModuleDocCatalog.BranchCode(wizards[0].Seed.Wizard);
|
||||
return ModuleDocRenderer.Skeleton(ModuleDocRenderer.Title(wizards.Select(w => w.Seed), branch), branch);
|
||||
}
|
||||
|
||||
public async Task<List<ModuleDocDto>> GetListAsync()
|
||||
{
|
||||
var catalog = await LoadCatalogAsync();
|
||||
var groups = catalog.GroupByDoc();
|
||||
|
||||
var result = new List<ModuleDocDto>();
|
||||
foreach (var name in groups.Keys.Union(catalog.ExistingDocNames(), StringComparer.OrdinalIgnoreCase).OrderBy(n => n, StringComparer.OrdinalIgnoreCase))
|
||||
result.Add(await ToDtoAsync(catalog, name, groups, includeContent: false));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<ModuleDocDto> GetAsync(string input)
|
||||
{
|
||||
var catalog = await LoadCatalogAsync();
|
||||
var name = catalog.FindName(input) ?? throw new UserFriendlyException($"Modül dokümanı bulunamadı: {input}");
|
||||
|
||||
return await ToDtoAsync(catalog, name, catalog.GroupByDoc(), includeContent: true);
|
||||
}
|
||||
|
||||
public async Task<ModuleDocDto> SaveAsync(string input, string content)
|
||||
{
|
||||
var catalog = await LoadCatalogAsync();
|
||||
var name = catalog.FindName(input) ?? throw new UserFriendlyException($"Geçersiz modül dokümanı adı: {input}");
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
throw new UserFriendlyException("Doküman içeriği boş olamaz.");
|
||||
|
||||
var path = catalog.DocPath(name);
|
||||
var manual = ModuleDocCatalog.StripAuto(Normalize(content)).TrimEnd() + "\n";
|
||||
|
||||
Directory.CreateDirectory(catalog.DocsPath);
|
||||
await File.WriteAllTextAsync(path, manual, Utf8NoBom);
|
||||
|
||||
// Envanter dosyaya yeniden eklenir; sahiplik beyani degismis olabilecegi icin katalog tazelenir.
|
||||
catalog = await LoadCatalogAsync();
|
||||
var groups = catalog.GroupByDoc();
|
||||
await RefreshAsync(catalog, name, groups.GetValueOrDefault(name) ?? []);
|
||||
|
||||
return await ToDtoAsync(catalog, name, groups, includeContent: true);
|
||||
}
|
||||
|
||||
public async Task<List<ModuleDocDto>> GetIncompleteForDevRequestAsync(Guid devRequestId)
|
||||
{
|
||||
var catalog = await LoadCatalogAsync();
|
||||
var groups = catalog.GroupByDoc();
|
||||
|
||||
var names = catalog.Wizards
|
||||
.Where(w => w.Seed.DevRequest?.Id == devRequestId)
|
||||
.Select(w => catalog.Resolve(w.Seed.Wizard))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var result = new List<ModuleDocDto>();
|
||||
foreach (var name in names)
|
||||
{
|
||||
var doc = await ToDtoAsync(catalog, name, groups, includeContent: false);
|
||||
if (!doc.Exists || !doc.IsComplete)
|
||||
result.Add(doc);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static async Task<ModuleDocDto> ToDtoAsync(
|
||||
ModuleDocCatalog catalog,
|
||||
string name,
|
||||
Dictionary<string, List<(string FileName, WizardSeedFileDto Seed)>> groups,
|
||||
bool includeContent)
|
||||
{
|
||||
var path = catalog.DocPath(name);
|
||||
var exists = File.Exists(path);
|
||||
var content = exists ? Normalize(await File.ReadAllTextAsync(path)) : null;
|
||||
var missing = content == null ? [.. ModuleDocRenderer.Sections] : ModuleDocCatalog.MissingSections(content);
|
||||
|
||||
return new ModuleDocDto
|
||||
{
|
||||
Name = name,
|
||||
Path = ModuleDocCatalog.RelativePath(name),
|
||||
Exists = exists,
|
||||
IsComplete = exists && missing.Count == 0,
|
||||
MissingSections = missing,
|
||||
Wizards = [.. (groups.GetValueOrDefault(name) ?? []).Select(w => w.Seed.Wizard.ResolveListFormCode())],
|
||||
Content = includeContent ? content : null,
|
||||
};
|
||||
}
|
||||
|
||||
private static string Normalize(string text) => text.TrimStart('').Replace("\r\n", "\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using Sozsoft.Platform.Data.Seeds;
|
||||
using Sozsoft.Platform.Enums;
|
||||
|
||||
namespace Sozsoft.Platform.ListForms;
|
||||
|
||||
/// <summary>
|
||||
/// Modul dokumaninin uretilen kisimlari: ilk deploy'da acilan iskelet ve her yenilemede yeniden
|
||||
/// yazilan "Ek — Ekran envanteri" bolumu. Envanter yalnizca wizard dosyasinda yazanlari aktarir;
|
||||
/// isin neden boyle kuruldugu elle (ya da AI ile) yazilan bolumlerdedir.
|
||||
/// </summary>
|
||||
public static class ModuleDocRenderer
|
||||
{
|
||||
/// <summary>lowcode §0.13'teki bolumler; iskelet bu sirayla acilir.</summary>
|
||||
public static readonly string[] Sections =
|
||||
[
|
||||
"1. Amaç ve kapsam",
|
||||
"2. Analiz ve kararlar",
|
||||
"3. Menü ve ekranlar",
|
||||
"4. Veri modeli",
|
||||
"5. İş kuralları ve hesaplar",
|
||||
"6. Yetki ve görünürlük",
|
||||
"7. Entegrasyonlar",
|
||||
"8. Akış örneği",
|
||||
"9. Sık sorulanlar",
|
||||
"10. Dosyalar ve geri alma",
|
||||
];
|
||||
|
||||
private static readonly Regex ProcedurePattern = new(@"\bEXEC(?:UTE)?\s+(?:\[?dbo\]?\.)?\[?(?<name>\w+)\]?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex FromPattern = new(@"\bFROM\s+""?\[?(?<name>\w+)\]?""?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
public static string Skeleton(string title, string branchCode)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("# ").Append(title).Append(" (`").Append(branchCode).Append("`)\n\n");
|
||||
sb.Append("> Bu dosya ilk deploy'da otomatik açıldı. `module-doc:todo` işaretli bölümleri modülü üreten kişi ya da AI doldurur ")
|
||||
.Append("(`lowcode.instructions.md` §0.13); MCP ile üretimde talep bu bölümler doldurulmadan Testing'e alınamaz. ")
|
||||
.Append("\"Ek — Ekran envanteri\" bölümü wizard dosyalarından üretilir, elle düzenlenmez.\n");
|
||||
|
||||
foreach (var section in Sections)
|
||||
sb.Append("\n## ").Append(section).Append("\n\n_Henüz yazılmadı._ ").Append(ModuleDocCatalog.TodoMarker).Append('\n');
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Iskeletin basligi: dalin iki dilli adi wizard cevaplarinda varsa Turkcesi, yoksa kod.</summary>
|
||||
public static string Title(IEnumerable<WizardSeedFileDto> seeds, string branchCode)
|
||||
{
|
||||
foreach (var wizard in seeds.Select(s => s.Wizard))
|
||||
{
|
||||
if (string.Equals(wizard.ResolveMenuCode(), branchCode, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(wizard.MenuTr))
|
||||
return wizard.MenuTr;
|
||||
|
||||
var level = wizard.ResolveMenuParentChain().FirstOrDefault(l => string.Equals(l.Code, branchCode, StringComparison.OrdinalIgnoreCase));
|
||||
if (!string.IsNullOrWhiteSpace(level?.Tr))
|
||||
return level.Tr;
|
||||
}
|
||||
|
||||
return branchCode;
|
||||
}
|
||||
|
||||
public static string Inventory(IReadOnlyList<(string FileName, WizardSeedFileDto Seed)> wizards)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(ModuleDocCatalog.AutoBegin).Append('\n');
|
||||
sb.Append("## Ek — Ekran envanteri (otomatik)\n\n");
|
||||
sb.Append("> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.\n");
|
||||
|
||||
var ordered = wizards
|
||||
.OrderBy(w => w.Seed.Wizard.CreateMenu ? 0 : 1)
|
||||
.ThenBy(w => w.Seed.Wizard.MenuOrder)
|
||||
.ThenBy(w => w.Seed.Wizard.SeededAt);
|
||||
|
||||
foreach (var (fileName, seed) in ordered)
|
||||
AppendWizard(sb, fileName, seed);
|
||||
|
||||
sb.Append('\n').Append(ModuleDocCatalog.AutoEnd).Append('\n');
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static void AppendWizard(StringBuilder sb, string fileName, WizardSeedFileDto seed)
|
||||
{
|
||||
var wizard = seed.Wizard;
|
||||
var listForm = seed.ListForm;
|
||||
var code = wizard.ResolveListFormCode();
|
||||
var title = FirstText(wizard.MenuTr, wizard.TitleTr, wizard.MenuEn, code);
|
||||
|
||||
sb.Append("\n### ").Append(Cell(title)).Append(" — `").Append(code).Append("`\n\n");
|
||||
sb.Append("| Özellik | Değer |\n| --- | --- |\n");
|
||||
Row(sb, "Wizard", $"`{SeedPathResolver.WizardFolder}/{fileName}`");
|
||||
|
||||
if (wizard.ComponentKind == WizardComponentKindEnum.Custom)
|
||||
{
|
||||
Row(sb, "Yol", $"Custom Component `{wizard.CustomComponentName}`");
|
||||
Row(sb, "Rota", $"`{wizard.MenuUrl}`");
|
||||
}
|
||||
else
|
||||
{
|
||||
Row(sb, "Yol", "Liste (Wizard)");
|
||||
}
|
||||
|
||||
Row(sb, "Menü", wizard.CreateMenu
|
||||
? $"`{wizard.MenuParentCode}` › `{wizard.ResolveMenuCode()}` (sıra {wizard.MenuOrder})"
|
||||
: "Menüsüz (alt form)");
|
||||
Row(sb, "Yetki", $"`{wizard.ResolveMenuCode()}` + {string.Join(", ", WizardSeedRowKeys.ChildPermissions(wizard).Select(p => $"`.{p.Suffix}`"))}");
|
||||
|
||||
// Ayrintili aciklama ekranin bilgi diyalogundadir; envantere yalnizca ozet satiri girer.
|
||||
if (!string.IsNullOrWhiteSpace(wizard.DescTr))
|
||||
Row(sb, "Açıklama", wizard.DescTr.Split('\n')[0]);
|
||||
|
||||
if (seed.DevRequest != null)
|
||||
Row(sb, "Geliştirme talebi", seed.DevRequest.Title);
|
||||
|
||||
if (listForm != null)
|
||||
{
|
||||
Row(sb, "Kaynak", $"`{listForm.SelectCommand}`" + (string.IsNullOrWhiteSpace(listForm.DefaultFilter) ? string.Empty : $" · filtre `{listForm.DefaultFilter}`"));
|
||||
|
||||
var layout = listForm.LayoutDto;
|
||||
var views = new (bool On, string Name)[]
|
||||
{
|
||||
(layout.Grid, "Grid"), (layout.Card, "Card"), (layout.Pivot, "Pivot"), (layout.Chart, "Chart"),
|
||||
(layout.Tree, "Tree"), (layout.Gantt, "Gantt"), (layout.Scheduler, "Scheduler"), (layout.Todo, "Todo"),
|
||||
};
|
||||
Row(sb, "Görünümler", $"{string.Join(", ", views.Where(v => v.On).Select(v => v.Name))} (açılış {layout.DefaultLayout})");
|
||||
|
||||
var editing = listForm.EditingOptionDto;
|
||||
Row(sb, "Düzenleme", $"ekle {Flag(editing.AllowAdding)} · düzenle {Flag(editing.AllowUpdating)} · sil {Flag(editing.AllowDeleting)} · {editing.Mode}");
|
||||
Row(sb, "Kapsam", listForm.IsTenant ? "Kiracı" : "Host");
|
||||
|
||||
var subForms = listForm.SubFormsDto?.ToList() ?? [];
|
||||
if (subForms.Count > 0)
|
||||
Row(sb, "Alt formlar", string.Join(", ", subForms.Select(s =>
|
||||
$"`{s.Code}` ({string.Join(", ", (s.Relation ?? []).Select(r => $"{r.ParentFieldName} → {r.ChildFieldName}"))})")));
|
||||
|
||||
var widgets = listForm.WidgetsDto?.ToList() ?? [];
|
||||
if (widgets.Count > 0)
|
||||
Row(sb, "Widget'lar", string.Join(", ", widgets.SelectMany(w => WidgetTitles(w.SqlQuery)).Distinct().Select(t => $"`{t}`")));
|
||||
|
||||
var todo = listForm.TodoOptionDto;
|
||||
if (layout.Todo && !string.IsNullOrWhiteSpace(todo?.StatusExpr))
|
||||
Row(sb, "Todo", $"başlık `{todo.TitleExpr}`, durum `{todo.StatusExpr}`" + (string.IsNullOrWhiteSpace(todo.StatusOrder) ? string.Empty : $" ({todo.StatusOrder})"));
|
||||
|
||||
var commands = new (string Name, string? Sql)[]
|
||||
{
|
||||
("InsertBefore", listForm.InsertBeforeCommand), ("InsertAfter", listForm.InsertAfterCommand),
|
||||
("UpdateBefore", listForm.UpdateBeforeCommand), ("UpdateAfter", listForm.UpdateAfterCommand),
|
||||
("DeleteBefore", listForm.DeleteBeforeCommand), ("DeleteAfter", listForm.DeleteAfterCommand),
|
||||
};
|
||||
var commandText = commands
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c.Sql))
|
||||
.Select(c =>
|
||||
{
|
||||
var procedures = ProcedurePattern.Matches(c.Sql!).Select(m => m.Groups["name"].Value).Distinct().ToList();
|
||||
return $"{c.Name}: " + (procedures.Count > 0 ? string.Join(", ", procedures.Select(p => $"`{p}`")) : "SQL");
|
||||
})
|
||||
.ToList();
|
||||
if (commandText.Count > 0)
|
||||
Row(sb, "Komutlar", string.Join(" · ", commandText));
|
||||
|
||||
var defaults = (listForm.FormFieldsDefaultValueDto ?? []).Select(d => $"{d.FieldName}={d.Value}").ToList();
|
||||
if (defaults.Count > 0)
|
||||
Row(sb, "Form varsayılanları", string.Join(", ", defaults));
|
||||
|
||||
var buttons = listForm.CommandColumnDto?.ToList() ?? [];
|
||||
if (buttons.Count > 0)
|
||||
Row(sb, "Butonlar", string.Join(", ", buttons.Select(b => $"`{b.Text}`")));
|
||||
|
||||
var criteria = listForm.WorkflowDto?.Criteria?.ToList() ?? [];
|
||||
if (criteria.Count > 0)
|
||||
Row(sb, "Onay akışı", string.Join(" → ", criteria.Select(c => $"{c.Kind} '{c.Title}'")));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(listForm.SeedFilePath))
|
||||
Row(sb, "Veri aynası", $"`{listForm.SeedFilePath}`");
|
||||
}
|
||||
|
||||
AppendFields(sb, wizard, seed.Fields ?? []);
|
||||
}
|
||||
|
||||
private static void AppendFields(StringBuilder sb, ListFormWizardDto wizard, List<ColumnFormatEditDto> fields)
|
||||
{
|
||||
if (fields.Count == 0)
|
||||
return;
|
||||
|
||||
var captions = (wizard.Groups ?? [])
|
||||
.SelectMany(g => g.Items ?? [])
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i.FieldName))
|
||||
.GroupBy(i => i.FieldName, StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(g => g.Key, g => FirstText(g.First().TurkishCaption, g.First().EnglishCaption, g.Key), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
sb.Append("\n| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |\n| --- | --- | --- | --- | --- | --- |\n");
|
||||
foreach (var field in fields.OrderBy(f => f.ListOrderNo))
|
||||
{
|
||||
if (string.Equals(field.FieldName, wizard.KeyFieldName, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
var required = (field.ValidationRuleDto ?? []).Any(r => string.Equals(r.Type, "required", StringComparison.OrdinalIgnoreCase));
|
||||
var source = LookupSource(field.LookupDto);
|
||||
if (!string.IsNullOrWhiteSpace(field.EditorScript))
|
||||
source = string.IsNullOrEmpty(source) ? "script" : source + " · script";
|
||||
|
||||
sb.Append("| `").Append(field.FieldName).Append("` | ")
|
||||
.Append(Cell(captions.GetValueOrDefault(field.FieldName ?? string.Empty) ?? field.FieldName ?? string.Empty)).Append(" | ")
|
||||
.Append(field.EditorType2).Append(" | ")
|
||||
.Append(required ? "✓" : string.Empty).Append(" | ")
|
||||
.Append(field.EditGroupOrderNo.HasValue ? "✓" : string.Empty).Append(" | ")
|
||||
.Append(Cell(source)).Append(" |\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static string LookupSource(LookupDto? lookup)
|
||||
{
|
||||
if (lookup == null || string.IsNullOrWhiteSpace(lookup.LookupQuery))
|
||||
return string.Empty;
|
||||
|
||||
if (lookup.DataSourceType == UiLookupDataSourceTypeEnum.StaticData)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var document = JsonDocument.Parse(lookup.LookupQuery);
|
||||
var keys = document.RootElement.EnumerateArray()
|
||||
.Select(e => e.TryGetProperty("key", out var key) ? key.ToString() : string.Empty)
|
||||
.Where(k => k.Length > 0);
|
||||
return "liste: " + string.Join(", ", keys);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return "liste";
|
||||
}
|
||||
}
|
||||
|
||||
var table = FromPattern.Match(lookup.LookupQuery);
|
||||
var text = table.Success ? $"sorgu: {table.Groups["name"].Value}" : "sorgu";
|
||||
return string.IsNullOrWhiteSpace(lookup.CascadeParentFields) ? text : $"{text} (← {lookup.CascadeParentFields})";
|
||||
}
|
||||
|
||||
/// <summary>Widget sorgusundaki kart basliklari (ilk kolondaki dil anahtarlari).</summary>
|
||||
private static IEnumerable<string> WidgetTitles(string? sql)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sql))
|
||||
yield break;
|
||||
|
||||
foreach (Match match in Regex.Matches(sql, @"SELECT\s+'(?<title>[^']+)'", RegexOptions.IgnoreCase))
|
||||
yield return match.Groups["title"].Value;
|
||||
}
|
||||
|
||||
private static void Row(StringBuilder sb, string name, string value) =>
|
||||
sb.Append("| ").Append(name).Append(" | ").Append(Cell(value)).Append(" |\n");
|
||||
|
||||
private static string Cell(string? value) =>
|
||||
(value ?? string.Empty).Replace("\r", string.Empty).Replace("\n", " ").Replace("|", "\\|");
|
||||
|
||||
private static string Flag(bool value) => value ? "✓" : "✗";
|
||||
|
||||
private static string FirstText(params string?[] values) =>
|
||||
values.FirstOrDefault(v => !string.IsNullOrWhiteSpace(v)) ?? string.Empty;
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@ public sealed class WizardExportCollector(string scopeRoot)
|
|||
private readonly Dictionary<string, WizardExportItem> items = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly HashSet<string> customComponents = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly List<string> warnings = [];
|
||||
private readonly List<ListFormWizardDto> collectedWizards = [];
|
||||
|
||||
/// <summary>Toplanan wizard'larin platform seed dosyalarindaki (menu, yetki, dil) satir anahtarlari.</summary>
|
||||
private WizardInsertedRecordsDto platformRows = new();
|
||||
|
|
@ -92,6 +93,7 @@ public sealed class WizardExportCollector(string scopeRoot)
|
|||
|
||||
AddDiskFile($"{SeedPathResolver.WizardFolder}/{System.IO.Path.GetFileName(filePath)}", reason);
|
||||
platformRows = platformRows.Union(WizardSeedRowKeys.All(seed.Wizard));
|
||||
collectedWizards.Add(seed.Wizard);
|
||||
|
||||
if (seed.Wizard.ComponentKind == WizardComponentKindEnum.Custom)
|
||||
await CollectCustomAsync(seed.Wizard.CustomComponentName, seed.Wizard.WizardName);
|
||||
|
|
@ -101,10 +103,28 @@ public sealed class WizardExportCollector(string scopeRoot)
|
|||
|
||||
await MaterializeCustomComponentsAsync();
|
||||
await MaterializePlatformRowsAsync();
|
||||
await CollectModuleDocsAsync();
|
||||
|
||||
return [.. items.Values.OrderBy(x => x.Path, StringComparer.OrdinalIgnoreCase)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toplanan wizard'larin modul dokumanlari. Dokuman kapanisin zorunlu parcasi degildir: yoksa
|
||||
/// uyari uretilmez, hedefte ilk deploy ya da import kapanisi iskeleti acar.
|
||||
/// </summary>
|
||||
private async Task CollectModuleDocsAsync()
|
||||
{
|
||||
if (collectedWizards.Count == 0)
|
||||
return;
|
||||
|
||||
var catalog = await ModuleDocCatalog.LoadAsync(scopeRoot);
|
||||
foreach (var name in collectedWizards.Select(catalog.Resolve).Distinct(StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
if (System.IO.File.Exists(catalog.DocPath(name)))
|
||||
AddDiskFile(ModuleDocCatalog.RelativePath(name), "Modül dokümanı");
|
||||
}
|
||||
}
|
||||
|
||||
// ── List yolu ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ public class WizardSeedSynchronizer(
|
|||
IObjectMapper objectMapper,
|
||||
IConfiguration configuration,
|
||||
ICurrentTenant currentTenant,
|
||||
ModuleDocManager moduleDocManager,
|
||||
ILogger<WizardSeedSynchronizer> logger) : IWizardSeedSynchronizer, ITransientDependency
|
||||
{
|
||||
|
||||
|
|
@ -76,6 +77,9 @@ public class WizardSeedSynchronizer(
|
|||
|
||||
await File.WriteAllTextAsync(filePath, seed.ToSeedJson());
|
||||
logger.LogInformation("Wizard seed file synchronized: {FilePath}", filePath);
|
||||
|
||||
// Modul dokumaninin envanteri ekranin guncel halini anlatmali.
|
||||
await moduleDocManager.RefreshAllAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -74,6 +74,15 @@ public static class SeedPathResolver
|
|||
/// <summary>Liste verisinin aynalandigi seed dosyalari (<c>data/{ListFormCode}.json</c>).</summary>
|
||||
public const string DataFolder = WizardConsts.SeedDataFolder;
|
||||
|
||||
/// <summary>
|
||||
/// Kapsam klasorundeki dokumanlar. Modul dokumanlari <c>docs/modules/{Modul}.md</c> altindadir;
|
||||
/// sunucu (wizard deploy, MCP) yalnizca seed kokune yazabildigi icin depo kokunde degil buradadir.
|
||||
/// </summary>
|
||||
public const string DocsFolder = "docs";
|
||||
|
||||
/// <summary><see cref="DocsFolder"/> altindaki modul dokumani klasoru.</summary>
|
||||
public const string ModuleDocsFolder = "modules";
|
||||
|
||||
/// <summary>
|
||||
/// Bir ListForm icin varsayilan veri seed dosyasinin kapsam klasorune gore goreli yolu. Bicim
|
||||
/// Domain.Shared'dedir; wizard'in urettigi ekran (Application.Contracts) ayni yolu yazar.
|
||||
|
|
|
|||
24
claude.md
24
claude.md
|
|
@ -111,6 +111,7 @@ These sections encode expectations the user will **not** repeat in every prompt.
|
|||
| `api/` kod standardı (sürüm, nullable, ölü kod, modern C#, ABP katmanları) | `.github/instructions/dotnet.instructions.md` |
|
||||
| Modül/liste ekleme prosedürü, seeder dosya sorumlulukları | `.github/instructions/list.instructions.md` |
|
||||
| Ne nerede yaşıyor, hangi ekran ne yapıyor | `README.md` |
|
||||
| Bir modülün nasıl çalıştığı, analizi ve kararları | `configs/seeds/host/docs/modules/{Modül}.md` (dizin: `README.md` §10.5) |
|
||||
| Yetki kodları | `PlatformConsts.AppCodes` (backend) + `constants/permission.constant.ts` (UI) |
|
||||
| Seed yolları | `SeedPathResolver` |
|
||||
|
||||
|
|
@ -182,9 +183,29 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
|
|||
`lowcode.instructions.md` §4.6.1.
|
||||
Alt form ekranının menü/yetki/düzenleme kuralları (menüsüz alt formun yetkisi ana ekranın altında,
|
||||
`Form` sekmesi tek kayıt + `AllowAdding`/`AllowUpdating` açık): `lowcode.instructions.md` §4.6.
|
||||
14. **Modül dokümanı** → MCP ya da wizard ile oluşturulan her modül çalışma şeklini
|
||||
`configs/seeds/{kapsam}/docs/modules/{Modül}.md` dosyasında taşır: keşif cevapları ve onaylanan
|
||||
tarif (analiz), ekranlar, veri modeli, hesaplar/durum geçişleri, yetki dağılımı, entegrasyonlar,
|
||||
sık sorulanlar. Dosyayı ve "Ek — Ekran envanteri"ni deploy kendisi açar/yeniler; anlatım
|
||||
bölümlerini (`module-doc:todo`) üreten doldurur — MCP'de `save_module_doc`, Claude Code'da dosyaya
|
||||
doğrudan. MCP talebi doküman tamamlanmadan `Testing`'e alınamaz. Wizard dışı modül dokümanı elle
|
||||
yazılır. README'ye yalnızca §10.5 dizin satırı ve ilgili bölümde tek cümlelik bağlantı yazılır.
|
||||
"X nasıl çalışıyor?" sorusunda önce bu dosya okunur. Ayrıntı: `lowcode.instructions.md` §0.13.
|
||||
15. **Ekran açıklaması** → wizard/MCP ile üretilen her liste ekranının (alt formlar dahil)
|
||||
`DescTr`/`DescEn` metni ayrıntılıdır; başlıktaki ⓘ simgesinde gösterilir: ne işe yaradığı,
|
||||
menüde nerede / hangi ekranın sekmesi olduğu, ana alanlar, otomatik hesap ve geçişler, ilişkili
|
||||
ekranlar (`RichText` biçimi). MCP `deploy_wizard` 3 satır / 150 karakterin altını reddeder.
|
||||
Ayrıntı: `lowcode.instructions.md` §4.4.2.
|
||||
|
||||
### Cross-cutting: touching one thing means touching these too
|
||||
|
||||
- **Modül dokümanı** → `ModuleDocManager.RefreshAllAsync` wizard'ı yazan her yoldan çağrılır (deploy,
|
||||
silme, `WizardSeedSynchronizer`, import kapanışı); wizard dosyasını yazan yeni bir yol eklenirse
|
||||
çağrı da eklenir, yoksa envanter bayatlar. Wizard → doküman eşlemesi tek yerdedir
|
||||
(`ModuleDocCatalog`: beyan → alt formun ana ekranı → menü dalı); envanter biçimi
|
||||
`ModuleDocRenderer`'dadır. Export kapanışı dokümanı taşır (`WizardExportCollector`), import
|
||||
`docs/modules/*.md` yolunu kabul eder.
|
||||
|
||||
- **`scriptRecipes.ts` (TS) ↔ `Domain.Shared/Editors/*.cs`** — biri değişirse diğeri de değişir.
|
||||
İkisinin çıktısı **birebir aynı** olmak zorundadır; aksi hâlde seeder ile basılan script
|
||||
dialogda "elle düzenlenmiş" sayılır ve kural editörü kapanır.
|
||||
|
|
@ -475,6 +496,9 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
|
|||
silinmeden önce **repo geneli** (api + ui + configs) referans taraması yapılır; DI ile çözülen
|
||||
tipler düz metin aramasında referanssız görünür.
|
||||
- Yorum satırına alınmış kod bloğu bırakılmaz.
|
||||
- Modül/ekran/bileşen ekleyen ya da davranışını değiştiren iş modül dokümanını
|
||||
(`configs/seeds/{kapsam}/docs/modules/{Modül}.md`) yazar veya günceller; liste ekranının açıklaması
|
||||
ayrıntılıdır (standing default 14–15).
|
||||
- `api/` değişikliğinden sonra: `dotnet build -p:EnforceCodeStyleInBuild=true` — 0 hata, yeni
|
||||
`IDE00xx` yok.
|
||||
- `ui/` değişikliğinden sonra: `npm run typecheck` ve `npm run lint`.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"ListFormCode": "App.DeveloperKit.CustomComponents",
|
||||
"KeyFieldName": "Id",
|
||||
"GeneratedAt": "2026-10-04T13:55:55Z",
|
||||
"Order": 0,
|
||||
"Rows": [
|
||||
{
|
||||
"Id": "98a5c0b9-c8d6-5e83-ae76-d9ccb5b70cba",
|
||||
"Name": "TeamPerformanceWidget",
|
||||
"RoutePath": null,
|
||||
"Description": "Intranet panosu: yöneticinin ekibindeki değerlendirmelerin özeti",
|
||||
"IsActive": true,
|
||||
"Dependencies": [],
|
||||
"Code": "// Yoneticinin ekip ozeti. Satirlar ekranin sorgusundan gelir (ManagerId = oturum acan kullanici);\n// degerlendirmesini bekleyen calisanlar adlariyla listelenir.\nconst TEAM = 'App.Hr.TeamPerformanceReview'\n\nconst Stat = ({ label, value, children }) => (\n <div className=\"flex items-center gap-3 rounded-lg border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-900/40\">\n {children}\n <div className=\"min-w-0\">\n <div className=\"text-lg font-semibold text-gray-900 dark:text-white\">{value}</div>\n <div className=\"truncate text-xs text-gray-500 dark:text-gray-400\">{label}</div>\n </div>\n </div>\n)\n\nconst TeamPerformanceWidget = () => {\n const [rows, setRows] = useState([])\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let active = true\n apiService\n .fetchData({\n method: 'GET',\n url: '/api/app/list-form-select/select',\n params: { listFormCode: TEAM, take: 500 },\n })\n .then((response) => active && setRows(response.data?.data ?? []))\n .catch(() => {})\n .finally(() => active && setLoading(false))\n return () => {\n active = false\n }\n }, [])\n\n const inGoalOrSelf = rows.filter((r) => r.Status === 'GoalSetting' || r.Status === 'SelfReview')\n const awaitingMe = rows.filter((r) => r.Status === 'ManagerReview')\n const completed = rows.filter((r) => r.Status === 'Completed')\n\n return (\n <div className=\"overflow-hidden rounded-xl border border-gray-200/50 bg-white shadow-lg dark:border-gray-700/50 dark:bg-gray-800\">\n <div className=\"flex items-center gap-2 border-b border-gray-200 p-4 dark:border-gray-700\">\n <PlatformIcon name=\"FaUsers\" className=\"h-5 w-5 text-indigo-500\" />\n <h2 className=\"text-base font-semibold text-gray-900 dark:text-white\">\n {translate('::App.DashboardWidget.TeamPerformance')}\n </h2>\n </div>\n <div className=\"space-y-3 p-3\">\n {loading ? (\n <div className=\"p-4 text-center text-sm text-gray-500\">...</div>\n ) : rows.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-gray-500 dark:text-gray-400\">\n {translate('::App.DashboardWidget.Performance.NoTeamReview')}\n </div>\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-2\">\n <Stat label={translate('::App.Hr.Performance.Widget.AwaitingMe')} value={awaitingMe.length}>\n <PlatformIcon name=\"FaUserTie\" className=\"h-5 w-5 text-purple-500\" />\n </Stat>\n <Stat label={translate('::App.Hr.Performance.Widget.InGoalOrSelf')} value={inGoalOrSelf.length}>\n <PlatformIcon name=\"FaHourglassHalf\" className=\"h-5 w-5 text-amber-500\" />\n </Stat>\n <Stat label={translate('::App.Hr.Performance.Widget.Completed')} value={completed.length}>\n <PlatformIcon name=\"FaCheckCircle\" className=\"h-5 w-5 text-green-500\" />\n </Stat>\n <Stat label={translate('::App.Widget.Total')} value={rows.length}>\n <PlatformIcon name=\"FaClipboardList\" className=\"h-5 w-5 text-blue-500\" />\n </Stat>\n </div>\n {awaitingMe.length > 0 && (\n <ul className=\"divide-y divide-gray-100 rounded-lg border border-gray-200 dark:divide-gray-700 dark:border-gray-700\">\n {awaitingMe.slice(0, 5).map((r) => (\n <li key={r.Id} className=\"truncate px-3 py-2 text-sm text-gray-700 dark:text-gray-200\">\n {r.EmployeeName}\n </li>\n ))}\n </ul>\n )}\n </>\n )}\n <a href={'/admin/list/' + TEAM} className=\"text-sm font-medium text-indigo-600 hover:underline dark:text-indigo-400\">\n {translate('::App.Hr.TeamPerformanceReview')} →\n </a>\n </div>\n </div>\n )\n}\n\nexport default TeamPerformanceWidget",
|
||||
"Props": null,
|
||||
"DataSources": [],
|
||||
"SeoTitle": null,
|
||||
"SeoDescription": null,
|
||||
"SeoKeywords": null,
|
||||
"SeoOgImage": null,
|
||||
"SeoCanonicalUrl": null,
|
||||
"SeoNoIndex": true,
|
||||
"SeoIncludeInSitemap": false,
|
||||
"SeoChangeFrequency": null,
|
||||
"SeoPriority": null,
|
||||
"SeoStructuredData": null
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"ListFormCode": "App.DeveloperKit.CustomComponents",
|
||||
"KeyFieldName": "Id",
|
||||
"GeneratedAt": "2026-10-04T13:55:55Z",
|
||||
"Order": 0,
|
||||
"Rows": [
|
||||
{
|
||||
"Id": "d669129d-52fe-56e1-972d-d20fe1b3360e",
|
||||
"Name": "My360FeedbackWidget",
|
||||
"RoutePath": null,
|
||||
"Description": "Intranet panosu: kullanıcıya atanan 360 derece değerlendirme talepleri",
|
||||
"IsActive": true,
|
||||
"Dependencies": [],
|
||||
"Code": "// Kullaniciya degerlendirici olarak atanan 360 talepleri. Satirlar ekranin sorgusundan gelir\n// (ReviewerId = oturum acan kullanici).\nconst FEEDBACK = 'App.Hr.My360Feedback'\n\nconst Stat = ({ label, value, children }) => (\n <div className=\"flex items-center gap-3 rounded-lg border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-900/40\">\n {children}\n <div className=\"min-w-0\">\n <div className=\"text-lg font-semibold text-gray-900 dark:text-white\">{value}</div>\n <div className=\"truncate text-xs text-gray-500 dark:text-gray-400\">{label}</div>\n </div>\n </div>\n)\n\nconst My360FeedbackWidget = () => {\n const [rows, setRows] = useState([])\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let active = true\n apiService\n .fetchData({\n method: 'GET',\n url: '/api/app/list-form-select/select',\n params: { listFormCode: FEEDBACK, take: 500 },\n })\n .then((response) => active && setRows(response.data?.data ?? []))\n .catch(() => {})\n .finally(() => active && setLoading(false))\n return () => {\n active = false\n }\n }, [])\n\n const pending = rows.filter((r) => r.Status === 'Pending').length\n const submitted = rows.filter((r) => r.Status === 'Submitted').length\n\n return (\n <div className=\"overflow-hidden rounded-xl border border-gray-200/50 bg-white shadow-lg dark:border-gray-700/50 dark:bg-gray-800\">\n <div className=\"flex items-center gap-2 border-b border-gray-200 p-4 dark:border-gray-700\">\n <PlatformIcon name=\"FaComments\" className=\"h-5 w-5 text-indigo-500\" />\n <h2 className=\"text-base font-semibold text-gray-900 dark:text-white\">\n {translate('::App.DashboardWidget.My360Feedback')}\n </h2>\n </div>\n <div className=\"space-y-3 p-3\">\n {loading ? (\n <div className=\"p-4 text-center text-sm text-gray-500\">...</div>\n ) : rows.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-gray-500 dark:text-gray-400\">\n {translate('::App.DashboardWidget.Performance.NoFeedback')}\n </div>\n ) : (\n <div className=\"grid grid-cols-2 gap-2\">\n <Stat label={translate('::App.Hr.Performance.Widget.Pending')} value={pending}>\n <PlatformIcon name=\"FaHourglassHalf\" className=\"h-5 w-5 text-amber-500\" />\n </Stat>\n <Stat label={translate('::App.Hr.Performance.Widget.Submitted')} value={submitted}>\n <PlatformIcon name=\"FaPaperPlane\" className=\"h-5 w-5 text-green-500\" />\n </Stat>\n </div>\n )}\n <a href={'/admin/list/' + FEEDBACK} className=\"text-sm font-medium text-indigo-600 hover:underline dark:text-indigo-400\">\n {translate('::App.Hr.My360Feedback')} →\n </a>\n </div>\n </div>\n )\n}\n\nexport default My360FeedbackWidget",
|
||||
"Props": null,
|
||||
"DataSources": [],
|
||||
"SeoTitle": null,
|
||||
"SeoDescription": null,
|
||||
"SeoKeywords": null,
|
||||
"SeoOgImage": null,
|
||||
"SeoCanonicalUrl": null,
|
||||
"SeoNoIndex": true,
|
||||
"SeoIncludeInSitemap": false,
|
||||
"SeoChangeFrequency": null,
|
||||
"SeoPriority": null,
|
||||
"SeoStructuredData": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -80,6 +80,45 @@
|
|||
"Order": 60,
|
||||
"Props": "",
|
||||
"IsActive": true
|
||||
},
|
||||
{
|
||||
"Id": "26f94212-126d-5b99-b7a6-e4126ca9b78c",
|
||||
"Code": "my-performance",
|
||||
"Name": "My Performance",
|
||||
"LabelKey": "App.DashboardWidget.MyPerformance",
|
||||
"SourceType": 1,
|
||||
"ComponentName": "MyPerformanceWidget",
|
||||
"PermissionName": "App.Hr.MyPerformanceReview",
|
||||
"Column": 2,
|
||||
"Order": 70,
|
||||
"Props": "",
|
||||
"IsActive": true
|
||||
},
|
||||
{
|
||||
"Id": "dfaa5f03-0021-5b1f-b24c-6d72eeef66f7",
|
||||
"Code": "team-performance",
|
||||
"Name": "Team Performance",
|
||||
"LabelKey": "App.DashboardWidget.TeamPerformance",
|
||||
"SourceType": 1,
|
||||
"ComponentName": "TeamPerformanceWidget",
|
||||
"PermissionName": "App.Hr.TeamPerformanceReview",
|
||||
"Column": 2,
|
||||
"Order": 80,
|
||||
"Props": "",
|
||||
"IsActive": true
|
||||
},
|
||||
{
|
||||
"Id": "bf1abaa4-42a6-55f2-adae-cdd113ab7f19",
|
||||
"Code": "my-360-feedback",
|
||||
"Name": "My 360 Requests",
|
||||
"LabelKey": "App.DashboardWidget.My360Feedback",
|
||||
"SourceType": 1,
|
||||
"ComponentName": "My360FeedbackWidget",
|
||||
"PermissionName": "App.Hr.My360Feedback",
|
||||
"Column": 2,
|
||||
"Order": 90,
|
||||
"Props": "",
|
||||
"IsActive": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
63
configs/seeds/host/data/App.Hr.PerformanceRating.json
Normal file
63
configs/seeds/host/data/App.Hr.PerformanceRating.json
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"ListFormCode": "App.Hr.PerformanceRating",
|
||||
"KeyFieldName": "Id",
|
||||
"GeneratedAt": "2026-10-04T11:00:00Z",
|
||||
"Order": 10,
|
||||
"Rows": [
|
||||
{
|
||||
"Id": "0f576c94-f2dd-5a23-b25d-7dd963fd2e9d",
|
||||
"Level": 1,
|
||||
"Name": "Beklentinin Çok Altında",
|
||||
"MinScore": 0,
|
||||
"MaxScore": 50,
|
||||
"Color": "#dc2626",
|
||||
"TargetDistribution": 5,
|
||||
"Description": "Hedeflerin ve yetkinlik beklentilerinin belirgin şekilde altında; gelişim planı zorunludur.",
|
||||
"IsActive": true
|
||||
},
|
||||
{
|
||||
"Id": "9c313f68-f28e-5342-bf7d-3f61174efcb8",
|
||||
"Level": 2,
|
||||
"Name": "Geliştirilmeli",
|
||||
"MinScore": 50,
|
||||
"MaxScore": 70,
|
||||
"Color": "#f97316",
|
||||
"TargetDistribution": 15,
|
||||
"Description": "Beklentilerin bir kısmını karşılıyor; belirli alanlarda gelişim gerekir.",
|
||||
"IsActive": true
|
||||
},
|
||||
{
|
||||
"Id": "36c2303e-528e-566a-906e-8b88165e18f3",
|
||||
"Level": 3,
|
||||
"Name": "Beklenen Düzeyde",
|
||||
"MinScore": 70,
|
||||
"MaxScore": 90,
|
||||
"Color": "#eab308",
|
||||
"TargetDistribution": 60,
|
||||
"Description": "Hedefleri ve yetkinlik beklentilerini karşılıyor.",
|
||||
"IsActive": true
|
||||
},
|
||||
{
|
||||
"Id": "29a47454-8d29-54fd-bdb9-1b16a7d2f189",
|
||||
"Level": 4,
|
||||
"Name": "Beklentinin Üstünde",
|
||||
"MinScore": 90,
|
||||
"MaxScore": 110,
|
||||
"Color": "#22c55e",
|
||||
"TargetDistribution": 15,
|
||||
"Description": "Hedeflerin ve beklentilerin üzerinde performans.",
|
||||
"IsActive": true
|
||||
},
|
||||
{
|
||||
"Id": "57437b59-a8b5-5545-9473-cac4f02d36af",
|
||||
"Level": 5,
|
||||
"Name": "Olağanüstü",
|
||||
"MinScore": 110,
|
||||
"MaxScore": 1000,
|
||||
"Color": "#2563eb",
|
||||
"TargetDistribution": 5,
|
||||
"Description": "Hedefleri belirgin şekilde aşan, örnek gösterilen performans.",
|
||||
"IsActive": true
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1925,113 +1925,243 @@
|
|||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr",
|
||||
"Id": "3651b5de-4588-4632-9ce1-35352059e2e2",
|
||||
"Code": "App.Hr.Recruitment",
|
||||
"DisplayName": "App.Hr.Recruitment",
|
||||
"Order": 12,
|
||||
"Url": null,
|
||||
"Icon": "FcManager",
|
||||
"ParentCode": "App.Hr",
|
||||
"RequiredPermissionName": null,
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Definitions",
|
||||
"Id": "1b88ddd5-4875-442c-91e6-25f49f4bda05",
|
||||
"Code": "App.Hr.CandidateSource",
|
||||
"DisplayName": "App.Hr.CandidateSource",
|
||||
"Order": 13,
|
||||
"Url": "/admin/list/App.Hr.CandidateSource",
|
||||
"Icon": "FcFeedback",
|
||||
"ParentCode": "App.Hr.Definitions",
|
||||
"RequiredPermissionName": "App.Hr.CandidateSource",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Definitions",
|
||||
"Id": "f44ad474-e089-4852-b069-98856e791330",
|
||||
"Code": "App.Hr.RejectionReason",
|
||||
"DisplayName": "App.Hr.RejectionReason",
|
||||
"Order": 14,
|
||||
"Url": "/admin/list/App.Hr.RejectionReason",
|
||||
"Icon": "FcCancel",
|
||||
"ParentCode": "App.Hr.Definitions",
|
||||
"RequiredPermissionName": "App.Hr.RejectionReason",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Definitions",
|
||||
"Id": "b4717d28-e5ee-44ee-8219-472f85450bdf",
|
||||
"Code": "App.Hr.EvaluationCriterion",
|
||||
"DisplayName": "App.Hr.EvaluationCriterion",
|
||||
"Order": 15,
|
||||
"Url": "/admin/list/App.Hr.EvaluationCriterion",
|
||||
"Icon": "FcRating",
|
||||
"ParentCode": "App.Hr.Definitions",
|
||||
"RequiredPermissionName": "App.Hr.EvaluationCriterion",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"Id": "fc5b96b5-d927-4a5b-88ec-4521d99c79f9",
|
||||
"Code": "App.Hr.Interview",
|
||||
"DisplayName": "App.Hr.Interview",
|
||||
"Order": 5,
|
||||
"Url": "/admin/list/App.Hr.Interview",
|
||||
"Icon": "FcVideoCall",
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"RequiredPermissionName": "App.Hr.Interview",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"Id": "89e04aa5-f2e7-45a5-bfb5-6872912a6b10",
|
||||
"Code": "App.Hr.JobOffer",
|
||||
"DisplayName": "App.Hr.JobOffer",
|
||||
"Order": 6,
|
||||
"Url": "/admin/list/App.Hr.JobOffer",
|
||||
"Icon": "FcApproval",
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"RequiredPermissionName": "App.Hr.JobOffer",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"Id": "1f2fe9c5-2894-4932-8650-9cebc5b60535",
|
||||
"Code": "App.Hr.JobApplication",
|
||||
"DisplayName": "App.Hr.JobApplication",
|
||||
"Order": 4,
|
||||
"Url": "/admin/list/App.Hr.JobApplication",
|
||||
"Icon": "FcFlowChart",
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"RequiredPermissionName": "App.Hr.JobApplication",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"Id": "af1259e3-8f9e-4618-8dbd-5b0ed76e8dcc",
|
||||
"Code": "App.Hr.Candidate",
|
||||
"DisplayName": "App.Hr.Candidate",
|
||||
"Order": 3,
|
||||
"Url": "/admin/list/App.Hr.Candidate",
|
||||
"Icon": "FcPortraitMode",
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"RequiredPermissionName": "App.Hr.Candidate",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"Id": "5e25a5c3-c774-4e8c-b24b-513b979ba5c1",
|
||||
"Code": "App.Hr.JobPosting",
|
||||
"DisplayName": "App.Hr.JobPosting",
|
||||
"Order": 2,
|
||||
"Url": "/admin/list/App.Hr.JobPosting",
|
||||
"Icon": "FcAdvertising",
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"RequiredPermissionName": "App.Hr.JobPosting",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"Id": "e9899592-d782-4bf4-886f-857daf429704",
|
||||
"Code": "App.Hr.StaffRequest",
|
||||
"DisplayName": "App.Hr.StaffRequest",
|
||||
"Order": 1,
|
||||
"Url": "/admin/list/App.Hr.StaffRequest",
|
||||
"Icon": "FcPlanner",
|
||||
"ParentCode": "App.Hr.Recruitment",
|
||||
"RequiredPermissionName": "App.Hr.StaffRequest",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"Id": "bb024457-3b43-4f1f-af1c-733310506390",
|
||||
"Code": "App.Hr.PerformanceRating",
|
||||
"DisplayName": "App.Hr.PerformanceRating",
|
||||
"Order": 16,
|
||||
"Url": "/admin/list/App.Hr.PerformanceRating",
|
||||
"Icon": "FcRating",
|
||||
"ParentCode": "App.Hr.Definitions",
|
||||
"RequiredPermissionName": "App.Hr.PerformanceRating",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"Id": "3dc572da-bad3-4fab-991c-0fc7e1d0cded",
|
||||
"Code": "App.Hr.Performance",
|
||||
"DisplayName": "App.Hr.Performance",
|
||||
"Order": 13,
|
||||
"Url": null,
|
||||
"Icon": "FcBullish",
|
||||
"ParentCode": "App.Hr",
|
||||
"RequiredPermissionName": null,
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"Id": "4f47275a-3af8-42b4-a7cd-5f176f112721",
|
||||
"Code": "App.Hr.PerformancePeriod",
|
||||
"DisplayName": "App.Hr.PerformancePeriod",
|
||||
"Order": 1,
|
||||
"Url": "/admin/list/App.Hr.PerformancePeriod",
|
||||
"Icon": "FcCalendar",
|
||||
"ParentCode": "App.Hr.Performance",
|
||||
"RequiredPermissionName": "App.Hr.PerformancePeriod",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"Id": "fcb6d389-df5a-4f9f-a18c-d91373ae08bb",
|
||||
"Code": "App.Hr.PerformanceReview",
|
||||
"DisplayName": "App.Hr.PerformanceReview",
|
||||
"Order": 4,
|
||||
"Url": "/admin/list/App.Hr.PerformanceReview",
|
||||
"Icon": "FcInspection",
|
||||
"ParentCode": "App.Hr.Performance",
|
||||
"RequiredPermissionName": "App.Hr.PerformanceReview",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"Id": "f789d211-3bc6-4b13-bf92-7deb6b8cb40c",
|
||||
"Code": "App.Hr.PerformanceCalibration",
|
||||
"DisplayName": "App.Hr.PerformanceCalibration",
|
||||
"Order": 3,
|
||||
"Url": "/admin/list/App.Hr.PerformanceCalibration",
|
||||
"Icon": "FcComboChart",
|
||||
"ParentCode": "App.Hr.Performance",
|
||||
"RequiredPermissionName": "App.Hr.PerformanceCalibration",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
},
|
||||
{
|
||||
"Id": "b1e055bd-3373-48ba-a4f4-2b3a0202f843",
|
||||
"Code": "App.Hr.DevelopmentPlan",
|
||||
"DisplayName": "App.Hr.DevelopmentPlan",
|
||||
"Order": 2,
|
||||
"Url": "/admin/list/App.Hr.DevelopmentPlan",
|
||||
"Icon": "FcBullish",
|
||||
"ParentCode": "App.Hr.Performance",
|
||||
"RequiredPermissionName": "App.Hr.DevelopmentPlan",
|
||||
"CssClass": null,
|
||||
"Target": null,
|
||||
"IsDisabled": false,
|
||||
"ElementId": null,
|
||||
"ModuleId": "Hr"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -73,6 +73,46 @@
|
|||
"IsActive": true,
|
||||
"IsFixed": false,
|
||||
"IsCustomized": false
|
||||
},
|
||||
{
|
||||
"Id": "bd231ab9-6aa6-5396-9cb3-37d815c3423a",
|
||||
"NotificationTypeId": "6e4559f1-9cd2-5f6a-a768-a355be2c4cbe",
|
||||
"RecipientType": "Custom",
|
||||
"RecipientId": null,
|
||||
"Channel": "UiActivity",
|
||||
"IsActive": true,
|
||||
"IsFixed": false,
|
||||
"IsCustomized": false
|
||||
},
|
||||
{
|
||||
"Id": "88653d05-a78d-590e-99be-382b0255b9ff",
|
||||
"NotificationTypeId": "6e4559f1-9cd2-5f6a-a768-a355be2c4cbe",
|
||||
"RecipientType": "Custom",
|
||||
"RecipientId": null,
|
||||
"Channel": "UiToast",
|
||||
"IsActive": true,
|
||||
"IsFixed": false,
|
||||
"IsCustomized": false
|
||||
},
|
||||
{
|
||||
"Id": "47278cfc-a438-5f5c-acb6-aa4dc9553a7f",
|
||||
"NotificationTypeId": "cd6e4aed-f460-5af3-ab18-c3baa33a0a03",
|
||||
"RecipientType": "Custom",
|
||||
"RecipientId": null,
|
||||
"Channel": "UiActivity",
|
||||
"IsActive": true,
|
||||
"IsFixed": false,
|
||||
"IsCustomized": false
|
||||
},
|
||||
{
|
||||
"Id": "7f288026-b1da-5b7c-ae19-6a9fd80e1db1",
|
||||
"NotificationTypeId": "cd6e4aed-f460-5af3-ab18-c3baa33a0a03",
|
||||
"RecipientType": "Custom",
|
||||
"RecipientId": null,
|
||||
"Channel": "UiToast",
|
||||
"IsActive": true,
|
||||
"IsFixed": false,
|
||||
"IsCustomized": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,16 @@
|
|||
"Id": "de4c139f-dfa3-5bea-8a49-b3658e74336b",
|
||||
"Name": "IseAlimMulakatAtandi",
|
||||
"Description": "İşe alımda bir mülakat planlandığında mülakatçıya gider. Alıcı mülakat kaydındaki mülakatçıdır; bu tipin Custom kuralları yalnızca kanalı belirler (Mülakatlar ekranının ekleme sonrası komutu yazar)."
|
||||
},
|
||||
{
|
||||
"Id": "6e4559f1-9cd2-5f6a-a768-a355be2c4cbe",
|
||||
"Name": "PerformansDurumDegisti",
|
||||
"Description": "Performans değerlendirmesi aşama değiştirdiğinde (hedef belirleme, öz değerlendirme, yönetici değerlendirmesi, tamamlandı) ilgili çalışana ve yöneticisine gider. Alıcı değerlendirme kaydından gelir; bu tipin Custom kuralları yalnızca kanalı belirler (Hr_S_PerformanceReviewAfterSave / Hr_S_PerformancePeriodActivate yazar)."
|
||||
},
|
||||
{
|
||||
"Id": "cd6e4aed-f460-5af3-ab18-c3baa33a0a03",
|
||||
"Name": "Performans360Talebi",
|
||||
"Description": "Bir değerlendirmeye 360 derece değerlendirici eklendiğinde değerlendiriciye gider. Alıcı geri bildirim kaydındaki değerlendiricidir; bu tipin Custom kuralları yalnızca kanalı belirler (Hr_S_PerformanceFeedbackOpen yazar)."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
342
configs/seeds/host/docs/modules/HrDefinitions.md
Normal file
342
configs/seeds/host/docs/modules/HrDefinitions.md
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
# İK › Tanımlamalar (`App.Hr.Definitions`)
|
||||
|
||||
İK modüllerinin ortak sözlükleri. Bu doküman iki işi görür: (1) Tanımlamalar menüsünün **dizinidir**
|
||||
— her tanımın hangi modüle ait olduğunu ve nerede kullanıldığını gösterir; (2) belirli bir modüle ait
|
||||
olmayan genel tanımları (kurum doktoru, yeterlilik belgesi, hastane, hastane bölümü, evrak türü, izin
|
||||
türü, masraf türü, yan hak türü) anlatır.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Dizin
|
||||
|
||||
`İnsan Kaynakları › Tanımlamalar` (`App.Hr.Definitions`, ikon `FcFilingCabinet`)
|
||||
|
||||
| Sıra | Menü | `ListFormCode` | Kaynak | Ayrıntı |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Yetenek Tipleri | `App.Hr.SkillType` | Entity + seeder | [HrOrganization.md](HrOrganization.md) |
|
||||
| 2 | Departmanlar | `App.Hr.Department` | Entity + seeder | [HrOrganization.md](HrOrganization.md) |
|
||||
| 3 | Pozisyonlar | `App.Hr.JobPosition` | Entity + seeder | [HrOrganization.md](HrOrganization.md) |
|
||||
| 4 | Kurum Doktorları | `App.Hr.Doctor` | Wizard | bu doküman · [HrHealthCard.md](HrHealthCard.md) |
|
||||
| 5 | Yeterlilik Belgeleri | `App.Hr.Certificate` | Wizard | bu doküman |
|
||||
| 6 | Hastaneler | `App.Hr.Hospital` | Wizard | bu doküman · [HrHealthCard.md](HrHealthCard.md) |
|
||||
| 7 | Hastane Bölümleri | `App.Hr.HospitalDepartment` | Wizard | bu doküman · [HrHealthCard.md](HrHealthCard.md) |
|
||||
| 8 | Evrak Türleri | `App.Hr.DocumentType` | Wizard | bu doküman |
|
||||
| 9 | İzin Türleri | `App.Hr.LeaveType` | Wizard | bu doküman |
|
||||
| 10 | Masraf Türleri | `App.Hr.ExpenseType` | Wizard | bu doküman |
|
||||
| 11 | Yan Hak Türleri | `App.Hr.BenefitType` | Wizard | bu doküman |
|
||||
| 12 | Ceza Türleri | `App.Hr.DisciplinaryPenaltyType` | Wizard | [HrDisciplinaryCase.md](HrDisciplinaryCase.md) |
|
||||
| 13 | Aday Kaynakları | `App.Hr.CandidateSource` | Wizard | [HrRecruitment.md](HrRecruitment.md) |
|
||||
| 14 | Ret Sebepleri | `App.Hr.RejectionReason` | Wizard | [HrRecruitment.md](HrRecruitment.md) |
|
||||
| 15 | Değerlendirme Kriterleri | `App.Hr.EvaluationCriterion` | Wizard | [HrRecruitment.md](HrRecruitment.md) |
|
||||
| 16 | Performans Dereceleri | `App.Hr.PerformanceRating` | Wizard | [HrPerformance.md](HrPerformance.md) |
|
||||
|
||||
Tanımlamalar dışında duran tanımlar: Eğitim tipi/konusu → [HrTrainings.md](HrTrainings.md); araç
|
||||
belgesi/masrafı/gidilecek yer → [HrVehicles.md](HrVehicles.md); çalışma takvimi ve vardiya →
|
||||
[HrWorkCalendar.md](HrWorkCalendar.md).
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar (genel tanımlar)
|
||||
|
||||
> §0.13 kuralından önce üretildiler; keşif turu kaydı yoktur. Kararlar wizard ve seed dosyalarından okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Her tanım tek Wizard liste ekranı; veri seed dosyasına **aynalanır** (`SeedFilePath = data/App.Hr.{Kod}.json`, ekle/güncelle/sil senkron). Ekrandan yapılan değişiklik dosyaya yazılır, DB sıfırlanınca geri gelir |
|
||||
| Aktif/Pasif | Hepsinde `IsActive` (varsayılan aktif); lookup'lar çoğunlukla yalnız aktifleri listeler |
|
||||
| Kod alanı | İzin, masraf ve yan hak türlerinde iş kodu (`Code`, ör. `Annual`, `Meal`) ayrıca tutulur; yan hak kodu teklifte saklanan değerdir |
|
||||
| Hazırlık tanımları | İzin türü ve masraf türü **henüz bir talep ekranına bağlı değildir** — ileride izin/masraf talep ekranlarının (onaylı talep kalıbı, `lowcode.instructions.md` §10.7) kaynağı olmak üzere tanımlanmıştır. Hastane ve hastane bölümü de şu an kullanılmıyor |
|
||||
|
||||
---
|
||||
|
||||
## 3. Ekranlar
|
||||
|
||||
Hepsi Grid, Card, Pivot, Chart görünümlüdür.
|
||||
|
||||
| Ekran | Alanlar | Widget'lar | Seed |
|
||||
| --- | --- | --- | --- |
|
||||
| Kurum Doktorları | Ad soyad*, diploma no/tarihi, işyeri hekimi belge no/tarihi, T.C. kimlik no, aktif | Toplam · Aktif · Pasif | 1 |
|
||||
| Yeterlilik Belgeleri | Belge adı*, aktif | Toplam · Aktif · Pasif | 16 (operatör belgeleri, kaynakçı, SRC 4, forklift, mezuniyet belgeleri, çıraklık-ustalık…) |
|
||||
| Hastaneler | Kurum adı*, aktif | Toplam · Aktif · Pasif | 45 |
|
||||
| Hastane Bölümleri | Bölüm adı*, aktif | Toplam · Aktif · Pasif | 31 |
|
||||
| Evrak Türleri | Dosya grubu* (Genel / Özlük Evrakları / Sağlık), dosya türü*, zorunlu, aktif | Toplam · Aktif · Pasif · Zorunlu | 48 |
|
||||
| İzin Türleri | Kod*, ad*, cinsiyet* (All/Male/Female), yıllık en fazla gün, ücretli, yıllık izinden düşer, belge gerekir, yarım gün kullanılabilir, aktif | Toplam · Ücretli · Ücretsiz | 9 (Yıllık, Mazeret, Ücretsiz, Hastalık, Doğum 112 gün, Babalık 5, Evlilik 3, Ölüm 3, Süt) |
|
||||
| Masraf Türleri | Kod*, ad*, varsayılan tutar, para birimi, gelir vergisine tabi, SGK'ya tabi, fiş/belge gerekir, aktif | Toplam · Aktif · Pasif | 7 (yemek, yol, konaklama, akaryakıt, telefon, temsil, kırtasiye) |
|
||||
| Yan Hak Türleri | Kod*, ad*, varsayılan tutar, para birimi, gelir vergisine tabi, SGK'ya tabi, aktif | Toplam · Aktif · Pasif | 10 (yemek kartı, ulaşım, özel sağlık sigortası, BES, konut, şirket aracı, telefon, çocuk, yakacak, diğer) |
|
||||
|
||||
`*` zorunlu. Varsayılanlar: izin türünde ücretli = evet, yıllık izinden düşer/belge/yarım gün = hayır,
|
||||
cinsiyet = Tümü; masraf ve yan hakta para birimi TRY, vergi/SGK = hayır, masrafta fiş gerekir = evet.
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
Tablolar `sql/object/Hr_T_{Doctor,Certificate,Hospital,HospitalDepartment,DocumentType,LeaveType,ExpenseType,BenefitType}.sql`
|
||||
(entity yok); kiracı + audit + `IsActive`. Kolonlar §3'teki alanlarla aynıdır. Tablo düzeyinde tekil
|
||||
kısıt yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları
|
||||
|
||||
Hesap yoktur; yalnız form varsayılanları (§3). Seed dosyası aynalandığı için tanımlar ekrandan
|
||||
değiştirildiğinde `configs/seeds/host/data/App.Hr.*.json` dosyası da değişir — bu dosyalar commit'lenmelidir.
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. Her tanımın kökü + `.Create/.Update/.Delete/.Export/.Import/.Note`,
|
||||
hepsi `App.Hr.Definitions` ara yetkisinin altında. Tanım ekranlarının yazma yetkisi İK'da kalmalıdır;
|
||||
lookup olarak okunmaları ekran yetkisi gerektirmez. Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar (kim kullanıyor)
|
||||
|
||||
| Tanım | Kullanan |
|
||||
| --- | --- |
|
||||
| Kurum Doktorları | Sağlık Kartı (periyodik muayene, protokol, sonuç hekimleri) |
|
||||
| Yeterlilik Belgeleri | Kullanıcı detayı › Eğitim ve Yetkinlik (`UserCertificate`), Performans gelişim planı (sertifika aksiyonu) |
|
||||
| Evrak Türleri | Eğitim dosyaları, Disiplin belgeleri |
|
||||
| Yan Hak Türleri | İşe Alım › Teklif (`BenefitCodes`, kod ile) |
|
||||
| Hastaneler, Hastane Bölümleri, İzin Türleri, Masraf Türleri | Henüz kullanan ekran yok |
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. İK yeni bir yan hak tanımlar: kod `Gym`, ad "Spor Salonu Üyeliği", varsayılan tutar 1.500 TRY, gelir vergisine tabi.
|
||||
2. Kayıt `data/App.Hr.BenefitType.json` dosyasına da yazılır.
|
||||
3. İşe Alım › Teklif formundaki **Yan Haklar** listesinde yeni hak seçilebilir.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar
|
||||
|
||||
**Pasif yaptığım tanım listelerden kayboldu.** Lookup'lar yalnız aktif kayıtları listeler; eski kayıtlarda değer korunur.
|
||||
|
||||
**İzin talebi nereden girilir?** Henüz izin/masraf talep ekranı yoktur; türler tanım olarak hazırdır.
|
||||
|
||||
**Evrak Türleri "özlük dosyası" diyor ama özlük dosyası ekranı yok.** Doğru; türler şu an eğitim ve disiplin belgelerinde kullanılır.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_{Doctor,Certificate,Hospital,HospitalDepartment,DocumentType,LeaveType,ExpenseType,BenefitType}.sql` | Tablolar |
|
||||
| `configs/seeds/host/wizard/{Doctor,Certificate,Hospital,HospitalDepartment,DocumentType,LeaveType,ExpenseType,BenefitType}.json` | 8 wizard |
|
||||
| `configs/seeds/host/data/App.Hr.{Doctor,Certificate,Hospital,HospitalDepartment,DocumentType,LeaveType,ExpenseType,BenefitType}.json` | Aynalanan tanım verisi |
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Kurum Doktorları — `App.Hr.Doctor`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Doctor.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.Doctor` (sıra 4) |
|
||||
| Yetki | `App.Hr.Doctor` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Kurum Doktorları — işyeri hekimleri ve belge bilgileri. |
|
||||
| Geliştirme talebi | Human Resources -> Definitions |
|
||||
| Kaynak | `Hr_T_Doctor` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (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.Hr.Doctor.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `FullName` | Doktor Adı Soyadı | dxTextBox | ✓ | ✓ | |
|
||||
| `DiplomaNo` | Diploma No | dxTextBox | | ✓ | |
|
||||
| `DiplomaDate` | Diploma Tarihi | dxDateBox | | ✓ | |
|
||||
| `OhsCertificateNo` | İşyeri Hekimi Belge No | dxTextBox | | ✓ | |
|
||||
| `OhsCertificateDate` | İşyeri Hekimi Belge Tarihi | dxDateBox | | ✓ | |
|
||||
| `IdentityNo` | T.C. Kimlik No | dxTextBox | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Yeterlilik Belgeleri — `App.Hr.Certificate`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Certificate.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.Certificate` (sıra 5) |
|
||||
| Yetki | `App.Hr.Certificate` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Yeterlilik Belgeleri — personelin sahip olabileceği mesleki yeterlilik ve mezuniyet belgeleri. |
|
||||
| Geliştirme talebi | Human Resources -> Definitions |
|
||||
| Kaynak | `Hr_T_Certificate` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (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.Hr.Certificate.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Belge Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Hastaneler — `App.Hr.Hospital`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Hospital.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.Hospital` (sıra 6) |
|
||||
| Yetki | `App.Hr.Hospital` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Hastaneler — hastane ve sağlık kurumu tanımları. |
|
||||
| Geliştirme talebi | Human Resources -> Definitions |
|
||||
| Kaynak | `Hr_T_Hospital` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (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.Hr.Hospital.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Kurum Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Hastane Bölümleri — `App.Hr.HospitalDepartment`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HospitalDepartment.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.HospitalDepartment` (sıra 7) |
|
||||
| Yetki | `App.Hr.HospitalDepartment` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Hastane Bölümleri — hastane klinik/bölüm tanımları (acil, dahiliye, kardiyoloji…). |
|
||||
| Geliştirme talebi | Human Resources -> Definitions |
|
||||
| Kaynak | `Hr_T_HospitalDepartment` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (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.Hr.HospitalDepartment.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Bölüm Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Evrak Türleri — `App.Hr.DocumentType`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DocumentType.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.DocumentType` (sıra 8) |
|
||||
| Yetki | `App.Hr.DocumentType` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Evrak Türleri — personel ve süreç belgelerinin türleri (CV, dilekçe, ibraname, sağlık raporu…), gruplarıyla. |
|
||||
| Geliştirme talebi | Human Resources -> Definitions |
|
||||
| Kaynak | `Hr_T_DocumentType` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive`, `App.Listform.ListformField.IsRequired` |
|
||||
| Veri aynası | `data/App.Hr.DocumentType.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `GroupName` | Dosya Grubu | dxSelectBox | ✓ | ✓ | liste: Genel, Özlük Evrakları, Sağlık |
|
||||
| `Name` | Dosya Türü | dxTextBox | ✓ | ✓ | |
|
||||
| `IsRequired` | Zorunlu | dxCheckBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### İzin Türleri — `App.Hr.LeaveType`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/LeaveType.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.LeaveType` (sıra 9) |
|
||||
| Yetki | `App.Hr.LeaveType` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | İzin Türleri — izin çeşitleri ve kuralları (yıllık, mazeret, ücretsiz, hastalık, doğum, babalık, evlilik, ölüm, süt izni). |
|
||||
| Kaynak | `Hr_T_LeaveType` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Paid`, `App.Widget.Unpaid` |
|
||||
| Form varsayılanları | IsPaid=true, DeductsFromAnnualLeave=false, RequiresDocument=false, AllowHalfDay=false, Gender=All, IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.LeaveType.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Code` | Kod | dxTextBox | ✓ | ✓ | |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `Gender` | Cinsiyet | dxSelectBox | ✓ | ✓ | liste: All, Male, Female |
|
||||
| `MaxDaysPerYear` | Yıllık En Fazla Gün | dxNumberBox | | ✓ | |
|
||||
| `IsPaid` | Ücretli | dxCheckBox | ✓ | ✓ | |
|
||||
| `DeductsFromAnnualLeave` | Yıllık İzinden Düşer | dxCheckBox | ✓ | ✓ | |
|
||||
| `RequiresDocument` | Belge Gerekir | dxCheckBox | ✓ | ✓ | |
|
||||
| `AllowHalfDay` | Yarım Gün Kullanılabilir | dxCheckBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Masraf Türleri — `App.Hr.ExpenseType`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/ExpenseType.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.ExpenseType` (sıra 10) |
|
||||
| Yetki | `App.Hr.ExpenseType` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Masraf Türleri — personel masraf kalemleri (yemek, yol, konaklama, akaryakıt, telefon, temsil, kırtasiye) ve vergi/SGK özellikleri. |
|
||||
| Kaynak | `Hr_T_ExpenseType` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | CurrencyId=TRY, IsTaxable=false, IsSgkSubject=false, RequiresReceipt=true, IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.ExpenseType.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Code` | Kod | dxTextBox | ✓ | ✓ | |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `DefaultAmount` | Varsayılan Tutar | dxNumberBox | | ✓ | |
|
||||
| `CurrencyId` | Para Birimi | dxSelectBox | | ✓ | sorgu: Sas_H_Currency |
|
||||
| `IsTaxable` | Gelir Vergisine Tabi | dxCheckBox | ✓ | ✓ | |
|
||||
| `IsSgkSubject` | SGK'ya Tabi | dxCheckBox | ✓ | ✓ | |
|
||||
| `RequiresReceipt` | Fiş / Belge Gerekir | dxCheckBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Yan Hak Türleri — `App.Hr.BenefitType`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/BenefitType.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.BenefitType` (sıra 11) |
|
||||
| Yetki | `App.Hr.BenefitType` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Yan Hak Türleri — çalışanlara sağlanan yan haklar (yemek kartı, ulaşım, özel sağlık sigortası, BES, konut, şirket aracı, telefon, çocuk ve yakacak yardımı…). |
|
||||
| Kaynak | `Hr_T_BenefitType` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | CurrencyId=TRY, IsTaxable=false, IsSgkSubject=false, IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.BenefitType.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Code` | Kod | dxTextBox | ✓ | ✓ | |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `DefaultAmount` | Varsayılan Tutar | dxNumberBox | | ✓ | |
|
||||
| `CurrencyId` | Para Birimi | dxSelectBox | | ✓ | sorgu: Sas_H_Currency |
|
||||
| `IsTaxable` | Gelir Vergisine Tabi | dxCheckBox | ✓ | ✓ | |
|
||||
| `IsSgkSubject` | SGK'ya Tabi | dxCheckBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
297
configs/seeds/host/docs/modules/HrDisciplinaryCase.md
Normal file
297
configs/seeds/host/docs/modules/HrDisciplinaryCase.md
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
<!-- module-doc: claims=App.Hr.DisciplinaryPenaltyType -->
|
||||
# İK › Disiplin Dosyaları (`App.Hr.DisciplinaryCase`)
|
||||
|
||||
Personel disiplin süreci: olay tutanağı (personel, tarih/saat/yer, tanıklar, tutanağı tutan) →
|
||||
savunma talebi ve savunma → karar (ceza türü, yürürlük/tebliğ, ücret kesintisi) → belgeler. Tamamı
|
||||
konfigürasyondur (Wizard + SQL); entity, migration ya da React kodu yoktur.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| İK / disiplin kurulu sekreteryası | Dosya açar, tutanağı yazar, savunma ister, savunmayı ve kararı işler, belgeleri yükler, dosyayı kapatır | Disiplin Dosyaları |
|
||||
| Yönetici (tutanağı tutan) | Olayı kaydeder | Disiplin Dosyaları |
|
||||
| İK yöneticisi | Ceza türü tanımlarını yönetir | İK › Tanımlar › Ceza Türleri |
|
||||
|
||||
Kapsam: kiracı (`IsTenant`). Satır süzmesi yoktur; disiplin kaydı hassas veridir, görünürlük yalnızca yetkiyle sınırlanır.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar artefaktlardan (wizard,
|
||||
> SQL, seed, commit `130e23bc` "Disiplin Dosyaları, Çalışma Takvimi") okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Tek menü ekranı (dosya) + üç menüsüz alt form: Savunmalar, Kararlar, Belgeler |
|
||||
| Menü yeri | Dosya ekranı doğrudan `İnsan Kaynakları` kökünde; ceza türü İK › Tanımlar'da |
|
||||
| Dosya durumu | Open → AwaitingDefense → Decided → Closed; **elle** değiştirilir (Todo panosunda sürükleyerek ya da formdan). Savunma/karar girilmesi durumu otomatik değiştirmez |
|
||||
| Savunma süresi | Son savunma tarihi = talep tarihi + **2 gün** (formda önerilir, değiştirilebilir); talep tarihinden önce olamaz |
|
||||
| Ceza türü | Ağırlık (`Severity` 1–5) sırasıyla listelenir; karar ekranında yalnız aktif türler |
|
||||
| Ücret kesintisi | Kararda tutar olarak saklanır; bordroya aktarım yoktur |
|
||||
| Tanıklar | Çok değerli kullanıcı seçimi (`WitnessUserIds`, `dxTagBox`) |
|
||||
| Dosya numarası | `DSP-YYYY-00001` (kiracı + yıl bazında, insert sonrası SQL) |
|
||||
| Onay akışı, bildirim, rapor | Yok |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
| Menü (TR / EN) | `ListFormCode` | Yer | Alt formlar | Görünümler | Widget'lar |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Disiplin Dosyaları / Disciplinary Cases | `App.Hr.DisciplinaryCase` | `İnsan Kaynakları` (sıra 11, `FcHighPriority`) | `DisciplinaryDefense`, `DisciplinaryDecision`, `DisciplinaryFile` (`Id → CaseId`) | Grid, Card, Pivot, Chart, **Todo** | Toplam · Açık · Savunma Bekleniyor · Kapanan (Karara Bağlandı + Kapandı) |
|
||||
| Ceza Türleri / Penalty Types | `App.Hr.DisciplinaryPenaltyType` | `İnsan Kaynakları › Tanımlar` | — | Grid, Card, Pivot, Chart | — (tanım listesi) |
|
||||
|
||||
Todo panosu: başlık `Subject`, açıklama `IncidentDescription`, tarih `IncidentDate`, sütun sırası
|
||||
`Open, AwaitingDefense, Decided, Closed`.
|
||||
|
||||
Seed verisi (`data/App.Hr.DisciplinaryPenaltyType.json`): Sözlü Uyarı (1), Yazılı Uyarı (2), İhtar (3),
|
||||
Kınama (3), Ücret Kesintisi (4), Fesih (5).
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
```
|
||||
AbpUsers ──< Hr_T_DisciplinaryCase ──< Hr_T_DisciplinaryDefense
|
||||
(UserId, ReportedById, ├──< Hr_T_DisciplinaryDecision >── Hr_T_DisciplinaryPenaltyType
|
||||
WitnessUserIds) └──< Hr_T_DisciplinaryFile >── Hr_T_DocumentType
|
||||
```
|
||||
|
||||
| Tablo | Önemli kolonlar |
|
||||
| --- | --- |
|
||||
| `Hr_T_DisciplinaryPenaltyType` | `Name`, `Severity`, `Description`, `IsActive` |
|
||||
| `Hr_T_DisciplinaryCase` | `CaseNo`, `UserId`, `DepartmentId`, `JobPositionId`, `IncidentDate`, `IncidentTime`, `IncidentPlace`, `ReportedById`, `Status`, `Subject`, `IncidentDescription` (HTML tutanak), `WitnessUserIds` |
|
||||
| `Hr_T_DisciplinaryDefense` | `CaseId`, `RequestDate`, `DueDate`, `ResponseDate`, `Status` (Requested/Submitted/NotSubmitted), `DefenseText` |
|
||||
| `Hr_T_DisciplinaryDecision` | `CaseId`, `DecisionDate`, `PenaltyTypeId`, `EffectiveDate`, `NotificationDate`, `DeductionAmount`, `Status` (Draft/Final), `DecisionText` |
|
||||
| `Hr_T_DisciplinaryFile` | `CaseId`, `DocumentTypeId`, `FileDate`, `FileName`, `FileContent` |
|
||||
|
||||
Tablo düzeyinde CHECK ya da tekil indeks yoktur; kurallar formdadır.
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları ve hesaplar
|
||||
|
||||
| Yer | Kural |
|
||||
| --- | --- |
|
||||
| Dosya — yeni kayıt | Olay tarihi bugün, tutanağı tutan oturumdaki kullanıcı, durum `Open` |
|
||||
| Dosya — personel seçimi | Departman ve pozisyon kullanıcı kaydından kopyalanır (olay anındaki hâli saklanır) |
|
||||
| Dosya — insert sonrası | `CaseNo = 'DSP-' + yıl + '-' + 5 hane` (kiracı + yıl içinde `MAX + 1`, yalnız boşsa) |
|
||||
| Savunma — yeni kayıt | Talep tarihi bugün, durum `Requested`, son tarih talep + 2 gün |
|
||||
| Savunma — tarih kontrolü | Son tarih talep tarihinden önceyse uyarı + değişiklik geri alınır |
|
||||
| Karar — yeni kayıt | Karar tarihi bugün, durum `Draft` |
|
||||
| Belge — yeni kayıt | Tarih bugün |
|
||||
|
||||
Tavsiye edilen kullanım sırası: dosya `Open` → savunma istenince `AwaitingDefense` → karar
|
||||
`Final` olunca `Decided` → tebliğ ve belgeler tamamlanınca `Closed`. Bu sıra sistemce zorlanmaz.
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. `App.Hr.DisciplinaryCase` kökü + `.Create/.Update/.Delete/.Export/.Import/.Note`;
|
||||
`DisciplinaryDefense`, `DisciplinaryDecision`, `DisciplinaryFile` onun altındadır. Ceza türü
|
||||
`App.Hr.Definitions` altındadır. Satır süzmesi yoktur. Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
| Rol | Yetkiler |
|
||||
| --- | --- |
|
||||
| İK disiplin sorumlusu | Dosya + üç alt form (tam) + ceza türü |
|
||||
| Tutanak tutan yönetici | `App.Hr.DisciplinaryCase` (+ `.Create`) — ancak bu yetki tüm dosyaları gösterir |
|
||||
|
||||
Disiplin verisi kişisel ve hassas veridir; okuma yetkisi dar tutulmalıdır.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kaynak | Kullanım |
|
||||
| --- | --- |
|
||||
| `AbpUsers` | Personel, tutanağı tutan, tanıklar |
|
||||
| `Hr_T_Department`, `Hr_T_JobPosition` | Olay anındaki birim (Pivot kırılımı) |
|
||||
| `Hr_T_DocumentType` | Belge türü (ortak İK tanımı) |
|
||||
|
||||
Bildirim, onay akışı, rapor şablonu ya da bordro bağlantısı yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. Vardiya amiri **Disiplin Dosyaları**'nda yeni dosya açar: personel seçilir (departman/pozisyon
|
||||
dolar), olay tarihi/saati/yeri, konu, tutanak metni ve tanıklar girilir → `DSP-2026-00001`, durum Açık.
|
||||
2. İK **Savunmalar** sekmesine savunma talebi ekler; son tarih 2 gün sonrası önerilir; dosya panoda
|
||||
**Savunma Bekleniyor**'a çekilir.
|
||||
3. Personel savunmasını verince talep **Savunma Verildi** yapılır, metin ve tarih girilir; verilmezse **Savunma Verilmedi**.
|
||||
4. Kurul kararı **Kararlar** sekmesine girilir: ceza türü Yazılı Uyarı, yürürlük ve tebliğ tarihi, durum **Kesinleşti**; dosya **Karara Bağlandı**.
|
||||
5. İmzalı tutanak, savunma ve tebliğ belgesi **Belgeler** sekmesine yüklenir; dosya **Kapandı** yapılır.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar
|
||||
|
||||
**Savunma/karar girdim, dosya durumu değişmedi.** Durum elle yönetilir; panoda sürükleyin ya da formdan seçin.
|
||||
|
||||
**Son savunma tarihi neden 2 gün sonrası?** Formdaki varsayılan öneridir; değiştirilebilir, yalnızca talep tarihinden önce olamaz.
|
||||
|
||||
**Ücret kesintisi bordroya yansıyor mu?** Hayır; karar kaydında bilgi olarak durur.
|
||||
|
||||
**Tutanak metni listede görünmüyor.** HTML alan listede gizlidir; detayda ve Todo kartında görünür.
|
||||
|
||||
**Bir yöneticinin yalnız kendi tuttuğu dosyaları görmesi mümkün mü?** Şu an değil (satır süzmesi yok). Gerekirse ayrı bir persona ekranı `DefaultFilter` (`"ReportedById" = '@USERID'`) ile açılır (Performans modülündeki kalıp).
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_Disciplinary{PenaltyType,Case,Defense,Decision,File}.sql` | Tablolar |
|
||||
| `configs/seeds/host/wizard/Disciplinary{PenaltyType,Case,Defense,Decision,File}.json` | 5 wizard |
|
||||
| `configs/seeds/host/data/App.Hr.DisciplinaryPenaltyType.json` | Ceza türleri |
|
||||
| `configs/seeds/host/data/App.Menus.Menu.json`, `Abp.Identity.Permissions.json`, `App.Languages.LanguageText.json` | Menü, yetki, dil satırları |
|
||||
|
||||
Kurulum: DB Migrate. Geri alma: Wizard Manager'dan alt formlar (`DisciplinaryDefense`, `DisciplinaryDecision`,
|
||||
`DisciplinaryFile`) önce, sonra `DisciplinaryCase` ve `DisciplinaryPenaltyType` silinir; tablolar
|
||||
yalnızca onayda seçilirse düşer.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Disiplin Dosyaları — `App.Hr.DisciplinaryCase`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DisciplinaryCase.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr` › `App.Hr.DisciplinaryCase` (sıra 11) |
|
||||
| Yetki | `App.Hr.DisciplinaryCase` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Disiplin Dosyaları — bir personel hakkındaki olay tutanağı ile başlayan disiplin süreci: savunma, karar ve belgeler tek dosyada. |
|
||||
| Kaynak | `Hr_T_DisciplinaryCase` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart, Todo (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Alt formlar | `App.Hr.DisciplinaryDefense` (Id → CaseId), `App.Hr.DisciplinaryDecision` (Id → CaseId), `App.Hr.DisciplinaryFile` (Id → CaseId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Hr.DisciplinaryCase.Widget.Open`, `App.Hr.DisciplinaryCase.Widget.AwaitingDefense`, `App.Hr.DisciplinaryCase.Widget.Closed` |
|
||||
| Todo | başlık `Subject`, durum `Status` (Open,AwaitingDefense,Decided,Closed) |
|
||||
| Komutlar | InsertAfter: SQL |
|
||||
| Form varsayılanları | IncidentDate=@DATE, ReportedById=@USERID, Status=Open |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `CaseNo` | Dosya No | dxTextBox | | | |
|
||||
| `UserId` | Personel | dxSelectBox | ✓ | ✓ | sorgu: AbpUsers · script |
|
||||
| `DepartmentId` | Departman | dxSelectBox | | ✓ | sorgu: Hr_T_Department |
|
||||
| `JobPositionId` | Pozisyon | dxSelectBox | | ✓ | sorgu: Hr_T_JobPosition |
|
||||
| `IncidentDate` | Olay Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `IncidentTime` | Olay Saati | dxDateBox | | ✓ | |
|
||||
| `IncidentPlace` | Olay Yeri | dxTextBox | | ✓ | |
|
||||
| `ReportedById` | Tutanağı Tutan | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `Status` | Durum | dxRadioGroup | ✓ | ✓ | liste: Open, AwaitingDefense, Decided, Closed |
|
||||
| `Subject` | Konu | dxTextBox | ✓ | ✓ | |
|
||||
| `IncidentDescription` | Olay Tutanağı | dxHtmlEditor | ✓ | ✓ | |
|
||||
| `WitnessUserIds` | Tanıklar | dxTagBox | | ✓ | sorgu: AbpUsers |
|
||||
|
||||
### Ceza Türleri — `App.Hr.DisciplinaryPenaltyType`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DisciplinaryPenaltyType.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.DisciplinaryPenaltyType` (sıra 12) |
|
||||
| Yetki | `App.Hr.DisciplinaryPenaltyType` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Ceza Türleri — disiplin kararlarında verilebilecek cezalar ve ağırlıkları (sözlü uyarı, yazılı uyarı, ihtar, kınama, ücret kesintisi, fesih). |
|
||||
| Kaynak | `Hr_T_DisciplinaryPenaltyType` · 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ı | Severity=1, IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.DisciplinaryPenaltyType.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Ad | dxTextBox | ✓ | ✓ | |
|
||||
| `Severity` | Ağırlık | dxNumberBox | ✓ | ✓ | |
|
||||
| `Description` | Açıklama | dxTextArea | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Savunmalar — `App.Hr.DisciplinaryDefense`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DisciplinaryDefense.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.DisciplinaryDefense` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Savunmalar — disiplin dosyası için personelden istenen savunma ve verilen cevap. |
|
||||
| Kaynak | `Hr_T_DisciplinaryDefense` · 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ı | RequestDate=@DATE, Status=Requested |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `CaseId` | Disiplin Dosyası | dxTextBox | | | |
|
||||
| `RequestDate` | Talep Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `DueDate` | Son Savunma Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `ResponseDate` | Savunma Tarihi | dxDateBox | | ✓ | |
|
||||
| `Status` | Durum | dxRadioGroup | ✓ | ✓ | liste: Requested, Submitted, NotSubmitted |
|
||||
| `DefenseText` | Savunma Metni | dxTextArea | | ✓ | |
|
||||
|
||||
### Kararlar — `App.Hr.DisciplinaryDecision`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DisciplinaryDecision.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.DisciplinaryDecision` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Kararlar — disiplin dosyası için verilen karar ve ceza. |
|
||||
| Kaynak | `Hr_T_DisciplinaryDecision` · 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ı | DecisionDate=@DATE, Status=Draft |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `CaseId` | Disiplin Dosyası | dxTextBox | | | |
|
||||
| `DecisionDate` | Karar Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `PenaltyTypeId` | Ceza Türü | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_DisciplinaryPenaltyType |
|
||||
| `EffectiveDate` | Yürürlük Tarihi | dxDateBox | | ✓ | |
|
||||
| `NotificationDate` | Tebliğ Tarihi | dxDateBox | | ✓ | |
|
||||
| `DeductionAmount` | Kesinti Tutarı | dxNumberBox | | ✓ | |
|
||||
| `Status` | Durum | dxRadioGroup | ✓ | ✓ | liste: Draft, Final |
|
||||
| `DecisionText` | Karar Metni | dxTextArea | | ✓ | |
|
||||
|
||||
### Belgeler — `App.Hr.DisciplinaryFile`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DisciplinaryFile.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.DisciplinaryFile` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Disiplin Belgeleri — dosyaya ait imzalı tutanak, savunma, tebliğ gibi belgeler. |
|
||||
| Kaynak | `Hr_T_DisciplinaryFile` · 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ı | FileDate=@DATE |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `CaseId` | Disiplin Dosyası | dxTextBox | | | |
|
||||
| `DocumentTypeId` | Dosya Türü | dxSelectBox | | ✓ | sorgu: Hr_T_DocumentType |
|
||||
| `FileDate` | Tarih | dxDateBox | ✓ | ✓ | |
|
||||
| `FileName` | Dosya Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `FileContent` | Dosya | dxImageUpload | ✓ | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
142
configs/seeds/host/docs/modules/HrEventLog.md
Normal file
142
configs/seeds/host/docs/modules/HrEventLog.md
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# İK › Olay Günlüğü (`App.Hr.EventLog`)
|
||||
|
||||
Vardiya amiri, güvenlik odası ve gözlem odasının tuttuğu vardiya defteri: tarih–saat, kaynak,
|
||||
olayı yaşayan/kaydeden personel, vardiya, önem derecesi (1–5) ve açıklama. Tamamı konfigürasyondur
|
||||
(tek Wizard ekranı).
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| Vardiya amiri / güvenlik / gözlem odası | Vardiyada yaşanan önemli olayları kaydeder | Olay Günlüğü |
|
||||
| Yönetim / İK | Günün olaylarını ve önemli/kritik kayıtları izler; gerekirse disiplin dosyası açar | Olay Günlüğü (widget, Pivot) |
|
||||
|
||||
Kapsam: kiracı (`IsTenant`). Şube isteğe bağlıdır; satır süzmesi yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar wizard ve SQL'den okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Tek Wizard liste ekranı |
|
||||
| Kaynak | Sabit liste: Vardiya Amiri (`ShiftSupervisor`), Güvenlik Odası (`SecurityRoom`), Gözlem Odası (`ObservationRoom`) |
|
||||
| Önem | 1–5 yıldız: Rutin, Düşük, Önemli, Çok Önemli, Kritik; **4 ve üstü** "önemli" kartında sayılır |
|
||||
| Saat | `EventTime` `SS:dd` metin; yeni kayıtta şimdiki saat |
|
||||
| Vardiya | Vardiya tanımından seçilir (`Hr_T_Shift`) |
|
||||
| Disiplin bağı | Olaydan disiplin dosyasına otomatik geçiş **yoktur**; dosya elle açılır |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekran
|
||||
|
||||
| Menü (TR / EN) | `ListFormCode` | Yer | Görünümler | Widget'lar |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Olay Günlüğü / Event Log | `App.Hr.EventLog` | `İnsan Kaynakları` (sıra 9, `FcViewDetails`) | Grid, Card, Pivot, Chart | Toplam · Bugün · Önemli (önem ≥ 4) |
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
`Hr_T_EventLog` (`sql/object/Hr_T_EventLog.sql`, entity yok):
|
||||
|
||||
| Kolon | Açıklama |
|
||||
| --- | --- |
|
||||
| `LogSource` | Kayıt kaynağı (zorunlu) |
|
||||
| `BranchId` | Şube |
|
||||
| `UserId` | Vardiya amiri / olayı yaşayan personel (zorunlu) |
|
||||
| `EventDate`, `EventTime` | Olay tarihi ve saati (zorunlu) |
|
||||
| `Importance` | 1–5 (varsayılan 1) |
|
||||
| `ShiftId` | Vardiya |
|
||||
| `Description` | Açıklama |
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları
|
||||
|
||||
| Yer | Kural |
|
||||
| --- | --- |
|
||||
| Yeni kayıt | Olay saati boşsa şimdiki saat yazılır |
|
||||
| Önem kartı | `Importance >= 4` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`; `App.Hr.EventLog` + `.Create/.Update/.Delete/.Export/.Import/.Note`.
|
||||
Kayıt tutanlara kök + `.Create` (ve gerekiyorsa `.Update`) yeter; silme yalnız yöneticide kalmalıdır.
|
||||
Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
`Sas_T_Branch`, `AbpUsers`, `Hr_T_Shift` (bkz. `HrWorkCalendar.md`). Kritik olay için bildirim yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. Gece vardiyasında güvenlik odası "B kapısı alarmı" olayını kaynak Güvenlik Odası, önem 3, vardiya Gece ile kaydeder.
|
||||
2. Vardiya amiri bir iş kazasını önem 5 ile girer → "Önemli" kartı artar.
|
||||
3. Sabah İK önemli kayıtları süzer; gerekiyorsa Disiplin Dosyaları'nda elle dosya açar.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar
|
||||
|
||||
**Kritik olayda yöneticiye bildirim gidiyor mu?** Hayır; widget ve filtre ile izlenir.
|
||||
|
||||
**Olay disiplin dosyasına bağlanabiliyor mu?** Hayır; iki kayıt arasında bağ yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_EventLog.sql` | Tablo |
|
||||
| `configs/seeds/host/wizard/EventLog.json` | Wizard |
|
||||
|
||||
Geri alma: Wizard Manager'dan silinir; tablo yalnızca onayda seçilirse düşer.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Olay Günlüğü — `App.Hr.EventLog`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/EventLog.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr` › `App.Hr.EventLog` (sıra 7) |
|
||||
| Yetki | `App.Hr.EventLog` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Olay Günlüğü — vardiya amiri, güvenlik odası ve gözlem odasının vardiya sırasında kaydettiği önemli olaylar. |
|
||||
| Geliştirme talebi | Human Resources -> Olay Günlüğü |
|
||||
| Kaynak | `Hr_T_EventLog` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Today`, `App.Hr.EventLog.Widget.Important` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `LogSource` | Kaynak | dxSelectBox | ✓ | ✓ | liste: ShiftSupervisor, SecurityRoom, ObservationRoom |
|
||||
| `BranchId` | Şube Adı | dxSelectBox | | ✓ | sorgu: Sas_T_Branch |
|
||||
| `UserId` | Vardiya Amiri / Olayı Yaşayan | dxSelectBox | ✓ | ✓ | sorgu: AbpUsers |
|
||||
| `EventDate` | Olay Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `EventTime` | Olay Saati | dxTextBox | ✓ | ✓ | |
|
||||
| `Importance` | Önem Durumu | dxSelectBox | ✓ | ✓ | liste: 1, 2, 3, 4, 5 |
|
||||
| `ShiftId` | Vardiya | dxSelectBox | | ✓ | sorgu: Hr_T_Shift |
|
||||
| `Description` | Açıklama | dxTextArea | | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
429
configs/seeds/host/docs/modules/HrHealthCard.md
Normal file
429
configs/seeds/host/docs/modules/HrHealthCard.md
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
# İK › Sağlık Kartları (`App.Hr.HealthCard`)
|
||||
|
||||
İşyeri hekimliği için çalışan sağlık kartı: soy/özgeçmiş, anamnez, laboratuvar ve fizik muayene
|
||||
bulguları, çalışmaya elverişlilik sonucu (vardiya/gece çalışması dahil), periyodik muayeneler,
|
||||
revir (hasta protokol defteri) başvuruları ve istirahat raporları. Kart ayrı bir tablo değildir:
|
||||
tek kayıtlık bölümler doğrudan çalışanın kullanıcı satırında (`AbpUsers` genişletme kolonları),
|
||||
çok kayıtlı bölümler `Adm_T_User*` tablolarındadır. Tamamı konfigürasyon + platformun kullanıcı
|
||||
detay ekranıdır.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| İşyeri hekimi / sağlık personeli | Kartı doldurur, periyodik muayene ve revir başvurusu girer, elverişlilik sonucunu yazar | Sağlık Kartları (detay sekmeleri) |
|
||||
| İK | Kart durumunu izler, istirahat raporlarını girer; hekim, hastane ve bölüm tanımlarını yönetir | Sağlık Kartları · İK › Tanımlar |
|
||||
| Sistem yöneticisi | Aynı veriyi kullanıcı detayında görür | Kimlik › Kullanıcılar › detay › Sağlık Kartı sekmesi |
|
||||
|
||||
Kapsam: kiracı. Liste, kiracının **tüm kullanıcılarıdır** (aktif/pasif); satır süzmesi yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar artefaktlardan (wizard,
|
||||
> entity, `HealthCardTab.tsx`) okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Veri yeri | Kart başına tek değer taşıyan alanlar (kan grubu, anamnez, muayene bulguları, sonuç) **`AbpUsers` genişletme kolonlarıdır** — ayrı kart tablosu yok |
|
||||
| Liste | Sağlık Kartları ekranı `AbpUsers` üzerinde salt okunur listedir (ekle/düzenle/sil kapalı); kart bilgileri detaydaki sekmelerden düzenlenir |
|
||||
| Tek kayıtlık sekmeler | Soy/Özgeçmiş, Laboratuvar–Fizik Muayene, Anamnez, Sonuç: aynı kullanıcı satırını düzenleyen alt formlar (`Id → Id`, yalnız güncelleme) |
|
||||
| Çok kayıtlı sekmeler | Periyodik Muayeneler, Hasta Protokol Defteri, İstirahat Raporları: `Adm_T_UserPeriodicExamination`, `Adm_T_UserPatientProtocol`, `Adm_T_UserSickLeave` (`Id → UserId`) |
|
||||
| İkinci giriş | Kullanıcı detayındaki **Sağlık Kartı** sekmesi (`HealthCardTab.tsx`) aynı kolonları ve aynı üç tabloyu (`App.IdentityManagement.User{PeriodicExamination,PatientProtocol,SickLeave}` listeleriyle) düzenler |
|
||||
| Hekim | Kurum doktoru tanımı (`Hr_T_Doctor`); periyodik muayenede seçilince diploma no kopyalanır |
|
||||
| Koşullu alanlar | Anamnezde "evet" denmeyen sorunun not alanı, protokolde sonuç "Sevk" değilse sevk yeri kilitlidir (`readOnly` script) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
| Menü (TR / EN) | `ListFormCode` | Yer | Kaynak | Alt formlar |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Sağlık Kartları / Health Cards | `App.Hr.HealthCard` | `İnsan Kaynakları` (sıra 5, `FcInspection`) | `AbpUsers` | aşağıdaki 7 sekme |
|
||||
|
||||
| Sekme | `ListFormCode` (menüsüz) | Kaynak | İlişki | Düzenleme |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Soy / Özgeçmiş | `App.Hr.HealthCardHistory` | `AbpUsers` | `Id → Id` | Yalnız güncelleme |
|
||||
| Laboratuvar – Fizik Muayene | `App.Hr.HealthCardLabPhysical` | `AbpUsers` | `Id → Id` | Yalnız güncelleme |
|
||||
| Anamnez | `App.Hr.HealthCardAnamnesis` | `AbpUsers` | `Id → Id` | Yalnız güncelleme |
|
||||
| Sonuç | `App.Hr.HealthCardResult` | `AbpUsers` | `Id → Id` | Yalnız güncelleme |
|
||||
| Periyodik Muayeneler | `App.Hr.HealthCardPeriodicExamination` | `Adm_T_UserPeriodicExamination` | `Id → UserId` | Ekle/düzenle/sil |
|
||||
| Hasta Protokol Defteri | `App.Hr.HealthCardPatientProtocol` | `Adm_T_UserPatientProtocol` | `Id → UserId` | Ekle/düzenle/sil |
|
||||
| İstirahat Raporları | `App.Hr.HealthCardSickLeave` | `Adm_T_UserSickLeave` | `Id → UserId` | Ekle/düzenle/sil |
|
||||
|
||||
Widget'lar (liste): Toplam · Aktif · Pasif kullanıcı.
|
||||
|
||||
Tanımlar (`İnsan Kaynakları › Tanımlamalar`):
|
||||
|
||||
| Menü | `ListFormCode` | Seed |
|
||||
| --- | --- | --- |
|
||||
| Kurum Doktorları | `App.Hr.Doctor` | 1 kayıt (diploma, işyeri hekimi belge no/tarihi, T.C. kimlik) |
|
||||
| Hastaneler | `App.Hr.Hospital` | 45 kurum (devlet/özel hastaneler, sağlık ocağı, işyeri hekimliği…) |
|
||||
| Hastane Bölümleri | `App.Hr.HospitalDepartment` | 31 bölüm |
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
| Yer | Alanlar |
|
||||
| --- | --- |
|
||||
| `AbpUsers` — kimlik (liste) | `Name`, `Surname`, `IdentityNumber`, `BirthDate`, `Gender`, `BloodType`, `Email`, `PhoneNumber`, `DepartmentId`, `JobPositionId`, `HireDate`, `SskNo`, `IsActive` |
|
||||
| `AbpUsers` — soy/özgeçmiş | Anne/baba/kardeş/çocuk sağlık durumu (Alive/Disease/Deceased) + not, `BloodType` (8 grup), `ChronicDisease`, tetanoz/hepatit/diğer aşı |
|
||||
| `AbpUsers` — anamnez | Şikâyetler (`Complaint*`: göğüs ağrısı, balgamlı öksürük, nefes darlığı, çarpıntı, eklem/bel ağrısı, ishal/kabızlık), tanılar (`Diagnosis*`: diyabet, kalp, böbrek, sarılık, ülser, işitme, görme, sinir sistemi, deri, besin zehirlenmesi), evet/hayır + not soruları (hastanede yatış, ameliyat, iş kazası, meslek hastalığı muayenesi, malulen emeklilik, süren tedavi), sigara/alkol (None/Occasionally/Normal/Quit + not) |
|
||||
| `AbpUsers` — lab/fizik | `Lab*` (biyolojik, kan, idrar, radyolojik, odyometri, SFT, psikolojik, diğer), `Exam*` (duyu, göz, KBB, deri, kalp-damar, solunum, sindirim, ürogenital, kas-iskelet, nörolojik, psikiyatrik, diğer, tansiyon, nabız, boy, kilo) |
|
||||
| `AbpUsers` — sonuç | `FitForWorkJob`, `FitForWorkCondition`, `FitnessDoctorId`, `ShiftWorkFit`, `NightWorkFit`, `ShiftNightDoctorId` |
|
||||
| `Adm_T_UserPeriodicExamination` | `UserId`, `ExamDate`, `Examination`, `Result`, `DoctorId`, `DoctorDiplomaNo` |
|
||||
| `Adm_T_UserPatientProtocol` | `UserId`, `SequenceNo`, `ProtocolDate`, `ProtocolType` (Disease/WorkAccident/OccupationalDisease/Control/Other), `ProtocolResult` (TreatmentDischarged/Rest/Referral), `RestDays`, `ReferralPlace`, `DoctorId` |
|
||||
| `Adm_T_UserSickLeave` | `UserId`, `StartDate`, `EndDate`, `Days`, `SickLeaveType` (Disease/WorkAccident/OccupationalDisease/Maternity), `Institution`, `Clinic`, `SickLeaveReason` |
|
||||
| `Hr_T_Doctor` / `Hr_T_Hospital` / `Hr_T_HospitalDepartment` | Tanımlar |
|
||||
|
||||
Entity'ler: `Entities/Tenant/Administration/User{PeriodicExamination,PatientProtocol,SickLeave}.cs`;
|
||||
genişletme kolonları `AbpIdentityUserExtensions` ve EF genişletme eşlemeleri.
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları
|
||||
|
||||
| Yer | Kural |
|
||||
| --- | --- |
|
||||
| Anamnez | Evet/hayır sorusu işaretli değilse not alanı salt okunur; sigara/alkol "Kullanmıyor" ise not kilitli |
|
||||
| Periyodik muayene | Yeni satırda tarih bugün; hekim seçilince diploma no kopyalanır |
|
||||
| Protokol | Yeni satırda tarih bugün; sonuç "Sevk" değilse sevk yeri kilitli |
|
||||
| İstirahat | `Days = days(Başlangıç, Bitiş)` (bitiş dahil); bitiş başlangıçtan önceyse uyarı |
|
||||
| Liste | Kayıt eklenemez/silinemez — kartın sahibi kullanıcı kaydıdır |
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. `App.Hr.HealthCard` kökü; yedi sekme onun altındadır. Tanımlar
|
||||
`App.Hr.Definitions` altındadır. Kullanıcı detayındaki sekme, kullanıcı ekranının yetkileriyle
|
||||
(`AbpIdentity.Users` / `.Update`) çalışır. Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
Sağlık verisi **özel nitelikli kişisel veridir** (KVKK md. 6): Sağlık Kartları ve alt sekmelerinin
|
||||
yetkisi yalnız işyeri hekimi ve yetkili sağlık personeline verilmelidir. Kullanıcı detayına erişen
|
||||
yöneticiler de bu sekmeyi görebileceği için kullanıcı yönetimi yetkisi de buna göre sınırlanmalıdır.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kaynak | Kullanım |
|
||||
| --- | --- |
|
||||
| `AbpUsers` (+ `Hr_T_Department`, `Hr_T_JobPosition`) | Kartın sahibi ve kimlik bilgisi |
|
||||
| Kullanıcı detayı (`views/admin/user-management/HealthCardTab.tsx`) | Aynı verinin ikinci düzenleme yeri |
|
||||
| `Hr_T_Doctor` | Periyodik muayene, protokol, sonuç hekimleri |
|
||||
|
||||
Hastane ve hastane bölümü tanımları **henüz hiçbir sekmeye bağlı değildir** (istirahatte kurum/klinik
|
||||
serbest metindir). Bildirim, periyodik muayene hatırlatması ya da rapor şablonu yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. İşe giren çalışanın kartı listede hazırdır (kullanıcı açıldığı anda). Hekim **Soy/Özgeçmiş** ve
|
||||
**Anamnez** sekmelerini doldurur.
|
||||
2. İşe giriş muayenesi bulguları **Laboratuvar – Fizik Muayene**'ye, kararı **Sonuç**'a yazılır
|
||||
(vardiyalı/gece çalışabilir + hekimler).
|
||||
3. Yıllık kontrol **Periyodik Muayeneler**'e eklenir.
|
||||
4. Çalışan revire gelince **Hasta Protokol Defteri**'ne kayıt açılır (tür Hastalık, sonuç İstirahat, 1 gün).
|
||||
5. Dışarıdan alınan rapor **İstirahat Raporları**'na girilir; gün sayısı hesaplanır.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar
|
||||
|
||||
**Listeye neden kayıt eklenemiyor?** Kart kullanıcı kaydıdır; yeni çalışan Kimlik › Kullanıcılar'dan açılır.
|
||||
|
||||
**Sağlık kartı verisi nerede tutuluyor?** Tek değerli alanlar `AbpUsers` kolonlarında, muayene/protokol/istirahat ayrı tablolarda (§4).
|
||||
|
||||
**Kullanıcı detayındaki Sağlık Kartı sekmesiyle bu ekran aynı mı?** Evet; aynı veriyi iki yerden düzenlerler.
|
||||
|
||||
**Hastane tanımı nerede kullanılıyor?** Şu an hiçbir yerde; ileride istirahat/sevk alanlarına lookup olarak bağlanmak üzere duruyor.
|
||||
|
||||
**İstirahat raporu izin bakiyesine yansıyor mu?** Hayır; izin modülü yoktur (İzin Türleri yalnız tanımdır).
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/wizard/HealthCard{,History,LabPhysical,Anamnesis,Result,PeriodicExamination,PatientProtocol,SickLeave}.json` | 8 wizard |
|
||||
| `configs/seeds/host/wizard/{Doctor,Hospital,HospitalDepartment}.json`, `data/App.Hr.{Doctor,Hospital,HospitalDepartment}.json` | Tanım ekranları ve verisi |
|
||||
| `api/src/Sozsoft.Platform.Domain/Entities/Tenant/Administration/User{PeriodicExamination,PatientProtocol,SickLeave}.cs` | Çok kayıtlı sekmelerin entity'leri (migration'lı) |
|
||||
| `ui/src/views/admin/user-management/HealthCardTab.tsx` | Kullanıcı detayındaki sekme |
|
||||
|
||||
Kart sekmelerini kaldırmak wizard'ları siler; `AbpUsers` kolonları ve `Adm_T_User*` tabloları
|
||||
entity/migration'a bağlı olduğu için kalır.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Sağlık Kartları — `App.Hr.HealthCard`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCard.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr` › `App.Hr.HealthCard` (sıra 4) |
|
||||
| Yetki | `App.Hr.HealthCard` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Sağlık Kartları — işyeri hekimliği için her çalışanın sağlık kartı. Liste kiracının bütün kullanıcılarıdır; kart bilgileri detay sekmelerinden girilir. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `AbpUsers` · 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.Hr.HealthCardHistory` (Id → Id), `App.Hr.HealthCardLabPhysical` (Id → Id), `App.Hr.HealthCardAnamnesis` (Id → Id), `App.Hr.HealthCardResult` (Id → Id), `App.Hr.HealthCardPeriodicExamination` (Id → UserId), `App.Hr.HealthCardPatientProtocol` (Id → UserId), `App.Hr.HealthCardSickLeave` (Id → UserId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Ad | dxTextBox | | ✓ | |
|
||||
| `Surname` | Soyad | dxTextBox | | ✓ | |
|
||||
| `IdentityNumber` | T.C. Kimlik No | dxTextBox | | ✓ | |
|
||||
| `BirthDate` | Doğum Tarihi | dxDateBox | | ✓ | |
|
||||
| `Gender` | Cinsiyet | dxSelectBox | | ✓ | liste: Male, Female |
|
||||
| `BloodType` | Kan Grubu | dxTextBox | | ✓ | |
|
||||
| `Email` | E-posta | dxTextBox | | ✓ | |
|
||||
| `PhoneNumber` | Telefon | dxTextBox | | ✓ | |
|
||||
| `DepartmentId` | Departman | dxSelectBox | | ✓ | sorgu: Hr_T_Department |
|
||||
| `JobPositionId` | Pozisyon | dxSelectBox | | ✓ | sorgu: Hr_T_JobPosition |
|
||||
| `HireDate` | İşe Giriş Tarihi | dxDateBox | | ✓ | |
|
||||
| `SskNo` | SSK No | dxTextBox | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
|
||||
### Soy / Özgeçmiş — `App.Hr.HealthCardHistory`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCardHistory.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.HealthCardHistory` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Soy / Özgeçmiş — çalışanın aile sağlık geçmişi, kan grubu, kronik hastalıkları ve aşıları. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `AbpUsers` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `MotherHealthStatus` | Anne | dxSelectBox | | ✓ | liste: Alive, Disease, Deceased |
|
||||
| `MotherHealthNote` | Anne Notu | dxTextBox | | ✓ | |
|
||||
| `FatherHealthStatus` | Baba | dxSelectBox | | ✓ | liste: Alive, Disease, Deceased |
|
||||
| `FatherHealthNote` | Baba Notu | dxTextBox | | ✓ | |
|
||||
| `SiblingHealthStatus` | Kardeş | dxSelectBox | | ✓ | liste: Alive, Disease, Deceased |
|
||||
| `SiblingHealthNote` | Kardeş Notu | dxTextBox | | ✓ | |
|
||||
| `ChildHealthStatus` | Çocuk | dxSelectBox | | ✓ | liste: Alive, Disease, Deceased |
|
||||
| `ChildHealthNote` | Çocuk Notu | dxTextBox | | ✓ | |
|
||||
| `BloodType` | Kan Grubu | dxSelectBox | | ✓ | liste: 0 Rh+, 0 Rh-, A Rh+, A Rh-, B Rh+, B Rh-, AB Rh+, AB Rh- |
|
||||
| `ChronicDisease` | Doğuştan / Kronik Hastalık | dxTextBox | | ✓ | |
|
||||
| `TetanusVaccination` | Tetanoz | dxTextBox | | ✓ | |
|
||||
| `HepatitisVaccination` | Hepatit | dxTextBox | | ✓ | |
|
||||
| `OtherVaccination` | Diğer | dxTextBox | | ✓ | |
|
||||
|
||||
### Laboratuvar - Fizik Muayene — `App.Hr.HealthCardLabPhysical`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCardLabPhysical.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.HealthCardLabPhysical` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Laboratuvar – Fizik Muayene — işe giriş ya da periyodik muayenedeki tahlil ve fizik muayene bulguları. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `AbpUsers` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `LabBiologicalAnalysis` | Biyolojik Analizler | dxTextBox | | ✓ | |
|
||||
| `LabBlood` | Kan | dxTextBox | | ✓ | |
|
||||
| `LabUrine` | İdrar | dxTextBox | | ✓ | |
|
||||
| `LabRadiological` | Radyolojik Analizler | dxTextBox | | ✓ | |
|
||||
| `LabRadiologicalPhysiological` | Radyolojik Fizyolojik | dxTextBox | | ✓ | |
|
||||
| `LabAudiometry` | Odyometri | dxTextBox | | ✓ | |
|
||||
| `LabPulmonaryFunction` | Solunum Fonksiyon Testi | dxTextBox | | ✓ | |
|
||||
| `LabPsychologicalTests` | Psikolojik Testler | dxTextBox | | ✓ | |
|
||||
| `LabOther` | Diğer Laboratuvar Bulguları | dxTextBox | | ✓ | |
|
||||
| `ExamSensoryOrgans` | Duyu Organları | dxTextBox | | ✓ | |
|
||||
| `ExamEye` | Göz | dxTextBox | | ✓ | |
|
||||
| `ExamEnt` | Kulak-Burun-Boğaz | dxTextBox | | ✓ | |
|
||||
| `ExamSkin` | Deri | dxTextBox | | ✓ | |
|
||||
| `ExamCardiovascular` | Kalp-Damar Sistemi Muayenesi | dxTextBox | | ✓ | |
|
||||
| `ExamRespiratory` | Solunum Sistemi Muayenesi | dxTextBox | | ✓ | |
|
||||
| `ExamDigestive` | Sindirim Sistemi Muayenesi | dxTextBox | | ✓ | |
|
||||
| `ExamUrogenital` | Ürogenital Sistem Muayenesi | dxTextBox | | ✓ | |
|
||||
| `ExamMusculoskeletal` | Kas-İskelet Sistemi Muayenesi | dxTextBox | | ✓ | |
|
||||
| `ExamNeurological` | Nörolojik Muayene | dxTextBox | | ✓ | |
|
||||
| `ExamPsychiatric` | Psikiyatrik Muayene | dxTextBox | | ✓ | |
|
||||
| `ExamOther` | Diğer Muayene Bulguları | dxTextBox | | ✓ | |
|
||||
| `ExamBloodPressure` | Tansiyon | dxTextBox | | ✓ | |
|
||||
| `ExamPulse` | Nabız / dk | dxTextBox | | ✓ | |
|
||||
| `ExamHeight` | Boy (cm) | dxNumberBox | | ✓ | |
|
||||
| `ExamWeight` | Kilo (kg) | dxNumberBox | | ✓ | |
|
||||
|
||||
### Anamnez — `App.Hr.HealthCardAnamnesis`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCardAnamnesis.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.HealthCardAnamnesis` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Anamnez — çalışanın sağlık geçmişine dair soru formu. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `AbpUsers` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `ComplaintChestPain` | Göğüs Ağrısı | dxCheckBox | | ✓ | |
|
||||
| `ComplaintProductiveCough` | Balgamlı Öksürük | dxCheckBox | | ✓ | |
|
||||
| `ComplaintDyspnea` | Nefes Darlığı | dxCheckBox | | ✓ | |
|
||||
| `ComplaintPalpitation` | Çarpıntı | dxCheckBox | | ✓ | |
|
||||
| `ComplaintJointPain` | Eklem Ağrısı | dxCheckBox | | ✓ | |
|
||||
| `ComplaintBackPain` | Bel Ağrısı | dxCheckBox | | ✓ | |
|
||||
| `ComplaintDiarrheaConstipation` | İshal veya Kabızlık | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisDiabetes` | Şeker Hastalığı | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisHeartDisease` | Kalp Hastalığı | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisKidneyDisease` | Böbrek Hastalığı | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisJaundice` | Sarılık | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisPepticUlcer` | Mide / Oniki Parmak Ülseri | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisHearingLoss` | İşitme Kaybı | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisVisionImpairment` | Görme Bozukluğu | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisNervousSystemDisease` | Sinir Sistemi Hastalığı | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisSkinDisease` | Deri Hastalığı | dxCheckBox | | ✓ | |
|
||||
| `DiagnosisFoodPoisoning` | Besin Zehirlenmesi | dxCheckBox | | ✓ | |
|
||||
| `Hospitalized` | 3. Hastanede yattınız mı? | dxCheckBox | | ✓ | script |
|
||||
| `HospitalizedNote` | Hastanede Yatış Notu | dxTextBox | | ✓ | |
|
||||
| `HadSurgery` | 4. Ameliyat oldunuz mu? | dxCheckBox | | ✓ | script |
|
||||
| `HadSurgeryNote` | Ameliyat Notu | dxTextBox | | ✓ | |
|
||||
| `HadWorkAccident` | 5. İş kazası geçirdiniz mi? | dxCheckBox | | ✓ | script |
|
||||
| `HadWorkAccidentNote` | İş Kazası Notu | dxTextBox | | ✓ | |
|
||||
| `OccupationalDiseaseExam` | 6. Meslek hastalığı şüphesiyle tetkik veya muayene oldunuz mu? | dxCheckBox | | ✓ | script |
|
||||
| `OccupationalDiseaseExamNote` | Meslek Hastalığı Muayene Notu | dxTextBox | | ✓ | |
|
||||
| `DisabilityPension` | 7. Malulen emeklilik aldınız mı? | dxCheckBox | | ✓ | script |
|
||||
| `DisabilityPensionNote` | Malulen Emeklilik Notu | dxTextBox | | ✓ | |
|
||||
| `UnderTreatment` | 8. Şu anda bir tedavi görüyor musunuz? | dxCheckBox | | ✓ | script |
|
||||
| `UnderTreatmentNote` | Tedavi Notu | dxTextBox | | ✓ | |
|
||||
| `Smoking` | 9. Sigara kullanıyor musunuz? | dxSelectBox | | ✓ | liste: None, Occasionally, Normal, Quit · script |
|
||||
| `SmokingNote` | Sigara Notu | dxTextBox | | ✓ | |
|
||||
| `Alcohol` | 10. Alkol kullanıyor musunuz? | dxSelectBox | | ✓ | liste: None, Occasionally, Normal, Quit · script |
|
||||
| `AlcoholNote` | Alkol Notu | dxTextBox | | ✓ | |
|
||||
|
||||
### Sonuç — `App.Hr.HealthCardResult`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCardResult.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.HealthCardResult` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Sonuç — işyeri hekiminin çalışmaya elverişlilik kararı. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `AbpUsers` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `FitForWorkJob` | Çalışmaya Elverişli - İş | dxTextBox | | ✓ | |
|
||||
| `FitForWorkCondition` | Çalışmaya Elverişli - Koşul | dxTextBox | | ✓ | |
|
||||
| `FitnessDoctorId` | Doktor | dxSelectBox | | ✓ | sorgu: Hr_T_Doctor |
|
||||
| `ShiftWorkFit` | Vardiyalı Çalışabilir | dxCheckBox | | ✓ | |
|
||||
| `NightWorkFit` | Gece Çalışabilir | dxCheckBox | | ✓ | |
|
||||
| `ShiftNightDoctorId` | Vardiya / Gece Çalışması Doktoru | dxSelectBox | | ✓ | sorgu: Hr_T_Doctor |
|
||||
|
||||
### Periyodik Muayeneler — `App.Hr.HealthCardPeriodicExamination`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCardPeriodicExamination.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.HealthCardPeriodicExamination` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Periyodik Muayeneler — çalışanın yasal periyodik sağlık muayeneleri. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `Adm_T_UserPeriodicExamination` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `UserId` | Kullanıcı | dxSelectBox | | | sorgu: AbpUsers |
|
||||
| `ExamDate` | Tarih | dxDateBox | ✓ | ✓ | script |
|
||||
| `Examination` | Muayene | dxTextBox | ✓ | ✓ | |
|
||||
| `Result` | Sonuç | dxTextBox | | ✓ | |
|
||||
| `DoctorId` | Doktor | dxSelectBox | | ✓ | sorgu: Hr_T_Doctor · script |
|
||||
| `DoctorDiplomaNo` | Diploma No | dxTextBox | | ✓ | |
|
||||
|
||||
### Hasta Protokol Defteri — `App.Hr.HealthCardPatientProtocol`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCardPatientProtocol.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.HealthCardPatientProtocol` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Hasta Protokol Defteri — çalışanın revir başvuruları. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `Adm_T_UserPatientProtocol` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `UserId` | Kullanıcı | dxSelectBox | | | sorgu: AbpUsers |
|
||||
| `SequenceNo` | Sıra No | dxNumberBox | | ✓ | |
|
||||
| `ProtocolDate` | Tarih | dxDateBox | ✓ | ✓ | script |
|
||||
| `ProtocolType` | Protokol Türü | dxSelectBox | ✓ | ✓ | liste: Disease, WorkAccident, OccupationalDisease, Control, Other |
|
||||
| `ProtocolResult` | Sonuç | dxSelectBox | | ✓ | liste: TreatmentDischarged, Rest, Referral · script |
|
||||
| `RestDays` | İstirahat Günü | dxNumberBox | | ✓ | |
|
||||
| `ReferralPlace` | Sevk Yeri | dxTextBox | | ✓ | |
|
||||
| `DoctorId` | Doktor | dxSelectBox | | ✓ | sorgu: Hr_T_Doctor |
|
||||
|
||||
### İstirahat Raporları — `App.Hr.HealthCardSickLeave`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/HealthCardSickLeave.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.HealthCardSickLeave` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | İstirahat Raporları — çalışanın aldığı istirahat (rapor) kayıtları. |
|
||||
| Geliştirme talebi | Human Resources -> Health Card |
|
||||
| Kaynak | `Adm_T_UserSickLeave` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `UserId` | Kullanıcı | dxSelectBox | | | sorgu: AbpUsers |
|
||||
| `StartDate` | Başlangıç Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `EndDate` | Bitiş Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `Days` | Gün | dxNumberBox | ✓ | ✓ | |
|
||||
| `SickLeaveType` | İstirahat Türü | dxSelectBox | ✓ | ✓ | liste: Disease, WorkAccident, OccupationalDisease, Maternity |
|
||||
| `Institution` | Kurum | dxTextBox | | ✓ | |
|
||||
| `Clinic` | Klinik | dxTextBox | | ✓ | |
|
||||
| `SickLeaveReason` | İstirahat Nedeni | dxTextBox | | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
216
configs/seeds/host/docs/modules/HrIntranet.md
Normal file
216
configs/seeds/host/docs/modules/HrIntranet.md
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
# İK › Intranet (`App.Hr.Intranet`)
|
||||
|
||||
Kurum içi iletişim: ana sayfa panosu (bugün doğanlar, dokümanlar, aktif anketler, sosyal duvar,
|
||||
duyurular, yaklaşan etkinlikler), bunların yönetim ekranları (duyuru, anket, sosyal paylaşım,
|
||||
etkinlik), doküman kütüphanesi ve kullanıcılar arası mesajlaşma. Bu modül **entity + C# seeder +
|
||||
özel React sayfalarıyla** kuruludur (wizard değil); pano kutuları Developer Kit › Intranet Widgets
|
||||
kaydıyla yönetilir.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| Tüm çalışanlar | Panoyu görür; duyuru okur/beğenir/yorumlar, anket doldurur, paylaşım yapar, beğenir, yorumlar, ankete oy verir, etkinliği beğenir/yorumlar, doküman indirir, mesajlaşır | `/admin/dashboard` · mesajlaşma penceresi |
|
||||
| İK / iç iletişim | Duyuru, anket (soru/seçenek), etkinlik ve tanımlarını yönetir; yanıtları ve etkileşimleri izler | İK › Intranet › Duyurular · Anketler · Sosyal Paylaşımlar · Etkinlik Türleri/Kategorileri · Etkinlikler |
|
||||
| İK / doküman sorumlusu | Doküman yükler, yayına alır/kaldırır | İK › Intranet › Dokümanlar (`/admin/intranet-documents`) |
|
||||
| Sistem yöneticisi | Pano kutularını (hazır ya da custom component) tanımlar, sırasını ve yetkisini belirler | Developer Kit › Intranet Widgets |
|
||||
|
||||
Kapsam: kiracı. Bütün tablolar `IMultiTenant`; satır süzmesi yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar koddan
|
||||
> (`ListFormSeeder_Hr.cs`, `Entities/Tenant/Hr/Intranet`, `IntranetAppService`, `views/intranet`) okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Yönetim ekranları entity + seeder ListForm'u; pano ve etkileşimler özel React + `IntranetAppService` |
|
||||
| Modül yeri | Intranet İK'dadır: menü `App.Hr.Intranet`, yetkiler `App.Hr.Intranet.*`, tablolar `Hr_T_*`; pano kutusu kaydı (`Sas_T_IntranetWidget`) Saas › Developer Kit'te kalır |
|
||||
| Pano kutuları | Veritabanı kaydıdır (kod, kolon, sıra, yetki, aktiflik). **Builtin** kutu koda kayıtlı React bileşenidir (`id` = kayıt `Code`); **Custom** kutu Developer Kit custom component'idir (Props JSON ile) |
|
||||
| Kullanıcı yerleşimi | Pano tasarım modunda sürükle-bırak, gizle/göster, kolon oranı hazır ayarları; tercih **tarayıcıda (localStorage)** saklanır, sunucuya yazılmaz |
|
||||
| Doğum günleri | Her pano isteğinde kullanıcıların `BirthDate` genişletme alanından canlı hesaplanır (gün + ay) |
|
||||
| Duyuru panoda | Kutu yalnız **sabitlenmiş** (`IsPinned`) duyuruları, en fazla 3 tane gösterir |
|
||||
| Anket | `Status = active` anketler; kullanıcı yanıtını sonradan **güncelleyebilir**; anonim ankette yanıt `UserId` taşımaz |
|
||||
| Sosyal medya | Bir paylaşımda tek medya kaydı (resim(ler), video ya da anket); yüklenen dosya **base64 data URL** olarak `SocialMedia.Urls`'e yazılır |
|
||||
| Doküman yayını | Fiziksel CDN klasörleri: `intranet` (yayında) ve `intranet/_passive` (yayında değil); yayına alma = klasörler arası taşıma |
|
||||
| Mesajlaşma | Yalnız tablo öneki ile İK'dadır (`Hr_T_Messenger*`); menüsü/yetkisi yoktur, kabuk düzenine gömülü pencere + SignalR |
|
||||
| Bildirim / zamanlanmış iş | Yok |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
`İnsan Kaynakları › Intranet` (`App.Hr.Intranet`, sıra 10)
|
||||
|
||||
| Sıra | Menü | `ListFormCode` / rota | Alt formlar | Widget'lar |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Duyurular | `App.Hr.Intranet.Announcement` | `…Announcement.AnnouncementLike`, `…Announcement.AnnouncementComment` (`Id → AnnouncementId`) | Aktif · Sabitlenmiş · Süresi dolan · Toplam görüntülenme |
|
||||
| 2 | Anketler | `App.Hr.Intranet.Survey` | `SurveyQuestion` (→ `SurveyQuestionOption`), `SurveyResponse` (→ `SurveyAnswer`) — iki seviyeli | Aktif · Pasif · Toplam yanıt |
|
||||
| 3 | Sosyal Paylaşımlar | `App.Hr.Intranet.SocialPost` | `SocialComment`, `SocialMedia` (→ `SocialPollOption`), `SocialLike` (`Id → SocialPostId`) | Toplam · Bugün · Toplam beğeni |
|
||||
| 4 | Etkinlik Türleri | `App.Hr.Intranet.Events.EventType` | — | — |
|
||||
| 5 | Etkinlik Kategorisi | `App.Hr.Intranet.Events.EventCategory` | — | — |
|
||||
| 6 | Etkinlikler | `App.Hr.Intranet.Events.Event` | `EventLike`, `EventComment` (`Id → EventId`) | Yaklaşan · Yayında · Taslak · İptal |
|
||||
| 7 | Dokümanlar | `/admin/intranet-documents` (özel sayfa) | — | — |
|
||||
|
||||
Diğer giriş noktaları:
|
||||
|
||||
| Ne | Nerede |
|
||||
| --- | --- |
|
||||
| Pano | `/admin/dashboard` (`views/Dashboard.tsx` → `views/intranet/Dashboard.tsx`); rota yetkisizdir, menüde ayrı kaydı yoktur |
|
||||
| Pano kutusu tanımı | Developer Kit › Intranet Widgets (`App.DeveloperKit.IntranetWidgets`, `Sas_T_IntranetWidget`); veri `data/App.DeveloperKit.IntranetWidgets.json`'a aynalanır |
|
||||
| Mesajlaşma | Uygulama kabuğundaki `MessengerWidget` |
|
||||
|
||||
Pano kutuları (seed):
|
||||
|
||||
| Kod | Kolon / sıra | Yetki | Ne gösterir |
|
||||
| --- | --- | --- | --- |
|
||||
| `today-birthdays` | Sol / 10 | `AbpIdentity.Users.Widget` | Bugün doğanlar: avatar, ad, yaş, departman |
|
||||
| `documents` | Sol / 20 | `App.Files.Widget` | Yayındaki ilk 3 doküman (tür, boyut, tarih, indir) |
|
||||
| `active-surveys` | Sol / 30 | `App.Hr.Intranet.Survey.Widget` | Aktif anketler (kalan gün, soru/yanıt sayısı, doldurdum/doldur) |
|
||||
| `social-wall` | Orta / 40 | `App.Hr.Intranet.SocialPost.Widget` | Sosyal duvar (Tümü / Paylaşımlarım, sonsuz kaydırma 10'arlı) |
|
||||
| `announcements` | Sağ / 50 | `App.Hr.Intranet.Announcement.Widget` | Sabitlenmiş duyurular (en fazla 3) |
|
||||
| `upcoming-events` | Sağ / 60 | `App.Hr.Intranet.Events.Event.Widget` | Bugünden sonraki yayınlanmış ilk 3 etkinlik |
|
||||
| `my-performance` | Sağ / 70 | `App.Hr.MyPerformanceReview` | Custom `MyPerformanceWidget`: aktif performans değerlendirmesi, puanlar, gelişim aksiyonları → Değerlendirmelerim |
|
||||
| `team-performance` | Sağ / 80 | `App.Hr.TeamPerformanceReview` | Custom `TeamPerformanceWidget`: yöneticinin ekip değerlendirmeleri → Ekibimin Değerlendirmeleri |
|
||||
| `my-360-feedback` | Sağ / 90 | `App.Hr.My360Feedback` | Custom `My360FeedbackWidget`: kullanıcıya atanan 360 talepleri → 360 Taleplerim |
|
||||
|
||||
İlk altı kutu Builtin'dir (koddaki `Code`). Son üçü Performans Yönetimi'nin çalışana ait özetleridir:
|
||||
İK menüsü İK departmanınındır, çalışan kendi değerlendirmesini buradan takip eder; listeler menüsüzdür ve
|
||||
kutudaki bağlantıyla açılır. Ayrıntı: `HrPerformance.md` §3.3.
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
Entity'ler `Entities/Tenant/Hr/Intranet` (`FullAuditedEntity<Guid>, IMultiTenant`); tablolar migration'lıdır.
|
||||
|
||||
| Tablo | Önemli kolonlar | Kural |
|
||||
| --- | --- | --- |
|
||||
| `Hr_T_Announcement` | `Title`, `Excerpt`, `Content` (HTML), `ImageUrl`, `Category` (general/event/urgent/announcement), `UserId`, `PublishDate`, `ExpiryDate`, `IsPinned`, `ViewCount`, `Likes`, `Attachments` | Başlık kiracıda tekil |
|
||||
| `Hr_T_AnnouncementComment` / `Hr_T_AnnouncementLike` | `AnnouncementId`, `UserId`, (`Content`) | Beğeni kullanıcı başına tekil |
|
||||
| `Hr_T_Survey` | `Title`, `Description`, `Deadline`, `Responses`, `Status`, `IsAnonymous` | Başlık kiracıda tekil |
|
||||
| `Hr_T_SurveyQuestion` | `SurveyId`, `QuestionText`, `Type` (rating/multiple-choice/text/textarea/yes-no), `Order`, `IsRequired` | — |
|
||||
| `Hr_T_SurveyQuestionOption` | `QuestionId`, `Text`, `Order` | — |
|
||||
| `Hr_T_SurveyResponse` / `Hr_T_SurveyAnswer` | `SurveyId`, `UserId`, `SubmissionTime` / `ResponseId`, `QuestionId`, `QuestionType`, `Value` | — |
|
||||
| `Hr_T_SocialPost` | `UserId`, `Content`, `LikeCount`, `IsLiked`, `IsOwnPost` | — |
|
||||
| `Hr_T_SocialMedia` | `SocialPostId` (1:1), `Type` (image/video/poll), `Urls`, `PollQuestion`, `PollTotalVotes`, `PollEndsAt`, `PollUserVoteId` | — |
|
||||
| `Hr_T_SocialPollOption` | `SocialMediaId`, `Text`, `Votes` | — |
|
||||
| `Hr_T_SocialComment` / `Hr_T_SocialLike` | `SocialPostId`, `UserId`, (`Content`) | Beğeni kullanıcı başına tekil |
|
||||
| `Hr_T_SocialLocation` | Konum bilgisi | Kullanan ekran/servis yok |
|
||||
| `Hr_T_EventType` / `Hr_T_EventCategory` | `Name` | Kiracıda tekil |
|
||||
| `Hr_T_Event` | `CategoryId`, `TypeId`, `Date`, `Name`, `Description`, `Place`, `Status` (published/draft/cancelled), `UserId`, `ParticipantsCount`, `Likes`, `isPublished`, `Photos` | `(CategoryId, TypeId, Name)` tekil |
|
||||
| `Hr_T_EventComment` / `Hr_T_EventLike` | `EventId`, `UserId`, (`Content`) | Beğeni tekil |
|
||||
| `Sas_T_IntranetWidget` | `Code`, `Name`, `LabelKey`, `SourceType` (0 Builtin / 1 Custom), `ComponentName`, `PermissionName`, `Column` (0 sol / 1 orta / 2 sağ), `Order`, `Props`, `IsActive` | Kod kiracıda tekil |
|
||||
| `Hr_T_MessengerConversation` / `Hr_T_MessengerConversationMessage` | Konuşma (katılımcılar, son mesaj) / mesaj (gönderen, alıcılar, metin, ekler, zaman) | — |
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları (`IntranetAppService`)
|
||||
|
||||
| İşlem | Kural |
|
||||
| --- | --- |
|
||||
| Pano verisi | Doğum günleri (bugün), `intranet` klasöründeki dosyalar (`_passive` hariç), son 50 duyuru, `active` anketler + kullanıcının yanıtı, `isPublished` son 50 etkinlik, aktif ve yetkisi verilmiş pano kutuları. Duyuru için tarih/sabitleme süzmesi, anket için son tarih süzmesi **sunucuda yoktur** |
|
||||
| Duyuru aç | Her açılışta `ViewCount + 1` |
|
||||
| Beğeni (duyuru, paylaşım, etkinlik) | Aç/kapa: beğeni satırı eklenir/silinir, sayaç ±1 |
|
||||
| Yorum | Satır eklenir; listelenirken yazar bilgisi doldurulur |
|
||||
| Anket yanıtı | Kullanıcının önceki yanıtı varsa cevaplar güncellenir; yoksa yeni yanıt + `Responses + 1`; anonimde `UserId` boş |
|
||||
| Paylaşım | İsteğe bağlı tek medya ya da 2–6 seçenekli anket; yalnız sahibi silebilir |
|
||||
| Ankete oy | Seçenek ve toplam oy +1, `PollUserVoteId` = seçenek; tekrar oy UI'da engellenir |
|
||||
| Doküman | Yüklemede görünen ad zorunlu (uzantı korunur); yayına al/kaldır = klasör taşıma; silme toplu |
|
||||
| Mesaj | Aynı kiracıdaki aktif kullanıcılara (en fazla 100 kişi listelenir); en fazla 10 ek; çevrimiçi durumu SignalR (`/messengerhub`) |
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. Kök `App.Hr.Intranet`; her yönetim ekranının kökü + standart alt
|
||||
yetkiler (`.Create/.Update/.Delete/.Export/.Import`, ana ekranlarda `.Note`). Duyuru, Anket, Sosyal
|
||||
Paylaşım ve Etkinlik ayrıca **`.Widget`** taşır — pano kutusunu görme yetkisidir. Dokümanlar:
|
||||
`App.Hr.Intranet.Document` + `.Create` (yükle) / `.Update` (yayına al/kaldır) / `.Delete`.
|
||||
Intranet Widgets: `App.DeveloperKit.IntranetWidgets` (+ CRUD). Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
Önerilen dağıtım:
|
||||
|
||||
| Rol | Yetkiler |
|
||||
| --- | --- |
|
||||
| Tüm çalışanlar | `AbpIdentity.Users.Widget`, `App.Files.Widget`, dört `.Widget` yetkisi, `App.Hr.Intranet.Document` (okuma); performans kutuları için `HrPerformance.md` §6 |
|
||||
| İç iletişim | `App.Hr.Intranet` dalının tamamı |
|
||||
| Sistem yöneticisi | `App.DeveloperKit.IntranetWidgets` |
|
||||
|
||||
**Kontrol edilmeli — güvenlik:** `IntranetAppService`, `MessengerAppService` ve dosya yöneticisi servisi
|
||||
yalnız oturum ister (`[Authorize]`); `App.Hr.Intranet.*` yetkilerini sunucuda denetlemez. Pano
|
||||
kutularının yetkisi (`PermissionName`) sunucuda süzülür, doküman yetkileri ise **yalnız arayüzde**
|
||||
uygulanır.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kaynak | Kullanım |
|
||||
| --- | --- |
|
||||
| `AbpUsers` (+ departman, pozisyon) | Doğum günleri, yazar/kullanıcı kartları, mesajlaşma rehberi |
|
||||
| Dosya yöneticisi / CDN (`intranet`, `intranet/_passive`) | Doküman kütüphanesi ve pano doküman kutusu |
|
||||
| Developer Kit › Custom Components | Custom pano kutuları |
|
||||
| SignalR (`/messengerhub`) | Mesajlaşma ve çevrimiçi durumu |
|
||||
| Organizasyon Şeması | Kullanıcı satırlarında sosyal duvarın `UserProfileCard` bileşenini kullanır |
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. İç iletişim **Duyurular**'a "Yeni ofis açılışı"nı görsel ve HTML içerikle ekler, **sabitler** → panonun sağ kolonunda görünür.
|
||||
2. **Anketler**'de "Çalışan Memnuniyet Anketi"ni anonim ve aktif açar; **Sorular** sekmesine puanlama, çoktan seçmeli (seçenekleriyle) ve metin soruları ekler.
|
||||
3. Çalışan panoda anketi doldurur, sonradan yanıtını günceller; İK **Yanıtlar** sekmesinden sonuçları görür (anonimde kişi boş).
|
||||
4. **Etkinlikler**'de "Jazz Akşamı" tarih, yer ve fotoğraflarla yayınlanır → "Yaklaşan Etkinlikler" kutusunda çıkar; çalışanlar beğenir/yorumlar.
|
||||
5. Çalışan sosyal duvarda iki seçenekli bir anket paylaşır; diğerleri oy verir.
|
||||
6. Doküman sorumlusu "İzin Prosedürü.pdf"i yükler ve yayına alır → pano doküman kutusunda indirilebilir olur.
|
||||
7. Sistem yöneticisi Intranet Widgets'a bir custom component'i (ör. kurum KPI kartı) orta kolona ekler.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar ve bilinen sınırlar
|
||||
|
||||
**Duyuru panoda görünmüyor.** Kutu yalnız sabitlenmiş duyuruları (en fazla 3) gösterir; listelenmek için **Sabitle** işaretli olmalı.
|
||||
|
||||
**Süresi dolmuş duyuru/anket hâlâ görünüyor.** Sunucuda son tarih süzmesi yoktur; duyuru sabitlemesi kaldırılmalı, anket `passive` yapılmalıdır.
|
||||
|
||||
**Pano yerleşimim başka bilgisayarda yok.** Yerleşim tarayıcıda saklanır.
|
||||
|
||||
**Pano kutusu görünmüyor.** Kayıt aktif olmalı ve kullanıcıda `PermissionName` yetkisi bulunmalı; Custom kutuda bileşen aktif olmalı.
|
||||
|
||||
**Yanıtlarımı değiştirebilir miyim?** Evet; anketi tekrar açıp kaydetmek önceki yanıtı günceller.
|
||||
|
||||
Kontrol edilmeli (koddan tespit edilenler):
|
||||
- Ankete oy sunucuda kullanıcı bazında tutulmaz (`PollUserVoteId` tek kolon); aynı kullanıcı API'yi doğrudan çağırarak tekrar oy verebilir.
|
||||
- `SocialPost.IsLiked` beğenen son kullanıcıya göre veritabanına yazılır; listelerken sunucu kullanıcıya göre yeniden hesaplar.
|
||||
- Duyuru modalındaki ekler bölümü dizi bekler, `Attachments` metindir; ekler görünmeyebilir.
|
||||
- Anket entity açıklaması `draft|active|closed` der, ekran `active|passive` sunar.
|
||||
- Sosyal paylaşımda yüklenen medya base64 olarak veritabanına yazılır; büyük dosyalar tabloyu büyütür.
|
||||
- `Hr_T_EventPhoto` tablosu ve `sql/object/Hr_T_EventPhoto.sql` yoktur (referans dokümanda geçer); etkinlik fotoğrafları `Hr_T_Event.Photos` kolonundadır.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Hr.cs` | Yönetim ekranları |
|
||||
| `api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Saas.cs` | Intranet Widgets ekranı |
|
||||
| `api/src/Sozsoft.Platform.Domain/Entities/Tenant/Hr/Intranet/*.cs`, `Entities/Tenant/Administration/IntranetWidget.cs`, `Entities/Tenant/Messenger*.cs` | Entity'ler |
|
||||
| `api/src/Sozsoft.Platform.Application/Intranet/IntranetAppService.cs`, `Messenger/MessengerAppService.cs` | Servisler |
|
||||
| `ui/src/views/intranet/Dashboard.tsx`, `widgets/*`, `SocialWall/*`, `documents/IntranetDocuments.tsx` | Pano, kutular, sosyal duvar, doküman sayfası |
|
||||
| `ui/src/components/template/MessengerWidget.tsx` | Mesajlaşma penceresi |
|
||||
| `configs/seeds/host/data/App.Hr.Intranet.*.json`, `App.DeveloperKit.IntranetWidgets.json` | Örnek veri ve pano kutuları |
|
||||
|
||||
Örnek veri:
|
||||
- 5 duyuru (3'ü sabitlenmiş).
|
||||
- 3 anket, 10 soru ve 13 seçenek.
|
||||
- 6 paylaşım: 4 medya (2 resim, 1 video, 1 anket), 8 yorum.
|
||||
- 50 etkinlik türü, 5 kategori, 3 etkinlik ve 9 yorum.
|
||||
187
configs/seeds/host/docs/modules/HrOrganization.md
Normal file
187
configs/seeds/host/docs/modules/HrOrganization.md
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
# İK › Organizasyon ve Yetkinlik (Departman, Pozisyon, Organizasyon Şeması, Yetenek Tipleri)
|
||||
|
||||
Şirketin organizasyon iskeleti ve yetkinlik sözlüğü: şubeye bağlı departman ağacı, departmana bağlı
|
||||
pozisyon ağacı, bunların görsel organizasyon şeması ve yetenek tipi → yetenek → seviye sözlüğü.
|
||||
Çalışanın departman/pozisyon/işe giriş/vardiya bilgileri ve yetkinlikleri kullanıcı kaydında tutulur.
|
||||
Diğer bütün İK modülleri (İşe Alım, Eğitim, Performans, Disiplin, Sağlık Kartı…) bu tanımları lookup
|
||||
olarak kullanır. Bu bölüm **entity + C# seeder** ile kuruludur (wizard değil); Organizasyon Şeması
|
||||
özel bir React sayfasıdır.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| İK | Departman ve pozisyon ağacını, yetenek sözlüğünü yönetir | İK › Tanımlamalar › Departmanlar · Pozisyonlar · Yetenek Tipleri |
|
||||
| İK / sistem yöneticisi | Çalışanın departman, pozisyon, işe giriş, vardiya, yetkinlik ve dil bilgilerini girer | Kimlik › Kullanıcılar › detay (İş Bilgileri, Eğitim ve Yetkinlik sekmeleri) |
|
||||
| Tüm kullanıcılar (yetkili) | Organizasyonu departman ya da pozisyon bazında görür, JPG olarak dışa aktarır | İK › Organizasyon Şeması |
|
||||
|
||||
Kapsam: kiracı. Departman ve pozisyon **şube bazlıdır** (`BranchId` zorunlu); ekranlarda satır süzmesi yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Bu bölüm §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar koddan
|
||||
> (`ListFormSeeder_Hr.cs`, entity'ler, `OrgChartAppService`, `OrgChart.tsx`) okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Entity + `ListFormSeeder_Hr.cs` (migration'lı tablolar); şema için özel React sayfası + AppService |
|
||||
| Departman | Ağaç (`ParentId`), şubeye bağlı; varsayılan görünüm **Tree**; aynı şubede ad tekil |
|
||||
| Pozisyon | Ağaç (`ParentId` = üst pozisyon), departmana ve şubeye bağlı; varsayılan görünüm **Tree**; aynı departmanda ad tekil |
|
||||
| Yönetici ilişkisi | Departmanda yönetici alanı **yoktur**; hiyerarşi pozisyon ağacından okunur |
|
||||
| Host şubesi | Host varsayılan şubesi sabit kimlikle kurulur (`PlatformConsts.Branches.BranchIdDefaultValue = 1c125bf3-…`); seed departman/pozisyon satırları buna bağlıdır, kiracı şubeleri yeni GUID alır |
|
||||
| Admin varsayılanı | Admin kullanıcı departman **Yönetim**, pozisyon **Genel Müdür** ile kurulur |
|
||||
| Yetkinlik sözlüğü | Yetenek Tipi ekranının iki alt formu: Seviyeler (ad + `Progress` 0–100 kaydırıcı + varsayılan) ve Yetenekler |
|
||||
| Çalışan yetkinliği | İki ayrı ölçek: **diller** `Hr_T_SkillLevel` seviyesiyle (`UserLanguage`), **diğer yetkinlikler** sabit 1–5 ile (`Adm_T_UserSkill`) |
|
||||
| Tip adı bağımlılığı | Bazı lookup'lar tip adını sabit yazar (`'Languages'`, `'Technical Skills'`) — bu tipler yeniden adlandırılmamalıdır |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
| Menü (TR) | `ListFormCode` / rota | Yer | Görünüm | Alt formlar |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Yetenek Tipleri | `App.Hr.SkillType` | Tanımlamalar (1) | Grid | `App.Hr.SkillLevel`, `App.Hr.Skill` (`Id → SkillTypeId`) |
|
||||
| Departmanlar | `App.Hr.Department` | Tanımlamalar (2) | **Tree** (`Id`/`ParentId`, tümü açık) | — |
|
||||
| Pozisyonlar | `App.Hr.JobPosition` | Tanımlamalar (3) | **Tree** | — |
|
||||
| Organizasyon Şeması | `/admin/organization` (`@/views/admin/hr/OrgChart`) | `İnsan Kaynakları` (4) | Özel sayfa | — |
|
||||
|
||||
Bu ekranlarda widget yoktur ve veri seed dosyasına aynalanmaz (`SeedSync*` kapalı).
|
||||
|
||||
**Organizasyon Şeması** (`ui/src/views/admin/hr/OrgChart.tsx`):
|
||||
- **Mod:** Departman ya da Pozisyon.
|
||||
- **Kullanıcıları göster:** Açık/kapalı seçilebilir.
|
||||
- **Yakınlaştırma:** %30–300 arası, Ctrl + tekerlek ile de.
|
||||
- **Dışa aktarma:** JPG olarak.
|
||||
- **Kartlar:** Derinliğe göre renklenir, alt sayısı ve aç/kapa düğmesi taşır, sürüklenerek yeri değiştirilir (yer kaydedilmez).
|
||||
- **Kullanıcı satırı:** Avatar gösterir; üzerine gelince profil kartı açılır (unvan, departman, e-posta, telefon).
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
```
|
||||
Sas_T_Branch ──< Hr_T_Department (ParentId ağacı) ──< Hr_T_JobPosition (ParentId ağacı)
|
||||
▲
|
||||
AbpUsers.DepartmentId / JobPositionId / HireDate / ShiftId ┘
|
||||
|
||||
Hr_T_SkillType ──< Hr_T_SkillLevel (Progress, IsDefault)
|
||||
└────────< Hr_T_Skill ──< Adm_T_UserSkill (Level 1–5)
|
||||
└────< UserLanguage (SkillLevelId)
|
||||
```
|
||||
|
||||
| Tablo | Kolonlar | Kural |
|
||||
| --- | --- | --- |
|
||||
| `Hr_T_Department` | `BranchId` (zorunlu), `Name` (64), `ParentId` | `UX (TenantId, BranchId, Name)` |
|
||||
| `Hr_T_JobPosition` | `BranchId` (zorunlu), `DepartmentId` (zorunlu, FK Restrict), `Name` (64), `ParentId` | `UX (TenantId, Name, DepartmentId)` |
|
||||
| `Hr_T_SkillType` | `Name` (128) | `UX (TenantId, Name)`; silinince yetenek/seviye kademeli silinir |
|
||||
| `Hr_T_SkillLevel` | `SkillTypeId`, `Name`, `Progress` (int, 0), `IsDefault` | `UX (TenantId, SkillTypeId, Name)` |
|
||||
| `Hr_T_Skill` | `SkillTypeId`, `Name` | `UX (TenantId, SkillTypeId, Name)` |
|
||||
| `Adm_T_UserSkill` | `UserId`, `SkillId`, `Level`, `Note` (512) | `CHECK Level BETWEEN 1 AND 5`; `UX (TenantId, UserId, SkillId)` |
|
||||
| `AbpUsers` (genişletme) | `DepartmentId`, `JobPositionId`, `HireDate`, `ShiftId`, sözleşme/fesih/ehliyet alanları | `PlatformModuleExtensionConfigurator`, `AbpIdentityUserExtensions` |
|
||||
|
||||
Entity'ler: `Entities/Tenant/Hr/Definitions/{SkillType,Skill,SkillLevel,Department,JobPosition}.cs`
|
||||
(`FullAuditedEntity<Guid>, IMultiTenant`); EF yapılandırması `PlatformDbContext.cs`.
|
||||
|
||||
Seed (`configs/seeds/host/data/`):
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `App.Hr.Department.json` | Yönetim (kök) → Üretim, Satış, Finans (→ Muhasebe), Bilgi İşlem |
|
||||
| `App.Hr.JobPosition.json` | Genel Müdür (kök) → BT, İhracat, İç Piyasa, Üretim, Finans müdürleri; Finans Müdürü → Muhasebe Müdürü → Muhasebe Şefi |
|
||||
| `App.Hr.SkillType.json` | Languages, Soft Skills, Technical Skills |
|
||||
| `App.Hr.Skill.json` | 31 yetenek: 21 dil, 3 soft skill, 7 teknik |
|
||||
| `App.Hr.SkillLevel.json` | Diller C2 100 · C1 85 · B2 75 · B1 60 · A2 40 · A1 10 (varsayılan); Soft Skills Expert 100 · Advanced 80 · Intermediate 50 · Elementary 25 · Beginner 15 (varsayılan); **Technical Skills için seviye yok** |
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları
|
||||
|
||||
| Yer | Kural |
|
||||
| --- | --- |
|
||||
| Departman formu | Ad → üst departman → şube; şube değişince üst departman temizlenir; üst departman listesi şubeye göre süzülür |
|
||||
| Pozisyon formu | Ad → üst pozisyon → şube → departman; şube değişince departman ve üst pozisyon, departman değişince üst pozisyon temizlenir. Üst pozisyon listesi seçilen departmanın **ve üst departmanlarının** pozisyonları + tüm kök pozisyonlardır (`JobPositionFullValues`) |
|
||||
| Seviye — yeni kayıt | `IsDefault = true` (tek varsayılan zorlanmaz) |
|
||||
| Kullanıcı — İş Bilgileri | Departman değişince pozisyon temizlenir, pozisyon listesi departmana göre süzülür; deneme süresi sonu işe girişten önce ya da 4 aydan sonra olamaz (`PlatformIdentityAppService`) |
|
||||
| Şema — Departman modu | Her departman kartında o departmanın **en üst pozisyonu** ve yalnızca o pozisyondaki kullanıcılar gösterilir (üst pozisyonu olmayan ya da üstü başka departmanda olan; ada göre ilk) |
|
||||
| Şema — Pozisyon modu | Her pozisyon bir kart; o pozisyondaki tüm kullanıcılar |
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`:
|
||||
|
||||
| Yetki | Üst | Alt yetkiler |
|
||||
| --- | --- | --- |
|
||||
| `App.Hr.SkillType` | `App.Hr.Definitions` | Create, Update, Delete, Export, Import, Note |
|
||||
| `App.Hr.SkillLevel`, `App.Hr.Skill` | `App.Hr.Definitions` | Create, Update, Delete, Export, Import |
|
||||
| `App.Hr.Department`, `App.Hr.JobPosition` | `App.Hr.Definitions` | Create, Update, Delete, Export, Import |
|
||||
| `App.Hr.OrgChart` | grup kökü | — (menü ve rota bu yetkiyi ister) |
|
||||
|
||||
Çalışanın iş bilgileri ve yetkinlikleri kullanıcı ekranının yetkileriyle (`AbpIdentity.Users.*`) düzenlenir.
|
||||
Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar (kim kullanıyor)
|
||||
|
||||
| Tanım | Kullanan modüller |
|
||||
| --- | --- |
|
||||
| Departman / Pozisyon | İşe Alım (talep, ilan, teklif), Eğitim katılımcısı, Disiplin dosyası, Sağlık Kartı listesi, Performans değerlendirmesi, kullanıcı ekranı, Organizasyon Şeması |
|
||||
| Yetenek / Seviye | Aday yetkinlikleri, eğitimin kazandırdıkları, Performans yetkinlik değerlendirmesi (seviye `Progress` = puan), kullanıcı dil ve yetkinlik listeleri |
|
||||
| `Adm_T_UserSkill` | Performans Yönetimi tamamlanınca yönetici seviyesini buraya yazar (bkz. `HrPerformance.md`) |
|
||||
| Vardiya (`ShiftId`) | Bkz. `HrWorkCalendar.md` |
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. İK **Departmanlar**'a "Kalite" departmanını şube Merkez, üst departman Üretim olarak ekler (ağaçta Üretim'in altında görünür).
|
||||
2. **Pozisyonlar**'a "Kalite Şefi"ni departman Kalite, üst pozisyon Üretim Müdürü olarak ekler.
|
||||
3. Kullanıcı detayının **İş Bilgileri** sekmesinde çalışanın departmanı Kalite, pozisyonu Kalite Şefi, işe giriş tarihi ve vardiyası girilir; **Eğitim ve Yetkinlik** sekmesine İngilizce B2 ve "Kaynak Uzmanı 4/5" eklenir.
|
||||
4. **Organizasyon Şeması** Pozisyon modunda Kalite Şefi kartı Üretim Müdürü'nün altında, çalışanla birlikte görünür; şema JPG olarak dışa aktarılır.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar ve bilinen sınırlar
|
||||
|
||||
**Departman yöneticisi nerede?** Yok; hiyerarşi pozisyon ağacındadır. (Performans modülü bu yüzden yöneticiyi değerlendirme kaydında tutar.)
|
||||
|
||||
**Şemada departman kartında neden tüm çalışanlar yok?** Departman modunda yalnız en üst pozisyondakiler gösterilir; herkes için Pozisyon modunu kullanın.
|
||||
|
||||
**Şemadaki kart yerleri kaydedilmiyor.** Sürükleme yalnız görünümü değiştirir.
|
||||
|
||||
**Teknik yetenekler için seviye seçilemiyor.** Seed'de Technical Skills tipine seviye tanımlı değil; kullanıcı yetkinliği 1–5 ölçeğiyle girilir. Performans modülünde bu tipe seviye eklenmesi gerekir.
|
||||
|
||||
**"Languages" tipinin adını değiştirdim, dil listesi boşaldı.** Lookup'lar tip adını sabit kullanır (`TenantLanguageSkillValues`, `TechnicalSkillsValues`).
|
||||
|
||||
Kontrol edilmeli (koddan tespit edilen tutarsızlıklar):
|
||||
- Organizasyon Şeması API'si (`api/app/org-chart`) yalnız oturum ister, `App.Hr.OrgChart` yetkisini denetlemez; menü ve rota yetkiyle korunur.
|
||||
- `BranchDepartmentValues` ve `JobPositionFullValues` lookup'larında açık kiracı koşulu yoktur; `JobPositionFullValues` departmandan bağımsız tüm kök pozisyonları da listeler.
|
||||
- Yetenek alt formunun popup başlığı Seviye ekranının anahtarını kullanır (`ListFormSeeder_Hr.cs`).
|
||||
- Yetenek Tipi/Seviye/Yetenek yetkileri `MultiTenancySide 2`, Departman/Pozisyon `3`'tür.
|
||||
- Bir tipte birden çok varsayılan seviye işaretlenebilir.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Hr.cs` | Beş ekranın ListForm tanımı |
|
||||
| `api/src/Sozsoft.Platform.Domain/Entities/Tenant/Hr/Definitions/*.cs` | Entity'ler |
|
||||
| `api/src/Sozsoft.Platform.Application/OrgChart/OrgChartAppService.cs`, `Application.Contracts/OrgChart/OrgChartDto.cs` | Şema API'si (`GET departments`, `GET job-positions`) |
|
||||
| `ui/src/views/admin/hr/OrgChart.tsx`, `ui/src/services/orgChart.service.ts` | Şema sayfası |
|
||||
| `ui/src/views/admin/user-management/Details.tsx`, `EducationSkillsTab.tsx` | Kullanıcı iş bilgileri ve yetkinlik sekmeleri |
|
||||
| `api/src/Sozsoft.Platform.Application.Contracts/LookUpQueryValues.cs` | Şube/departman/pozisyon/yetenek lookup'ları |
|
||||
| `configs/seeds/host/data/App.Hr.{Department,JobPosition,SkillType,Skill,SkillLevel}.json` | Seed |
|
||||
| `configs/seeds/host/data/App.Menus.Routes.json` (`admin.hr.organization`) | Şema rotası |
|
||||
|
||||
Bu tablolar migration'lıdır; ekranlar seeder'dan kurulduğu için Wizard Manager'dan silinmez.
|
||||
1060
configs/seeds/host/docs/modules/HrPerformance.md
Normal file
1060
configs/seeds/host/docs/modules/HrPerformance.md
Normal file
File diff suppressed because it is too large
Load diff
181
configs/seeds/host/docs/modules/HrPersonnel.md
Normal file
181
configs/seeds/host/docs/modules/HrPersonnel.md
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
# İK › Personel Kaydı (Kimlik › Kullanıcılar › detay)
|
||||
|
||||
Çalışanın özlük kaydı ayrı bir İK ekranında değil, kullanıcı detay sayfasındadır
|
||||
(`/admin/users/detail/:userId`): iletişim ve ek bilgiler, askerlik, engellilik, nüfus/kimlik, doğum ve
|
||||
aile, yabancı uyruklu belgeleri, organizasyon (departman/pozisyon/vardiya), sözleşme ve deneme süresi,
|
||||
işten çıkış, sürücü belgesi, eğitim geçmişi, yabancı diller, yetenekler, yeterlilik belgeleri, eş ve
|
||||
çocuklar, acil durum kişileri, banka ve ücret bilgileri, yan haklar, iş deneyimi. (Sağlık Kartı sekmesi
|
||||
için bkz. [HrHealthCard.md](HrHealthCard.md).) Tek değerli alanlar `AbpUsers` genişletme kolonlarında,
|
||||
çok kayıtlılar `Adm_T_User*` tablolarındadır; diğer İK modüllerinin hepsi çalışanı buradan okur.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| İK / özlük | Personelin bütün özlük, sözleşme, eğitim, aile ve mali bilgisini girer | Kimlik › Kullanıcılar › Detay |
|
||||
| Sistem yöneticisi | Kullanıcıyı açar; listede temel alanları (departman, pozisyon, cinsiyet, adres…) düzenler | Kimlik › Kullanıcılar |
|
||||
| Yönetici | Deneme süresi bitimine 15 gün kala bildirim alır | Bildirimler |
|
||||
|
||||
Kapsam: kiracı. Rota yetkisi `AbpIdentity.Users.Update`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar koddan (`Details.tsx` ve sekme
|
||||
> bileşenleri, `PlatformIdentityAppService`, `ListFormSeeder_Administration.cs`, entity'ler) okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yer | Ayrı "personel" tablosu yok; özlük = kullanıcı. Tek değerli alanlar ABP extra property olarak `AbpUsers` kolonları |
|
||||
| Çok kayıtlı bilgiler | `Adm_T_User{WorkExperience,Education,Language,Skill,Certificate,FamilyMember,EmergencyContact,Benefit}`; detay sekmelerinde gömülü liste (`App.IdentityManagement.*`), yeni satırın `UserId`'si sayfa filtresinden dolar |
|
||||
| Kaydetme | Her form sekmesi kendi formuyla bütün modeli `PUT /api/app/platform-identity/user` (`UpdateUserAsync`) ile gönderir; başka sekmede kaydedilmemiş değişiklik gitmez |
|
||||
| Mali bilgiler | Ayrı DTO ve uç (`GetFinancialAsync` / `UpdateFinancialAsync`, `Users.Update` yetkisi) — intranet listelerine akan `UserInfoViewModel`'de taşınmasın diye |
|
||||
| Deneme süresi | İşe giriş ile işe giriş + **4 ay** arasında olmalı (4857 s. İK md. 15; toplu sözleşmeyle 4 ay) — hem formda hem sunucuda |
|
||||
| Koşullu alanlar | Tecil bitişi yalnız "Tecilli"de, sözleşme bitişi yalnız "Belirli Süreli"de, yabancı uyruklu bölümü yalnız TR dışı uyrukta, engellilik oranı/raporu yalnız "Engelli"de **görünür**; gizlenince değer silinmez |
|
||||
| Ölçekler | Dil seviyesi `Hr_T_SkillLevel` ile, diğer yetenekler sabit 1–5 ile (bkz. [HrOrganization.md](HrOrganization.md)) |
|
||||
| Saklama biçimleri | Engellilik raporu ve avatar dışındaki dosyalar base64 kolonda; ehliyet sınıfları `|` ile birleştirilmiş metin; medeni durum ve eğitim düzeyi Türkçe anahtar |
|
||||
|
||||
---
|
||||
|
||||
## 3. Ekranlar ve sekmeler
|
||||
|
||||
| Sekme (TR) | İçerik | Kayıt |
|
||||
| --- | --- | --- |
|
||||
| Genel | İletişim (e-posta, ikinci e-posta, ad, soyad, telefon, ikinci telefon, kullanıcı tipi İç/Dış), ek bilgiler (ev adresi, uyruk, cinsiyet), askerlik (durum: Yapıldı/Muaf/Tecilli/Yapılmadı + tecil bitişi), avatar (kırpma, ≤ 2 MB), engellilik (engelli, oran %, rapor PDF/JPG/PNG ≤ 5 MB) | `UpdateUserAsync` (+ avatar `UpdateAvatarAsync`) |
|
||||
| Kimlik Bilgileri | Nüfus cüzdanı (kimlik no, seri no, veriliş yeri/tarihi, il, ilçe, köy, cilt, aile sıra, sıra no), doğum ve aile (doğum yeri/tarihi, baba/anne adı, medeni durum Bekar/Evli/Boşanmış/Dul, evlenme tarihi), yabancı uyruklu (pasaport no/geçerlilik, çalışma izni no/bitiş) | `UpdateUserAsync` |
|
||||
| İş | Organizasyon (departman → pozisyon, sicil no, SGK no, vardiya grubu, PDKS kart no), sözleşme (çalışma şekli Tam/Yarı Zamanlı, sözleşme türü Belirsiz/Belirli, işe başlama, sözleşme bitişi, deneme süresi bitişi, kıdem başlangıcı), işten çıkış (tarih, SGK çıkış kodu, açıklama), sürücü belgesi (sınıflar çoklu M…G, no, veriliş, geçerlilik), iletişim kanalları (Rocket, Telegram) + **Daha Önce Çalıştığı Yerler** listesi | `UpdateUserAsync` + `App.IdentityManagement.UserWorkExperience` |
|
||||
| Eğitim ve Yetenekler | En yüksek eğitim seviyesi + **Eğitim Geçmişi**, **Yabancı Diller**, **Yetenekler**, **Yeterlilik Belgeleri** listeleri | `UpdateUserAsync` + 4 liste |
|
||||
| Aile / Acil Durum | **Eş ve Çocuklar**, **Acil Durum Kişileri** listeleri | 2 liste |
|
||||
| Finansal | Banka adı, IBAN; ücret tipi Aylık/Günlük/Saatlik, brüt ücret, para birimi + **Yan Haklar** listesi | `UpdateFinancialAsync` + `App.IdentityManagement.UserBenefit` |
|
||||
| Sağlık Kartı | Bkz. [HrHealthCard.md](HrHealthCard.md) | — |
|
||||
|
||||
Gömülü listeler (hepsi menüsüz alt liste, `Adm_T_*`):
|
||||
|
||||
| Liste | Alanlar | Kural |
|
||||
| --- | --- | --- |
|
||||
| `UserWorkExperience` | Firma*, iş kolu* (sektör), giriş*, çıkış, yaptığı iş (HTML) | Giriş tarihine göre azalan |
|
||||
| `UserEducation` | Eğitim düzeyi* (İlkokul…Doktora), okul*, bölüm, başlangıç, mezuniyet, mezun (varsayılan evet) | — |
|
||||
| `UserLanguage` | Dil* ("Languages" tipi yetenekler), seviye (dilin seviyeleri), not | Kullanıcı × dil tekil |
|
||||
| `UserSkill` | Yetenek* (dil dışı tipler), seviye* 1–5 (Başlangıç…Uzman, varsayılan 3), not | `CHECK 1–5`; kullanıcı × yetenek tekil |
|
||||
| `UserCertificate` | Belge* (`Hr_T_Certificate`), belge no, veren kurum, düzenleme, son kullanma, not | Son kullanmaya göre artan |
|
||||
| `UserFamilyMember` | Yakınlık* (Eş/Çocuk), ad*, soyad, TC kimlik, doğum tarihi, çalışma durumu (Çalışıyor/Çalışmıyor/Öğrenci/Emekli), sigorta kapsamında, yan hak kapsamında | — |
|
||||
| `UserEmergencyContact` | Ad soyad*, yakınlık* (Eş, Anne/Baba, Kardeş, Çocuk, Akraba, Arkadaş, Diğer), telefon* | — |
|
||||
| `UserBenefit` | Yan hak türü* (`Hr_T_BenefitType`, **kod** saklanır), tutar, başlangıç, bitiş, not | — |
|
||||
|
||||
Kullanıcı listesi (`AbpIdentity.Users`) popup'ında düzenlenen İK alanları: departman*, pozisyon*,
|
||||
cinsiyet, ev adresi (+ avatar, e-posta, ad, soyad, tip, telefon, çalışma saati). Diğer özlük alanları
|
||||
listede gizli kolon olarak durur.
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
| Yer | İçerik |
|
||||
| --- | --- |
|
||||
| `AbpUsers` genişletme kolonları | Bütün form sekmesi alanları; sabitler `PlatformConsts.AbpIdentity.User.*`, erişim `AbpIdentityUserExtensions`, kolon tipleri `PlatformEfCoreEntityExtensionMappings` |
|
||||
| `Adm_T_UserWorkExperience` | `CompanyName`, `SectorId` (FK Sector), `StartDate`, `EndDate`, `JobDescription` |
|
||||
| `Adm_T_UserEducation` | `EducationLevel`, `SchoolName`, `Department`, `StartDate`, `EndDate`, `IsGraduated` |
|
||||
| `Adm_T_UserLanguage` | `SkillId` (FK Skill), `SkillLevelId` (FK SkillLevel), `Note` |
|
||||
| `Adm_T_UserSkill` | `SkillId`, `Level` (1–5), `Note` |
|
||||
| `Adm_T_UserCertificate` | `CertificateId` (`Hr_T_Certificate`, FK'siz), `CertificateNo`, `IssuedBy`, `IssueDate`, `ExpiryDate`, `Note` |
|
||||
| `Adm_T_UserFamilyMember` | `Relationship`, `Name`, `Surname`, `IdentityNumber`, `BirthDate`, `EmploymentStatus`, `IsInsuranceCovered`, `IsBenefitCovered` |
|
||||
| `Adm_T_UserEmergencyContact` | `Name`, `Relationship`, `PhoneNumber` |
|
||||
| `Adm_T_UserBenefit` | `BenefitType` (kod), `Amount`, `StartDate`, `EndDate`, `Note` |
|
||||
|
||||
Entity'ler `Entities/Tenant/Administration/User*.cs` (`FullAuditedEntity<Guid>, IMultiTenant`), EF
|
||||
yapılandırması `PlatformDbContext.cs`.
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları
|
||||
|
||||
| Yer | Kural |
|
||||
| --- | --- |
|
||||
| Deneme süresi | `HireDate ≤ ProbationEndDate ≤ HireDate + 4 ay`; formda gün bazında, sunucuda (`UpdateUserAsync`) tam zamanla |
|
||||
| Departman değişimi | Pozisyon temizlenir; pozisyon listesi departmana göre süzülür |
|
||||
| IBAN | Formda boşluk silinir, büyük harfe çevrilir, `^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$` deseni; sunucu yalnız normalleştirir |
|
||||
| Engellilik raporu | ≤ 5 MB (yalnız formda), base64 olarak kolonda |
|
||||
| Avatar | `{userId}.jpg` avatar blob kabına yazılır; boş gönderim siler |
|
||||
| Deneme süresi hatırlatması | `ProbationReminderWorker` günlük çalışır; aktif, çıkışı olmayan ve deneme bitişi **bugün + 15 gün** olan kullanıcılar için `DenemeSuresiBitiyor` bildirimi üretir (tip yoksa atlar) |
|
||||
| Doğum günü | `BirthDate` intranet panosundaki "Bugün Doğanlar" kutusunu besler (bkz. [HrIntranet.md](HrIntranet.md)) |
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
| İşlem | Yetki |
|
||||
| --- | --- |
|
||||
| Detay sayfası (rota), liste "Detay" butonu | `AbpIdentity.Users.Update` |
|
||||
| Gömülü listeler | okuma `AbpIdentity.Users`; ekle/güncelle/sil `AbpIdentity.Users.Update` (Yan Haklar alanlarında ekleme `Users.Create`) |
|
||||
| Mali bilgiler, avatar | `AbpIdentity.Users.Update` (sunucuda) |
|
||||
| Kullanıcı listesi ekle/güncelle | `Users.Create` / `Users.Update` |
|
||||
|
||||
Özlük verisi kişisel veri, sağlık ve engellilik verisi özel nitelikli kişisel veridir (KVKK). Kullanıcı
|
||||
yönetimi yetkisi yalnız İK ve sistem yöneticilerinde olmalıdır.
|
||||
|
||||
**Kontrol edilmeli — güvenlik (koddan tespit edildi):**
|
||||
- `PlatformIdentityAppService.GetByIdAsync` ve `UpdateUserAsync` yalnız oturum ister (`[Authorize]`); `Users.Update` yalnız arayüz rotasında denetlenir. Oturum açmış herhangi bir kullanıcı API'yi doğrudan çağırarak başka birinin özlük kaydını (engellilik raporu dahil) okuyup güncelleyebilir.
|
||||
- Banka, IBAN ve ücret alanları `AbpIdentity.Users` listesinde gizli ama okunabilir/dışa aktarılabilir kolon olarak durur; liste okuma yetkisi olan kullanıcı kolon seçiciyle görebilir.
|
||||
- Intranet doğum günü listesine giden `UserInfoViewModel` kimlik no, SGK no ve sağlık kartı alanlarını da taşır.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kullanan | Okuduğu |
|
||||
| --- | --- |
|
||||
| Tüm İK modülleri | Çalışan, departman, pozisyon |
|
||||
| Organizasyon Şeması | Pozisyondaki kullanıcılar |
|
||||
| Vardiyalar / Olay Günlüğü | `ShiftId` |
|
||||
| Yeterlilik Belgeleri, Yan Hak Türleri, Sektörler, SGK çıkış kodları, Para Birimleri | Lookup kaynakları |
|
||||
| Performans Yönetimi | Tamamlanan değerlendirme `Adm_T_UserSkill`'e yazar |
|
||||
| İşe Alım | İşe alınan adayın kaydı kullanıcıya `UserId` ile bağlanır |
|
||||
| Intranet | Doğum günleri, kullanıcı kartları |
|
||||
| Bildirimler | Deneme süresi hatırlatması (`DenemeSuresiBitiyor`) |
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. BT kullanıcıyı listeden açar (ad, e-posta, departman, pozisyon). İK **Detay**'a girer.
|
||||
2. **Kimlik Bilgileri**: nüfus ve aile bilgileri; **Genel**: adres, uyruk, askerlik, avatar.
|
||||
3. **İş**: sicil/SGK no, vardiya, sözleşme türü Belirsiz, işe başlama 01.10, deneme süresi bitişi 01.12 (4 ayı aşarsa kayıt reddedilir); önceki iş yerleri listesi.
|
||||
4. **Eğitim ve Yetenekler**: lisans mezuniyeti, İngilizce B2, "Kaynak Uzmanı 4", forklift belgesi.
|
||||
5. **Aile / Acil Durum**: eş ve çocuk (sigorta kapsamında), acil durum kişisi.
|
||||
6. **Finansal**: banka/IBAN, aylık brüt ücret TRY; yemek kartı yan hakkı.
|
||||
7. 15 Kasım'da yöneticilere deneme süresinin bitmek üzere olduğu bildirimi gider.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar ve bilinen sınırlar
|
||||
|
||||
**Detayda e-postayı değiştirdim, kaydolmadı.** `UpdateUserAsync` e-postayı yazmaz; e-posta kullanıcı listesindeki düzenlemeden değişir.
|
||||
|
||||
**Başka sekmede yaptığım değişiklik kayboldu.** Her sekme ayrı kaydedilir; sekme değiştirmeden önce kaydedin.
|
||||
|
||||
**Sözleşmeyi Belirsiz yaptım, bitiş tarihi hâlâ kayıtlı.** Koşullu alanlar yalnız gizlenir, değer silinmez.
|
||||
|
||||
**Pozisyon listede zorunlu, detayda değil.** Doğru; kullanıcı listesi popup'ı zorunlu tutar.
|
||||
|
||||
**Acil durum kişisinde ad kolonu "Doktor Adı Soyadı" görünüyor.** Alan başlığı yanlış dil anahtarını (`App.Listform.ListformField.FullName`) kullanıyor; düzeltilmeli.
|
||||
|
||||
**Aile üyelerindeki sigorta/yan hak işaretleri bir yere gidiyor mu?** Şu an bunları okuyan bir ekran/rapor bulunmadı.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `ui/src/views/admin/user-management/Details.tsx`, `EducationSkillsTab.tsx`, `FamilyEmergencyTab.tsx`, `FinancialTab.tsx`, `userFormFields.tsx`, `useUserFieldLookup.ts` | Detay sayfası ve sekmeler |
|
||||
| `api/src/Sozsoft.Platform.Application/Identity/PlatformIdentityAppService.cs` | `GetByIdAsync`, `UpdateUserAsync`, `Get/UpdateFinancialAsync`, `UpdateAvatarAsync` |
|
||||
| `api/src/Sozsoft.Platform.Domain/Extensions/AbpIdentityUserExtensions.cs`, `EntityFrameworkCore/PlatformEfCoreEntityExtensionMappings.cs` | Genişletme alanları |
|
||||
| `api/src/Sozsoft.Platform.Domain/Entities/Tenant/Administration/User*.cs` | Çok kayıtlı entity'ler |
|
||||
| `api/src/Sozsoft.Platform.DbMigrator/Migrations/ListFormSeeder_Administration.cs` | `AbpIdentity.Users` ve `App.IdentityManagement.*` listeleri |
|
||||
| `api/src/Sozsoft.Platform.Domain/BackgroundWorkers/ProbationReminderWorker.cs` | Deneme süresi hatırlatması |
|
||||
573
configs/seeds/host/docs/modules/HrRecruitment.md
Normal file
573
configs/seeds/host/docs/modules/HrRecruitment.md
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
<!-- module-doc: claims=App.Hr.CandidateSource, App.Hr.RejectionReason, App.Hr.EvaluationCriterion -->
|
||||
# İK › İşe Alım (`App.Hr.Recruitment`)
|
||||
|
||||
Kadro talebinden işe alıma kadar uçtan uca süreç: onaylı kadro talebi → iş ilanı → aday havuzu
|
||||
(CV, KVKK açık rızası) → başvuru (aşama panosu) → mülakat (takvim, kriter ağırlıklı puan) →
|
||||
teklif (iç onay, teklif mektubu). Tamamı konfigürasyondur (Wizard + SQL + rapor şablonu); entity,
|
||||
migration ya da React kodu yoktur.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| Talep eden yönetici | Kadro talebi açar, onaya gönderir | Kadro Talepleri |
|
||||
| Onaycı | Kadro talebini ve teklifi onaylar / reddeder | Kadro Talepleri · Teklifler (Grid Workflow butonları) |
|
||||
| İK / işe alım uzmanı | İlan açar, aday ve başvuruları yönetir, mülakat planlar, teklif hazırlar, aday kaydını personele bağlar | İlanlar · Adaylar · Başvurular · Mülakatlar · Teklifler |
|
||||
| Mülakatçı | Kendisine atanan mülakatta kriter bazlı puan verir | Mülakatlar (+ bildirim) |
|
||||
| İK yöneticisi | Aday kaynağı, ret sebebi, değerlendirme kriteri tanımlarını yönetir | İK › Tanımlar |
|
||||
|
||||
Kapsam: kiracı (`IsTenant`). Şube, kayıtta veri olarak tutulur (satır süzmesi yoktur).
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Aşağıdaki kararlar üretilen
|
||||
> artefaktlardan (wizard, SQL, seed, commit `16fd5df0` "İşe Alım modülü") okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Her adım ayrı Wizard ekranı; ilan ve aday ekranlarında başvuru alt formu, başvuruda mülakat ve teklif alt formu |
|
||||
| Kadro talebi ve teklif onayı | **Grid Workflow** (`WorkflowDto`): Start → Approval (`Onay Bekliyor`) → Inform → End `Onaylandı` / `Reddedildi`. Onaycı **düğümün `Approver` değeridir** (seed'de platform admin e-postası); motor onaycıyı kayıttaki alandan okumaz — ListForm › Workflow sekmesinden değiştirilir |
|
||||
| İlan kaynağı | İlan yalnızca **onaylı** (`ApprovalStatus = 'Onaylandı'`) kadro talebinden açılır; şube/departman/pozisyon/adet/çalışma şekli talepten `copy` ile dolar |
|
||||
| Aday kimliği | E-posta kiracı içinde tekildir (filtreli unique index) |
|
||||
| KVKK | Açık rıza **zorunlu**: formda zorunlu alan + tabloda `CHECK (KvkkConsent = 1)`; rıza tarihi/yöntemi/imzalı belge saklanır; satır butonu **KVKK Açık Rıza Formu** raporunu açar |
|
||||
| Başvuru | Aday × ilan çifti tekildir; aşama **Todo (kanban)** panosunda yönetilir |
|
||||
| Aşama ilerlemesi | Mülakat eklenince `Interview`, teklif eklenince `Offer`, teklif `Accepted` olunca `Hired` — SQL ile, **geri gitmez** |
|
||||
| Mülakat puanı | Kriter başına 1–5; `OverallScore = Σ(puan × kriter ağırlığı) / Σ ağırlık`; başvurunun `AverageScore`'u mülakatların ortalaması |
|
||||
| Mülakatçı bildirimi | Mülakat eklenince mülakatçıya `IseAlimMulakatAtandi` bildirimi (kanallar `UiActivity` + `Mail`) |
|
||||
| Belge numaraları | `KT-YYYY-00001` (talep), `ILN-…` (ilan), `TKL-…` (teklif) — insert sonrası SQL, kiracı + yıl bazında |
|
||||
| Personele dönüşüm | İşe alınan adayın kullanıcı (personel) kaydını **BT elle açar**; İK aday kaydını `UserId` ile o kullanıcıya bağlar (otomatik kullanıcı açılmaz) |
|
||||
| Kanban başlığı | `CandidateName` / `PostingTitle` başvuruya metin olarak kopyalanır (Todo başlığı metin kolon ister) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
`İnsan Kaynakları › İşe Alım` (`App.Hr.Recruitment`, ikon `FcManager`)
|
||||
|
||||
| Sıra | Menü (TR / EN) | `ListFormCode` | Alt formlar | Görünümler | Widget'lar |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | Kadro Talepleri / Staff Requests | `App.Hr.StaffRequest` | — | Grid, Card, Pivot, Chart | Toplam · Onay Bekliyor · Onaylanan · Onaylı kadro adedi (Σ Headcount) |
|
||||
| 2 | İlanlar / Job Postings | `App.Hr.JobPosting` | `JobApplication` (`Id → JobPostingId`) | Grid, Card, Pivot, Chart | Toplam · Yayında · Taslak · Kapalı |
|
||||
| 3 | Adaylar / Candidates | `App.Hr.Candidate` | `JobApplication` (`Id → CandidateId`) | Grid, Card, Pivot, Chart | Toplam · Aktif · Pasif · Personele Dönüşen |
|
||||
| 4 | Başvurular / Applications | `App.Hr.JobApplication` | `Interview`, `JobOffer` (`Id → ApplicationId`) | Grid, Card, Pivot, Chart, **Todo** | — (alt form olarak da kullanıldığı için yok) |
|
||||
| 5 | Mülakatlar / Interviews | `App.Hr.Interview` | `InterviewScore` (`Id → InterviewId`, menüsüz) | Grid, Card, Pivot, Chart, **Scheduler** | — |
|
||||
| 6 | Teklifler / Job Offers | `App.Hr.JobOffer` | — | Grid, Card, Pivot, Chart | — |
|
||||
|
||||
Tanımlar `İnsan Kaynakları › Tanımlar` (`App.Hr.Definitions`) altında, verileri seed dosyasıyla aynalı:
|
||||
|
||||
| Menü | `ListFormCode` | Seed |
|
||||
| --- | --- | --- |
|
||||
| Aday Kaynakları | `App.Hr.CandidateSource` | 7 kayıt: LinkedIn, Kariyer.net, Yenibiris, Şirket Web Sitesi, Referans, Kariyer Fuarı, Doğrudan Başvuru |
|
||||
| Ret Sebepleri | `App.Hr.RejectionReason` | 8 kayıt; `RejectedBy` = Company / Candidate |
|
||||
| Değerlendirme Kriterleri | `App.Hr.EvaluationCriterion` | 6 kayıt (ağırlıklı): İletişim 1, Teknik Yetkinlik 2, Problem Çözme 1.5, Takım Çalışması 1, Motivasyon 1, Kurum Kültürüne Uyum 1 |
|
||||
|
||||
Satır butonları (`DynamicReport`, `Raporlar` kategorisi):
|
||||
|
||||
| Ekran | Buton | Rapor şablonu | Görünürlük |
|
||||
| --- | --- | --- | --- |
|
||||
| Adaylar | KVKK Açık Rıza Formu | `475c1ab4-4600-5ef2-a43e-1366ed89b0ed` | Her satır |
|
||||
| Teklifler | Teklif Mektubu | `80d38666-423d-5e1d-8766-01f2c46be768` | `ApprovalStatus === 'Onaylandı'` |
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
```
|
||||
Hr_T_StaffRequest ──< Hr_T_JobPosting ──< Hr_T_JobApplication >── Hr_T_Candidate ──> AbpUsers (UserId, personel)
|
||||
│
|
||||
├──< Hr_T_Interview ──< Hr_T_InterviewScore >── Hr_T_EvaluationCriterion
|
||||
└──< Hr_T_JobOffer
|
||||
```
|
||||
|
||||
| Tablo | Önemli kolonlar | Kural |
|
||||
| --- | --- | --- |
|
||||
| `Hr_T_StaffRequest` | `RequestNo`, `RequestDate`, `RequestedById`, `BranchId` → `DepartmentId` → `JobPositionId` (cascade), `Headcount`, `EmploymentType`, `ExpectedStartDate`, `Reason` (NewPosition/Replacement), `ReplacedUserId`, ücret aralığı + `CurrencyId`, `Qualifications` (HTML), onay alanları | `Reason ≠ Replacement` ise `ReplacedUserId` temizlenir (script) |
|
||||
| `Hr_T_JobPosting` | `PostingNo`, `StaffRequestId`, `Title`, `Status` (Draft/Published/Closed/Cancelled), şube/departman/pozisyon, `Headcount`, `EmploymentType`, `WorkModel` (Office/Hybrid/Remote), `Location`, `PublishDate`, `ClosingDate`, `SourceIds` (yayın kanalları, çok değerli), açıklama/nitelikler (HTML) | Başlık boşsa pozisyon adı kopyalanır |
|
||||
| `Hr_T_Candidate` | Kişisel bilgiler, fotoğraf, ülke → şehir, eğitim (`EducationLevel`, okul, bölüm, mezuniyet), deneyim, ücret beklentisi, `SourceId`, `SkillIds` (`Hr_T_Skill`, çok değerli), `CvDocument`, `UserId`, KVKK alanları | `UX (TenantId, Email)`; `CHECK (KvkkConsent = 1)` |
|
||||
| `Hr_T_JobApplication` | `CandidateId`, `JobPostingId`, `CandidateName`, `PostingTitle`, `ApplicationDate`, `SourceId`, `OwnerUserId`, `AverageScore`, `Stage`, `RejectionReasonId`, `RejectionNote`, `SortOrder` | `UX (TenantId, CandidateId, JobPostingId)`; aşama `Rejected` değilse ret sebebi/notu temizlenir |
|
||||
| `Hr_T_Interview` | `ApplicationId`, `Title`, `InterviewType` (Phone/Video/FaceToFace/Technical/Hr), `InterviewerUserId`, `StartDate`, `EndDate`, `Location`, `MeetingUrl`, `Status` (Planned/Completed/Cancelled/NoShow), `Recommendation` (Hire/Hold/Reject), `OverallScore` | Bitiş boşsa başlangıç + 1 saat (script) |
|
||||
| `Hr_T_InterviewScore` | `InterviewId`, `CriterionId`, `Score`, `Comment` | `CHECK (Score BETWEEN 1 AND 5)`; `UX (InterviewId, CriterionId)` |
|
||||
| `Hr_T_JobOffer` | `OfferNo`, `ApplicationId`, `CandidateName`, `OfferDate`, `ValidUntil`, `StartDate`, `GrossSalary` + `CurrencyId`, `Status` (Draft/Sent/Accepted/Declined/Expired), `ResponseDate`, pozisyon bilgileri, `BenefitCodes` (`Hr_T_BenefitType`), onay alanları | `CHECK (GrossSalary >= 0)`; durum Accepted/Declined olunca yanıt tarihi bugün (script) |
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları ve hesaplar
|
||||
|
||||
### 5.1 Başvuru aşamaları
|
||||
|
||||
```
|
||||
Applied → Screening → Interview → Offer → Hired
|
||||
└──→ Rejected (her aşamadan, elle)
|
||||
```
|
||||
|
||||
| Tetik | Etki (after-command SQL) |
|
||||
| --- | --- |
|
||||
| Mülakat eklendi | Başvuru `Applied`/`Screening` ise → `Interview` |
|
||||
| Teklif eklendi | Başvuru `Applied`/`Screening`/`Interview` ise → `Offer`; teklif zaten `Accepted` ise → `Hired` |
|
||||
| Teklif güncellendi (`Accepted`) | Başvuru henüz `Hired` değilse → `Hired` |
|
||||
| Elle | Panodan sürükleme ya da formdan her aşama seçilebilir |
|
||||
|
||||
Otomatik ilerleme yalnızca ileri gider; geri almak elle yapılır.
|
||||
|
||||
### 5.2 Puanlar
|
||||
|
||||
- `Interview.OverallScore = Σ(Score × Criterion.Weight) / Σ Weight` (silinmemiş puanlar).
|
||||
- `JobApplication.AverageScore = AVG(Interview.OverallScore)` (puanı olan mülakatlar).
|
||||
- Puan eklenince, güncellenince ya da silinince ikisi de yeniden hesaplanır.
|
||||
|
||||
### 5.3 Metin kopyaları
|
||||
|
||||
`CandidateName`, `PostingTitle` (başvuru), `Title` (mülakat = aday – ilan), `CandidateName`
|
||||
(teklif) after-command ile yazılır. Aday, ilan ya da başvuru güncellendiğinde **tüm** değişmiş
|
||||
kopyalar topluca düzeltilir (sorgu `@Id` ile değil fark koşuluyla çalışır).
|
||||
|
||||
### 5.4 Numaratörler
|
||||
|
||||
`KT-`, `ILN-`, `TKL-` + yıl + 5 hane; kiracı ve yıl bazında `MAX + 1`. Numara yalnızca boşsa yazılır.
|
||||
|
||||
### 5.5 Onay akışı (Kadro Talebi, Teklif)
|
||||
|
||||
Grid Workflow; durum `ApprovalStatus`, onaylayan `ApprovalUser`, tarih `ApprovalDate`, açıklama
|
||||
`ApprovalDescription`. Onay/Ret butonlarını akış kendisi çizer. Onaycı düğümde sabittir
|
||||
(`system@sozsoft.com` seed değeri) — gerçek onaycı ListForm › Workflow'dan girilmelidir.
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. Yetki ağacı menüyü izler: `App.Hr.Recruitment` ara yetkisinin
|
||||
altında her ekranın kökü + `.Create/.Update/.Delete/.Export/.Import/.Note`; `App.Hr.InterviewScore`
|
||||
mülakat yetkisinin altındadır. Tanımlar `App.Hr.Definitions` altındadır. Satır süzmesi yoktur —
|
||||
ekran yetkisi olan tüm kayıtları görür. Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
Önerilen dağıtım:
|
||||
|
||||
| Rol | Yetkiler |
|
||||
| --- | --- |
|
||||
| Talep eden yöneticiler | `App.Hr.StaffRequest` (+ `.Create/.Update`) |
|
||||
| Mülakatçılar | `App.Hr.Interview` (+ `.Update`), `App.Hr.InterviewScore` (+ `.Create/.Update/.Delete`) |
|
||||
| İşe alım uzmanı | `App.Hr.Recruitment` dalının tamamı + üç tanım ekranı |
|
||||
| Onaycı | Onaylayacağı ekranın kökü + `.Update` |
|
||||
|
||||
KVKK: aday verisi kişisel veridir; Adaylar ekranının yetkisi yalnızca işe alım ekibine verilmelidir.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kaynak | Kullanım |
|
||||
| --- | --- |
|
||||
| `Sas_T_Branch`, `Hr_T_Department`, `Hr_T_JobPosition` | Şube → departman → pozisyon cascade (talep, ilan, teklif) |
|
||||
| `Sas_H_Currency` | Ücret para birimi (varsayılan TRY) |
|
||||
| `Sas_H_Country`, `Sas_H_City` | Aday adresi (ülke → şehir cascade) |
|
||||
| `Hr_T_Skill` / `Hr_T_SkillType` | Aday yetkinlikleri (`SkillIds`) |
|
||||
| `Hr_T_BenefitType` | Teklifteki yan haklar (`BenefitCodes`) |
|
||||
| `AbpUsers` | Talep eden, ayrılan personel, sorumlu, mülakatçı, personele dönüşen aday |
|
||||
| Bildirimler | Tip `IseAlimMulakatAtandi`; kurallar `Custom` + `UiActivity`/`Mail`; metin `App.Hr.Interview.Notification.{Subject,Message}`, yer tutucular `[Candidate]`, `[Posting]`, `[Date]` |
|
||||
| Raporlar | KVKK Açık Rıza Formu, Teklif Mektubu (`DynamicReport`) |
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. Satış müdürü **Kadro Talepleri**'nde "Satış Temsilcisi, 2 kişi, yeni pozisyon" talebini açar →
|
||||
`KT-2026-00001`; onaya gönderir, onaycı onaylar → `Onaylandı`.
|
||||
2. İK **İlanlar**'da talebi seçer; şube/departman/pozisyon/adet dolar, başlık pozisyon adı olur;
|
||||
yayın kanallarını (LinkedIn, Kariyer.net) seçip durumu **Published** yapar → `ILN-2026-00001`.
|
||||
3. Gelen adaylar **Adaylar**'a CV ve KVKK rızasıyla girilir; KVKK formu satır butonundan basılır.
|
||||
4. İlanın **Başvurular** sekmesinden aday eklenir (`Applied`); kanban panosunda **Screening**'e çekilir.
|
||||
5. Başvurunun **Mülakatlar** sekmesinden teknik mülakat planlanır → başvuru `Interview` olur,
|
||||
mülakatçıya bildirim gider; mülakatçı kriterleri puanlar → genel ve ortalama puan hesaplanır.
|
||||
6. **Teklifler**'de teklif hazırlanır → başvuru `Offer`; teklif onaya gider, onaylanınca
|
||||
**Teklif Mektubu** basılır.
|
||||
7. Aday kabul eder, teklif **Accepted** yapılır → başvuru `Hired`. BT kullanıcıyı açar, İK aday
|
||||
kaydının **Personel** alanına bağlar ("Personele Dönüşen" kartı artar).
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar
|
||||
|
||||
**İlan açarken kadro talebi listede yok.** Yalnızca onaylanmış (`ApprovalStatus = 'Onaylandı'`) talepler listelenir.
|
||||
|
||||
**Onay butonu kimde görünüyor?** Akış düğümündeki `Approver`'da (seed'de admin). ListForm › Workflow'dan gerçek onaycıyı yazın.
|
||||
|
||||
**Başvuru aşaması geri gitmedi.** Otomatik ilerleme yalnız ileri gider; geri almayı panodan ya da formdan elle yapın.
|
||||
|
||||
**Ret sebebi alanı temizlendi.** Ret sebebi ve notu yalnızca `Rejected` aşamasında tutulur.
|
||||
|
||||
**Aday kaydı kaydedilmiyor.** KVKK rızası işaretli olmalı (tablo da zorlar) ve e-posta kiracıda tekil olmalı.
|
||||
|
||||
**Aynı aday aynı ilana ikinci kez eklenemiyor.** Aday × ilan tekildir.
|
||||
|
||||
**Mülakat puanı nasıl hesaplanıyor?** Kriter ağırlıklı ortalama (§5.2); ağırlıklar İK › Tanımlar › Değerlendirme Kriterleri'nden.
|
||||
|
||||
**İşe alınan aday otomatik personel olmuyor mu?** Hayır; kullanıcıyı BT açar, İK aday kaydına bağlar.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_{StaffRequest,JobPosting,Candidate,JobApplication,Interview,InterviewScore,JobOffer,CandidateSource,RejectionReason,EvaluationCriterion}.sql` | Tablolar, CHECK ve tekil indeksler |
|
||||
| `configs/seeds/host/wizard/{StaffRequest,JobPosting,Candidate,JobApplication,Interview,InterviewScore,JobOffer,CandidateSource,RejectionReason,EvaluationCriterion}.json` | 10 wizard |
|
||||
| `configs/seeds/host/data/App.Hr.{CandidateSource,RejectionReason,EvaluationCriterion}.json` | Tanım verisi |
|
||||
| `configs/seeds/host/data/App.Reports.ReportTemplates.json` | KVKK formu ve teklif mektubu şablonları |
|
||||
| `configs/seeds/host/data/App.Notifications.Notification{Types,Rules}.json` | `IseAlimMulakatAtandi` tipi ve 2 kuralı |
|
||||
| `configs/seeds/host/data/App.Menus.Menu.json`, `Abp.Identity.Permissions.json`, `App.Languages.LanguageText.json` | Menü, yetki, dil satırları |
|
||||
|
||||
Kurulum: DB Migrate. Geri alma: Wizard Manager'dan wizard'lar silinir (alt formlar önce: `InterviewScore`
|
||||
→ `Interview`/`JobOffer` → `JobApplication` → diğerleri); tablolar yalnızca onayda seçilirse düşer.
|
||||
Rapor şablonları ve bildirim satırları elle kaldırılır.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Kadro Talepleri — `App.Hr.StaffRequest`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/StaffRequest.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Recruitment` › `App.Hr.StaffRequest` (sıra 1) |
|
||||
| Yetki | `App.Hr.StaffRequest` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Kadro Talepleri — bir departmanın yeni ya da boşalan bir pozisyon için personel istemesi ve bu isteğin onay süreci. İşe alım sürecinin ilk adımıdır; ilan yalnızca onaylanmış talepten açılır. |
|
||||
| Kaynak | `Hr_T_StaffRequest` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Pending`, `App.Hr.StaffRequest.Widget.Approved`, `App.Hr.StaffRequest.Widget.Headcount` |
|
||||
| Komutlar | InsertAfter: SQL |
|
||||
| Form varsayılanları | IsActive=true, RequestDate=@DATE, RequestedById=@USERID, Headcount=1, EmploymentType=FullTime, Reason=NewPosition, CurrencyId=TRY |
|
||||
| Onay akışı | Start 'Onaya Gönderildi' → Approval 'Onay Bekliyor' → Inform 'Onay Bilgisi' → Inform 'Ret Bilgisi' → End 'Onaylandı' → End 'Reddedildi' |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `RequestNo` | Talep No | dxTextBox | | ✓ | |
|
||||
| `RequestDate` | Talep Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `RequestedById` | Talep Eden | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `BranchId` | Şube Adı | dxSelectBox | ✓ | ✓ | sorgu: Sas_T_Branch |
|
||||
| `DepartmentId` | Departman | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_Department (← BranchId) |
|
||||
| `JobPositionId` | İş Pozisyonu | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_JobPosition (← DepartmentId) |
|
||||
| `Headcount` | Kadro Adedi | dxNumberBox | ✓ | ✓ | |
|
||||
| `EmploymentType` | Çalışma Şekli | dxSelectBox | ✓ | ✓ | liste: FullTime, PartTime, Contract, Intern, Seasonal |
|
||||
| `ExpectedStartDate` | Beklenen Başlangıç | dxDateBox | | ✓ | |
|
||||
| `Reason` | Talep Nedeni | dxRadioGroup | ✓ | ✓ | liste: NewPosition, Replacement · script |
|
||||
| `ReplacedUserId` | Ayrılan Personel | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
| `MinSalary` | Asgari Ücret | dxNumberBox | | ✓ | |
|
||||
| `MaxSalary` | Azami Ücret | dxNumberBox | | ✓ | |
|
||||
| `CurrencyId` | Para Birimi | dxSelectBox | | ✓ | sorgu: Sas_H_Currency |
|
||||
| `Qualifications` | Aranan Nitelikler | dxHtmlEditor | | ✓ | |
|
||||
| `Description` | Açıklama | dxTextArea | | ✓ | |
|
||||
| `ApprovalStatus` | Onay Durumu | dxTextBox | | ✓ | |
|
||||
| `ApprovalUser` | Onaylayan | dxTextBox | | ✓ | |
|
||||
| `ApprovalDate` | Onay Tarihi | dxDateBox | | ✓ | |
|
||||
| `ApprovalDescription` | Onay Açıklaması | dxTextArea | | ✓ | |
|
||||
|
||||
### İlanlar — `App.Hr.JobPosting`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/JobPosting.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Recruitment` › `App.Hr.JobPosting` (sıra 2) |
|
||||
| Yetki | `App.Hr.JobPosting` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | İlanlar — onaylanmış kadro taleplerinden açılan iş ilanları ve ilana gelen başvurular. |
|
||||
| Kaynak | `Hr_T_JobPosting` · 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.Hr.JobApplication` (Id → JobPostingId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Published`, `App.Widget.Draft`, `App.Hr.JobPosting.Widget.Closed` |
|
||||
| Komutlar | InsertAfter: SQL · UpdateAfter: SQL |
|
||||
| Form varsayılanları | IsActive=true, Status=Draft, Headcount=1, EmploymentType=FullTime, WorkModel=Office, PublishDate=@DATE |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `PostingNo` | İlan No | dxTextBox | | ✓ | |
|
||||
| `StaffRequestId` | Kadro Talebi | dxSelectBox | | ✓ | sorgu: Hr_T_StaffRequest · script |
|
||||
| `Title` | İlan Başlığı | dxTextBox | ✓ | ✓ | |
|
||||
| `Status` | Durum | dxSelectBox | ✓ | ✓ | liste: Draft, Published, Closed, Cancelled |
|
||||
| `BranchId` | Şube Adı | dxSelectBox | ✓ | ✓ | sorgu: Sas_T_Branch |
|
||||
| `DepartmentId` | Departman | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_Department (← BranchId) |
|
||||
| `JobPositionId` | İş Pozisyonu | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_JobPosition (← DepartmentId) |
|
||||
| `Headcount` | Kadro Adedi | dxNumberBox | ✓ | ✓ | |
|
||||
| `EmploymentType` | Çalışma Şekli | dxSelectBox | ✓ | ✓ | liste: FullTime, PartTime, Contract, Intern, Seasonal |
|
||||
| `WorkModel` | Çalışma Modeli | dxSelectBox | ✓ | ✓ | liste: Office, Hybrid, Remote |
|
||||
| `Location` | Lokasyon | dxTextBox | | ✓ | |
|
||||
| `PublishDate` | Yayın Tarihi | dxDateBox | | ✓ | |
|
||||
| `ClosingDate` | Son Başvuru Tarihi | dxDateBox | | ✓ | |
|
||||
| `SourceIds` | Yayın Kanalları | dxTagBox | | ✓ | sorgu: Hr_T_CandidateSource |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
| `Description` | Açıklama | dxHtmlEditor | | ✓ | |
|
||||
| `Requirements` | Aranan Nitelikler | dxHtmlEditor | | ✓ | |
|
||||
|
||||
### Adaylar — `App.Hr.Candidate`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Candidate.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Recruitment` › `App.Hr.Candidate` (sıra 3) |
|
||||
| Yetki | `App.Hr.Candidate` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Adaylar — CV ve KVKK açık rızası ile tutulan aday havuzu. Bir aday birden fazla ilana başvurabilir. |
|
||||
| Kaynak | `Hr_T_Candidate` · 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.Hr.JobApplication` (Id → CandidateId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive`, `App.Hr.Candidate.Widget.Converted` |
|
||||
| Komutlar | UpdateAfter: SQL |
|
||||
| Form varsayılanları | IsActive=true, KvkkConsentDate=@NOW, KvkkConsentMethod=Written, CurrencyId=TRY |
|
||||
| Butonlar | `App.Hr.Candidate.KvkkConsentForm` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Photo` | Fotoğraf | dxImageUpload | | ✓ | |
|
||||
| `FirstName` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `LastName` | Soyadı | dxTextBox | ✓ | ✓ | |
|
||||
| `Email` | E-posta | dxTextBox | ✓ | ✓ | |
|
||||
| `PhoneNumber` | Telefon | dxTextBox | | ✓ | |
|
||||
| `Gender` | Cinsiyet | dxSelectBox | | ✓ | liste: Male, Female |
|
||||
| `BirthDate` | Doğum Tarihi | dxDateBox | | ✓ | |
|
||||
| `Country` | Ülke | dxSelectBox | | ✓ | sorgu: Sas_H_Country |
|
||||
| `City` | Şehir | dxSelectBox | | ✓ | sorgu: Sas_H_City (← Country) |
|
||||
| `Address` | Adres | dxTextBox | | ✓ | |
|
||||
| `EducationLevel` | Eğitim Düzeyi | dxSelectBox | | ✓ | liste: Primary, HighSchool, Associate, Bachelor, Master, Doctorate |
|
||||
| `School` | Okul | dxTextBox | | ✓ | |
|
||||
| `Major` | Bölüm | dxTextBox | | ✓ | |
|
||||
| `GraduationYear` | Mezuniyet Yılı | dxNumberBox | | ✓ | |
|
||||
| `ExperienceYears` | Deneyim (Yıl) | dxNumberBox | | ✓ | |
|
||||
| `CurrentCompany` | Mevcut Firma | dxTextBox | | ✓ | |
|
||||
| `CurrentTitle` | Mevcut Ünvan | dxTextBox | | ✓ | |
|
||||
| `ExpectedSalary` | Ücret Beklentisi | dxNumberBox | | ✓ | |
|
||||
| `CurrencyId` | Para Birimi | dxSelectBox | | ✓ | sorgu: Sas_H_Currency |
|
||||
| `SourceId` | Kaynak | dxSelectBox | | ✓ | sorgu: Hr_T_CandidateSource |
|
||||
| `LinkedInUrl` | LinkedIn | dxTextBox | | ✓ | |
|
||||
| `UserId` | Personel | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `SkillIds` | Yetkinlikler | dxTagBox | | ✓ | sorgu: Hr_T_Skill |
|
||||
| `CvDocument` | CV | dxImageUpload | | ✓ | |
|
||||
| `Notes` | Notlar | dxTextBox | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
| `KvkkConsent` | Adayın KVKK kapsamında açık rızası alındı | dxCheckBox | ✓ | ✓ | |
|
||||
| `KvkkConsentDate` | Rıza Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `KvkkConsentMethod` | Rıza Alma Yöntemi | dxSelectBox | ✓ | ✓ | liste: Written, Electronic, Email |
|
||||
| `KvkkConsentDocument` | İmzalı Rıza Belgesi | dxImageUpload | | ✓ | |
|
||||
|
||||
### Başvurular — `App.Hr.JobApplication`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/JobApplication.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Recruitment` › `App.Hr.JobApplication` (sıra 4) |
|
||||
| Yetki | `App.Hr.JobApplication` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Başvurular — bir adayın bir ilana başvurusu ve başvurunun aşama takibi (kanban panosu). |
|
||||
| Kaynak | `Hr_T_JobApplication` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart, Todo (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Alt formlar | `App.Hr.Interview` (Id → ApplicationId), `App.Hr.JobOffer` (Id → ApplicationId) |
|
||||
| Todo | başlık `CandidateName`, durum `Stage` (Applied,Screening,Interview,Offer,Hired,Rejected) |
|
||||
| Komutlar | InsertAfter: SQL · UpdateAfter: SQL |
|
||||
| Form varsayılanları | IsActive=true, ApplicationDate=@DATE, Stage=Applied, OwnerUserId=@USERID |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `CandidateId` | Aday | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_Candidate · script |
|
||||
| `JobPostingId` | İlan | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_JobPosting |
|
||||
| `CandidateName` | Aday | dxTextBox | | | |
|
||||
| `PostingTitle` | İlan | dxTextBox | | | |
|
||||
| `ApplicationDate` | Başvuru Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `SourceId` | Kaynak | dxSelectBox | | ✓ | sorgu: Hr_T_CandidateSource |
|
||||
| `OwnerUserId` | Sorumlu | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `AverageScore` | Ortalama Puan | dxNumberBox | | ✓ | |
|
||||
| `Stage` | Aşama | dxSelectBox | ✓ | ✓ | liste: Applied, Screening, Interview, Offer, Hired, Rejected · script |
|
||||
| `RejectionReasonId` | Ret Sebebi | dxSelectBox | | ✓ | sorgu: Hr_T_RejectionReason |
|
||||
| `RejectionNote` | Ret Açıklaması | dxTextArea | | ✓ | |
|
||||
| `SortOrder` | Sıralama | dxNumberBox | | | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
| `Notes` | Notlar | dxTextArea | | ✓ | |
|
||||
|
||||
### Mülakatlar — `App.Hr.Interview`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Interview.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Recruitment` › `App.Hr.Interview` (sıra 5) |
|
||||
| Yetki | `App.Hr.Interview` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Mülakatlar — başvuru için mülakat planlama, mülakatçı ataması ve kriter bazlı puanlama. |
|
||||
| Kaynak | `Hr_T_Interview` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart, Scheduler (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Alt formlar | `App.Hr.InterviewScore` (Id → InterviewId) |
|
||||
| Komutlar | InsertAfter: SQL · UpdateAfter: SQL · DeleteAfter: SQL |
|
||||
| Form varsayılanları | IsActive=true, InterviewType=FaceToFace, Status=Planned, InterviewerUserId=@USERID |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `ApplicationId` | Başvuru | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_JobApplication |
|
||||
| `Title` | Başlık | dxTextBox | | | |
|
||||
| `InterviewType` | Mülakat Türü | dxSelectBox | ✓ | ✓ | liste: Phone, Video, FaceToFace, Technical, Hr |
|
||||
| `InterviewerUserId` | Mülakatçı | dxSelectBox | ✓ | ✓ | sorgu: AbpUsers |
|
||||
| `StartDate` | Başlangıç | dxDateBox | ✓ | ✓ | script |
|
||||
| `EndDate` | Bitiş | dxDateBox | ✓ | ✓ | |
|
||||
| `Location` | Yer | dxTextBox | | ✓ | |
|
||||
| `MeetingUrl` | Toplantı Bağlantısı | dxTextBox | | ✓ | |
|
||||
| `Status` | Durum | dxSelectBox | ✓ | ✓ | liste: Planned, Completed, Cancelled, NoShow |
|
||||
| `Recommendation` | Öneri | dxSelectBox | | ✓ | liste: Hire, Hold, Reject |
|
||||
| `OverallScore` | Genel Puan | dxNumberBox | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
| `Notes` | Notlar | dxTextArea | | ✓ | |
|
||||
|
||||
### Teklifler — `App.Hr.JobOffer`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/JobOffer.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Recruitment` › `App.Hr.JobOffer` (sıra 6) |
|
||||
| Yetki | `App.Hr.JobOffer` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Teklifler — işe alınması düşünülen adaya yapılan ücret ve şart teklifi, iç onayı ve teklif mektubu. |
|
||||
| Kaynak | `Hr_T_JobOffer` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Komutlar | InsertAfter: SQL · UpdateAfter: SQL |
|
||||
| Form varsayılanları | IsActive=true, OfferDate=@DATE, Status=Draft, CurrencyId=TRY, EmploymentType=FullTime, WorkModel=Office |
|
||||
| Butonlar | `App.Hr.JobOffer.OfferLetter` |
|
||||
| Onay akışı | Start 'Onaya Gönderildi' → Approval 'Onay Bekliyor' → Inform 'Onay Bilgisi' → Inform 'Ret Bilgisi' → End 'Onaylandı' → End 'Reddedildi' |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `OfferNo` | Teklif No | dxTextBox | | ✓ | |
|
||||
| `ApplicationId` | Başvuru | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_JobApplication · script |
|
||||
| `CandidateName` | Aday | dxTextBox | | | |
|
||||
| `OfferDate` | Teklif Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `ValidUntil` | Geçerlilik Tarihi | dxDateBox | | ✓ | |
|
||||
| `StartDate` | İşe Başlama Tarihi | dxDateBox | | ✓ | |
|
||||
| `GrossSalary` | Brüt Maaş | dxNumberBox | ✓ | ✓ | |
|
||||
| `CurrencyId` | Para Birimi | dxSelectBox | ✓ | ✓ | sorgu: Sas_H_Currency |
|
||||
| `Status` | Durum | dxSelectBox | ✓ | ✓ | liste: Draft, Sent, Accepted, Declined, Expired · script |
|
||||
| `ResponseDate` | Yanıt Tarihi | dxDateBox | | ✓ | |
|
||||
| `BranchId` | Şube Adı | dxSelectBox | ✓ | ✓ | sorgu: Sas_T_Branch |
|
||||
| `DepartmentId` | Departman | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_Department (← BranchId) |
|
||||
| `JobPositionId` | İş Pozisyonu | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_JobPosition (← DepartmentId) |
|
||||
| `EmploymentType` | Çalışma Şekli | dxSelectBox | ✓ | ✓ | liste: FullTime, PartTime, Contract, Intern, Seasonal |
|
||||
| `WorkModel` | Çalışma Modeli | dxSelectBox | ✓ | ✓ | liste: Office, Hybrid, Remote |
|
||||
| `BenefitCodes` | Yan Haklar | dxTagBox | | ✓ | sorgu: Hr_T_BenefitType |
|
||||
| `Notes` | Notlar | dxTextBox | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
| `ApprovalStatus` | Onay Durumu | dxTextBox | | ✓ | |
|
||||
| `ApprovalUser` | Onaylayan | dxTextBox | | ✓ | |
|
||||
| `ApprovalDate` | Onay Tarihi | dxDateBox | | ✓ | |
|
||||
| `ApprovalDescription` | Onay Açıklaması | dxTextBox | | ✓ | |
|
||||
|
||||
### Aday Kaynakları — `App.Hr.CandidateSource`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/CandidateSource.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.CandidateSource` (sıra 13) |
|
||||
| Yetki | `App.Hr.CandidateSource` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Aday Kaynakları — adayların ve ilanların hangi kanaldan geldiğini/yayınlandığını tanımlayan liste (LinkedIn, Kariyer.net, referans, kariyer fuarı…). |
|
||||
| Kaynak | `Hr_T_CandidateSource` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.CandidateSource.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `Description` | Açıklama | dxTextArea | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
|
||||
### Ret Sebepleri — `App.Hr.RejectionReason`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/RejectionReason.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.RejectionReason` (sıra 14) |
|
||||
| Yetki | `App.Hr.RejectionReason` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Ret Sebepleri — bir başvurunun şirket ya da aday tarafından neden kapatıldığını sınıflandıran liste. |
|
||||
| Kaynak | `Hr_T_RejectionReason` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsActive=true, RejectedBy=Company |
|
||||
| Veri aynası | `data/App.Hr.RejectionReason.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `RejectedBy` | Reddeden | dxRadioGroup | ✓ | ✓ | liste: Company, Candidate |
|
||||
| `Description` | Açıklama | dxTextArea | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
|
||||
### Değerlendirme Kriterleri — `App.Hr.EvaluationCriterion`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/EvaluationCriterion.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.EvaluationCriterion` (sıra 15) |
|
||||
| Yetki | `App.Hr.EvaluationCriterion` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Değerlendirme Kriterleri — mülakatlarda puanlanan kriterler ve ağırlıkları (iletişim, teknik yetkinlik, problem çözme…). |
|
||||
| Kaynak | `Hr_T_EvaluationCriterion` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsActive=true, Weight=1 |
|
||||
| Veri aynası | `data/App.Hr.EvaluationCriterion.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `Weight` | Ağırlık | dxNumberBox | ✓ | ✓ | |
|
||||
| `Description` | Açıklama | dxTextArea | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
|
||||
### Mülakat Puanları — `App.Hr.InterviewScore`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/InterviewScore.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.InterviewScore` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Mülakat Puanları — mülakatta her değerlendirme kriterine verilen 1–5 puan. |
|
||||
| Kaynak | `Hr_T_InterviewScore` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Komutlar | InsertAfter: SQL · UpdateAfter: SQL · DeleteAfter: SQL |
|
||||
| Form varsayılanları | IsActive=true |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `InterviewId` | Mülakat | dxTextBox | | | |
|
||||
| `CriterionId` | Kriter | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_EvaluationCriterion |
|
||||
| `Score` | Puan | dxSelectBox | ✓ | ✓ | liste: 1, 2, 3, 4, 5 |
|
||||
| `Comment` | Yorum | dxTextArea | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
315
configs/seeds/host/docs/modules/HrTrainings.md
Normal file
315
configs/seeds/host/docs/modules/HrTrainings.md
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
# İK › Eğitimler (`App.Hr.Trainings`)
|
||||
|
||||
Şirket içi ve dışı eğitimlerin kaydı: eğitim tipi → konu tanımları, eğitim oturumu (tarih/saat,
|
||||
süre, yer, eğitmen, maliyet, kazandırdığı yetkinlikler), katılımcılar (katılım durumu, puan,
|
||||
katılım belgesi) ve eğitim dosyaları. Tamamı konfigürasyondur (Wizard + rapor şablonu); entity,
|
||||
migration ya da React kodu yoktur.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| İK / eğitim sorumlusu | Tip ve konu tanımlar, eğitim açar, katılımcı ekler, katılım/puan girer, dosya yükler, katılım belgesi basar | Eğitim Tipleri · Eğitim Konuları · Eğitimler |
|
||||
| Yönetim | Eğitim adedi, açık/kapalı durum ve toplam maliyeti izler (widget, Pivot, Chart) | Eğitimler |
|
||||
|
||||
Kapsam: kiracı (`IsTenant`). Eğitim bir şubeye bağlıdır (`BranchId` zorunlu); satır süzmesi yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar artefaktlardan
|
||||
> (wizard, SQL, seed, commit `36546d0c` "Human Resources -> Eğitim bilgileri") okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Wizard ekranları; eğitim kaydının altında Katılımcılar ve Dosyalar sekmeleri (menüsüz alt formlar) |
|
||||
| Tanımlar | Tip ve konu tanımları İK › Tanımlar'da değil **Eğitimler** dalının içindedir; konu bir tipe bağlıdır ve tip seçimine göre süzülür |
|
||||
| Süre | `Toplam Süre (saat) = gün sayısı (bitiş dahil) × günlük saat (bitiş – başlangıç saati)` — formda hesaplanır |
|
||||
| Maliyet | Altı kalem (yer, eğitmen, konaklama, ulaşım, ikram, diğer) toplanarak `CostTotal` formda hesaplanır |
|
||||
| Yetkinlik | Eğitimin kazandırdığı yetkinlikler `SkillIds` (çok değerli, `Hr_T_Skill`) olarak saklanır; çalışan profiline (`Adm_T_UserSkill`) **yazılmaz** |
|
||||
| Katılımcı | Personel seçilince işe giriş tarihi, departman ve pozisyon kullanıcı kaydından kopyalanır (eğitim anındaki hâli saklanır) |
|
||||
| Katılım durumu | Attended / NotAttended / Excused; varsayılan **Attended** |
|
||||
| Katılım belgesi | Yalnızca `Attended` satırda görünen satır butonu → **Katılım Belgesi** raporu (`DynamicReport`) |
|
||||
| Dosyalar | Belge türü `Hr_T_DocumentType` (ortak İK tanımı); dosya içeriği base64 (`dxImageUpload`) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
`İnsan Kaynakları › Eğitimler` (`App.Hr.Trainings`, ikon `FcGraduationCap`)
|
||||
|
||||
| Sıra | Menü (TR / EN) | `ListFormCode` | Alt formlar | Görünümler | Widget'lar |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | Eğitim Tipleri / Training Types | `App.Hr.TrainingType` | — | Grid, Card, Pivot, Chart | Toplam · Aktif · Pasif |
|
||||
| 2 | Eğitim Konuları / Training Subjects | `App.Hr.TrainingSubject` | — | Grid, Card, Pivot, Chart | Toplam · Aktif · Pasif |
|
||||
| 3 | Eğitimler / Trainings | `App.Hr.Training` | `TrainingParticipant`, `TrainingFile` (`Id → TrainingId`, menüsüz) | Grid, Card, Pivot, Chart | Toplam · Açık · Kapalı · Toplam Maliyet |
|
||||
|
||||
Seed verisi: 8 eğitim tipi (Oryantasyon, İş Başı, Teknik Oryantasyon, Grup, Firma Dışı, Eğitim
|
||||
İçerikli Sosyal Faaliyet, Akademi, Rotasyon) ve 18 eğitim konusu (`data/App.Hr.{TrainingType,TrainingSubject}.json`).
|
||||
|
||||
Satır butonu: Katılımcılar › **Katılım Belgesi** — rapor `3840a20d-3233-4d17-bc06-ccfd8d87b32a`,
|
||||
görünürlük `AttendanceStatus === 'Attended'`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
```
|
||||
Hr_T_TrainingType ──< Hr_T_TrainingSubject
|
||||
│ │
|
||||
└──────< Hr_T_Training >──── Sas_T_Branch
|
||||
├──< Hr_T_TrainingParticipant >── AbpUsers (+ Department, JobPosition)
|
||||
└──< Hr_T_TrainingFile >── Hr_T_DocumentType
|
||||
```
|
||||
|
||||
| Tablo | Önemli kolonlar | Kural |
|
||||
| --- | --- | --- |
|
||||
| `Hr_T_TrainingType` | `Name`, `IsActive` | — |
|
||||
| `Hr_T_TrainingSubject` | `TrainingTypeId`, `Name`, `IsEvaluated` (değerlendirilsin mi), `IsActive` | — |
|
||||
| `Hr_T_Training` | `TrainingTypeId`, `TrainingSubjectId` (tipe göre cascade), `EntryDate`, `BranchId`, `StartDate`, `EndDate`, `StartTime`, `EndTime`, `TotalHours`, `Status` (Open/Closed), `TrainerName`, `TrainingPlace`, `TrainingInstitution`, `Description`, `SkillIds`, `CostPlace`, `CostTrainer`, `CostAccommodation`, `CostTransport`, `CostCatering`, `CostOther`, `CostTotal` | Bitiş başlangıçtan önce olamaz (form) |
|
||||
| `Hr_T_TrainingParticipant` | `TrainingId`, `UserId`, `HireDate`, `DepartmentId`, `JobPositionId`, `AttendanceStatus`, `EvaluationScore`, `ExamScore`, `LeaveDate`, `Note` | — |
|
||||
| `Hr_T_TrainingFile` | `TrainingId`, `DocumentTypeId`, `FileDate`, `FileName`, `FileContent` | Dosya zorunlu |
|
||||
|
||||
Tablo düzeyinde CHECK ya da tekil indeks yoktur; kurallar formdadır.
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları ve hesaplar
|
||||
|
||||
Hesapların tamamı `EditorScript`'tir (sunucu tarafında after-command yoktur):
|
||||
|
||||
| Alan | Kural |
|
||||
| --- | --- |
|
||||
| `EntryDate` | Yeni kayıtta bugün |
|
||||
| `Status` | Yeni kayıtta `Open` |
|
||||
| `TotalHours` | Başlangıç/bitiş tarihi ya da saatlerinden biri değişince `round(days(StartDate, EndDate) × hours(StartTime, EndTime), 2)`; dört alan dolu olmalı |
|
||||
| `EndDate` | Başlangıçtan önceyse uyarı + değişiklik geri alınır |
|
||||
| `CostTotal` | Altı maliyet kaleminden biri değişince toplam |
|
||||
| Katılımcı `UserId` | Seçilince `HireDate`, `DepartmentId`, `JobPositionId` kopyalanır |
|
||||
| `AttendanceStatus` | Yeni satırda `Attended` |
|
||||
| Dosya `FileDate` | Yeni satırda bugün |
|
||||
| Tip/Konu `IsActive`, `IsEvaluated` | Yeni kayıtta `true` |
|
||||
|
||||
Saat hesabı aynı günlük saat aralığının her gün tekrarlandığını varsayar; gün sayısına bitiş günü dahildir.
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. Yetki ağacı menüyü izler: `App.Hr.Trainings` ara yetkisinin
|
||||
altında üç ekranın kökü + `.Create/.Update/.Delete/.Export/.Import/.Note`; `TrainingParticipant` ve
|
||||
`TrainingFile` `App.Hr.Training` altındadır. Satır süzmesi yoktur. Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
| Rol | Yetkiler |
|
||||
| --- | --- |
|
||||
| Eğitim sorumlusu | `App.Hr.Trainings` dalının tamamı |
|
||||
| Bölüm yöneticisi (izleme) | `App.Hr.Training` + `App.Hr.TrainingParticipant` (salt okuma) |
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kaynak | Kullanım |
|
||||
| --- | --- |
|
||||
| `Sas_T_Branch` | Eğitimin şubesi |
|
||||
| `AbpUsers` | Katılımcı; işe giriş tarihi, departman, pozisyon kopyası |
|
||||
| `Hr_T_Department`, `Hr_T_JobPosition` | Katılımcının o anki birimi (Pivot kırılımı) |
|
||||
| `Hr_T_Skill` / `Hr_T_SkillType` | Eğitimin kazandırdığı yetkinlikler |
|
||||
| `Hr_T_DocumentType` | Eğitim dosyası türü |
|
||||
| Raporlar | Katılım Belgesi (`DynamicReport`, `Raporlar` kategorisi) |
|
||||
| Performans Yönetimi | Gelişim planı aksiyonu bir eğitime bağlanabilir (`Hr_T_DevelopmentPlan.TrainingId`); çalışan o eğitimde **Attended** ise aksiyon kayıtta kendiliğinden tamamlanır (`Hr_S_DevelopmentPlanSync`, bkz. `HrPerformance.md`). Eğitimler ekranı bu bağı bilmez |
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. İK **Eğitimler**'de "İş Sağlığı ve Güvenliği" kaydını açar: tip Grup Eğitimi, konu İSG, şube
|
||||
Merkez, 3–4 Kasım 09:00–17:00 → toplam süre 16 saat; eğitmen ve yer maliyetini girer → toplam
|
||||
maliyet hesaplanır; kazandırdığı yetkinliği (İSG) seçer.
|
||||
2. **Katılımcılar** sekmesine personeli ekler; departman/pozisyon kopyalanır, durum Katıldı.
|
||||
3. Gelmeyen personeli **Katılmadı**, raporlu olanı **Mazeretli** yapar; sınav/değerlendirme puanlarını girer.
|
||||
4. Katılanların satırından **Katılım Belgesi** basılır; imzalı liste **Dosyalar** sekmesine yüklenir.
|
||||
5. Eğitim **Kapalı** yapılır; widget'taki toplam maliyete eklenir.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar
|
||||
|
||||
**Toplam süre hesaplanmıyor.** Başlangıç/bitiş tarihi ve başlangıç/bitiş saatinin dördü de dolu olmalı.
|
||||
|
||||
**Katılım belgesi butonu görünmüyor.** Yalnızca katılım durumu "Katıldı" olan satırda çıkar.
|
||||
|
||||
**Eğitim konusu listesi boş.** Konu, seçilen eğitim tipine göre süzülür; önce tip seçin.
|
||||
|
||||
**Eğitimdeki yetkinlik çalışan profiline yazılıyor mu?** Hayır; `SkillIds` eğitimin bilgisidir. Profil, Performans Yönetimi'nde tamamlanan değerlendirmeden güncellenir.
|
||||
|
||||
**Katılımcının departmanı sonradan değişti, eğitimde eski görünüyor.** Bilinçli: eğitim anındaki birim saklanır.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_{TrainingType,TrainingSubject,Training,TrainingParticipant,TrainingFile}.sql` | Tablolar |
|
||||
| `configs/seeds/host/wizard/{TrainingType,TrainingSubject,Training,TrainingParticipant,TrainingFile}.json` | 5 wizard |
|
||||
| `configs/seeds/host/data/App.Hr.{TrainingType,TrainingSubject}.json` | Tanım verisi |
|
||||
| `configs/seeds/host/data/App.Reports.ReportTemplates.json` | Katılım Belgesi şablonu |
|
||||
| `configs/seeds/host/data/App.Menus.Menu.json`, `Abp.Identity.Permissions.json`, `App.Languages.LanguageText.json` | Menü, yetki, dil satırları |
|
||||
|
||||
Kurulum: DB Migrate. Geri alma: Wizard Manager'dan alt formlar (`TrainingParticipant`, `TrainingFile`)
|
||||
önce, sonra `Training`, `TrainingSubject`, `TrainingType` silinir; tablolar yalnızca onayda seçilirse
|
||||
düşer. Gelişim planlarındaki `TrainingId` bağları silinmez, boşa düşer.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Eğitim Tipleri — `App.Hr.TrainingType`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/TrainingType.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Trainings` › `App.Hr.TrainingType` (sıra 1) |
|
||||
| Yetki | `App.Hr.TrainingType` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Eğitim Tipleri — eğitimlerin türü (oryantasyon, iş başı, grup, firma dışı, akademi, rotasyon…). |
|
||||
| Geliştirme talebi | Human Resources -> Eğitim |
|
||||
| Kaynak | `Hr_T_TrainingType` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (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.Hr.TrainingType.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | script |
|
||||
|
||||
### Eğitim Konuları — `App.Hr.TrainingSubject`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/TrainingSubject.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Trainings` › `App.Hr.TrainingSubject` (sıra 2) |
|
||||
| Yetki | `App.Hr.TrainingSubject` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Eğitim Konuları — bir eğitim tipine bağlı konu başlıkları (İSG, siber güvenlik, iş başı eğitimi…). |
|
||||
| Geliştirme talebi | Human Resources -> Eğitim |
|
||||
| Kaynak | `Hr_T_TrainingSubject` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (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.Hr.TrainingSubject.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `TrainingTypeId` | Eğitim Tipi | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_TrainingType |
|
||||
| `Name` | Eğitim Konusu | dxTextBox | ✓ | ✓ | |
|
||||
| `IsEvaluated` | Değerlendirilsin mi? | dxCheckBox | ✓ | ✓ | script |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | script |
|
||||
|
||||
### Eğitimler — `App.Hr.Training`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Training.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Trainings` › `App.Hr.Training` (sıra 3) |
|
||||
| Yetki | `App.Hr.Training` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Eğitimler — düzenlenen her eğitim oturumu: tarih/saat, süre, yer, eğitmen, maliyet, kazandırdığı yetkinlikler, katılımcılar ve dosyalar. |
|
||||
| Geliştirme talebi | Human Resources -> Eğitim |
|
||||
| Kaynak | `Hr_T_Training` · 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.Hr.TrainingParticipant` (Id → TrainingId), `App.Hr.TrainingFile` (Id → TrainingId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Hr.Training.Widget.Open`, `App.Hr.Training.Widget.Closed`, `App.Hr.Training.Widget.Cost` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `TrainingTypeId` | Eğitim Tipi | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_TrainingType |
|
||||
| `TrainingSubjectId` | Eğitim Konusu | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_TrainingSubject (← TrainingTypeId) |
|
||||
| `EntryDate` | Giriş Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `BranchId` | Şube Adı | dxSelectBox | ✓ | ✓ | sorgu: Sas_T_Branch |
|
||||
| `StartDate` | Eğitim Baş. Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `EndDate` | Bit. Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `StartTime` | Eğitim Baş. Saati | dxDateBox | | ✓ | script |
|
||||
| `EndTime` | Bit. Saati | dxDateBox | | ✓ | script |
|
||||
| `TotalHours` | Top. Eğitim Süresi (Saat) | dxNumberBox | | ✓ | |
|
||||
| `Status` | Durum | dxRadioGroup | ✓ | ✓ | liste: Open, Closed · script |
|
||||
| `TrainerName` | Eğitim Veren Kişi | dxTextBox | | ✓ | |
|
||||
| `TrainingPlace` | Eğitim Yeri | dxTextBox | | ✓ | |
|
||||
| `TrainingInstitution` | Eğitim Veren Kurum | dxTextBox | | ✓ | |
|
||||
| `Description` | Açıklama | dxTextArea | | ✓ | |
|
||||
| `SkillIds` | Yetkinlikler | dxTagBox | | ✓ | sorgu: Hr_T_Skill |
|
||||
| `CostPlace` | Eğitim Yeri Maliyeti | dxNumberBox | | ✓ | script |
|
||||
| `CostTrainer` | Eğitmen Maliyeti | dxNumberBox | | ✓ | script |
|
||||
| `CostAccommodation` | Konaklama | dxNumberBox | | ✓ | script |
|
||||
| `CostTransport` | Ulaşım | dxNumberBox | | ✓ | script |
|
||||
| `CostCatering` | İkram | dxNumberBox | | ✓ | script |
|
||||
| `CostOther` | Diğer | dxNumberBox | | ✓ | script |
|
||||
| `CostTotal` | Toplam Maliyet | dxNumberBox | | ✓ | |
|
||||
|
||||
### Katılımcılar — `App.Hr.TrainingParticipant`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/TrainingParticipant.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.TrainingParticipant` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Katılımcılar — eğitime katılan personel ve katılım sonucu. |
|
||||
| Geliştirme talebi | Human Resources -> Eğitim |
|
||||
| Kaynak | `Hr_T_TrainingParticipant` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Butonlar | `App.Hr.TrainingParticipant.Certificate` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `TrainingId` | Eğitim | dxSelectBox | | | sorgu: Hr_T_Training |
|
||||
| `UserId` | Adı Soyadı | dxSelectBox | ✓ | ✓ | sorgu: AbpUsers · script |
|
||||
| `HireDate` | İşe Giriş Tarihi | dxDateBox | | ✓ | |
|
||||
| `DepartmentId` | Bölüm | dxSelectBox | | ✓ | sorgu: Hr_T_Department |
|
||||
| `JobPositionId` | Görevi | dxSelectBox | | ✓ | sorgu: Hr_T_JobPosition |
|
||||
| `AttendanceStatus` | Katılım Durumu | dxSelectBox | ✓ | ✓ | liste: Attended, NotAttended, Excused · script |
|
||||
| `EvaluationScore` | Değerlendirme Puanı | dxNumberBox | | ✓ | |
|
||||
| `ExamScore` | Sınav Notu | dxNumberBox | | ✓ | |
|
||||
| `LeaveDate` | Ayrılma Tarihi | dxDateBox | | ✓ | |
|
||||
| `Note` | Not | dxTextArea | | ✓ | |
|
||||
|
||||
### Dosyalar — `App.Hr.TrainingFile`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/TrainingFile.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.TrainingFile` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Eğitim Dosyaları — eğitime ait doküman ve dijital kaynaklar (sunum, imzalı katılım listesi, sertifika örneği…). |
|
||||
| Geliştirme talebi | Human Resources -> Eğitim |
|
||||
| Kaynak | `Hr_T_TrainingFile` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `TrainingId` | Eğitim | dxTextBox | | | |
|
||||
| `DocumentTypeId` | Dosya Türü | dxSelectBox | | ✓ | sorgu: Hr_T_DocumentType |
|
||||
| `FileDate` | Tarih | dxDateBox | ✓ | ✓ | script |
|
||||
| `FileName` | Dosya Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `FileContent` | Dosya | dxImageUpload | ✓ | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
545
configs/seeds/host/docs/modules/HrVehicles.md
Normal file
545
configs/seeds/host/docs/modules/HrVehicles.md
Normal file
|
|
@ -0,0 +1,545 @@
|
|||
# İK › Araçlar (`App.Hr.Vehicles`)
|
||||
|
||||
Şirket araç filosu yönetimi: araç ve şoför kayıtları, araç/şoför belgeleri (ruhsat, sigorta,
|
||||
muayene, ehliyet, psikoteknik), trafik cezaları ve kazalar, fatura bazlı araç masrafları ve
|
||||
güvenlik kulübesinden araç giriş–çıkış takibi (km, süre, gidilen yer). Tamamı konfigürasyondur
|
||||
(Wizard + SQL); entity, migration ya da React kodu yoktur.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| Filo / idari işler sorumlusu | Araç, şoför, belge ve masraf tanımlarını yönetir; araç belgelerini ve masraf faturalarını girer | Araç Belgeleri · Araçlar · Gidilecek Yerler · Şoför Tanımlama · Masraf Tanımlama · Masraf Girişleri |
|
||||
| Güvenlik personeli | Aracın çıkışını ve dönüşünü (km, saat, kullanan personel) kaydeder | Araç Giriş-Çıkış Takip |
|
||||
| Yönetim | Dışarıdaki araç sayısı, toplam km ve masrafı izler | Widget'lar, Pivot, Chart |
|
||||
|
||||
Kapsam: kiracı (`IsTenant`). Araç bir şubeye (tesis) bağlıdır; satır süzmesi yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar artefaktlardan (wizard,
|
||||
> SQL, seed, commit'ler `7be0b4ed` "Human Resources -> Araçlar" ve `021a8a34` "Araçlar düzenlemesi")
|
||||
> okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Wizard ekranları; aracın altında Belgeler, şoförün altında Belgeler / Cezalar / Kazalar, masraf girişinin altında Kalemler (menüsüz alt formlar) |
|
||||
| Belge tanımı | Tek tanım tablosu (`Hr_T_VehicleDocument`) iki eksenle ayrılır: **grup** (Vehicle / Driver) ve **tip** (Insurance, Document, Tax, Toll, Inspection, Maintenance, Penalty, Accident). Her alt form kendi kümesini süzer |
|
||||
| Araç durumu | `Arrived` (Geldi — şirkette) / `Left` (Gitti — dışarıda); giriş–çıkış kaydından güncellenir |
|
||||
| Araç km'si | `CurrentKm` giriş–çıkış kaydının giriş km'sinden güncellenir; yeni çıkışta önerilen çıkış km'si budur |
|
||||
| Zimmet | Şoföre en fazla **5 araç** zimmetlenir (`Vehicle1Id`…`Vehicle5Id` sabit kolonlar) |
|
||||
| Şoför km'si | Şoförün `TotalKm`'si, kullandığı tüm hareketlerin yapılan km toplamıdır (SQL) |
|
||||
| Masraf | Fatura başlığı + kalemler; `Net Tutar = Miktar × Tutar × (1 − İskonto% / 100)` formda hesaplanır |
|
||||
| Muayene/sigorta tarihleri | Araç kaydında başlangıç–bitiş tarihleri olarak tutulur; **hatırlatma/bildirim yoktur** |
|
||||
| Hareket numarası | `MovementNo` kiracı bazında `MAX + 1` (insert sonrası SQL) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
`İnsan Kaynakları › Araçlar` (`App.Hr.Vehicles`, ikon `FcAutomotive`)
|
||||
|
||||
| Sıra | Menü (TR / EN) | `ListFormCode` | Alt formlar | Widget'lar |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Araç Belgeleri / Vehicle Documents | `App.Hr.VehicleDocument` | — | Toplam · Aktif · Pasif |
|
||||
| 2 | Araçlar / Vehicles | `App.Hr.Vehicle` | `VehicleFile` (`Id → VehicleId`) | Toplam · Geldi · Gitti · Pasif |
|
||||
| 3 | Gidilecek Yerler / Destinations | `App.Hr.VehicleDestination` | — | Toplam · Aktif · Pasif |
|
||||
| 4 | Şoför Tanımlama / Drivers | `App.Hr.Driver` | `DriverDocument`, `DriverPenalty`, `DriverAccident` (`Id → DriverId`) | Toplam · Zimmetli Araçlı · Toplam Km |
|
||||
| 5 | Masraf Tanımlama / Expense Definitions | `App.Hr.VehicleExpenseDefinition` | — | Toplam · Aktif · Pasif |
|
||||
| 6 | Masraf Girişleri / Vehicle Expenses | `App.Hr.VehicleExpense` | `VehicleExpenseLine` (`Id → VehicleExpenseId`) | Toplam · Bugün · Toplam Tutar (net kalemler) |
|
||||
| 7 | Araç Giriş-Çıkış Takip / Vehicle Gate Log | `App.Hr.VehicleMovement` | — | Toplam · Gitti · Bugün |
|
||||
|
||||
Tüm ekranlar Grid, Card, Pivot, Chart görünümleriyle gelir; özel görünüm (Todo, Scheduler) yoktur.
|
||||
|
||||
Seed verisi:
|
||||
- 17 belge tanımı (`data/App.Hr.VehicleDocument.json`). Örnekler: trafik sigortası, ruhsat, K2, MTV, OGS/HGS, egzoz/genel muayene, takograf (araç); sürücü belgesi, psikoteknik, SRC 4, kırmızı ışık ve hız cezası (şoför).
|
||||
- 9 masraf tanımı (`data/App.Hr.VehicleExpenseDefinition.json`): sigorta, vergi, bakım, muayene ×2, geçiş ×2, ceza, yakıt.
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
```
|
||||
Sas_T_Branch ──< Hr_T_Vehicle ──< Hr_T_VehicleFile >── Hr_T_VehicleDocument (grup Vehicle)
|
||||
│ ▲
|
||||
│ └── Hr_T_Driver.Vehicle1..5Id ── AbpUsers (UserId)
|
||||
│ ├──< Hr_T_DriverDocument >── VehicleDocument (grup Driver, ceza/kaza hariç)
|
||||
│ ├──< Hr_T_DriverPenalty >── VehicleDocument (tip Penalty)
|
||||
│ └──< Hr_T_DriverAccident >── VehicleDocument (tip Accident)
|
||||
├──< Hr_T_VehicleExpense ──< Hr_T_VehicleExpenseLine >── Hr_T_VehicleExpenseDefinition
|
||||
│ └── Hr_T_VehicleDestination (firma)
|
||||
└──< Hr_T_VehicleMovement >── AbpUsers (gönderen, güvenlik, kullanan), Hr_T_VehicleDestination
|
||||
```
|
||||
|
||||
| Tablo | Önemli kolonlar |
|
||||
| --- | --- |
|
||||
| `Hr_T_VehicleDocument` | `DocumentGroup` (Vehicle/Driver), `DocumentType` (8 tip), `Name`, `IsActive` |
|
||||
| `Hr_T_Vehicle` | `BranchId` (tesis), `Name`, `Brand`, `Model`, `BodyType`, `UsagePlace`, `RegistrationDate`, `PlateNumber`, `Status` (Arrived/Left), `CurrentKm`, muayene / sigorta / egzoz / takograf başlangıç–bitiş tarihleri, `IsActive` |
|
||||
| `Hr_T_VehicleFile` | `VehicleId`, `VehicleDocumentId`, `FileName`, `FileContent` |
|
||||
| `Hr_T_VehicleDestination` | `Name`, `Distance` (km), `IsActive` |
|
||||
| `Hr_T_Driver` | `UserId`, `Vehicle1Id`…`Vehicle5Id`, `TotalKm` |
|
||||
| `Hr_T_DriverDocument` | `DriverId`, `VehicleDocumentId`, `FileName`, `FileContent` |
|
||||
| `Hr_T_DriverPenalty` | `DriverId`, `PenaltyDate`, `Amount`, `Description`, `VehicleDocumentId`, dosya |
|
||||
| `Hr_T_DriverAccident` | `DriverId`, `AccidentDate`, `VehicleDocumentId`, `Description`, dosya |
|
||||
| `Hr_T_VehicleExpenseDefinition` | `ExpenseType`, `Name`, `IsActive` |
|
||||
| `Hr_T_VehicleExpense` | `VehicleId`, `InvoiceNo`, `InvoiceDate`, `DestinationId` (firma), `VehicleDocumentId`, dosya |
|
||||
| `Hr_T_VehicleExpenseLine` | `VehicleExpenseId`, `ExpenseDefinitionId`, `DetailName`, `Quantity`, `Amount`, `DiscountRate`, `NetAmount`, `Description` |
|
||||
| `Hr_T_VehicleMovement` | `MovementNo`, `ExitDate`, `ExitTime` (SS:dd metin), `BranchId`, `ExitKm`, `SenderUserId`, `SecurityUserId`, `DriverUserId`, `VehicleId`, `DestinationId`, `Reason`, `Location`, `EntrySecurityUserId`, `EntryDate`, `EntryBranchId`, `EntryTime`, `EntryKm`, `TravelledKm`, `Status`, `DurationMinutes`, `ExpectedKm` |
|
||||
|
||||
Tablo düzeyinde CHECK ya da tekil indeks yoktur (plaka tekilliği zorlanmaz); kurallar form ve SQL'dedir.
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları ve hesaplar
|
||||
|
||||
### 5.1 Giriş–çıkış (`App.Hr.VehicleMovement`)
|
||||
|
||||
Form script'leri:
|
||||
|
||||
| Olay | Kural |
|
||||
| --- | --- |
|
||||
| Form açılışı | Çıkış tarihi bugün, çıkış saati şimdi, durum `Left` |
|
||||
| Araç seçimi | `ExpectedKm` = aracın `CurrentKm`'si; çıkış km boşsa aynı değer yazılır |
|
||||
| Çıkış km | `ExpectedKm`'den küçükse uyarı + `ExpectedKm` yazılır; giriş km varsa yapılan km yeniden hesaplanır |
|
||||
| Giriş km | Çıkış km'den küçükse uyarı + geri alınır. Doluysa durum `Arrived`, `TravelledKm = EntryKm − ExitKm`, giriş tarihi/saati boşsa şimdi. Boşsa durum `Left`, yapılan km boş |
|
||||
| Tarih/saat değişimi | `DurationMinutes` = giriş − çıkış (dakika; saat `SS:dd` biçiminde olmalı) |
|
||||
|
||||
Sunucu komutları:
|
||||
|
||||
| Komut | Etki |
|
||||
| --- | --- |
|
||||
| Insert sonrası | `MovementNo` atanır; aracın `Status`'u ve (giriş km varsa) `CurrentKm`'si hareketten yazılır; kullanan personelin şoför kaydındaki `TotalKm` yeniden toplanır |
|
||||
| Delete sonrası | Şoför `TotalKm` yeniden toplanır; aracın `CurrentKm`'si son girişin km'sine, `Status`'u son hareketin durumuna döner (hareket yoksa `Arrived`) |
|
||||
| Update sonrası | **Yok** — bkz. §9 |
|
||||
|
||||
### 5.2 Masraf
|
||||
|
||||
`NetAmount = round(Quantity × Amount × (1 − DiscountRate / 100), 2)`; miktar, tutar ya da iskonto
|
||||
değişince formda hesaplanır. Fatura tarihi yeni kayıtta bugündür. "Toplam Tutar" widget'ı
|
||||
silinmemiş tüm kalemlerin toplamıdır.
|
||||
|
||||
### 5.3 Belge süzmesi
|
||||
|
||||
| Ekran | Listelenen belge tanımları |
|
||||
| --- | --- |
|
||||
| Araç › Belgeler, Masraf Girişi | `DocumentGroup = 'Vehicle'` |
|
||||
| Şoför › Belgeler | `DocumentGroup = 'Driver'` ve tip `Penalty`/`Accident` dışı |
|
||||
| Şoför › Cezalar | `DocumentType = 'Penalty'` |
|
||||
| Şoför › Kazalar | `DocumentType = 'Accident'` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. Yetki ağacı menüyü izler: `App.Hr.Vehicles` ara yetkisinin
|
||||
altında yedi ekranın kökü + `.Create/.Update/.Delete/.Export/.Import/.Note`; alt formlar (`VehicleFile`,
|
||||
`DriverDocument`, `DriverPenalty`, `DriverAccident`, `VehicleExpenseLine`) ana ekranlarının altındadır.
|
||||
Satır süzmesi yoktur. Hiçbir yetki role otomatik atanmaz.
|
||||
|
||||
| Rol | Yetkiler |
|
||||
| --- | --- |
|
||||
| Filo sorumlusu | `App.Hr.Vehicles` dalının tamamı |
|
||||
| Güvenlik | `App.Hr.VehicleMovement` (+ `.Create/.Update`) |
|
||||
| Muhasebe (masraf) | `App.Hr.VehicleExpense`, `App.Hr.VehicleExpenseLine` |
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kaynak | Kullanım |
|
||||
| --- | --- |
|
||||
| `Sas_T_Branch` | Aracın tesisi; hareketin çıkış/giriş şubesi |
|
||||
| `AbpUsers` | Şoför, gönderen personel, güvenlik personeli, kullanan personel |
|
||||
|
||||
Bildirim, zamanlanmış iş ya da rapor şablonu yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. Filo sorumlusu **Araçlar**'a "34 ABC 123"ü girer (şube Merkez, km 45.000, muayene/sigorta bitiş
|
||||
tarihleri); **Belgeler** sekmesine ruhsat ve trafik sigortasını yükler.
|
||||
2. **Şoför Tanımlama**'da personeli şoför yapar, aracı zimmet 1'e bağlar; sürücü belgesini yükler.
|
||||
3. Güvenlik **Araç Giriş-Çıkış Takip**'te yeni kayıt açar: tarih/saat dolar, araç seçilince çıkış
|
||||
km 45.000 olur; kullanan personel ve gidilen yer seçilir → araç **Dışarıda**.
|
||||
4. Dönüşte giriş km'si (45.180) girilir → durum Şirkette, yapılan km 180, süre dakika olarak hesaplanır.
|
||||
5. Yakıt faturası **Masraf Girişleri**'ne başlık + kalem (yakıt, 40 lt × 45 ₺) olarak girilir.
|
||||
6. Gelen hız cezası şoförün **Cezalar** sekmesine tutar ve belgeyle eklenir.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar ve bilinen sınırlar
|
||||
|
||||
**Plakası aynı iki araç girilebiliyor mu?** Evet; tabloda tekil kısıt yoktur.
|
||||
|
||||
**Muayene/sigorta bitişi yaklaşınca uyarı geliyor mu?** Hayır; tarihler yalnızca kayıttadır.
|
||||
Hatırlatma için zamanlanmış iş + bildirim tipi eklenmelidir (yok).
|
||||
|
||||
**Bir şoföre 5'ten fazla araç zimmetlenebilir mi?** Hayır; kolonlar sabittir.
|
||||
|
||||
**Masraf girişindeki "Firma Adı" neden Gidilecek Yerler'den geliyor?** Masraf firması ayrı bir
|
||||
tanım olarak açılmamış, gidilecek yer tanımı kullanılmıştır.
|
||||
|
||||
**Kontrol edilmeli — dönüş güncellemeyle girildiğinde araç/şoför güncellenmiyor.** Giriş–çıkış
|
||||
ekranında yalnızca insert ve delete sonrası komut vardır. Çıkış kaydı açılıp dönüş **aynı kaydı
|
||||
düzenleyerek** girildiğinde aracın `Status`/`CurrentKm`'si ve şoförün `TotalKm`'si güncellenmez
|
||||
(bir sonraki ekleme ya da silmeye kadar).
|
||||
|
||||
**Kontrol edilmeli — yalnız çıkış girilen kayıtta aracın km'si.** Formda `EntryKm` varsayılanı
|
||||
`0`'dır. Insert sonrası komut `@EntryKm` boş değilse aracın `CurrentKm`'sini ona eşitler. Giriş km
|
||||
temizlenmeden kaydedilen bir çıkış kaydı aracın km'sini 0'a çekebilir.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_{VehicleDocument,Vehicle,VehicleFile,VehicleDestination,Driver,DriverDocument,DriverPenalty,DriverAccident,VehicleExpenseDefinition,VehicleExpense,VehicleExpenseLine,VehicleMovement}.sql` | Tablolar |
|
||||
| `configs/seeds/host/wizard/{VehicleDocument,Vehicle,VehicleFile,VehicleDestination,Driver,DriverDocument,DriverPenalty,DriverAccident,VehicleExpenseDefinition,VehicleExpense,VehicleExpenseLine,VehicleMovement}.json` | 12 wizard |
|
||||
| `configs/seeds/host/data/App.Hr.{VehicleDocument,VehicleExpenseDefinition}.json` | Tanım verisi |
|
||||
| `configs/seeds/host/data/App.Menus.Menu.json`, `Abp.Identity.Permissions.json`, `App.Languages.LanguageText.json` | Menü, yetki, dil satırları |
|
||||
|
||||
Kurulum: DB Migrate. Geri alma: Wizard Manager'dan alt formlar önce, ana ekranlar sonra silinir;
|
||||
tablolar yalnızca onayda seçilirse düşer.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Araç Belgeleri — `App.Hr.VehicleDocument`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/VehicleDocument.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Vehicles` › `App.Hr.VehicleDocument` (sıra 1) |
|
||||
| Yetki | `App.Hr.VehicleDocument` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Araç Belgeleri — araç ve şoför kayıtlarında kullanılan belge tanımları (ruhsat, sigorta, muayene, MTV, OGS/HGS, ehliyet, psikoteknik, ceza ve kaza belgeleri). |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_VehicleDocument` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.VehicleDocument.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `DocumentGroup` | Belge Grubu | dxSelectBox | ✓ | ✓ | liste: Vehicle, Driver |
|
||||
| `DocumentType` | Belge Tipi | dxSelectBox | ✓ | ✓ | liste: Insurance, Document, Tax, Toll, Inspection, Maintenance, Penalty, Accident |
|
||||
| `Name` | Belge Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Araçlar — `App.Hr.Vehicle`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Vehicle.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Vehicles` › `App.Hr.Vehicle` (sıra 2) |
|
||||
| Yetki | `App.Hr.Vehicle` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Araçlar — şubeye ait şirket araçları, anlık durumu (şirkette/dışarıda), güncel km'si ve muayene/sigorta tarihleri. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_Vehicle` · 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.Hr.VehicleFile` (Id → VehicleId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Hr.Vehicle.Widget.Arrived`, `App.Hr.Vehicle.Widget.Left`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsActive=true |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `BranchId` | Tesis Adı | dxSelectBox | ✓ | ✓ | sorgu: Sas_T_Branch |
|
||||
| `Name` | Araç Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `Brand` | Markası | dxTextBox | | ✓ | |
|
||||
| `Model` | Modeli | dxTextBox | | ✓ | |
|
||||
| `BodyType` | Cinsi | dxTextBox | | ✓ | |
|
||||
| `UsagePlace` | Kullanıldığı Yer | dxTextBox | | ✓ | |
|
||||
| `RegistrationDate` | Tescil Tarihi | dxDateBox | | ✓ | |
|
||||
| `PlateNumber` | Plakası | dxTextBox | ✓ | ✓ | |
|
||||
| `Status` | Durumu | dxSelectBox | | ✓ | liste: Arrived, Left |
|
||||
| `CurrentKm` | Araç Km'si | dxNumberBox | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
| `InspectionStart` | Muayene Başlangıç | dxDateBox | | ✓ | |
|
||||
| `InspectionEnd` | Muayene Bitiş | dxDateBox | | ✓ | |
|
||||
| `InsuranceStart` | Sigorta Başlangıç | dxDateBox | | ✓ | |
|
||||
| `InsuranceEnd` | Sigorta Bitiş | dxDateBox | | ✓ | |
|
||||
| `EmissionStart` | Egzoz Muayene Başlangıç | dxDateBox | | ✓ | |
|
||||
| `EmissionEnd` | Egzoz Muayene Bitiş | dxDateBox | | ✓ | |
|
||||
| `TachographStart` | Takograf Kalib. Başlangıç | dxDateBox | | ✓ | |
|
||||
| `TachographEnd` | Takograf Kalib. Bitiş | dxDateBox | | ✓ | |
|
||||
|
||||
### Gidilecek Yerler — `App.Hr.VehicleDestination`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/VehicleDestination.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Vehicles` › `App.Hr.VehicleDestination` (sıra 3) |
|
||||
| Yetki | `App.Hr.VehicleDestination` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Gidilecek Yerler — araçlarla gidilen tanımlı yerler ve uzaklıkları. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_VehicleDestination` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsActive=true |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Gidilecek Yerin Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `Distance` | Uzaklığı (km) | dxNumberBox | | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Şoför Tanımlama — `App.Hr.Driver`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Driver.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Vehicles` › `App.Hr.Driver` (sıra 4) |
|
||||
| Yetki | `App.Hr.Driver` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Şoför Tanımlama — şirket araçlarını kullanan personel, zimmetli araçları ve sürüş geçmişi. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_Driver` · 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.Hr.DriverDocument` (Id → DriverId), `App.Hr.DriverPenalty` (Id → DriverId), `App.Hr.DriverAccident` (Id → DriverId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Hr.Driver.Widget.WithVehicle`, `App.Hr.Driver.Widget.TotalKm` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `UserId` | Sicil No / Adı Soyadı | dxSelectBox | ✓ | ✓ | sorgu: AbpUsers |
|
||||
| `Vehicle1Id` | Zimmetli Araç 1 | dxSelectBox | | ✓ | sorgu: Hr_T_Vehicle |
|
||||
| `Vehicle2Id` | Zimmetli Araç 2 | dxSelectBox | | ✓ | sorgu: Hr_T_Vehicle |
|
||||
| `Vehicle3Id` | Zimmetli Araç 3 | dxSelectBox | | ✓ | sorgu: Hr_T_Vehicle |
|
||||
| `Vehicle4Id` | Zimmetli Araç 4 | dxSelectBox | | ✓ | sorgu: Hr_T_Vehicle |
|
||||
| `Vehicle5Id` | Zimmetli Araç 5 | dxSelectBox | | ✓ | sorgu: Hr_T_Vehicle |
|
||||
| `TotalKm` | Yapılan KM | dxNumberBox | | ✓ | |
|
||||
|
||||
### Masraf Tanımlama — `App.Hr.VehicleExpenseDefinition`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/VehicleExpenseDefinition.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Vehicles` › `App.Hr.VehicleExpenseDefinition` (sıra 5) |
|
||||
| Yetki | `App.Hr.VehicleExpenseDefinition` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Masraf Tanımlama — araç masraf kalemleri (sigorta, vergi, bakım, muayene, geçiş, ceza, yakıt…). |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_VehicleExpenseDefinition` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.VehicleExpenseDefinition.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `ExpenseType` | Masraf Tipi | dxTextBox | ✓ | ✓ | |
|
||||
| `Name` | Masraf Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Masraf Girişleri — `App.Hr.VehicleExpense`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/VehicleExpense.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Vehicles` › `App.Hr.VehicleExpense` (sıra 6) |
|
||||
| Yetki | `App.Hr.VehicleExpense` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Masraf Girişleri — araç için gelen her fatura/fiş: başlık bilgileri ve kalemleri. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_VehicleExpense` · 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.Hr.VehicleExpenseLine` (Id → VehicleExpenseId) |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Today`, `App.Widget.TotalRevenue` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `VehicleId` | Araç Adı | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_Vehicle |
|
||||
| `InvoiceNo` | Fatura No | dxTextBox | ✓ | ✓ | |
|
||||
| `InvoiceDate` | Fatura Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `DestinationId` | Firma Adı | dxSelectBox | | ✓ | sorgu: Hr_T_VehicleDestination |
|
||||
| `VehicleDocumentId` | Belge Adı | dxSelectBox | | ✓ | sorgu: Hr_T_VehicleDocument |
|
||||
| `FileName` | Dosya Adı | dxTextBox | | ✓ | |
|
||||
| `FileContent` | Dosya | dxImageUpload | | ✓ | |
|
||||
|
||||
### Araç Giriş-Çıkış Takip — `App.Hr.VehicleMovement`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/VehicleMovement.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Vehicles` › `App.Hr.VehicleMovement` (sıra 7) |
|
||||
| Yetki | `App.Hr.VehicleMovement` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Araç Giriş-Çıkış Takip — güvenliğin tuttuğu araç hareket defteri: araç şirketten ne zaman, kimle, hangi km ile çıktı, ne zaman döndü. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_VehicleMovement` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Hr.Vehicle.Widget.Left`, `App.Widget.Today` |
|
||||
| Komutlar | InsertAfter: SQL · DeleteAfter: SQL |
|
||||
| Form varsayılanları | EntryKm=0 |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `MovementNo` | Hareket No | dxNumberBox | | | |
|
||||
| `ExitDate` | Çıkış Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `BranchId` | Çıkış Şube | dxSelectBox | | ✓ | sorgu: Sas_T_Branch |
|
||||
| `ExitTime` | Çıkış Saati | dxTextBox | ✓ | ✓ | script |
|
||||
| `ExitKm` | Çıkış Km | dxNumberBox | ✓ | ✓ | script |
|
||||
| `SenderUserId` | Gönderen Personel | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `SecurityUserId` | Güvenlik Personeli | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `DriverUserId` | Kullanan Personel | dxSelectBox | ✓ | ✓ | sorgu: AbpUsers |
|
||||
| `VehicleId` | Araç Adı / Plaka | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_Vehicle · script |
|
||||
| `DestinationId` | Gidilen Yer | dxSelectBox | | ✓ | sorgu: Hr_T_VehicleDestination |
|
||||
| `Reason` | Gidiş Sebebi | dxTextBox | | ✓ | |
|
||||
| `Location` | Konum | dxTextBox | | ✓ | |
|
||||
| `EntrySecurityUserId` | Giriş Yapan Güvenlik Per. | dxSelectBox | | ✓ | sorgu: AbpUsers |
|
||||
| `EntryDate` | Giriş Tarihi | dxDateBox | | ✓ | script |
|
||||
| `EntryBranchId` | Giriş Şube | dxSelectBox | | ✓ | sorgu: Sas_T_Branch |
|
||||
| `EntryTime` | Giriş Saati | dxTextBox | | ✓ | script |
|
||||
| `EntryKm` | Giriş Km | dxNumberBox | | ✓ | script |
|
||||
| `TravelledKm` | Yapılan Km | dxNumberBox | | ✓ | |
|
||||
| `Status` | Durum | dxSelectBox | | ✓ | liste: Arrived, Left |
|
||||
| `DurationMinutes` | Gezinti Süresi / Dk | dxNumberBox | | ✓ | |
|
||||
| `ExpectedKm` | Olması Gereken Km | dxNumberBox | | ✓ | |
|
||||
|
||||
### Araç Belgeleri — `App.Hr.VehicleFile`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/VehicleFile.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.VehicleFile` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Araç Dosyaları — araca yüklenen belgeler (ruhsat, poliçe, muayene raporu…). |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_VehicleFile` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `VehicleId` | Araç | dxSelectBox | | | sorgu: Hr_T_Vehicle |
|
||||
| `VehicleDocumentId` | Belge Adı | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_VehicleDocument |
|
||||
| `FileName` | Dosya Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `FileContent` | Dosya | dxImageUpload | ✓ | ✓ | |
|
||||
|
||||
### Şoför Belgeleri — `App.Hr.DriverDocument`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DriverDocument.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.DriverDocument` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Şoför Belgeleri — şoföre ait belgeler (sürücü belgesi, psikoteknik, SRC…). |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_DriverDocument` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `DriverId` | Şoför | dxSelectBox | | | sorgu: Hr_T_Driver |
|
||||
| `VehicleDocumentId` | Belge Adı | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_VehicleDocument |
|
||||
| `FileName` | Dosya Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `FileContent` | Dosya | dxImageUpload | ✓ | ✓ | |
|
||||
|
||||
### Ceza Belgeleri — `App.Hr.DriverPenalty`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DriverPenalty.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.DriverPenalty` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Şoför Cezaları — şoföre kesilen trafik cezaları. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_DriverPenalty` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `DriverId` | Şoför | dxSelectBox | | | sorgu: Hr_T_Driver |
|
||||
| `PenaltyDate` | Ceza Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `Amount` | Tutarı | dxNumberBox | | ✓ | |
|
||||
| `Description` | Ceza Açıklama | dxTextBox | | ✓ | |
|
||||
| `VehicleDocumentId` | Belge Adı | dxSelectBox | | ✓ | sorgu: Hr_T_VehicleDocument |
|
||||
| `FileName` | Dosya Adı | dxTextBox | | ✓ | |
|
||||
| `FileContent` | Dosya | dxImageUpload | | ✓ | |
|
||||
|
||||
### Kaza Belgeleri — `App.Hr.DriverAccident`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/DriverAccident.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.DriverAccident` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Şoför Kazaları — şoförün karıştığı trafik kazaları ve belgeleri. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_DriverAccident` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `DriverId` | Şoför | dxSelectBox | | | sorgu: Hr_T_Driver |
|
||||
| `AccidentDate` | Kaza Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `VehicleDocumentId` | Belge Adı | dxSelectBox | | ✓ | sorgu: Hr_T_VehicleDocument |
|
||||
| `Description` | Kaza Açıklama | dxTextBox | | ✓ | |
|
||||
| `FileName` | Dosya Adı | dxTextBox | | ✓ | |
|
||||
| `FileContent` | Dosya | dxImageUpload | | ✓ | |
|
||||
|
||||
### Masraf Kalemleri — `App.Hr.VehicleExpenseLine`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/VehicleExpenseLine.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | Menüsüz (alt form) |
|
||||
| Yetki | `App.Hr.VehicleExpenseLine` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Masraf Kalemleri — bir masraf faturasının satırları. |
|
||||
| Geliştirme talebi | Human Resources -> Araçlar |
|
||||
| Kaynak | `Hr_T_VehicleExpenseLine` · 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 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `VehicleExpenseId` | Masraf Girişi | dxTextBox | | | |
|
||||
| `ExpenseDefinitionId` | Masraf Adı | dxSelectBox | ✓ | ✓ | sorgu: Hr_T_VehicleExpenseDefinition |
|
||||
| `DetailName` | Masraf Detay Adı | dxTextBox | | ✓ | |
|
||||
| `Quantity` | Miktar | dxNumberBox | ✓ | ✓ | script |
|
||||
| `Amount` | Tutarı | dxNumberBox | ✓ | ✓ | script |
|
||||
| `DiscountRate` | İskonto Oranı (%) | dxNumberBox | ✓ | ✓ | script |
|
||||
| `NetAmount` | Net Tutar | dxNumberBox | ✓ | ✓ | |
|
||||
| `Description` | Masraf Açıklama | dxTextBox | | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
150
configs/seeds/host/docs/modules/HrVisitor.md
Normal file
150
configs/seeds/host/docs/modules/HrVisitor.md
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
# İK › Ziyaretçiler (`App.Hr.Visitor`)
|
||||
|
||||
Güvenlik/resepsiyon için ziyaretçi giriş–çıkış defteri: kim, hangi firmadan, kimi ziyarete, ne
|
||||
zaman geldi, hangi kartı aldı, ne zaman çıktı. Tamamı konfigürasyondur (tek Wizard ekranı).
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| Güvenlik / resepsiyon | Ziyaretçiyi girişte kaydeder, kart verir, çıkışta çıkış saatini işler | Ziyaretçiler |
|
||||
| İK / idari işler | Günlük ziyaretçi sayısını, içeride kalanları ve geçmişi izler | Ziyaretçiler (widget, Pivot) |
|
||||
|
||||
Kapsam: kiracı (`IsTenant`). Her kayıt bir şubeye bağlıdır; satır süzmesi yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modül §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar wizard ve SQL'den okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Yol | Tek Wizard liste ekranı |
|
||||
| Ziyaretçi kimliği | Ziyaretçi ayrı bir kişi kartı değildir; her ziyaret satırında ad soyad serbest metindir (tekrar gelen ziyaretçi yeniden yazılır) |
|
||||
| Firma | Serbest metin + **otomatik tamamlama** (daha önce girilen firma adlarından) |
|
||||
| Ziyaretçi tipi | Sabit liste: Ziyaretçi, Müşteri, Tedarikçi, Taşeron, Kurye (değerler Türkçe anahtardır) |
|
||||
| İçeride mi? | `ExitTime` boşsa ziyaretçi içeride sayılır |
|
||||
| Bildirim | Ziyaret edilen personele bildirim **gönderilmez** |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekran
|
||||
|
||||
| Menü (TR / EN) | `ListFormCode` | Yer | Görünümler | Widget'lar (bugün) |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Ziyaretçiler / Visitors | `App.Hr.Visitor` | `İnsan Kaynakları` (sıra 8, `FcBusinessman`) | Grid, Card, Pivot, Chart | Bugün Gelen · İçeride · Çıkış Yapan |
|
||||
|
||||
Widget'lar yalnız **bugünün** (`VisitDate = bugün`) kayıtlarını sayar.
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
`Hr_T_Visitor` (`sql/object/Hr_T_Visitor.sql`, entity yok):
|
||||
|
||||
| Kolon | Açıklama |
|
||||
| --- | --- |
|
||||
| `BranchId` | Şube (zorunlu) |
|
||||
| `VisitorType` | Ziyaretçi tipi (varsayılan "Ziyaretçi") |
|
||||
| `VisitDate` | Ziyaret tarihi |
|
||||
| `EntryTime` / `ExitTime` | Giriş / çıkış zamanı (`datetime`) |
|
||||
| `CardNo` | Verilen ziyaretçi kartı |
|
||||
| `VisitorFullName` | Ziyaretçi adı soyadı (zorunlu) |
|
||||
| `VisitedUserId` | Ziyaret edilen personel (`AbpUsers`, zorunlu) |
|
||||
| `CompanyName` | Firma |
|
||||
| `VisitReason` | Ziyaret sebebi |
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları
|
||||
|
||||
| Yer | Kural |
|
||||
| --- | --- |
|
||||
| Yeni kayıt | Ziyaret tarihi bugün, giriş saati şimdi, tip "Ziyaretçi" |
|
||||
| Çıkış | Kayıt düzenlenip çıkış saati girilir; otomatik çıkış yoktur |
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`; `App.Hr.Visitor` + `.Create/.Update/.Delete/.Export/.Import/.Note`.
|
||||
Güvenliğe kök + `.Create/.Update` yeter. Hiçbir yetki role otomatik atanmaz. Ziyaretçi adı kişisel
|
||||
veridir; saklama süresi için periyodik temizlik yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
`Sas_T_Branch` (şube), `AbpUsers` (ziyaret edilen personel). Bildirim, rapor ya da zamanlanmış iş yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. Tedarikçi temsilcisi gelir; güvenlik yeni kayıt açar (tarih/saat dolu), tip Tedarikçi, ad soyad,
|
||||
firma (otomatik tamamlamadan), ziyaret edilen satın alma uzmanı, kart no 12.
|
||||
2. "İçeride" kartı 1 artar.
|
||||
3. Çıkışta kayıt açılıp çıkış saati girilir; "Çıkış Yapan" kartı artar.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar
|
||||
|
||||
**Tekrar gelen ziyaretçinin bilgileri neden dolmuyor?** Ziyaretçi kartı yoktur; yalnız firma adı otomatik tamamlanır.
|
||||
|
||||
**Gün sonunda içeride kalanlar nasıl görülür?** Bugünün "İçeride" kartı ya da `ExitTime` boş filtresi.
|
||||
|
||||
**Ziyaret edilen kişiye haber gidiyor mu?** Hayır.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_Visitor.sql` | Tablo |
|
||||
| `configs/seeds/host/wizard/Visitor.json` | Wizard |
|
||||
|
||||
Geri alma: Wizard Manager'dan silinir; tablo yalnızca onayda seçilirse düşer.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Ziyaretçiler — `App.Hr.Visitor`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Visitor.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr` › `App.Hr.Visitor` (sıra 3) |
|
||||
| Yetki | `App.Hr.Visitor` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Ziyaretçiler — güvenlik/resepsiyonun tuttuğu ziyaretçi giriş-çıkış defteri. |
|
||||
| Geliştirme talebi | Human Resources -> Ziyaretçi Takip Listesi |
|
||||
| Kaynak | `Hr_T_Visitor` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Hr.Visitor.Widget.Today`, `App.Hr.Visitor.Widget.Inside`, `App.Hr.Visitor.Widget.Exited` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `VisitDate` | Ziyaret Tarihi | dxDateBox | ✓ | ✓ | script |
|
||||
| `VisitorType` | Ziyaretçi Tipi | dxSelectBox | ✓ | ✓ | liste: Ziyaretçi, Müşteri, Tedarikçi, Taşeron, Kurye · script |
|
||||
| `EntryTime` | Giriş Saati | dxDateBox | ✓ | ✓ | script |
|
||||
| `ExitTime` | Çıkış Saati | dxDateBox | | ✓ | |
|
||||
| `CardNo` | Kart No | dxTextBox | | ✓ | |
|
||||
| `VisitedUserId` | Ziyaret Edilen Personel | dxSelectBox | ✓ | ✓ | sorgu: AbpUsers |
|
||||
| `VisitorFullName` | Ziyaretçi Adı Soyadı | dxTextBox | ✓ | ✓ | |
|
||||
| `CompanyName` | Firma Adı | dxAutocomplete | | ✓ | sorgu: Hr_T_Visitor |
|
||||
| `VisitReason` | Ziyaret Sebebi | dxTextArea | | ✓ | |
|
||||
| `BranchId` | Şube Adı | dxSelectBox | ✓ | ✓ | sorgu: Sas_T_Branch |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
195
configs/seeds/host/docs/modules/HrWorkCalendar.md
Normal file
195
configs/seeds/host/docs/modules/HrWorkCalendar.md
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
<!-- module-doc: claims=App.Hr.Shift -->
|
||||
# İK › Çalışma Takvimi ve Vardiyalar (`App.Hr.WorkCalendar`, `App.Hr.Shift`)
|
||||
|
||||
Çalışma zamanının iki temel tanımı: resmi tatil / yarım gün takvimi (yıllık tekrarlı ya da tek
|
||||
seferlik) ve vardiya tanımları (saat aralığı, mola, gece vardiyası). Diğer modüller bu tanımları
|
||||
lookup olarak kullanır. Tamamı konfigürasyondur (Wizard + seed); vardiya ayrıca kullanıcı kaydına
|
||||
bağlanır.
|
||||
|
||||
> Bu doküman modülün tek "nasıl çalışır" kaynağıdır. Modülde yapılan her değişiklik aynı commit'te
|
||||
> buraya yansır (`lowcode.instructions.md` §0.13).
|
||||
|
||||
---
|
||||
|
||||
## 1. Amaç ve kapsam
|
||||
|
||||
| Persona | Ne yapar | Ekran |
|
||||
| --- | --- | --- |
|
||||
| İK | Yılın tatil ve yarım günlerini girer, takvim görünümünden kontrol eder | Çalışma Takvimi |
|
||||
| İK / üretim planlama | Vardiya tanımlarını yönetir, çalışanı vardiyaya bağlar | Vardiyalar · Kimlik › Kullanıcılar |
|
||||
|
||||
Kapsam: kiracı (`IsTenant`). Şube kırılımı yoktur — takvim kiracının tamamı için geçerlidir.
|
||||
|
||||
---
|
||||
|
||||
## 2. Analiz ve kararlar
|
||||
|
||||
> Modüller §0.13 kuralından önce üretildi; keşif turu kaydı yoktur. Kararlar artefaktlardan
|
||||
> (wizard, seed, commit `130e23bc` "Disiplin Dosyaları, Çalışma Takvimi") okunmuştur.
|
||||
|
||||
| Konu | Karar |
|
||||
| --- | --- |
|
||||
| Tatil tekrarı | Sabit tarihli resmi tatiller `RecurrenceRule = FREQ=YEARLY` ile **bir kez** girilir, her yıl tekrarlar; dini bayramlar ay takvimine bağlı olduğu için **her yıl ayrı** satırdır (tekrar kuralı boş) |
|
||||
| Gün türü | `Holiday` (tam gün tatil) / `HalfDay` (arife, yarım gün) |
|
||||
| Görünüm | Liste görünümlerine ek olarak **Scheduler** (takvim) görünümü; `AllDay` her zaman `true` |
|
||||
| Vardiya saatleri | `StartTime` / `EndTime` `SS:dd` metin; çalışma süresi elle girilir (otomatik hesap yok) |
|
||||
| Gece vardiyası | Bayrak (`IsNightShift`) — sağlık kartındaki "gece çalışabilir" sonucuyla birlikte değerlendirilir, otomatik kontrol yoktur |
|
||||
| Vardiya bağı | Kullanıcı kaydında `ShiftId` alanı (`LookupQueryValues.TenantShiftValues`: "Ad (başlangıç-bitiş)") |
|
||||
| Menü yeri | Çalışma Takvimi ve Vardiyalar `İnsan Kaynakları` kökündedir. Vardiyalar wizard dosyasında üst menü `App.Hr.Definitions` yazılıdır, menü satırı kökte durur (bkz. §9) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Menü ve ekranlar
|
||||
|
||||
| Menü (TR / EN) | `ListFormCode` | Yer | Görünümler | Widget'lar |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Çalışma Takvimi / Work Calendar | `App.Hr.WorkCalendar` | `İnsan Kaynakları` (sıra 2, `FcCalendar`) | Grid, Card, Pivot, Chart, **Scheduler** | Toplam · Tatil · Yarım Gün |
|
||||
| Vardiyalar / Shifts | `App.Hr.Shift` | `İnsan Kaynakları` (sıra 3, `FcClock`) | Grid, Card, Pivot, Chart | Toplam · Aktif · Pasif |
|
||||
|
||||
Scheduler eşlemesi: metin `Name`, başlangıç `StartDate`, bitiş `EndDate`, tüm gün `AllDay`,
|
||||
tekrar `RecurrenceRule`.
|
||||
|
||||
Seed verisi:
|
||||
- Çalışma takvimi, 16 satır (`data/App.Hr.WorkCalendar.json`):
|
||||
- Yıllık tekrarlı tatiller: Yılbaşı, 23 Nisan, 1 Mayıs, 19 Mayıs, 15 Temmuz, 30 Ağustos, 29 Ekim.
|
||||
- Yıllık tekrarlı yarım gün: 28 Ekim arifesi.
|
||||
- Yıla özel satırlar: 2026 ve 2027 Ramazan/Kurban bayramları ve arifeleri.
|
||||
- Vardiyalar, 3 satır (`data/App.Hr.Shift.json`): Sabah 08:00–16:00, Akşam 16:00–00:00, Gece 00:00–08:00 (gece vardiyası).
|
||||
|
||||
---
|
||||
|
||||
## 4. Veri modeli
|
||||
|
||||
| Tablo | Kolonlar |
|
||||
| --- | --- |
|
||||
| `Hr_T_WorkCalendar` | `Name`, `StartDate`, `EndDate`, `DayType` (Holiday/HalfDay), `RecurrenceRule` (boş / `FREQ=YEARLY`), `AllDay`, `IsActive` |
|
||||
| `Hr_T_Shift` | `Name`, `StartTime`, `EndTime`, `BreakMinutes`, `WorkingHours`, `IsNightShift`, `IsActive` |
|
||||
| `AbpUsers.ShiftId` | Çalışanın vardiyası (genişletme kolonu) |
|
||||
|
||||
Entity yoktur (wizard tabloları); `sql/object/Hr_T_{WorkCalendar,Shift}.sql`.
|
||||
|
||||
---
|
||||
|
||||
## 5. İş kuralları
|
||||
|
||||
| Yer | Kural |
|
||||
| --- | --- |
|
||||
| Takvim — yeni kayıt | Gün türü `Holiday`, tekrar `FREQ=YEARLY`, tüm gün, aktif |
|
||||
| Takvim — çok günlü tatil | Başlangıç–bitiş aralığı olarak tek satırda girilebilir |
|
||||
| Vardiya — yeni kayıt | Gece vardiyası hayır, aktif |
|
||||
|
||||
Takvim ve vardiya başka bir hesaba (izin günü, mesai, puantaj) **bağlı değildir**; platformda puantaj/izin hesaplayan modül yoktur.
|
||||
|
||||
---
|
||||
|
||||
## 6. Yetki ve görünürlük
|
||||
|
||||
İzin grubu `App.Hr`, modül `Sas|Hr`. Her ekranın kökü + `.Create/.Update/.Delete/.Export/.Import/.Note`.
|
||||
Hiçbir yetki role otomatik atanmaz. Takvimin okunması tüm çalışanlara açılabilir; düzenleme İK'da kalmalıdır.
|
||||
|
||||
---
|
||||
|
||||
## 7. Entegrasyonlar
|
||||
|
||||
| Kullanan | Nasıl |
|
||||
| --- | --- |
|
||||
| Kimlik › Kullanıcılar | `ShiftId` alanı vardiya lookup'ı |
|
||||
| Olay Günlüğü (`App.Hr.EventLog`) | Olay kaydında vardiya seçimi |
|
||||
| Sağlık Kartları | Vardiyalı / gece çalışabilir sonucu (bilgi; vardiya tanımıyla otomatik eşleşmez) |
|
||||
|
||||
---
|
||||
|
||||
## 8. Akış örneği
|
||||
|
||||
1. Yıl başında İK **Çalışma Takvimi**'nde o yılın dini bayram satırlarını ekler (sabit tatiller zaten yıllık tekrarlıdır) ve Scheduler görünümünde yılı kontrol eder.
|
||||
2. Üretim için **Vardiyalar**'a "Hafta Sonu 08:00–20:00, mola 60 dk, çalışma 11 saat" eklenir.
|
||||
3. Kullanıcı ekranında çalışanların **Vardiya** alanı güncellenir; Olay Günlüğü kayıtlarında da bu vardiyalar seçilir.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sık sorulanlar ve bilinen sınırlar
|
||||
|
||||
**Ramazan Bayramı gelecek yıl görünmüyor.** Dini bayramlar yıla özeldir; her yıl yeni satır girilir.
|
||||
|
||||
**Çalışma süresi neden hesaplanmıyor?** Vardiya saatleri metindir, süre elle girilir.
|
||||
|
||||
**Takvim izin/puantaj hesabını etkiliyor mu?** Hayır; bu hesapları yapan bir modül yoktur.
|
||||
|
||||
**Vardiyalar menüde Tanımlamalar altında değil.** Menü satırı `İnsan Kaynakları` kökündedir; wizard
|
||||
dosyasındaki üst menü (`App.Hr.Definitions`) eski değerdir. Wizard yeniden deploy edilirse menü
|
||||
Tanımlamalar altına taşınabilir — yeniden deploy etmeden önce wizard'daki üst menü kökle eşitlenmelidir.
|
||||
|
||||
---
|
||||
|
||||
## 10. Dosyalar ve geri alma
|
||||
|
||||
| Dosya | İçerik |
|
||||
| --- | --- |
|
||||
| `configs/seeds/host/sql/object/Hr_T_{WorkCalendar,Shift}.sql` | Tablolar |
|
||||
| `configs/seeds/host/wizard/{WorkCalendar,Shift}.json` | 2 wizard |
|
||||
| `configs/seeds/host/data/App.Hr.{WorkCalendar,Shift}.json` | Takvim ve vardiya verisi (ekran kayıtları dosyaya aynalanır) |
|
||||
| `api/src/Sozsoft.Platform.Application.Contracts/LookUpQueryValues.cs` (`TenantShiftValues`) | Kullanıcı ekranındaki vardiya lookup'ı |
|
||||
|
||||
Geri alma: Wizard Manager'dan silinir; vardiya tablosu kullanıcı ekranının lookup'ı tarafından okunduğu için düşürülmemelidir.
|
||||
|
||||
<!-- module-doc:auto:begin -->
|
||||
## Ek — Ekran envanteri (otomatik)
|
||||
|
||||
> Wizard dosyalarından üretilir; deploy, silme, tasarımcı kaydı ve import'ta yenilenir. Elle düzenleme bir sonraki yenilemede kaybolur.
|
||||
|
||||
### Çalışma Takvimi — `App.Hr.WorkCalendar`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/WorkCalendar.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr` › `App.Hr.WorkCalendar` (sıra 2) |
|
||||
| Yetki | `App.Hr.WorkCalendar` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Çalışma Takvimi — resmi tatiller, arife (yarım gün) ve çalışılmayan günler. |
|
||||
| Kaynak | `Hr_T_WorkCalendar` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart, Scheduler (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Hr.WorkCalendar.DayType.Holiday`, `App.Hr.WorkCalendar.DayType.HalfDay` |
|
||||
| Form varsayılanları | DayType=Holiday, RecurrenceRule=FREQ=YEARLY, AllDay=true, IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.WorkCalendar.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `StartDate` | Başlangıç Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `EndDate` | Bitiş Tarihi | dxDateBox | ✓ | ✓ | |
|
||||
| `DayType` | Gün Türü | dxSelectBox | ✓ | ✓ | liste: Holiday, HalfDay |
|
||||
| `RecurrenceRule` | Tekrarlama Kuralı | dxSelectBox | | ✓ | liste: FREQ=YEARLY |
|
||||
| `AllDay` | Tüm Gün | dxCheckBox | | | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
### Vardiyalar — `App.Hr.Shift`
|
||||
|
||||
| Özellik | Değer |
|
||||
| --- | --- |
|
||||
| Wizard | `wizard/Shift.json` |
|
||||
| Yol | Liste (Wizard) |
|
||||
| Menü | `App.Hr.Definitions` › `App.Hr.Shift` (sıra 9) |
|
||||
| Yetki | `App.Hr.Shift` + `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
|
||||
| Açıklama | Vardiyalar — çalışma vardiyalarının tanımı (sabah, akşam, gece…). |
|
||||
| Geliştirme talebi | Human Resources -> Olay Günlüğü |
|
||||
| Kaynak | `Hr_T_Shift` · filtre `"IsDeleted" = 'false'` |
|
||||
| Görünümler | Grid, Card, Pivot, Chart (açılış grid) |
|
||||
| Düzenleme | ekle ✓ · düzenle ✓ · sil ✓ · popup |
|
||||
| Kapsam | Kiracı |
|
||||
| Widget'lar | `App.Widget.Total`, `App.Widget.Active`, `App.Widget.Passive` |
|
||||
| Form varsayılanları | IsNightShift=false, IsActive=true |
|
||||
| Veri aynası | `data/App.Hr.Shift.json` |
|
||||
|
||||
| Alan | Başlık | Editör | Zorunlu | Formda | Kaynak |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `Name` | Vardiya Adı | dxTextBox | ✓ | ✓ | |
|
||||
| `StartTime` | Başlangıç Saati | dxTextBox | | ✓ | |
|
||||
| `EndTime` | Bitiş Saati | dxTextBox | | ✓ | |
|
||||
| `BreakMinutes` | Mola (dk) | dxNumberBox | | ✓ | |
|
||||
| `WorkingHours` | Çalışma Süresi (Saat) | dxNumberBox | | ✓ | |
|
||||
| `IsNightShift` | Gece Vardiyası | dxCheckBox | ✓ | ✓ | |
|
||||
| `IsActive` | Aktif | dxCheckBox | ✓ | ✓ | |
|
||||
|
||||
<!-- module-doc:auto:end -->
|
||||
18
configs/seeds/host/sql/object/Hr_S_DevelopmentPlanSync.sql
Normal file
18
configs/seeds/host/sql/object/Hr_S_DevelopmentPlanSync.sql
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
CREATE OR ALTER PROCEDURE [dbo].[Hr_S_DevelopmentPlanSync]
|
||||
@PlanId uniqueidentifier
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
-- Eğitim aksiyonu, çalışan o eğitime "Katıldı" olarak işlendiyse kendiliğinden tamamlanır;
|
||||
-- tamamlanan aksiyonun ilerlemesi her zaman %100'dür.
|
||||
UPDATE dp
|
||||
SET Status = N'Completed', Progress = 100
|
||||
FROM Hr_T_DevelopmentPlan dp
|
||||
WHERE dp.Id = @PlanId AND dp.IsDeleted = 0 AND dp.Status <> N'Cancelled'
|
||||
AND (dp.Status = N'Completed' OR EXISTS (
|
||||
SELECT 1 FROM Hr_T_TrainingParticipant tp
|
||||
WHERE tp.TrainingId = dp.TrainingId AND tp.UserId = dp.EmployeeId
|
||||
AND tp.AttendanceStatus = N'Attended' AND tp.IsDeleted = 0));
|
||||
END
|
||||
GO
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
CREATE OR ALTER PROCEDURE [dbo].[Hr_S_PerformanceFeedbackOpen]
|
||||
@FeedbackId uniqueidentifier,
|
||||
@ActorId uniqueidentifier = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @ReviewId uniqueidentifier, @ReviewerId uniqueidentifier;
|
||||
|
||||
SELECT @ReviewId = ReviewId, @ReviewerId = ReviewerId
|
||||
FROM Hr_T_PerformanceFeedback
|
||||
WHERE Id = @FeedbackId AND IsDeleted = 0;
|
||||
|
||||
IF @ReviewId IS NULL
|
||||
RETURN;
|
||||
|
||||
-- Değerlendirici, değerlendirmenin yetkinlikleri üzerinden puan verir; satırlar burada açılır.
|
||||
INSERT INTO Hr_T_PerformanceFeedbackScore (Id, TenantId, FeedbackId, SkillId, IsActive, CreationTime, CreatorId, IsDeleted)
|
||||
SELECT NEWID(), c.TenantId, @FeedbackId, c.SkillId, 1, GETUTCDATE(), @ActorId, 0
|
||||
FROM Hr_T_PerformanceCompetency c
|
||||
WHERE c.ReviewId = @ReviewId AND c.IsDeleted = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM Hr_T_PerformanceFeedbackScore s
|
||||
WHERE s.FeedbackId = @FeedbackId AND s.SkillId = c.SkillId AND s.IsDeleted = 0);
|
||||
|
||||
EXEC dbo.Hr_S_PerformanceNotify @ReviewId, @ReviewerId, N'Performans360Talebi',
|
||||
N'App.Hr.Performance.Notification.Feedback.Subject', N'App.Hr.Performance.Notification.Feedback.Message', @ActorId;
|
||||
END
|
||||
GO
|
||||
54
configs/seeds/host/sql/object/Hr_S_PerformanceGuard.sql
Normal file
54
configs/seeds/host/sql/object/Hr_S_PerformanceGuard.sql
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
CREATE OR ALTER PROCEDURE [dbo].[Hr_S_PerformanceGuard]
|
||||
@ReviewId uniqueidentifier,
|
||||
@UserId uniqueidentifier,
|
||||
@Actor nvarchar(16),
|
||||
@Scope nvarchar(16),
|
||||
@FeedbackId uniqueidentifier = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
-- Kişisel ekranlar (Değerlendirmelerim, Ekibim, 360 Taleplerim) satırı listede süzer; bu kontrol
|
||||
-- aynı kuralı yazma tarafında uygular. Kayıt uçları satırı yalnızca Id ile güncellediği için
|
||||
-- başka birinin kaydına doğrudan yapılan istek burada reddedilir.
|
||||
IF @Actor = N'Hr'
|
||||
RETURN;
|
||||
|
||||
DECLARE @Status nvarchar(16), @EmployeeId uniqueidentifier, @ManagerId uniqueidentifier, @PeriodStatus nvarchar(16);
|
||||
|
||||
SELECT @Status = rv.Status, @EmployeeId = rv.EmployeeId, @ManagerId = rv.ManagerId, @PeriodStatus = p.Status
|
||||
FROM Hr_T_PerformanceReview rv
|
||||
INNER JOIN Hr_T_PerformancePeriod p ON p.Id = rv.PeriodId
|
||||
WHERE rv.Id = @ReviewId AND rv.IsDeleted = 0;
|
||||
|
||||
IF @Status IS NULL
|
||||
THROW 51000, N'Değerlendirme kaydı bulunamadı.', 1;
|
||||
|
||||
IF @PeriodStatus = N'Closed'
|
||||
THROW 51001, N'Dönem kapatıldığı için değerlendirme değiştirilemez.', 1;
|
||||
|
||||
IF @Actor = N'Employee' AND (@UserId IS NULL OR @UserId <> @EmployeeId)
|
||||
THROW 51002, N'Yalnızca kendi değerlendirmenizi değiştirebilirsiniz.', 1;
|
||||
|
||||
IF @Actor = N'Manager' AND (@UserId IS NULL OR @ManagerId IS NULL OR @UserId <> @ManagerId)
|
||||
THROW 51003, N'Yalnızca yöneticisi olduğunuz değerlendirmeleri değiştirebilirsiniz.', 1;
|
||||
|
||||
IF @Actor = N'Reviewer' AND NOT EXISTS (
|
||||
SELECT 1 FROM Hr_T_PerformanceFeedback f
|
||||
WHERE f.Id = @FeedbackId AND f.ReviewId = @ReviewId AND f.ReviewerId = @UserId AND f.IsDeleted = 0)
|
||||
THROW 51004, N'Yalnızca size atanan 360 değerlendirmesini doldurabilirsiniz.', 1;
|
||||
|
||||
-- Durum matrisi: hangi rol hangi aşamada neyi değiştirebilir.
|
||||
DECLARE @Allowed bit = CASE
|
||||
WHEN @Scope = N'DevelopmentPlan' THEN 1
|
||||
WHEN @Actor = N'Employee' AND @Scope = N'Review' THEN IIF(@Status IN (N'GoalSetting', N'SelfReview'), 1, 0)
|
||||
WHEN @Actor = N'Employee' AND @Scope IN (N'Goal', N'Competency') THEN IIF(@Status IN (N'GoalSetting', N'SelfReview'), 1, 0)
|
||||
WHEN @Actor = N'Manager' AND @Scope IN (N'Review', N'Goal', N'Competency') THEN IIF(@Status IN (N'GoalSetting', N'SelfReview', N'ManagerReview'), 1, 0)
|
||||
WHEN @Actor = N'Reviewer' THEN IIF(@Status IN (N'GoalSetting', N'SelfReview', N'ManagerReview'), 1, 0)
|
||||
ELSE 0
|
||||
END;
|
||||
|
||||
IF @Allowed = 0
|
||||
THROW 51005, N'Değerlendirme bu aşamada bu işlem için açık değil.', 1;
|
||||
END
|
||||
GO
|
||||
41
configs/seeds/host/sql/object/Hr_S_PerformanceNotify.sql
Normal file
41
configs/seeds/host/sql/object/Hr_S_PerformanceNotify.sql
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
CREATE OR ALTER PROCEDURE [dbo].[Hr_S_PerformanceNotify]
|
||||
@ReviewId uniqueidentifier,
|
||||
@RecipientId uniqueidentifier,
|
||||
@TypeName nvarchar(64),
|
||||
@SubjectKey nvarchar(128),
|
||||
@MessageKey nvarchar(128),
|
||||
@ActorId uniqueidentifier = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
-- Alıcı kayıttan gelir (çalışan, yönetici ya da 360 değerlendiricisi); tipin Custom kuralları
|
||||
-- yalnızca kanalı belirler. Metin TR dil anahtarından okunur, yer tutucular kayıttan dolar.
|
||||
IF @ReviewId IS NULL OR @RecipientId IS NULL
|
||||
RETURN;
|
||||
|
||||
INSERT INTO Adm_T_Notification (Id, TenantId, NotificationRuleId, NotificationChannel, NotificationTypeId, Identifier, UserId, Message, Subject, IsSent, IsRead, CreationTime, CreatorId, IsDeleted)
|
||||
SELECT NEWID(), rv.TenantId, r.Id, r.Channel, t.Id,
|
||||
CASE WHEN r.Channel = N'Mail' THEN u.Email ELSE CONVERT(nvarchar(64), u.Id) END,
|
||||
u.Id,
|
||||
LEFT(REPLACE(REPLACE(REPLACE(COALESCE(msg.Value, @MessageKey),
|
||||
N'[Employee]', COALESCE(e.Name + N' ' + e.Surname, N'')),
|
||||
N'[Period]', COALESCE(p.Name, N'')),
|
||||
N'[Status]', COALESCE(st.Value, rv.Status)), 2048),
|
||||
LEFT(COALESCE(sub.Value, @SubjectKey), 256),
|
||||
CASE WHEN r.Channel = N'UiActivity' THEN 1 ELSE 0 END, 0, GETUTCDATE(), @ActorId, 0
|
||||
FROM Hr_T_PerformanceReview rv
|
||||
INNER JOIN Hr_T_PerformancePeriod p ON p.Id = rv.PeriodId
|
||||
INNER JOIN AbpUsers e ON e.Id = rv.EmployeeId
|
||||
INNER JOIN AbpUsers u ON u.Id = @RecipientId AND u.IsActive = 1
|
||||
INNER JOIN Adm_T_NotificationType t ON t.Name = @TypeName AND t.IsDeleted = 0
|
||||
AND (t.TenantId = rv.TenantId OR (t.TenantId IS NULL AND rv.TenantId IS NULL))
|
||||
INNER JOIN Adm_T_NotificationRule r ON r.NotificationTypeId = t.Id AND r.IsActive = 1 AND r.IsCustomized = 0
|
||||
AND r.IsDeleted = 0 AND r.RecipientType = N'Custom' AND r.RecipientId IS NULL
|
||||
LEFT JOIN Sas_H_LanguageText msg ON msg.ResourceName = N'Platform' AND msg.[Key] = @MessageKey AND msg.CultureName = N'tr'
|
||||
LEFT JOIN Sas_H_LanguageText sub ON sub.ResourceName = N'Platform' AND sub.[Key] = @SubjectKey AND sub.CultureName = N'tr'
|
||||
LEFT JOIN Sas_H_LanguageText st ON st.ResourceName = N'Platform' AND st.[Key] = N'App.Hr.PerformanceReview.Status.' + rv.Status AND st.CultureName = N'tr'
|
||||
WHERE rv.Id = @ReviewId
|
||||
AND (r.Channel <> N'Mail' OR u.Email IS NOT NULL);
|
||||
END
|
||||
GO
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
CREATE OR ALTER PROCEDURE [dbo].[Hr_S_PerformancePeriodActivate]
|
||||
@PeriodId uniqueidentifier,
|
||||
@ActorId uniqueidentifier = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @TenantId uniqueidentifier;
|
||||
|
||||
SELECT @TenantId = TenantId
|
||||
FROM Hr_T_PerformancePeriod
|
||||
WHERE Id = @PeriodId AND IsDeleted = 0 AND Status = N'Active';
|
||||
|
||||
IF @@ROWCOUNT = 0
|
||||
RETURN;
|
||||
|
||||
DECLARE @Created TABLE (Id uniqueidentifier, EmployeeId uniqueidentifier);
|
||||
|
||||
-- Dönem aktif olduğunda kiracının aktif her kullanıcısına bir değerlendirme açılır; var olana
|
||||
-- dokunulmaz, böylece dönem yeniden kaydedildiğinde yalnızca yeni katılan çalışanlar eklenir.
|
||||
INSERT INTO Hr_T_PerformanceReview (Id, TenantId, PeriodId, EmployeeId, EmployeeName, DepartmentId, JobPositionId, Status, LastStatus, IsActive, CreationTime, CreatorId, IsDeleted)
|
||||
OUTPUT inserted.Id, inserted.EmployeeId INTO @Created
|
||||
SELECT NEWID(), @TenantId, @PeriodId, u.Id, LEFT(LTRIM(COALESCE(u.Name, N'') + N' ' + COALESCE(u.Surname, N'')), 128), u.DepartmentId, u.JobPositionId, N'GoalSetting', N'GoalSetting', 1, GETUTCDATE(), @ActorId, 0
|
||||
FROM AbpUsers u
|
||||
WHERE u.IsDeleted = 0 AND u.IsActive = 1
|
||||
AND (u.TenantId = @TenantId OR (u.TenantId IS NULL AND @TenantId IS NULL))
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM Hr_T_PerformanceReview rv
|
||||
WHERE rv.PeriodId = @PeriodId AND rv.EmployeeId = u.Id AND rv.IsDeleted = 0);
|
||||
|
||||
-- Dönemin yetkinlik seti eksik olan her değerlendirmeye kopyalanır (sonradan eklenen yetkinlik dahil).
|
||||
INSERT INTO Hr_T_PerformanceCompetency (Id, TenantId, ReviewId, SkillId, ExpectedLevelId, IsActive, CreationTime, CreatorId, IsDeleted)
|
||||
SELECT NEWID(), rv.TenantId, rv.Id, ps.SkillId, ps.ExpectedLevelId, 1, GETUTCDATE(), @ActorId, 0
|
||||
FROM Hr_T_PerformanceReview rv
|
||||
INNER JOIN Hr_T_PerformancePeriodSkill ps ON ps.PeriodId = rv.PeriodId AND ps.IsDeleted = 0 AND ps.IsActive = 1
|
||||
WHERE rv.PeriodId = @PeriodId AND rv.IsDeleted = 0 AND rv.Status <> N'Completed'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM Hr_T_PerformanceCompetency c
|
||||
WHERE c.ReviewId = rv.Id AND c.SkillId = ps.SkillId AND c.IsDeleted = 0);
|
||||
|
||||
DECLARE @ReviewId uniqueidentifier, @EmployeeId uniqueidentifier;
|
||||
DECLARE created CURSOR LOCAL FAST_FORWARD FOR SELECT Id, EmployeeId FROM @Created;
|
||||
OPEN created;
|
||||
FETCH NEXT FROM created INTO @ReviewId, @EmployeeId;
|
||||
WHILE @@FETCH_STATUS = 0
|
||||
BEGIN
|
||||
EXEC dbo.Hr_S_PerformanceNotify @ReviewId, @EmployeeId, N'PerformansDurumDegisti',
|
||||
N'App.Hr.Performance.Notification.Status.Subject', N'App.Hr.Performance.Notification.Status.Message', @ActorId;
|
||||
FETCH NEXT FROM created INTO @ReviewId, @EmployeeId;
|
||||
END
|
||||
CLOSE created;
|
||||
DEALLOCATE created;
|
||||
END
|
||||
GO
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
CREATE OR ALTER PROCEDURE [dbo].[Hr_S_PerformanceReviewAfterSave]
|
||||
@ReviewId uniqueidentifier,
|
||||
@UserId uniqueidentifier,
|
||||
@Actor nvarchar(16)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @Status nvarchar(16), @Last nvarchar(16), @EmployeeId uniqueidentifier, @ManagerId uniqueidentifier, @TenantId uniqueidentifier;
|
||||
|
||||
SELECT @Status = Status, @Last = COALESCE(LastStatus, N'GoalSetting'), @EmployeeId = EmployeeId, @ManagerId = ManagerId, @TenantId = TenantId
|
||||
FROM Hr_T_PerformanceReview
|
||||
WHERE Id = @ReviewId AND IsDeleted = 0;
|
||||
|
||||
IF @Status IS NULL
|
||||
RETURN;
|
||||
|
||||
-- Elle açılan değerlendirmede organizasyon bilgisi çalışandan, yetkinlikler dönemin setinden gelir.
|
||||
-- Ad, pano kartının başlığı olduğu için kayıtta metin olarak tutulur.
|
||||
UPDATE rv
|
||||
SET EmployeeName = LEFT(LTRIM(COALESCE(u.Name, N'') + N' ' + COALESCE(u.Surname, N'')), 128),
|
||||
DepartmentId = COALESCE(rv.DepartmentId, u.DepartmentId),
|
||||
JobPositionId = COALESCE(rv.JobPositionId, u.JobPositionId)
|
||||
FROM Hr_T_PerformanceReview rv
|
||||
INNER JOIN AbpUsers u ON u.Id = rv.EmployeeId
|
||||
WHERE rv.Id = @ReviewId;
|
||||
|
||||
INSERT INTO Hr_T_PerformanceCompetency (Id, TenantId, ReviewId, SkillId, ExpectedLevelId, IsActive, CreationTime, CreatorId, IsDeleted)
|
||||
SELECT NEWID(), rv.TenantId, rv.Id, ps.SkillId, ps.ExpectedLevelId, 1, GETUTCDATE(), @UserId, 0
|
||||
FROM Hr_T_PerformanceReview rv
|
||||
INNER JOIN Hr_T_PerformancePeriodSkill ps ON ps.PeriodId = rv.PeriodId AND ps.IsDeleted = 0 AND ps.IsActive = 1
|
||||
WHERE rv.Id = @ReviewId AND rv.Status <> N'Completed'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM Hr_T_PerformanceCompetency c
|
||||
WHERE c.ReviewId = rv.Id AND c.SkillId = ps.SkillId AND c.IsDeleted = 0);
|
||||
|
||||
IF @Status <> @Last
|
||||
BEGIN
|
||||
-- İK her geçişi yapar; çalışan öz değerlendirmeyi gönderir; yönetici hedefleri onaylar,
|
||||
-- değerlendirmesini kalibrasyona gönderir ya da kaydı bir önceki aşamaya iade eder.
|
||||
DECLARE @Valid bit = CASE
|
||||
WHEN @Actor = N'Hr' THEN 1
|
||||
WHEN @Actor = N'Employee' AND @Last = N'SelfReview' AND @Status = N'ManagerReview' THEN 1
|
||||
WHEN @Actor = N'Manager' AND @Last = N'GoalSetting' AND @Status = N'SelfReview' THEN 1
|
||||
WHEN @Actor = N'Manager' AND @Last = N'SelfReview' AND @Status = N'GoalSetting' THEN 1
|
||||
WHEN @Actor = N'Manager' AND @Last = N'ManagerReview' AND @Status IN (N'SelfReview', N'Calibration') THEN 1
|
||||
ELSE 0
|
||||
END;
|
||||
|
||||
-- Hedef belirleme ancak ağırlıkları toplamı 100 olan en az bir hedefle kapanır.
|
||||
IF @Valid = 1 AND @Last = N'GoalSetting' AND @Status <> N'GoalSetting' AND NOT EXISTS (
|
||||
SELECT 1 FROM Hr_T_PerformanceGoal g
|
||||
WHERE g.ReviewId = @ReviewId AND g.IsDeleted = 0
|
||||
HAVING SUM(g.Weight) = 100)
|
||||
SET @Valid = 0;
|
||||
|
||||
IF @Valid = 0
|
||||
BEGIN
|
||||
UPDATE Hr_T_PerformanceReview SET Status = @Last WHERE Id = @ReviewId;
|
||||
SET @Status = @Last;
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
UPDATE Hr_T_PerformanceReview
|
||||
SET LastStatus = @Status,
|
||||
SelfSubmittedDate = IIF(@Status = N'ManagerReview', GETUTCDATE(), SelfSubmittedDate),
|
||||
ManagerSubmittedDate = IIF(@Status = N'Calibration', GETUTCDATE(), ManagerSubmittedDate),
|
||||
CompletedDate = IIF(@Status = N'Completed', GETUTCDATE(), NULL)
|
||||
WHERE Id = @ReviewId;
|
||||
|
||||
IF @Status IN (N'GoalSetting', N'SelfReview', N'Completed')
|
||||
EXEC dbo.Hr_S_PerformanceNotify @ReviewId, @EmployeeId, N'PerformansDurumDegisti',
|
||||
N'App.Hr.Performance.Notification.Status.Subject', N'App.Hr.Performance.Notification.Status.Message', @UserId;
|
||||
|
||||
IF @Status IN (N'ManagerReview', N'Completed')
|
||||
EXEC dbo.Hr_S_PerformanceNotify @ReviewId, @ManagerId, N'PerformansDurumDegisti',
|
||||
N'App.Hr.Performance.Notification.Status.Subject', N'App.Hr.Performance.Notification.Status.Message', @UserId;
|
||||
|
||||
-- Tamamlanan değerlendirmenin yönetici seviyeleri çalışanın yetkinlik profiline yazılır
|
||||
-- (Progress 0–100 → UserSkill.Level 1–5).
|
||||
IF @Status = N'Completed'
|
||||
BEGIN
|
||||
UPDATE us
|
||||
SET [Level] = x.[Level], Note = LEFT(N'Performans: ' + p.Name, 512),
|
||||
LastModificationTime = GETUTCDATE(), LastModifierId = @UserId
|
||||
FROM Adm_T_UserSkill us
|
||||
INNER JOIN Hr_T_PerformanceCompetency c ON c.SkillId = us.SkillId AND c.ReviewId = @ReviewId AND c.IsDeleted = 0
|
||||
INNER JOIN Hr_T_SkillLevel l ON l.Id = c.ManagerLevelId
|
||||
INNER JOIN Hr_T_PerformanceReview rv ON rv.Id = c.ReviewId
|
||||
INNER JOIN Hr_T_PerformancePeriod p ON p.Id = rv.PeriodId
|
||||
CROSS APPLY (SELECT IIF(l.Progress <= 20, 1, IIF(l.Progress >= 100, 5, CAST(CEILING(l.Progress / 20.0) AS int))) AS [Level]) x
|
||||
WHERE us.UserId = @EmployeeId AND us.IsDeleted = 0
|
||||
AND (us.TenantId = @TenantId OR (us.TenantId IS NULL AND @TenantId IS NULL));
|
||||
|
||||
INSERT INTO Adm_T_UserSkill (Id, TenantId, UserId, SkillId, [Level], Note, CreationTime, CreatorId, IsDeleted)
|
||||
SELECT NEWID(), @TenantId, @EmployeeId, c.SkillId, x.[Level], LEFT(N'Performans: ' + p.Name, 512), GETUTCDATE(), @UserId, 0
|
||||
FROM Hr_T_PerformanceCompetency c
|
||||
INNER JOIN Hr_T_SkillLevel l ON l.Id = c.ManagerLevelId
|
||||
INNER JOIN Hr_T_PerformanceReview rv ON rv.Id = c.ReviewId
|
||||
INNER JOIN Hr_T_PerformancePeriod p ON p.Id = rv.PeriodId
|
||||
CROSS APPLY (SELECT IIF(l.Progress <= 20, 1, IIF(l.Progress >= 100, 5, CAST(CEILING(l.Progress / 20.0) AS int))) AS [Level]) x
|
||||
WHERE c.ReviewId = @ReviewId AND c.IsDeleted = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM Adm_T_UserSkill us
|
||||
WHERE us.UserId = @EmployeeId AND us.SkillId = c.SkillId AND us.IsDeleted = 0
|
||||
AND (us.TenantId = @TenantId OR (us.TenantId IS NULL AND @TenantId IS NULL)));
|
||||
END
|
||||
END
|
||||
END
|
||||
|
||||
EXEC dbo.Hr_S_PerformanceReviewRecalc @ReviewId;
|
||||
END
|
||||
GO
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
CREATE OR ALTER PROCEDURE [dbo].[Hr_S_PerformanceReviewRecalc]
|
||||
@ReviewId uniqueidentifier
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
IF @ReviewId IS NULL
|
||||
RETURN;
|
||||
|
||||
-- Gerçekleşme %: Artan hedefte Gerçekleşen/Hedef, Azalan hedefte Hedef/Gerçekleşen; 0–150'ye kırpılır.
|
||||
-- Azalan hedefte sıfır gerçekleşme hedefin tamamen tutturulduğu anlamına gelir, tavan verilir.
|
||||
UPDATE g
|
||||
SET AchievementRate = CASE
|
||||
WHEN x.Rate IS NULL THEN NULL
|
||||
WHEN x.Rate > 150 THEN 150
|
||||
WHEN x.Rate < 0 THEN 0
|
||||
ELSE x.Rate
|
||||
END
|
||||
FROM Hr_T_PerformanceGoal g
|
||||
CROSS APPLY (SELECT CAST(CASE
|
||||
WHEN g.ActualValue IS NULL THEN NULL
|
||||
WHEN g.Direction = N'Decreasing' AND g.ActualValue <= 0 THEN 150
|
||||
WHEN g.Direction = N'Decreasing' THEN g.TargetValue / g.ActualValue * 100
|
||||
ELSE g.ActualValue / g.TargetValue * 100
|
||||
END AS decimal(18, 2)) AS Rate) x
|
||||
WHERE g.ReviewId = @ReviewId AND g.IsDeleted = 0;
|
||||
|
||||
-- Yetkinlik puanı yöneticinin seçtiği seviyenin Progress değeridir.
|
||||
UPDATE c
|
||||
SET Score = l.Progress
|
||||
FROM Hr_T_PerformanceCompetency c
|
||||
LEFT JOIN Hr_T_SkillLevel l ON l.Id = c.ManagerLevelId AND l.IsDeleted = 0
|
||||
WHERE c.ReviewId = @ReviewId AND c.IsDeleted = 0;
|
||||
|
||||
UPDATE f
|
||||
SET Score = x.Score
|
||||
FROM Hr_T_PerformanceFeedback f
|
||||
OUTER APPLY (
|
||||
SELECT CAST(AVG(CAST(l.Progress AS decimal(9, 2))) AS decimal(6, 2)) AS Score
|
||||
FROM Hr_T_PerformanceFeedbackScore s
|
||||
INNER JOIN Hr_T_SkillLevel l ON l.Id = s.LevelId AND l.IsDeleted = 0
|
||||
WHERE s.FeedbackId = f.Id AND s.IsDeleted = 0) x
|
||||
WHERE f.ReviewId = @ReviewId AND f.IsDeleted = 0;
|
||||
|
||||
UPDATE rv
|
||||
SET GoalScore = gs.Score,
|
||||
CompetencyScore = cs.Score,
|
||||
Feedback360Score = fs.Score,
|
||||
OverallScore = CASE
|
||||
WHEN gs.Score IS NULL AND cs.Score IS NULL THEN NULL
|
||||
ELSE CAST((COALESCE(gs.Score, 0) * p.GoalWeight + COALESCE(cs.Score, 0) * p.CompetencyWeight) / 100 AS decimal(6, 2))
|
||||
END
|
||||
FROM Hr_T_PerformanceReview rv
|
||||
INNER JOIN Hr_T_PerformancePeriod p ON p.Id = rv.PeriodId
|
||||
OUTER APPLY (
|
||||
SELECT CASE WHEN COUNT(*) = 0 THEN NULL
|
||||
ELSE CAST(SUM(COALESCE(g.AchievementRate, 0) * g.Weight) / 100 AS decimal(6, 2)) END AS Score
|
||||
FROM Hr_T_PerformanceGoal g
|
||||
WHERE g.ReviewId = rv.Id AND g.IsDeleted = 0) gs
|
||||
OUTER APPLY (
|
||||
SELECT CAST(AVG(c.Score) AS decimal(6, 2)) AS Score
|
||||
FROM Hr_T_PerformanceCompetency c
|
||||
WHERE c.ReviewId = rv.Id AND c.IsDeleted = 0 AND c.Score IS NOT NULL) cs
|
||||
OUTER APPLY (
|
||||
SELECT CAST(AVG(f.Score) AS decimal(6, 2)) AS Score
|
||||
FROM Hr_T_PerformanceFeedback f
|
||||
WHERE f.ReviewId = rv.Id AND f.IsDeleted = 0 AND f.Status = N'Submitted' AND f.Score IS NOT NULL) fs
|
||||
WHERE rv.Id = @ReviewId;
|
||||
|
||||
-- Derece kalibre puandan, yoksa genel puandan; aralık alt sınırı dahil, üst sınırı hariçtir.
|
||||
UPDATE rv
|
||||
SET RatingId = (
|
||||
SELECT TOP 1 rt.Id
|
||||
FROM Hr_T_PerformanceRating rt
|
||||
WHERE rt.IsDeleted = 0 AND rt.IsActive = 1
|
||||
AND (rt.TenantId = rv.TenantId OR (rt.TenantId IS NULL AND rv.TenantId IS NULL))
|
||||
AND COALESCE(rv.CalibratedScore, rv.OverallScore) >= rt.MinScore
|
||||
AND COALESCE(rv.CalibratedScore, rv.OverallScore) < rt.MaxScore
|
||||
ORDER BY rt.[Level] DESC)
|
||||
FROM Hr_T_PerformanceReview rv
|
||||
WHERE rv.Id = @ReviewId;
|
||||
END
|
||||
GO
|
||||
59
configs/seeds/host/sql/object/Hr_T_DevelopmentPlan.sql
Normal file
59
configs/seeds/host/sql/object/Hr_T_DevelopmentPlan.sql
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_DevelopmentPlan]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_DevelopmentPlan]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[EmployeeId] uniqueidentifier NOT NULL,
|
||||
[ReviewId] uniqueidentifier NULL,
|
||||
[SkillId] uniqueidentifier NULL,
|
||||
[Title] nvarchar(256) NOT NULL,
|
||||
[ActionType] nvarchar(16) NOT NULL DEFAULT 'Training',
|
||||
[TrainingId] uniqueidentifier NULL,
|
||||
[CertificateId] uniqueidentifier NULL,
|
||||
[MentorId] uniqueidentifier NULL,
|
||||
[StartDate] date NULL,
|
||||
[DueDate] date NULL,
|
||||
[Status] nvarchar(16) NOT NULL DEFAULT 'Planned',
|
||||
[Progress] int NOT NULL DEFAULT 0,
|
||||
[Description] nvarchar(1024) NULL,
|
||||
[EmployeeNote] nvarchar(1024) NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_DevelopmentPlan] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_DevelopmentPlan_ActionType]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_DevelopmentPlan] ADD CONSTRAINT [CK_Hr_T_DevelopmentPlan_ActionType] CHECK ([ActionType] IN ('Training', 'Mentoring', 'Project', 'Reading', 'Certificate', 'Other'))
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_DevelopmentPlan_Status]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_DevelopmentPlan] ADD CONSTRAINT [CK_Hr_T_DevelopmentPlan_Status] CHECK ([Status] IN ('Planned', 'InProgress', 'Completed', 'Cancelled'))
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_DevelopmentPlan_Progress]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_DevelopmentPlan] ADD CONSTRAINT [CK_Hr_T_DevelopmentPlan_Progress] CHECK ([Progress] BETWEEN 0 AND 100)
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_DevelopmentPlan_Dates]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_DevelopmentPlan] ADD CONSTRAINT [CK_Hr_T_DevelopmentPlan_Dates] CHECK ([DueDate] IS NULL OR [StartDate] IS NULL OR [DueDate] >= [StartDate])
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Hr_T_DevelopmentPlan_Employee' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_DevelopmentPlan]'))
|
||||
CREATE NONCLUSTERED INDEX [IX_Hr_T_DevelopmentPlan_Employee] ON [dbo].[Hr_T_DevelopmentPlan] ([EmployeeId])
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Hr_T_DevelopmentPlan_Review' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_DevelopmentPlan]'))
|
||||
CREATE NONCLUSTERED INDEX [IX_Hr_T_DevelopmentPlan_Review] ON [dbo].[Hr_T_DevelopmentPlan] ([ReviewId])
|
||||
GO
|
||||
33
configs/seeds/host/sql/object/Hr_T_PerformanceCompetency.sql
Normal file
33
configs/seeds/host/sql/object/Hr_T_PerformanceCompetency.sql
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformanceCompetency]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformanceCompetency]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[ReviewId] uniqueidentifier NOT NULL,
|
||||
[SkillId] uniqueidentifier NOT NULL,
|
||||
[ExpectedLevelId] uniqueidentifier NULL,
|
||||
[SelfLevelId] uniqueidentifier NULL,
|
||||
[ManagerLevelId] uniqueidentifier NULL,
|
||||
[Score] decimal(6, 2) NULL,
|
||||
[SelfComment] nvarchar(1024) NULL,
|
||||
[ManagerComment] nvarchar(1024) NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformanceCompetency] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_Hr_T_PerformanceCompetency_Skill' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceCompetency]'))
|
||||
CREATE UNIQUE NONCLUSTERED INDEX [UX_Hr_T_PerformanceCompetency_Skill] ON [dbo].[Hr_T_PerformanceCompetency] ([ReviewId], [SkillId]) WHERE [IsDeleted] = 0
|
||||
GO
|
||||
44
configs/seeds/host/sql/object/Hr_T_PerformanceFeedback.sql
Normal file
44
configs/seeds/host/sql/object/Hr_T_PerformanceFeedback.sql
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformanceFeedback]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformanceFeedback]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[ReviewId] uniqueidentifier NOT NULL,
|
||||
[ReviewerId] uniqueidentifier NOT NULL,
|
||||
[Relation] nvarchar(16) NOT NULL DEFAULT 'Peer',
|
||||
[Status] nvarchar(16) NOT NULL DEFAULT 'Pending',
|
||||
[Score] decimal(6, 2) NULL,
|
||||
[Comment] nvarchar(2048) NULL,
|
||||
[SubmittedDate] datetime2 NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformanceFeedback] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceFeedback_Relation]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceFeedback] ADD CONSTRAINT [CK_Hr_T_PerformanceFeedback_Relation] CHECK ([Relation] IN ('Peer', 'Subordinate', 'Superior', 'InternalCustomer'))
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceFeedback_Status]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceFeedback] ADD CONSTRAINT [CK_Hr_T_PerformanceFeedback_Status] CHECK ([Status] IN ('Pending', 'Submitted'))
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_Hr_T_PerformanceFeedback_Reviewer' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceFeedback]'))
|
||||
CREATE UNIQUE NONCLUSTERED INDEX [UX_Hr_T_PerformanceFeedback_Reviewer] ON [dbo].[Hr_T_PerformanceFeedback] ([ReviewId], [ReviewerId]) WHERE [IsDeleted] = 0
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Hr_T_PerformanceFeedback_ReviewerId' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceFeedback]'))
|
||||
CREATE NONCLUSTERED INDEX [IX_Hr_T_PerformanceFeedback_ReviewerId] ON [dbo].[Hr_T_PerformanceFeedback] ([ReviewerId])
|
||||
GO
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformanceFeedbackScore]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformanceFeedbackScore]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[FeedbackId] uniqueidentifier NOT NULL,
|
||||
[SkillId] uniqueidentifier NOT NULL,
|
||||
[LevelId] uniqueidentifier NULL,
|
||||
[Comment] nvarchar(1024) NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformanceFeedbackScore] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_Hr_T_PerformanceFeedbackScore_Skill' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceFeedbackScore]'))
|
||||
CREATE UNIQUE NONCLUSTERED INDEX [UX_Hr_T_PerformanceFeedbackScore_Skill] ON [dbo].[Hr_T_PerformanceFeedbackScore] ([FeedbackId], [SkillId]) WHERE [IsDeleted] = 0
|
||||
GO
|
||||
53
configs/seeds/host/sql/object/Hr_T_PerformanceGoal.sql
Normal file
53
configs/seeds/host/sql/object/Hr_T_PerformanceGoal.sql
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformanceGoal]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformanceGoal]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[ReviewId] uniqueidentifier NOT NULL,
|
||||
[GoalType] nvarchar(8) NOT NULL DEFAULT 'KPI',
|
||||
[Title] nvarchar(256) NOT NULL,
|
||||
[Description] nvarchar(1024) NULL,
|
||||
[Direction] nvarchar(16) NOT NULL DEFAULT 'Increasing',
|
||||
[Unit] nvarchar(32) NULL,
|
||||
[TargetValue] decimal(18, 2) NOT NULL,
|
||||
[ActualValue] decimal(18, 2) NULL,
|
||||
[Weight] decimal(5, 2) NOT NULL,
|
||||
[AchievementRate] decimal(6, 2) NULL,
|
||||
[SelfComment] nvarchar(1024) NULL,
|
||||
[ManagerComment] nvarchar(1024) NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformanceGoal] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceGoal_GoalType]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceGoal] ADD CONSTRAINT [CK_Hr_T_PerformanceGoal_GoalType] CHECK ([GoalType] IN ('KPI', 'OKR'))
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceGoal_Direction]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceGoal] ADD CONSTRAINT [CK_Hr_T_PerformanceGoal_Direction] CHECK ([Direction] IN ('Increasing', 'Decreasing'))
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceGoal_Weight]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceGoal] ADD CONSTRAINT [CK_Hr_T_PerformanceGoal_Weight] CHECK ([Weight] > 0 AND [Weight] <= 100)
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceGoal_TargetValue]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceGoal] ADD CONSTRAINT [CK_Hr_T_PerformanceGoal_TargetValue] CHECK ([TargetValue] > 0)
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Hr_T_PerformanceGoal_Review' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceGoal]'))
|
||||
CREATE NONCLUSTERED INDEX [IX_Hr_T_PerformanceGoal_Review] ON [dbo].[Hr_T_PerformanceGoal] ([ReviewId])
|
||||
GO
|
||||
43
configs/seeds/host/sql/object/Hr_T_PerformancePeriod.sql
Normal file
43
configs/seeds/host/sql/object/Hr_T_PerformancePeriod.sql
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformancePeriod]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformancePeriod]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[Name] nvarchar(128) NOT NULL,
|
||||
[StartDate] date NOT NULL,
|
||||
[EndDate] date NOT NULL,
|
||||
[SelfReviewDueDate] date NULL,
|
||||
[ManagerReviewDueDate] date NULL,
|
||||
[GoalWeight] decimal(5, 2) NOT NULL DEFAULT 60,
|
||||
[CompetencyWeight] decimal(5, 2) NOT NULL DEFAULT 40,
|
||||
[Is360Enabled] bit NOT NULL DEFAULT 0,
|
||||
[Status] nvarchar(16) NOT NULL DEFAULT 'Planned',
|
||||
[Description] nvarchar(1024) NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformancePeriod] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformancePeriod_Dates]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformancePeriod] ADD CONSTRAINT [CK_Hr_T_PerformancePeriod_Dates] CHECK ([EndDate] >= [StartDate])
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformancePeriod_Weights]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformancePeriod] ADD CONSTRAINT [CK_Hr_T_PerformancePeriod_Weights] CHECK ([GoalWeight] >= 0 AND [CompetencyWeight] >= 0 AND [GoalWeight] + [CompetencyWeight] = 100)
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformancePeriod_Status]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformancePeriod] ADD CONSTRAINT [CK_Hr_T_PerformancePeriod_Status] CHECK ([Status] IN ('Planned', 'Active', 'Calibration', 'Closed'))
|
||||
GO
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformancePeriodSkill]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformancePeriodSkill]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[PeriodId] uniqueidentifier NOT NULL,
|
||||
[SkillId] uniqueidentifier NOT NULL,
|
||||
[ExpectedLevelId] uniqueidentifier NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformancePeriodSkill] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_Hr_T_PerformancePeriodSkill_Skill' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformancePeriodSkill]'))
|
||||
CREATE UNIQUE NONCLUSTERED INDEX [UX_Hr_T_PerformancePeriodSkill_Skill] ON [dbo].[Hr_T_PerformancePeriodSkill] ([PeriodId], [SkillId]) WHERE [IsDeleted] = 0
|
||||
GO
|
||||
40
configs/seeds/host/sql/object/Hr_T_PerformanceRating.sql
Normal file
40
configs/seeds/host/sql/object/Hr_T_PerformanceRating.sql
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformanceRating]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformanceRating]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[Name] nvarchar(128) NOT NULL,
|
||||
[Level] int NOT NULL,
|
||||
[MinScore] decimal(6, 2) NOT NULL,
|
||||
[MaxScore] decimal(6, 2) NOT NULL,
|
||||
[Color] nvarchar(16) NULL,
|
||||
[TargetDistribution] decimal(5, 2) NULL,
|
||||
[Description] nvarchar(512) NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformanceRating] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceRating_Range]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceRating] ADD CONSTRAINT [CK_Hr_T_PerformanceRating_Range] CHECK ([MinScore] < [MaxScore])
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceRating_TargetDistribution]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceRating] ADD CONSTRAINT [CK_Hr_T_PerformanceRating_TargetDistribution] CHECK ([TargetDistribution] IS NULL OR [TargetDistribution] BETWEEN 0 AND 100)
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_Hr_T_PerformanceRating_Level' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceRating]'))
|
||||
CREATE UNIQUE NONCLUSTERED INDEX [UX_Hr_T_PerformanceRating_Level] ON [dbo].[Hr_T_PerformanceRating] ([TenantId], [Level]) WHERE [IsDeleted] = 0
|
||||
GO
|
||||
57
configs/seeds/host/sql/object/Hr_T_PerformanceReview.sql
Normal file
57
configs/seeds/host/sql/object/Hr_T_PerformanceReview.sql
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
IF OBJECT_ID(N'[dbo].[Hr_T_PerformanceReview]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Hr_T_PerformanceReview]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[PeriodId] uniqueidentifier NOT NULL,
|
||||
[EmployeeId] uniqueidentifier NOT NULL,
|
||||
[EmployeeName] nvarchar(128) NULL,
|
||||
[ManagerId] uniqueidentifier NULL,
|
||||
[DepartmentId] uniqueidentifier NULL,
|
||||
[JobPositionId] uniqueidentifier NULL,
|
||||
[Status] nvarchar(16) NOT NULL DEFAULT 'GoalSetting',
|
||||
[LastStatus] nvarchar(16) NULL,
|
||||
[GoalScore] decimal(6, 2) NULL,
|
||||
[CompetencyScore] decimal(6, 2) NULL,
|
||||
[Feedback360Score] decimal(6, 2) NULL,
|
||||
[OverallScore] decimal(6, 2) NULL,
|
||||
[CalibratedScore] decimal(6, 2) NULL,
|
||||
[RatingId] uniqueidentifier NULL,
|
||||
[SelfComment] nvarchar(2048) NULL,
|
||||
[ManagerComment] nvarchar(2048) NULL,
|
||||
[CalibrationNote] nvarchar(1024) NULL,
|
||||
[SelfSubmittedDate] datetime2 NULL,
|
||||
[ManagerSubmittedDate] datetime2 NULL,
|
||||
[CompletedDate] datetime2 NULL,
|
||||
[IsActive] bit NOT NULL DEFAULT 1,
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Hr_T_PerformanceReview] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceReview_Status]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceReview] ADD CONSTRAINT [CK_Hr_T_PerformanceReview_Status] CHECK ([Status] IN ('GoalSetting', 'SelfReview', 'ManagerReview', 'Calibration', 'Completed'))
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[CK_Hr_T_PerformanceReview_CalibratedScore]', 'C') IS NULL
|
||||
ALTER TABLE [dbo].[Hr_T_PerformanceReview] ADD CONSTRAINT [CK_Hr_T_PerformanceReview_CalibratedScore] CHECK ([CalibratedScore] IS NULL OR [CalibratedScore] BETWEEN 0 AND 150)
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_Hr_T_PerformanceReview_Employee' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceReview]'))
|
||||
CREATE UNIQUE NONCLUSTERED INDEX [UX_Hr_T_PerformanceReview_Employee] ON [dbo].[Hr_T_PerformanceReview] ([PeriodId], [EmployeeId]) WHERE [IsDeleted] = 0
|
||||
GO
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Hr_T_PerformanceReview_Manager' AND object_id = OBJECT_ID(N'[dbo].[Hr_T_PerformanceReview]'))
|
||||
CREATE NONCLUSTERED INDEX [IX_Hr_T_PerformanceReview_Manager] ON [dbo].[Hr_T_PerformanceReview] ([ManagerId])
|
||||
GO
|
||||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Yan Hak Türleri",
|
||||
"TitleEn": "Fringe Benefit Types",
|
||||
"TitleTr": "Yan Hak Türleri",
|
||||
"DescEn": "Fringe benefit type definitions",
|
||||
"DescTr": "Yan hak türü tanımları"
|
||||
"DescEn": "Benefit Types — fringe benefits provided to employees (meal card, transport, private health insurance, pension, housing, company car, phone, child and heating allowance…).\nWhere: Human Resources › Definitions › Benefit Types.\nFields: code (stored value), name, default amount, currency, income-taxable, social-security subject, active.\nUsed by: Recruitment › Job Offers (benefits) and Identity › Users › detail › Financial › Benefits.",
|
||||
"DescTr": "Yan Hak Türleri — çalışanlara sağlanan yan haklar (yemek kartı, ulaşım, özel sağlık sigortası, BES, konut, şirket aracı, telefon, çocuk ve yakacak yardımı…).\nNerede: İnsan Kaynakları › Tanımlamalar › Yan Hak Türleri.\nAlanlar: kod (kayıtlarda saklanan değer), ad, varsayılan tutar, para birimi, gelir vergisine tabi, SGK'ya tabi, aktif.\nKullanıldığı yerler: İşe Alım › Teklifler (yan haklar) ve Kimlik › Kullanıcılar › detay › Finansal › Yan Haklar."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Adaylar",
|
||||
"TitleEn": "Candidates",
|
||||
"TitleTr": "Adaylar",
|
||||
"DescEn": "Candidate pool with CV and KVKK explicit consent",
|
||||
"DescTr": "CV ve KVKK açık rızası ile aday havuzu",
|
||||
"DescEn": "Candidates — candidate pool kept with CV and explicit KVKK (GDPR) consent. One candidate may apply to several postings.\nWhere: Human Resources › Recruitment › Candidates. The Applications tab lists all applications of the candidate; the row button prints the KVKK consent form.\nFields:\n• Personal data, photo, country → city, address\n• Education, years of experience, current company and title, salary expectation\n• SourceId → channel the candidate came from; SkillIds → skills (Skill Types dictionary)\n• CvDocument → CV file (PDF/DOC accepted)\n• KVKK → consent is mandatory (also enforced by the table); date, method and signed document are stored\n• UserId → employee user opened by IT after hiring; HR links it here\nRule: e-mail is unique within the tenant.\nWidgets: total, active, passive and converted-to-employee candidates.",
|
||||
"DescTr": "Adaylar — CV ve KVKK açık rızası ile tutulan aday havuzu. Bir aday birden fazla ilana başvurabilir.\nNerede: İnsan Kaynakları › İşe Alım › Adaylar. Detaydaki Başvurular sekmesi adayın bütün başvurularını gösterir; satırdaki KVKK Açık Rıza Formu butonu formu yazdırır.\nAlanlar:\n• Kişisel bilgiler, fotoğraf, ülke → şehir, adres\n• Eğitim (düzey, okul, bölüm, mezuniyet yılı), deneyim yılı, mevcut firma ve unvan, ücret beklentisi\n• SourceId → adayın geldiği kanal; SkillIds → yetkinlikleri (Yetenek Tipleri sözlüğü)\n• CvDocument → CV dosyası (PDF/DOC kabul edilir, tıklanınca açılır)\n• KVKK → rıza zorunludur (tablo da zorlar); rıza tarihi, yöntemi ve imzalı belge saklanır\n• UserId → işe alındıktan sonra BT'nin açtığı personel kullanıcısı; İK bu alanla bağlar\nKural: e-posta kiracı içinde tekildir.\nWidget'lar: toplam, aktif, pasif ve personele dönüşen aday sayısı.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.Candidate.Education.Primary",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Aday Kaynakları",
|
||||
"TitleEn": "Candidate Sources",
|
||||
"TitleTr": "Aday Kaynakları",
|
||||
"DescEn": "Channels candidates come from (job boards, referral, career fair)",
|
||||
"DescTr": "Adayların geldiği kanallar (ilan siteleri, referans, kariyer fuarı)"
|
||||
"DescEn": "Candidate Sources — channels candidates come from and postings are published on (LinkedIn, job boards, referral, career fair…).\nWhere: Human Resources › Definitions › Candidate Sources.\nUsed by: Candidates (source), Applications (source, copied from the candidate), Job Postings (publishing channels).\nNote: a passive source cannot be selected on new records; existing values are kept. Records are mirrored to the seed file.",
|
||||
"DescTr": "Aday Kaynakları — adayların ve ilanların hangi kanaldan geldiğini/yayınlandığını tanımlayan liste (LinkedIn, Kariyer.net, referans, kariyer fuarı…).\nNerede: İnsan Kaynakları › Tanımlamalar › Aday Kaynakları.\nKullanıldığı yerler: Adaylar (adayın kaynağı), Başvurular (kaynak, adaydan kopyalanır), İlanlar (yayın kanalları, çoklu seçim).\nDikkat: pasif yapılan kaynak yeni kayıtta seçilemez, eski kayıtlarda değer korunur. Kayıtlar seed dosyasına da yazılır."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Yeterlilik Belgeleri",
|
||||
"TitleEn": "Qualification Certificates",
|
||||
"TitleTr": "Yeterlilik Belgeleri",
|
||||
"DescEn": "Qualification certificate definitions",
|
||||
"DescTr": "Yeterlilik belgesi tanımları"
|
||||
"DescEn": "Qualification Certificates — vocational qualification and graduation certificates employees may hold.\nWhere: Human Resources › Definitions › Qualification Certificates.\nFields: name, active.\nUsed by: Identity › Users › detail › Education & Skills › Certificates and certificate actions in Performance Management development plans.",
|
||||
"DescTr": "Yeterlilik Belgeleri — personelin sahip olabileceği mesleki yeterlilik ve mezuniyet belgeleri.\nNerede: İnsan Kaynakları › Tanımlamalar › Yeterlilik Belgeleri.\nAlanlar: belge adı, aktif.\nKullanıldığı yerler: Kimlik › Kullanıcılar › detay › Eğitim ve Yetenekler › Yeterlilik Belgeleri ve Performans Yönetimi gelişim aksiyonlarında sertifika hedefi."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
3049
configs/seeds/host/wizard/DevelopmentPlan.json
Normal file
3049
configs/seeds/host/wizard/DevelopmentPlan.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -24,8 +24,8 @@
|
|||
"MenuTr": "Disiplin Dosyaları",
|
||||
"TitleEn": "Disciplinary Cases",
|
||||
"TitleTr": "Disiplin Dosyaları",
|
||||
"DescEn": "Incident reports with defense requests, decisions and documents",
|
||||
"DescTr": "Savunma talebi, karar ve belgeleriyle olay tutanakları",
|
||||
"DescEn": "Disciplinary Cases — the disciplinary process of an employee starting with an incident report: defense, decision and documents in one file.\nWhere: Human Resources › Disciplinary Cases. The detail has Defenses, Decisions and Documents tabs; the Todo view groups cases by status.\nFields:\n• CaseNo → DSP-YYYY-00001, automatic\n• Employee → department and position are copied\n• Incident date/time/place, reporter (defaults to the creator), witnesses (multiple users)\n• Subject and incident report (HTML)\n• Status → Open / Awaiting defense / Decided / Closed; changed manually\nNote: disciplinary data is sensitive personal data; grant this screen to HR only. Entering a defense or decision does not change the status by itself.",
|
||||
"DescTr": "Disiplin Dosyaları — bir personel hakkındaki olay tutanağı ile başlayan disiplin süreci: savunma, karar ve belgeler tek dosyada.\nNerede: İnsan Kaynakları › Disiplin Dosyaları. Detayda Savunmalar, Kararlar ve Belgeler sekmeleri vardır; Todo görünümünde dosyalar duruma göre sütunlardadır.\nAlanlar:\n• CaseNo → DSP-YYYY-00001, otomatik\n• Personel → seçilince departman ve pozisyon kopyalanır\n• Olay tarihi/saati/yeri, tutanağı tutan (varsayılan kaydı açan), tanıklar (çoklu kullanıcı)\n• Konu ve olay tutanağı (HTML)\n• Status → Açık / Savunma Bekleniyor / Karara Bağlandı / Kapandı; elle değiştirilir\nDikkat: disiplin verisi hassas kişisel veridir; ekran yetkisi yalnız İK'ya verilmelidir. Savunma ya da karar girilmesi durumu kendiliğinden değiştirmez.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.DisciplinaryCase.Widget.Open",
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Kararlar",
|
||||
"TitleEn": "Decisions",
|
||||
"TitleTr": "Kararlar",
|
||||
"DescEn": "Decisions taken for the disciplinary case",
|
||||
"DescTr": "Disiplin dosyası için verilen kararlar",
|
||||
"DescEn": "Decisions — the decision and penalty for a disciplinary case.\nWhere: the Decisions tab of a Disciplinary Case.\nFields: decision date (today), penalty type (Penalty Types, ordered by severity), effective and notification dates, deduction amount, status (Draft / Final), decision text.\nNote: the deduction is informational and is not sent to payroll.",
|
||||
"DescTr": "Kararlar — disiplin dosyası için verilen karar ve ceza.\nNerede: Disiplin Dosyaları ekranında kaydın Kararlar sekmesi.\nAlanlar: karar tarihi (bugün), ceza türü (Ceza Türleri, ağırlık sırasıyla), yürürlük ve tebliğ tarihi, kesinti tutarı, durum (Taslak / Kesinleşti), karar metni.\nDikkat: kesinti tutarı bilgi amaçlıdır, bordroya aktarılmaz.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.DisciplinaryDecision.Status.Draft",
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Savunmalar",
|
||||
"TitleEn": "Defense Requests",
|
||||
"TitleTr": "Savunmalar",
|
||||
"DescEn": "Defense requests and responses of the disciplinary case",
|
||||
"DescTr": "Disiplin dosyasına ait savunma talepleri ve cevapları",
|
||||
"DescEn": "Defenses — the defense requested from the employee for a disciplinary case and the answer.\nWhere: the Defenses tab of a Disciplinary Case.\nFields: request date (today), defense due date (request + 2 days suggested; cannot be earlier), response date, status (Requested / Submitted / Not submitted), defense text.",
|
||||
"DescTr": "Savunmalar — disiplin dosyası için personelden istenen savunma ve verilen cevap.\nNerede: Disiplin Dosyaları ekranında kaydın Savunmalar sekmesi.\nAlanlar: talep tarihi (varsayılan bugün), son savunma tarihi (talep + 2 gün önerilir; talepten önce olamaz), savunma tarihi, durum (Talep Edildi / Savunma Verildi / Savunma Verilmedi), savunma metni.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.DisciplinaryDefense.Status.Requested",
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Belgeler",
|
||||
"TitleEn": "Documents",
|
||||
"TitleTr": "Belgeler",
|
||||
"DescEn": "Documents of the disciplinary case",
|
||||
"DescTr": "Disiplin dosyasına ait belgeler"
|
||||
"DescEn": "Disciplinary Documents — signed report, defense, notification and other documents of a case.\nWhere: the Documents tab of a Disciplinary Case.\nFields: document type (Document Types), date (today), file name, file.",
|
||||
"DescTr": "Disiplin Belgeleri — dosyaya ait imzalı tutanak, savunma, tebliğ gibi belgeler.\nNerede: Disiplin Dosyaları ekranında kaydın Belgeler sekmesi.\nAlanlar: belge türü (Evrak Türleri), tarih (bugün), dosya adı, dosya."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"ComponentKind": 0,
|
||||
"WizardName": "DisciplinaryPenaltyType",
|
||||
"WizardCode": "App.Hr.DisciplinaryPenaltyType",
|
||||
"SeededAt": "2026-10-03T10:00:00.0000000+03:00",
|
||||
"SeededAt": "2026-10-03T10:00:00+03:00",
|
||||
"CustomComponentName": null,
|
||||
"PermissionGroupName": "App.Hr",
|
||||
"ModuleId": "Hr",
|
||||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Ceza Türleri",
|
||||
"TitleEn": "Penalty Types",
|
||||
"TitleTr": "Ceza Türleri",
|
||||
"DescEn": "Disciplinary penalty type definitions",
|
||||
"DescTr": "Disiplin cezası türü tanımları"
|
||||
"DescEn": "Penalty Types — penalties that may be given in disciplinary decisions and their severity.\nWhere: Human Resources › Definitions › Penalty Types.\nFields: name, Severity (defines the order), description, active.\nUsed by: Disciplinary Cases › Decisions.",
|
||||
"DescTr": "Ceza Türleri — disiplin kararlarında verilebilecek cezalar ve ağırlıkları (sözlü uyarı, yazılı uyarı, ihtar, kınama, ücret kesintisi, fesih).\nNerede: İnsan Kaynakları › Tanımlamalar › Ceza Türleri.\nAlanlar: ad, Severity (ağırlık; listede sıralamayı belirler), açıklama, aktif.\nKullanıldığı yer: Disiplin Dosyaları › Kararlar sekmesi."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Kurum Doktorları",
|
||||
"TitleEn": "Company Doctors",
|
||||
"TitleTr": "Kurum Doktorları",
|
||||
"DescEn": "Company doctor definitions",
|
||||
"DescTr": "Kurum doktoru tanımları"
|
||||
"DescEn": "Company Doctors — workplace doctors and their certificates.\nWhere: Human Resources › Definitions › Company Doctors.\nFields: full name, diploma no and date, workplace doctor certificate no and date, identity no, active.\nUsed by: doctor selection in Health Cards › Periodic Examinations, Patient Protocol and Result.",
|
||||
"DescTr": "Kurum Doktorları — işyeri hekimleri ve belge bilgileri.\nNerede: İnsan Kaynakları › Tanımlamalar › Kurum Doktorları.\nAlanlar: ad soyad, diploma no ve tarihi, işyeri hekimi belge no ve tarihi, T.C. kimlik no, aktif.\nKullanıldığı yerler: Sağlık Kartları › Periyodik Muayeneler, Hasta Protokol Defteri ve Sonuç sekmelerindeki hekim seçimi."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Evrak Türleri",
|
||||
"TitleEn": "Document Types",
|
||||
"TitleTr": "Evrak Türleri",
|
||||
"DescEn": "Personnel file document type definitions",
|
||||
"DescTr": "Personel özlük dosyası evrak türü tanımları",
|
||||
"DescEn": "Document Types — types of personnel and process documents (CV, petition, release, health report…) with groups.\nWhere: Human Resources › Definitions › Document Types.\nFields: group (General, Personnel file, Health), name, required, active.\nUsed by: document type selection in Trainings › Files and Disciplinary Cases › Documents.",
|
||||
"DescTr": "Evrak Türleri — personel ve süreç belgelerinin türleri (CV, dilekçe, ibraname, sağlık raporu…), gruplarıyla.\nNerede: İnsan Kaynakları › Tanımlamalar › Evrak Türleri.\nAlanlar: dosya grubu (Genel, Özlük Evrakları, Sağlık), tür adı, zorunlu, aktif.\nKullanıldığı yerler: Eğitimler › Dosyalar ve Disiplin Dosyaları › Belgeler sekmelerinde belge türü seçimi.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.DocumentType.Group.General",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Şoför Tanımlama",
|
||||
"TitleEn": "Drivers",
|
||||
"TitleTr": "Şoför Tanımlama",
|
||||
"DescEn": "Users who drive company vehicles",
|
||||
"DescTr": "Şirket araçlarını kullanan kullanıcılar",
|
||||
"DescEn": "Drivers — employees using company vehicles, their assigned vehicles and driving history.\nWhere: Human Resources › Vehicles › Drivers. The detail has Documents, Penalties and Accidents tabs.\nFields:\n• UserId → registration no / name\n• Vehicle1Id … Vehicle5Id → up to five assigned vehicles\n• TotalKm → sum of travelled km of all movements by the person (automatic from the gate log)\nWidgets: total drivers, drivers with vehicles, total km.",
|
||||
"DescTr": "Şoför Tanımlama — şirket araçlarını kullanan personel, zimmetli araçları ve sürüş geçmişi.\nNerede: İnsan Kaynakları › Araçlar › Şoför Tanımlama. Detayda Belgeler, Cezalar ve Kazalar sekmeleri vardır.\nAlanlar:\n• UserId → sicil no / ad soyad\n• Vehicle1Id … Vehicle5Id → en fazla beş zimmetli araç\n• TotalKm → kişinin kullandığı bütün hareketlerin yapılan km toplamı (giriş-çıkış kayıtlarından otomatik)\nWidget'lar: toplam şoför, araç zimmetli şoför, toplam km.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.Driver.Widget.WithVehicle",
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Kaza Belgeleri",
|
||||
"TitleEn": "Accident Documents",
|
||||
"TitleTr": "Kaza Belgeleri",
|
||||
"DescEn": "Traffic accidents of the driver",
|
||||
"DescTr": "Şoförün trafik kazaları"
|
||||
"DescEn": "Driver Accidents — traffic accidents involving the driver and their documents.\nWhere: the Accidents tab of a Driver record.\nFields: date, document type (Accident definitions), description, file (report, appraisal).",
|
||||
"DescTr": "Şoför Kazaları — şoförün karıştığı trafik kazaları ve belgeleri.\nNerede: Şoför Tanımlama ekranında kaydın Kazalar sekmesi.\nAlanlar: kaza tarihi, belge türü (Kaza tipindeki tanımlar), açıklama, dosya (tutanak, ekspertiz)."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Şoför Belgeleri",
|
||||
"TitleEn": "Driver Documents",
|
||||
"TitleTr": "Şoför Belgeleri",
|
||||
"DescEn": "Documents uploaded for the driver",
|
||||
"DescTr": "Şoföre yüklenen belgeler"
|
||||
"DescEn": "Driver Documents — documents of a driver (licence, psychotechnical report, SRC…).\nWhere: the Documents tab of a Driver record.\nFields: document (Driver-group definitions except penalty and accident), file name, file.",
|
||||
"DescTr": "Şoför Belgeleri — şoföre ait belgeler (sürücü belgesi, psikoteknik, SRC…).\nNerede: Şoför Tanımlama ekranında kaydın Belgeler sekmesi.\nAlanlar: belge adı (Şoför grubundaki tanımlar; ceza ve kaza hariç), dosya adı, dosya."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Ceza Belgeleri",
|
||||
"TitleEn": "Penalty Documents",
|
||||
"TitleTr": "Ceza Belgeleri",
|
||||
"DescEn": "Traffic penalties of the driver",
|
||||
"DescTr": "Şoförün trafik cezaları"
|
||||
"DescEn": "Driver Penalties — traffic fines of a driver.\nWhere: the Penalties tab of a Driver record.\nFields: date, amount, description, document type (Penalty definitions), file.\nUse: penalty analysis by driver and period with Pivot/Chart; the cost can also be entered as a vehicle expense.",
|
||||
"DescTr": "Şoför Cezaları — şoföre kesilen trafik cezaları.\nNerede: Şoför Tanımlama ekranında kaydın Cezalar sekmesi.\nAlanlar: ceza tarihi, tutar, açıklama, belge türü (Ceza tipindeki tanımlar), dosya.\nKullanım: Pivot/Chart ile şoför ve dönem bazında ceza analizi yapılır; ceza masrafı ayrıca Masraf Girişleri'ne işlenebilir."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Değerlendirme Kriterleri",
|
||||
"TitleEn": "Evaluation Criteria",
|
||||
"TitleTr": "Değerlendirme Kriterleri",
|
||||
"DescEn": "Interview scoring criteria and their weights",
|
||||
"DescTr": "Mülakat puanlama kriterleri ve ağırlıkları"
|
||||
"DescEn": "Evaluation Criteria — criteria scored in interviews and their weights.\nWhere: Human Resources › Definitions › Evaluation Criteria.\nFields: name, Weight (default 1), description, active.\nUsed by: Interviews › Scores. Interview overall score = Σ(score × weight) / Σ weight.",
|
||||
"DescTr": "Değerlendirme Kriterleri — mülakatlarda puanlanan kriterler ve ağırlıkları (iletişim, teknik yetkinlik, problem çözme…).\nNerede: İnsan Kaynakları › Tanımlamalar › Değerlendirme Kriterleri.\nAlanlar: ad, Weight (ağırlık; varsayılan 1), açıklama, aktif.\nKullanıldığı yer: Mülakatlar › Puanlar sekmesi. Mülakat genel puanı = Σ(puan × ağırlık) / Σ ağırlık; ağırlığı yüksek kriter sonucu daha çok etkiler."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
"MenuTr": "Olay Günlüğü",
|
||||
"TitleEn": "Event Log",
|
||||
"TitleTr": "Olay Günlüğü",
|
||||
"DescEn": "Important events recorded by shift supervisors, security and observation rooms",
|
||||
"DescTr": "Vardiya amiri, güvenlik ve gözlem odasının kaydettiği önemli olaylar",
|
||||
"DescEn": "Event Log — important events recorded during shifts by the shift supervisor, security room and observation room.\nWhere: Human Resources › Event Log.\nFields: source (Shift supervisor, Security room, Observation room), branch, employee involved/recorder, date and time (now on new), importance (1 Routine … 5 Critical), shift, description.\nUse: importance 4+ counts as Important; a disciplinary case can be opened manually (no automatic link).\nWidgets: total, today and important events.",
|
||||
"DescTr": "Olay Günlüğü — vardiya amiri, güvenlik odası ve gözlem odasının vardiya sırasında kaydettiği önemli olaylar.\nNerede: İnsan Kaynakları › Olay Günlüğü.\nAlanlar: kaynak (Vardiya Amiri, Güvenlik Odası, Gözlem Odası), şube, olayı yaşayan / kaydeden personel, olay tarihi ve saati (yeni kayıtta şimdi), önem (1 Rutin … 5 Kritik), vardiya, açıklama.\nKullanım: önem 4 ve üzeri kayıtlar Önemli kartında sayılır; gerekirse Disiplin Dosyaları'nda elle dosya açılır (otomatik bağ yoktur).\nWidget'lar: toplam, bugün ve önemli olaylar.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.EventLog.Widget.Important",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Masraf Türleri",
|
||||
"TitleEn": "Expense Types",
|
||||
"TitleTr": "Masraf Türleri",
|
||||
"DescEn": "Expense type definitions",
|
||||
"DescTr": "Masraf türü tanımları"
|
||||
"DescEn": "Expense Types — personnel expense items (meal, travel, accommodation, fuel, phone, hospitality, office) and their tax/social security attributes.\nWhere: Human Resources › Definitions › Expense Types.\nFields: code, name, default amount, currency, income-taxable, social-security subject, receipt required, active.\nNote: not yet linked to an expense request screen.",
|
||||
"DescTr": "Masraf Türleri — personel masraf kalemleri (yemek, yol, konaklama, akaryakıt, telefon, temsil, kırtasiye) ve vergi/SGK özellikleri.\nNerede: İnsan Kaynakları › Tanımlamalar › Masraf Türleri.\nAlanlar: kod, ad, varsayılan tutar, para birimi, gelir vergisine tabi, SGK'ya tabi, fiş/belge gerekir, aktif.\nDikkat: henüz bir masraf talep ekranına bağlı değildir."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
"MenuTr": "Sağlık Kartları",
|
||||
"TitleEn": "Health Cards",
|
||||
"TitleTr": "Sağlık Kartları",
|
||||
"DescEn": "Employee health cards",
|
||||
"DescTr": "Çalışan sağlık kartları"
|
||||
"DescEn": "Health Cards — occupational health card of every employee. The list is all users of the tenant; card data is entered in the detail tabs.\nWhere: Human Resources › Health Cards. The same data is also edited in Identity › Users › detail › Health Card.\nTabs:\n• Family / Personal History → family health, blood type, chronic disease, vaccinations\n• Laboratory – Physical Examination → lab and exam findings, blood pressure, pulse, height, weight\n• Anamnesis → complaints, diagnoses, hospital/surgery/work accident/occupational disease/treatment questions, smoking and alcohol\n• Result → fitness for work, shift and night work fitness, doctors\n• Periodic Examinations, Patient Protocol (infirmary), Sick Leaves → multi-row lists\nRules: no add/delete on the list (the card is the user). Health data is special-category personal data; grant only to the workplace doctor and health staff.",
|
||||
"DescTr": "Sağlık Kartları — işyeri hekimliği için her çalışanın sağlık kartı. Liste kiracının bütün kullanıcılarıdır; kart bilgileri detay sekmelerinden girilir.\nNerede: İnsan Kaynakları › Sağlık Kartları. Aynı veri Kimlik › Kullanıcılar › detay › Sağlık Kartı sekmesinde de düzenlenir.\nSekmeler:\n• Soy / Özgeçmiş → aile sağlık durumu, kan grubu, kronik hastalık, aşılar\n• Laboratuvar – Fizik Muayene → tahlil ve muayene bulguları, tansiyon, nabız, boy, kilo\n• Anamnez → şikâyetler, tanılar, hastane/ameliyat/iş kazası/meslek hastalığı/tedavi soruları, sigara ve alkol\n• Sonuç → çalışmaya elverişlilik, vardiyalı ve gece çalışabilirlik, hekimler\n• Periyodik Muayeneler, Hasta Protokol Defteri (revir), İstirahat Raporları → çok kayıtlı listeler\nKurallar: listeye kayıt eklenmez/silinmez (kart kullanıcının kendisidir). Sağlık verisi özel nitelikli kişisel veridir; yetki yalnız işyeri hekimi ve sağlık personeline verilmelidir."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Anamnez",
|
||||
"TitleEn": "Anamnesis",
|
||||
"TitleTr": "Anamnez",
|
||||
"DescEn": "Health card anamnesis questions",
|
||||
"DescTr": "Sağlık kartı anamnez soruları"
|
||||
"DescEn": "Anamnesis — questionnaire about the employee's health history.\nWhere: the Anamnesis tab of Health Cards.\nFields: complaints, diagnoses, yes/no questions (hospitalisation, surgery, work accident, occupational disease exam, disability pension, ongoing treatment) with notes, smoking and alcohol use.\nRule: a note stays locked until its question is answered Yes; smoking/alcohol notes are locked when usage is None.",
|
||||
"DescTr": "Anamnez — çalışanın sağlık geçmişine dair soru formu.\nNerede: Sağlık Kartları ekranında kaydın Anamnez sekmesi.\nAlanlar: şikâyetler (göğüs ağrısı, öksürük, nefes darlığı, çarpıntı, eklem/bel ağrısı…), tanılar (diyabet, kalp, böbrek, sarılık, ülser, işitme/görme…), evet/hayır soruları (hastanede yatış, ameliyat, iş kazası, meslek hastalığı muayenesi, malulen emeklilik, süren tedavi) ve notları, sigara ve alkol kullanımı.\nKural: soru Evet işaretlenmeden notu, kullanım Yok seçiliyken sigara/alkol notu kilitlidir."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Soy / Özgeçmiş",
|
||||
"TitleEn": "Family / Personal History",
|
||||
"TitleTr": "Soy / Özgeçmiş",
|
||||
"DescEn": "Health card family and personal history",
|
||||
"DescTr": "Sağlık kartı soy ve özgeçmiş bilgileri"
|
||||
"DescEn": "Family / Personal History — family health history, blood type, chronic diseases and vaccinations.\nWhere: the Family / Personal History tab of Health Cards (edits the user record itself).\nFields: mother/father/sibling/child health status and notes, blood type, chronic disease, tetanus, hepatitis and other vaccinations.",
|
||||
"DescTr": "Soy / Özgeçmiş — çalışanın aile sağlık geçmişi, kan grubu, kronik hastalıkları ve aşıları.\nNerede: Sağlık Kartları ekranında kaydın Soy / Özgeçmiş sekmesi (kullanıcı kaydının kendisini düzenler).\nAlanlar: anne/baba/kardeş/çocuk sağlık durumu (Yaşıyor, Hasta, Vefat) ve notları, kan grubu, doğuştan/kronik hastalık, tetanoz, hepatit ve diğer aşılar."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Laboratuvar - Fizik Muayene",
|
||||
"TitleEn": "Laboratory - Physical Examination",
|
||||
"TitleTr": "Laboratuvar - Fizik Muayene",
|
||||
"DescEn": "Health card laboratory findings and physical examination results",
|
||||
"DescTr": "Sağlık kartı laboratuvar bulguları ve fizik muayene sonuçları"
|
||||
"DescEn": "Laboratory – Physical Examination — lab and physical examination findings at hiring or periodic checks.\nWhere: the Laboratory – Physical Examination tab of Health Cards.\nFields: biological, blood, urine, radiology, audiometry, pulmonary function, psychological tests; sensory, eye, ENT, skin, cardiovascular, respiratory, digestive, urogenital, musculoskeletal, neurological, psychiatric exams; blood pressure, pulse, height, weight.",
|
||||
"DescTr": "Laboratuvar – Fizik Muayene — işe giriş ya da periyodik muayenedeki tahlil ve fizik muayene bulguları.\nNerede: Sağlık Kartları ekranında kaydın Laboratuvar – Fizik Muayene sekmesi.\nAlanlar: biyolojik, kan, idrar, radyolojik, odyometri, solunum fonksiyon, psikolojik test sonuçları; duyu organları, göz, KBB, deri, kalp-damar, solunum, sindirim, ürogenital, kas-iskelet, nörolojik, psikiyatrik muayene; tansiyon, nabız, boy, kilo."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Hasta Protokol Defteri",
|
||||
"TitleEn": "Patient Protocol Book",
|
||||
"TitleTr": "Hasta Protokol Defteri",
|
||||
"DescEn": "Infirmary visits of the employee",
|
||||
"DescTr": "Çalışanın revir başvuruları"
|
||||
"DescEn": "Patient Protocol Book — the employee's infirmary visits.\nWhere: the Patient Protocol tab of Health Cards.\nFields: sequence no, date (today), protocol type (Disease, Work accident, Occupational disease, Control, Other), result (Treated, Rest, Referral), rest days, referral place (only for Referral), doctor.",
|
||||
"DescTr": "Hasta Protokol Defteri — çalışanın revir başvuruları.\nNerede: Sağlık Kartları ekranında kaydın Hasta Protokol Defteri sekmesi.\nAlanlar: sıra no, tarih (bugün), protokol türü (Hastalık, İş kazası, Meslek hastalığı, Kontrol, Diğer), sonuç (Tedavi edildi, İstirahat, Sevk), istirahat günü, sevk yeri (yalnız Sevk'te açılır), hekim."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Periyodik Muayeneler",
|
||||
"TitleEn": "Periodic Examinations",
|
||||
"TitleTr": "Periyodik Muayeneler",
|
||||
"DescEn": "Periodic health examinations of the employee",
|
||||
"DescTr": "Çalışanın periyodik sağlık muayeneleri"
|
||||
"DescEn": "Periodic Examinations — the employee's statutory periodic health examinations.\nWhere: the Periodic Examinations tab of Health Cards (also in the user detail Health Card tab).\nFields: date (today), examination, result, doctor (Company Doctors; diploma no is filled).",
|
||||
"DescTr": "Periyodik Muayeneler — çalışanın yasal periyodik sağlık muayeneleri.\nNerede: Sağlık Kartları ekranında kaydın Periyodik Muayeneler sekmesi (kullanıcı detayındaki Sağlık Kartı sekmesinde de görünür).\nAlanlar: tarih (varsayılan bugün), muayene, sonuç, hekim (Kurum Doktorları; seçilince diploma no dolar)."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "Sonuç",
|
||||
"TitleEn": "Result",
|
||||
"TitleTr": "Sonuç",
|
||||
"DescEn": "Health card fitness for work result",
|
||||
"DescTr": "Sağlık kartı çalışmaya elverişlilik sonucu"
|
||||
"DescEn": "Result — the workplace doctor's fitness-for-work decision.\nWhere: the Result tab of Health Cards.\nFields: job and condition the employee is fit for, doctor; shift work fit, night work fit and the doctor for this decision.",
|
||||
"DescTr": "Sonuç — işyeri hekiminin çalışmaya elverişlilik kararı.\nNerede: Sağlık Kartları ekranında kaydın Sonuç sekmesi.\nAlanlar: çalışmaya elverişli olduğu iş ve koşul, hekim; vardiyalı çalışabilir, gece çalışabilir ve bu karar için hekim."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
"MenuTr": "İstirahat Raporları",
|
||||
"TitleEn": "Sick Leaves",
|
||||
"TitleTr": "İstirahat Raporları",
|
||||
"DescEn": "Medical rest reports of the employee",
|
||||
"DescTr": "Çalışanın istirahat raporları"
|
||||
"DescEn": "Sick Leaves — the employee's sick leave records.\nWhere: the Sick Leaves tab of Health Cards.\nFields: start and end date, days (end inclusive, automatic), type (Disease, Work accident, Occupational disease, Maternity), institution, clinic, reason.\nNote: sick leave does not affect leave balances.",
|
||||
"DescTr": "İstirahat Raporları — çalışanın aldığı istirahat (rapor) kayıtları.\nNerede: Sağlık Kartları ekranında kaydın İstirahat Raporları sekmesi.\nAlanlar: başlangıç ve bitiş tarihi, gün (bitiş dahil, otomatik), istirahat türü (Hastalık, İş kazası, Meslek hastalığı, Doğum), kurum, klinik, neden.\nDikkat: rapor izin bakiyesine yansımaz."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Hastaneler",
|
||||
"TitleEn": "Hospitals",
|
||||
"TitleTr": "Hastaneler",
|
||||
"DescEn": "Hospital and health institution definitions",
|
||||
"DescTr": "Hastane ve sağlık kurumu tanımları"
|
||||
"DescEn": "Hospitals — hospital and health institution definitions.\nWhere: Human Resources › Definitions › Hospitals.\nFields: name, active.\nNote: currently not linked to any screen; sick leave and referral records use free text.",
|
||||
"DescTr": "Hastaneler — hastane ve sağlık kurumu tanımları.\nNerede: İnsan Kaynakları › Tanımlamalar › Hastaneler.\nAlanlar: kurum adı, aktif.\nDikkat: şu an hiçbir ekrana bağlı değildir; istirahat ve sevk kayıtlarında kurum serbest metin olarak yazılır."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Hastane Bölümleri",
|
||||
"TitleEn": "Hospital Departments",
|
||||
"TitleTr": "Hastane Bölümleri",
|
||||
"DescEn": "Hospital department definitions",
|
||||
"DescTr": "Hastane bölümü tanımları"
|
||||
"DescEn": "Hospital Departments — hospital clinic definitions (emergency, internal medicine, cardiology…).\nWhere: Human Resources › Definitions › Hospital Departments.\nFields: name, active.\nNote: currently not linked to any screen; sick leave records use free text.",
|
||||
"DescTr": "Hastane Bölümleri — hastane klinik/bölüm tanımları (acil, dahiliye, kardiyoloji…).\nNerede: İnsan Kaynakları › Tanımlamalar › Hastane Bölümleri.\nAlanlar: bölüm adı, aktif.\nDikkat: şu an hiçbir ekrana bağlı değildir; istirahat kayıtlarında klinik serbest metindir."
|
||||
},
|
||||
"Groups": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Mülakatlar",
|
||||
"TitleEn": "Interviews",
|
||||
"TitleTr": "Mülakatlar",
|
||||
"DescEn": "Interview planning, interviewer assignment and criterion-based scoring",
|
||||
"DescTr": "Mülakat planlama, mülakatçı ataması ve kriter bazlı puanlama",
|
||||
"DescEn": "Interviews — scheduling interviews for an application, assigning interviewers and criteria-based scoring.\nWhere: Human Resources › Recruitment › Interviews (calendar view) and the Interviews tab of Applications. Criterion scores are entered in the Scores tab.\nFields:\n• ApplicationId → candidate – posting; InterviewType → phone, video, face to face, technical, HR\n• InterviewerUserId → interviewer (defaults to the creator)\n• Start / end (end defaults to start + 1 hour), place, meeting link\n• Status → Planned / Completed / Cancelled / No show; Recommendation → hire / hold / reject\n• OverallScore → criteria-weighted average, automatic\nAutomatic: adding an interview moves the application to Interview and notifies the interviewer (IseAlimMulakatAtandi: in-app + e-mail).",
|
||||
"DescTr": "Mülakatlar — başvuru için mülakat planlama, mülakatçı ataması ve kriter bazlı puanlama.\nNerede: İnsan Kaynakları › İşe Alım › Mülakatlar (takvim görünümü) ve Başvurular ekranının Mülakatlar sekmesi. Detaydaki Puanlar sekmesinde kriter puanları girilir.\nAlanlar:\n• ApplicationId → aday – ilan; InterviewType → telefon, video, yüz yüze, teknik, İK\n• InterviewerUserId → mülakatçı (varsayılan kaydı açan kişi)\n• Başlangıç / bitiş (bitiş boşsa başlangıç + 1 saat), yer, toplantı bağlantısı\n• Status → Planlandı / Tamamlandı / İptal / Gelmedi; Recommendation → işe al / beklet / reddet\n• OverallScore → kriter ağırlıklı ortalama, otomatik\nOtomatik: kayıt eklenince başvuru Mülakat aşamasına geçer ve mülakatçıya bildirim gider (IseAlimMulakatAtandi: uygulama içi + e-posta).",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.Interview.Type.Phone",
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
"MenuTr": "Mülakat Puanları",
|
||||
"TitleEn": "Interview Scores",
|
||||
"TitleTr": "Mülakat Puanları",
|
||||
"DescEn": "Score per evaluation criterion (1-5)",
|
||||
"DescTr": "Değerlendirme kriteri başına puan (1-5)",
|
||||
"DescEn": "Interview Scores — a 1–5 score for each evaluation criterion in an interview.\nWhere: the Scores tab of an Interview record (no menu entry).\nFields:\n• CriterionId → Evaluation Criteria definition; a criterion is scored once per interview\n• Score → 1 very poor … 5 very good; Comment → reasoning\nAutomatic: every change recalculates the interview overall score (Σ score × weight / Σ weight) and the application average.",
|
||||
"DescTr": "Mülakat Puanları — mülakatta her değerlendirme kriterine verilen 1–5 puan.\nNerede: Mülakatlar ekranında kaydın Puanlar sekmesi (menüde ayrıca yoktur).\nAlanlar:\n• CriterionId → Değerlendirme Kriterleri tanımı; aynı kriter bir mülakatta bir kez puanlanır\n• Score → 1 Çok zayıf … 5 Çok iyi; Comment → gerekçe\nOtomatik: puan eklenince/değişince/silinince mülakat genel puanı (Σ puan × ağırlık / Σ ağırlık) ve başvurunun ortalama puanı yeniden hesaplanır.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.InterviewScore.Score.1",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Başvurular",
|
||||
"TitleEn": "Applications",
|
||||
"TitleTr": "Başvurular",
|
||||
"DescEn": "Candidate applications per job posting and stage tracking",
|
||||
"DescTr": "İlan bazında aday başvuruları ve aşama takibi",
|
||||
"DescEn": "Applications — a candidate's application to a posting and its stage tracking (kanban).\nWhere: Human Resources › Recruitment › Applications, and the Applications tab of Job Postings and Candidates. The detail has Interviews and Offers tabs.\nStages: Applied → Screening → Interview → Offer → Hired / Rejected. In the Todo view cards are dragged between stages.\nFields:\n• CandidateId + JobPostingId → a candidate can apply to a posting only once\n• SourceId (copied from the candidate), OwnerUserId (recruiter), application date\n• AverageScore → average of interview scores (automatic)\n• RejectionReasonId + note → kept only in the Rejected stage\nAutomatic: adding an interview moves the stage to Interview, adding an offer to Offer, an accepted offer to Hired; automatic moves never go back. Candidate and posting names are copied for the kanban title.",
|
||||
"DescTr": "Başvurular — bir adayın bir ilana başvurusu ve başvurunun aşama takibi (kanban panosu).\nNerede: İnsan Kaynakları › İşe Alım › Başvurular; ayrıca İlanlar ve Adaylar ekranlarının Başvurular sekmesi. Detayda Mülakatlar ve Teklifler sekmeleri vardır.\nAşamalar: Başvuru → Ön Eleme → Mülakat → Teklif → İşe Alındı / Reddedildi. Todo görünümünde kart sürüklenerek ilerletilir.\nAlanlar:\n• CandidateId + JobPostingId → aynı aday aynı ilana bir kez başvurabilir\n• SourceId (adaydan kopyalanır), OwnerUserId (sorumlu), başvuru tarihi\n• AverageScore → mülakat genel puanlarının ortalaması (otomatik)\n• RejectionReasonId + not → yalnızca Reddedildi aşamasında tutulur\nOtomatik: mülakat eklenince aşama Mülakat'a, teklif eklenince Teklif'e, teklif Kabul edildi olunca İşe Alındı'ya ilerler; otomatik ilerleme geri gitmez. Aday ve ilan adı kanban başlığı için kopyalanır.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.JobApplication.Stage.Applied",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "Teklifler",
|
||||
"TitleEn": "Job Offers",
|
||||
"TitleTr": "Teklifler",
|
||||
"DescEn": "Offers made to candidates, internal approval and offer letter",
|
||||
"DescTr": "Adaylara yapılan teklifler, iç onay ve teklif mektubu",
|
||||
"DescEn": "Job Offers — salary and terms offered to a candidate, internal approval and offer letter.\nWhere: Human Resources › Recruitment › Job Offers and the Offers tab of Applications.\nFields:\n• OfferNo → TKL-YYYY-00001, automatic; selecting the application fills position data from the posting\n• GrossSalary + currency, start and valid-until dates, benefits (Benefit Types)\n• Status → Draft / Sent / Accepted / Declined / Expired; Accepted or Declined sets the response date to today\nApproval: Grid Workflow (same flow as staff requests). Approved rows show the Offer Letter button.\nAutomatic: adding an offer moves the application to Offer, acceptance moves it to Hired.",
|
||||
"DescTr": "Teklifler — işe alınması düşünülen adaya yapılan ücret ve şart teklifi, iç onayı ve teklif mektubu.\nNerede: İnsan Kaynakları › İşe Alım › Teklifler ve Başvurular ekranının Teklifler sekmesi.\nAlanlar:\n• OfferNo → TKL-YYYY-00001, otomatik; ApplicationId seçilince pozisyon bilgileri ilandan dolar\n• GrossSalary + para birimi, işe başlama ve geçerlilik tarihi, yan haklar (Yan Hak Türleri)\n• Status → Taslak / Gönderildi / Kabul / Ret / Süresi Doldu; Kabul ya da Ret seçilince yanıt tarihi bugün olur\nOnay: Grid Workflow (kadro talebiyle aynı akış). Onaylanan satırda Teklif Mektubu butonu mektubu basar.\nOtomatik: teklif eklenince başvuru Teklif aşamasına, Kabul olunca İşe Alındı aşamasına geçer.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.Recruitment.EmploymentType.FullTime",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "İlanlar",
|
||||
"TitleEn": "Job Postings",
|
||||
"TitleTr": "İlanlar",
|
||||
"DescEn": "Job postings opened from approved staff requests",
|
||||
"DescTr": "Onaylı kadro taleplerinden açılan iş ilanları",
|
||||
"DescEn": "Job Postings — job advertisements opened from approved staff requests, together with their applications.\nWhere: Human Resources › Recruitment › Job Postings. The Applications tab in the record detail shows applications to this posting.\nFields:\n• PostingNo → ILN-YYYY-00001, automatic\n• StaffRequestId → approved requests only; selecting one fills title, branch, department, position, headcount and employment type\n• Status → Draft / Published / Closed / Cancelled\n• WorkModel → Office / Hybrid / Remote; location, publish and closing dates\n• SourceIds → channels the posting is published on (Candidate Sources, multi-select)\n• Description and requirements (HTML)\nAutomatic: updating the posting refreshes the posting title copies on applications, interviews and offers.\nRelated: Staff Requests (source), Applications (tab), Candidate Sources (channels).",
|
||||
"DescTr": "İlanlar — onaylanmış kadro taleplerinden açılan iş ilanları ve ilana gelen başvurular.\nNerede: İnsan Kaynakları › İşe Alım › İlanlar. Kaydın detayındaki Başvurular sekmesi bu ilana yapılan başvuruları gösterir.\nAlanlar:\n• PostingNo → ILN-YYYY-00001, otomatik\n• StaffRequestId → yalnızca onaylı talepler; seçilince başlık, şube, departman, pozisyon, adet ve çalışma şekli dolar\n• Status → Taslak / Yayında / Kapalı / İptal\n• WorkModel → Ofis / Hibrit / Uzaktan; Location, yayın ve son başvuru tarihi\n• SourceIds → ilanın yayınlandığı kanallar (Aday Kaynakları tanımı, çoklu seçim)\n• Açıklama ve aranan nitelikler (HTML)\nOtomatik: ilan güncellenince başvuru, mülakat ve teklif kayıtlarındaki ilan başlığı kopyaları düzeltilir.\nİlişkili: Kadro Talepleri (kaynak), Başvurular (alt sekme), Aday Kaynakları (yayın kanalı).",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Hr.Recruitment.EmploymentType.FullTime",
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
"MenuTr": "İzin Türleri",
|
||||
"TitleEn": "Leave Types",
|
||||
"TitleTr": "İzin Türleri",
|
||||
"DescEn": "Leave type definitions",
|
||||
"DescTr": "İzin türü tanımları",
|
||||
"DescEn": "Leave Types — kinds of leave and their rules (annual, excuse, unpaid, sick, maternity, paternity, marriage, bereavement, nursing).\nWhere: Human Resources › Definitions › Leave Types.\nFields: code, name, gender (All/Male/Female), max days per year, paid, deducts from annual leave, document required, half-day allowed, active.\nNote: not yet linked to a leave request screen; it is the source definition for a future leave process.",
|
||||
"DescTr": "İzin Türleri — izin çeşitleri ve kuralları (yıllık, mazeret, ücretsiz, hastalık, doğum, babalık, evlilik, ölüm, süt izni).\nNerede: İnsan Kaynakları › Tanımlamalar › İzin Türleri.\nAlanlar: kod, ad, cinsiyet (Tümü/Erkek/Kadın), yıllık en fazla gün, ücretli, yıllık izinden düşer, belge gerekir, yarım gün kullanılabilir, aktif.\nDikkat: henüz bir izin talep ekranına bağlı değildir; izin talep süreci kurulduğunda kaynak tanım olarak kullanılacaktır.",
|
||||
"Texts": [
|
||||
{
|
||||
"Key": "App.Widget.Paid",
|
||||
|
|
|
|||
2011
configs/seeds/host/wizard/My360Feedback.json
Normal file
2011
configs/seeds/host/wizard/My360Feedback.json
Normal file
File diff suppressed because it is too large
Load diff
1499
configs/seeds/host/wizard/My360FeedbackScore.json
Normal file
1499
configs/seeds/host/wizard/My360FeedbackScore.json
Normal file
File diff suppressed because it is too large
Load diff
2906
configs/seeds/host/wizard/MyDevelopmentPlan.json
Normal file
2906
configs/seeds/host/wizard/MyDevelopmentPlan.json
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue