feat(EsyWeb/Intranet): Ajoute et modifie les routes et gère les prix automatiques.
```
This commit is contained in:
Serreau Jovann
2025-10-22 11:35:06 +02:00
parent da028d4f39
commit 23154c4372
8 changed files with 337 additions and 4 deletions

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20251017085407 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE customer_price (id SERIAL NOT NULL, type VARCHAR(255) NOT NULL, ammount DOUBLE PRECISION NOT NULL, description TEXT DEFAULT NULL, PRIMARY KEY(id))');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('DROP TABLE customer_price');
}
}

View File

@@ -20,7 +20,7 @@ use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
class EsyWebController extends AbstractController
{
#[Route(path: '/artemis/esyweb', name: 'artemis_esyweb', methods: ['GET', 'POST'])]
#[Route(path: '/artemis/esyweb/website', name: 'artemis_esyweb', methods: ['GET', 'POST'])]
public function websites(LoggerService $loggerService,Request $request,EntityManagerInterface $entityManager,WebsiteRepository $websiteRepository)
{
$loggerService->log("VIEW","Affiche la page de site internet",$this->getUser());
@@ -37,7 +37,7 @@ class EsyWebController extends AbstractController
'websites' => $websiteRepository->findAll(),
]);
}
#[Route(path: '/artemis/esyweb/{id}', name: 'artemis_esyweb_view', methods: ['GET', 'POST'])]
#[Route(path: '/artemis/esyweb/website/{id}', name: 'artemis_esyweb_view', methods: ['GET', 'POST'])]
public function websiteView(?Website $website,LoggerService $loggerService,Request $request,EntityManagerInterface $entityManager,WebsiteRepository $websiteRepository)
{
if(is_null($website)) {
@@ -50,7 +50,7 @@ class EsyWebController extends AbstractController
'website' => $website
]);
}
#[Route(path: '/artemis/esyweb/add', name: 'artemis_esyweb_add', methods: ['GET', 'POST'])]
#[Route(path: '/artemis/esyweb/website/add', name: 'artemis_esyweb_add', methods: ['GET', 'POST'])]
public function websiteAdd(LoggerService $loggerService,Request $request,EntityManagerInterface $entityManager,EventDispatcherInterface $eventDispatcher)
{
$loggerService->log("VIEW","Affiche la page de création de site internet",$this->getUser());

View File

@@ -0,0 +1,103 @@
<?php
namespace App\Controller\Artemis\Intranet;
use App\Service\Echeance\EventEcheanceCreated;
use App\Service\Pdf\EmailListPdf;
use App\Service\Pdf\PaymentPdf;
use App\Entity\{Account,
Customer,
CustomerAdvertPayment,
CustomerAdvertPaymentLine,
CustomerContact,
CustomerDevis,
CustomerDevisLine,
CustomerDns,
CustomerDnsEmail,
CustomerOrder,
CustomerOrderLine,
CustomerPrice,
CustomerSplit,
CustomerSplitLine,
OrderNumberCurrent};
use App\Form\Artemis\Intranet\{CustomerDnsEmailType, CustomerEditType, CustomerNddType, CustomerType, PriceType};
use App\Repository\{CustomerDnsRepository,
CustomerOrderRepository,
CustomerPriceRepository,
CustomerRepository,
OrderNumberCurrentRepository,
OrderNumberDispoRepository};
use App\Security\PasswordGenerator;
use App\Service\Customer\Billing\{
CreateAvisEventSend,
CreateDevisCustomerEvent,
CreateDevisCustomerEventSend,
CreateFactureEventSend
};
use App\Service\Customer\{CreateAvisEvent,
CreateCustomerNddEmailEvent,
CreateFactureEvent,
CustomerSendPasswordEmail,
DeleteCustomerEvent,
EventSpaceCustomerCreated,
PdfList\SendPdfEmailListEvent,
RestoreCustomerEvent};
use App\Service\Logger\LoggerService;
use App\Service\Ovh\Client;
use App\Service\Vault\VaultClient;
use Doctrine\ORM\EntityManagerInterface;
use Exbil\MailCowAPI;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Uid\Uuid;
class PriceController extends AbstractController
{
#[Route(path: '/artemis/customer/price', name: 'artemis_intranet_price', methods: ['GET', 'POST'])]
public function customerPrice(
LoggerService $loggerService,
CustomerPriceRepository $customerPriceRepository,
EntityManagerInterface $entityManager,
Request $request,
FormFactoryInterface $formFactory,
)
{
$loggerService->log("VIEW","Affichage price automatique",$this->getUser());
$pricesList = [
'price_ndd',
'price_hosting',
'price_email'
];
foreach ($pricesList as $price) {
$ptc = $customerPriceRepository->findOneBy(['type' => $price]);
if(!$ptc instanceof CustomerPrice) {
$ptc = new CustomerPrice();
$ptc->setType($price);
$ptc->setAmmount(0);
$ptc->setDescription("");
$entityManager->persist($ptc);
$entityManager->flush();
}
}
$forms = [];
foreach ($customerPriceRepository->findAll() as $price) {
$fc = $formFactory->createNamed('price_'.$price->getId(),PriceType::class,$price);
$fc->handleRequest($request);
$forms[$price->getType()] = $fc->createView();
}
return $this->render('artemis/intranet/price.twig', [
'ptcs' => $forms
]);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Entity;
use App\Repository\CustomerPriceRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: CustomerPriceRepository::class)]
class CustomerPrice
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $type = null;
#[ORM\Column]
private ?float $ammount = null;
#[ORM\Column(type: 'text', nullable: true)]
private ?string $description = null;
public function getId(): ?int
{
return $this->id;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): static
{
$this->type = $type;
return $this;
}
public function getAmmount(): ?float
{
return $this->ammount;
}
public function setAmmount(float $ammount): static
{
$this->ammount = $ammount;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Form\Artemis\Intranet;
use App\Entity\CustomerPrice;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class PriceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('ammount',TextType::class,[
'label' => 'Prix',
'required' => true,
])
->add('description',TextareaType::class,[
'label' => 'Description',
'required' => true,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('data_class',CustomerPrice::class);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Repository;
use App\Entity\CustomerPrice;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<CustomerPrice>
*/
class CustomerPriceRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, CustomerPrice::class);
}
// /**
// * @return CustomerPrice[] Returns an array of CustomerPrice objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('c')
// ->andWhere('c.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('c.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?CustomerPrice
// {
// return $this->createQueryBuilder('c')
// ->andWhere('c.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@@ -127,7 +127,11 @@
<span class="ml-3">Client(s)</span>
</a>
</li>
<li>
<a href="{{ path('artemis_intranet_price') }}" class="flex items-center p-2 text-base font-normal text-gray-900 dark:text-white {% if app.request.get('_route') == 'artemis_intranet_price' %}bg-gray-200 dark:bg-gray-700{% endif %} rounded-lg">
<span class="ml-3">Prix automatique</span>
</a>
</li>
</ul>
</li>
<li class="px-4 py-2">

View File

@@ -0,0 +1,54 @@
{% extends 'artemis/base.twig' %}
{% block content %}
{# Conteneur principal en mode sombre #}
<div class="bg-gray-900 min-h-screen text-gray-100 p-4 sm:p-6 lg:p-8">
<div class="container mx-auto">
{# Titre en couleur claire #}
<h1 class="text-3xl font-bold mb-6 text-white">Prix automatique</h1>
{# Le conteneur principal pour les formulaires #}
<div class="space-y-6">
{% for key,form in ptcs %}
{# Conteneur pour chaque formulaire : une carte plus claire sur fond sombre #}
<div class="bg-gray-800 p-6 rounded-lg shadow-xl border border-gray-700 transition duration-300 hover:shadow-2xl">
<h2 class="text-2xl font-bold mb-6 text-white">{{ key|trans }}</h2>
{{ form_start(form, {'attr': {'class': 'space-y-4'}}) }}
{# Style pour le champ 'ammount' #}
<div class="mb-4">
{# Label en blanc #}
<label for="{{ form.ammount.vars.id }}" class="block text-sm font-medium text-gray-200">Montant</label>
{# Champ de formulaire adapté au mode sombre (fond sombre, texte blanc) #}
{{ form_widget(form.ammount, {'attr': {'class': 'mt-1 block w-full px-3 py-2 border border-gray-700 bg-gray-900 text-white rounded-md shadow-sm placeholder-gray-500 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm'}}) }}
{{ form_errors(form.ammount) }}
</div>
{# Style pour le champ 'description' #}
<div class="mb-4">
{# Label en blanc #}
<label for="{{ form.description.vars.id }}" class="block text-sm font-medium text-gray-200">Description</label>
{# Champ de formulaire adapté au mode sombre (fond sombre, texte blanc) #}
{{ form_widget(form.description, {'attr': {'class': 'mt-1 block w-full px-3 py-2 border border-gray-700 bg-gray-900 text-white rounded-md shadow-sm placeholder-gray-500 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm'}}) }}
{{ form_errors(form.description) }}
</div>
{# Style pour le bouton d'envoi (inchangé car les couleurs Indigo fonctionnent bien en mode sombre) #}
<div class="text-right">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 focus:ring-offset-gray-800">
Enregistrer
</button>
</div>
{{ form_end(form) }}
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
{% block title %}
Prix automatique
{% endblock %}