Ajout et liste fournisseur
This commit is contained in:
parent
e924c4f819
commit
ca09f6da2f
@ -0,0 +1,208 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\StoreFournisseurRequest;
|
||||||
|
use App\Http\Requests\UpdateFournisseurRequest;
|
||||||
|
use App\Http\Resources\Fournisseur\FournisseurResource;
|
||||||
|
use App\Http\Resources\Fournisseur\FournisseurCollection;
|
||||||
|
use App\Repositories\FournisseurRepositoryInterface;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class FournisseurController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly FournisseurRepositoryInterface $fournisseurRepository
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of fournisseurs.
|
||||||
|
*/
|
||||||
|
public function index(Request $request): FournisseurCollection|JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$perPage = $request->get('per_page', 15);
|
||||||
|
$filters = [
|
||||||
|
'search' => $request->get('search'),
|
||||||
|
'is_active' => $request->get('is_active'),
|
||||||
|
'sort_by' => $request->get('sort_by', 'created_at'),
|
||||||
|
'sort_direction' => $request->get('sort_direction', 'desc'),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Remove null filters
|
||||||
|
$filters = array_filter($filters, function ($value) {
|
||||||
|
return $value !== null && $value !== '';
|
||||||
|
});
|
||||||
|
|
||||||
|
$fournisseurs = $this->fournisseurRepository->paginate($perPage, $filters);
|
||||||
|
|
||||||
|
return new FournisseurCollection($fournisseurs);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error fetching fournisseurs: ' . $e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Une erreur est survenue lors de la récupération des fournisseurs.',
|
||||||
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created fournisseur.
|
||||||
|
*/
|
||||||
|
public function store(StoreFournisseurRequest $request): FournisseurResource|JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$fournisseur = $this->fournisseurRepository->create($request->validated());
|
||||||
|
return new FournisseurResource($fournisseur);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error creating fournisseur: ' . $e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'data' => $request->validated(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Une erreur est survenue lors de la création du fournisseur.',
|
||||||
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified fournisseur.
|
||||||
|
*/
|
||||||
|
public function show(string $id): FournisseurResource|JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$fournisseur = $this->fournisseurRepository->find($id);
|
||||||
|
|
||||||
|
if (!$fournisseur) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Fournisseur non trouvé.',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FournisseurResource($fournisseur);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error fetching fournisseur: ' . $e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'fournisseur_id' => $id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Une erreur est survenue lors de la récupération du fournisseur.',
|
||||||
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchBy(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$name = $request->get('name', '');
|
||||||
|
|
||||||
|
if (empty($name)) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Le paramètre "name" est requis.',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fournisseurs = $this->fournisseurRepository->searchByName($name);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'data' => $fournisseurs,
|
||||||
|
'count' => $fournisseurs->count(),
|
||||||
|
'message' => $fournisseurs->count() > 0
|
||||||
|
? 'Fournisseurs trouvés avec succès.'
|
||||||
|
: 'Aucun fournisseur trouvé.',
|
||||||
|
], 200);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error searching fournisseurs by name: ' . $e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'search_term' => $name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Une erreur est survenue lors de la recherche des fournisseurs.',
|
||||||
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified fournisseur.
|
||||||
|
*/
|
||||||
|
public function update(UpdateFournisseurRequest $request, string $id): FournisseurResource|JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$updated = $this->fournisseurRepository->update($id, $request->validated());
|
||||||
|
|
||||||
|
if (!$updated) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Fournisseur non trouvé ou échec de la mise à jour.',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fournisseur = $this->fournisseurRepository->find($id);
|
||||||
|
return new FournisseurResource($fournisseur);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error updating fournisseur: ' . $e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'fournisseur_id' => $id,
|
||||||
|
'data' => $request->validated(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Une erreur est survenue lors de la mise à jour du fournisseur.',
|
||||||
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified fournisseur.
|
||||||
|
*/
|
||||||
|
public function destroy(string $id): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$deleted = $this->fournisseurRepository->delete($id);
|
||||||
|
|
||||||
|
if (!$deleted) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Fournisseur non trouvé ou échec de la suppression.',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Fournisseur supprimé avec succès.',
|
||||||
|
], 200);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error deleting fournisseur: ' . $e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'fournisseur_id' => $id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Une erreur est survenue lors de la suppression du fournisseur.',
|
||||||
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
thanasoft-back/app/Http/Requests/StoreFournisseurRequest.php
Normal file
59
thanasoft-back/app/Http/Requests/StoreFournisseurRequest.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreFournisseurRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|max:255',
|
||||||
|
'vat_number' => 'nullable|string|max:32',
|
||||||
|
'siret' => 'nullable|string|max:20',
|
||||||
|
'email' => 'nullable|email|max:191',
|
||||||
|
'phone' => 'nullable|string|max:50',
|
||||||
|
'billing_address_line1' => 'nullable|string|max:255',
|
||||||
|
'billing_address_line2' => 'nullable|string|max:255',
|
||||||
|
'billing_postal_code' => 'nullable|string|max:20',
|
||||||
|
'billing_city' => 'nullable|string|max:191',
|
||||||
|
'billing_country_code' => 'nullable|string|size:2',
|
||||||
|
'notes' => 'nullable|string',
|
||||||
|
'is_active' => 'boolean',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name.required' => 'Le nom du fournisseur est obligatoire.',
|
||||||
|
'name.string' => 'Le nom du fournisseur doit être une chaîne de caractères.',
|
||||||
|
'name.max' => 'Le nom du fournisseur ne peut pas dépasser 255 caractères.',
|
||||||
|
'vat_number.max' => 'Le numéro de TVA ne peut pas dépasser 32 caractères.',
|
||||||
|
'siret.max' => 'Le SIRET ne peut pas dépasser 20 caractères.',
|
||||||
|
'email.email' => 'L\'adresse email doit être valide.',
|
||||||
|
'email.max' => 'L\'adresse email ne peut pas dépasser 191 caractères.',
|
||||||
|
'phone.max' => 'Le téléphone ne peut pas dépasser 50 caractères.',
|
||||||
|
'billing_address_line1.max' => 'L\'adresse ne peut pas dépasser 255 caractères.',
|
||||||
|
'billing_address_line2.max' => 'Le complément d\'adresse ne peut pas dépasser 255 caractères.',
|
||||||
|
'billing_postal_code.max' => 'Le code postal ne peut pas dépasser 20 caractères.',
|
||||||
|
'billing_city.max' => 'La ville ne peut pas dépasser 191 caractères.',
|
||||||
|
'billing_country_code.size' => 'Le code pays doit contenir 2 caractères.',
|
||||||
|
'is_active.boolean' => 'Le statut actif doit être vrai ou faux.',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdateFournisseurRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'sometimes|required|string|max:255',
|
||||||
|
'vat_number' => 'nullable|string|max:32',
|
||||||
|
'siret' => 'nullable|string|max:20',
|
||||||
|
'email' => 'nullable|email|max:191',
|
||||||
|
'phone' => 'nullable|string|max:50',
|
||||||
|
'billing_address_line1' => 'nullable|string|max:255',
|
||||||
|
'billing_address_line2' => 'nullable|string|max:255',
|
||||||
|
'billing_postal_code' => 'nullable|string|max:20',
|
||||||
|
'billing_city' => 'nullable|string|max:191',
|
||||||
|
'billing_country_code' => 'nullable|string|size:2',
|
||||||
|
'notes' => 'nullable|string',
|
||||||
|
'is_active' => 'boolean',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name.required' => 'Le nom du fournisseur est obligatoire.',
|
||||||
|
'name.string' => 'Le nom du fournisseur doit être une chaîne de caractères.',
|
||||||
|
'name.max' => 'Le nom du fournisseur ne peut pas dépasser 255 caractères.',
|
||||||
|
'vat_number.max' => 'Le numéro de TVA ne peut pas dépasser 32 caractères.',
|
||||||
|
'siret.max' => 'Le SIRET ne peut pas dépasser 20 caractères.',
|
||||||
|
'email.email' => 'L\'adresse email doit être valide.',
|
||||||
|
'email.max' => 'L\'adresse email ne peut pas dépasser 191 caractères.',
|
||||||
|
'phone.max' => 'Le téléphone ne peut pas dépasser 50 caractères.',
|
||||||
|
'billing_address_line1.max' => 'L\'adresse ne peut pas dépasser 255 caractères.',
|
||||||
|
'billing_address_line2.max' => 'Le complément d\'adresse ne peut pas dépasser 255 caractères.',
|
||||||
|
'billing_postal_code.max' => 'Le code postal ne peut pas dépasser 20 caractères.',
|
||||||
|
'billing_city.max' => 'La ville ne peut pas dépasser 191 caractères.',
|
||||||
|
'billing_country_code.size' => 'Le code pays doit contenir 2 caractères.',
|
||||||
|
'is_active.boolean' => 'Le statut actif doit être vrai ou faux.',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Fournisseur;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class FournisseurCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource collection into an array.
|
||||||
|
*
|
||||||
|
* @return array<int|string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'data' => $this->collection,
|
||||||
|
'meta' => [
|
||||||
|
'total' => $this->total(),
|
||||||
|
'per_page' => $this->perPage(),
|
||||||
|
'current_page' => $this->currentPage(),
|
||||||
|
'last_page' => $this->lastPage(),
|
||||||
|
'from' => $this->firstItem(),
|
||||||
|
'to' => $this->lastItem(),
|
||||||
|
'stats' => [
|
||||||
|
'active' => $this->collection->where('is_active', true)->count(),
|
||||||
|
'inactive' => $this->collection->where('is_active', false)->count(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'links' => [
|
||||||
|
'first' => $this->url(1),
|
||||||
|
'last' => $this->url($this->lastPage()),
|
||||||
|
'prev' => $this->previousPageUrl(),
|
||||||
|
'next' => $this->nextPageUrl(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function with(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => 'Fournisseurs récupérés avec succès',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Fournisseur;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class FournisseurResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'commercial' => $this->commercial(),
|
||||||
|
'name' => $this->name,
|
||||||
|
'vat_number' => $this->vat_number,
|
||||||
|
'siret' => $this->siret,
|
||||||
|
'email' => $this->email,
|
||||||
|
'phone' => $this->phone,
|
||||||
|
'billing_address' => [
|
||||||
|
'line1' => $this->billing_address_line1,
|
||||||
|
'line2' => $this->billing_address_line2,
|
||||||
|
'postal_code' => $this->billing_postal_code,
|
||||||
|
'city' => $this->billing_city,
|
||||||
|
'country_code' => $this->billing_country_code,
|
||||||
|
'full_address' => $this->billing_address,
|
||||||
|
],
|
||||||
|
'notes' => $this->notes,
|
||||||
|
'is_active' => $this->is_active,
|
||||||
|
'created_at' => $this->created_at?->format('Y-m-d H:i:s'),
|
||||||
|
'updated_at' => $this->updated_at?->format('Y-m-d H:i:s'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
54
thanasoft-back/app/Models/Fournisseur.php
Normal file
54
thanasoft-back/app/Models/Fournisseur.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
class Fournisseur extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'vat_number',
|
||||||
|
'siret',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'billing_address_line1',
|
||||||
|
'billing_address_line2',
|
||||||
|
'billing_postal_code',
|
||||||
|
'billing_city',
|
||||||
|
'billing_country_code',
|
||||||
|
'notes',
|
||||||
|
'is_active',
|
||||||
|
'user_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'is_active' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commercial(): ?string
|
||||||
|
{
|
||||||
|
return $this->user ? $this->user->name : 'Système';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full billing address as a string.
|
||||||
|
*/
|
||||||
|
public function getBillingAddressAttribute(): ?string
|
||||||
|
{
|
||||||
|
$parts = array_filter([
|
||||||
|
$this->billing_address_line1,
|
||||||
|
$this->billing_address_line2,
|
||||||
|
$this->billing_postal_code ? $this->billing_postal_code . ' ' . $this->billing_city : $this->billing_city,
|
||||||
|
$this->billing_country_code,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return !empty($parts) ? implode(', ', $parts) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -31,6 +31,10 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
$this->app->bind(\App\Repositories\ClientLocationRepositoryInterface::class, function ($app) {
|
$this->app->bind(\App\Repositories\ClientLocationRepositoryInterface::class, function ($app) {
|
||||||
return new \App\Repositories\ClientLocationRepository($app->make(\App\Models\ClientLocation::class));
|
return new \App\Repositories\ClientLocationRepository($app->make(\App\Models\ClientLocation::class));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->app->bind(\App\Repositories\FournisseurRepositoryInterface::class, function ($app) {
|
||||||
|
return new \App\Repositories\FournisseurRepository($app->make(\App\Models\Fournisseur::class));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
58
thanasoft-back/app/Repositories/FournisseurRepository.php
Normal file
58
thanasoft-back/app/Repositories/FournisseurRepository.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Fournisseur;
|
||||||
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
|
|
||||||
|
class FournisseurRepository extends BaseRepository implements FournisseurRepositoryInterface
|
||||||
|
{
|
||||||
|
public function __construct(Fournisseur $model)
|
||||||
|
{
|
||||||
|
parent::__construct($model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get paginated fournisseurs
|
||||||
|
*/
|
||||||
|
public function paginate(int $perPage = 15, array $filters = []): LengthAwarePaginator
|
||||||
|
{
|
||||||
|
$query = $this->model->newQuery();
|
||||||
|
|
||||||
|
// Apply filters
|
||||||
|
if (!empty($filters['search'])) {
|
||||||
|
$query->where(function ($q) use ($filters) {
|
||||||
|
$q->where('name', 'like', '%' . $filters['search'] . '%')
|
||||||
|
->orWhere('email', 'like', '%' . $filters['search'] . '%')
|
||||||
|
->orWhere('vat_number', 'like', '%' . $filters['search'] . '%')
|
||||||
|
->orWhere('siret', 'like', '%' . $filters['search'] . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filters['is_active'])) {
|
||||||
|
$query->where('is_active', $filters['is_active']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply sorting
|
||||||
|
$sortField = $filters['sort_by'] ?? 'created_at';
|
||||||
|
$sortDirection = $filters['sort_direction'] ?? 'desc';
|
||||||
|
$query->orderBy($sortField, $sortDirection);
|
||||||
|
|
||||||
|
return $query->paginate($perPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchByName(string $name, int $perPage = 15, bool $exactMatch = false)
|
||||||
|
{
|
||||||
|
$query = $this->model->newQuery();
|
||||||
|
|
||||||
|
if ($exactMatch) {
|
||||||
|
$query->where('name', $name);
|
||||||
|
} else {
|
||||||
|
$query->where('name', 'like', '%' . $name . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
|
|
||||||
|
interface FournisseurRepositoryInterface extends BaseRepositoryInterface
|
||||||
|
{
|
||||||
|
public function paginate(int $perPage = 15, array $filters = []): LengthAwarePaginator;
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('fournisseurs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('vat_number', 32)->nullable();
|
||||||
|
$table->string('siret', 20)->nullable();
|
||||||
|
$table->string('email', 191)->nullable();
|
||||||
|
$table->string('phone', 50)->nullable();
|
||||||
|
$table->string('billing_address_line1')->nullable();
|
||||||
|
$table->string('billing_address_line2')->nullable();
|
||||||
|
$table->string('billing_postal_code', 20)->nullable();
|
||||||
|
$table->string('billing_city', 191)->nullable();
|
||||||
|
$table->string('billing_country_code', 2)->nullable();
|
||||||
|
$table->text('notes')->nullable();
|
||||||
|
$table->boolean('is_active')->default(true);
|
||||||
|
$table->foreignId('user_id')->nullable()->constrained()->onDelete('set null');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('fournisseurs');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -7,6 +7,7 @@ use App\Http\Controllers\Api\ClientGroupController;
|
|||||||
use App\Http\Controllers\Api\ClientLocationController;
|
use App\Http\Controllers\Api\ClientLocationController;
|
||||||
use App\Http\Controllers\Api\ContactController;
|
use App\Http\Controllers\Api\ContactController;
|
||||||
use App\Http\Controllers\Api\ClientCategoryController;
|
use App\Http\Controllers\Api\ClientCategoryController;
|
||||||
|
use App\Http\Controllers\Api\FournisseurController;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@ -49,4 +50,7 @@ Route::middleware('auth:sanctum')->group(function () {
|
|||||||
|
|
||||||
Route::apiResource('client-categories', ClientCategoryController::class);
|
Route::apiResource('client-categories', ClientCategoryController::class);
|
||||||
|
|
||||||
|
// Fournisseur management
|
||||||
|
Route::get('/fournisseurs/searchBy', [FournisseurController::class, 'searchBy']);
|
||||||
|
Route::apiResource('fournisseurs', FournisseurController::class);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user