# Review — Fatura belgesi implementasyonu — Re-review (EGT-222) — 2026-10-20

> **Review type:** impl-re-review
> **Previous review:** `docs/reviews/review-fatura-belgesi-impl-2026-10-20.md` (heyet 826, ❌ REJECTED, 4 bulgu: F-R1…F-R4)
> **Upstream document(s) read:** `docs/plans/fatura-belgesi-plan.md` v1.1 (locked), `proje-haritasi.md` §4.4 fatura belgesi kararları + «heyet 826 F-R4 cevapları» satırı, `docs/reviews/tasarim-39-kapsama.md` (güncel hâli)
> **Other cross-referenced documents:** `CLAUDE.md`, `app/Domain/Sales/QuoteTotals.php`, `app/Actions/Sales/IssueInvoice.php`, `app/Queries/Office/InvoiceDocument.php`, `resources/js/organisms/InvoiceDocument.vue`, `resources/css/invoice.css`, `app/Queries/Office/QuotePrintout.php`, `app/Queries/Office/TrainingRevenue.php` (kapsam dışı bulgunun doğrulanması için)
> **Stage locks in effect:** Spec yok (Sets kararı) + Plan v1.1 locked

**Doğrulama koşuları (bu oturumda, benim tarafımdan):** TeamCity **#1824 SUCCESS — 2725 test** (origin/main = `edf8999f`, incelenen üç düzeltme commit'i dahil — push doğrulandı). Önceki review'da `php -r` ile ürettiğim kuruş-çelişkisi karşı-örneği (1.000,00 TL kalem, 55,56 TL tutar-tipi indirim, %20 KDV) düzeltilmiş kodla **yeniden çalıştırıldı**: belge artık 944,44 + 188,89 = 1.133,33 basıyor, önceki 1.133,32 çelişkisi yok.

---

## Upstream Coverage Matrix (sıfırdan üretildi — önceki 4 bulgu + plan F-1…F-16)

| Madde | Durum | Kanıt |
|---|---|---|
| F-R1 (kök sebep: `IssueInvoice::discountOn` yuvarlanmış yüzdeden indirim) | ✓ | `discountOn` kaldırıldı; `QuoteTotals::of` artık `line_nets` döndürüyor (`QuoteTotals.php:116-125`); `IssueInvoice` kalemi doğrudan `$totals['line_nets'][$index]`'ten yazıyor (`IssueInvoice.php:223`); eski faturalar için `InvoiceDocument::balanced()` oran satırlarını faturanın kendi `net_total`/`vat_total`'ına denkleştiriyor (ilk/en yüksek orana kalan farkı veriyor). Çalıştırarak doğruladım: karşı-örnek artık kuruşa kadar tutuyor. Testler: «writes a line from its exact net…» (`InvoiceDocumentTest.php` +166 satır), «balances an earlier invoice…» (elle 944,40 yazılmış satırla) |
| F-R2 (portal erişim logu testi eksikti) | ✓ | «logs a natural person opening their own invoice in the portal» — `user_type`/`user_id` = gerçek `CustomerUser`, `tenant_id` = müşteri; portal akışının üzerinden (`fromToken` → policy → `InvoiceDocument::for`) geçiyor |
| F-R3 (düzenleme/dönüşüm testi eksikti) | ✓ | «keeps billing details when a company is edited» (`PUT /musteriler/{token}`, `hasBillingDetails()` true doğrulanıyor), «carries billing details over when a prospect is converted» (`POST …/musteriye-donustur`, dönüşen müşteri kendi kiracısında okunuyor) |
| F-R4(a) çok sayfa devam başlığı doğrulanmadı | ✓ | Matris güncellendi: 40 kalemli fatura PDF'e basılmış, 2. sayfada devam başlığı + «AÇIKLAMA» tekrar + «Sayfa 2 / 2» metinde görülmüş (`tasarim-39-kapsama.md`, commit `9bc9c996`) |
| F-R4(b) «Alıcı: …» satırı cevapsızdı | ✓ (Sets) | Tasarımcı notu, basılmaz — `proje-haritasi.md:912` kayıtlı Sets kararı |
| F-R4(c) baskıda yasal ibarenin yeri cevapsızdı | ✓ (Sets) | «şimdiki gibi kalsın»; dibe sabitlenmez — kayıtlı karar |
| F-R4(d) iptal damgası «yer yoksa basma» yapılmamıştı | ✓ | `InvoiceDocument.vue` `measureStamp()` son sayfanın boş yüksekliğini ölçüyor, yetmezse `data-room="none"` → `invoice.css:424` baskıda gizliyor; PDF'te 1–11/12–21/22 kalemle üç durumda da denenmiş (matris) |
| Ek Sets kararı: `QuotePrintout` şahıs TCKN erişim logu | ✓ | Bu ticket kapsamına alınmış (proje-haritasi kaydı); `AccessLogger::record($customer, 'national_id', …)` eklendi; test «logs every printing of a natural person's national id, and none for a company» — şahısta 1, firmada 0 |
| QuoteTotals docblock yeri | ✓ | `percentageOf`'un docblock'u artık kendi metodunun üzerinde; `vatByRate`'inki kendi üzerinde |
| Kapsam dışı bildirim: `TrainingRevenue` aynı yuvarlanmış-yüzde kalıbı | ✓ (doğru raporlanmış) | `TrainingRevenue.php:138` hâlâ `line_percentages`'tan türetiyor — EGT-222'nin (fatura belgesi) dosyası değil, maliyet-kâr marjı ekranı; düzeltilmemiş olması bu review'ın kapsamı dışında, doğru işaretlenmiş |

