<?php
/**
* @author Thomas HERISSON (contact@scaledev.fr)
* @copyright 2021 - ScaleDEV SAS, 12 RUE CHARLES MORET, 10120 ST ANDRE LES VERGERS
* @license commercial
*/
declare(strict_types=1);
namespace Bluue\SalesBundle\EventSubscriber;
use App\Entity\TaxRule;
use Bluue\SalesBundle\Entity\Order;
use App\Services\CheckBundleInstall;
use Bluue\SalesBundle\Entity\OrderState;
use Bluue\SalesBundle\Entity\PaymentMethod;
use Bluue\SalesBundle\Entity\PaymentTerm;
use Bluue\SalesBundle\Services\Document;
use Doctrine\ORM\EntityManagerInterface;
use Bluue\CustomersBundle\Entity\Customer;
use Bluue\SalesBundle\Entity\DeliveryNote;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Security\Core\Security;
use Bluue\SalesBundle\Repository\OrderRepository;
use Bluue\CustomersBundle\Event\CustomerEditEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Translation\TranslatorInterface;
use Bluue\SalesBundle\Repository\DeliveryNoteRepository;
use Bluue\SalesBundle\Repository\CustomerOptionsRepository;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Doctrine\ORM\Query\Expr\Join;
class CustomerEditSubscriber implements EventSubscriberInterface
{
/**
* @var TranslatorInterface
*/
private TranslatorInterface $tr;
/**
* @var RequestStack
*/
protected RequestStack $requestStack;
/**
* @var Security
*/
private Security $security;
/**
* @var CustomerOptionsRepository
*/
private CustomerOptionsRepository $customerOptionsRepo;
/**
* @var EntityManagerInterface
*/
private EntityManagerInterface $em;
/**
* @param RequestStack $requestStack
* @param TranslatorInterface $tr
* @param Security $security
* @param CustomerOptionsRepository $customerOptionsRepo
* @param EntityManagerInterface $em
*/
public function __construct(
RequestStack $requestStack,
TranslatorInterface $tr,
Security $security,
CustomerOptionsRepository $customerOptionsRepo,
EntityManagerInterface $em
) {
$this->requestStack = $requestStack;
$this->tr = $tr;
$this->security = $security;
$this->customerOptionsRepo = $customerOptionsRepo;
$this->em = $em;
}
/**
* @return string[]
*/
public static function getSubscribedEvents(): array
{
return [
CustomerEditEvent::PRE_SET_DATA => 'addFields',
CustomerEditEvent::POST_SUBMIT => 'postSubmit',
CustomerEditEvent::TABS => 'tabs'
];
}
/**
* @param CustomerEditEvent $event
* @return void
*/
public function addFields(CustomerEditEvent $event): void
{
if (!$this->security->isGranted('ROLE__SALES__READ_ONLY')) {
return;
}
$switchAttrs = [
'required' => false,
'mapped' => false,
'label_attr' => [
'class' => 'custom-control-label cursor-pointer'
],
'row_attr' => [
'class' => 'custom-control custom-switch pl-3 mb-0'
],
'attr' => [
'class' => 'custom-control-input'
]
];
$builder = $event->getBuilder();
$customer = $builder->getOptions()['data'];
if ($customer instanceof Customer) {
$customerOptions = $this->customerOptionsRepo->findOneBy([
'customer' => $customer
]);
}
$builder
->add(
'forQuotation',
CheckboxType::class,
array_merge([
'label' => $this->tr->trans('Quotation', [], 'SalesBundle'),
'data' => !empty($customerOptions) && $customerOptions->isForQuotation()
], $switchAttrs)
)
->add(
'forOrder',
CheckboxType::class,
array_merge([
'label' => $this->tr->trans('Order', [], 'SalesBundle'),
'data' => !empty($customerOptions) && $customerOptions->isForOrder()
], $switchAttrs)
)
->add(
'forDeliveryNote',
CheckboxType::class,
array_merge([
'label' => $this->tr->trans('Delivery note', [], 'SalesBundle'),
'data' => !empty($customerOptions) && $customerOptions->isForDeliveryNote()
], $switchAttrs)
)
->add(
'forInvoice',
CheckboxType::class,
array_merge([
'label' => $this->tr->trans('Invoice', [], 'SalesBundle'),
'data' => !empty($customerOptions) && $customerOptions->isForInvoice()
], $switchAttrs)
)
->add(
'forCreditNote',
CheckboxType::class,
array_merge([
'label' => $this->tr->trans('Credit note', [], 'SalesBundle'),
'data' => !empty($customerOptions) && $customerOptions->isForCreditNote()
], $switchAttrs)
);
if (!$customer->getParent()) {
$builder
->add('defaultPaymentMethod', EntityType::class, [
'label' => $this->tr->trans('Default payment method', [], 'SalesBundle'),
'required' => false,
'mapped' => false,
'class' => PaymentMethod::class,
'choice_label' => 'name',
'placeholder' => $this->tr->trans('No payment method', [], 'SalesBundle'),
'data' => !empty($customerOptions) ? $customerOptions->getDefaultPaymentMethod() : null
])
->add('defaultPaymentTerm', EntityType::class, [
'label' => $this->tr->trans('Default payment term', [], 'SalesBundle'),
'required' => false,
'mapped' => false,
'class' => PaymentTerm::class,
'choice_label' => 'name',
'placeholder' => $this->tr->trans('No payment term', [], 'SalesBundle'),
'data' => !empty($customerOptions) ? $customerOptions->getDefaultPaymentTerm() : null
])
->add('defaultOrderState', EntityType::class, [
'label' => $this->tr->trans('Default order state', [], 'SalesBundle'),
'required' => false,
'mapped' => false,
'class' => OrderState::class,
'choice_label' => 'name',
'placeholder' => $this->tr->trans('No order state', [], 'SalesBundle'),
'data' => !empty($customerOptions) ? $customerOptions->getDefaultOrderState() : null
])
->add('defaultReducedTaxRule', EntityType::class, [
'label' => $this->tr->trans('Default reduced tax rule', [], 'SalesBundle'),
'required' => false,
'mapped' => false,
'class' => TaxRule::class,
'choice_label' => 'name',
'placeholder' => $this->tr->trans('No tax rule', [], 'SalesBundle'),
'data' => !empty($customerOptions) ? $customerOptions->getDefaultReducedTaxRule() : null
])
->add('defaultReducedVat', CheckboxType::class, array_merge([
'label' => $this->tr->trans('Default reduced VAT', [], 'SalesBundle'),
'data' => !empty($customerOptions) && $customerOptions->isDefaultReducedVat()
], $switchAttrs))
->add('relaunchUnpaidInvoices', CheckboxType::class, array_merge([
'label' => $this->tr->trans('Relaunch unpaid invoices', [], 'SalesBundle'),
'data' => !empty($customerOptions) && $customerOptions->isRelaunchUnpaidInvoices()
], $switchAttrs))
;
}
$event->setBuilder($builder);
}
/**
* @param CustomerEditEvent $event
* @return void
*/
public function postSubmit(CustomerEditEvent $event): void
{
if (!$this->security->isGranted('ROLE__SALES__READ_ONLY')) {
return;
}
$form = $event->getForm();
$customer = $form->getData();
if ($customer instanceof Customer) {
$options = [
'setForQuotation' => $form->get('forQuotation')->getData(),
'setForOrder' => $form->get('forOrder')->getData(),
'setForDeliveryNote' => $form->get('forDeliveryNote')->getData(),
'setForInvoice' => $form->get('forInvoice')->getData(),
'setForCreditNote' => $form->get('forCreditNote')->getData()
];
if (!$customer->getParent()) {
$options['setDefaultPaymentMethod'] = $form->get('defaultPaymentMethod')->getData();
$options['setDefaultPaymentTerm'] = $form->get('defaultPaymentTerm')->getData();
$options['setDefaultOrderState'] = $form->get('defaultOrderState')->getData();
$options['setDefaultReducedTaxRule'] = $form->get('defaultReducedTaxRule')->getData();
$options['setDefaultReducedVat'] = $form->get('defaultReducedVat')->getData();
$options['setRelaunchUnpaidInvoices'] = $form->get('relaunchUnpaidInvoices')->getData();
}
$this->customerOptionsRepo->addOptions($customer, $options);
if ($customer->getParent()) {
/** @var OrderRepository $orderRepo */
$orderRepo = $this->em->getRepository(Order::class);
$ordersAssociated = $orderRepo->createQueryBuilder('o')
->andWhere('o.delivery_address = :delivery_address')
->setParameter('delivery_address', $customer->getId()->toBinary())
->andWhere('o.validatedAt IS NOT NULL')
->join('o.lines', 'ol')
->andWhere('(ol.quantity - ol.quantity_delivered > 0 OR ol.quantity_delivered IS NULL)')
->getQuery()->getResult();
foreach ($ordersAssociated as $order) {
$options = $order->getOptions();
$options['delivery_address'] = Document::normalizeAddress($order->getDeliveryAddress());
$order->setOptions($options);
$this->em->persist($order);
}
if (CheckBundleInstall::exist('shipments-bundle')) {
/** @var DeliveryNoteRepository $deliveryNoteRepo */
$deliveryNoteRepo = $this->em->getRepository(DeliveryNote::class);
$deliveryNotesAssociated = $deliveryNoteRepo->createQueryBuilder('dn')
->innerJoin(
'ShipmentsBundle:OrderOptions',
'op',
Join::WITH,
'dn = op.delivery_note AND op.status = 1'
)
->andWhere('dn.delivery_address = :delivery_address')
->setParameter('delivery_address', $customer->getId()->toBinary())
->getQuery()->getResult()
;
foreach ($deliveryNotesAssociated as $deliveryNote) {
$deliveryNote->addOptions([
'delivery_address' => Document::normalizeAddress($customer)
]);
}
}
if (!empty($ordersAssociated) || !empty($deliveryNotesAssociated)) {
$this->em->flush();
}
}
}
}
/**
* @param CustomerEditEvent $event
* @return void
*/
public function tabs(CustomerEditEvent $event): void
{
if (!$this->security->isGranted('ROLE__SALES__READ_ONLY')) {
return;
}
$tabs = $event->getTabs();
$newTabs = [
[
'template' => '@Sales/CustomersBundle/_options.html.twig',
'name' => $this->tr->trans('Sales', [], 'SalesBundle'),
'icon' => 'fas fa-money-bill-alt',
'key' => 'sales'
]
];
$event->setTabs(array_merge($tabs, $newTabs));
}
}