✨ feat(edl): Ajoute la gestion de l'état des lieux de retour et met à jour les URLs de l'environnement.
This commit is contained in:
6
.env
6
.env
@@ -83,9 +83,9 @@ STRIPE_PK=pk_test_51SUA22173W4aeFB1nO6oFfDZ12HOTffDKtCshhZ8rkUg6kUO2ZaQC0tK72rhE
|
||||
STRIPE_SK=sk_test_51SUA22173W4aeFB16EB2LxGI0hNvNJzFshDI98zRImWBIhSfzqOGAz5TlPxSpUWbj3x4COm6kmSsaal9FpQR1A7M0022DvjbbR
|
||||
STRIPE_WEBHOOKS_SECRET=
|
||||
|
||||
SIGN_URL=https://eefa-82-67-166-187.ngrok-free.app
|
||||
STRIPE_BASEURL=https://eefa-82-67-166-187.ngrok-free.app
|
||||
CONTRAT_BASEURL=https://eefa-82-67-166-187.ngrok-free.app
|
||||
SIGN_URL=https://c55e-82-67-166-187.ngrok-free.app
|
||||
STRIPE_BASEURL=https://c55e-82-67-166-187.ngrok-free.app
|
||||
CONTRAT_BASEURL=https://c55e-82-67-166-187.ngrok-free.app
|
||||
|
||||
MINIO_S3_URL=
|
||||
MINIO_S3_CLIENT_ID=
|
||||
|
||||
@@ -45,7 +45,7 @@ class EtlController extends AbstractController
|
||||
}
|
||||
|
||||
$missions = [];
|
||||
$states = ['ready', 'pending','progress'];
|
||||
$states = ['ready', 'pending', 'progress'];
|
||||
|
||||
$qb = $contratsRepository->createQueryBuilder('c');
|
||||
$qb->select('count(c.id)');
|
||||
@@ -353,10 +353,10 @@ class EtlController extends AbstractController
|
||||
}
|
||||
|
||||
$method = $request->request->get('method');
|
||||
$amount = (float) $request->request->get('amount'); // Optional, or calculate solde
|
||||
$amount = (float)$request->request->get('amount'); // Optional, or calculate solde
|
||||
|
||||
if ($amount <= 0) {
|
||||
// Calculate Solde if not provided
|
||||
// Calculate Solde if not provided
|
||||
$totalHt = 0;
|
||||
$days = ($contrat->getDateAt() && $contrat->getEndAt()) ? ($contrat->getDateAt()->diff($contrat->getEndAt())->days + 1) : 1;
|
||||
foreach ($contrat->getContratsLines() as $line) {
|
||||
@@ -430,6 +430,26 @@ class EtlController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/return', name: 'etl_mission_edl_return', methods: ['GET'])]
|
||||
public function eltEdlReturn(Contrats $contrat): Response
|
||||
{
|
||||
$user = $this->getUser();
|
||||
if (!$user) {
|
||||
return $this->redirectToRoute('etl_login');
|
||||
}
|
||||
|
||||
// Security check
|
||||
if ($user instanceof Prestaire && $contrat->getPrestataire() !== $user) {
|
||||
throw $this->createAccessDeniedException('Vous n\'avez pas accès à cette mission.');
|
||||
}
|
||||
|
||||
return $this->render('etl/edl.twig', [
|
||||
'mission' => $contrat,
|
||||
'etatLieux' => $contrat->getEtatLieux(),
|
||||
'isReturnEdl' => true // Flag to indicate it\'s a return EDL
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/comment', name: 'etl_edl_add_comment', methods: ['POST'])]
|
||||
public function eltEdlAddComment(Contrats $contrat, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
@@ -462,7 +482,7 @@ class EtlController extends AbstractController
|
||||
|
||||
$etatLieux = $contrat->getEtatLieux();
|
||||
if (!$etatLieux) {
|
||||
return $this->redirectToRoute('etl_mission_edl', ['id' => $contrat->getId()]);
|
||||
return $this->redirectToRoute('etl_mission_edl', ['id' => $contrat->getId()]);
|
||||
}
|
||||
|
||||
$data = $request->request->all('points');
|
||||
@@ -501,98 +521,92 @@ class EtlController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/file', name: 'etl_edl_add_file', methods: ['POST'])]
|
||||
public function eltEdlAddFile(Contrats $contrat, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$user = $this->getUser();
|
||||
if (!$user) {
|
||||
return $this->redirectToRoute('etl_login');
|
||||
public function eltEdlAddFile(Contrats $contrat, Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$user = $this->getUser();
|
||||
if (!$user) {
|
||||
return $this->redirectToRoute('etl_login');
|
||||
}
|
||||
|
||||
$photos = $request->files->get('photos');
|
||||
$videos = $request->files->get('videos');
|
||||
$etatLieux = $contrat->getEtatLieux();
|
||||
$hasFiles = false;
|
||||
|
||||
if ($photos) {
|
||||
if (!is_array($photos)) $photos = [$photos];
|
||||
foreach ($photos as $uploadedFile) {
|
||||
if ($uploadedFile instanceof UploadedFile) {
|
||||
$this->compressImage($uploadedFile);
|
||||
$file = new EtatLieuxFile();
|
||||
$file->setFile($uploadedFile);
|
||||
$file->setType('photo');
|
||||
$file->setEtatLieux($etatLieux);
|
||||
$em->persist($file);
|
||||
$hasFiles = true;
|
||||
}
|
||||
|
||||
$photos = $request->files->get('photos');
|
||||
$videos = $request->files->get('videos');
|
||||
$etatLieux = $contrat->getEtatLieux();
|
||||
$hasFiles = false;
|
||||
|
||||
if ($photos) {
|
||||
if (!is_array($photos)) $photos = [$photos];
|
||||
foreach ($photos as $uploadedFile) {
|
||||
if ($uploadedFile instanceof UploadedFile) {
|
||||
$this->compressImage($uploadedFile);
|
||||
$file = new EtatLieuxFile();
|
||||
$file->setFile($uploadedFile);
|
||||
$file->setType('photo');
|
||||
$file->setEtatLieux($etatLieux);
|
||||
$em->persist($file);
|
||||
$hasFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($videos) {
|
||||
if (!is_array($videos)) $videos = [$videos];
|
||||
foreach ($videos as $uploadedFile) {
|
||||
if ($uploadedFile instanceof UploadedFile) {
|
||||
$this->compressVideo($uploadedFile);
|
||||
$file = new EtatLieuxFile();
|
||||
$file->setFile($uploadedFile);
|
||||
$file->setType('video');
|
||||
$file->setEtatLieux($etatLieux);
|
||||
$em->persist($file);
|
||||
$hasFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($hasFiles) {
|
||||
$em->flush();
|
||||
$this->addFlash('success', 'Fichiers ajoutés.');
|
||||
}
|
||||
}
|
||||
if ($videos) {
|
||||
if (!is_array($videos)) $videos = [$videos];
|
||||
foreach ($videos as $uploadedFile) {
|
||||
if ($uploadedFile instanceof UploadedFile) {
|
||||
$this->compressVideo($uploadedFile);
|
||||
$file = new EtatLieuxFile();
|
||||
$file->setFile($uploadedFile);
|
||||
$file->setType('video');
|
||||
$file->setEtatLieux($etatLieux);
|
||||
$em->persist($file);
|
||||
$hasFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($hasFiles) {
|
||||
$em->flush();
|
||||
$this->addFlash('success', 'Fichiers ajoutés.');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('etl_mission_edl', ['id' => $contrat->getId()]);
|
||||
return $this->redirectToRoute('etl_mission_edl', ['id' => $contrat->getId()]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/file/{fileId}/delete', name: 'etl_edl_delete_file', methods: ['POST'])]
|
||||
public function eltEdlDeleteFile(Contrats $contrat, int $fileId, EntityManagerInterface $em): Response
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/file/{fileId}/delete', name: 'etl_edl_delete_file', methods: ['POST'])]
|
||||
{
|
||||
|
||||
public function eltEdlDeleteFile(Contrats $contrat, int $fileId, EntityManagerInterface $em): Response
|
||||
$user = $this->getUser();
|
||||
|
||||
{
|
||||
if (!$user) {
|
||||
|
||||
$user = $this->getUser();
|
||||
return $this->redirectToRoute('etl_login');
|
||||
|
||||
if (!$user) {
|
||||
|
||||
return $this->redirectToRoute('etl_login');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$etatLieux = $contrat->getEtatLieux();
|
||||
|
||||
$etatLieux = $contrat->getEtatLieux();
|
||||
|
||||
$file = $em->getRepository(EtatLieuxFile::class)->find($fileId);
|
||||
$file = $em->getRepository(EtatLieuxFile::class)->find($fileId);
|
||||
|
||||
|
||||
if ($file && $file->getEtatLieux() === $etatLieux) {
|
||||
|
||||
if ($file && $file->getEtatLieux() === $etatLieux) {
|
||||
$em->remove($file);
|
||||
|
||||
$em->remove($file);
|
||||
$em->flush();
|
||||
|
||||
$em->flush();
|
||||
$this->addFlash('success', 'Fichier supprimé.');
|
||||
|
||||
$this->addFlash('success', 'Fichier supprimé.');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $this->redirectToRoute('etl_mission_edl', ['id' => $contrat->getId()]);
|
||||
|
||||
return $this->redirectToRoute('etl_mission_edl', ['id' => $contrat->getId()]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/finish', name: 'etl_edl_finish', methods: ['POST'])]
|
||||
#[Route('/etl/mission/{id}/edl/finish', name: 'etl_edl_finish', methods: ['POST'])]
|
||||
public function eltEdlFinish(Contrats $contrat, EntityManagerInterface $em, KernelInterface $kernel, SignatureClient $signatureClient): Response
|
||||
{
|
||||
$user = $this->getUser();
|
||||
@@ -611,6 +625,28 @@ class EtlController extends AbstractController
|
||||
return $this->redirectToRoute('etl_contrat_view', ['id' => $contrat->getId()]);
|
||||
}
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/return/start', name: 'etl_mission_edl_return_start', methods: ['POST'])]
|
||||
public function eltMissionEdlReturnStart(Contrats $contrat, EntityManagerInterface $em): Response
|
||||
{
|
||||
$user = $this->getUser();
|
||||
if (!$user) {
|
||||
return $this->redirectToRoute('etl_login');
|
||||
}
|
||||
|
||||
if ($user instanceof Prestaire && $contrat->getPrestataire() !== $user) {
|
||||
throw $this->createAccessDeniedException("Vous n'avez pas accès à cette mission.");
|
||||
}
|
||||
|
||||
$etatLieux = $contrat->getEtatLieux();
|
||||
if ($etatLieux) {
|
||||
$etatLieux->setStatus('return_edl_progress');
|
||||
$em->flush();
|
||||
$this->addFlash('success', 'État des lieux de retour commencé.');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('etl_mission_edl_return', ['id' => $contrat->getId()]);
|
||||
}
|
||||
|
||||
#[Route('/etl/mission/{id}/edl/regenerate-view', name: 'etl_edl_regenerate_view', methods: ['GET'])]
|
||||
public function eltEdlRegenerateAndView(Contrats $contrat, EntityManagerInterface $em, KernelInterface $kernel, SignatureClient $signatureClient, UploaderHelper $uploaderHelper): Response
|
||||
{
|
||||
@@ -672,14 +708,16 @@ class EtlController extends AbstractController
|
||||
try {
|
||||
$sub = $signatureClient->getSubmiter($etatLieux->getSignIdDelivery());
|
||||
if ($sub && ($sub['status'] ?? '') === 'completed') $providerSigned = true;
|
||||
} catch (\Exception $e) {}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($etatLieux->getSignIdCustomer()) {
|
||||
try {
|
||||
$sub = $signatureClient->getSubmiter($etatLieux->getSignIdCustomer());
|
||||
if ($sub && ($sub['status'] ?? '') === 'completed') $customerSigned = true;
|
||||
} catch (\Exception $e) {}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('etl/signed_entry_state.twig', [
|
||||
@@ -802,10 +840,11 @@ class EtlController extends AbstractController
|
||||
|
||||
#[Route('/etl/account', name: 'etl_account', methods: ['GET', 'POST'])]
|
||||
public function eltAccount(
|
||||
Request $request,
|
||||
Request $request,
|
||||
UserPasswordHasherInterface $passwordHasher,
|
||||
EntityManagerInterface $entityManager
|
||||
): Response {
|
||||
EntityManagerInterface $entityManager
|
||||
): Response
|
||||
{
|
||||
$user = $this->getUser();
|
||||
if (!$user) {
|
||||
return $this->redirectToRoute('etl_login');
|
||||
|
||||
@@ -67,6 +67,15 @@
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% if providerSigned and customerSigned and etatLieux.status == 'edl_validated' %}
|
||||
<form action="{{ path('etl_mission_edl_return_start', {id: mission.id}) }}" method="post">
|
||||
<button type="submit" class="w-full py-4 bg-orange-600 hover:bg-orange-700 text-white rounded-2xl font-black uppercase text-sm tracking-widest shadow-lg shadow-orange-600/30 transition-all active:scale-95 flex items-center justify-center gap-3 mt-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" /></svg>
|
||||
Faire état des lieux retour
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
{% set is_chorus = (mission.devis and 'Chorus' in mission.devis.paymentMethod) %}
|
||||
|
||||
{% if not is_chorus %}
|
||||
|
||||
|
||||
{# CAUTION #}
|
||||
<div class="bg-white rounded-[2rem] p-6 border border-slate-100 shadow-sm mb-4">
|
||||
<h3 class="text-xs font-black text-slate-400 uppercase tracking-widest mb-4">Caution</h3>
|
||||
@@ -94,7 +94,7 @@
|
||||
<p class="text-xs font-black uppercase tracking-widest">Solde Réglé</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% elseif mission.etatLieux.status == 'edl_progress' %}
|
||||
<a href="{{ path('etl_mission_edl', {id: mission.id}) }}" class="w-full py-4 bg-indigo-600 hover:bg-indigo-500 text-white rounded-2xl font-black uppercase text-sm tracking-widest shadow-lg shadow-indigo-600/30 transition-all active:scale-95 flex items-center justify-center gap-3 mb-6">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
|
||||
@@ -116,6 +116,11 @@
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
|
||||
Reprendre l'état des lieux
|
||||
</a>
|
||||
{% elseif mission.etatLieux.status == 'edl_validated' %}
|
||||
<a href="{{ path('etl_mission_edl_return', {id: mission.id}) }}" class="w-full py-4 bg-indigo-600 hover:bg-indigo-500 text-white rounded-2xl font-black uppercase text-sm tracking-widest shadow-lg shadow-indigo-600/30 transition-all active:scale-95 flex items-center justify-center gap-3 mb-6">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>
|
||||
Commenter l'état des lieux de retour
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{# DATES #}
|
||||
|
||||
Reference in New Issue
Block a user