Önceki review'da F-1…F-16, Rollout ve kırmızı çizgi taramasının geri kalanı zaten ✓ idi ve bu turda değişmedi; yeniden açılmadı.

---

## ✅ What works

- **F-R1'in çözümü köktendir, yama değil:** `discountOn`'un kaldırılması ve `line_nets`'in tek kaynak hâline gelmesi, sorunun kaynağını (yuvarlanmış yüzdeden yeniden türetme) ortadan kaldırıyor; `InvoiceDocument::balanced()` ayrıca eski kayıtlar için bir denkleştirme kemeri ekliyor. Kendi ürettiğim karşı-örneği yeniden çalıştırarak bunu doğruladım.
- Dört bulgunun dördü de isim bazında, dosya+satır kanıtıyla ve (F-R4'te) Sets'in kayıtlı kararıyla kapanmış; goal drift yok.
- Bu turda bulunan ayrı bir kırmızı çizgi 13 boşluğu (`QuotePrintout`'un şahıs TCKN'sini loglamaması) Sets'in kararıyla aynı ticket'a alınmış ve düzeltilmiş — kapsam genişlemesi keyfi değil, onaylı.
- Kapsam dışı bulgu (`TrainingRevenue`) dürüstçe raporlanmış, düzeltilmemiş — bu doğru davranış (global kural: out-of-scope bulgular raporlanır, izinsiz düzeltilmez).
- CI otoritesi yeşil: **#1824 SUCCESS, 2725 test** (bu review'da tetiklendi ve beklendi).

## ⚠️ Findings & Risks (in-scope for this review type)

Yok. Matriste ❌/⚠ satır kalmadı.

## ❓ Open Questions (to be answered before next stage)

Yok — F-R4'ün tüm açık soruları Sets tarafından cevaplanmış ve kayıtlı.

## Previous Findings Status

| Önceki bulgu | Durum |
|---|---|
| F-R1 — kuruş tutarsızlığı (kök sebep `discountOn`) | ✅ Resolved |
| F-R2 — portal erişim log testi eksik | ✅ Resolved |
| F-R3 — düzenleme/dönüşüm testi eksik | ✅ Resolved |
| F-R4 — kapsama matrisinin 4 cevapsız satırı | ✅ Resolved |

## ⚠️ Upstream Findings

Yok.

## Verdict: ✅ APPROVED

Matriste kalan ❌/⚠ satır yok. Önceki turun asıl red sebebi olan kuruş tutarsızlığı kökten düzeltildi ve bizzat çalıştırılarak doğrulandı; diğer üç bulgu test ve kayıtlı kararla kapandı. CI otoritesi yeşil (#1824, 2725 test). Kapsam dışı bulgu doğru raporlanmış, zorlanmadan bırakılmış. Teslime hazır.
