# FAZ 3c — Kargo Tahsisi ve İş Günü Takvimi

Kararın: kargo satıcıya yansıyacak, kırılım temiz kalacak. Uyguladım, ama
kararın bir yan etkisi vardı — onu çözerek uyguladım. Aşağıda anlatıyorum.

---

## 1. Kargo: dağıtmıyoruz, yoğunlaştırıyoruz

### Sorun

Kargoyu kırılıma hiç yazmazsak iyzico satıcıya kalem tutarının **tamamını**
ödüyor. Kargoyu geri almak için borç kaydı açmak gerekiyor.

Ve bu **her siparişte** olur. İadede istisnai olan borç mekanizması, kargoda
normal yol haline gelir. Sonuç: her satıcı sürekli borç-mahsup modunda görünür,
bakiye ekranı okunamaz hale gelir, ve mutabakatta her sipariş için bir açık
kalem birikir.

### Çözüm

Kargoyu kalemlere **dağıtmıyoruz** — istediğin temizlik korunuyor. Siparişin
**en büyük kalemi** kargonun tamamını taşıyor, diğer kalemler tamamen temiz:
sadece `gross − komisyon − komisyon KDV − stopaj`.

Taşıyıcı olarak satıcı payı en yüksek kalem seçiliyor; kargoyu emme kapasitesi
en yüksek olan o.

### Yoğunlaştırma toplamı değiştirmiyor

Test ettim — 600 + 300 + 100 TL'lik üç kalemli sipariş, kargo 45 TL:

| Kalem | Brüt | Satıcı payı | Yüklenen kargo |
|---|---|---|---|
| 1 | 600,00 | 460,00 | 45,00 ← taşıyıcı |
| 2 | 300,00 | 252,50 | — |
| 3 | 100,00 | 84,17 | — |
| **Toplam** | **1.000,00** | **796,67** | |

Tek kalemli 1.000 TL'lik sipariş de aynı 796,67 TL veriyor — Faz 2 dokümanındaki
değerle birebir. Yani yoğunlaştırma yalnızca **hangi satırın** taşıdığını
değiştiriyor, satıcının aldığı toplamı değiştirmiyor. Defter dengesi bozulmuyor.

### Taşma

Kargo, taşıyıcı kalemin satıcı payından büyükse kalan sonraki kalemlere taşıyor.
Test: 40 + 35 + 30 TL'lik sipariş, kargo 60 TL → birinci kalem 33,67 TL emiyor
(payı sıfırlanıyor), kalan 26,33 TL ikinci kaleme geçiyor. `subMerchantPrice`
hiçbir zaman negatife düşmüyor; iyzico negatif değeri reddediyor.

Tüm kalemler tükenirse **istisna atıyorum.** 20 + 15 TL'lik siparişe 100 TL
kargo geldiğinde 70,56 TL karşılanamıyor — bu kargo tarifesinin veya komisyon
oranının hatalı olduğu anlamına gelir ve sessizce geçilmemesi gereken bir durum.
Ödeme isteği gönderilmeden önce patlıyor.

### Ek doğrulama

`OrderChargeAllocator::assertReconciled()` ödeme isteği kurulmadan önce iki şeyi
kontrol ediyor: kırılım brüt toplamı sipariş tutarına eşit mi, ve satıcı payı +
kesintiler brüt tutarı veriyor mu. Tutmuyorsa defter dengesizleşeceği için
istek gönderilmiyor.

---

## 2. İş günü takvimi

5 iş günü sınırı **takvim günü değil iş günü** sayıyor. Hafta sonunu atlamak
yetmiyor, resmî tatiller de sayılmıyor.

Sabit tatiller kuralla hesaplanıyor: 1 Ocak, 23 Nisan, 1 Mayıs, 19 Mayıs,
15 Temmuz, 30 Ağustos, 29 Ekim.

Dinî bayramlar hicri takvime bağlı, kuralla hesaplanamıyor — `mg_public_holidays`
tablosundan okunuyor.

### Gerçek tarihlerle test

| Teslim | Bizim vade (+3 iş günü) | Yasal son (+5 iş günü) | Emniyet payı |
|---|---|---|---|
| 24 Tem 2026 Cuma | 29 Tem Çar | 31 Tem Cuma | 2 gün |
| 13 Tem 2026 Pzt (15 Tem arada) | 17 Tem Cuma | 21 Tem Sal | 4 gün |
| 27 Ağu 2026 Per (30 Ağu arada) | 1 Eyl Sal | 3 Eyl Per | 2 gün |
| 26 Eki 2026 Pzt (29 Eki arada) | 30 Eki Cuma | 3 Kas Sal | 4 gün |
| 31 Ara 2026 Per (1 Oca arada) | 6 Oca 2027 Çar | 8 Oca Cuma | 2 gün |

