# 14 — TEST PAKETİ

**65 test metodu, 8 dosya.** Kurulumdan sonra tek komutla neyin çalıştığını
görüyorsun:

```bash
php artisan test
```

Bu paketin varlık sebebi şu: 128 dosyalık bir kod tabanı yazdık ve hiçbiri
çalışan bir sunucuda denenmedi. Testler o belirsizliği tek komuta indiriyor.

Daha önemlisi: Python simülasyonlarında doğruladığım her senaryo artık
**kalıcı**. Biri altı ay sonra bir satır değiştirirse hangi varsayımı
bozduğunu anında görüyor.

---

## Kurulum

```bash
cp -r tests/Unit/*    ~/magostore/tests/Unit/
cp -r tests/Feature/* ~/magostore/tests/Feature/

# .env.testing (yoksa oluştur)
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
```

```bash
php artisan test                          # hepsi
php artisan test --testsuite=Unit         # veritabanı gerektirmeyenler
php artisan test tests/Feature/LedgerPosterTest.php   # sadece defter
```

`Unit` testlerinin çoğu veritabanı gerektirmiyor — sunucuya kurmadan bile
çalıştırabilirsin.

---

## Neyi koruyorlar

### Defter · 15 test — projenin en önemli dosyası

`tests/Feature/LedgerPosterTest.php`

Defter yanlış çalışırsa para kaybolur ve **fark edilmez.** Her test bir felaket
senaryosunu önlüyor:

- Dengesiz fiş reddediliyor **ve hiç yazılmıyor** — yarım yazılırsa defter
  kalıcı bozulur ve hangi fişin bozuk olduğu bulunamaz
- Ters kayıt borç/alacağı çeviriyor, **orijinal fişe dokunmuyor**
- Aynı fiş iki kez ters çevrilemiyor
- Ters kaydın tersi alınamıyor
- Toplam borç = toplam alacak, her senaryodan sonra
- Bakiye önbelleği bozulsa bile defterden **yeniden üretilebiliyor**
- Platform hesabı yoksa anlamlı hata veriyor ("Migration çalıştı mı?")

#### ⭐ Kilit test: `test_iade_sonrasi_mahsup_otomatik_olur`

Mimarinin doğruluğunu kanıtlayan test. Senaryo:

| Adım | Alacak | Borç |
|---|---|---|
| A teslim (796,67) | 796,67 | 0 |
| B teslim (460,00) | 1.256,67 | 0 |
| İkisi ödendi | 0 | 0 |
| **B iade edildi** | 0 | **460,00** |
| C teslim (712,50) | **252,50** | 0 |

`712,50 − 460,00 = 252,50` — **mahsup kendiliğinden oldu.** Ayrı mahsup kodu
yazmaya gerek kalmadı, çünkü borç ve alacak aynı hesapta (2000) yaşıyor ve
işaret farkı işi yapıyor.

Bu test geçtiği sürece 5 iş günü kuralı ile 14 günlük cayma hakkı arasındaki
çelişki çözülmüş durumda.

### Buybox · 11 test

`tests/Unit/BuyboxScorerTest.php`

- **Determinizm:** 50 kez karışık sırayla, kazanan hep aynı. Buybox her
  hesaplamada zıplarsa satıcılar haklı olarak şikâyet eder.
- Tasarım prototipindeki dört teklifle kazanan Kandil — mockup'ta elle
  seçtiğimle algoritma hemfikir
- Kargo dahil toplam, liste fiyatından önemli
- **IBAN'ı olmayan satıcı kazanamıyor** (Faz 3 bağlantısı) — kazandırırsak
  satışı alıp parasını alamayan satıcı üretmiş oluruz
- Fiyat manipülasyonu kapısı: medyanın %25'i ve 2 katı eleniyor
- Tam eşitlikte kıdem kazanıyor
- Ağırlıklar 1,0 toplamıyorsa yakalanıyor

### Hakediş ve stopaj · 7 test

`tests/Unit/ItemSettlementCalculatorTest.php`

Referans örnek kilitli: 1.000 TL / %20 KDV / %15 komisyon / 45 TL kargo →
**796,67 TL.** Bu sayı tüm dokümanlarda ve tasarım prototiplerinde geçiyor.

**En kritik test:** `test_stopaj_matrahi_brut_bedel_uzerinden`

Aynı satış bedeli, çok farklı kesintiler → **aynı stopaj.** Çünkü matrah KDV
hariç brüt bedel; komisyon ve kargo matrahı düşürmüyor (330 seri no.lu GVK
Genel Tebliği).

