custom/plugins/UandiEfbDownloadCenter/src/Service/PdfRenderer.php line 111

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Uandi\UandiEfbDownloadCenter\Service;
  3. use Mpdf\Mpdf;
  4. use Mpdf\MpdfException;
  5. use Mpdf\Output\Destination;
  6. use Psr\Log\LoggerInterface;
  7. use Shopware\Core\Content\Product\ProductEntity;
  8. use Shopware\Core\Content\Property\PropertyGroupEntity;
  9. use Shopware\Core\Defaults;
  10. use Shopware\Core\Framework\Context;
  11. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  14. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  15. use Shopware\Core\System\SystemConfig\SystemConfigService;
  16. use Twig\Environment;
  17. use Twig\Error\LoaderError;
  18. use Twig\Error\RuntimeError;
  19. use Twig\Error\SyntaxError;
  20. use Uandi\EFB\Storefront\Service\VariantLoader;
  21. use Uandi\UandiEfbErpSynchronization\Service\Document\Lists\DeclarationOfConformity;
  22. use Uandi\UandiEfbErpSynchronization\Service\Document\Lists\UkcaDeclaration;
  23. class PdfRenderer
  24. {
  25.     private Environment $twig;
  26.     private EntityRepository $propertyGroupRepository;
  27.     private SystemConfigService $systemConfigService;
  28.     private DeclarationOfConformity $conformityDeclaration;
  29.     private UkcaDeclaration $ukcaDeclaration;
  30.     private VariantLoader $variantLoader;
  31.     private LoggerInterface $logger;
  32.     public function __construct(
  33.         Environment $twig,
  34.         EntityRepository $propertyGroupRepository,
  35.         SystemConfigService $systemConfigService,
  36.         DeclarationOfConformity $conformityDeclaration,
  37.         UkcaDeclaration $ukcaDeclaration,
  38.         VariantLoader $variantLoader,
  39.         LoggerInterface $logger
  40.     ) {
  41.         $this->twig $twig;
  42.         $this->propertyGroupRepository $propertyGroupRepository;
  43.         $this->systemConfigService $systemConfigService;
  44.         $this->conformityDeclaration $conformityDeclaration;
  45.         $this->ukcaDeclaration $ukcaDeclaration;
  46.         $this->variantLoader $variantLoader;
  47.         $this->logger $logger;
  48.     }
  49.     /**
  50.      * Render datasheet pdf for the supplied product.
  51.      *
  52.      * @param ProductEntity $product
  53.      * @param SalesChannelContext $salesChannelContext
  54.      *
  55.      * @return string|null
  56.      * @throws LoaderError
  57.      * @throws MpdfException
  58.      * @throws RuntimeError
  59.      * @throws SyntaxError
  60.      */
  61.     public function renderDataSheetPdf(ProductEntity $productSalesChannelContext $salesChannelContext): ?string
  62.     {
  63.         $propertyData $this->getPropertyData($product$salesChannelContext->getContext());
  64.         $this->variantLoader->loadVariantTable($product$salesChannelContext);
  65.         $pdf = new Mpdf();
  66.         $datasheetTemplate $this->twig->createTemplate($this->getConfig('uandidownloadcenterdatasheetcontent'));
  67.         $header $this->twig->createTemplate($this->getConfig('uandidownloadcenterdatasheetheader'));
  68.         $footer $this->twig->createTemplate($this->getConfig('uandidownloadcenterdatasheetfooter'));
  69.         $html $this->twig->render($datasheetTemplate, ['properties' => $propertyData'product' => $product]);
  70.         $header $this->twig->render($header, ['product' => $product]);
  71.         $footer $this->twig->render($footer, ['product' => $product]);
  72.         $pdf->setAutoTopMargin 'pad';
  73.         $pdf->setAutoBottomMargin 'pad';
  74.         $pdf->SetHTMLHeader($header);
  75.         $pdf->SetHTMLFooter($footer);
  76.         $pdf->WriteHTML($html);
  77.         $renderedPdf $pdf->Output(''Destination::STRING_RETURN);
  78.         if ($renderedPdf === null) {
  79.             $this->logger->error(
  80.                 sprintf('%s: Product %s: Generated datasheet is empty.'__METHOD__$product->getProductNumber())
  81.             );
  82.         }
  83.         return $renderedPdf;
  84.     }
  85.     /**
  86.      * Render declaration of conformity pdf for the supplied customer number and products.
  87.      *
  88.      * @param array $products
  89.      * @param SalesChannelContext $salesChannelContext
  90.      *
  91.      * @return bool|string|null
  92.      * @throws LoaderError
  93.      * @throws MpdfException
  94.      * @throws RuntimeError
  95.      * @throws SyntaxError
  96.      */
  97.     public function renderConfirmityDeclarationPdf(
  98.         array $products,
  99.         SalesChannelContext $salesChannelContext
  100.     ): bool|string|null {
  101.         $customer $salesChannelContext->getCustomer();
  102.         $customerNumber $salesChannelContext->getCustomer() ? $customer->getCustomerNumber() : '';
  103.         $productNumbers array_map(function (ProductEntity $product) {
  104.             return $product->getProductNumber();
  105.         }, $products);
  106.         $conformityInfo $this->conformityDeclaration->getConformityDeclarationAttributes(
  107.             $customerNumber,
  108.             $productNumbers,
  109.             $salesChannelContext
  110.         );
  111.         if (count($products) == 1) {
  112.             $product array_pop($products);
  113.             $this->variantLoader->loadVariantTable($product$salesChannelContext);
  114.         }
  115.         if ($conformityInfo === []) {
  116.             $this->logger->warning(
  117.                 sprintf(
  118.                     '%s: Product(s) %s: ERP API response is empty.',
  119.                     __METHOD__,
  120.                     implode(','$productNumbers)
  121.                 )
  122.             );
  123.             return false;
  124.         }
  125.         if ($conformityInfo['attributes']['ROHS'] == 0) {
  126.             $this->logger->warning(
  127.                 sprintf('%s: Product(s) %s: ROHS = 0 in API response.'__METHOD__implode(','$productNumbers))
  128.             );
  129.             return false;
  130.         }
  131.         $pdf = new Mpdf();
  132.         $header $this->twig->createTemplate($this->getConfig('uandidownloadcenterconformityheader'));
  133.         $footer $this->twig->createTemplate($this->getConfig('uandidownloadcenterconformityfooter'));
  134.         $html $this->getConfig('uandidownloadcenterconformityrohs');
  135.         if ($conformityInfo['attributes']['EMV'] == 1) {
  136.             $html .= $this->getConfig('uandidownloadcenterconformityemv');
  137.         }
  138.         if ($conformityInfo['attributes']['NSR'] == 1) {
  139.             $html .= $this->getConfig('uandidownloadcenterconformitynsr');
  140.         }
  141.         $html .= $this->getConfig('uandidownloadcenterconformityproductlist');
  142.         $header $this->twig->render($header, []);
  143.         $footer $this->twig->render($footer, []);
  144.         $renderedHtml $this->twig->render(
  145.             $this->twig->createTemplate($html),
  146.             ['productList' => $conformityInfo['product_list'], 'product' => $product]
  147.         );
  148.         $pdf->setAutoTopMargin 'pad';
  149.         $pdf->setAutoBottomMargin 'pad';
  150.         $pdf->SetHTMLHeader($header);
  151.         $pdf->SetHTMLFooter($footer);
  152.         $pdf->WriteHTML($renderedHtml);
  153.         $renderedPdf $pdf->Output(''Destination::STRING_RETURN);
  154.         if ($renderedPdf === null) {
  155.             $this->logger->error(
  156.                 sprintf(
  157.                     '%s: Product(s) %s: Generated declaration of conformity is empty.',
  158.                     __METHOD__,
  159.                     implode(','$productNumbers)
  160.                 )
  161.             );
  162.         }
  163.         return $renderedPdf;
  164.     }
  165.     /**
  166.      * Render UKCA declaration of conformity pdf for the supplied customer number and products.
  167.      *
  168.      * @param array $products
  169.      * @param SalesChannelContext $salesChannelContext
  170.      *
  171.      * @return bool|string|null
  172.      * @throws LoaderError
  173.      * @throws MpdfException
  174.      * @throws RuntimeError
  175.      * @throws SyntaxError
  176.      */
  177.     public function renderUkcaPdf(array $productsSalesChannelContext $salesChannelContext): bool|string|null
  178.     {
  179.         $customer $salesChannelContext->getCustomer();
  180.         $customerNumber $salesChannelContext->getCustomer() ? $customer->getCustomerNumber() : '';
  181.         $productNumbers array_map(function (ProductEntity $product) {
  182.             return $product->getProductNumber();
  183.         }, $products);
  184.         $conformityInfo $this->ukcaDeclaration->getUkcaAttributes(
  185.             $customerNumber,
  186.             $productNumbers,
  187.             $salesChannelContext
  188.         );
  189.         if (count($products) == 1) {
  190.             $product array_pop($products);
  191.             $this->variantLoader->loadVariantTable($product$salesChannelContext);
  192.         }
  193.         if ($conformityInfo === []) {
  194.             $this->logger->warning(
  195.                 sprintf('%s: Product(s) %s: ERP API response is empty.'__METHOD__implode(','$productNumbers))
  196.             );
  197.             return false;
  198.         }
  199.         if ($conformityInfo['attributes']['ROHS'] == 0) {
  200.             $this->logger->warning(
  201.                 sprintf('%s: Product(s) %s: ROHS = 0 in API response.'__METHOD__implode(','$productNumbers))
  202.             );
  203.             return false;
  204.         }
  205.         $pdf = new Mpdf();
  206.         $header $this->twig->createTemplate($this->getConfig('uandidownloadcenterukcaheader'));
  207.         $footer $this->twig->createTemplate($this->getConfig('uandidownloadcenterukcafooter'));
  208.         $html $this->getConfig('uandidownloadcenterukcarohs');
  209.         if ($conformityInfo['attributes']['EMV'] == 1) {
  210.             $html .= $this->getConfig('uandidownloadcenterukcaemv');
  211.         }
  212.         if ($conformityInfo['attributes']['NSR'] == 1) {
  213.             $html .= $this->getConfig('uandidownloadcenterukcansr');
  214.         }
  215.         $html .= $this->getConfig('uandidownloadcenterukcaproductlist');
  216.         $header $this->twig->render($header, []);
  217.         $footer $this->twig->render($footer, []);
  218.         $renderedHtml $this->twig->render(
  219.             $this->twig->createTemplate($html),
  220.             ['productList' => $conformityInfo['product_list'], 'product' => $product]
  221.         );
  222.         $pdf->setAutoTopMargin 'pad';
  223.         $pdf->setAutoBottomMargin 'pad';
  224.         $pdf->SetHTMLHeader($header);
  225.         $pdf->SetHTMLFooter($footer);
  226.         $pdf->WriteHTML($renderedHtml);
  227.         $renderedPdf $pdf->Output(''Destination::STRING_RETURN);
  228.         if ($renderedPdf === null) {
  229.             $this->logger->error(
  230.                 sprintf(
  231.                     '%s: Product(s) %s: Generated declaration of conformity is empty.',
  232.                     __METHOD__,
  233.                     implode(','$productNumbers)
  234.                 )
  235.             );
  236.         }
  237.         return $renderedPdf;
  238.     }
  239.     /**
  240.      * Read product properties into an array.
  241.      * - Format: [ 'Group Name' => [ propertyKey => propertyValue, ... ], ... ]
  242.      *
  243.      * @param ProductEntity $product
  244.      * @param Context $context
  245.      *
  246.      * @return array
  247.      */
  248.     private function getPropertyData(ProductEntity $productContext $context): array
  249.     {
  250.         $criteria = new Criteria();
  251.         $criteria->addAssociation('translations');
  252.         $criteria->addFilter(new EqualsAnyFilter('id'$product->getProperties()->getPropertyGroupIds()));
  253.         $propertyGroups $this->propertyGroupRepository->search($criteria$context);
  254.         $propertyGroupData = [];
  255.         /** @var PropertyGroupEntity $propertyGroup */
  256.         foreach ($propertyGroups as $propertyGroup) {
  257.             $propertyGroupData[$propertyGroup->getId()] = [
  258.                 'name' => $propertyGroup->getName(),
  259.                 'attributeGroup' => $this->getAttributeGroupFromDefaultStoreLanguage($propertyGroup)
  260.             ];
  261.         }
  262.         $result = [];
  263.         foreach ($product->getProperties() as $property) {
  264.             $parentName $propertyGroupData[$property->getGroupId()]['name'];
  265.             $parentAttributeGroup $propertyGroupData[$property->getGroupId()]['attributeGroup'];
  266.             $propertyValue $property->getName();
  267.             if (empty($parentName)) {
  268.                 continue;
  269.             }
  270.             $result[$parentAttributeGroup][$parentName] = $propertyValue;
  271.         }
  272.         return $result;
  273.     }
  274.     /**
  275.      * Shortcut for reading config fields.
  276.      *
  277.      * @param string $configField
  278.      *
  279.      * @return array|bool|float|int|string|null
  280.      */
  281.     private function getConfig(string $configField): float|int|bool|array|string|null
  282.     {
  283.         return $this->systemConfigService->get('UandiEfbDownloadCenter.config.' $configField);
  284.     }
  285.     /**
  286.      * Get attribute group in custom field from store main language
  287.      * - custom field is saved only for main language, it is necessayr to get attribute group for other languages
  288.      *
  289.      * @param PropertyGroupEntity $propertyGroup
  290.      * @return string
  291.      */
  292.     private function getAttributeGroupFromDefaultStoreLanguage(PropertyGroupEntity $propertyGroup): string
  293.     {
  294.         $mainLanguageTranslation array_filter($propertyGroup->getTranslations()->getElements(), function ($k) {
  295.             return $k->getLanguageId() === Defaults::LANGUAGE_SYSTEM;
  296.         }, ARRAY_FILTER_USE_BOTH);
  297.         $translation current($mainLanguageTranslation);
  298.         $customFields $translation->getCustomFields() ?? [];
  299.         return $customFields['attribute_group'] ?? '';
  300.     }
  301. }