Tatil araya girdiğinde emniyet payı 2 günden 4 güne çıkıyor — yani tatil
yoğunluğu bizim lehimize çalışıyor.

### Hata yönü konusunda kendimi düzelttim

Bu bölümü ilk yazdığımda gerekçeyi **ters** kurmuşum. Test çıktısını okuyunca
fark ettim, düzeltiyorum çünkü fark önemli.

İki yanlış yapma biçimi var ve riskleri **simetrik değil**:

**Eksik tatil** (tabloya bayram girilmemiş) → **güvenli taraf.** Takvim o günleri
iş günü sayar, vadeyi olduğundan **erken** hesaplar, ödemeyi yasal sınırdan önce
yaparız. Uyum bozulmaz.

Test: 8 Mart 2027 teslim, Ramazan Bayramı tabloda yoksa sistem son günü 15 Mart
sanıyor; gerçek son gün 18 Mart. Yani 3 gün **erken** ödüyoruz. Sorun değil.

**Fazla veya yanlış tatil** (olmayan bir gün tatil girilmiş) → **riskli taraf.**
Takvim vadeyi olduğundan **geç** hesaplar, 5 iş günü sınırı aşılır, ve panelde
"zamanında ödendi" görünür. İhlal sessizce olur.

Bu asimetri yüzünden tabloya tahmini tarih **seed etmiyorum.** Boş tablo güvenli,
yanlış dolu tablo riskli. `is_verified` alanı da bu yüzden var: Resmî Gazete'de
ilan edilmiş tarihler için `true`, astronomik tahmin için `false`, ve takvim
doğrulanmamış bir tarih kullandığında uyarı logluyor.

Arife günleri `is_half_day = true` ile giriliyor ve **iş günü sayılıyor** —
yarım gün tatil olsa da bankalar çalışıyor, ödeme geçiyor.

---

## 3. Teslim edilen kod

| Dosya | Görevi |
|---|---|
| `app/Magostore/Settlement/OrderChargeAllocator.php` | Kargo yoğunlaştırma, taşma, mutabakat doğrulaması |
| `app/Magostore/Support/BusinessDayCalendar.php` | İş günü hesabı, tatil yönetimi, önbellek |
| `database/migrations/..._000005_create_public_holidays.php` | Hareketli tatiller tablosu |

### Tatil tablosunu doldurmak

Sistem canlıya çıkmadan önce **cari ve gelecek yılın** dinî bayramlarını girmen
gerekiyor. Resmî Gazete'den doğrulanmış tarihlerle:

```sql
INSERT INTO mg_public_holidays (holiday_date, name, is_half_day, is_verified, source)
VALUES ('2027-03-09', 'Ramazan Bayramı Arifesi', 1, 1, 'RG ... sayı/tarih');
```

Girmezsen sistem çalışır ve güvenli tarafta kalır (erken ödeme), ama log'da
uyarı görürsün.

---

## 4. Sıradaki iş

1. **`HookServiceProvider` devralma** — eklentinin ödeme kurulumunu kendi
   sağlayıcımızla değiştirmek, `MarketplaceBasketBuilder` + `OrderChargeAllocator`
   zincirini bağlamak
2. **`paymentTransactionId` yakalama** — ödeme dönüşünde `getPaymentItems()`
   üzerinden `mg_settlement_items` satırlarını doldurmak, `getItemId()` bizim
   `order_product_id` değerini döndürüyor
3. **Teslim tetikleyicisi** — sipariş teslim edildiğinde `approvable_at`
   hesabı (`BusinessDayCalendar::addBusinessDays($teslim, 3)`) ve hakediş fişi
4. **İade akışı** — onay öncesi `disapprove`, onay sonrası ters kayıt + borç

1 ve 2 birlikte gidiyor, 3 artık takvim hazır olduğu için başlanabilir.

Bu dörtlü bitince para uçtan uca akıyor: ödeme alınıyor, kırılım kaydediliyor,
teslimde vade hesaplanıyor, vadesi gelince onaylanıyor, iade gelirse mahsup
ediliyor.
