✨ feat(Customer): Ajoute la gestion des échéances de paiement client
Ajoute l'entité CustomerSplit et les services associés pour gérer les échéances de paiement des clients (PDF, envoi mail, etc.).
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -36,3 +36,4 @@ script/demande/hosts.ini
|
|||||||
backup/*.zip
|
backup/*.zip
|
||||||
backup/*.sql
|
backup/*.sql
|
||||||
discord_bot/node_modules
|
discord_bot/node_modules
|
||||||
|
public/tmp-sign/*.pdf
|
||||||
|
|||||||
@@ -99,6 +99,7 @@
|
|||||||
- "{{ path }}/var/log" # Specific for log, though var/log might be created by composer later
|
- "{{ path }}/var/log" # Specific for log, though var/log might be created by composer later
|
||||||
- "{{ path }}/public/media" # For uploads
|
- "{{ path }}/public/media" # For uploads
|
||||||
- "{{ path }}/public/storage" # For uploads
|
- "{{ path }}/public/storage" # For uploads
|
||||||
|
- "{{ path }}/public/tmp-sign" # For uploads
|
||||||
|
|
||||||
- name: Exécuter 'composer install' dans le répertoire de l'application
|
- name: Exécuter 'composer install' dans le répertoire de l'application
|
||||||
ansible.builtin.command: composer install --no-dev --optimize-autoloader
|
ansible.builtin.command: composer install --no-dev --optimize-autoloader
|
||||||
@@ -253,3 +254,4 @@
|
|||||||
- "{{ path }}/var/log"
|
- "{{ path }}/var/log"
|
||||||
- "{{ path }}/public/media"
|
- "{{ path }}/public/media"
|
||||||
- "{{ path }}/public/storage" # For uploads
|
- "{{ path }}/public/storage" # For uploads
|
||||||
|
- "{{ path }}/public/tmp-sign" # For uploads
|
||||||
|
|||||||
@@ -435,3 +435,8 @@ confirm-modal{
|
|||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ech-created{
|
||||||
|
color: orange;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|||||||
32
migrations/Version20251008065523.php
Normal file
32
migrations/Version20251008065523.php
Normal 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 Version20251008065523 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('ALTER TABLE customer_advert_payment ADD type_payment VARCHAR(255) DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
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 customer_advert_payment DROP type_payment');
|
||||||
|
}
|
||||||
|
}
|
||||||
32
migrations/Version20251008084118.php
Normal file
32
migrations/Version20251008084118.php
Normal 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 Version20251008084118 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('ALTER TABLE customer_order ADD is_lock BOOLEAN DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
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 customer_order DROP is_lock');
|
||||||
|
}
|
||||||
|
}
|
||||||
42
migrations/Version20251008124926.php
Normal file
42
migrations/Version20251008124926.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?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 Version20251008124926 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_split (id SERIAL NOT NULL, customer_id INT DEFAULT NULL, create_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, num VARCHAR(255) NOT NULL, amount DOUBLE PRECISION NOT NULL, state VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX IDX_7FC0EF2A9395C3F3 ON customer_split (customer_id)');
|
||||||
|
$this->addSql('COMMENT ON COLUMN customer_split.create_at IS \'(DC2Type:datetime_immutable)\'');
|
||||||
|
$this->addSql('CREATE TABLE customer_split_line (id SERIAL NOT NULL, split_id INT DEFAULT NULL, date_prev TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, amount DOUBLE PRECISION NOT NULL, state VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX IDX_B054515F3DDC68C5 ON customer_split_line (split_id)');
|
||||||
|
$this->addSql('COMMENT ON COLUMN customer_split_line.date_prev IS \'(DC2Type:datetime_immutable)\'');
|
||||||
|
$this->addSql('ALTER TABLE customer_split ADD CONSTRAINT FK_7FC0EF2A9395C3F3 FOREIGN KEY (customer_id) REFERENCES customer (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE customer_split_line ADD CONSTRAINT FK_B054515F3DDC68C5 FOREIGN KEY (split_id) REFERENCES customer_split (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 customer_split DROP CONSTRAINT FK_7FC0EF2A9395C3F3');
|
||||||
|
$this->addSql('ALTER TABLE customer_split_line DROP CONSTRAINT FK_B054515F3DDC68C5');
|
||||||
|
$this->addSql('DROP TABLE customer_split');
|
||||||
|
$this->addSql('DROP TABLE customer_split_line');
|
||||||
|
}
|
||||||
|
}
|
||||||
32
migrations/Version20251008125048.php
Normal file
32
migrations/Version20251008125048.php
Normal 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 Version20251008125048 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('ALTER TABLE customer_split ADD description TEXT NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
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 customer_split DROP description');
|
||||||
|
}
|
||||||
|
}
|
||||||
34
migrations/Version20251008133426.php
Normal file
34
migrations/Version20251008133426.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?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 Version20251008133426 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('ALTER TABLE customer_split ADD submission_id VARCHAR(255) DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE customer_split_line ADD payment_id VARCHAR(255) DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
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 customer_split_line DROP payment_id');
|
||||||
|
$this->addSql('ALTER TABLE customer_split DROP submission_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
0
public/tmp-sign/.gitignore
vendored
Normal file
0
public/tmp-sign/.gitignore
vendored
Normal file
@@ -5,6 +5,8 @@ namespace App\Controller\ApiInterne\Intranet;
|
|||||||
|
|
||||||
use App\Entity\CustomerAdvertPayment;
|
use App\Entity\CustomerAdvertPayment;
|
||||||
use App\Repository\CustomerAdvertPaymentRepository;
|
use App\Repository\CustomerAdvertPaymentRepository;
|
||||||
|
use App\Service\Echeance\EventEcheanceCreated;
|
||||||
|
use App\Service\Logger\LoggerService;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use LuFiipe\InseeSierene\Sirene;
|
use LuFiipe\InseeSierene\Sirene;
|
||||||
use Stancer\Config;
|
use Stancer\Config;
|
||||||
@@ -12,6 +14,7 @@ use Stancer\Customer;
|
|||||||
use Stancer\Payment;
|
use Stancer\Payment;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
@@ -38,7 +41,7 @@ class CustomerController extends AbstractController
|
|||||||
return $this->json([]);
|
return $this->json([]);
|
||||||
}
|
}
|
||||||
#[Route(path: '/api-interne/intranet/customer/payment/',name: 'api-interne-intranet-customer-payment')]
|
#[Route(path: '/api-interne/intranet/customer/payment/',name: 'api-interne-intranet-customer-payment')]
|
||||||
public function customerPayment(EntityManagerInterface $entityManager,Request $request,CustomerAdvertPaymentRepository $customerAdvertPayment): Response
|
public function customerPayment(LoggerService $loggerService,EventDispatcherInterface $eventDispatcher,EntityManagerInterface $entityManager,Request $request,CustomerAdvertPaymentRepository $customerAdvertPayment): Response
|
||||||
{
|
{
|
||||||
if(!$request->query->has('id'))
|
if(!$request->query->has('id'))
|
||||||
return $this->json([],Response::HTTP_FORBIDDEN);
|
return $this->json([],Response::HTTP_FORBIDDEN);
|
||||||
@@ -77,6 +80,7 @@ class CustomerController extends AbstractController
|
|||||||
$payment->setCapture(true);
|
$payment->setCapture(true);
|
||||||
$paimentId = $payment->send();
|
$paimentId = $payment->send();
|
||||||
$advert->setPaymentId($paimentId);
|
$advert->setPaymentId($paimentId);
|
||||||
|
$advert->setTypePayment($request->query->has('type')?"sepa":"card");
|
||||||
$entityManager->persist($advert);
|
$entityManager->persist($advert);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Controller\Artemis\Intranet;
|
namespace App\Controller\Artemis\Intranet;
|
||||||
|
|
||||||
|
use App\Service\Echeance\EventEcheanceCreated;
|
||||||
use App\Service\Pdf\EmailListPdf;
|
use App\Service\Pdf\EmailListPdf;
|
||||||
use App\Service\Pdf\PaymentPdf;
|
use App\Service\Pdf\PaymentPdf;
|
||||||
use App\Entity\{
|
use App\Entity\{Customer,
|
||||||
Customer,
|
|
||||||
CustomerAdvertPayment,
|
CustomerAdvertPayment,
|
||||||
CustomerAdvertPaymentLine,
|
CustomerAdvertPaymentLine,
|
||||||
CustomerContact,
|
CustomerContact,
|
||||||
@@ -15,8 +15,9 @@ use App\Entity\{
|
|||||||
CustomerDnsEmail,
|
CustomerDnsEmail,
|
||||||
CustomerOrder,
|
CustomerOrder,
|
||||||
CustomerOrderLine,
|
CustomerOrderLine,
|
||||||
OrderNumberCurrent
|
CustomerSplit,
|
||||||
};
|
CustomerSplitLine,
|
||||||
|
OrderNumberCurrent};
|
||||||
use App\Form\Artemis\Intranet\{
|
use App\Form\Artemis\Intranet\{
|
||||||
CustomerDnsEmailType,
|
CustomerDnsEmailType,
|
||||||
CustomerEditType,
|
CustomerEditType,
|
||||||
@@ -258,6 +259,7 @@ class CustomerController extends AbstractController
|
|||||||
$entityManager->persist($order);
|
$entityManager->persist($order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
$event = new CreateFactureEvent($order, false);
|
$event = new CreateFactureEvent($order, false);
|
||||||
@@ -281,6 +283,16 @@ class CustomerController extends AbstractController
|
|||||||
return $this->redirectToRoute('artemis_intranet_customer_view', ['id' => $customer->getId(), 'current' => 'order', 'currentOrder' => 'a']);
|
return $this->redirectToRoute('artemis_intranet_customer_view', ['id' => $customer->getId(), 'current' => 'order', 'currentOrder' => 'a']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($request->query->has('idFacture') && $request->query->get('act') == 'send') {
|
||||||
|
$order = $customerOrderRepository->find($request->get('idFacture'));
|
||||||
|
$event = new CreateFactureEventSend($order);
|
||||||
|
$eventDispatcher->dispatch($event);
|
||||||
|
$order->setState("f-send");
|
||||||
|
$entityManager->persist($order);
|
||||||
|
$entityManager->flush();
|
||||||
|
$this->addFlash("success","Facture envoyée");
|
||||||
|
return $this->redirectToRoute('artemis_intranet_customer_view', ['id' => $customer->getId(),'current' => 'order', 'currentOrder' => 'f']);
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->query->has('idDevis') && $request->query->has('act')) {
|
if ($request->query->has('idDevis') && $request->query->has('act')) {
|
||||||
$idDevis = $request->query->getInt('idDevis');
|
$idDevis = $request->query->getInt('idDevis');
|
||||||
@@ -606,6 +618,7 @@ class CustomerController extends AbstractController
|
|||||||
$loggerService->log('CREATE', 'Création d\'une boîte mail ' . $nddEmail->getEmail(), $this->getUser());
|
$loggerService->log('CREATE', 'Création d\'une boîte mail ' . $nddEmail->getEmail(), $this->getUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$splitList = $entityManager->getRepository(CustomerSplit::class)->findBy(['customer' => $customer], ['id' => 'ASC']);
|
||||||
$orderDevis = $entityManager->getRepository(CustomerDevis::class)->findBy(['customer' => $customer], ['id' => 'ASC']);
|
$orderDevis = $entityManager->getRepository(CustomerDevis::class)->findBy(['customer' => $customer], ['id' => 'ASC']);
|
||||||
$orderAdvert = $entityManager->getRepository(CustomerAdvertPayment::class)->findBy(['customer' => $customer], ['id' => 'ASC']);
|
$orderAdvert = $entityManager->getRepository(CustomerAdvertPayment::class)->findBy(['customer' => $customer], ['id' => 'ASC']);
|
||||||
$orderOrder = $entityManager->getRepository(CustomerOrder::class)->findBy(['customer' => $customer], ['id' => 'ASC']);
|
$orderOrder = $entityManager->getRepository(CustomerOrder::class)->findBy(['customer' => $customer], ['id' => 'ASC']);
|
||||||
@@ -618,6 +631,9 @@ class CustomerController extends AbstractController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$ev = new EventEcheanceCreated($splitList[0]);
|
||||||
|
$eventDispatcher->dispatch($ev);
|
||||||
|
|
||||||
return $this->render('artemis/intranet/customer/edit.twig', [
|
return $this->render('artemis/intranet/customer/edit.twig', [
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
'formNdd' => $formNdd->createView(),
|
'formNdd' => $formNdd->createView(),
|
||||||
@@ -625,6 +641,7 @@ class CustomerController extends AbstractController
|
|||||||
'customer' => $customer,
|
'customer' => $customer,
|
||||||
'ndd' => $customerNdd,
|
'ndd' => $customerNdd,
|
||||||
'nddEmails' => $nddEmails,
|
'nddEmails' => $nddEmails,
|
||||||
|
'splitList' => $paginator->paginate($splitList, $request->query->getInt('page', 1), 10),
|
||||||
'orderDevis' => $paginator->paginate($orderDevis, $request->query->getInt('page', 1), 20),
|
'orderDevis' => $paginator->paginate($orderDevis, $request->query->getInt('page', 1), 20),
|
||||||
'orderOrders' => $paginator->paginate($orderOrder, $request->query->getInt('page', 1), 20),
|
'orderOrders' => $paginator->paginate($orderOrder, $request->query->getInt('page', 1), 20),
|
||||||
'orderAdverts' => $paginator->paginate($orderAdvert, $request->query->getInt('page', 1), 20),
|
'orderAdverts' => $paginator->paginate($orderAdvert, $request->query->getInt('page', 1), 20),
|
||||||
@@ -696,6 +713,7 @@ class CustomerController extends AbstractController
|
|||||||
$devis->setEvent($eventDispatcher);
|
$devis->setEvent($eventDispatcher);
|
||||||
|
|
||||||
if ($request->isMethod('POST')) {
|
if ($request->isMethod('POST')) {
|
||||||
|
$data = $request->request->all();
|
||||||
$data = $request->request->all();
|
$data = $request->request->all();
|
||||||
$devis->setCreateAt(\DateTimeImmutable::createFromFormat('Y-m-d\TH:i', $data['date']));
|
$devis->setCreateAt(\DateTimeImmutable::createFromFormat('Y-m-d\TH:i', $data['date']));
|
||||||
$entityManager->persist($devis);
|
$entityManager->persist($devis);
|
||||||
@@ -843,5 +861,56 @@ class CustomerController extends AbstractController
|
|||||||
'customer' => $customer,
|
'customer' => $customer,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
#[Route(path: '/artemis/intranet/customer/{id}/splitAdd', name: 'artemis_intranet_customer_splitAdd', methods: ['GET', 'POST'])]
|
||||||
|
public function customerSplitAdd(
|
||||||
|
?Customer $customer,
|
||||||
|
Request $request,
|
||||||
|
LoggerService $loggerService,
|
||||||
|
EntityManagerInterface $entityManager,
|
||||||
|
EventDispatcherInterface $eventDispatcher
|
||||||
|
): Response {
|
||||||
|
|
||||||
|
$num = "ECH-".sprintf('%05d',$entityManager->getRepository(CustomerSplit::class)->count([])+1);
|
||||||
|
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$request = $request->request->all();
|
||||||
|
$total = 0;
|
||||||
|
$ech = new CustomerSplit();
|
||||||
|
$ech->setCustomer($customer);
|
||||||
|
$ech->setNum($request['num']);
|
||||||
|
$ech->setDescription($request['description']);
|
||||||
|
$ech->setCreateAt(new \DateTimeImmutable());
|
||||||
|
$ech->setState('created');
|
||||||
|
$entityManager->persist($ech);
|
||||||
|
foreach ($request['lines'] ?? [] as $pos => $line) {
|
||||||
|
$echLine = new CustomerSplitLine();
|
||||||
|
$echLine->setAmount(floatval($line['price']));
|
||||||
|
$echLine->setDatePrev(\DateTimeImmutable::createFromFormat('Y-m-d',$line['date']));
|
||||||
|
$echLine->setState("created");
|
||||||
|
$entityManager->persist($echLine);
|
||||||
|
$ech->addCustomerSplitLine($echLine);
|
||||||
|
$total = $total + floatval($line['price']);
|
||||||
|
}
|
||||||
|
$ech->setAmount($total);
|
||||||
|
$entityManager->persist($ech);
|
||||||
|
$entityManager->flush();
|
||||||
|
|
||||||
|
|
||||||
|
$event = new EventEcheanceCreated($ech);
|
||||||
|
$eventDispatcher->dispatch($event);
|
||||||
|
$this->addFlash("success","Création de l'échéance de paiement");
|
||||||
|
$loggerService->log("CREATE","Création de l'échéance de paiement - ".$customer->getRaisonSocial(),$this->getUser());
|
||||||
|
return $this->redirectToRoute('artemis_intranet_customer_view', [
|
||||||
|
'id' => $customer?->getId(),
|
||||||
|
'current' => 'order',
|
||||||
|
'currentOrder' => 'split',
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('artemis/intranet/customer/slit-add.twig', [
|
||||||
|
'customer' => $customer,
|
||||||
|
'num' => $num
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class PaymentController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
if($advert->getState() == "pay") {
|
if($advert->getState() != "pay") {
|
||||||
$client = Config::init([$_ENV['STANCER_PUBLIC_KEY'], $_ENV['STANCER_PRIVATE_KEY']]);
|
$client = Config::init([$_ENV['STANCER_PUBLIC_KEY'], $_ENV['STANCER_PRIVATE_KEY']]);
|
||||||
$client->setMode($_ENV['STANCER_ENV']);
|
$client->setMode($_ENV['STANCER_ENV']);
|
||||||
$payEdit = str_replace('"', "", $advert->getPaymentId());
|
$payEdit = str_replace('"', "", $advert->getPaymentId());
|
||||||
@@ -74,30 +74,41 @@ class PaymentController extends AbstractController
|
|||||||
$advert->setPayAt(new \DateTimeImmutable());
|
$advert->setPayAt(new \DateTimeImmutable());
|
||||||
$entityManager->persist($advert);
|
$entityManager->persist($advert);
|
||||||
|
|
||||||
|
$register = new CustomerAdvertPaymentRegister();
|
||||||
|
$register->setAmount(floatval($payment->amount/100));
|
||||||
|
$register->setType("CB");
|
||||||
|
$register->setAdvert($advert);
|
||||||
|
$register->setCreateAt(new \DateTimeImmutable());
|
||||||
|
$entityManager->persist($register);
|
||||||
|
|
||||||
$num = $advert->getNumAvis();
|
$num = $advert->getNumAvis();
|
||||||
if(str_contains($num,"DIFF-")) {
|
if(str_contains($num,"DIFF-")) {
|
||||||
$idRef = str_replace("DIFF-", "", $num);
|
$idRef = str_replace("DIFF-", "", $num);
|
||||||
$mainAdvert= $entityManager->getRepository(CustomerAdvertPayment::class)->find($idRef);
|
$mainAdvert= $entityManager->getRepository(CustomerAdvertPayment::class)->find($idRef);
|
||||||
/*$register = new CustomerAdvertPaymentRegister();
|
$registerSub = new CustomerAdvertPaymentRegister();
|
||||||
$register->setAmount(floatval($payment->amount/100));
|
$registerSub->setAmount(floatval($payment->amount/100));
|
||||||
$register->setType("CB");
|
$registerSub->setType("CB");
|
||||||
$register->setAdvert($mainAdvert);
|
$registerSub->setAdvert($mainAdvert);
|
||||||
$register->setCreateAt(new \DateTimeImmutable());
|
$registerSub->setCreateAt(new \DateTimeImmutable());
|
||||||
$entityManager->persist($register);*/
|
$mainAdvert->setState("pay");
|
||||||
$advertSiteconseilPaymentComplete = new SiteconseilAdvertPaymentComplete($advert,$mainAdvert);
|
$entityManager->persist($registerSub);
|
||||||
|
$entityManager->persist($mainAdvert);
|
||||||
|
$advertSiteconseilPaymentComplete = new SiteconseilAdvertPaymentComplete($advert,$mainAdvert,$register);
|
||||||
} else {
|
} else {
|
||||||
$advertSiteconseilPaymentComplete = new SiteconseilAdvertPaymentComplete($advert);
|
$advertSiteconseilPaymentComplete = new SiteconseilAdvertPaymentComplete($advert,null,$register);
|
||||||
}
|
}
|
||||||
|
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
$advertCustomerePaymentComplete = new CustomerAdvertPaymentComplete($advert);
|
$advertCustomerePaymentComplete = new CustomerAdvertPaymentComplete($advert,$register);
|
||||||
$eventDispatcher->dispatch($advertCustomerePaymentComplete);
|
$eventDispatcher->dispatch($advertCustomerePaymentComplete);
|
||||||
$eventDispatcher->dispatch($advertSiteconseilPaymentComplete);
|
$eventDispatcher->dispatch($advertSiteconseilPaymentComplete);
|
||||||
|
return $this->render('admin/payement_complete.twig',[
|
||||||
|
'advert' => $advert,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $this->render('admin/payement_complete.twig',[
|
return $this->render('admin/payement_no_complete.twig',[
|
||||||
'advert' => $advert,
|
'advert' => $advert,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,12 @@ class Customer
|
|||||||
#[ORM\OneToMany(targetEntity: Website::class, mappedBy: 'customer')]
|
#[ORM\OneToMany(targetEntity: Website::class, mappedBy: 'customer')]
|
||||||
private Collection $websites;
|
private Collection $websites;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Collection<int, CustomerSplit>
|
||||||
|
*/
|
||||||
|
#[ORM\OneToMany(targetEntity: CustomerSplit::class, mappedBy: 'customer')]
|
||||||
|
private Collection $customerSplits;
|
||||||
|
|
||||||
|
|
||||||
public function __clone(): void
|
public function __clone(): void
|
||||||
{
|
{
|
||||||
@@ -130,6 +136,7 @@ class Customer
|
|||||||
$this->customerAdvertPayments = new ArrayCollection();
|
$this->customerAdvertPayments = new ArrayCollection();
|
||||||
$this->customerOrders = new ArrayCollection();
|
$this->customerOrders = new ArrayCollection();
|
||||||
$this->websites = new ArrayCollection();
|
$this->websites = new ArrayCollection();
|
||||||
|
$this->customerSplits = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
@@ -544,4 +551,34 @@ class Customer
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<int, CustomerSplit>
|
||||||
|
*/
|
||||||
|
public function getCustomerSplits(): Collection
|
||||||
|
{
|
||||||
|
return $this->customerSplits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCustomerSplit(CustomerSplit $customerSplit): static
|
||||||
|
{
|
||||||
|
if (!$this->customerSplits->contains($customerSplit)) {
|
||||||
|
$this->customerSplits->add($customerSplit);
|
||||||
|
$customerSplit->setCustomer($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeCustomerSplit(CustomerSplit $customerSplit): static
|
||||||
|
{
|
||||||
|
if ($this->customerSplits->removeElement($customerSplit)) {
|
||||||
|
// set the owning side to null (unless already changed)
|
||||||
|
if ($customerSplit->getCustomer() === $this) {
|
||||||
|
$customerSplit->setCustomer(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ class CustomerAdvertPayment
|
|||||||
*/
|
*/
|
||||||
#[ORM\OneToMany(targetEntity: CustomerAdvertPaymentRegister::class, mappedBy: 'advert')]
|
#[ORM\OneToMany(targetEntity: CustomerAdvertPaymentRegister::class, mappedBy: 'advert')]
|
||||||
private Collection $customerAdvertPaymentRegisters;
|
private Collection $customerAdvertPaymentRegisters;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $typePayment = null;
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->customerAdvertPaymentLines = new ArrayCollection();
|
$this->customerAdvertPaymentLines = new ArrayCollection();
|
||||||
@@ -376,4 +379,16 @@ class CustomerAdvertPayment
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTypePayment(): ?string
|
||||||
|
{
|
||||||
|
return $this->typePayment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTypePayment(?string $typePayment): static
|
||||||
|
{
|
||||||
|
$this->typePayment = $typePayment;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ class CustomerOrder
|
|||||||
private ?string $factureMineType = null;
|
private ?string $factureMineType = null;
|
||||||
#[ORM\Column(length: 255,nullable: true)]
|
#[ORM\Column(length: 255,nullable: true)]
|
||||||
private ?string $factureOriginalName = null;
|
private ?string $factureOriginalName = null;
|
||||||
|
|
||||||
|
#[ORM\Column(nullable: true)]
|
||||||
|
private ?bool $isLock = null;
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->customerOrderLines = new ArrayCollection();
|
$this->customerOrderLines = new ArrayCollection();
|
||||||
@@ -270,4 +273,16 @@ class CustomerOrder
|
|||||||
{
|
{
|
||||||
$this->factureSize = $factureSize;
|
$this->factureSize = $factureSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isLock(): ?bool
|
||||||
|
{
|
||||||
|
return $this->isLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsLock(?bool $isLock): static
|
||||||
|
{
|
||||||
|
$this->isLock = $isLock;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
169
src/Entity/CustomerSplit.php
Normal file
169
src/Entity/CustomerSplit.php
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\CustomerSplitRepository;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: CustomerSplitRepository::class)]
|
||||||
|
class CustomerSplit
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne(inversedBy: 'customerSplits')]
|
||||||
|
private ?Customer $customer = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?\DateTimeImmutable $createAt = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $num = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?float $amount = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $state = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Collection<int, CustomerSplitLine>
|
||||||
|
*/
|
||||||
|
#[ORM\OneToMany(targetEntity: CustomerSplitLine::class, mappedBy: 'split')]
|
||||||
|
private Collection $customerSplitLines;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::TEXT)]
|
||||||
|
private ?string $description = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255,nullable: true)]
|
||||||
|
private ?string $submissionId = null;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->customerSplitLines = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getCreateAt(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->createAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCreateAt(\DateTimeImmutable $createAt): static
|
||||||
|
{
|
||||||
|
$this->createAt = $createAt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNum(): ?string
|
||||||
|
{
|
||||||
|
return $this->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNum(string $num): static
|
||||||
|
{
|
||||||
|
$this->num = $num;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAmount(): ?float
|
||||||
|
{
|
||||||
|
return $this->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAmount(float $amount): static
|
||||||
|
{
|
||||||
|
$this->amount = $amount;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getState(): ?string
|
||||||
|
{
|
||||||
|
return $this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setState(string $state): static
|
||||||
|
{
|
||||||
|
$this->state = $state;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<int, CustomerSplitLine>
|
||||||
|
*/
|
||||||
|
public function getCustomerSplitLines(): Collection
|
||||||
|
{
|
||||||
|
return $this->customerSplitLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCustomerSplitLine(CustomerSplitLine $customerSplitLine): static
|
||||||
|
{
|
||||||
|
if (!$this->customerSplitLines->contains($customerSplitLine)) {
|
||||||
|
$this->customerSplitLines->add($customerSplitLine);
|
||||||
|
$customerSplitLine->setSplit($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeCustomerSplitLine(CustomerSplitLine $customerSplitLine): static
|
||||||
|
{
|
||||||
|
if ($this->customerSplitLines->removeElement($customerSplitLine)) {
|
||||||
|
// set the owning side to null (unless already changed)
|
||||||
|
if ($customerSplitLine->getSplit() === $this) {
|
||||||
|
$customerSplitLine->setSplit(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): ?string
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDescription(string $description): static
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubmissionId(): ?string
|
||||||
|
{
|
||||||
|
return $this->submissionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSubmissionId(string $submissionId): static
|
||||||
|
{
|
||||||
|
$this->submissionId = $submissionId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/Entity/CustomerSplitLine.php
Normal file
95
src/Entity/CustomerSplitLine.php
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\CustomerSplitLineRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: CustomerSplitLineRepository::class)]
|
||||||
|
class CustomerSplitLine
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne(inversedBy: 'customerSplitLines')]
|
||||||
|
private ?CustomerSplit $split = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?\DateTimeImmutable $datePrev = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?float $amount = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $state = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255,nullable: true)]
|
||||||
|
private ?string $paymentId = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSplit(): ?CustomerSplit
|
||||||
|
{
|
||||||
|
return $this->split;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSplit(?CustomerSplit $split): static
|
||||||
|
{
|
||||||
|
$this->split = $split;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatePrev(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->datePrev;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDatePrev(\DateTimeImmutable $datePrev): static
|
||||||
|
{
|
||||||
|
$this->datePrev = $datePrev;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAmount(): ?float
|
||||||
|
{
|
||||||
|
return $this->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAmount(float $amount): static
|
||||||
|
{
|
||||||
|
$this->amount = $amount;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getState(): ?string
|
||||||
|
{
|
||||||
|
return $this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setState(string $state): static
|
||||||
|
{
|
||||||
|
$this->state = $state;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPaymentId(): ?string
|
||||||
|
{
|
||||||
|
return $this->paymentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPaymentId(string $paymentId): static
|
||||||
|
{
|
||||||
|
$this->paymentId = $paymentId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/Repository/CustomerSplitLineRepository.php
Normal file
43
src/Repository/CustomerSplitLineRepository.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\CustomerSplitLine;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<CustomerSplitLine>
|
||||||
|
*/
|
||||||
|
class CustomerSplitLineRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, CustomerSplitLine::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return CustomerSplitLine[] Returns an array of CustomerSplitLine 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): ?CustomerSplitLine
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('c')
|
||||||
|
// ->andWhere('c.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
||||||
43
src/Repository/CustomerSplitRepository.php
Normal file
43
src/Repository/CustomerSplitRepository.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\CustomerSplit;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<CustomerSplit>
|
||||||
|
*/
|
||||||
|
class CustomerSplitRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, CustomerSplit::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return CustomerSplit[] Returns an array of CustomerSplit 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): ?CustomerSplit
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('c')
|
||||||
|
// ->andWhere('c.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -3,10 +3,19 @@
|
|||||||
namespace App\Service\Customer\Billing;
|
namespace App\Service\Customer\Billing;
|
||||||
|
|
||||||
use App\Entity\CustomerAdvertPayment;
|
use App\Entity\CustomerAdvertPayment;
|
||||||
|
use App\Entity\CustomerAdvertPaymentRegister;
|
||||||
|
|
||||||
class CustomerAdvertPaymentComplete
|
class CustomerAdvertPaymentComplete
|
||||||
{
|
{
|
||||||
public function __construct(private CustomerAdvertPayment $currentAdvertPayment){
|
public function __construct(private CustomerAdvertPayment $currentAdvertPayment,private CustomerAdvertPaymentRegister $customerAdvertPaymentRegister){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CustomerAdvertPaymentRegister
|
||||||
|
*/
|
||||||
|
public function getCustomerAdvertPaymentRegister(): CustomerAdvertPaymentRegister
|
||||||
|
{
|
||||||
|
return $this->customerAdvertPaymentRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,12 +3,20 @@
|
|||||||
namespace App\Service\Customer\Billing;
|
namespace App\Service\Customer\Billing;
|
||||||
|
|
||||||
use App\Entity\CustomerAdvertPayment;
|
use App\Entity\CustomerAdvertPayment;
|
||||||
|
use App\Entity\CustomerAdvertPaymentRegister;
|
||||||
|
|
||||||
class SiteconseilAdvertPaymentComplete
|
class SiteconseilAdvertPaymentComplete
|
||||||
{
|
{
|
||||||
public function __construct(private CustomerAdvertPayment $currentAdvertPayment,private ?CustomerAdvertPayment $parentAdvert=null){
|
public function __construct(private CustomerAdvertPayment $currentAdvertPayment,private ?CustomerAdvertPayment $parentAdvert=null,private ?CustomerAdvertPaymentRegister $customerAdvertPaymentRegister = null){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CustomerAdvertPaymentRegister|null
|
||||||
|
*/
|
||||||
|
public function getCustomerAdvertPaymentRegister(): ?CustomerAdvertPaymentRegister
|
||||||
|
{
|
||||||
|
return $this->customerAdvertPaymentRegister;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @return CustomerAdvertPayment
|
* @return CustomerAdvertPayment
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Entity\CustomerAdvertPaymentLine;
|
|||||||
use App\Service\Customer\Billing\CreateAvisEventSend;
|
use App\Service\Customer\Billing\CreateAvisEventSend;
|
||||||
use App\Service\Customer\Billing\CreateDevisCustomerEvent;
|
use App\Service\Customer\Billing\CreateDevisCustomerEvent;
|
||||||
use App\Service\Customer\Billing\CreateDevisCustomerEventSend;
|
use App\Service\Customer\Billing\CreateDevisCustomerEventSend;
|
||||||
|
use App\Service\Customer\Billing\CreateFactureEventSend;
|
||||||
use App\Service\Customer\Billing\CustomerAdvertPaymentComplete;
|
use App\Service\Customer\Billing\CustomerAdvertPaymentComplete;
|
||||||
use App\Service\Customer\Billing\SiteconseilAdvertPaymentComplete;
|
use App\Service\Customer\Billing\SiteconseilAdvertPaymentComplete;
|
||||||
use App\Service\Docuseal\SignClient;
|
use App\Service\Docuseal\SignClient;
|
||||||
@@ -34,6 +35,7 @@ use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
|||||||
#[AsEventListener(event: CreateAvisEvent::class, method: 'onCreatedAvisEvent')]
|
#[AsEventListener(event: CreateAvisEvent::class, method: 'onCreatedAvisEvent')]
|
||||||
#[AsEventListener(event: CreateAvisEventSend::class, method: 'onCreatedAvisEventSend')]
|
#[AsEventListener(event: CreateAvisEventSend::class, method: 'onCreatedAvisEventSend')]
|
||||||
#[AsEventListener(event: CreateFactureEvent::class, method: 'onCreateFactureEvent')]
|
#[AsEventListener(event: CreateFactureEvent::class, method: 'onCreateFactureEvent')]
|
||||||
|
#[AsEventListener(event: CreateFactureEventSend::class, method: 'onCreateFactureEventSend')]
|
||||||
#[AsEventListener(event: SiteconseilAdvertPaymentComplete::class, method: 'onSiteconseilAdvertPaymentComplete')]
|
#[AsEventListener(event: SiteconseilAdvertPaymentComplete::class, method: 'onSiteconseilAdvertPaymentComplete')]
|
||||||
#[AsEventListener(event: CustomerAdvertPaymentComplete::class, method: 'onCustomerAdvertPaymentComplete')]
|
#[AsEventListener(event: CustomerAdvertPaymentComplete::class, method: 'onCustomerAdvertPaymentComplete')]
|
||||||
class BillingEventSusbriber
|
class BillingEventSusbriber
|
||||||
@@ -57,11 +59,28 @@ class BillingEventSusbriber
|
|||||||
$currentAdvert = $advertPaymentComplete->getCurrentAdvertPayment();
|
$currentAdvert = $advertPaymentComplete->getCurrentAdvertPayment();
|
||||||
/** @var CustomerAdvertPayment $parent */
|
/** @var CustomerAdvertPayment $parent */
|
||||||
$parent = $advertPaymentComplete->getParentAdvert();
|
$parent = $advertPaymentComplete->getParentAdvert();
|
||||||
|
|
||||||
|
$register = $advertPaymentComplete->getCustomerAdvertPaymentRegister();
|
||||||
|
$customer = $currentAdvert->getCustomer();
|
||||||
|
$this->mailer->sendMulti(["jovann@siteconseil.fr","legrand@siteconseil.fr"],"[SARL SITECONSEIL] - Validation d'un paiement par le client","mails/customer/validate_paiement_customer.twig",[
|
||||||
|
'customer' => $customer,
|
||||||
|
'advert' => $currentAdvert,
|
||||||
|
'parent' => $parent,
|
||||||
|
'register' => $register,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onCustomerAdvertPaymentComplete(CustomerAdvertPaymentComplete $advertPaymentComplete): void
|
public function onCustomerAdvertPaymentComplete(CustomerAdvertPaymentComplete $advertPaymentComplete): void
|
||||||
{
|
{
|
||||||
$currentAdvert = $advertPaymentComplete->getCurrentAdvertPayment();
|
$currentAdvert = $advertPaymentComplete->getCurrentAdvertPayment();
|
||||||
|
$register = $advertPaymentComplete->getCustomerAdvertPaymentRegister();
|
||||||
|
$customer = $currentAdvert->getCustomer();
|
||||||
|
|
||||||
|
$this->mailer->send($customer->mainContact()->getEmail(),$customer->getRaisonSocial(),"[SARL SITECONSEIL] - Validation de votre paiement","mails/customer/validate_paiement.twig",[
|
||||||
|
'customer' => $customer,
|
||||||
|
'advert' => $currentAdvert,
|
||||||
|
'register' => $register,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onCustomerSendPasswordEmail(CustomerSendPasswordEmail $customerSendPasswordEmail)
|
public function onCustomerSendPasswordEmail(CustomerSendPasswordEmail $customerSendPasswordEmail)
|
||||||
@@ -97,14 +116,55 @@ class BillingEventSusbriber
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onCreateFactureEventSend(CreateFactureEventSend $createFactureEventSend): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$createAvis = $createFactureEventSend->getCustomerOrder();
|
||||||
|
$contentCgv = file_get_contents($this->kernel->getProjectDir()."/public/cgv.pdf");
|
||||||
|
|
||||||
|
$files =[];
|
||||||
|
$files[] = new DataPart(file_get_contents($this->kernel->getProjectDir()."/public".$this->uploaderHelper->asset($createAvis,"facture")),"FACTURE - ".$createAvis->getNumOrder().".pdf");
|
||||||
|
$files[] = new DataPart($contentCgv,"Conditions Générale de Vente.pdf");
|
||||||
|
|
||||||
|
$amountHt=0;
|
||||||
|
$amount=0;
|
||||||
|
foreach ($createAvis->getCustomerOrderLines() as $line) {
|
||||||
|
$amount = $amount + ($line->getPriceHt()*1.20);
|
||||||
|
$amountHt = $amountHt + floatval($line->getPriceHt());
|
||||||
|
}
|
||||||
|
$this->mailer->send($createAvis->getCustomer()->mainContact()->getEmail(),$createAvis->getCustomer()->getRaisonSocial(),"[SARL SITECONSEIL] - Votre facture n° ".$createAvis->getNumOrder(),"mails/customer/facture-payment.twig",[
|
||||||
|
'createAvis' => $createAvis,
|
||||||
|
'paymentNotice' => [
|
||||||
|
'number' => $createAvis->getNumOrder(),
|
||||||
|
'amountHt' => $amountHt,
|
||||||
|
'amount' => $amount,
|
||||||
|
],
|
||||||
|
'customer' => $createAvis->getCustomer(),
|
||||||
|
],$files);
|
||||||
|
}
|
||||||
|
|
||||||
public function onCreateFactureEvent(CreateFactureEvent $event)
|
public function onCreateFactureEvent(CreateFactureEvent $event)
|
||||||
{
|
{
|
||||||
$order = $event->getCustomerOrder();
|
$order = $event->getCustomerOrder();
|
||||||
$isSend = $event->isSend();
|
$isSend = $event->isSend();
|
||||||
|
|
||||||
$pdf = New FacturePdf($this->kernel,$order);
|
$pdf = New FacturePdf($this->kernel,$order,true);
|
||||||
|
$tmpname = Uuid::v4().".pdf";
|
||||||
|
$dir = sys_get_temp_dir().'/'.$tmpname;
|
||||||
$pdf->generate();
|
$pdf->generate();
|
||||||
$pdf->Output('I');
|
$content = $pdf->Output('S');
|
||||||
|
file_put_contents($dir,$content);
|
||||||
|
$pathSign = $this->signClient->signOrder($content,$order);
|
||||||
|
|
||||||
|
unlink($dir);
|
||||||
|
file_put_contents($dir,file_get_contents($pathSign));
|
||||||
|
$upload = new UploadedFile($dir,"avis-".$order->getNumOrder().".pdf","application/pdf",0,true);
|
||||||
|
$order->setFacture($upload);
|
||||||
|
|
||||||
|
$this->entityManager->persist($order);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->onCreateFactureEventSend(new CreateFactureEventSend($order));
|
||||||
}
|
}
|
||||||
public function onCreatedAvisEventSend(CreateAvisEventSend $createAvisEventSend)
|
public function onCreatedAvisEventSend(CreateAvisEventSend $createAvisEventSend)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
namespace App\Service\Docuseal;
|
namespace App\Service\Docuseal;
|
||||||
|
|
||||||
use App\Entity\CustomerDevis;
|
use App\Entity\CustomerDevis;
|
||||||
|
use App\Entity\CustomerOrder;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
||||||
|
|
||||||
@@ -16,7 +18,8 @@ class SignClient
|
|||||||
private readonly RequestStack $requestStack,
|
private readonly RequestStack $requestStack,
|
||||||
private readonly UploaderHelper $uploaderHelper,
|
private readonly UploaderHelper $uploaderHelper,
|
||||||
private readonly UrlGeneratorInterface $urlGenerator,
|
private readonly UrlGeneratorInterface $urlGenerator,
|
||||||
private readonly EntityManagerInterface $entityManager
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
private readonly KernelInterface $kernelInterface,
|
||||||
) {
|
) {
|
||||||
$key = $_ENV['DOCUSIGN_KEY'] ?? '';
|
$key = $_ENV['DOCUSIGN_KEY'] ?? '';
|
||||||
$url = $_ENV['DOCUSIGN_URL'] ?? '';
|
$url = $_ENV['DOCUSIGN_URL'] ?? '';
|
||||||
@@ -62,4 +65,34 @@ class SignClient
|
|||||||
|
|
||||||
return "https://signature.esy-web.dev/s/" . $submissionData['slug'];
|
return "https://signature.esy-web.dev/s/" . $submissionData['slug'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function signOrder(string $content,CustomerOrder $customerOrder)
|
||||||
|
{
|
||||||
|
$currentRequest = $this->requestStack->getCurrentRequest();
|
||||||
|
|
||||||
|
if(file_exists($this->kernelInterface->getProjectDir()."/public/tmp-sign/facture.pdf"))
|
||||||
|
unlink($this->kernelInterface->getProjectDir()."/public/tmp-sign/facture.pdf");
|
||||||
|
file_put_contents($this->kernelInterface->getProjectDir()."/public/tmp-sign/facture.pdf",$content);
|
||||||
|
|
||||||
|
$submission = $this->docuseal->createSubmissionFromPdf([
|
||||||
|
'name' => 'Facture N°' . $customerOrder->getNumOrder(),
|
||||||
|
'documents' => [
|
||||||
|
[
|
||||||
|
'name' => 'facture',
|
||||||
|
'file' => $this->requestStack->getCurrentRequest()."/tmp-sign/facture.pdf",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'submitters' => [
|
||||||
|
[
|
||||||
|
'role' => 'SARL SITECONSEIL',
|
||||||
|
'completed' => true,
|
||||||
|
'email' => 's.com@siteconseil.fr'
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$submiter = $this->docuseal->getSubmitter($submission['submitters'][0]['id']);
|
||||||
|
$path = $submiter['documents'][0]['url'];
|
||||||
|
return $path;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/Service/Echeance/EcheanceEventSusbriber.php
Normal file
27
src/Service/Echeance/EcheanceEventSusbriber.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\Echeance;
|
||||||
|
|
||||||
|
use App\Service\Docuseal\SignClient;
|
||||||
|
use App\Service\Pdf\EchPdfDetails;
|
||||||
|
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
|
||||||
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
|
|
||||||
|
#[AsEventListener(event: EventEcheanceCreated::class, method: 'onEventEcheanceCreated')]
|
||||||
|
class EcheanceEventSusbriber
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly SignClient $signClient,
|
||||||
|
private readonly KernelInterface $kernel
|
||||||
|
){
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEventEcheanceCreated(EventEcheanceCreated $event) {
|
||||||
|
$ech = $event->getCustomerSplit();
|
||||||
|
|
||||||
|
$pdf = new EchPdfDetails($this->kernel,$ech);
|
||||||
|
$pdf->generated();
|
||||||
|
$content = $pdf->Output('I');
|
||||||
|
dd($content);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Service/Echeance/EventEcheanceCreated.php
Normal file
20
src/Service/Echeance/EventEcheanceCreated.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\Echeance;
|
||||||
|
|
||||||
|
use App\Entity\CustomerSplit;
|
||||||
|
|
||||||
|
class EventEcheanceCreated
|
||||||
|
{
|
||||||
|
public function __construct(private CustomerSplit $customerSplit)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CustomerSplit
|
||||||
|
*/
|
||||||
|
public function getCustomerSplit(): CustomerSplit
|
||||||
|
{
|
||||||
|
return $this->customerSplit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ class DevisPdf extends FPDF
|
|||||||
public function Header(): void
|
public function Header(): void
|
||||||
{
|
{
|
||||||
$this->SetFont('Arial', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Image($this->kernel->getProjectDir() . "/public/assets/logo_siteconseil.png", 90, 5, 25);
|
||||||
|
|
||||||
$formatter = new IntlDateFormatter(
|
$formatter = new IntlDateFormatter(
|
||||||
'fr_FR',
|
'fr_FR',
|
||||||
|
|||||||
288
src/Service/Pdf/EchPdfDetails.php
Normal file
288
src/Service/Pdf/EchPdfDetails.php
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\Pdf;
|
||||||
|
|
||||||
|
use App\Entity\CustomerSplit;
|
||||||
|
use Fpdf\Fpdf;
|
||||||
|
use IntlDateFormatter;
|
||||||
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
use App\Entity\Account; // Import inutile, laissé pour garder la cohérence avec le code fourni
|
||||||
|
|
||||||
|
// Define the EURO symbol as it's often missing in standard character sets for FPDF's ISO-8859-1
|
||||||
|
if (!defined('EURO_ECH')) {
|
||||||
|
define('EURO_ECH', chr(128));
|
||||||
|
}
|
||||||
|
|
||||||
|
class EchPdfDetails extends FPDF
|
||||||
|
{
|
||||||
|
private array $items;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly KernelInterface $kernel,
|
||||||
|
private readonly CustomerSplit $customerSplit,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
foreach ($this->customerSplit->getCustomerSplitLines() as $line) {
|
||||||
|
$items[] = [
|
||||||
|
'dates' => $line->getDatePrev(),
|
||||||
|
'amount' => $line->getAmount(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// Assuming ksort was intended to sort by date, but it sorts by key.
|
||||||
|
// Given $items is a simple array of indexed arrays, ksort does nothing useful here.
|
||||||
|
// If sorting by date is needed, a custom sort function should be used.
|
||||||
|
// For now, I'll keep the original logic but note the intent.
|
||||||
|
// ksort($items);
|
||||||
|
$this->items = $items;
|
||||||
|
|
||||||
|
$title = mb_convert_encoding("FACILITE DE PAIEMENT N° " . $this->customerSplit->getNum(), "ISO-8859-1", "UTF-8");
|
||||||
|
$this->SetTitle($title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Header(): void
|
||||||
|
{
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Image($this->kernel->getProjectDir() . "/public/assets/logo_siteconseil.png", 90, 5, 25);
|
||||||
|
|
||||||
|
$formatter = new IntlDateFormatter(
|
||||||
|
'fr_FR',
|
||||||
|
IntlDateFormatter::FULL,
|
||||||
|
IntlDateFormatter::NONE,
|
||||||
|
'Europe/Paris',
|
||||||
|
IntlDateFormatter::GREGORIAN
|
||||||
|
);
|
||||||
|
|
||||||
|
// Uniformisation de l'encodage en 'ISO-8859-1'
|
||||||
|
$numDevisText = mb_convert_encoding("FACILITE DE PAIEMENT N° " . $this->customerSplit->getNum(), 'ISO-8859-1', 'UTF-8');
|
||||||
|
$dateText = mb_convert_encoding("Saint-Quentin, " . $formatter->format($this->customerSplit->getCreateAt()), 'ISO-8859-1', 'UTF-8');
|
||||||
|
|
||||||
|
$this->Text(15, 80, $numDevisText);
|
||||||
|
$this->Text(15, 85, $dateText);
|
||||||
|
|
||||||
|
$this->SetFont('Arial', 'B', 12);
|
||||||
|
|
||||||
|
$y = 60;
|
||||||
|
$customer = $this->customerSplit->getCustomer();
|
||||||
|
|
||||||
|
// Uniformisation de l'encodage en 'ISO-8859-1'
|
||||||
|
$this->Text(110, $y, mb_convert_encoding($customer->getRaisonSocial(), 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$y += 5;
|
||||||
|
$this->Text(110, $y, mb_convert_encoding($customer->getAddress(), 'ISO-8859-1', 'UTF-8'));
|
||||||
|
|
||||||
|
if ($address2 = $customer->getAddress2()) {
|
||||||
|
$y += 5;
|
||||||
|
$this->Text(110, $y, mb_convert_encoding($address2, 'ISO-8859-1', 'UTF-8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($address3 = $customer->getAddress3()) {
|
||||||
|
$y += 5;
|
||||||
|
$this->Text(110, $y, mb_convert_encoding($address3, 'ISO-8859-1', 'UTF-8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$y += 5;
|
||||||
|
$cityLine = $customer->getZipcode() . " " . $customer->getCity();
|
||||||
|
$this->Text(110, $y, mb_convert_encoding($cityLine, 'ISO-8859-1', 'UTF-8'));
|
||||||
|
|
||||||
|
// Add a line break after the header to start the content below.
|
||||||
|
$this->SetY(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function generated(): void
|
||||||
|
{
|
||||||
|
$this->AddPage(); // Ensure a page is available
|
||||||
|
$this->SetY(105); // Start position after the header
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->SetTextColor(0, 0, 0);
|
||||||
|
|
||||||
|
// Calculate total amount and number of installments
|
||||||
|
$totalAmount = 0.0;
|
||||||
|
$installmentsCount = count($this->items);
|
||||||
|
foreach ($this->items as $item) {
|
||||||
|
$totalAmount += $item['amount'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format total amount with two decimals
|
||||||
|
$formattedTotalAmount = number_format($totalAmount, 2, ',', ' ');
|
||||||
|
|
||||||
|
// Main text introduction
|
||||||
|
$introText = "Voici la facilité de paiement qui vous a été accordée :";
|
||||||
|
$this->Write(5, mb_convert_encoding($introText, 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->Ln(8);
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
// --- CLAUSE : Rétractation ---
|
||||||
|
// ----------------------------------------------
|
||||||
|
$this->SetFont('Arial', 'U', 10); // Souligné
|
||||||
|
$retractTitle = "Droit de Rétractation";
|
||||||
|
$this->Write(5, mb_convert_encoding($retractTitle, 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Ln(5);
|
||||||
|
|
||||||
|
// Correction du problème de mise en gras de l'email
|
||||||
|
$this->Write(5, mb_convert_encoding("Pour vous rétracter de cette facilité de paiement, vous devez envoyer un mail à l'adresse ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10); // DÉBUT GRAS
|
||||||
|
$this->Write(5, mb_convert_encoding("s.com@siteconseil.fr", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10); // FIN GRAS
|
||||||
|
$retractTextEnd = " pour en demander l'annulation, à condition qu'aucun paiement n'ait déjà été effectué.";
|
||||||
|
$this->Write(5, mb_convert_encoding($retractTextEnd, 'ISO-8859-1', 'UTF-8')); // Utilisation de Write() pour continuer sur la même ligne
|
||||||
|
$this->Ln(8);
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
// --- CLAUSE : Limitation et Impayé ---
|
||||||
|
// ----------------------------------------------
|
||||||
|
$this->SetFont('Arial', 'I', 10); // Italique
|
||||||
|
$limitationText = "Attention : Une seule facilité de paiement peut être accordée à la fois. Tout impayé entraînera l'impossibilité de demander une nouvelle facilité de paiement.";
|
||||||
|
$this->MultiCell(180, 5, mb_convert_encoding($limitationText, 'ISO-8859-1', 'UTF-8'), 0, 'L');
|
||||||
|
$this->Ln(8);
|
||||||
|
$this->SetFont('Arial', '', 10); // Retour à la police normale
|
||||||
|
|
||||||
|
// Summary details - Displayed in parts to allow for bolding
|
||||||
|
$this->Write(5, mb_convert_encoding("Cette facilité de paiement est répartie sur ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding($installmentsCount . " mensualité(s)", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding(" pour un montant total de ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding($formattedTotalAmount. " ", 'ISO-8859-1', 'UTF-8').EURO_ECH);
|
||||||
|
|
||||||
|
$this->Ln(10);
|
||||||
|
|
||||||
|
// Reset font for the rest of the content
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
|
||||||
|
// Add installment details table
|
||||||
|
if (!empty($this->items)) {
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Cell(50, 7, mb_convert_encoding('Échéance', 'ISO-8859-1', 'UTF-8'), 1, 0, 'C');
|
||||||
|
$this->Cell(50, 7, mb_convert_encoding('Montant', 'ISO-8859-1', 'UTF-8'), 1, 1, 'C');
|
||||||
|
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$formatter = new IntlDateFormatter(
|
||||||
|
'fr_FR',
|
||||||
|
IntlDateFormatter::SHORT,
|
||||||
|
IntlDateFormatter::NONE,
|
||||||
|
'Europe/Paris',
|
||||||
|
IntlDateFormatter::GREGORIAN
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($this->items as $item) {
|
||||||
|
// Assuming 'dates' is a \DateTimeInterface object
|
||||||
|
$dateText = $formatter->format($item['dates']);
|
||||||
|
$amountText = number_format($item['amount'], 2, ',', ' ');
|
||||||
|
|
||||||
|
$this->Cell(50, 6, mb_convert_encoding($dateText, 'ISO-8859-1', 'UTF-8'), 1, 0, 'C');
|
||||||
|
$this->Cell(50, 6, mb_convert_encoding($amountText, 'ISO-8859-1', 'UTF-8')." ".EURO_ECH, 1, 1, 'R');
|
||||||
|
}
|
||||||
|
$this->Ln(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- SECTION: Default Payment Clause & Services Suspension ---
|
||||||
|
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->SetTextColor(255, 0, 0); // Red color for emphasis
|
||||||
|
$defaultTitle = "Conséquences en cas de défaut de paiement :";
|
||||||
|
$this->Write(5, mb_convert_encoding($defaultTitle, 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->Ln(7);
|
||||||
|
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->SetTextColor(0, 0, 0); // Reset to black
|
||||||
|
|
||||||
|
// 1. Regularization Clause (7 days) with manual bolding
|
||||||
|
$this->Write(5, mb_convert_encoding("En cas de défaut de paiement à l'échéance convenue, vous disposerez d'un délai de ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding("7 jours calendaires", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding(" pour régulariser votre situation. Passé ce délai, la présente facilité de paiement sera ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding("immédiatement rompue", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding(" et l'intégralité des sommes restant dues deviendra exigible, ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding("sans qu'aucun remboursement ne puisse être accordé", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding(".", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
|
||||||
|
$this->Ln(5);
|
||||||
|
|
||||||
|
// 2. Service Suspension Clause and Collection with manual bolding
|
||||||
|
$this->Write(5, mb_convert_encoding("Tout défaut de paiement entraînera la ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding("suspension immédiate des services associés", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding(" et la créance pourra être transmise à une ", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding("société de recouvrement", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Write(5, mb_convert_encoding(".", 'ISO-8859-1', 'UTF-8'));
|
||||||
|
|
||||||
|
$this->Ln(15);
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
// --- Signature Blocks ---
|
||||||
|
// ----------------------------------------------
|
||||||
|
|
||||||
|
$this->SetFont('Arial', 'B', 10);
|
||||||
|
|
||||||
|
// Signature Block for the Client
|
||||||
|
$this->Cell(80, 5, mb_convert_encoding('Le Client', 'ISO-8859-1', 'UTF-8'), 0, 0, 'C');
|
||||||
|
|
||||||
|
// Separator/Spacer
|
||||||
|
$this->Cell(30, 5, '', 0, 0, 'C');
|
||||||
|
|
||||||
|
// Signature Block for SARL SITECONSEIL
|
||||||
|
$this->Cell(80, 5, mb_convert_encoding('SARL SITECONSEIL', 'ISO-8859-1', 'UTF-8'), 0, 1, 'C'); // 1 = Go to next line
|
||||||
|
|
||||||
|
$this->Ln(5); // Vertical space for the signature line and placeholder
|
||||||
|
|
||||||
|
// Signature Line for the Client
|
||||||
|
$this->Cell(80, 0, '', 'T', 0, 'C'); // 'T' for Top border (the line)
|
||||||
|
|
||||||
|
// Separator/Spacer
|
||||||
|
$this->Cell(30, 0, '', 0, 0, 'C');
|
||||||
|
|
||||||
|
// Signature Line for SARL SITECONSEIL
|
||||||
|
$this->Cell(80, 0, '', 'T', 1, 'C'); // 1 = Go to next line
|
||||||
|
|
||||||
|
$this->SetY($this->GetY() - 5); // Remonte d'une ligne pour aligner les marqueurs
|
||||||
|
|
||||||
|
// Add Signature Placeholder for the Client
|
||||||
|
$this->SetX(15);
|
||||||
|
$this->Cell(70, 5, '{{Signature;type=signature;role=Client}}', 0, 0, 'C');
|
||||||
|
|
||||||
|
// Separator/Spacer
|
||||||
|
$this->Cell(30, 5, '', 0, 0, 'C');
|
||||||
|
|
||||||
|
$t = new \DateTimeImmutable();
|
||||||
|
// Add Acceptance Text for SARL SITECONSEIL (Restored previous logic)
|
||||||
|
$this->Cell(80, 5, mb_convert_encoding("Accepter le ".$t->format('d/m/y H:i'), 'ISO-8859-1', 'UTF-8'), 0, 1, 'C');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Footer()
|
||||||
|
{
|
||||||
|
// This is where FPDF positions the footer content, regardless of the page content length.
|
||||||
|
|
||||||
|
// SetY(-30) ensures the pointer is 30mm from the bottom, placing the footer reliably.
|
||||||
|
$this->SetY(-30);
|
||||||
|
|
||||||
|
$this->SetFont('Arial', 'B', 8);
|
||||||
|
$this->SetTextColor(253, 140,4);
|
||||||
|
$this->SetDrawColor(253, 140,4);
|
||||||
|
$this->Cell(190, 5, mb_convert_encoding("Partenaire de vos projects de puis 1997", 'ISO-8859-1', 'UTF-8'), 0, 1,'C');
|
||||||
|
$this->Line(15,$this->GetY(),195,$this->GetY());
|
||||||
|
$this->SetFont('Arial', '', 8);
|
||||||
|
$this->SetTextColor(0, 0, 0);
|
||||||
|
$this->Ln(2);
|
||||||
|
$this->Cell(190, 4, mb_convert_encoding("27, rue le Sérurier - 02100 SAINT-QUENTIN - Tél: 03 23 05 62 43 - Réglement par virement: FR76 1020 6006 7198 7497 7981 061", 'ISO-8859-1', 'UTF-8'), 0, 1,'C');
|
||||||
|
$this->Cell(190, 4, mb_convert_encoding("e-mail : s.com@siteconseil.fr - www.siteconseil.fr", 'ISO-8859-1', 'UTF-8'), 0, 1,'C');
|
||||||
|
$this->Cell(190, 4, mb_convert_encoding("S.A.R.L aux captial de 71400 ", 'ISO-8859-1', 'UTF-8').EURO_ECH." - ".mb_convert_encoding("N°SIRET 418 664 058 00025 - N° TVA FR 05 418 664 058 - CODE APE 6201 Z - R.C. St-Quentin 418 664 058", 'ISO-8859-1', 'UTF-8'), 0,0 ,'C');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Service\Pdf;
|
namespace App\Service\Pdf;
|
||||||
|
|
||||||
|
use App\Entity\Customer;
|
||||||
|
use App\Entity\CustomerAdvertPayment;
|
||||||
use App\Entity\CustomerOrder;
|
use App\Entity\CustomerOrder;
|
||||||
use Fpdf\Fpdf;
|
use Fpdf\Fpdf;
|
||||||
use IntlDateFormatter;
|
use IntlDateFormatter;
|
||||||
@@ -15,12 +17,13 @@ class FacturePdf extends Fpdf
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly KernelInterface $kernel,
|
private readonly KernelInterface $kernel,
|
||||||
private readonly CustomerOrder $customerDevis
|
private readonly CustomerOrder $customerOrder,
|
||||||
|
private readonly bool $showSign
|
||||||
) {
|
) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$items = [];
|
$items = [];
|
||||||
foreach ($this->customerDevis->getCustomerOrderLines() as $line) {
|
foreach ($this->customerOrder->getCustomerOrderLines() as $line) {
|
||||||
$items[$line->getPo()] = [
|
$items[$line->getPo()] = [
|
||||||
'title' => $line->getName(),
|
'title' => $line->getName(),
|
||||||
'content' => $line->getContent(),
|
'content' => $line->getContent(),
|
||||||
@@ -28,17 +31,18 @@ class FacturePdf extends Fpdf
|
|||||||
'priceTTC' => round(1.20 * $line->getPriceHT(), 2),
|
'priceTTC' => round(1.20 * $line->getPriceHT(), 2),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($items);
|
ksort($items);
|
||||||
$this->items = $items;
|
$this->items = $items;
|
||||||
|
|
||||||
$title = mb_convert_encoding("Facture N° " . $this->customerDevis->getNumOrder(), "ISO-8859-1", "UTF-8");
|
$title = mb_convert_encoding("Facture N° " . $this->customerOrder->getNumOrder(), "ISO-8859-1", "UTF-8");
|
||||||
$this->SetTitle($title);
|
$this->SetTitle($title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Header(): void
|
public function Header(): void
|
||||||
{
|
{
|
||||||
$this->SetFont('Arial', '', 10);
|
$this->SetFont('Arial', '', 10);
|
||||||
|
$this->Image($this->kernel->getProjectDir() . "/public/assets/logo_siteconseil.png", 90, 5, 25);
|
||||||
$formatter = new IntlDateFormatter(
|
$formatter = new IntlDateFormatter(
|
||||||
'fr_FR',
|
'fr_FR',
|
||||||
IntlDateFormatter::FULL,
|
IntlDateFormatter::FULL,
|
||||||
@@ -47,15 +51,16 @@ class FacturePdf extends Fpdf
|
|||||||
IntlDateFormatter::GREGORIAN
|
IntlDateFormatter::GREGORIAN
|
||||||
);
|
);
|
||||||
|
|
||||||
$factureNumber = mb_convert_encoding("Facture N° " . $this->customerDevis->getNumOrder(), 'ISO-8859-1', 'UTF-8');
|
$numDevisText = mb_convert_encoding("Facture N° " . $this->customerOrder->getNumOrder(), 'ISO-8859-1', 'UTF-8');
|
||||||
$dateFacture = mb_convert_encoding("Saint-Quentin, " . $formatter->format($this->customerDevis->getCreateAt()), 'ISO-8859-1', 'UTF-8');
|
$dateText = mb_convert_encoding("Saint-Quentin, " . $formatter->format($this->customerOrder->getCreateAt()), 'ISO-8859-1', 'UTF-8');
|
||||||
|
|
||||||
$this->Text(15, 80, $factureNumber);
|
$this->Text(15, 80, $numDevisText);
|
||||||
$this->Text(15, 85, $dateFacture);
|
$this->Text(15, 85, $dateText);
|
||||||
|
|
||||||
$this->SetFont('Arial', 'B', 12);
|
$this->SetFont('Arial', 'B', 12);
|
||||||
|
|
||||||
$y = 60;
|
$y = 60;
|
||||||
$customer = $this->customerDevis->getCustomer();
|
$customer = $this->customerOrder->getCustomer();
|
||||||
|
|
||||||
$this->Text(110, $y, mb_convert_encoding($customer->getRaisonSocial(), 'ISO-8859-1', 'UTF-8'));
|
$this->Text(110, $y, mb_convert_encoding($customer->getRaisonSocial(), 'ISO-8859-1', 'UTF-8'));
|
||||||
$y += 5;
|
$y += 5;
|
||||||
@@ -72,13 +77,9 @@ class FacturePdf extends Fpdf
|
|||||||
}
|
}
|
||||||
|
|
||||||
$y += 5;
|
$y += 5;
|
||||||
$this->Text(110, $y, mb_convert_encoding(
|
$cityLine = $customer->getZipcode() . " " . $customer->getCity();
|
||||||
$customer->getZipcode() . " " . $customer->getCity(),
|
$this->Text(110, $y, mb_convert_encoding($cityLine, 'ISO-8859-1', 'UTF-8'));
|
||||||
'ISO-8859-1',
|
|
||||||
'UTF-8'
|
|
||||||
));
|
|
||||||
|
|
||||||
$this->SetFont('Arial', '', 12);
|
|
||||||
$this->body();
|
$this->body();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ class FacturePdf extends Fpdf
|
|||||||
foreach ($this->items as $item) {
|
foreach ($this->items as $item) {
|
||||||
if ($this->GetY() + 30 > $contentBottomLimit) {
|
if ($this->GetY() + 30 > $contentBottomLimit) {
|
||||||
$this->AddPage();
|
$this->AddPage();
|
||||||
$this->body(); // redraw headers
|
$this->body(); // redraw table headers
|
||||||
$this->SetY($startY);
|
$this->SetY($startY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +120,10 @@ class FacturePdf extends Fpdf
|
|||||||
$this->SetFont('Arial', 'B', 11);
|
$this->SetFont('Arial', 'B', 11);
|
||||||
$this->Cell(95, 10, mb_convert_encoding($item['title'], 'ISO-8859-1', 'UTF-8'), 0, 0);
|
$this->Cell(95, 10, mb_convert_encoding($item['title'], 'ISO-8859-1', 'UTF-8'), 0, 0);
|
||||||
|
|
||||||
// Price HT
|
// Prices
|
||||||
$this->SetFont('Arial', 'B', 11);
|
$this->SetFont('Arial', '', 11);
|
||||||
$this->SetXY(142, $currentY);
|
$this->SetXY(142, $currentY);
|
||||||
|
$this->SetFont('Arial', 'B', 11);
|
||||||
$this->Cell(39, 8, number_format($item['priceHt'], 2, ",") . " " . EURO_FACTURE, 0, 1, 'R');
|
$this->Cell(39, 8, number_format($item['priceHt'], 2, ",") . " " . EURO_FACTURE, 0, 1, 'R');
|
||||||
$this->SetFont('Arial', '', 11);
|
$this->SetFont('Arial', '', 11);
|
||||||
|
|
||||||
@@ -135,6 +137,22 @@ class FacturePdf extends Fpdf
|
|||||||
$this->displaySummary();
|
$this->displaySummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function Footer()
|
||||||
|
{
|
||||||
|
$this->Ln(10);
|
||||||
|
$this->SetFont('Arial', 'B', 8);
|
||||||
|
$this->SetTextColor(253, 140,4);
|
||||||
|
$this->SetDrawColor(253, 140,4);
|
||||||
|
$this->Cell(190, 5, mb_convert_encoding("Partenaire de vos projects de puis 1997", 'ISO-8859-1', 'UTF-8'), 0, 1,'C');
|
||||||
|
$this->Line(15,$this->GetY(),195,$this->GetY());
|
||||||
|
$this->SetFont('Arial', '', 8);
|
||||||
|
$this->SetTextColor(0, 0, 0);
|
||||||
|
$this->Ln(2);
|
||||||
|
$this->Cell(190, 4, mb_convert_encoding("27, rue le Sérurier - 02100 SAINT-QUENTIN - Tél: 03 23 05 62 43", 'ISO-8859-1', 'UTF-8'), 0, 1,'C');
|
||||||
|
$this->Cell(190, 4, mb_convert_encoding("e-mail : s.com@siteconseil.fr - www.siteconseil.fr", 'ISO-8859-1', 'UTF-8'), 0, 1,'C');
|
||||||
|
$this->Cell(190, 4, mb_convert_encoding("S.A.R.L aux captial de 71400 ", 'ISO-8859-1', 'UTF-8').EURO_FACTURE." - ".mb_convert_encoding("N°SIRET 418 664 058 00025 - N° TVA FR 05 418 664 058 - CODE APE 6201 Z - R.C. St-Quentin 418 664 058", 'ISO-8859-1', 'UTF-8'), 0,0 ,'C');
|
||||||
|
}
|
||||||
|
|
||||||
private function displaySummary(): void
|
private function displaySummary(): void
|
||||||
{
|
{
|
||||||
$totalHT = array_sum(array_column($this->items, 'priceHt'));
|
$totalHT = array_sum(array_column($this->items, 'priceHt'));
|
||||||
@@ -142,6 +160,7 @@ class FacturePdf extends Fpdf
|
|||||||
$totalTTC = $totalHT + $totalTVA;
|
$totalTTC = $totalHT + $totalTVA;
|
||||||
|
|
||||||
$this->SetY(-60);
|
$this->SetY(-60);
|
||||||
|
$this->SetFont('Arial', '', 10);
|
||||||
|
|
||||||
$this->SetFont('Arial', '', 12);
|
$this->SetFont('Arial', '', 12);
|
||||||
$this->Cell(135, 10, mb_convert_encoding('Total HT :', 'ISO-8859-1', 'UTF-8'), 0, 0, 'R');
|
$this->Cell(135, 10, mb_convert_encoding('Total HT :', 'ISO-8859-1', 'UTF-8'), 0, 0, 'R');
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use App\Entity\Customer;
|
|||||||
use App\Entity\CustomerAdvertPayment;
|
use App\Entity\CustomerAdvertPayment;
|
||||||
use App\Entity\CustomerDevis;
|
use App\Entity\CustomerDevis;
|
||||||
use App\Entity\CustomerDns;
|
use App\Entity\CustomerDns;
|
||||||
|
use App\Entity\CustomerOrder;
|
||||||
|
use App\Entity\CustomerSplit;
|
||||||
use Twig\Extension\AbstractExtension;
|
use Twig\Extension\AbstractExtension;
|
||||||
use Twig\TwigFilter;
|
use Twig\TwigFilter;
|
||||||
use Twig\TwigFunction;
|
use Twig\TwigFunction;
|
||||||
@@ -19,8 +21,19 @@ class TwigOrderExtensions extends AbstractExtension
|
|||||||
new TwigFilter('totalOrder',[$this,'totalOrder']),
|
new TwigFilter('totalOrder',[$this,'totalOrder']),
|
||||||
new TwigFilter('countEmail',[$this,'countEmail']),
|
new TwigFilter('countEmail',[$this,'countEmail']),
|
||||||
new TwigFilter('skFormat',[$this,'skFormat']),
|
new TwigFilter('skFormat',[$this,'skFormat']),
|
||||||
|
new TwigFilter('noCompletedEch',[$this,'noCompletedEch']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function noCompletedEch(CustomerSplit $customerSplit)
|
||||||
|
{
|
||||||
|
$nbEch = 0;
|
||||||
|
foreach ($customerSplit->getCustomerSplitLines() as $customerSplitLine) {
|
||||||
|
if($customerSplitLine->getState() != "completed")
|
||||||
|
$nbEch++;
|
||||||
|
}
|
||||||
|
return $nbEch;
|
||||||
|
}
|
||||||
public function getFunctions()
|
public function getFunctions()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -59,6 +72,14 @@ class TwigOrderExtensions extends AbstractExtension
|
|||||||
|
|
||||||
public function totalOrder($object): float|int
|
public function totalOrder($object): float|int
|
||||||
{
|
{
|
||||||
|
if($object instanceof CustomerOrder) {
|
||||||
|
$total = 0;
|
||||||
|
foreach ($object->getCustomerOrderLines() as $customerDevisLine){
|
||||||
|
$total = $total + (1.20*$customerDevisLine->getPriceHT());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
if($object instanceof CustomerAdvertPayment) {
|
if($object instanceof CustomerAdvertPayment) {
|
||||||
$total = 0;
|
$total = 0;
|
||||||
foreach ($object->getCustomerAdvertPaymentLines() as $customerDevisLine){
|
foreach ($object->getCustomerAdvertPaymentLines() as $customerDevisLine){
|
||||||
|
|||||||
20
templates/admin/payement_no_complete.twig
Normal file
20
templates/admin/payement_no_complete.twig
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{% extends 'admin/base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="max-w-md w-full space-y-8 p-10 rounded-xl shadow-lg bg-gray-700">
|
||||||
|
<div class="text-center">
|
||||||
|
<h2 class="mt-6 text-3xl font-extrabold text-white">
|
||||||
|
Le paiement n'a pas été effectuée
|
||||||
|
</h2>
|
||||||
|
<a href="{{ path('app_payment',{id:advert.id}) }}" style="margin-top: 5rem" class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md text-center transition duration-300 ease-in-out">
|
||||||
|
Retenter le paiement
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
Paiement réussi !
|
||||||
|
{% endblock %}
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script src="https://signature.esy-web.dev/js/form.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
<body class="bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Factures / Devis / Avis de Paiement</h2>
|
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Factures / Devis / Avis de Paiement</h2>
|
||||||
<div>
|
<div>
|
||||||
|
{% if currentOrder == "split" %}
|
||||||
|
<a href="{{ path('artemis_intranet_customer_splitAdd',{id:customer.id}) }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||||
|
+ Crée un échéancier de paiement
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
<a href="{{ path('artemis_intranet_customer_orderAdd',{id:customer.id}) }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
<a href="{{ path('artemis_intranet_customer_orderAdd',{id:customer.id}) }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||||
+ Crée un devis / avis de paiement / facture
|
+ Crée un devis / avis de paiement / facture
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -20,6 +26,9 @@
|
|||||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',currentOrder:'d'}) }}" class="w-33 px-4 py-2 font-semibold {% if currentOrder== "d" %}{{ active }}{% else %}{{ desactive }}{% endif %}">
|
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',currentOrder:'d'}) }}" class="w-33 px-4 py-2 font-semibold {% if currentOrder== "d" %}{{ active }}{% else %}{{ desactive }}{% endif %}">
|
||||||
Devis
|
Devis
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',currentOrder:'split'}) }}" class="w-33 px-4 py-2 font-semibold {% if currentOrder== "split" %}{{ active }}{% else %}{{ desactive }}{% endif %}">
|
||||||
|
Facturation en X Fois
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include 'artemis/intranet/customer/order/'~currentOrder~".twig" %}
|
{% include 'artemis/intranet/customer/order/'~currentOrder~".twig" %}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for orderAdvert in orderAdverts %}
|
{% for orderAdvert in orderAdverts %}
|
||||||
|
{% if "DIFF-" not in orderAdvert.numAvis %}
|
||||||
<tr class="hover:bg-gray-700">
|
<tr class="hover:bg-gray-700">
|
||||||
<td class="px-6 py-4">Avis de paiement</td>
|
<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.numAvis }}</td>
|
||||||
@@ -22,14 +23,18 @@
|
|||||||
{% if orderAdvert.state == "created" %}
|
{% 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>
|
<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>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<a target="_blank" href="{{ vich_uploader_asset(orderAdvert,'file') }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Téléchager</a>
|
||||||
|
|
||||||
{% if orderAdvert.state == "pay" and orderAdvert.customerOrder is null %}
|
{% 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>
|
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',idAvis:orderAdvert.id,act:'createFacture'}) }}" style="margin-top: 1rem" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Crée la facture</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% 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>
|
{% if orderAdvert.state == "wait-bank" or orderAdvert.state == "wait-virement" or orderAdvert.state == "p-payment" or orderAdvert.state == "pay" %}
|
||||||
|
<button is="register-payment" id="{{ orderAdvert.id }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded" style="margin-top: 1rem; width: 100%">Enregistrée un paiement</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
{% if orderOrder.state == "f-send" %}
|
{% if orderOrder.state == "f-send" %}
|
||||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',idFacture:orderOrder.id,act:'resend'}) }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Réenvoyée la facture</a>
|
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',idFacture:orderOrder.id,act:'resend'}) }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Réenvoyée la facture</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ vich_uploader_asset(orderOrder,'facture') }}" download="facture-{{ orderOrder.numOrder }}.pdf" class="block w-full mt-1 bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Télécharger la facture</a>
|
<a target="_blank" href="{{ vich_uploader_asset(orderOrder,'facture') }}" class="block w-full mt-1 bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Télécharger la facture</a>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
29
templates/artemis/intranet/customer/order/split.twig
Normal file
29
templates/artemis/intranet/customer/order/split.twig
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<div class="overflow-x-auto bg-gray-800 rounded-lg shadow">
|
||||||
|
<table class="min-w-full divide-y divide-gray-700">
|
||||||
|
<thead class="bg-gray-700">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Date</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">N°</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Montant</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Statut</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Total Échéances</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">Restant Échéances</th>
|
||||||
|
<th class="px-6 py-3 text-center text-xs font-medium uppercase tracking-wider">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for splitItem in splitList %}
|
||||||
|
<tr class="hover:bg-gray-700">
|
||||||
|
<td class="px-6 py-4">{{ splitItem.createAt|date('d/m/Y') }}</td>
|
||||||
|
<td class="px-6 py-4">{{ splitItem.num }}</td>
|
||||||
|
<td class="px-6 py-4">{{ splitItem.amount|format_currency('EUR') }} </td>
|
||||||
|
<td class="px-6 py-4 ech-{{ splitItem.state }}">{{ ('ech_'~splitItem.state)|trans }} </td>
|
||||||
|
<td class="px-6 py-4">{{ splitItem.customerSplitLines.count }}</td>
|
||||||
|
<td class="px-6 py-4">{{ splitItem|noCompletedEch() }}</td>
|
||||||
|
<td class="px-6 py-4"></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ knp_pagination_render(splitList) }}
|
||||||
|
</div>
|
||||||
82
templates/artemis/intranet/customer/slit-add.twig
Normal file
82
templates/artemis/intranet/customer/slit-add.twig
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{% extends 'artemis/base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Client - {{ customer.raisonSocial }} -Création échéancier de paiement</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="mt-5 bg-gray-800 rounded-lg shadow-lg p-6 space-y-4">
|
||||||
|
<div class="flex space-x-4">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="mb-1">
|
||||||
|
<label for="num" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Numéro</label>
|
||||||
|
<input type="text" name="num" id="num_devis" 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 value="{{ num }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-5">
|
||||||
|
<label for="description" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Description</label>
|
||||||
|
<textarea rows="7" type="text" name="description" id="description" 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></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset class="form-section">
|
||||||
|
<legend>
|
||||||
|
<h2>Mensualité</h2>
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
<div class="form-repeater" data-component="repeater" is="repeat-line">
|
||||||
|
<ol class="form-repeater__rows" data-ref="rows" tabindex="0">
|
||||||
|
<!-- This element will be repeated: -->
|
||||||
|
<li class="form-repeater__row">
|
||||||
|
<fieldset class="form-group form-group--horizontal">
|
||||||
|
<div class="flex space-x-4">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="form-field">
|
||||||
|
<div class="mb-1">
|
||||||
|
<label for="lines[0][date]" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Date du prélévement</label>
|
||||||
|
<input type="date" name="lines[0][date]" id="lines[0][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="mb-1">
|
||||||
|
<label for="price" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Montant TTC</label>
|
||||||
|
<input type="number" step="0.1" name="lines[0][price]" id="lines[0][price]" 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 class="flex-1">
|
||||||
|
<button
|
||||||
|
style="margin-top: 2rem"
|
||||||
|
class="w-full form-repeater__remove-button bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded"
|
||||||
|
data-ref="removeButton"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Supprimer la ligne
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="form-repeater__add-button w-full bg-purple-600 hover:bg-purple-700 text-white px-3 py-1 rounded"
|
||||||
|
data-ref="addButton"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
+ Ajouter une ligne
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="w-full bg-purple-600 hover:bg-purple-700 text-white px-3 py-1 rounded"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
Enregistrer
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}Intranet - Client - {{ customer.raisonSocial }} - Création échéancier de paiement{% endblock %}
|
||||||
30
templates/mails/customer/facture-payment.twig
Normal file
30
templates/mails/customer/facture-payment.twig
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{% extends 'mails/base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="20px" font-weight="bold" color="#333333" padding-bottom="10px">
|
||||||
|
Votre nouvelle facture est disponible
|
||||||
|
</mj-text>
|
||||||
|
<mj-text font-size="16px" color="#555555" padding-bottom="20px">
|
||||||
|
Bonjour,
|
||||||
|
</mj-text>
|
||||||
|
<mj-text font-size="16px" color="#555555" padding-bottom="10px">
|
||||||
|
Nous vous informons que votre nouvelle <strong>facture</strong> n°<strong>{{ datas.paymentNotice.number }}</strong>) d'un montant de <strong>{{ datas.paymentNotice.amount | number_format(2, ',', ' ') }} € TTC</strong> est maintenant disponible.
|
||||||
|
</mj-text>
|
||||||
|
|
||||||
|
<mj-text font-size="16px" color="#555555" padding-bottom="20px" font-weight="bold">
|
||||||
|
Veuillez trouver la facture en pièce jointe de cet e-mail (format PDF).
|
||||||
|
</mj-text>
|
||||||
|
|
||||||
|
<mj-divider border-color="#cccccc" />
|
||||||
|
|
||||||
|
<mj-text font-size="14px" color="#555555" padding-top="20px">
|
||||||
|
Si vous avez des questions ou besoin d'assistance concernant cette facture, n'hésitez pas à nous contacter.
|
||||||
|
</mj-text>
|
||||||
|
|
||||||
|
<mj-text font-size="14px" color="#333333" padding-top="30px">
|
||||||
|
Cordialement,<br/>
|
||||||
|
L’équipe Support
|
||||||
|
</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
{% endblock %}
|
||||||
34
templates/mails/customer/validate_paiement.twig
Normal file
34
templates/mails/customer/validate_paiement.twig
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{% extends 'mails/base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="20px" font-weight="bold" color="#333333" padding-bottom="10px">
|
||||||
|
Notification de Paiement Client Validé
|
||||||
|
</mj-text>
|
||||||
|
<mj-text font-size="16px" color="#555555" padding-bottom="20px">
|
||||||
|
Bonjour<br/><br/>
|
||||||
|
Ce courriel confirme la **réception et la validation de votre paiement** pour l'avis de paiement {{ datas.advert.numAvis }}
|
||||||
|
</mj-text>
|
||||||
|
|
||||||
|
<mj-divider border-color="#cccccc" />
|
||||||
|
|
||||||
|
<mj-text font-size="16px" font-weight="bold" color="#333333" padding-top="15px" padding-bottom="5px">
|
||||||
|
Détails de la Transaction :
|
||||||
|
</mj-text>
|
||||||
|
<mj-text font-size="14px" color="#555555" line-height="1.5">
|
||||||
|
- **Numéro de commande / Dossier** : <strong>{{ datas.advert.numAvis }}</strong><br/>
|
||||||
|
- **Client concerné** : {{ datas.customer.raisonSocial }}<br/>
|
||||||
|
- **Montant total encaissé** : <strong>{{ datas.register.amount|format_currency('EUR') }}</strong><br/>
|
||||||
|
- **Date de validation du paiement** : {{ datas.register.createAt|date('d/m/Y') }}<br/>
|
||||||
|
- **Méthode de paiement** : {{ datas.register.type|trans }}<br/>
|
||||||
|
</mj-text>
|
||||||
|
|
||||||
|
<mj-text>
|
||||||
|
Une fois le paiement vérifiée de notre coté, une facture vous sera envoyée
|
||||||
|
</mj-text>
|
||||||
|
<mj-text font-size="14px" color="#333333" padding-top="30px">
|
||||||
|
Cordialement,<br/>
|
||||||
|
Le Support Commercial
|
||||||
|
</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
{% endblock %}
|
||||||
31
templates/mails/customer/validate_paiement_customer.twig
Normal file
31
templates/mails/customer/validate_paiement_customer.twig
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{% extends 'mails/base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<mj-column>
|
||||||
|
<mj-text font-size="20px" font-weight="bold" color="#333333" padding-bottom="10px">
|
||||||
|
Notification de Paiement Client Validé
|
||||||
|
</mj-text>
|
||||||
|
<mj-text font-size="16px" color="#555555" padding-bottom="20px">
|
||||||
|
Bonjour<br/><br/>
|
||||||
|
Ce courriel confirme la **réception et la validation d'un paiement client** pour avis de paiement {{ datas.advert.numAvis }} {% if datas.parent is not null %}(Différence de l'avis de paiement {{ datas.parent.numAvis }}){% endif %}.
|
||||||
|
</mj-text>
|
||||||
|
|
||||||
|
<mj-divider border-color="#cccccc" />
|
||||||
|
|
||||||
|
<mj-text font-size="16px" font-weight="bold" color="#333333" padding-top="15px" padding-bottom="5px">
|
||||||
|
Détails de la Transaction :
|
||||||
|
</mj-text>
|
||||||
|
<mj-text font-size="14px" color="#555555" line-height="1.5">
|
||||||
|
- **Numéro de commande / Dossier** : <strong>{{ datas.advert.numAvis }}</strong><br/>
|
||||||
|
- **Client concerné** : {{ datas.customer.raisonSocial }}<br/>
|
||||||
|
- **Montant total encaissé** : <strong>{{ datas.register.amount|format_currency('EUR') }}</strong><br/>
|
||||||
|
- **Date de validation du paiement** : {{ datas.register.createAt|date('d/m/Y') }}<br/>
|
||||||
|
- **Méthode de paiement** : {{ datas.register.type|trans }}<br/>
|
||||||
|
</mj-text>
|
||||||
|
|
||||||
|
<mj-text font-size="14px" color="#333333" padding-top="30px">
|
||||||
|
Cordialement,<br/>
|
||||||
|
Le Support Commercial
|
||||||
|
</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
{% endblock %}
|
||||||
@@ -76,3 +76,4 @@ customer: Client
|
|||||||
administrator: Adminisateur
|
administrator: Adminisateur
|
||||||
customer_group: Groupe d'accée
|
customer_group: Groupe d'accée
|
||||||
customer_settings: Paramétres
|
customer_settings: Paramétres
|
||||||
|
ech_created: Crée - En attends de validation
|
||||||
|
|||||||
Reference in New Issue
Block a user