✅ KDV Sistemi - FINAL Implementation

📅 2025-12-03 | 🎯 Migration YOK! Mevcut base_price Kullanılacak | 🏢 İxtif

🎯 Final Strateji

✅ Basitleştirilmiş Yaklaşım

  • Mevcut base_price = KDV hariç fiyat olarak kullanılacak
  • Mevcut tax_rate = KDV oranı (zaten var)
  • price_with_tax = Accessor ile runtime hesaplanacak
  • Migration GEREKMEZ! Yeni kolon eklenmeyecek

💡 Neden Bu Yaklaşım?

  • ixtif.com ürünleri zaten KDV hariç girilmiş
  • base_price alanı zaten mevcut
  • Gereksiz kolon duplikasyonu yok
  • Daha temiz ve basit

⚠️ Admin UX

İki input olacak:

  • KDV Hariç (base_price) → Editable
  • KDV Dahil (price_with_tax) → Editable

Hangisine girilirse diğeri otomatik hesaplanacak!

Database'e sadece base_price kaydedilecek.

🏗️ Adım 1: ShopProduct Model - Sadece Accessor Ekle

1 Model Accessor Ekle

Dosya: Modules/Shop/app/Models/ShopProduct.php

Konum: getFinalPriceAttribute() metodundan sonra (~line 1325)

/** * KDV dahil fiyat hesaplama (Runtime) * base_price üzerinden hesaplanır */ public function getPriceWithTaxAttribute(): float { if (!$this->base_price) { return 0.0; } $taxRate = $this->tax_rate ?? 20.0; return (float) ($this->base_price * (1 + $taxRate / 100)); } /** * KDV tutarı hesaplama */ public function getTaxAmountAttribute(): float { return $this->price_with_tax - ($this->base_price ?? 0.0); }

💡 Kullanım

$product = ShopProduct::find(1); // Database'den gelir: $product->base_price; // 1000.00 (KDV hariç) $product->tax_rate; // 20.00 // Accessor'dan gelir (hesaplanan): $product->price_with_tax; // 1200.00 $product->tax_amount; // 200.00

🎨 Adım 2: Admin Livewire - İki Input Senkron

2 Livewire Component Güncelle

Dosya: Modules/Shop/app/Http/Livewire/Admin/ShopProductManageComponent.php

// Public properties ekle public $base_price; // KDV hariç (DB'ye kaydedilecek) public $price_with_tax; // KDV dahil (hesaplanan, DB'ye kaydedilmez) public $tax_rate = 20.0; // mount() içinde public function mount($productId = null) { // ... existing code if ($productId) { $product = ShopProduct::find($productId); $this->base_price = $product->base_price; $this->tax_rate = $product->tax_rate ?? 20.0; $this->calculatePriceWithTax(); } } // KDV hariç fiyat değiştiğinde public function updatedBasePrice() { $this->calculatePriceWithTax(); } // KDV dahil fiyat değiştiğinde public function updatedPriceWithTax() { $this->calculateBasePrice(); } // KDV oranı değiştiğinde public function updatedTaxRate() { if ($this->base_price) { $this->calculatePriceWithTax(); } elseif ($this->price_with_tax) { $this->calculateBasePrice(); } } private function calculatePriceWithTax() { if (!$this->base_price || !$this->tax_rate) { $this->price_with_tax = null; return; } $this->price_with_tax = $this->base_price * (1 + $this->tax_rate / 100); } private function calculateBasePrice() { if (!$this->price_with_tax || !$this->tax_rate) { $this->base_price = null; return; } $this->base_price = $this->price_with_tax / (1 + $this->tax_rate / 100); } // save() metodunda public function save() { // ... validation $product->update([ 'base_price' => $this->base_price, // Sadece bu kaydedilir! 'tax_rate' => $this->tax_rate, // price_with_tax KAYDEDİLMEZ! Accessor ile hesaplanır ]); }

3 Blade Template

Dosya: Modules/Shop/resources/views/admin/livewire/shop-product-manage-component.blade.php

