139 lines
4.2 KiB
PHP
139 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Repositories;
|
|
|
|
use App\Models\Product;
|
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
|
|
|
class ProductRepository extends BaseRepository implements ProductRepositoryInterface
|
|
{
|
|
public function __construct(Product $model)
|
|
{
|
|
parent::__construct($model);
|
|
}
|
|
|
|
/**
|
|
* Get paginated products with filters
|
|
*/
|
|
public function paginate(int $perPage = 15, array $filters = []): LengthAwarePaginator
|
|
{
|
|
$query = $this->model->newQuery()->with('fournisseur');
|
|
|
|
// Apply filters
|
|
if (!empty($filters['search'])) {
|
|
$query->where(function ($q) use ($filters) {
|
|
$q->where('nom', 'like', '%' . $filters['search'] . '%')
|
|
->orWhere('reference', 'like', '%' . $filters['search'] . '%')
|
|
->orWhere('categorie', 'like', '%' . $filters['search'] . '%')
|
|
->orWhere('fabricant', 'like', '%' . $filters['search'] . '%');
|
|
});
|
|
}
|
|
|
|
if (!empty($filters['categorie'])) {
|
|
$query->where('categorie', $filters['categorie']);
|
|
}
|
|
|
|
if (!empty($filters['fournisseur_id'])) {
|
|
$query->where('fournisseur_id', $filters['fournisseur_id']);
|
|
}
|
|
|
|
if (isset($filters['low_stock'])) {
|
|
$query->whereRaw('stock_actuel <= stock_minimum');
|
|
}
|
|
|
|
if (isset($filters['expiring_soon'])) {
|
|
$query->where('date_expiration', '<=', now()->addDays(30)->toDateString())
|
|
->where('date_expiration', '>=', now()->toDateString());
|
|
}
|
|
|
|
// Apply sorting
|
|
$sortField = $filters['sort_by'] ?? 'created_at';
|
|
$sortDirection = $filters['sort_direction'] ?? 'desc';
|
|
$query->orderBy($sortField, $sortDirection);
|
|
|
|
return $query->paginate($perPage);
|
|
}
|
|
|
|
/**
|
|
* Get products with low stock
|
|
*/
|
|
public function getLowStockProducts(int $perPage = 15): LengthAwarePaginator
|
|
{
|
|
return $this->model->newQuery()
|
|
->with('fournisseur')
|
|
->whereRaw('stock_actuel <= stock_minimum')
|
|
->orderBy('stock_actuel', 'asc')
|
|
->paginate($perPage);
|
|
}
|
|
|
|
/**
|
|
* Search products by name
|
|
*/
|
|
public function searchByName(string $name, int $perPage = 15, bool $exactMatch = false)
|
|
{
|
|
$query = $this->model->newQuery()->with('fournisseur');
|
|
|
|
if ($exactMatch) {
|
|
$query->where('nom', $name);
|
|
} else {
|
|
$query->where('nom', 'like', '%' . $name . '%');
|
|
}
|
|
|
|
return $query->paginate($perPage);
|
|
}
|
|
|
|
/**
|
|
* Get products by category
|
|
*/
|
|
public function getByCategory(string $category, int $perPage = 15): LengthAwarePaginator
|
|
{
|
|
return $this->model->newQuery()
|
|
->with('fournisseur')
|
|
->where('categorie', $category)
|
|
->orderBy('nom')
|
|
->paginate($perPage);
|
|
}
|
|
|
|
/**
|
|
* Get products by fournisseur
|
|
*/
|
|
public function getProductsByFournisseur(int $fournisseurId): LengthAwarePaginator
|
|
{
|
|
return $this->model->newQuery()
|
|
->where('fournisseur_id', $fournisseurId)
|
|
->orderBy('nom')
|
|
->paginate(15);
|
|
}
|
|
|
|
/**
|
|
* Update stock quantity
|
|
*/
|
|
public function updateStock(int $productId, float $newQuantity): bool
|
|
{
|
|
return $this->model->where('id', $productId)
|
|
->update(['stock_actuel' => $newQuantity]) > 0;
|
|
}
|
|
|
|
/**
|
|
* Get product statistics
|
|
*/
|
|
public function getStatistics(): array
|
|
{
|
|
$totalProducts = $this->model->count();
|
|
$lowStockProducts = $this->model->whereRaw('stock_actuel <= stock_minimum')->count();
|
|
$expiringProducts = $this->model->where('date_expiration', '<=', now()->addDays(30)->toDateString())
|
|
->where('date_expiration', '>=', now()->toDateString())
|
|
->count();
|
|
$totalValue = $this->model->sum(\DB::raw('stock_actuel * prix_unitaire'));
|
|
|
|
return [
|
|
'total_products' => $totalProducts,
|
|
'low_stock_products' => $lowStockProducts,
|
|
'expiring_products' => $expiringProducts,
|
|
'total_value' => $totalValue,
|
|
];
|
|
}
|
|
}
|