ajout table thanato dans intervention
This commit is contained in:
parent
a51e05559a
commit
496b427e13
@ -4,11 +4,12 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\StoreInterventionRequest;
|
||||
use App\Http\Requests\StoreInterventionWithAllDataRequest;
|
||||
use App\HttpRequests\StoreInterventionWithAllDataRequest;
|
||||
use App\Http\Requests\UpdateInterventionRequest;
|
||||
use App\Http\Resources\Intervention\InterventionResource;
|
||||
use App\Http\Resources\Intervention\InterventionCollection;
|
||||
use App\Repositories\InterventionRepositoryInterface;
|
||||
use App\Repositories\InterventionPractitionerRepositoryInterface;
|
||||
use App\Repositories\ClientRepositoryInterface;
|
||||
use App\Repositories\ContactRepositoryInterface;
|
||||
use App\Repositories\DeceasedRepositoryInterface;
|
||||
@ -25,6 +26,11 @@ class InterventionController extends Controller
|
||||
*/
|
||||
protected $interventionRepository;
|
||||
|
||||
/**
|
||||
* @var InterventionPractitionerRepositoryInterface
|
||||
*/
|
||||
protected $interventionPractitionerRepository;
|
||||
|
||||
/**
|
||||
* @var ClientRepositoryInterface
|
||||
*/
|
||||
@ -44,17 +50,20 @@ class InterventionController extends Controller
|
||||
* InterventionController constructor.
|
||||
*
|
||||
* @param InterventionRepositoryInterface $interventionRepository
|
||||
* @param InterventionPractitionerRepositoryInterface $interventionPractitionerRepository
|
||||
* @param ClientRepositoryInterface $clientRepository
|
||||
* @param ContactRepositoryInterface $contactRepository
|
||||
* @param DeceasedRepositoryInterface $deceasedRepository
|
||||
*/
|
||||
public function __construct(
|
||||
InterventionRepositoryInterface $interventionRepository,
|
||||
InterventionPractitionerRepositoryInterface $interventionPractitionerRepository,
|
||||
ClientRepositoryInterface $clientRepository,
|
||||
ContactRepositoryInterface $contactRepository,
|
||||
DeceasedRepositoryInterface $deceasedRepository
|
||||
) {
|
||||
$this->interventionRepository = $interventionRepository;
|
||||
$this->interventionPractitionerRepository = $interventionPractitionerRepository;
|
||||
$this->clientRepository = $clientRepository;
|
||||
$this->contactRepository = $contactRepository;
|
||||
$this->deceasedRepository = $deceasedRepository;
|
||||
@ -361,13 +370,13 @@ class InterventionController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a practitioner to an intervention
|
||||
* Create assignment of practitioners to an intervention
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function assignPractitioner(Request $request, int $id): JsonResponse
|
||||
public function createAssignment(Request $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$validated = $request->validate([
|
||||
@ -376,6 +385,7 @@ class InterventionController extends Controller
|
||||
'assistant_practitioner_ids.*' => 'integer|exists:thanatopractitioners,id',
|
||||
]);
|
||||
|
||||
|
||||
$intervention = $this->interventionRepository->findById($id);
|
||||
|
||||
if (!$intervention) {
|
||||
@ -384,41 +394,164 @@ class InterventionController extends Controller
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Sync practitioners with their roles
|
||||
$practitioners = [];
|
||||
|
||||
// Remove existing principal practitioner first
|
||||
if (isset($validated['principal_practitioner_id'])) {
|
||||
$practitioners[$validated['principal_practitioner_id']] = ['role' => 'principal'];
|
||||
$principalId = $validated['principal_practitioner_id'];
|
||||
$this->interventionPractitionerRepository->createAssignment($id, $principalId, 'principal');
|
||||
}
|
||||
|
||||
if (isset($validated['assistant_practitioner_ids'])) {
|
||||
// Handle assistant practitioners
|
||||
if (isset($validated['assistant_practitioner_ids']) && is_array($validated['assistant_practitioner_ids'])) {
|
||||
foreach ($validated['assistant_practitioner_ids'] as $assistantId) {
|
||||
$practitioners[$assistantId] = ['role' => 'assistant'];
|
||||
$this->interventionPractitionerRepository->createAssignment($id, $assistantId, 'assistant');
|
||||
}
|
||||
}
|
||||
|
||||
// Sync the practitioners (this will replace existing assignments)
|
||||
$intervention->practitioners()->sync($practitioners);
|
||||
|
||||
// Reload the intervention with relationships
|
||||
$intervention = $this->interventionRepository->findById($id);
|
||||
// Load the intervention with practitioners to return updated data
|
||||
$intervention->load('practitioners');
|
||||
$practitioners = $intervention->practitioners;
|
||||
|
||||
return response()->json([
|
||||
'data' => new InterventionResource($intervention),
|
||||
'message' => 'Praticien(s) assigné(s) avec succès.'
|
||||
'message' => 'Assignment(s) créé(s) avec succès.',
|
||||
'practitioners_count' => $practitioners->count(),
|
||||
'practitioners' => $practitioners->map(function($p) {
|
||||
return [
|
||||
'id' => $p->id,
|
||||
'full_name' => $p->full_name ?? ($p->first_name . ' ' . $p->last_name),
|
||||
'role' => $p->pivot->role ?? 'unknown'
|
||||
];
|
||||
})->toArray()
|
||||
], Response::HTTP_OK);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error assigning practitioner to intervention: ' . $e->getMessage(), [
|
||||
'intervention_id' => $id,
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Une erreur est survenue lors de la création de l\'assignment.',
|
||||
'error' => $e->getMessage()
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unassign a practitioner from an intervention
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $interventionId
|
||||
* @param int $practitionerId
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function unassignPractitioner(Request $request, int $interventionId, int $practitionerId): JsonResponse
|
||||
{
|
||||
try {
|
||||
Log::info('Unassigning practitioner from intervention', [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId
|
||||
]);
|
||||
|
||||
// Validate that the intervention exists
|
||||
$intervention = $this->interventionRepository->findById($interventionId);
|
||||
|
||||
if (!$intervention) {
|
||||
return response()->json([
|
||||
'message' => 'Intervention non trouvée.'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Check if the practitioner is actually assigned to this intervention
|
||||
$isAssigned = $this->interventionPractitionerRepository->isPractitionerAssigned($interventionId, $practitionerId);
|
||||
|
||||
if (!$isAssigned) {
|
||||
return response()->json([
|
||||
'message' => 'Le praticien n\'est pas assigné à cette intervention.'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Remove the practitioner assignment
|
||||
$deleted = $this->interventionPractitionerRepository->removeAssignment($interventionId, $practitionerId);
|
||||
|
||||
if ($deleted > 0) {
|
||||
Log::info('Practitioner unassigned successfully', [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId,
|
||||
'deleted_records' => $deleted
|
||||
]);
|
||||
|
||||
// Reload intervention with remaining practitioners
|
||||
$intervention->load('practitioners');
|
||||
$remainingPractitioners = $intervention->practitioners;
|
||||
|
||||
return response()->json([
|
||||
'data' => new InterventionResource($intervention),
|
||||
'message' => 'Praticien désassigné avec succès.',
|
||||
'remaining_practitioners_count' => $remainingPractitioners->count(),
|
||||
'remaining_practitioners' => $remainingPractitioners->map(function($p) {
|
||||
return [
|
||||
'id' => $p->id,
|
||||
'employee_name' => $p->employee->full_name ?? ($p->employee->first_name . ' ' . $p->employee->last_name),
|
||||
'role' => $p->pivot->role ?? 'unknown'
|
||||
];
|
||||
})->toArray()
|
||||
], Response::HTTP_OK);
|
||||
} else {
|
||||
Log::warning('No practitioner assignment found to delete', [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Aucun assignment de praticien trouvé à supprimer.'
|
||||
], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error unassigning practitioner from intervention: ' . $e->getMessage(), [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId,
|
||||
'request_data' => $request->all(),
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Une erreur est survenue lors de l\'assignation du praticien.',
|
||||
'message' => 'Une erreur est survenue lors de la désassignation du praticien.',
|
||||
'error' => $e->getMessage()
|
||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug endpoint to check practitioners in database
|
||||
*/
|
||||
public function debugPractitioners(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$intervention = $this->interventionRepository->findById($id);
|
||||
|
||||
// Direct database query
|
||||
$dbPractitioners = DB::table('intervention_practitioner')
|
||||
->where('intervention_id', $id)
|
||||
->get();
|
||||
|
||||
// Eager loaded practitioners
|
||||
$eagerPractitioners = $intervention->practitioners()->get();
|
||||
|
||||
return response()->json([
|
||||
'intervention_id' => $id,
|
||||
'database_records' => $dbPractitioners,
|
||||
'eager_loaded_count' => $eagerPractitioners->count(),
|
||||
'eager_loaded_data' => $eagerPractitioners->map(function($p) {
|
||||
return [
|
||||
'id' => $p->id,
|
||||
'full_name' => $p->full_name ?? ($p->first_name . ' ' . $p->last_name),
|
||||
'role' => $p->pivot->role ?? 'unknown'
|
||||
];
|
||||
})->toArray()
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error in debug practitioners: ' . $e->getMessage());
|
||||
return response()->json(['error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
namespace App\Http\Resources\Employee;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use App\Http\Resources\Employee\EmployeeResource;
|
||||
use App\Http\Resources\Employee\PractitionerDocumentResource;
|
||||
|
||||
class ThanatopractitionerResource extends JsonResource
|
||||
{
|
||||
@ -17,6 +19,10 @@ class ThanatopractitionerResource extends JsonResource
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'employee_id' => $this->employee_id,
|
||||
'employee_name' => $this->when(
|
||||
$this->relationLoaded('employee'),
|
||||
$this->employee->full_name ?? ($this->employee->first_name . ' ' . $this->employee->last_name)
|
||||
),
|
||||
'diploma_number' => $this->diploma_number,
|
||||
'diploma_date' => $this->diploma_date?->format('Y-m-d'),
|
||||
'authorization_number' => $this->authorization_number,
|
||||
|
||||
@ -37,11 +37,44 @@ class InterventionResource extends JsonResource
|
||||
'duration_min' => $this->duration_min,
|
||||
'status' => $this->status,
|
||||
'practitioners' => $this->whenLoaded('practitioners', function () {
|
||||
return ThanatopractitionerResource::collection($this->practitioners);
|
||||
return $this->practitioners->map(function ($practitioner) {
|
||||
return [
|
||||
'id' => $practitioner->id,
|
||||
'employee_id' => $practitioner->employee_id,
|
||||
'employee_name' => $practitioner->employee->full_name ?? ($practitioner->employee->first_name . ' ' . $practitioner->employee->last_name),
|
||||
'diploma_number' => $practitioner->diploma_number,
|
||||
'diploma_date' => $practitioner->diploma_date?->format('Y-m-d'),
|
||||
'authorization_number' => $practitioner->authorization_number,
|
||||
'authorization_issue_date' => $practitioner->authorization_issue_date?->format('Y-m-d'),
|
||||
'authorization_expiry_date' => $practitioner->authorization_expiry_date?->format('Y-m-d'),
|
||||
'notes' => $practitioner->notes,
|
||||
'is_authorization_valid' => $practitioner->is_authorization_valid,
|
||||
'created_at' => $practitioner->created_at?->format('Y-m-d H:i:s'),
|
||||
'updated_at' => $practitioner->updated_at?->format('Y-m-d H:i:s'),
|
||||
'role' => $practitioner->pivot->role ?? null,
|
||||
];
|
||||
});
|
||||
}),
|
||||
'principal_practitioner' => $this->whenLoaded('practitioners', function () {
|
||||
$principal = $this->practitioners->where('pivot.role', 'principal')->first();
|
||||
return $principal ? new ThanatopractitionerResource($principal) : null;
|
||||
if (!$principal) {
|
||||
return null;
|
||||
}
|
||||
return [
|
||||
'id' => $principal->id,
|
||||
'employee_id' => $principal->employee_id,
|
||||
'employee_name' => $principal->employee->full_name ?? ($principal->employee->first_name . ' ' . $principal->employee->last_name),
|
||||
'diploma_number' => $principal->diploma_number,
|
||||
'diploma_date' => $principal->diploma_date?->format('Y-m-d'),
|
||||
'authorization_number' => $principal->authorization_number,
|
||||
'authorization_issue_date' => $principal->authorization_issue_date?->format('Y-m-d'),
|
||||
'authorization_expiry_date' => $principal->authorization_expiry_date?->format('Y-m-d'),
|
||||
'notes' => $principal->notes,
|
||||
'is_authorization_valid' => $principal->is_authorization_valid,
|
||||
'created_at' => $principal->created_at?->format('Y-m-d H:i:s'),
|
||||
'updated_at' => $principal->updated_at?->format('Y-m-d H:i:s'),
|
||||
'role' => $principal->pivot->role ?? null,
|
||||
];
|
||||
}),
|
||||
'attachments_count' => $this->attachments_count,
|
||||
'notes' => $this->notes,
|
||||
|
||||
72
thanasoft-back/app/Models/InterventionPractitioner.php
Normal file
72
thanasoft-back/app/Models/InterventionPractitioner.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class InterventionPractitioner extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'intervention_practitioner';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'intervention_id',
|
||||
'practitioner_id',
|
||||
'role',
|
||||
'assigned_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'assigned_at' => 'datetime'
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the intervention that owns the practitioner assignment.
|
||||
*/
|
||||
public function intervention(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Intervention::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the practitioner assigned to the intervention.
|
||||
*/
|
||||
public function practitioner(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Thanatopractitioner::class, 'practitioner_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to get principal practitioners.
|
||||
*/
|
||||
public function scopePrincipal($query)
|
||||
{
|
||||
return $query->where('role', 'principal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to get assistant practitioners.
|
||||
*/
|
||||
public function scopeAssistant($query)
|
||||
{
|
||||
return $query->where('role', 'assistant');
|
||||
}
|
||||
}
|
||||
@ -60,6 +60,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
$this->app->bind(\App\Repositories\InterventionRepositoryInterface::class, \App\Repositories\InterventionRepository::class);
|
||||
|
||||
$this->app->bind(\App\Repositories\DeceasedRepositoryInterface::class, \App\Repositories\DeceasedRepository::class);
|
||||
|
||||
$this->app->bind(\App\Repositories\InterventionPractitionerRepositoryInterface::class, \App\Repositories\InterventionPractitionerRepository::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\InterventionPractitioner;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class InterventionPractitionerRepository implements InterventionPractitionerRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a new intervention-practitioner assignment.
|
||||
*/
|
||||
public function createAssignment(int $interventionId, int $practitionerId, string $role, ?string $assignedAt = null): InterventionPractitioner
|
||||
{
|
||||
try {
|
||||
// Check if assignment already exists
|
||||
if ($this->isPractitionerAssigned($interventionId, $practitionerId)) {
|
||||
// If exists, update the role
|
||||
$this->updatePractitionerRole($interventionId, $practitionerId, $role);
|
||||
|
||||
// Return the updated record
|
||||
return InterventionPractitioner::where('intervention_id', $interventionId)
|
||||
->where('practitioner_id', $practitionerId)
|
||||
->first();
|
||||
}
|
||||
|
||||
$assignment = InterventionPractitioner::create([
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId,
|
||||
'role' => $role,
|
||||
'assigned_at' => $assignedAt ?: now()
|
||||
]);
|
||||
|
||||
Log::info('Intervention-practitioner assignment created', [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId,
|
||||
'role' => $role,
|
||||
'assignment_id' => $assignment->id
|
||||
]);
|
||||
|
||||
return $assignment;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error creating intervention-practitioner assignment', [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId,
|
||||
'role' => $role,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all practitioner assignments for an intervention.
|
||||
*/
|
||||
public function removeAllAssignments(int $interventionId): int
|
||||
{
|
||||
$deleted = InterventionPractitioner::where('intervention_id', $interventionId)->delete();
|
||||
|
||||
Log::info('Removed all practitioner assignments for intervention', [
|
||||
'intervention_id' => $interventionId,
|
||||
'deleted_count' => $deleted
|
||||
]);
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove specific practitioner assignment.
|
||||
*/
|
||||
public function removeAssignment(int $interventionId, int $practitionerId): int
|
||||
{
|
||||
$deleted = InterventionPractitioner::where('intervention_id', $interventionId)
|
||||
->where('practitioner_id', $practitionerId)
|
||||
->delete();
|
||||
|
||||
if ($deleted > 0) {
|
||||
Log::info('Removed intervention-practitioner assignment', [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId
|
||||
]);
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a practitioner is already assigned to an intervention.
|
||||
*/
|
||||
public function isPractitionerAssigned(int $interventionId, int $practitionerId): bool
|
||||
{
|
||||
return InterventionPractitioner::where('intervention_id', $interventionId)
|
||||
->where('practitioner_id', $practitionerId)
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all practitioner assignments for an intervention.
|
||||
*/
|
||||
public function getAssignmentsForIntervention(int $interventionId)
|
||||
{
|
||||
return InterventionPractitioner::with('practitioner')
|
||||
->where('intervention_id', $interventionId)
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get principal practitioners for an intervention.
|
||||
*/
|
||||
public function getPrincipalPractitioners(int $interventionId)
|
||||
{
|
||||
return InterventionPractitioner::with('practitioner')
|
||||
->where('intervention_id', $interventionId)
|
||||
->principal()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assistant practitioners for an intervention.
|
||||
*/
|
||||
public function getAssistantPractitioners(int $interventionId)
|
||||
{
|
||||
return InterventionPractitioner::with('practitioner')
|
||||
->where('intervention_id', $interventionId)
|
||||
->assistant()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update practitioner role for an intervention.
|
||||
*/
|
||||
public function updatePractitionerRole(int $interventionId, int $practitionerId, string $role): bool
|
||||
{
|
||||
$updated = InterventionPractitioner::where('intervention_id', $interventionId)
|
||||
->where('practitioner_id', $practitionerId)
|
||||
->update([
|
||||
'role' => $role,
|
||||
'assigned_at' => now()
|
||||
]);
|
||||
|
||||
if ($updated > 0) {
|
||||
Log::info('Updated practitioner role for intervention', [
|
||||
'intervention_id' => $interventionId,
|
||||
'practitioner_id' => $practitionerId,
|
||||
'new_role' => $role
|
||||
]);
|
||||
}
|
||||
|
||||
return $updated > 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\InterventionPractitioner;
|
||||
|
||||
interface InterventionPractitionerRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a new intervention-practitioner assignment.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @param int $practitionerId
|
||||
* @param string $role
|
||||
* @param string|null $assignedAt
|
||||
* @return InterventionPractitioner
|
||||
*/
|
||||
public function createAssignment(int $interventionId, int $practitionerId, string $role, ?string $assignedAt = null): InterventionPractitioner;
|
||||
|
||||
/**
|
||||
* Remove all practitioner assignments for an intervention.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @return int
|
||||
*/
|
||||
public function removeAllAssignments(int $interventionId): int;
|
||||
|
||||
/**
|
||||
* Remove specific practitioner assignment.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @param int $practitionerId
|
||||
* @return int
|
||||
*/
|
||||
public function removeAssignment(int $interventionId, int $practitionerId): int;
|
||||
|
||||
/**
|
||||
* Check if a practitioner is already assigned to an intervention.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @param int $practitionerId
|
||||
* @return bool
|
||||
*/
|
||||
public function isPractitionerAssigned(int $interventionId, int $practitionerId): bool;
|
||||
|
||||
/**
|
||||
* Get all practitioner assignments for an intervention.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function getAssignmentsForIntervention(int $interventionId);
|
||||
|
||||
/**
|
||||
* Get principal practitioners for an intervention.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function getPrincipalPractitioners(int $interventionId);
|
||||
|
||||
/**
|
||||
* Get assistant practitioners for an intervention.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function getAssistantPractitioners(int $interventionId);
|
||||
|
||||
/**
|
||||
* Update practitioner role for an intervention.
|
||||
*
|
||||
* @param int $interventionId
|
||||
* @param int $practitionerId
|
||||
* @param string $role
|
||||
* @return bool
|
||||
*/
|
||||
public function updatePractitionerRole(int $interventionId, int $practitionerId, string $role): bool;
|
||||
}
|
||||
@ -55,7 +55,7 @@ class InterventionRepository implements InterventionRepositoryInterface
|
||||
'client',
|
||||
'deceased',
|
||||
'location',
|
||||
'assignedPractitioner'
|
||||
'practitioners'
|
||||
]);
|
||||
|
||||
return $query->paginate($perPage);
|
||||
@ -149,8 +149,43 @@ class InterventionRepository implements InterventionRepositoryInterface
|
||||
|
||||
return Intervention::query()
|
||||
->whereBetween('scheduled_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59'])
|
||||
->with(['client', 'deceased', 'location', 'assignedPractitioner'])
|
||||
->with(['client', 'deceased', 'location', 'practitioners'])
|
||||
->orderBy('scheduled_at', 'asc')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add practitioners to an intervention
|
||||
*
|
||||
* @param Intervention $intervention
|
||||
* @param array $practitionerData
|
||||
* @return array Array with 'principal' and 'assistant' results
|
||||
*/
|
||||
public function addPractitioners(Intervention $intervention, array $practitionerData): array
|
||||
{
|
||||
// This method is deprecated in favor of using InterventionPractitionerRepository directly
|
||||
// Implementation kept for interface compatibility
|
||||
$results = [
|
||||
'principal' => null,
|
||||
'assistant' => []
|
||||
];
|
||||
|
||||
if (isset($practitionerData['principal_practitioner_id'])) {
|
||||
$results['principal'] = [
|
||||
'id' => $practitionerData['principal_practitioner_id'],
|
||||
'status' => 'handled_by_practitioner_repository'
|
||||
];
|
||||
}
|
||||
|
||||
if (isset($practitionerData['assistant_practitioner_ids']) && is_array($practitionerData['assistant_practitioner_ids'])) {
|
||||
foreach ($practitionerData['assistant_practitioner_ids'] as $assistantId) {
|
||||
$results['assistant'][] = [
|
||||
'id' => $assistantId,
|
||||
'status' => 'handled_by_practitioner_repository'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,4 +66,13 @@ interface InterventionRepositoryInterface
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function getByMonth(int $year, int $month): \Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
/**
|
||||
* Add practitioners to an intervention
|
||||
*
|
||||
* @param Intervention $intervention
|
||||
* @param array $practitionerData
|
||||
* @return array Array with 'principal' and 'assistant' results
|
||||
*/
|
||||
public function addPractitioners(Intervention $intervention, array $practitionerData): array;
|
||||
}
|
||||
|
||||
@ -131,7 +131,9 @@ Route::middleware('auth:sanctum')->group(function () {
|
||||
Route::put('/{intervention}', [InterventionController::class, 'update']);
|
||||
Route::delete('/{intervention}', [InterventionController::class, 'destroy']);
|
||||
Route::patch('/{intervention}/status', [InterventionController::class, 'changeStatus']);
|
||||
Route::patch('/{intervention}/assign', [InterventionController::class, 'assignPractitioner']);
|
||||
Route::patch('/{intervention}/assign', [InterventionController::class, 'createAssignment']);
|
||||
Route::patch('/{intervention}/{practitionerId}/unassignPractitioner', [InterventionController::class, 'unassignPractitioner']);
|
||||
Route::get('/{intervention}/debug', [InterventionController::class, 'debugPractitioners']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -19,15 +19,13 @@
|
||||
</template>
|
||||
<template #intervention-detail-sidebar>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<InterventionDetailSidebar
|
||||
:intervention="mappedIntervention"
|
||||
:active-tab="activeTab"
|
||||
:practitioners="practitioners"
|
||||
@change-tab="activeTab = $event"
|
||||
@assign-practitioner="handleAssignPractitioner"
|
||||
/>
|
||||
</div>
|
||||
<InterventionDetailSidebar
|
||||
:intervention="mappedIntervention"
|
||||
:active-tab="activeTab"
|
||||
:practitioners="practitioners"
|
||||
@change-tab="activeTab = $event"
|
||||
@assign-practitioner="handleAssignPractitioner"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #intervention-detail-content>
|
||||
|
||||
@ -27,183 +27,207 @@
|
||||
<template v-else-if="intervention">
|
||||
<!-- Overview Tab -->
|
||||
<div v-if="activeTab === 'overview'" class="tab-pane fade show active">
|
||||
<div class="mb-4">
|
||||
<h6 class="mb-3">Informations Générales</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="info-horizontal">
|
||||
<div class="icon-sm text-center">
|
||||
<i class="fas fa-user text-primary"></i>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p class="text-xs mb-0">
|
||||
<b>Nom du défunt:</b> {{ intervention.defuntName }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header pb-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<h6 class="mb-0">Détails de l'intervention</h6>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-primary ms-auto"
|
||||
@click="toggleEditMode"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i class="fas fa-edit me-1"></i
|
||||
>{{ editMode ? "Sauvegarder" : "Modifier" }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="info-horizontal">
|
||||
<div class="icon-sm text-center">
|
||||
<i class="fas fa-calendar text-primary"></i>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p class="text-xs mb-0">
|
||||
<b>Date:</b> {{ intervention.date }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<!-- Basic Information Card -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<InfoCard
|
||||
title="Informations Générales"
|
||||
icon="fas fa-user text-primary"
|
||||
>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item border-0 ps-0 pt-0 text-sm">
|
||||
<strong class="text-dark">Nom du défunt:</strong>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.defuntName || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
v-model="localIntervention.defuntName"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
<li class="list-group-item border-0 ps-0 text-sm">
|
||||
<strong class="text-dark">Date:</strong>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.date || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
type="datetime-local"
|
||||
v-model="localIntervention.date"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
<li class="list-group-item border-0 ps-0 text-sm">
|
||||
<strong class="text-dark">Lieu:</strong>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.lieux || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
v-model="localIntervention.lieux"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
<li class="list-group-item border-0 ps-0 text-sm">
|
||||
<strong class="text-dark">Durée:</strong>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.duree || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
v-model="localIntervention.duree"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</InfoCard>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="info-horizontal">
|
||||
<div class="icon-sm text-center">
|
||||
<i class="fas fa-map-marker text-primary"></i>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p class="text-xs mb-0">
|
||||
<b>Lieu:</b> {{ intervention.lieux }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Contact Information Card -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<InfoCard
|
||||
title="Contact et Communication"
|
||||
icon="fas fa-phone text-primary"
|
||||
>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item border-0 ps-0 pt-0 text-sm">
|
||||
<strong class="text-dark">Contact familial:</strong>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.contactFamilial || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
v-model="localIntervention.contactFamilial"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
<li class="list-group-item border-0 ps-0 text-sm">
|
||||
<strong class="text-dark">Coordonnées:</strong>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.coordonneesContact || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
v-model="localIntervention.coordonneesContact"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
<li class="list-group-item border-0 ps-0 text-sm">
|
||||
<strong class="text-dark">Type de cérémonie:</strong>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.title || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
v-model="localIntervention.title"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</InfoCard>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="info-horizontal">
|
||||
<div class="icon-sm text-center">
|
||||
<i class="fas fa-clock text-primary"></i>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p class="text-xs mb-0">
|
||||
<b>Durée:</b> {{ intervention.duree }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Additional Information Card (Full Width) -->
|
||||
<div class="col-12 mb-3">
|
||||
<InfoCard
|
||||
title="Informations Supplémentaires"
|
||||
icon="fas fa-info-circle text-info"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item border-0 ps-0 pt-0 text-sm">
|
||||
<strong class="text-dark"
|
||||
>Nombre de personnes attendues:</strong
|
||||
>
|
||||
<span v-if="!editMode" class="ms-2">{{
|
||||
intervention.nombrePersonnes || "-"
|
||||
}}</span>
|
||||
<SoftInput
|
||||
v-else
|
||||
type="number"
|
||||
v-model="localIntervention.nombrePersonnes"
|
||||
class="mt-2"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<template v-if="!editMode">
|
||||
<p class="text-sm">
|
||||
<strong class="text-dark"
|
||||
>Prestations supplémentaires:</strong
|
||||
>
|
||||
<span class="ms-2">{{
|
||||
intervention.prestationsSupplementaires || "-"
|
||||
}}</span>
|
||||
</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="text-sm">
|
||||
<strong class="text-dark"
|
||||
>Prestations supplémentaires:</strong
|
||||
>
|
||||
</p>
|
||||
<SoftInput
|
||||
type="textarea"
|
||||
rows="3"
|
||||
v-model="localIntervention.prestationsSupplementaires"
|
||||
class="mt-2"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</InfoCard>
|
||||
</div>
|
||||
|
||||
<!-- Description Card (Full Width) -->
|
||||
<div class="col-12 mb-3">
|
||||
<InfoCard
|
||||
title="Description"
|
||||
icon="fas fa-file-alt text-warning"
|
||||
>
|
||||
<template v-if="!editMode">
|
||||
<p class="text-sm mb-0">
|
||||
{{
|
||||
intervention.description ||
|
||||
"Aucune description disponible"
|
||||
}}
|
||||
</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<SoftInput
|
||||
type="textarea"
|
||||
rows="3"
|
||||
v-model="localIntervention.description"
|
||||
class="mt-2"
|
||||
/>
|
||||
</template>
|
||||
</InfoCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="mb-3">Contact et Communication</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="info-horizontal">
|
||||
<div class="icon-sm text-center">
|
||||
<i class="fas fa-phone text-primary"></i>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p class="text-xs mb-0">
|
||||
<b>Contact:</b> {{ intervention.contactFamilial }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="info-horizontal">
|
||||
<div class="icon-sm text-center">
|
||||
<i class="fas fa-envelope text-primary"></i>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p class="text-xs mb-0">
|
||||
<b>Coordonnées:</b> {{ intervention.coordonneesContact }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="mb-3">Description</h6>
|
||||
<p class="text-sm">{{ intervention.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Details Tab -->
|
||||
<div v-if="activeTab === 'details'" class="tab-pane fade show active">
|
||||
<div class="mb-4">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h6 class="mb-0">Détails Complets</h6>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm bg-gradient-secondary"
|
||||
@click="toggleEditMode"
|
||||
:disabled="loading"
|
||||
>
|
||||
{{ editMode ? "Sauvegarder" : "Modifier" }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<SoftInput
|
||||
label="Nom du défunt"
|
||||
v-model="localIntervention.defuntName"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
<SoftInput
|
||||
label="Date de l'intervention"
|
||||
type="datetime-local"
|
||||
v-model="localIntervention.date"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
<SoftInput
|
||||
label="Lieu"
|
||||
v-model="localIntervention.lieux"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<SoftInput
|
||||
label="Durée prévue"
|
||||
v-model="localIntervention.duree"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
<SoftInput
|
||||
label="Type de cérémonie"
|
||||
v-model="localIntervention.title"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
<SoftInput
|
||||
label="Contact familial"
|
||||
v-model="localIntervention.contactFamilial"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="mb-3">Informations Suplementaires</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<SoftInput
|
||||
label="Nombre de personnes attendues"
|
||||
type="number"
|
||||
v-model="localIntervention.nombrePersonnes"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<SoftInput
|
||||
label="Prestations supplémentaires"
|
||||
type="textarea"
|
||||
rows="3"
|
||||
v-model="localIntervention.prestationsSupplementaires"
|
||||
:disabled="!editMode"
|
||||
class="mb-3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="d-flex justify-content-end mt-4">
|
||||
<!-- Action Buttons for Overview -->
|
||||
<div class="d-flex justify-content-end mt-3" v-if="editMode">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm bg-gradient-secondary me-2"
|
||||
@ -225,104 +249,157 @@
|
||||
|
||||
<!-- Team Tab -->
|
||||
<div v-if="activeTab === 'team'" class="tab-pane fade show active">
|
||||
<div class="mb-4">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h6 class="mb-0">Équipe Assignée</h6>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm bg-gradient-info"
|
||||
@click="$emit('assign-practitioner')"
|
||||
:disabled="loading"
|
||||
>
|
||||
Gérer l'équipe
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="
|
||||
intervention.practitioners &&
|
||||
intervention.practitioners.length > 0
|
||||
"
|
||||
class="list-group list-group-flush"
|
||||
>
|
||||
<div
|
||||
v-for="(practitioner, index) in intervention.practitioners"
|
||||
:key="index"
|
||||
class="list-group-item d-flex justify-content-between align-items-center border-0 px-0"
|
||||
>
|
||||
<div>
|
||||
<h6 class="text-sm mb-0">
|
||||
{{
|
||||
practitioner.employee?.full_name ||
|
||||
(practitioner.employee?.first_name &&
|
||||
practitioner.employee?.last_name
|
||||
? practitioner.employee.first_name +
|
||||
" " +
|
||||
practitioner.employee.last_name
|
||||
: "Praticien " + (index + 1))
|
||||
}}
|
||||
</h6>
|
||||
<p class="text-xs text-muted mb-0">Praticien</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="text-center py-4">
|
||||
<div class="avatar avatar-xl mb-3">
|
||||
<div
|
||||
class="avatar-title bg-gradient-secondary text-white h5 mb-0"
|
||||
<div class="card">
|
||||
<div class="card-header pb-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<h6 class="mb-0">Équipe Assignée</h6>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-info ms-auto"
|
||||
@click="$emit('assign-practitioner')"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i class="fas fa-user-plus"></i>
|
||||
</div>
|
||||
Ajouter un thanatopracteur
|
||||
</button>
|
||||
</div>
|
||||
<h6 class="text-sm text-muted">Aucun praticien assigné</h6>
|
||||
<p class="text-xs text-muted">
|
||||
Cliquez sur "Gérer l'équipe" pour assigner des praticiens
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<InfoCard
|
||||
title="Praticiens Assignés"
|
||||
icon="fas fa-user-md text-success"
|
||||
>
|
||||
<template
|
||||
v-if="
|
||||
intervention.practitioners &&
|
||||
intervention.practitioners.length > 0
|
||||
"
|
||||
>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-hover align-middle">
|
||||
<thead></thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(
|
||||
practitioner, index
|
||||
) in intervention.practitioners"
|
||||
:key="index"
|
||||
>
|
||||
<td class="ps-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<div
|
||||
class="avatar-placeholder bg-gradient-secondary text-white d-flex align-items-center justify-content-center rounded-circle"
|
||||
>
|
||||
{{ getInitials(practitioner.employee_name) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-0 text-sm">
|
||||
{{ practitioner.employee_name }}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-end pe-3">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-danger"
|
||||
@click="
|
||||
$emit('unassign-practitioner', {
|
||||
practitionerId: practitioner.id,
|
||||
practitionerName: practitioner.employee_name,
|
||||
})
|
||||
"
|
||||
title="Désassigner le praticien"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i class="fas fa-times"></i>
|
||||
<span class="d-none d-sm-inline ms-1"
|
||||
>Désassigner</span
|
||||
>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="text-center py-4">
|
||||
<div class="avatar avatar-xl mb-3">
|
||||
<div
|
||||
class="avatar-title bg-gradient-secondary text-white h5 mb-0"
|
||||
>
|
||||
<i class="fas fa-user-plus"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h6 class="text-sm text-muted">Aucun praticien assigné</h6>
|
||||
<p class="text-xs text-muted mb-3">
|
||||
Cliquez sur "Gérer l'équipe" pour assigner des praticiens
|
||||
</p>
|
||||
</div>
|
||||
</InfoCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Documents Tab -->
|
||||
<div v-if="activeTab === 'documents'" class="tab-pane fade show active">
|
||||
<div class="text-center py-5">
|
||||
<div class="avatar avatar-xl mb-3">
|
||||
<div class="avatar-title bg-gradient-info text-white h5 mb-0">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
<div class="card">
|
||||
<div class="card-header pb-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<h6 class="mb-0">Documents</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="text-center py-5">
|
||||
<div class="avatar avatar-xl mb-3">
|
||||
<div class="avatar-title bg-gradient-info text-white h5 mb-0">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h6 class="text-sm text-muted">Documents</h6>
|
||||
<p class="text-xs text-muted">
|
||||
Interface de gestion des documents à implémenter...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<h6 class="text-sm text-muted">Documents</h6>
|
||||
<p class="text-xs text-muted">
|
||||
Interface de gestion des documents à implémenter...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- History Tab -->
|
||||
<div v-if="activeTab === 'history'" class="tab-pane fade show active">
|
||||
<div class="text-center py-5">
|
||||
<div class="avatar avatar-xl mb-3">
|
||||
<div class="avatar-title bg-gradient-warning text-white h5 mb-0">
|
||||
<i class="fas fa-history"></i>
|
||||
<div class="card">
|
||||
<div class="card-header pb-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<h6 class="mb-0">Historique</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="text-center py-5">
|
||||
<div class="avatar avatar-xl mb-3">
|
||||
<div
|
||||
class="avatar-title bg-gradient-warning text-white h5 mb-0"
|
||||
>
|
||||
<i class="fas fa-history"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h6 class="text-sm text-muted">Historique</h6>
|
||||
<p class="text-xs text-muted">
|
||||
Interface d'historique des modifications à implémenter...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<h6 class="text-sm text-muted">Historique</h6>
|
||||
<p class="text-xs text-muted">
|
||||
Interface d'historique des modifications à implémenter...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Actions -->
|
||||
<hr class="horizontal dark" />
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="d-flex justify-content-between mt-3">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm bg-gradient-danger"
|
||||
@click="$emit('cancel')"
|
||||
:disabled="loading"
|
||||
>
|
||||
Annuler
|
||||
<i class="fas fa-arrow-left me-2"></i>Retour
|
||||
</button>
|
||||
|
||||
<div>
|
||||
@ -338,11 +415,11 @@
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm"
|
||||
:class="`bg-gradient-${intervention.action.color}`"
|
||||
:class="`bg-gradient-${intervention.action?.color || 'primary'}`"
|
||||
@click="saveChanges"
|
||||
:disabled="!hasChanges || loading"
|
||||
>
|
||||
{{ intervention.action.label }}
|
||||
{{ intervention.action?.label || "Sauvegarder" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -358,6 +435,7 @@
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import SoftInput from "@/components/SoftInput.vue";
|
||||
import InfoCard from "@/components/atoms/client/InfoCard.vue";
|
||||
import { defineProps, defineEmits } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
@ -384,6 +462,7 @@ const emit = defineEmits([
|
||||
"update-intervention",
|
||||
"cancel",
|
||||
"assign-practitioner",
|
||||
"unassign-practitioner",
|
||||
]);
|
||||
|
||||
// État local pour l'édition
|
||||
@ -431,4 +510,35 @@ watch(
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
const getInitials = (name) => {
|
||||
if (!name) return "?";
|
||||
return name
|
||||
.split(" ")
|
||||
.map((word) => word[0])
|
||||
.join("")
|
||||
.toUpperCase()
|
||||
.substring(0, 2);
|
||||
};
|
||||
|
||||
const unassignPractitioner = async (practitionerId) => {
|
||||
if (!props.intervention?.id) return;
|
||||
|
||||
try {
|
||||
// Use the intervention store to unassign the practitioner
|
||||
const { useInterventionStore } = await import("@/stores/interventionStore");
|
||||
const interventionStore = useInterventionStore();
|
||||
|
||||
await interventionStore.unassignPractitioner(
|
||||
props.intervention.id,
|
||||
practitionerId
|
||||
);
|
||||
|
||||
// Refresh the intervention data by emitting an event to parent
|
||||
emit("refresh-intervention");
|
||||
} catch (error) {
|
||||
console.error("Error unassigning practitioner:", error);
|
||||
// You might want to show a toast notification here
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -288,6 +288,21 @@ export const InterventionService = {
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unassign a practitioner from intervention
|
||||
*/
|
||||
async unassignPractitioner(
|
||||
interventionId: number,
|
||||
practitionerId: number
|
||||
): Promise<Intervention> {
|
||||
const response = await request<Intervention>({
|
||||
url: `/api/interventions/${interventionId}/${practitionerId}/unassignPractitioner`,
|
||||
method: "patch",
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get interventions by month
|
||||
*/
|
||||
|
||||
@ -559,6 +559,53 @@ export const useInterventionStore = defineStore("intervention", () => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unassign a practitioner from intervention
|
||||
*/
|
||||
const unassignPractitioner = async (
|
||||
interventionId: number,
|
||||
practitionerId: number
|
||||
) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setSuccess(false);
|
||||
|
||||
try {
|
||||
const intervention = await InterventionService.unassignPractitioner(
|
||||
interventionId,
|
||||
practitionerId
|
||||
);
|
||||
|
||||
// Update in the interventions list
|
||||
const index = interventions.value.findIndex(
|
||||
(i) => i.id === intervention.id
|
||||
);
|
||||
if (index !== -1) {
|
||||
interventions.value[index] = intervention;
|
||||
}
|
||||
|
||||
// Update current intervention if it's the one being updated
|
||||
if (
|
||||
currentIntervention.value &&
|
||||
currentIntervention.value.id === intervention.id
|
||||
) {
|
||||
setCurrentIntervention(intervention);
|
||||
}
|
||||
|
||||
setSuccess(true);
|
||||
return intervention;
|
||||
} catch (err: any) {
|
||||
const errorMessage =
|
||||
err.response?.data?.message ||
|
||||
err.message ||
|
||||
"Échec de la désassignation du praticien";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get interventions by month
|
||||
*/
|
||||
@ -651,6 +698,7 @@ export const useInterventionStore = defineStore("intervention", () => {
|
||||
assignPractitioner,
|
||||
assignPractitioners,
|
||||
updatePractitioners,
|
||||
unassignPractitioner,
|
||||
fetchInterventionsByMonth,
|
||||
resetState,
|
||||
};
|
||||
|
||||
@ -47,6 +47,7 @@ const fetchIntervention = async () => {
|
||||
);
|
||||
intervention.value = result; // Store method returns the intervention directly
|
||||
}
|
||||
console.log(intervention.value);
|
||||
} catch (error) {
|
||||
console.error("Error loading intervention:", error);
|
||||
notificationStore.error(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user