✨ feat(Customer): Ajoute la relation OneToMany avec l'entité Website
✨ feat(esyweb): Ajoute un contrôleur et une page pour les sites web 🐛 fix(register): Corrige l'enregistrement des paiements partiels et complets ✨ feat(Payment): Gère les paiements complets et partiels via Stancer ✨ feat(BillingEvent): Ajoute des listeners pour les paiements complétés
This commit is contained in:
@@ -4,26 +4,31 @@ export class RegisterPayment extends HTMLButtonElement {
|
||||
element.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const advertId = element.getAttribute('id');
|
||||
|
||||
let modal = document.createElement('div');
|
||||
modal.classList = "modal-payment"
|
||||
modal.innerHTML =`
|
||||
<div class="modal-payment-content">
|
||||
<h2>Enregistrée un paiement</h2>
|
||||
<a class="block dbclose bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded">Fermer</a>
|
||||
<form method="post" class="content">
|
||||
// Classes de fond du modal Dark Mode
|
||||
modal.classList.add("modal-payment", "fixed", "inset-0", "bg-gray-900", "bg-opacity-75", "flex", "items-center", "justify-center", "z-50");
|
||||
|
||||
modal.innerHTML = `
|
||||
<div class="modal-payment-content dark:bg-gray-800 bg-white shadow-2xl rounded-lg p-6 relative" style="max-width: 900px; width: 90%; max-height: 90vh; overflow-y: auto;">
|
||||
<h2 class="text-xl font-bold dark:text-white mb-4">Enregistrer un paiement</h2>
|
||||
|
||||
<a class="block dbclose bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded" style="cursor: pointer; position: absolute; top: 10px; right: 10px;">Fermer</a>
|
||||
|
||||
<form method="post" class="content mb-6">
|
||||
<div class="flex space-x-4 w-full">
|
||||
<fieldset class="form-group form-group--horizontal w-full">
|
||||
<div class="flex space-x-4">
|
||||
<div class="flex-1">
|
||||
<div class="form-field">
|
||||
<div class="mb-1">
|
||||
<label for="titre" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Type</label>
|
||||
<select name="type" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
|
||||
<label for="type" class="block mb-2 text-sm font-medium dark:text-gray-300 text-gray-900">Type</label>
|
||||
<select name="type" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
|
||||
<option value="CB">Carte Bancaire</option>
|
||||
<option value="PREV">Prévélevement</option>
|
||||
<option value="CH">Chéque</option>
|
||||
<option value="ESP">Espéce</option>
|
||||
<option value="PREV">Prélèvement</option>
|
||||
<option value="CH">Chèque</option>
|
||||
<option value="ESP">Espèce</option>
|
||||
<option value="VIR">Virement</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -32,65 +37,186 @@ export class RegisterPayment extends HTMLButtonElement {
|
||||
<div class="flex-1">
|
||||
<div class="form-field">
|
||||
<div class="mb-1">
|
||||
<label for="titre" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Date</label>
|
||||
<input name="date" type="date" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required />
|
||||
<label for="date" class="block mb-2 text-sm font-medium dark:text-gray-300 text-gray-900">Date</label>
|
||||
<input name="date" type="date" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="form-field">
|
||||
<div class="mb-1">
|
||||
<label for="titre" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Montant</label>
|
||||
<input name="amount" type="number" step="0.01" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required />
|
||||
<label for="amount" class="block mb-2 text-sm font-medium dark:text-gray-300 text-gray-900">Montant</label>
|
||||
<input name="amount" type="number" step="0.01" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="form-field">
|
||||
<div class="mb-1">
|
||||
<label for="titre" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Numéro de remise de chéque</label>
|
||||
<input name="num_cheque" type="text" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" />
|
||||
<label for="num_cheque" class="block mb-2 text-sm font-medium dark:text-gray-300 text-gray-900">Numéro de remise de chèque</label>
|
||||
<input name="num_cheque" type="text" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<button type="submit" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-semibold px-4 py-2 rounded">Enregistrer</button>
|
||||
<button type="submit" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-semibold px-4 py-2 rounded mt-3">Enregistrer</button>
|
||||
</form>
|
||||
|
||||
<h3 class="mt-6 text-lg font-semibold dark:text-white border-t border-gray-700 pt-4">Historique des paiements</h3>
|
||||
<div class="overflow-x-auto">
|
||||
<table id="payment-table" class="min-w-full divide-y dark:divide-gray-700 divide-gray-200">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-6 py-3 dark:bg-gray-700 bg-gray-100 text-left text-xs font-medium dark:text-gray-300 text-gray-500 uppercase tracking-wider">Date</th>
|
||||
<th class="px-6 py-3 dark:bg-gray-700 bg-gray-100 text-left text-xs font-medium dark:text-gray-300 text-gray-500 uppercase tracking-wider">Type</th>
|
||||
<th class="px-6 py-3 dark:bg-gray-700 bg-gray-100 text-left text-xs font-medium dark:text-gray-300 text-gray-500 uppercase tracking-wider">Montant</th>
|
||||
<th class="px-6 py-3 dark:bg-gray-700 bg-gray-100 text-left text-xs font-medium dark:text-gray-300 text-gray-500 uppercase tracking-wider">Réf. Chèque</th>
|
||||
<th class="px-6 py-3 dark:bg-gray-700 bg-gray-100 text-right text-xs font-medium dark:text-gray-300 text-gray-500 uppercase tracking-wider">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="dark:bg-gray-800 bg-white divide-y dark:divide-gray-700 divide-gray-200">
|
||||
<tr id="loading-row"><td colspan="6" class="px-6 py-4 whitespace-nowrap text-sm dark:text-gray-400 text-gray-500 text-center">Chargement...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
modal.querySelector('.dbclose').addEventListener('click',()=>{
|
||||
|
||||
const paymentTableBody = modal.querySelector('#payment-table tbody');
|
||||
|
||||
/**
|
||||
* Fonction pour récupérer et afficher la liste des paiements.
|
||||
*/
|
||||
const loadPayments = () => {
|
||||
paymentTableBody.innerHTML = '<tr id="loading-row"><td colspan="6" class="px-6 py-4 whitespace-nowrap text-sm dark:text-gray-400 text-gray-500 text-center">Chargement...</td></tr>';
|
||||
|
||||
fetch(`/api-interne/intranet/customer/register?idPayment=${advertId}`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Erreur lors de la récupération des paiements (code: ' + response.status + ')');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((listPayment) => {
|
||||
paymentTableBody.innerHTML = '';
|
||||
|
||||
if (listPayment && listPayment.length > 0) {
|
||||
listPayment.forEach(payment => {
|
||||
const tr = document.createElement('tr');
|
||||
const date = new Date(payment.date).toLocaleDateString();
|
||||
|
||||
// Classes pour les lignes (alternance des couleurs en dark mode)
|
||||
tr.classList.add('hover:bg-gray-700');
|
||||
|
||||
tr.innerHTML = `
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm dark:text-gray-300 text-gray-500">${date}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm dark:text-gray-300 text-gray-500">${payment.type}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold text-green-400 dark:text-green-400">${parseFloat(payment.amount).toFixed(2)} €</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm dark:text-gray-300 text-gray-500">${payment.num_cheque || ''}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<button data-payment-id="${payment.id}" class="delete-payment-btn text-red-500 hover:text-red-400 dark:text-red-400 dark:hover:text-red-300">Supprimer</button>
|
||||
</td>
|
||||
`;
|
||||
|
||||
paymentTableBody.appendChild(tr);
|
||||
});
|
||||
|
||||
modal.querySelectorAll('.delete-payment-btn').forEach(button => {
|
||||
button.addEventListener('click', (e) => {
|
||||
const paymentId = e.currentTarget.dataset.paymentId;
|
||||
deletePayment(paymentId, loadPayments);
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
paymentTableBody.innerHTML = '<tr><td colspan="6" class="px-6 py-4 whitespace-nowrap text-sm dark:text-gray-400 text-gray-500 text-center">Aucun paiement enregistré pour le moment.</td></tr>';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Erreur de chargement des paiements:", error);
|
||||
paymentTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-4 whitespace-nowrap text-sm text-red-500 text-center">Erreur lors du chargement: ${error.message}</td></tr>`;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Fonction pour envoyer la requête de suppression de paiement.
|
||||
*/
|
||||
const deletePayment = (paymentId, callback) => {
|
||||
if (!confirm(`Êtes-vous sûr de vouloir supprimer le paiement ?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api-interne/intranet/customer/payment/${paymentId}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Échec de la suppression.');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(() => {
|
||||
alert('Paiement supprimé avec succès.');
|
||||
callback(); // Recharger la liste des paiements
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Erreur de suppression:", error);
|
||||
alert(`Erreur lors de la suppression du paiement: ${error.message}`);
|
||||
});
|
||||
};
|
||||
|
||||
// 1. Charger les paiements lors de l'ouverture du modal
|
||||
loadPayments();
|
||||
|
||||
// 2. Écouteur pour la fermeture du modal
|
||||
modal.querySelector('.dbclose').addEventListener('click', () => {
|
||||
modal.remove();
|
||||
})
|
||||
modal.querySelector('form').addEventListener('submit',(e)=>{
|
||||
|
||||
// 3. Écouteur pour l'enregistrement d'un nouveau paiement
|
||||
modal.querySelector('form').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = {};
|
||||
const formElements = e.target.elements;
|
||||
|
||||
for (let i = 0; i < formElements.length; i++) {
|
||||
const el = formElements[i];
|
||||
if (el.name) {
|
||||
formData[el.name] = el.value;
|
||||
}
|
||||
}
|
||||
|
||||
formData['idAdvert'] = advertId;
|
||||
|
||||
let inputs = [];
|
||||
modal.querySelectorAll('select').forEach(selectItem=>{
|
||||
inputs.push({
|
||||
name: selectItem.name,
|
||||
val: selectItem.value
|
||||
})
|
||||
})
|
||||
modal.querySelectorAll('input').forEach(inputItem=>{
|
||||
inputs[inputItem.name] = inputItem.value;
|
||||
inputs.push({
|
||||
name: inputItem.name,
|
||||
val: inputItem.value
|
||||
})
|
||||
})
|
||||
inputs.push({
|
||||
name : 'idAdvert',
|
||||
val :element.getAttribute('id')
|
||||
});
|
||||
fetch("/api-interne/intranet/customer/register",{
|
||||
method:'POST',
|
||||
Object.keys(formData).forEach(key => inputs.push({ name: key, val: formData[key] }));
|
||||
|
||||
fetch("/api-interne/intranet/customer/register", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(inputs),
|
||||
}).then(response=>response.json())
|
||||
.then(()=>{
|
||||
//location.reload();
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
return response.json().then(err => { throw new Error(err.message || 'Erreur lors de l\'enregistrement'); });
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(() => {
|
||||
loadPayments();
|
||||
e.target.reset();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Erreur lors de l'enregistrement:", error);
|
||||
alert("Une erreur est survenue lors de l'enregistrement du paiement: " + error.message);
|
||||
});
|
||||
})
|
||||
|
||||
document.body.appendChild(modal);
|
||||
})
|
||||
}
|
||||
|
||||
36
migrations/Version20251007110952.php
Normal file
36
migrations/Version20251007110952.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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 Version20251007110952 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 website (id SERIAL NOT NULL, customer_id INT DEFAULT NULL, uuid UUID NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_476F5DE79395C3F3 ON website (customer_id)');
|
||||
$this->addSql('COMMENT ON COLUMN website.uuid IS \'(DC2Type:uuid)\'');
|
||||
$this->addSql('ALTER TABLE website ADD CONSTRAINT FK_476F5DE79395C3F3 FOREIGN KEY (customer_id) REFERENCES customer (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
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('ALTER TABLE website DROP CONSTRAINT FK_476F5DE79395C3F3');
|
||||
$this->addSql('DROP TABLE website');
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,30 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class RegisterController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/api-interne/intranet/customer/register',name: 'api-interne-intranet-customer-register')]
|
||||
public function customerRegisterPayment(EventDispatcherInterface $eventDispatcher,EntityManagerInterface $entityManager,Request $request,CustomerAdvertPaymentRepository $customerAdvertPaymentRepository): Response {
|
||||
public function customerRegisterPayment(EventDispatcherInterface $eventDispatcher,EntityManagerInterface $entityManager,Request $request,CustomerAdvertPaymentRepository $customerAdvertPaymentRepository,
|
||||
TranslatorInterface $translator): Response {
|
||||
|
||||
if($request->isMethod('GET')) {
|
||||
$advert = $customerAdvertPaymentRepository->find($request->query->get('idPayment'));
|
||||
$listPayments = [];
|
||||
foreach ($advert->getCustomerAdvertPaymentRegisters() as $payment) {
|
||||
$listPayments[] = [
|
||||
'id' => $payment->getId(),
|
||||
'amount' => $payment->getAmount(),
|
||||
'type' => $translator->trans('register_'.$payment->getType()),
|
||||
'num_cheque' => $payment->getNumeroRemise(),
|
||||
'date'=> $payment->getCreateAt()->format('Y-m-d'),
|
||||
];
|
||||
}
|
||||
|
||||
return $this->json($listPayments);
|
||||
}
|
||||
|
||||
$content = $request->getContent();
|
||||
$content = json_decode($content);
|
||||
$format = [];
|
||||
@@ -31,6 +50,13 @@ class RegisterController extends AbstractController
|
||||
foreach ($advert->getCustomerAdvertPaymentLines() as $customerAdvertPaymentLine)
|
||||
$total += (1.20*$customerAdvertPaymentLine->getPriceHt());
|
||||
|
||||
$totalPay = 0;
|
||||
foreach ($advert->getCustomerAdvertPaymentRegisters() as $customerAdvertPaymentRegister)
|
||||
$totalPay += $customerAdvertPaymentRegister->getAmount();
|
||||
|
||||
if($total - $totalPay <=0)
|
||||
return $this->json([]);
|
||||
|
||||
$advertRegister = new CustomerAdvertPaymentRegister();
|
||||
$advertRegister->setAdvert($advert);
|
||||
$advertRegister->setCreateAt(\DateTimeImmutable::createFromFormat('Y-m-d', $format['date']));
|
||||
@@ -43,15 +69,17 @@ class RegisterController extends AbstractController
|
||||
$diff = $total - floatval($format['amount']);
|
||||
if($diff >0){
|
||||
$t = new \DateTimeImmutable();
|
||||
$num = 'A-' . $t->format('Y/m') . '/' . sprintf('%05d', $entityManager->getRepository(CustomerAdvertPayment::class)->count() + 1);
|
||||
|
||||
$num = 'DIFF-' . $advert->getId();
|
||||
$advert->setState("p-payment");
|
||||
$entityManager->persist($advert);
|
||||
$entityManager->flush();
|
||||
$diffAdvert = new CustomerAdvertPayment();
|
||||
$diffAdvert->setCustomer($advertRegister->getAdvert()->getCustomer());
|
||||
$diffAdvert->setDevis($advertRegister->getAdvert()->getDevis());
|
||||
$diffAdvert->setUpdateAt(\DateTimeImmutable::createFromFormat('Y-m-d', $format['date']));
|
||||
$diffAdvert->setCreateAt(\DateTimeImmutable::createFromFormat('Y-m-d', $format['date']));
|
||||
$diffAdvert->setNumAvis($num);
|
||||
$diffAdvert->setState('created');
|
||||
$diffAdvert->setState('send_avis');
|
||||
$entityManager->persist($diffAdvert);
|
||||
$diffAdvertLine = new CustomerAdvertPaymentLine();
|
||||
$diffAdvertLine->setPos(0);
|
||||
@@ -65,7 +93,6 @@ class RegisterController extends AbstractController
|
||||
$entityManager->flush();
|
||||
$event = new CreateAvisEvent($diffAdvert, true);
|
||||
$eventDispatcher->dispatch($event);
|
||||
|
||||
return $this->json([]);
|
||||
} else {
|
||||
dd("completed");
|
||||
|
||||
27
src/Controller/Artemis/EsyWeb/EsyWebController.php
Normal file
27
src/Controller/Artemis/EsyWeb/EsyWebController.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Artemis\EsyWeb;
|
||||
|
||||
use App\Repository\EsyWeb\WebsiteRepository;
|
||||
use App\Repository\EsyWebTutoRepository;
|
||||
use App\Service\Logger\LoggerService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
||||
|
||||
class EsyWebController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/artemis/esyweb', name: 'artemis_esyweb', methods: ['GET', 'POST'])]
|
||||
public function tutos(LoggerService $loggerService,WebsiteRepository $websiteRepository)
|
||||
{
|
||||
$loggerService->log("VIEW","Affiche la page de site internet",$this->getUser());
|
||||
|
||||
return $this->render('artemis/esyweb/website.twig', [
|
||||
'websites' => $websiteRepository->findAll(),
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,17 @@ namespace App\Controller;
|
||||
|
||||
use App\Entity\CustomerAdvertPayment;
|
||||
use App\Entity\CustomerAdvertPaymentLine;
|
||||
use App\Entity\CustomerAdvertPaymentRegister;
|
||||
use App\Repository\CustomerAdvertPaymentRepository;
|
||||
use App\Service\Customer\Billing\CustomerAdvertPaymentComplete;
|
||||
use App\Service\Customer\Billing\SiteconseilAdvertPaymentComplete;
|
||||
use App\Service\Mailer\Mailer;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Stancer\Config;
|
||||
use Stancer\Customer;
|
||||
use Stancer\Payment;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
@@ -38,7 +42,7 @@ class PaymentController extends AbstractController
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/paiement/complete',name: 'app_payment_complete')]
|
||||
public function paymentComplete(EntityManagerInterface $entityManager,Mailer $mailer,Request $request,CustomerAdvertPaymentRepository $customerAdvertPaymentRepository): Response
|
||||
public function paymentComplete(EventDispatcherInterface $eventDispatcher,EntityManagerInterface $entityManager,Mailer $mailer,Request $request,CustomerAdvertPaymentRepository $customerAdvertPaymentRepository): Response
|
||||
{
|
||||
if(!$request->query->has('id'))
|
||||
return $this->render('admin/payement_invalid.twig',[
|
||||
@@ -69,9 +73,28 @@ class PaymentController extends AbstractController
|
||||
$advert->setCard($cardInfo);
|
||||
$advert->setPayAt(new \DateTimeImmutable());
|
||||
$entityManager->persist($advert);
|
||||
|
||||
$num = $advert->getNumAvis();
|
||||
if(str_contains($num,"DIFF-")) {
|
||||
$idRef = str_replace("DIFF-", "", $num);
|
||||
$mainAdvert= $entityManager->getRepository(CustomerAdvertPayment::class)->find($idRef);
|
||||
/*$register = new CustomerAdvertPaymentRegister();
|
||||
$register->setAmount(floatval($payment->amount/100));
|
||||
$register->setType("CB");
|
||||
$register->setAdvert($mainAdvert);
|
||||
$register->setCreateAt(new \DateTimeImmutable());
|
||||
$entityManager->persist($register);*/
|
||||
$advertSiteconseilPaymentComplete = new SiteconseilAdvertPaymentComplete($advert,$mainAdvert);
|
||||
} else {
|
||||
$advertSiteconseilPaymentComplete = new SiteconseilAdvertPaymentComplete($advert);
|
||||
}
|
||||
|
||||
$entityManager->flush();
|
||||
dd('email customer');
|
||||
dd('email siteconseil');
|
||||
|
||||
$advertCustomerePaymentComplete = new CustomerAdvertPaymentComplete($advert);
|
||||
$eventDispatcher->dispatch($advertCustomerePaymentComplete);
|
||||
$eventDispatcher->dispatch($advertSiteconseilPaymentComplete);
|
||||
|
||||
}
|
||||
}
|
||||
return $this->render('admin/payement_complete.twig',[
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\EsyWeb\Website;
|
||||
use App\Repository\CustomerRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
@@ -101,6 +102,12 @@ class Customer
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $stancerId = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Website>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Website::class, mappedBy: 'customer')]
|
||||
private Collection $websites;
|
||||
|
||||
|
||||
public function __clone(): void
|
||||
{
|
||||
@@ -122,6 +129,7 @@ class Customer
|
||||
$this->customerDevis = new ArrayCollection();
|
||||
$this->customerAdvertPayments = new ArrayCollection();
|
||||
$this->customerOrders = new ArrayCollection();
|
||||
$this->websites = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@@ -506,4 +514,34 @@ class Customer
|
||||
{
|
||||
$this->id = $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Website>
|
||||
*/
|
||||
public function getWebsites(): Collection
|
||||
{
|
||||
return $this->websites;
|
||||
}
|
||||
|
||||
public function addWebsite(Website $website): static
|
||||
{
|
||||
if (!$this->websites->contains($website)) {
|
||||
$this->websites->add($website);
|
||||
$website->setCustomer($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeWebsite(Website $website): static
|
||||
{
|
||||
if ($this->websites->removeElement($website)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($website->getCustomer() === $this) {
|
||||
$website->setCustomer(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
52
src/Entity/EsyWeb/Website.php
Normal file
52
src/Entity/EsyWeb/Website.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity\EsyWeb;
|
||||
|
||||
use App\Entity\Customer;
|
||||
use App\Repository\EsyWeb\WebsiteRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
#[ORM\Entity(repositoryClass: WebsiteRepository::class)]
|
||||
class Website
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'websites')]
|
||||
private ?Customer $customer = null;
|
||||
|
||||
#[ORM\Column(type: 'uuid')]
|
||||
private ?Uuid $uuid = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCustomer(): ?Customer
|
||||
{
|
||||
return $this->customer;
|
||||
}
|
||||
|
||||
public function setCustomer(?Customer $customer): static
|
||||
{
|
||||
$this->customer = $customer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUuid(): ?Uuid
|
||||
{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
public function setUuid(Uuid $uuid): static
|
||||
{
|
||||
$this->uuid = $uuid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
43
src/Repository/EsyWeb/WebsiteRepository.php
Normal file
43
src/Repository/EsyWeb/WebsiteRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository\EsyWeb;
|
||||
|
||||
use App\Entity\EsyWeb\Website;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Website>
|
||||
*/
|
||||
class WebsiteRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Website::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Website[] Returns an array of Website objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('w')
|
||||
// ->andWhere('w.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('w.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?Website
|
||||
// {
|
||||
// return $this->createQueryBuilder('w')
|
||||
// ->andWhere('w.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\Customer\Billing;
|
||||
|
||||
use App\Entity\CustomerAdvertPayment;
|
||||
|
||||
class CustomerAdvertPaymentComplete
|
||||
{
|
||||
public function __construct(private CustomerAdvertPayment $currentAdvertPayment){
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CustomerAdvertPayment
|
||||
*/
|
||||
public function getCurrentAdvertPayment(): CustomerAdvertPayment
|
||||
{
|
||||
return $this->currentAdvertPayment;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\Customer\Billing;
|
||||
|
||||
use App\Entity\CustomerAdvertPayment;
|
||||
|
||||
class SiteconseilAdvertPaymentComplete
|
||||
{
|
||||
public function __construct(private CustomerAdvertPayment $currentAdvertPayment,private ?CustomerAdvertPayment $parentAdvert=null){
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CustomerAdvertPayment
|
||||
*/
|
||||
public function getCurrentAdvertPayment(): CustomerAdvertPayment
|
||||
{
|
||||
return $this->currentAdvertPayment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CustomerAdvertPayment|null
|
||||
*/
|
||||
public function getParentAdvert(): ?CustomerAdvertPayment
|
||||
{
|
||||
return $this->parentAdvert;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace App\Service\Customer;
|
||||
|
||||
use App\Entity\CustomerAdvertPayment;
|
||||
use App\Entity\CustomerAdvertPaymentLine;
|
||||
use App\Service\Customer\Billing\CreateAvisEventSend;
|
||||
use App\Service\Customer\Billing\CreateDevisCustomerEvent;
|
||||
use App\Service\Customer\Billing\CreateDevisCustomerEventSend;
|
||||
use App\Service\Customer\Billing\CustomerAdvertPaymentComplete;
|
||||
use App\Service\Customer\Billing\SiteconseilAdvertPaymentComplete;
|
||||
use App\Service\Docuseal\SignClient;
|
||||
use App\Service\Mailer\Mailer;
|
||||
use App\Service\Pdf\DevisPdf;
|
||||
@@ -31,6 +34,8 @@ use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
||||
#[AsEventListener(event: CreateAvisEvent::class, method: 'onCreatedAvisEvent')]
|
||||
#[AsEventListener(event: CreateAvisEventSend::class, method: 'onCreatedAvisEventSend')]
|
||||
#[AsEventListener(event: CreateFactureEvent::class, method: 'onCreateFactureEvent')]
|
||||
#[AsEventListener(event: SiteconseilAdvertPaymentComplete::class, method: 'onSiteconseilAdvertPaymentComplete')]
|
||||
#[AsEventListener(event: CustomerAdvertPaymentComplete::class, method: 'onCustomerAdvertPaymentComplete')]
|
||||
class BillingEventSusbriber
|
||||
{
|
||||
|
||||
@@ -46,6 +51,19 @@ class BillingEventSusbriber
|
||||
){
|
||||
}
|
||||
|
||||
public function onSiteconseilAdvertPaymentComplete(SiteconseilAdvertPaymentComplete $advertPaymentComplete): void
|
||||
{
|
||||
/** @var CustomerAdvertPayment $currentAdvert */
|
||||
$currentAdvert = $advertPaymentComplete->getCurrentAdvertPayment();
|
||||
/** @var CustomerAdvertPayment $parent */
|
||||
$parent = $advertPaymentComplete->getParentAdvert();
|
||||
}
|
||||
|
||||
public function onCustomerAdvertPaymentComplete(CustomerAdvertPaymentComplete $advertPaymentComplete): void
|
||||
{
|
||||
$currentAdvert = $advertPaymentComplete->getCurrentAdvertPayment();
|
||||
}
|
||||
|
||||
public function onCustomerSendPasswordEmail(CustomerSendPasswordEmail $customerSendPasswordEmail)
|
||||
{
|
||||
$ndd = $customerSendPasswordEmail->getCustomerDnsEmail()->getDns();
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Entity\CustomerDevis;
|
||||
use App\Entity\CustomerDns;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class TwigOrderExtensions extends AbstractExtension
|
||||
{
|
||||
@@ -20,6 +21,20 @@ class TwigOrderExtensions extends AbstractExtension
|
||||
new TwigFilter('skFormat',[$this,'skFormat']),
|
||||
];
|
||||
}
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new TwigFunction('totalOrderPayment',[$this,'totalOrderPayment']),
|
||||
];
|
||||
}
|
||||
public function totalOrderPayment(CustomerAdvertPayment $customerAdvertPayment)
|
||||
{
|
||||
$totalPayment = 0;
|
||||
foreach ($customerAdvertPayment->getCustomerAdvertPaymentRegisters() as $register) {
|
||||
$totalPayment += $register->getAmount();
|
||||
}
|
||||
return $totalPayment;
|
||||
}
|
||||
|
||||
public function countEmail(Customer $customer): int
|
||||
{
|
||||
|
||||
@@ -74,6 +74,11 @@
|
||||
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400 arrow-icon" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path></svg>
|
||||
</button>
|
||||
<ul id="submenu-cmsesyweb" class="submenu ml-6 mt-2 space-y-2">
|
||||
<li>
|
||||
<a href="{{ path('artemis_esyweb') }}" class="flex items-center p-2 text-sm font-normal text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<span class="ml-3">SITE INTERNET</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ path('artemis_esyweb_tuto') }}" class="flex items-center p-2 text-sm font-normal text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<span class="ml-3">Tutoriels</span>
|
||||
|
||||
10
templates/artemis/esyweb/website.twig
Normal file
10
templates/artemis/esyweb/website.twig
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
Liste des site internet
|
||||
{% endblock %}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<td class="px-6 py-4">Avis de paiement</td>
|
||||
<td class="px-6 py-4">{{ orderAdvert.numAvis }}</td>
|
||||
<td class="px-6 py-4">{{ orderAdvert.createAt|date('d/m/Y H:i') }}</td>
|
||||
<td class="px-6 py-4">{{ (orderAdvert|totalOrder)|format_currency('EUR') }}</td>
|
||||
<td class="px-6 py-4 {% if orderAdvert.state == "pay"%} text-green-400 {% else %}text-orange-400{% endif %}">{{ orderAdvert.state|trans }} </td>
|
||||
<td class="px-6 py-4">{{ (orderAdvert|totalOrder)|format_currency('EUR') }} {% if orderAdvert.state == "p-payment" %} <span class="text-green-400">({{ totalOrderPayment(orderAdvert) }}€)</span>{% endif %}</td>
|
||||
<td class="px-6 py-4 {% if orderAdvert.state == "pay"%} text-green-400 {% elseif orderAdvert.state == "p-payment"%}text-purple-400{% else %}text-orange-400{% endif %}">{{ orderAdvert.state|trans }} </td>
|
||||
<td class="px-6 py-4 text-center">
|
||||
{% if orderAdvert.state == "created" %}
|
||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,currentOrder:'a',current:'order',idAvis:orderAdvert.id,act:'send'}) }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Envoyée l'avis de paiement</a>
|
||||
@@ -25,7 +25,7 @@
|
||||
{% if orderAdvert.state == "pay" and orderAdvert.customerOrder is null %}
|
||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',idAvis:orderAdvert.id,act:'createFacture'}) }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Crée la facture</a>
|
||||
{% endif %}
|
||||
{% if orderAdvert.state == "wait-bank" or orderAdvert.state == "wait-virement" %}
|
||||
{% if orderAdvert.state == "wait-bank" or orderAdvert.state == "wait-virement" or orderAdvert.state == "p-payment" %}
|
||||
<button is="register-payment" id="{{ orderAdvert.id }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Enregistrée un paiement</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
@@ -14,8 +14,14 @@ send: Envoyée - Attends de signature
|
||||
send_avis: Envoyée - Attends de paiement
|
||||
accepted: Accéptée
|
||||
cancel: Annulée
|
||||
p-payment: Paiement partiel
|
||||
pay: Payée
|
||||
wait-virement: En attends de virement
|
||||
register_VIR: Virement Bancaire
|
||||
register_CB: Carte Bancaire
|
||||
register_CH: Chéque
|
||||
register_ESP: Espéce
|
||||
register_PREV: Prévévement
|
||||
|
||||
dashboard: Tableau de bord
|
||||
custom_graphics: Personalisation - Graphique
|
||||
|
||||
Reference in New Issue
Block a user