Merhabalar Ben Veteriner Hekim olarak çalışıyorum bugüne kadar bir çok firmanın yapmış olduğu hazır paketleri kullanmak zorunda kaldık. bazı paketler yeterli oldu bazıları ise tamamen yetersiz bende Laravel ile bir Hasta ve müşteri yönetim takip sistemi yapmaya karar verdim. Bu konuda tavsiyelerinize açığım. Laravel Konusunda Çok yeniyim ama kullandıkça keyif almaya başladım bunuda belirtmeliyim. şimdiden teşekkür ederim.
Veteriner Yönetim Uygulaması için tavsiye Lütfen
- Düzenlendi
Merhaba! Veteriner hekimlik için Laravel ile hasta ve müşteri yönetim takip sistemi geliştirme kararınız çok güzel. Laravel, güçlü ve esnek bir PHP framework'ü olduğundan böyle bir sistem için ideal bir seçim.
Filament ile birlikte bir veteriner kliniği yönetim sistemi için bazı önerilerim şunlar:
<?php
// Ana Modeller
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
// Müşteri (Hayvan Sahibi) Modeli
class Customer extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'name',
'surname',
'phone',
'email',
'address',
'city',
'notes',
'tax_number',
'tax_office',
'balance',
'status',
];
public function pets()
{
return $this->hasMany(Pet::class);
}
public function invoices()
{
return $this->hasMany(Invoice::class);
}
public function appointments()
{
return $this->hasMany(Appointment::class);
}
}
// Evcil Hayvan Modeli
class Pet extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'customer_id',
'name',
'species',
'breed',
'gender',
'date_of_birth',
'color',
'microchip_number',
'weight',
'status',
'notes',
];
protected $casts = [
'date_of_birth' => 'date',
];
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function appointments()
{
return $this->hasMany(Appointment::class);
}
public function medicalRecords()
{
return $this->hasMany(MedicalRecord::class);
}
public function vaccinations()
{
return $this->hasMany(Vaccination::class);
}
}
// Tıbbi Kayıt Modeli
class MedicalRecord extends Model
{
use HasFactory;
protected $fillable = [
'pet_id',
'veterinarian_id',
'date',
'diagnosis',
'treatment',
'notes',
'follow_up_date',
];
protected $casts = [
'date' => 'datetime',
'follow_up_date' => 'date',
];
public function pet()
{
return $this->belongsTo(Pet::class);
}
public function veterinarian()
{
return $this->belongsTo(User::class, 'veterinarian_id');
}
public function prescriptions()
{
return $this->hasMany(Prescription::class);
}
}
// Randevu Modeli
class Appointment extends Model
{
use HasFactory;
protected $fillable = [
'customer_id',
'pet_id',
'veterinarian_id',
'date',
'time',
'reason',
'status',
'notes',
];
protected $casts = [
'date' => 'date',
'time' => 'datetime',
];
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function pet()
{
return $this->belongsTo(Pet::class);
}
public function veterinarian()
{
return $this->belongsTo(User::class, 'veterinarian_id');
}
}
// Aşı Modeli
class Vaccination extends Model
{
use HasFactory;
protected $fillable = [
'pet_id',
'veterinarian_id',
'vaccine_id',
'date',
'expiry_date',
'batch_number',
'notes',
];
protected $casts = [
'date' => 'date',
'expiry_date' => 'date',
];
public function pet()
{
return $this->belongsTo(Pet::class);
}
public function veterinarian()
{
return $this->belongsTo(User::class, 'veterinarian_id');
}
public function vaccine()
{
return $this->belongsTo(Vaccine::class);
}
}
// Aşı Ürünü Modeli
class Vaccine extends Model
{
use HasFactory;
protected $fillable = [
'name',
'manufacturer',
'type',
'description',
'stock',
'price',
];
public function vaccinations()
{
return $this->hasMany(Vaccination::class);
}
}
// İlaç Modeli
class Medication extends Model
{
use HasFactory;
protected $fillable = [
'name',
'description',
'category',
'manufacturer',
'stock',
'unit',
'price',
'expiry_date',
'batch_number',
];
protected $casts = [
'expiry_date' => 'date',
];
public function prescriptions()
{
return $this->belongsToMany(Prescription::class)
->withPivot('dosage', 'instructions', 'quantity')
->withTimestamps();
}
}
// Reçete Modeli
class Prescription extends Model
{
use HasFactory;
protected $fillable = [
'medical_record_id',
'date',
'notes',
];
protected $casts = [
'date' => 'date',
];
public function medicalRecord()
{
return $this->belongsTo(MedicalRecord::class);
}
public function medications()
{
return $this->belongsToMany(Medication::class)
->withPivot('dosage', 'instructions', 'quantity')
->withTimestamps();
}
}
// Fatura Modeli
class Invoice extends Model
{
use HasFactory;
protected $fillable = [
'customer_id',
'invoice_number',
'date',
'due_date',
'total_amount',
'paid_amount',
'payment_status',
'payment_method',
'notes',
];
protected $casts = [
'date' => 'date',
'due_date' => 'date',
];
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function invoiceItems()
{
return $this->hasMany(InvoiceItem::class);
}
}
// Fatura Kalemi Modeli
class InvoiceItem extends Model
{
use HasFactory;
protected $fillable = [
'invoice_id',
'description',
'quantity',
'unit_price',
'tax_rate',
'amount',
];
public function invoice()
{
return $this->belongsTo(Invoice::class);
}
}
// Filament Resource'ları
namespace App\Filament\Resources;
use App\Filament\Resources\CustomerResource\Pages;
use App\Models\Customer;
use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
class CustomerResource extends Resource
{
protected static ?string $model = Customer::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
protected static ?string $navigationGroup = 'Müşteri Yönetimi';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Card::make()
->schema([
Forms\Components\TextInput::make('name')
->label('Ad')
->required(),
Forms\Components\TextInput::make('surname')
->label('Soyad')
->required(),
Forms\Components\TextInput::make('phone')
->label('Telefon')
->tel()
->required(),
Forms\Components\TextInput::make('email')
->label('E-posta')
->email(),
Forms\Components\Textarea::make('address')
->label('Adres')
->rows(3),
Forms\Components\TextInput::make('city')
->label('Şehir'),
Forms\Components\TextInput::make('tax_number')
->label('Vergi No'),
Forms\Components\TextInput::make('tax_office')
->label('Vergi Dairesi'),
Forms\Components\Textarea::make('notes')
->label('Notlar')
->rows(3),
Forms\Components\Select::make('status')
->label('Durum')
->options([
'active' => 'Aktif',
'passive' => 'Pasif',
])
->default('active'),
])->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label('Ad')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('surname')
->label('Soyad')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('phone')
->label('Telefon'),
Tables\Columns\TextColumn::make('email')
->label('E-posta'),
Tables\Columns\BadgeColumn::make('status')
->label('Durum')
->colors([
'success' => 'active',
'danger' => 'passive',
])
->enum([
'active' => 'Aktif',
'passive' => 'Pasif',
]),
Tables\Columns\TextColumn::make('pets_count')
->label('Hayvan Sayısı')
->counts('pets'),
])
->filters([
Tables\Filters\SelectFilter::make('status')
->label('Durum')
->options([
'active' => 'Aktif',
'passive' => 'Pasif',
]),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getRelations(): array
{
return [
RelationManagers\PetsRelationManager::class,
RelationManagers\AppointmentsRelationManager::class,
RelationManagers\InvoicesRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListCustomers::route('/'),
'create' => Pages\CreateCustomer::route('/create'),
'edit' => Pages\EditCustomer::route('/{record}/edit'),
];
}
}
namespace App\Filament\Resources;
use App\Filament\Resources\PetResource\Pages;
use App\Models\Pet;
use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
class PetResource extends Resource
{
protected static ?string $model = Pet::class;
protected static ?string $navigationIcon = 'heroicon-o-heart';
protected static ?string $navigationGroup = 'Hasta Yönetimi';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Card::make()
->schema([
Forms\Components\Select::make('customer_id')
->label('Müşteri')
->relationship('customer', 'name')
->searchable()
->required(),
Forms\Components\TextInput::make('name')
->label('Adı')
->required(),
Forms\Components\Select::make('species')
->label('Tür')
->options([
'dog' => 'Köpek',
'cat' => 'Kedi',
'bird' => 'Kuş',
'rabbit' => 'Tavşan',
'other' => 'Diğer',
])
->required(),
Forms\Components\TextInput::make('breed')
->label('Irk'),
Forms\Components\Select::make('gender')
->label('Cinsiyet')
->options([
'male' => 'Erkek',
'female' => 'Dişi',
'unknown' => 'Bilinmiyor',
]),
Forms\Components\DatePicker::make('date_of_birth')
->label('Doğum Tarihi'),
Forms\Components\TextInput::make('color')
->label('Renk'),
Forms\Components\TextInput::make('microchip_number')
->label('Mikroçip Numarası')
->unique(ignoreRecord: true),
Forms\Components\TextInput::make('weight')
->label('Ağırlık (kg)')
->numeric()
->step(0.01),
Forms\Components\Select::make('status')
->label('Durum')
->options([
'active' => 'Aktif',
'deceased' => 'Vefat Etmiş',
])
->default('active'),
Forms\Components\Textarea::make('notes')
->label('Notlar')
->rows(3),
])->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label('Adı')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('customer.name')
->label('Müşteri')
->searchable()
->sortable(),
Tables\Columns\SelectColumn::make('species')
->label('Tür')
->options([
'dog' => 'Köpek',
'cat' => 'Kedi',
'bird' => 'Kuş',
'rabbit' => 'Tavşan',
'other' => 'Diğer',
]),
Tables\Columns\TextColumn::make('breed')
->label('Irk'),
Tables\Columns\TextColumn::make('date_of_birth')
->label('Doğum Tarihi')
->date(),
Tables\Columns\BadgeColumn::make('status')
->label('Durum')
->colors([
'success' => 'active',
'danger' => 'deceased',
])
->enum([
'active' => 'Aktif',
'deceased' => 'Vefat Etmiş',
]),
])
->filters([
Tables\Filters\SelectFilter::make('species')
->label('Tür')
->options([
'dog' => 'Köpek',
'cat' => 'Kedi',
'bird' => 'Kuş',
'rabbit' => 'Tavşan',
'other' => 'Diğer',
]),
Tables\Filters\SelectFilter::make('status')
->label('Durum')
->options([
'active' => 'Aktif',
'deceased' => 'Vefat Etmiş',
]),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getRelations(): array
{
return [
RelationManagers\MedicalRecordsRelationManager::class,
RelationManagers\VaccinationsRelationManager::class,
RelationManagers\AppointmentsRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListPets::route('/'),
'create' => Pages\CreatePet::route('/create'),
'edit' => Pages\EditPet::route('/{record}/edit'),
];
}
}
// Randevu Dashboard Filament Widget
namespace App\Filament\Widgets;
use App\Models\Appointment;
use Carbon\Carbon;
use Filament\Widgets\TableWidget as BaseWidget;
use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;
class AppointmentsToday extends BaseWidget
{
protected int | string | array $columnSpan = 'full';
protected static ?string $heading = 'Bugünkü Randevular';
protected function getTableQuery(): Builder
{
return Appointment::query()
->where('date', Carbon::today())
->orderBy('time');
}
protected function getTableColumns(): array
{
return [
Tables\Columns\TextColumn::make('time')
->label('Saat')
->time(),
Tables\Columns\TextColumn::make('pet.name')
->label('Hasta'),
Tables\Columns\TextColumn::make('customer.name')
->label('Müşteri'),
Tables\Columns\TextColumn::make('reason')
->label('Sebep')
->limit(30),
Tables\Columns\BadgeColumn::make('status')
->label('Durum')
->colors([
'warning' => 'scheduled',
'success' => 'completed',
'danger' => 'cancelled',
])
->enum([
'scheduled' => 'Planlandı',
'completed' => 'Tamamlandı',
'cancelled' => 'İptal Edildi',
]),
Tables\Columns\TextColumn::make('veterinarian.name')
->label('Veteriner'),
];
}
protected function getTableActions(): array
{
return [
Tables\Actions\Action::make('complete')
->label('Tamamla')
->color('success')
->icon('heroicon-o-check')
->action(function (Appointment $record): void {
$record->update(['status' => 'completed']);
})
->visible(fn (Appointment $record): bool => $record->status === 'scheduled'),
Tables\Actions\Action::make('cancel')
->label('İptal Et')
->color('danger')
->icon('heroicon-o-x')
->action(function (Appointment $record): void {
$record->update(['status' => 'cancelled']);
})
->visible(fn (Appointment $record): bool => $record->status === 'scheduled'),
];
}
}
// Dashboard özeti widget'ı
namespace App\Filament\Widgets;
use App\Models\Appointment;
use App\Models\Customer;
use App\Models\Pet;
use Carbon\Carbon;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Card;
class StatsOverview extends BaseWidget
{
protected function getCards(): array
{
return [
Card::make('Toplam Müşteri', Customer::count())
->description('Sistemde kayıtlı tüm müşteriler')
->descriptionIcon('heroicon-s-users')
->color('success'),
Card::make('Toplam Hasta', Pet::count())
->description('Sistemde kayıtlı tüm hayvanlar')
->descriptionIcon('heroicon-s-heart')
->color('primary'),
Card::make('Bugünkü Randevular', Appointment::whereDate('date', Carbon::today())->count())
->description('Bugün için planlanmış randevular')
->descriptionIcon('heroicon-s-calendar')
->color('warning'),
Card::make('Bu Ayki Randevular', Appointment::whereMonth('date', Carbon::now()->month)
->whereYear('date', Carbon::now()->year)
->count())
->description('Bu ay için planlanmış randevular')
->descriptionIcon('heroicon-s-calendar')
->color('danger'),
];
}
}
Laravel ve Filament ile veteriner kliniğiniz için harika bir yönetim sistemi oluşturabilirsiniz. İşte bazı önerilerim:
Ana Modüller:
- Müşteri (Hayvan Sahipleri) Yönetimi
- Hasta (Hayvanlar) Yönetimi
- Randevu Sistemi
- Tıbbi Kayıtlar
- Aşı Takibi
- Reçete ve İlaç Yönetimi
- Faturalama ve Ödeme Takibi
- Raporlama ve İstatistikler
Filament Admin Panel Kullanımı:
Filament, Laravel üzerinde hızlı ve şık admin panelleri oluşturmanıza olanak tanır. İçerdiği özellikler:- Hazır CRUD (Oluştur-Oku-Güncelle-Sil) işlemleri
- İlişkisel modeller için yönetim arayüzleri
- Dashboard widget'ları
- Form bileşenleri ve doğrulama
- Tablolar, filtreler ve arama özellikleri
Başlarken:
composer require filament/filament php artisan filament:install
Performans için İpuçları:
- İlişkili modelleri eager loading kullanarak yükleyin
- Aşı ve randevu hatırlatmaları için önbellekleme kullanın
- Büyük veri setleri için sayfalama uygulayın
Güvenlik Önlemleri:
- Rol ve izin tabanlı erişim kontrolü ekleyin
- Hassas hasta verilerini şifreleyin
- Yetkilendirme politikaları oluşturun
Artifact'ta sisteminiz için başlangıç kodu modellerini ve Filament resource'larını oluşturdum. Bu modeller arasında müşteriler, hastalar, tıbbi kayıtlar, randevular, aşılar, ilaçlar ve faturalama bulunmakta. Ayrıca, bugünkü randevuları gösteren bir dashboard widget'ı ile temel istatistikler için bir özet widget'ı ekledim.
Başka sorularınız veya ilave ihtiyaçlarınız olursa, lütfen sormaktan çekinmeyin. Laravel ve Filament ile veteriner kliniği yönetim sistemini geliştirme sürecinizde size yardımcı olmaktan memnuniyet duyarim
SencerKahraman https://filamentphp.com/docs inceleyebilirsiniz
- Düzenlendi
Amacınız bir yönetim uygulaması yapmaksa cursor ai ye yaptırın. Öğrenmekse, nacizane tavsiyem neyin ne oldugunu kavrayarak ilerleyin. Örneğin laravel bir php freamworku olmasına rağmen neden node.js e ihtiyaç duyuyor gibi...
koti42
hocam emeğinize sağlık hemen hemen düşündüğüm modeller Müşteri formunu Daha geniş olarak düşündümbu şekilde bir Protokol No Hem Müşteri'de otomatik artan değer olacak hemde Hasta hayvan yönetiminde yapmayı planlıyorum Müşterinin birden fazla hayvanı olduğunda Protokol numarası kullanılabilir Hastanın protokol numarası ise O hastanın yapılan laboratuvar analizleri için daha uygun olur diye düşündüm.
Tab_1 Form
Adı Soyadı
Protokol No
Borç
Ödeme
Bakiye
İletişim Tipi
Sms-Email-Gsm
Telefon
Kimlik No
Açıklama
adres Tab_2 Form
Şehir
ilçe
Köy-Mahalle
adres
özel Tab_3
Durum
Beni Uyar
Meslek
doğum Tarihi
Tüzel mi Evet-Hayır
Tüzel Ünvan
Vergi No
Vergi Dairesi
koti42 hocam merhaba bu yazılımla ilgili bir süre ara verdim yazmaya ve bu konuda zamanınız varsa kontrol edebilir miyiz uzak bağlantıyla takıldığım bir yer vardı en son kafam karıştı.
umutcankarce Çok fazla bir vaktim olmuyor ama takıldığın yeri paylaşabilirsen yardımcı olurum elbette
umutcankarce sizde mi bu yazılımdan yapıyorsunuz hocam ?