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\Controllers\Controller;
|
||||||
use App\Http\Requests\StoreInterventionRequest;
|
use App\Http\Requests\StoreInterventionRequest;
|
||||||
use App\Http\Requests\StoreInterventionWithAllDataRequest;
|
use App\HttpRequests\StoreInterventionWithAllDataRequest;
|
||||||
use App\Http\Requests\UpdateInterventionRequest;
|
use App\Http\Requests\UpdateInterventionRequest;
|
||||||
use App\Http\Resources\Intervention\InterventionResource;
|
use App\Http\Resources\Intervention\InterventionResource;
|
||||||
use App\Http\Resources\Intervention\InterventionCollection;
|
use App\Http\Resources\Intervention\InterventionCollection;
|
||||||
use App\Repositories\InterventionRepositoryInterface;
|
use App\Repositories\InterventionRepositoryInterface;
|
||||||
|
use App\Repositories\InterventionPractitionerRepositoryInterface;
|
||||||
use App\Repositories\ClientRepositoryInterface;
|
use App\Repositories\ClientRepositoryInterface;
|
||||||
use App\Repositories\ContactRepositoryInterface;
|
use App\Repositories\ContactRepositoryInterface;
|
||||||
use App\Repositories\DeceasedRepositoryInterface;
|
use App\Repositories\DeceasedRepositoryInterface;
|
||||||
@ -25,6 +26,11 @@ class InterventionController extends Controller
|
|||||||
*/
|
*/
|
||||||
protected $interventionRepository;
|
protected $interventionRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var InterventionPractitionerRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $interventionPractitionerRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ClientRepositoryInterface
|
* @var ClientRepositoryInterface
|
||||||
*/
|
*/
|
||||||
@ -44,17 +50,20 @@ class InterventionController extends Controller
|
|||||||
* InterventionController constructor.
|
* InterventionController constructor.
|
||||||
*
|
*
|
||||||
* @param InterventionRepositoryInterface $interventionRepository
|
* @param InterventionRepositoryInterface $interventionRepository
|
||||||
|
* @param InterventionPractitionerRepositoryInterface $interventionPractitionerRepository
|
||||||
* @param ClientRepositoryInterface $clientRepository
|
* @param ClientRepositoryInterface $clientRepository
|
||||||
* @param ContactRepositoryInterface $contactRepository
|
* @param ContactRepositoryInterface $contactRepository
|
||||||
* @param DeceasedRepositoryInterface $deceasedRepository
|
* @param DeceasedRepositoryInterface $deceasedRepository
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
InterventionRepositoryInterface $interventionRepository,
|
InterventionRepositoryInterface $interventionRepository,
|
||||||
|
InterventionPractitionerRepositoryInterface $interventionPractitionerRepository,
|
||||||
ClientRepositoryInterface $clientRepository,
|
ClientRepositoryInterface $clientRepository,
|
||||||
ContactRepositoryInterface $contactRepository,
|
ContactRepositoryInterface $contactRepository,
|
||||||
DeceasedRepositoryInterface $deceasedRepository
|
DeceasedRepositoryInterface $deceasedRepository
|
||||||
) {
|
) {
|
||||||
$this->interventionRepository = $interventionRepository;
|
$this->interventionRepository = $interventionRepository;
|
||||||
|
$this->interventionPractitionerRepository = $interventionPractitionerRepository;
|
||||||
$this->clientRepository = $clientRepository;
|
$this->clientRepository = $clientRepository;
|
||||||
$this->contactRepository = $contactRepository;
|
$this->contactRepository = $contactRepository;
|
||||||
$this->deceasedRepository = $deceasedRepository;
|
$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 Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return JsonResponse
|
* @return JsonResponse
|
||||||
*/
|
*/
|
||||||
public function assignPractitioner(Request $request, int $id): JsonResponse
|
public function createAssignment(Request $request, int $id): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
@ -376,6 +385,7 @@ class InterventionController extends Controller
|
|||||||
'assistant_practitioner_ids.*' => 'integer|exists:thanatopractitioners,id',
|
'assistant_practitioner_ids.*' => 'integer|exists:thanatopractitioners,id',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$intervention = $this->interventionRepository->findById($id);
|
$intervention = $this->interventionRepository->findById($id);
|
||||||
|
|
||||||
if (!$intervention) {
|
if (!$intervention) {
|
||||||
@ -384,41 +394,164 @@ class InterventionController extends Controller
|
|||||||
], Response::HTTP_NOT_FOUND);
|
], Response::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync practitioners with their roles
|
// Remove existing principal practitioner first
|
||||||
$practitioners = [];
|
|
||||||
|
|
||||||
if (isset($validated['principal_practitioner_id'])) {
|
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) {
|
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)
|
// Load the intervention with practitioners to return updated data
|
||||||
$intervention->practitioners()->sync($practitioners);
|
$intervention->load('practitioners');
|
||||||
|
$practitioners = $intervention->practitioners;
|
||||||
// Reload the intervention with relationships
|
|
||||||
$intervention = $this->interventionRepository->findById($id);
|
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'data' => new InterventionResource($intervention),
|
'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);
|
], Response::HTTP_OK);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} 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(),
|
'error' => $e->getMessage(),
|
||||||
'trace' => $e->getTraceAsString()
|
'trace' => $e->getTraceAsString()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return response()->json([
|
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()
|
'error' => $e->getMessage()
|
||||||
], Response::HTTP_INTERNAL_SERVER_ERROR);
|
], 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;
|
namespace App\Http\Resources\Employee;
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use App\Http\Resources\Employee\EmployeeResource;
|
||||||
|
use App\Http\Resources\Employee\PractitionerDocumentResource;
|
||||||
|
|
||||||
class ThanatopractitionerResource extends JsonResource
|
class ThanatopractitionerResource extends JsonResource
|
||||||
{
|
{
|
||||||
@ -17,6 +19,10 @@ class ThanatopractitionerResource extends JsonResource
|
|||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'employee_id' => $this->employee_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_number' => $this->diploma_number,
|
||||||
'diploma_date' => $this->diploma_date?->format('Y-m-d'),
|
'diploma_date' => $this->diploma_date?->format('Y-m-d'),
|
||||||
'authorization_number' => $this->authorization_number,
|
'authorization_number' => $this->authorization_number,
|
||||||
|
|||||||
@ -37,11 +37,44 @@ class InterventionResource extends JsonResource
|
|||||||
'duration_min' => $this->duration_min,
|
'duration_min' => $this->duration_min,
|
||||||
'status' => $this->status,
|
'status' => $this->status,
|
||||||
'practitioners' => $this->whenLoaded('practitioners', function () {
|
'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_practitioner' => $this->whenLoaded('practitioners', function () {
|
||||||
$principal = $this->practitioners->where('pivot.role', 'principal')->first();
|
$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,
|
'attachments_count' => $this->attachments_count,
|
||||||
'notes' => $this->notes,
|
'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\InterventionRepositoryInterface::class, \App\Repositories\InterventionRepository::class);
|
||||||
|
|
||||||
$this->app->bind(\App\Repositories\DeceasedRepositoryInterface::class, \App\Repositories\DeceasedRepository::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',
|
'client',
|
||||||
'deceased',
|
'deceased',
|
||||||
'location',
|
'location',
|
||||||
'assignedPractitioner'
|
'practitioners'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $query->paginate($perPage);
|
return $query->paginate($perPage);
|
||||||
@ -149,8 +149,43 @@ class InterventionRepository implements InterventionRepositoryInterface
|
|||||||
|
|
||||||
return Intervention::query()
|
return Intervention::query()
|
||||||
->whereBetween('scheduled_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59'])
|
->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')
|
->orderBy('scheduled_at', 'asc')
|
||||||
->get();
|
->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
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
*/
|
*/
|
||||||
public function getByMonth(int $year, int $month): \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::put('/{intervention}', [InterventionController::class, 'update']);
|
||||||
Route::delete('/{intervention}', [InterventionController::class, 'destroy']);
|
Route::delete('/{intervention}', [InterventionController::class, 'destroy']);
|
||||||
Route::patch('/{intervention}/status', [InterventionController::class, 'changeStatus']);
|
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>
|
||||||
<template #intervention-detail-sidebar>
|
<template #intervention-detail-sidebar>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<InterventionDetailSidebar
|
||||||
<InterventionDetailSidebar
|
:intervention="mappedIntervention"
|
||||||
:intervention="mappedIntervention"
|
:active-tab="activeTab"
|
||||||
:active-tab="activeTab"
|
:practitioners="practitioners"
|
||||||
:practitioners="practitioners"
|
@change-tab="activeTab = $event"
|
||||||
@change-tab="activeTab = $event"
|
@assign-practitioner="handleAssignPractitioner"
|
||||||
@assign-practitioner="handleAssignPractitioner"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #intervention-detail-content>
|
<template #intervention-detail-content>
|
||||||
|
|||||||
@ -27,183 +27,207 @@
|
|||||||
<template v-else-if="intervention">
|
<template v-else-if="intervention">
|
||||||
<!-- Overview Tab -->
|
<!-- Overview Tab -->
|
||||||
<div v-if="activeTab === 'overview'" class="tab-pane fade show active">
|
<div v-if="activeTab === 'overview'" class="tab-pane fade show active">
|
||||||
<div class="mb-4">
|
<div class="card">
|
||||||
<h6 class="mb-3">Informations Générales</h6>
|
<div class="card-header pb-0">
|
||||||
<div class="row">
|
<div class="d-flex align-items-center">
|
||||||
<div class="col-md-6">
|
<h6 class="mb-0">Détails de l'intervention</h6>
|
||||||
<div class="info-horizontal">
|
<button
|
||||||
<div class="icon-sm text-center">
|
type="button"
|
||||||
<i class="fas fa-user text-primary"></i>
|
class="btn btn-sm btn-primary ms-auto"
|
||||||
</div>
|
@click="toggleEditMode"
|
||||||
<div class="description">
|
:disabled="loading"
|
||||||
<p class="text-xs mb-0">
|
>
|
||||||
<b>Nom du défunt:</b> {{ intervention.defuntName }}
|
<i class="fas fa-edit me-1"></i
|
||||||
</p>
|
>{{ editMode ? "Sauvegarder" : "Modifier" }}
|
||||||
</div>
|
</button>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
</div>
|
||||||
<div class="info-horizontal">
|
<div class="card-body">
|
||||||
<div class="icon-sm text-center">
|
<div class="row">
|
||||||
<i class="fas fa-calendar text-primary"></i>
|
<!-- Basic Information Card -->
|
||||||
</div>
|
<div class="col-md-6 mb-3">
|
||||||
<div class="description">
|
<InfoCard
|
||||||
<p class="text-xs mb-0">
|
title="Informations Générales"
|
||||||
<b>Date:</b> {{ intervention.date }}
|
icon="fas fa-user text-primary"
|
||||||
</p>
|
>
|
||||||
</div>
|
<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>
|
|
||||||
<div class="col-md-6">
|
<!-- Contact Information Card -->
|
||||||
<div class="info-horizontal">
|
<div class="col-md-6 mb-3">
|
||||||
<div class="icon-sm text-center">
|
<InfoCard
|
||||||
<i class="fas fa-map-marker text-primary"></i>
|
title="Contact et Communication"
|
||||||
</div>
|
icon="fas fa-phone text-primary"
|
||||||
<div class="description">
|
>
|
||||||
<p class="text-xs mb-0">
|
<ul class="list-group list-group-flush">
|
||||||
<b>Lieu:</b> {{ intervention.lieux }}
|
<li class="list-group-item border-0 ps-0 pt-0 text-sm">
|
||||||
</p>
|
<strong class="text-dark">Contact familial:</strong>
|
||||||
</div>
|
<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>
|
|
||||||
<div class="col-md-6">
|
<!-- Additional Information Card (Full Width) -->
|
||||||
<div class="info-horizontal">
|
<div class="col-12 mb-3">
|
||||||
<div class="icon-sm text-center">
|
<InfoCard
|
||||||
<i class="fas fa-clock text-primary"></i>
|
title="Informations Supplémentaires"
|
||||||
</div>
|
icon="fas fa-info-circle text-info"
|
||||||
<div class="description">
|
>
|
||||||
<p class="text-xs mb-0">
|
<div class="row">
|
||||||
<b>Durée:</b> {{ intervention.duree }}
|
<div class="col-md-6">
|
||||||
</p>
|
<ul class="list-group list-group-flush">
|
||||||
</div>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-4">
|
<!-- Action Buttons for Overview -->
|
||||||
<h6 class="mb-3">Contact et Communication</h6>
|
<div class="d-flex justify-content-end mt-3" v-if="editMode">
|
||||||
<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">
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-sm bg-gradient-secondary me-2"
|
class="btn btn-sm bg-gradient-secondary me-2"
|
||||||
@ -225,104 +249,157 @@
|
|||||||
|
|
||||||
<!-- Team Tab -->
|
<!-- Team Tab -->
|
||||||
<div v-if="activeTab === 'team'" class="tab-pane fade show active">
|
<div v-if="activeTab === 'team'" class="tab-pane fade show active">
|
||||||
<div class="mb-4">
|
<div class="card">
|
||||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
<div class="card-header pb-0">
|
||||||
<h6 class="mb-0">Équipe Assignée</h6>
|
<div class="d-flex align-items-center">
|
||||||
<button
|
<h6 class="mb-0">Équipe Assignée</h6>
|
||||||
type="button"
|
<button
|
||||||
class="btn btn-sm bg-gradient-info"
|
type="button"
|
||||||
@click="$emit('assign-practitioner')"
|
class="btn btn-sm btn-outline-info ms-auto"
|
||||||
:disabled="loading"
|
@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"
|
|
||||||
>
|
>
|
||||||
<i class="fas fa-user-plus"></i>
|
Ajouter un thanatopracteur
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<h6 class="text-sm text-muted">Aucun praticien assigné</h6>
|
</div>
|
||||||
<p class="text-xs text-muted">
|
<div class="card-body">
|
||||||
Cliquez sur "Gérer l'équipe" pour assigner des praticiens
|
<InfoCard
|
||||||
</p>
|
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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Documents Tab -->
|
<!-- Documents Tab -->
|
||||||
<div v-if="activeTab === 'documents'" class="tab-pane fade show active">
|
<div v-if="activeTab === 'documents'" class="tab-pane fade show active">
|
||||||
<div class="text-center py-5">
|
<div class="card">
|
||||||
<div class="avatar avatar-xl mb-3">
|
<div class="card-header pb-0">
|
||||||
<div class="avatar-title bg-gradient-info text-white h5 mb-0">
|
<div class="d-flex align-items-center">
|
||||||
<i class="fas fa-file-alt"></i>
|
<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>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- History Tab -->
|
<!-- History Tab -->
|
||||||
<div v-if="activeTab === 'history'" class="tab-pane fade show active">
|
<div v-if="activeTab === 'history'" class="tab-pane fade show active">
|
||||||
<div class="text-center py-5">
|
<div class="card">
|
||||||
<div class="avatar avatar-xl mb-3">
|
<div class="card-header pb-0">
|
||||||
<div class="avatar-title bg-gradient-warning text-white h5 mb-0">
|
<div class="d-flex align-items-center">
|
||||||
<i class="fas fa-history"></i>
|
<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>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Navigation Actions -->
|
<!-- Navigation Actions -->
|
||||||
<hr class="horizontal dark" />
|
<div class="d-flex justify-content-between mt-3">
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-sm bg-gradient-danger"
|
class="btn btn-sm bg-gradient-danger"
|
||||||
@click="$emit('cancel')"
|
@click="$emit('cancel')"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
>
|
>
|
||||||
Annuler
|
<i class="fas fa-arrow-left me-2"></i>Retour
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -338,11 +415,11 @@
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-sm"
|
class="btn btn-sm"
|
||||||
:class="`bg-gradient-${intervention.action.color}`"
|
:class="`bg-gradient-${intervention.action?.color || 'primary'}`"
|
||||||
@click="saveChanges"
|
@click="saveChanges"
|
||||||
:disabled="!hasChanges || loading"
|
:disabled="!hasChanges || loading"
|
||||||
>
|
>
|
||||||
{{ intervention.action.label }}
|
{{ intervention.action?.label || "Sauvegarder" }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -358,6 +435,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch } from "vue";
|
import { ref, computed, watch } from "vue";
|
||||||
import SoftInput from "@/components/SoftInput.vue";
|
import SoftInput from "@/components/SoftInput.vue";
|
||||||
|
import InfoCard from "@/components/atoms/client/InfoCard.vue";
|
||||||
import { defineProps, defineEmits } from "vue";
|
import { defineProps, defineEmits } from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -384,6 +462,7 @@ const emit = defineEmits([
|
|||||||
"update-intervention",
|
"update-intervention",
|
||||||
"cancel",
|
"cancel",
|
||||||
"assign-practitioner",
|
"assign-practitioner",
|
||||||
|
"unassign-practitioner",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// État local pour l'édition
|
// État local pour l'édition
|
||||||
@ -431,4 +510,35 @@ watch(
|
|||||||
},
|
},
|
||||||
{ deep: true, immediate: true }
|
{ 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>
|
</script>
|
||||||
|
|||||||
@ -288,6 +288,21 @@ export const InterventionService = {
|
|||||||
return response;
|
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
|
* 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
|
* Get interventions by month
|
||||||
*/
|
*/
|
||||||
@ -651,6 +698,7 @@ export const useInterventionStore = defineStore("intervention", () => {
|
|||||||
assignPractitioner,
|
assignPractitioner,
|
||||||
assignPractitioners,
|
assignPractitioners,
|
||||||
updatePractitioners,
|
updatePractitioners,
|
||||||
|
unassignPractitioner,
|
||||||
fetchInterventionsByMonth,
|
fetchInterventionsByMonth,
|
||||||
resetState,
|
resetState,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -47,6 +47,7 @@ const fetchIntervention = async () => {
|
|||||||
);
|
);
|
||||||
intervention.value = result; // Store method returns the intervention directly
|
intervention.value = result; // Store method returns the intervention directly
|
||||||
}
|
}
|
||||||
|
console.log(intervention.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading intervention:", error);
|
console.error("Error loading intervention:", error);
|
||||||
notificationStore.error(
|
notificationStore.error(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user