src/Invoice/Security/InvoiceVoter.php line 30

  1. <?php
  2. declare(strict_types=1);
  3. /**
  4.  * Copyright (c) 2019 TECLA Consulting Group oü.
  5.  * All rights reserved.
  6.  *
  7.  * This unpublished material is proprietary to TECLA Consulting Group oü.
  8.  * All rights reserved. The methods and
  9.  * techniques described herein are considered trade secrets
  10.  * and/or confidential. Reproduction or distribution, in whole
  11.  * or in part, is forbidden except by express written permission
  12.  * of TECLA Consulting Group oü.
  13.  *
  14.  * @author    Matúš Sýkorjak <matus@tecla.no>
  15.  * @copyright 2019 TECLA Consulting Group oü
  16.  */
  17. namespace App\Invoice\Security;
  18. use App\Contact\Model\ContactInterface;
  19. use App\Contact\Security\ContactContextInterface;
  20. use App\Invoice\Enum\InvoiceStatus;
  21. use App\Invoice\Enum\InvoiceType;
  22. use App\Invoice\Model\InvoiceInterface;
  23. use LogicException;
  24. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  25. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  26. final class InvoiceVoter extends Voter
  27. {
  28.     public const CREATE_INVOICE 'invoice.create_invoice';
  29.     public const CREATE_CREDIT_NOTE 'invoice_create_credit_note';
  30.     public const CREATE_PAYMENT 'invoice_create_payment';
  31.     public const CREATE_REPEAT_RULE 'invoice.create_repeat_rule';
  32.     public const VIEW 'invoice_view';
  33.     public const EXPORT 'invoice_export';
  34.     public const COPY 'invoice_copy';
  35.     public const SEND 'invoice_send';
  36.     public const SUPPORTED_ATTRIBUTES = [
  37.         self::CREATE_INVOICE,
  38.         self::CREATE_PAYMENT,
  39.         self::CREATE_CREDIT_NOTE,
  40.         self::VIEW,
  41.         self::COPY,
  42.         self::EXPORT,
  43.         self::SEND,
  44.         self::CREATE_REPEAT_RULE,
  45.     ];
  46.     private ContactContextInterface $contactContext;
  47.     public function __construct(ContactContextInterface $contactContext)
  48.     {
  49.         $this->contactContext $contactContext;
  50.     }
  51.     protected function supports($attribute$subject): bool
  52.     {
  53.         if (true === \in_array($attributeself::SUPPORTED_ATTRIBUTEStrue)) {
  54.             return null === $subject || true === $subject instanceof InvoiceInterface;
  55.         }
  56.         return false;
  57.     }
  58.     protected function voteOnAttribute($attribute$subjectTokenInterface $token): bool
  59.     {
  60.         switch ($attribute) {
  61.             case self::CREATE_INVOICE:
  62.                 return $this->canCreateInvoice();
  63.             case self::CREATE_PAYMENT:
  64.                 return $this->canCreatePayment($subject);
  65.             case self::CREATE_CREDIT_NOTE:
  66.                 return $this->canCreateCreditNote($subject);
  67.             case self::VIEW:
  68.             case self::EXPORT:
  69.                 return $this->canAccessInvoice($subject);
  70.             case self::COPY:
  71.                 return $this->canCopyInvoice($subject);
  72.             case self::SEND:
  73.                 return $this->canSendInvoice($subject);
  74.             case self::CREATE_REPEAT_RULE:
  75.                 return $this->canRepeatInvoice($subject);
  76.         }
  77.         throw new LogicException('This code should not be reached!');
  78.     }
  79.     private function canCreateInvoice(): bool
  80.     {
  81.         $currentContext $this->contactContext->getCurrent();
  82.         if (null === $currentContext) {
  83.             return false;
  84.         }
  85.         if (ContactInterface::TYPE_COMPANY !== $currentContext->getType()) {
  86.             return false;
  87.         }
  88.         return true;
  89.     }
  90.     private function canViewInvoice(?InvoiceInterface $invoice): bool
  91.     {
  92.         if (null === $invoice) {
  93.             return false;
  94.         }
  95.         $currentContext $this->contactContext->getCurrent();
  96.         return null !== $currentContext && $invoice->getSupplier() === $currentContext;
  97.     }
  98.     private function canAccessInvoice(?InvoiceInterface $invoice): bool
  99.     {
  100.         if (null === $invoice) {
  101.             return false;
  102.         }
  103.         $currentContext $this->contactContext->getCurrent();
  104.         return $this->canViewInvoice($invoice) || (null !== $currentContext && $invoice->getCustomer() === $currentContext);
  105.     }
  106.     private function canCreateCreditNote(?InvoiceInterface $invoice): bool
  107.     {
  108.         if (null === $invoice) {
  109.             return $this->canCreateInvoice();
  110.         }
  111.         if (false === $this->canViewInvoice($invoice)) {
  112.             return false;
  113.         }
  114.         if (false === InvoiceType::INVOICE()->equals($invoice->getType())) {
  115.             return false;
  116.         }
  117.         if (true === InvoiceStatus::CREDITED()->equals($invoice->getStatus())) {
  118.             return false;
  119.         }
  120.         return true;
  121.     }
  122.     private function canCopyInvoice(?InvoiceInterface $invoice): bool
  123.     {
  124.         if (false === $this->canViewInvoice($invoice) || null === $invoice) {
  125.             return false;
  126.         }
  127.         return InvoiceType::INVOICE()->equals($invoice->getType());
  128.     }
  129.     private function canSendInvoice(?InvoiceInterface $invoice): bool
  130.     {
  131.         if (null === $invoice) {
  132.             return false;
  133.         }
  134.         $currentContext $this->contactContext->getCurrent();
  135.         return null !== $currentContext && $invoice->getSupplier() === $currentContext;
  136.     }
  137.     private function canCreatePayment(?InvoiceInterface $invoice): bool
  138.     {
  139.         if (null === $invoice) {
  140.             return false;
  141.         }
  142.         $currentContext $this->contactContext->getCurrent();
  143.         return
  144.             null !== $currentContext &&
  145.             $invoice->getSupplier() === $currentContext &&
  146.             true === InvoiceType::INVOICE()->equals($invoice->getType()) &&
  147.             false === InvoiceStatus::PAID()->equals($invoice->getStatus()) &&
  148.             false === InvoiceStatus::CREDITED()->equals($invoice->getStatus());
  149.     }
  150.     private function canRepeatInvoice(?InvoiceInterface $invoice): bool
  151.     {
  152.         if (null === $invoice) {
  153.             return false;
  154.         }
  155.         if (false === InvoiceType::INVOICE()->equals($invoice->getType())) {
  156.             return false;
  157.         }
  158.         if (false === $this->isOwner($invoice)) {
  159.             return false;
  160.         }
  161.         return true;
  162.     }
  163.     private function isOwner(?InvoiceInterface $invoice): bool
  164.     {
  165.         if (null === $invoice) {
  166.             return false;
  167.         }
  168.         $currentContext $this->contactContext->getCurrent();
  169.         return null !== $currentContext && $invoice->getSupplier() === $currentContext;
  170.     }
  171. }