<!-- Fiyatlandırma Bölümü --> <div class="row"> <div class="col-md-4"> <div class="mb-3"> <label class="form-label">KDV Hariç Fiyat (₺)</label> <input type="number" wire:model.live="base_price" class="form-control" step="0.01" placeholder="Örnek: 1000.00" > <small class="form-text text-muted"> Buraya girilince KDV dahil otomatik hesaplanır </small> </div> </div> <div class="col-md-4"> <div class="mb-3"> <label class="form-label">KDV Dahil Fiyat (₺)</label> <input type="number" wire:model.live="price_with_tax" class="form-control" step="0.01" placeholder="Örnek: 1200.00" > <small class="form-text text-muted"> Buraya girilince KDV hariç otomatik hesaplanır </small> </div> </div> <div class="col-md-4"> <div class="mb-3"> <label class="form-label">KDV Oranı (%)</label> <input type="number" wire:model.live="tax_rate" class="form-control" step="0.01" > </div> </div> </div> <!-- Fiyat Özeti --> <div class="alert alert-info"> <strong>Özet:</strong> KDV Hariç: {{ number_format($base_price ?? 0, 2) }} ₺ | KDV: {{ number_format(($price_with_tax ?? 0) - ($base_price ?? 0), 2) }} ₺ | KDV Dahil: {{ number_format($price_with_tax ?? 0, 2) }} ₺ </div>

🎨 Admin Panel Görünüm

Ürün Fiyatlandırma

→ KDV dahil otomatik
→ KDV hariç otomatik
KDV Hariç
1.000,00 ₺
KDV Tutarı
200,00 ₺
KDV Dahil
1.200,00 ₺

🌐 Adım 3: Frontend - Ürün Kartları

4 Product Card Component

Dosya: resources/views/components/ixtif/product-card.blade.php

@php // Setting'den gösterim modunu al $displayMode = setting('shop_product_tax', true); // true = KDV dahil, false = KDV hariç @endphp <div class="product-card"> <h3>{{ $product->title }}</h3> <div class="product-price"> @if($displayMode) <!-- KDV Dahil Göster --> <span class="price"> {{ number_format($product->price_with_tax, 2) }} ₺ </span> <small>KDV Dahil</small> @else <!-- KDV Hariç Göster --> <span class="price"> {{ number_format($product->base_price, 2) }} ₺ </span> <small>+ KDV</small> @endif </div> </div>

🛒 Adım 4: CartService - Accessor Kullan

5 CartService Güncelle

Dosya: Modules/Cart/app/Services/CartService.php

protected function setPricing($cartItem, $item, $quantity): void { // Accessor'ları kullan (artık hesaplama yok!) $priceWithoutTax = $item->base_price ?? 0; // KDV hariç $priceWithTax = $item->price_with_tax ?? 0; // KDV dahil (accessor) $taxRate = $item->tax_rate ?? 20.0; // KDV oranı $taxAmount = $priceWithTax - $priceWithoutTax; // KDV tutarı // Cart item'e set et $cartItem->unit_price = $priceWithoutTax; $cartItem->tax_amount = $taxAmount; $cartItem->tax_rate = $taxRate; $cartItem->final_price = $priceWithTax; // HER ZAMAN KDV DAHİL! $cartItem->subtotal = $priceWithoutTax * $quantity; $cartItem->total = $priceWithTax * $quantity; }

💡 Değişiklik

Eski: base_price'dan KDV dahil hesaplıyorduk

Yeni: Accessor'dan direkt alıyoruz (price_with_tax)

✅ Test Planı

6 Test Adımları

  • 1. Model Test:
    • Ürün çek, price_with_tax accessor çalışıyor mu?
    • tax_amount doğru hesaplanıyor mu?
  • 2. Admin Panel Test:
    • KDV hariç gir → KDV dahil otomatik hesaplanmalı
    • KDV dahil gir → KDV hariç otomatik hesaplanmalı
    • Kaydet → Sadece base_price database'e yazılmalı
  • 3. Frontend Test:
    • shop_product_tax = true → KDV dahil görünmeli
    • shop_product_tax = false → KDV hariç + KDV görünmeli
  • 4. Cart Test:
    • Sepete ekle → KDV dahil fiyat görünmeli
    • Toplam hesaplama doğru mu?

🎯 Özet - Yapılacaklar

✅ Basit ve Net!

  1. Model: 2 accessor ekle (~15 satır kod)
  2. Admin Livewire: Senkronizasyon metodları ekle (~40 satır)
  3. Frontend: Accessor kullan (değişiklik minimal)
  4. CartService: Accessor kullan (sadeleşir)
  5. Migration: GEREKMEZ!

⚠️ Önemli Notlar

  • base_price = KDV hariç (zaten öyle kullanılıyor)
  • price_with_tax = Runtime hesaplanan (DB'de yok)
  • Admin'de iki input, ama DB'ye sadece base_price yazılır
  • Cart/Checkout her zaman KDV dahil gösterir

🚀 Hazırım!

"UYGUNDUR" dersen hemen başlıyorum:

  1. Model accessor ekle
  2. Admin Livewire güncelle
  3. Frontend güncelle
  4. CartService güncelle
  5. Cache temizle + test