✨ feat(admin): Ajoute une modale de confirmation pour copier/supprimer un client.
🐛 fix(CustomerCommand): Corrige la suppression des données liées au client. 🎨 style(admin): Ajoute le style de la modale de confirmation. ➕ feat(CustomerCommand): Ajoute une commande pour purger les clients supprimés. 🛠️ chore(ansible): Ajoute une tâche cron pour purger les clients supprimés. 🗑️ feat(CustomerController): Ajoute une suppression forcée d'un client.
This commit is contained in:
@@ -195,6 +195,14 @@
|
||||
chdir: "{{ path }}"
|
||||
when: ansible_os_family == "Debian" # Added a when condition here, often missed
|
||||
|
||||
- name: "Cron Task purge customer delete"
|
||||
cron:
|
||||
name: "Mainframe - Purge customer"
|
||||
minute: "0"
|
||||
hour: "21"
|
||||
job: "php {{ site_path }}/bin/console mainframe:cron:customer"
|
||||
user: root
|
||||
|
||||
# Ensure final state of /public/media, if you want 'bot' to own it for uploads
|
||||
- name: Final check for public/media ownership and permissions
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -9,10 +9,12 @@ import {OrderCtrl} from './class/OrderCtrl'
|
||||
import {LockdownWall} from './class/LockdownWall'
|
||||
import {SecurityWall} from './class/SecurityWall'
|
||||
import {IpWall} from './class/IpWall'
|
||||
import {ConfirmModal} from './class/ConfirmModal'
|
||||
import preactCustomElement from './functions/preact'
|
||||
|
||||
|
||||
function script() {
|
||||
customElements.define('confirm-modal',ConfirmModal,{extends:'a'})
|
||||
customElements.define('auto-submit',AutoSubmit,{extends:'form'})
|
||||
customElements.define('server-card',ServerCard,{extends:'div'})
|
||||
customElements.define('auto-customer',AutoCustomer,{extends:'button'})
|
||||
|
||||
@@ -410,3 +410,28 @@ lockdown-wall-item{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
confirm-modal{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9000;
|
||||
background: rgba(0,0,0,0.5);
|
||||
backdrop-filter: blur(5px);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.confirm-modal-content{
|
||||
width: 50%;
|
||||
padding: 0.5rem;
|
||||
background: #1a202c;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
69
assets/class/ConfirmModal.js
Normal file
69
assets/class/ConfirmModal.js
Normal file
@@ -0,0 +1,69 @@
|
||||
export class ConfirmModal extends HTMLAnchorElement{
|
||||
connectedCallback() {
|
||||
let element = this;
|
||||
|
||||
element.addEventListener('click',btn=>{
|
||||
btn.preventDefault();
|
||||
|
||||
let modalConfirm = document.createElement('confirm-modal');
|
||||
modalConfirm.innerHTML = `<div class="confirm-modal-content"></div>`;
|
||||
if(element.getAttribute('type') == "cp-customer") {
|
||||
this.copyCustomer(modalConfirm,element.getAttribute('href'));
|
||||
}
|
||||
if(element.getAttribute('type') == "delete-customer") {
|
||||
this.deleteCustomer(modalConfirm,element.getAttribute('href'));
|
||||
}
|
||||
document.body.appendChild(modalConfirm);
|
||||
})
|
||||
}
|
||||
|
||||
deleteCustomer(modalConfirm,link) {
|
||||
let message = document.createElement('h2');
|
||||
message.innerText = "Confirmer la suppression du client";
|
||||
modalConfirm.querySelector('.confirm-modal-content').appendChild(message);
|
||||
|
||||
let grid = document.createElement('div')
|
||||
grid.classList = "grid grid-cols-1 gap-4 md:grid-cols-2";
|
||||
modalConfirm.querySelector('.confirm-modal-content').appendChild(grid);
|
||||
|
||||
let buttonOk = document.createElement('button');
|
||||
buttonOk.classList = "bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded";
|
||||
buttonOk.innerText = "Oui";
|
||||
buttonOk.addEventListener('click',()=>{
|
||||
modalConfirm.remove()
|
||||
location.href = link;
|
||||
})
|
||||
|
||||
let buttonKo = document.createElement('button');
|
||||
buttonKo.classList = "bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded";
|
||||
buttonKo.innerText = "Non";
|
||||
buttonKo.addEventListener('click',()=>modalConfirm.remove())
|
||||
grid.appendChild(buttonOk)
|
||||
grid.appendChild(buttonKo)
|
||||
}
|
||||
|
||||
copyCustomer(modalConfirm,link) {
|
||||
let message = document.createElement('h2');
|
||||
message.innerText = "Confirmer la copie du client";
|
||||
modalConfirm.querySelector('.confirm-modal-content').appendChild(message);
|
||||
|
||||
let grid = document.createElement('div')
|
||||
grid.classList = "grid grid-cols-1 gap-4 md:grid-cols-2";
|
||||
modalConfirm.querySelector('.confirm-modal-content').appendChild(grid);
|
||||
|
||||
let buttonOk = document.createElement('button');
|
||||
buttonOk.classList = "bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded";
|
||||
buttonOk.innerText = "Oui";
|
||||
buttonOk.addEventListener('click',()=>{
|
||||
modalConfirm.remove()
|
||||
location.href = link;
|
||||
})
|
||||
|
||||
let buttonKo = document.createElement('button');
|
||||
buttonKo.classList = "bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded";
|
||||
buttonKo.innerText = "Non";
|
||||
buttonKo.addEventListener('click',()=>modalConfirm.remove())
|
||||
grid.appendChild(buttonOk)
|
||||
grid.appendChild(buttonKo)
|
||||
}
|
||||
}
|
||||
49
src/Command/CustomerCommand.php
Normal file
49
src/Command/CustomerCommand.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Account;
|
||||
use App\Entity\Customer;
|
||||
use App\Service\Generator\TempPasswordGenerator;
|
||||
use App\Service\Mailer\Event\CreatedAdminEvent;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
#[AsCommand(name: 'mainframe:cron:customer')]
|
||||
class CustomerCommand extends Command
|
||||
{
|
||||
public function __construct(private readonly EventDispatcherInterface $eventDispatcher, private readonly EntityManagerInterface $entityManager, ?string $name = null)
|
||||
{
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title("Purge all customer delete");
|
||||
foreach ($this->entityManager->getRepository(Customer::class)->findBy(['isDeleted'=>true]) as $delete) {
|
||||
$io->info("Delete account - ".$delete->getRaisonSocial());
|
||||
foreach ($delete->getCustomerContacts()as $customerContact) {
|
||||
$this->entityManager->remove($customerContact);
|
||||
}
|
||||
foreach ($delete->getCustomerAdvertPayments() as $customerAdvertPayment) {
|
||||
$this->entityManager->remove($customerAdvertPayment);
|
||||
}
|
||||
foreach ($delete->getCustomerDevis() as $customerDevis) {
|
||||
$this->entityManager->remove($customerDevis);
|
||||
}
|
||||
$this->entityManager->remove($delete);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,22 @@ class CustomerController extends AbstractController
|
||||
$eventDispatcher->dispatch(new DeleteCustomerEvent($customer));
|
||||
return $this->redirectToRoute('artemis_intranet_customer');
|
||||
}
|
||||
#[Route(path: '/artemis/intranet/customer/forced/{id}',name: 'artemis_intranet_customer_forced',methods: ['GET', 'POST'])]
|
||||
public function customerForced(?Customer $customer,LoggerService $loggerService,EntityManagerInterface $entityManager,Request $request,PaginatorInterface $paginator): Response
|
||||
{
|
||||
if(!$customer instanceof Customer){
|
||||
return $this->redirectToRoute('artemis_intranet_customer');
|
||||
}
|
||||
$loggerService->log('DELETE',"Suppression accélérer d'un client - ".$customer->getRaisonSocial(),$this->getUser());
|
||||
foreach ($customer->getCustomerContacts() as $customerContact) {
|
||||
$entityManager->remove($customerContact);
|
||||
}
|
||||
$entityManager->remove($customer);
|
||||
$entityManager->flush();
|
||||
$this->addFlash("success","Suppression effectuée");
|
||||
|
||||
return $this->redirectToRoute('artemis_intranet_customer');
|
||||
}
|
||||
|
||||
#[Route(path: '/artemis/intranet/customer/restore/{id}',name: 'artemis_intranet_customer_restore',methods: ['GET', 'POST'])]
|
||||
public function customerRestore(?Customer $customer,LoggerService $loggerService,EntityManagerInterface $entityManager,EventDispatcherInterface $eventDispatcher): Response
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-700">
|
||||
{% for customer in customers %}
|
||||
|
||||
<tr class="hover:bg-gray-700 transition relative hover:bg-gray-700 transition">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="text-sm font-semibold">{{ customer.type|trans }} - {{ customer.raisonSocial }}</div>
|
||||
@@ -76,9 +75,12 @@
|
||||
<td class="px-6 py-4 text-center text-sm">0</td>
|
||||
<td class="px-6 py-4 text-center text-sm text-green-500 font-bold">Non</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-center">
|
||||
<a href="{{ path('artemis_intranet_customer',{idCopy:customer.id}) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Copier le client</a>
|
||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id}) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Voir</a>
|
||||
<a href="{{ path('artemis_intranet_customer_delete',{id:customer.id}) }}" class="bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded">Supprimer</a>
|
||||
<a data-turbo="false" is="confirm-modal" type="cp-customer" href="{{ path('artemis_intranet_customer',{idCopy:customer.id}) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Copier le client</a>
|
||||
|
||||
{% if customer.customerOrders.count <=0 and customer.customerDns.count <=0 %}
|
||||
<a data-turbo="false" is="confirm-modal" type="delete-customer" href="{{ path('artemis_intranet_customer_delete',{id:customer.id}) }}" class="bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded">Supprimer</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if customer.isDeleted %}
|
||||
<td colspan="7" class="absolute inset-0 z-20 rounded">
|
||||
@@ -88,7 +90,7 @@
|
||||
<div class="relative flex items-center justify-center h-full text-white text-lg font-semibold space-x-4">
|
||||
<span>Client supprimé</span>
|
||||
<a href="{{ path('artemis_intranet_customer_restore',{id:customer.id}) }}" type="submit" class="bg-purple-600 hover:bg-purples-700 px-4 py-2 rounded text-white font-semibold">Restaurer</a>
|
||||
|
||||
<a href="{{ path('artemis_intranet_customer_forced',{id:customer.id}) }}" type="submit" class="bg-purple-600 hover:bg-purples-700 px-4 py-2 rounded text-white font-semibold">Accélerer la suppression</a>
|
||||
</div>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user