custom/plugins/WbfkExtensions/src/Documents/DocumentConfigSubscriber.php line 49

Open in your IDE?
  1. <?php
  2. namespace WbfkExtensions\Documents;
  3. use Shopware\Core\Checkout\Document\DocumentConfiguration;
  4. use Shopware\Core\Checkout\Order\Aggregate\OrderAddress\OrderAddressEntity;
  5. use Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryEntity;
  6. use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionEntity;
  7. use Shopware\Core\Checkout\Order\OrderEntity;
  8. use Shopware\Core\Framework\Context;
  9. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Contracts\Translation\TranslatorInterface;
  13. use Wbfk\DigitalInvoice\Core\Document\DigitalDocumentConfigExtension;
  14. use Wbfk\DigitalInvoice\Event\GenerateDocumentConfigEvent;
  15. use Wbfk\DigitalInvoice\Service\Document\DocumentService;
  16. use Wbfk\DigitalInvoice\Service\Document\ZugferdService;
  17. use Wbfk\DigitalInvoice\Service\Utils\Utils;
  18. use WbfkExtensions\Service\TaxFreeProductService;
  19. class DocumentConfigSubscriber implements EventSubscriberInterface
  20. {
  21.     // ToDo: Change to a better (configurable) matching for payment method than the ID
  22.     //@formatter:off
  23.     private const paymentMethodIds = [
  24.         'invoice' => 'e29f15b5d53b4025baaf8ccb404aadbe',
  25.         'sepa'    => 'fb6bbe50888942efbf43e04f502bddc5',
  26.         'direct'  => '0280b3cfab6d4006afe3d5c46ef5f166',
  27.     ];
  28.     //@formatter:on
  29.     public function __construct(
  30.         private readonly TranslatorInterface $translator,
  31.         protected readonly EntityRepository $customerRepository,
  32.     ) {
  33.     }
  34.     public static function getSubscribedEvents(): array
  35.     {
  36.         return [
  37.             DocumentService::GENERATE_DOCUMENT_CONFIG_EVENT => 'generateDocumentConfig',
  38.         ];
  39.     }
  40.     public function generateDocumentConfig(GenerateDocumentConfigEvent $event): void
  41.     {
  42.         $extConf DigitalDocumentConfigExtension::fromDocumentConfig($event->documentConfiguration);
  43.         if (!$extConf) {
  44.             return;
  45.         }
  46.         $order $event->order;
  47.         $langCode $order->getLanguage()->getLocale()->getCode();
  48.         $shortDateFormatter = new \IntlDateFormatter($langCode\IntlDateFormatter::SHORT\IntlDateFormatter::NONE);
  49.         $dezimalFormatter = new \NumberFormatter($langCode\NumberFormatter::DECIMAL);
  50.         /** @var string[] $cf */
  51.         $cf $order->getCustomFields();
  52.         // Payment Target
  53.         /** @var ?OrderTransactionEntity $transaction */
  54.         $transaction $order->getTransactions()->last();
  55.         if ($transaction && $transaction->getPaymentMethodId() === self::paymentMethodIds['invoice']) {
  56.             $paymentTarget trim($cf['wbfk_invoice_payment_target'] ?? "14") ?: "14";
  57.             $bt20 $this->translator->trans('documents.paymentTarget', ['%paymentTarget%' => $paymentTarget], null$langCode);
  58.             $extConf->bt20[] = $bt20;
  59.             $extConf->pdfComments[] = $bt20;
  60.         }
  61.         // Skonto / QuickPayment Discount
  62.         $discountPercent = ((float)trim($cf['wbfk_invoice_discount'] ?? 0.0)) ?: 0.0;
  63.         $discountDays = ((int)trim($cf['wbfk_invoice_discount_days'] ?? 0)) ?: 0;
  64.         if ($discountPercent && $discountDays 0) {
  65.             $extConf->bt20[] = '#SKONTO#TAGE='.$discountDays.'#PROZENT='.Utils::num2($discountPercent).'#';
  66.             $extConf->pdfComments[] = $this->translator->trans('documents.earlyPaymentDiscount', [
  67.                 '%discountDays%' => $discountDays,
  68.                 '%discountPercent%' => $dezimalFormatter->format($discountPercent),
  69.             ], null$langCode);
  70.         }
  71.         // Payment Received
  72.         if (
  73.             $transaction
  74.             && $transaction->getPaymentMethodId() !== self::paymentMethodIds['invoice']
  75.             && $transaction->getPaymentMethodId() !== self::paymentMethodIds['sepa']
  76.             && $transaction->getPaymentMethodId() !== self::paymentMethodIds['direct']) {
  77.             $bt20 $this->translator->trans('documents.paymentReceived', [
  78.                 '%payment_date%' => $shortDateFormatter->format($order->getOrderDate()),
  79.                 '%payment_method%' => $transaction->getPaymentMethod()->getName(),
  80.             ], null$langCode);
  81.             $extConf->bt20[] = $bt20;
  82.             $extConf->pdfComments[] = $bt20;
  83.         }
  84.         // Will be charged with SEPA
  85.         if ($transaction && $transaction->getPaymentMethodId() == self::paymentMethodIds['sepa']) {
  86.             $bt20 $this->translator->trans('documents.willBeChargedWithSepa', [], null$langCode);
  87.             $extConf->bt20[] = $bt20;
  88.             $extConf->pdfComments[] = $bt20;
  89.         }
  90.         // Our property till payment
  91.         if (
  92.             $transaction && (
  93.                 $transaction->getPaymentMethodId() !== self::paymentMethodIds['invoice']
  94.                 || $transaction->getPaymentMethodId() !== self::paymentMethodIds['sepa']
  95.                 || $transaction->getPaymentMethodId() !== self::paymentMethodIds['direct']
  96.             )) {
  97.             $bt20 $this->translator->trans('documents.remainOurPropertyTillPayment', [], null$langCode);
  98.             $extConf->bt20[] = $bt20;
  99.             $extConf->pdfComments[] = $bt20;
  100.         }
  101.         // Leistungszeitraum
  102.         $extConf->pdfComments[] = $this->translator->trans('documents.serviceDateEqualInvoiceDate', [], null$langCode);
  103.         $this->setTaxClassificationAndInvoiceNote($extConf$event->documentConfiguration$order);
  104.         // ToDo: Frage Oliver
  105.         // "priceInclVat": "* Grundpreise verstehen sich inkl. gesetzl. Mehrwertsteuer."
  106.         // hasBasePrice == true
  107.     }
  108.     private function setTaxClassificationAndInvoiceNote(DigitalDocumentConfigExtension $extConfDocumentConfiguration $configOrderEntity $order): void
  109.     {
  110.         $orderTaxState $order->getTaxStatus();
  111.         if ($orderTaxState !== 'tax-free') {
  112.             $extConf->bt118 ZugferdService::TAX_CODE_STD;
  113.         } elseif ($this->isUsInvoice($order)) {
  114.             $extConf->bt118 ZugferdService::TAX_CODE_EXPORT;
  115.             $extConf->pdfComments[] = $this->translator->trans('documents.taxFreeUsArmyDelivery');
  116.         } elseif ($this->isIntraCommunityDelivery($config$order)) {
  117.             if ($this->isServiceOnly($order)) {
  118.                 $extConf->bt118 ZugferdService::TAX_CODE_REVERSE;
  119.                 $extConf->pdfComments[] = $this->translator->trans('documents.taxFreeReverseCharge');
  120.             } else {
  121.                 $extConf->bt118 ZugferdService::TAX_CODE_INTRA_COMMUNITY;
  122.                 $extConf->pdfComments[] = $this->translator->trans('documents.intraCommunityDelivery');
  123.             }
  124.         } else {
  125.             $extConf->bt118 ZugferdService::TAX_CODE_EXPORT;
  126.             $extConf->pdfComments[] = $this->translator->trans('documents.taxFreeExportDelivery');
  127.         }
  128.     }
  129.     /**
  130.      * Note! This does not test, if the order is tax-free, the customer is B2B or B2C, or if tyx-free is configured for the delivery country.
  131.      * This only test, if the delivery country is in the list of configured intra community countries.
  132.      *
  133.      * @param DocumentConfiguration $config
  134.      * @param OrderEntity $order
  135.      * @return bool
  136.      */
  137.     private function isIntraCommunityDelivery(DocumentConfiguration $configOrderEntity $order): bool
  138.     {
  139.         $deliveries $order->getDeliveries();
  140.         if (empty($deliveries)) {
  141.             return false;
  142.         }
  143.         /** @var OrderDeliveryEntity $delivery */
  144.         $delivery $deliveries->first();
  145.         /** @var OrderAddressEntity $shippingAddress */
  146.         $shippingAddress $delivery->getShippingOrderAddress();
  147.         $country $shippingAddress->getCountry();
  148.         if (!$country) {
  149.             return false;
  150.         }
  151.         $confArray $config->getVars();
  152.         return \in_array($country->getId(), $confArray['deliveryCountries'], true);
  153.     }
  154.     protected function isUsInvoice(OrderEntity $order): bool
  155.     {
  156.         $criteria = new Criteria([$order->getOrderCustomer()->getCustomer()->getId()]);
  157.         $criteria->addAssociation('tags');
  158.         $customer $this->customerRepository->search($criteriaContext::createDefaultContext())->first();
  159.         return $customer->getTags()->filterByProperty('name'TaxFreeProductService::TAX_FREE_TAG_NAME)->count() > 0;
  160.     }
  161.     protected function isServiceOnly(OrderEntity $order): bool
  162.     {
  163.         $lineItems $order->getLineItems();
  164.         $isServiceOnly true;
  165.         foreach ($lineItems as $lineItem) {
  166.             if ($lineItem->getGood()) {
  167.                 $isServiceOnly false;
  168.                 break;
  169.             }
  170.         }
  171.         return $isServiceOnly;
  172.     }
  173. }