Bu testi kaldıran biri "stopajı net üzerinden alalım" diye değiştirebilir ve
eksik beyan doğar. Test o kapıyı kapatıyor.

### Kargo tahsisi · 7 test

`tests/Unit/OrderChargeAllocatorTest.php`

**En önemlisi:** 3 kalemli sipariş ile 1 kalemli sipariş **aynı toplamı**
veriyor. Yoğunlaştırma sadece hangi satırın taşıdığını değiştiriyor, toplamı
değiştirmiyor — değiştirirse defter dengesizleşir.

Ayrıca: taşma çalışıyor, satıcı payı negatife düşmüyor, kargo siparişi aşarsa
istisna atıyor.

### Barkod · 7 test

`tests/Unit/GtinTest.php`

Yanlış barkod iki farklı ürünü aynı katalog kaydında birleştiriyor ve hata
**sessiz** — müşteri yanlış ürün alana kadar kimse fark etmiyor.

Gerçek barkodlarla test edildi. İki kritik durum: UPC-A ile başına sıfır
eklenmiş EAN-13 aynı sonuca normalize ediliyor (çift kayıt önleniyor), ve koli
barkodu (ITF-14) ayırt ediliyor.

### IBAN · 4 test

`tests/Unit/IbanTest.php`

mod-97 doğrulaması ve hesap sahibi eşleştirmesi. iyzico uyumsuzluk hatasını
**kayıt anında değil ödeme anında** veriyor — yani hata haftalar sonra, satıcıya
para göndermeye çalıştığın gün çıkıyor. Bu testler onu kayıt anına çekiyor.

### İş günü takvimi · 7 test

`tests/Unit/BusinessDayCalendarTest.php`

5 iş günü sınırı bu hesaba dayanıyor. Yedi sabit resmî tatil, hafta sonu
atlaması, gerçek tarihlerle beş senaryo.

**Hata yönü belgelendi:** `test_eksik_tatil_vadeyi_erkene_ceker_guvenli_taraf`
— tabloda dinî bayram yoksa vade ERKEN hesaplanıyor, yani ödemeyi yasal
sınırdan önce yapıyoruz. Güvenli taraf. Riskli olan tersi: olmayan bir günü
tatil girmek vadeyi uzatır ve sınır sessizce aşılır.

### Fiyat içgörüsü · 7 test

`tests/Unit/PriceInsightLogicTest.php`

**Bu testler bir hatayı belgelemek için var.** İlk yazdığım mantık dürüst
indirimi "yanıltıcı" sanıyordu — en düşük fiyatı hesaplarken bugünün fiyatını
da dahil ediyordum. Testte yakalandı, ölçüt değişti.

Şimdi kilitli: gerçek indirim (1590→1249) temiz geçiyor, şişirilmiş liste
fiyatı (30 gün 1000 ₺ ama liste 1800) yakalanıyor, 7 günden az veride hiçbir
iddia yapılmıyor.

---

## Yeni komut: yanıltıcı indirim denetimi

`php artisan magostore:price-audit`

Liste fiyatını şişirip indirim iddia eden ürünleri listeliyor. Mağaza bazlı
özet veriyor — hangi satıcıyla konuşulacağını gösteriyor.

```bash
php artisan magostore:price-audit
php artisan magostore:price-audit --store=42
php artisan magostore:price-audit --csv=denetim.csv
```

Panel ekranı değil komut, çünkü bu aylık bir denetim, günlük kullanılan bir
ekran değil. CSV çıktısı Excel'de BOM'lu, Türkçe karakterler bozulmuyor.

**Müşteriye asla gösterilmiyor.** Ölçüt sezgisel ve yanlış pozitif olabilir;
satıcıyla konuşmak için veri, müşteriye "bu satıcı sizi kandırıyor" demek
değil.

---

## Testlerin gösterdiği şey

Şu an testler **yeşil olmak zorunda değil** — sunucuda ilk çalıştırdığında
bazıları kırmızı yanacak. Sebepleri muhtemelen şunlar:

| Olası hata | Sebep |
|---|---|
| `Class not found` | `composer dump-autoload` gerekiyor |
| `Table not found` | Migration çalışmamış |
| `Botble\...Product not found` | Feature testleri Botble modelini bekliyor |
| Bakiye biçim farkı | MySQL/SQLite decimal dönüşü |

Bunlar **beklenen** ve düzeltmesi kolay. Kırmızı bir test, sessiz bir hatadan
kat kat iyi. Hata çıktısını olduğu gibi gönderirsen doğrudan çözerim.
