254 lines
10 KiB
Python
254 lines
10 KiB
Python
from django.shortcuts import render, get_object_or_404, redirect
|
||
from django.db.models import Sum, Count, Avg, Q
|
||
from django.db import transaction
|
||
from django.core.files.storage import default_storage
|
||
from django.contrib import messages
|
||
from .models import Firma, Fatura, FaturaKalemi
|
||
from .forms import FirmaForm, FaturaForm
|
||
from .utils import extract_text_from_pdf, analyze_invoice_text
|
||
import os
|
||
|
||
def home(request):
|
||
"""Fatura Yönetimi Gösterge Paneli."""
|
||
toplam_firma = Firma.objects.count()
|
||
toplam_fatura = Fatura.objects.count()
|
||
toplam_harcama = Fatura.objects.aggregate(Sum('genel_toplam'))['genel_toplam__sum'] or 0
|
||
son_faturalar = Fatura.objects.select_related('firma').all().order_by('-olusturulma_tarihi')[:10]
|
||
|
||
context = {
|
||
"toplam_firma": toplam_firma,
|
||
"toplam_fatura": toplam_fatura,
|
||
"toplam_harcama": toplam_harcama,
|
||
"son_faturalar": son_faturalar,
|
||
"active_menu": "dashboard"
|
||
}
|
||
return render(request, "core/index.html", context)
|
||
|
||
def fatura_arsivi(request):
|
||
"""Firmalara göre gruplanmış fatura arşivi."""
|
||
firmalar = Firma.objects.annotate(
|
||
fatura_sayisi=Count('faturalar'),
|
||
toplam_tutar=Sum('faturalar__genel_toplam')
|
||
).order_by('ad')
|
||
|
||
context = {
|
||
"firmalar": firmalar,
|
||
"active_menu": "archive"
|
||
}
|
||
return render(request, "core/fatura_arsivi.html", context)
|
||
|
||
def firma_detay(request, pk):
|
||
"""Belirli bir firmanın fatura listesi."""
|
||
firma = get_object_or_404(Firma, pk=pk)
|
||
faturalar = firma.faturalar.all().order_by('-tarih')
|
||
|
||
context = {
|
||
"firma": firma,
|
||
"faturalar": faturalar,
|
||
"active_menu": "archive"
|
||
}
|
||
return render(request, "core/firma_detay.html", context)
|
||
|
||
def fatura_detay(request, pk):
|
||
"""Fatura detay önizleme ve kalemleri."""
|
||
fatura = get_object_or_404(Fatura.objects.select_related('firma'), pk=pk)
|
||
kalemler = fatura.kalemler.all()
|
||
|
||
context = {
|
||
"fatura": fatura,
|
||
"kalemler": kalemler,
|
||
"active_menu": "archive"
|
||
}
|
||
return render(request, "core/fatura_detay.html", context)
|
||
|
||
def raporlar(request):
|
||
"""İstatistik ve Raporlar."""
|
||
# Aylık harcama trendi
|
||
aylik_harcama = Fatura.objects.values('tarih__month').annotate(
|
||
toplam=Sum('genel_toplam'),
|
||
adet=Count('id')
|
||
).order_by('tarih__month')
|
||
|
||
# KDV dağılımı
|
||
kdv_ozet = Fatura.objects.aggregate(
|
||
toplam_kdv=Sum('kdv_toplam'),
|
||
ortalama_kdv=Avg('kdv_toplam')
|
||
)
|
||
|
||
context = {
|
||
"aylik_harcama": aylik_harcama,
|
||
"kdv_ozet": kdv_ozet,
|
||
"active_menu": "reports"
|
||
}
|
||
return render(request, "core/raporlar.html", context)
|
||
|
||
def firma_ekle(request):
|
||
if request.method == 'POST':
|
||
form = FirmaForm(request.POST)
|
||
if form.is_valid():
|
||
form.save()
|
||
return redirect('fatura_arsivi')
|
||
else:
|
||
form = FirmaForm()
|
||
return render(request, 'core/firma_form.html', {'form': form, 'title': 'Yeni Firma Ekle'})
|
||
|
||
def fatura_ekle(request):
|
||
firma_id = request.GET.get('firma')
|
||
initial = {}
|
||
if firma_id:
|
||
initial['firma'] = firma_id
|
||
|
||
if request.method == 'POST':
|
||
form = FaturaForm(request.POST, request.FILES)
|
||
if form.is_valid():
|
||
fatura = form.save()
|
||
return redirect('fatura_detay', pk=fatura.pk)
|
||
else:
|
||
form = FaturaForm(initial=initial)
|
||
return render(request, 'core/fatura_form.html', {'form': form, 'title': 'Yeni Fatura Yükle'})
|
||
|
||
def fatura_otomatik_yukle(request):
|
||
if request.method == 'POST' and request.FILES.get('pdf_dosyasi'):
|
||
pdf_file = request.FILES['pdf_dosyasi']
|
||
|
||
# Save temporary file to extract text
|
||
temp_name = 'temp_' + pdf_file.name
|
||
path = default_storage.save('temp/' + temp_name, pdf_file)
|
||
full_path = default_storage.path(path)
|
||
|
||
try:
|
||
text = extract_text_from_pdf(full_path)
|
||
if not text:
|
||
messages.error(request, "PDF dosyasından metin okunamadı. Dosya taranmış bir resim olabilir veya şifreli olabilir.")
|
||
else:
|
||
data = analyze_invoice_text(text)
|
||
if not data:
|
||
messages.error(request, "Yapay zeka faturayı analiz edemedi. Lütfen dosyanın geçerli bir fatura olduğundan emin olun.")
|
||
else:
|
||
with transaction.atomic():
|
||
# Smarter Firma matching
|
||
vergi_no = str(data.get('vergi_no', '')).strip()
|
||
mersis_no = str(data.get('mersis_no', '')).strip()
|
||
firma_adi = data.get('firma_adi', '').strip() or 'Bilinmeyen Firma'
|
||
|
||
firma = None
|
||
|
||
# 1. Try by Vergi No / TCKN
|
||
if vergi_no and vergi_no != 'None' and vergi_no != 'null':
|
||
firma = Firma.objects.filter(vergi_no=vergi_no).first()
|
||
|
||
# 2. Try by Mersis No
|
||
if not firma and mersis_no and mersis_no != 'None' and mersis_no != 'null':
|
||
firma = Firma.objects.filter(mersis_no=mersis_no).first()
|
||
|
||
# 3. Try by Name (Exact)
|
||
if not firma and firma_adi != 'Bilinmeyen Firma':
|
||
firma = Firma.objects.filter(ad__iexact=firma_adi).first()
|
||
|
||
# 4. Create if not found
|
||
if not firma:
|
||
# Ensure we have a unique vergi_no even if AI failed
|
||
if not vergi_no or vergi_no == 'None' or vergi_no == 'null':
|
||
vergi_no = f"AUTO-{os.urandom(4).hex()}"
|
||
|
||
firma = Firma.objects.create(
|
||
ad=firma_adi,
|
||
vergi_no=vergi_no,
|
||
mersis_no=mersis_no if (mersis_no != 'None' and mersis_no != 'null') else None,
|
||
adres=data.get('adres', '')
|
||
)
|
||
else:
|
||
# Update missing info if found existing firma
|
||
updated = False
|
||
if not firma.mersis_no and mersis_no and mersis_no != 'None' and mersis_no != 'null':
|
||
firma.mersis_no = mersis_no
|
||
updated = True
|
||
if not firma.adres and data.get('adres'):
|
||
firma.adres = data.get('adres')
|
||
updated = True
|
||
if updated:
|
||
firma.save()
|
||
|
||
# Create Fatura
|
||
fatura_no = data.get('fatura_no') or f"AUTO-{os.urandom(4).hex()}"
|
||
|
||
# Check if this invoice already exists for this firm
|
||
fatura = Fatura.objects.filter(fatura_no=fatura_no, firma=firma).first()
|
||
if not fatura:
|
||
fatura = Fatura.objects.create(
|
||
firma=firma,
|
||
fatura_no=fatura_no,
|
||
tarih=data.get('tarih') or '2026-01-01',
|
||
ara_toplam=data.get('ara_toplam') or 0,
|
||
kdv_toplam=data.get('kdv_toplam') or 0,
|
||
genel_toplam=data.get('genel_toplam') or 0,
|
||
pdf_dosyasi=pdf_file,
|
||
islenmis=True
|
||
)
|
||
|
||
# Add Items
|
||
kalemler = data.get('kalemler', [])
|
||
if isinstance(kalemler, list):
|
||
for k in kalemler:
|
||
FaturaKalemi.objects.create(
|
||
fatura=fatura,
|
||
urun_adi=k.get('urun_adi') or 'Ürün',
|
||
adet=k.get('adet') or 1,
|
||
birim_fiyat=k.get('birim_fiyat') or 0,
|
||
kdv_orani=k.get('kdv_orani') or 20,
|
||
kdv_tutari=k.get('kdv_tutari') or 0,
|
||
toplam_tutar=k.get('toplam_tutar') or 0
|
||
)
|
||
|
||
# Clean up temp file
|
||
if default_storage.exists(path):
|
||
default_storage.delete(path)
|
||
|
||
messages.success(request, f"Fatura başarıyla analiz edildi ve {firma.ad} firmasına eklendi.")
|
||
return redirect('fatura_detay', pk=fatura.pk)
|
||
except Exception as e:
|
||
messages.error(request, f"Fatura işlenirken bir hata oluştu: {str(e)}")
|
||
print(f"Error processing automatic invoice: {e}")
|
||
finally:
|
||
# Clean up temp file
|
||
if default_storage.exists(path):
|
||
default_storage.delete(path)
|
||
|
||
return render(request, 'core/fatura_form_otomatik.html', {'title': 'Otomatik Fatura Yükle', 'active_menu': 'dashboard'})
|
||
|
||
def search(request):
|
||
query = request.GET.get('q', '')
|
||
faturalar = []
|
||
firmalar = []
|
||
if query:
|
||
faturalar = Fatura.objects.filter(
|
||
Q(fatura_no__icontains=query) |
|
||
Q(firma__ad__icontains=query)
|
||
).select_related('firma')
|
||
firmalar = Firma.objects.filter(
|
||
Q(ad__icontains=query) |
|
||
Q(vergi_no__icontains=query)
|
||
)
|
||
|
||
context = {
|
||
'query': query,
|
||
'faturalar': faturalar,
|
||
'firmalar': firmalar,
|
||
}
|
||
return render(request, 'core/search_results.html', context)
|
||
|
||
def firma_sil(request, pk):
|
||
firma = get_object_or_404(Firma, pk=pk)
|
||
if request.method == 'POST':
|
||
firma.delete()
|
||
return redirect('fatura_arsivi')
|
||
return render(request, 'core/confirm_delete.html', {'object': firma, 'type': 'Firma'})
|
||
|
||
def fatura_sil(request, pk):
|
||
fatura = get_object_or_404(Fatura, pk=pk)
|
||
firma_pk = fatura.firma.pk
|
||
if request.method == 'POST':
|
||
fatura.delete()
|
||
return redirect('firma_detay', pk=firma_pk)
|
||
return render(request, 'core/confirm_delete.html', {'object': fatura, 'type': 'Fatura'})
|