Skip to content
Code-Schnipsel Gruppen Projekte
Output.php 16,5 KiB
Newer Older
  • Learn to ignore specific revisions
  • <?php
    
    namespace QUI\ERP\Output;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    use Exception;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function array_column;
    use function class_exists;
    use function file_exists;
    use function http_build_query;
    use function json_decode;
    use function rename;
    use function unlink;
    use function usort;
    
    
    /**
     * Class Output
     *
     * Main handler for serving previews, PDFs and downloads for QUIQQER ERP documents
     */
    class Output
    {
    
        /**
         * Permissions
         */
        const PERMISSION_ATTACH_EMAIL_FILES = 'quiqqer.erp.mail_editor_attach_files';
    
    
        /**
         * Get the ERP Output Provider for a specific package
         *
         * @param string $package
    
         * @return OutputProviderInterface|false - OutputProvider class (static) or false if none found
    
         */
        public static function getOutputProviderByPackage(string $package)
        {
    
            foreach (self::getAllOutputProviders() as $outputProvider) {
                if ($outputProvider['package'] === $package) {
                    return $outputProvider['class'];
                }
            }
    
        /**
         * Get the OutputProvider for a specific entity type
         *
         * @param string $entityType
         * @return OutputProviderInterface|false - OutputProvider class (static) or false if none found
         */
        public static function getOutputProviderByEntityType(string $entityType)
        {
            foreach (self::getAllOutputProviders() as $outputProvider) {
                /** @var OutputProviderInterface $class */
                $class = $outputProvider['class'];
    
                if ($class::getEntityType() === $entityType) {
                    return $class;
                }
            }
    
        /**
         * Get HTML output for a specific document
         *
         * @param string|int $entityId
         * @param string $entityType
         * @param OutputProviderInterface $OutputProvider (optional)
         * @param OutputTemplateProviderInterface $TemplateProvider (optional)
    
         * @param string|null $template (optional)
    
         * @param bool $preview (optional) - Get preview HTML
    
         *
         * @return string
         *
         * @throws QUI\Exception
         */
        public static function getDocumentHtml(
            $entityId,
            string $entityType,
            $OutputProvider = null,
            $TemplateProvider = null,
    
    Henning Leutz's avatar
    Henning Leutz committed
            $template = null,
    
            bool $preview = false
    
            if (empty($OutputProvider)) {
                $OutputProvider = self::getOutputProviderByEntityType($entityType);
            }
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (empty($OutputProvider)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                throw new QUI\Exception('No output provider found for entity type "' . $entityType . '"');
    
            if (empty($TemplateProvider)) {
                $TemplateProvider = self::getDefaultOutputTemplateProviderForEntityType($entityType);
            }
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (empty($TemplateProvider)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                throw new QUI\Exception('No default output template provider found for entity type "' . $entityType . '"');
    
            $OutputTemplate = new OutputTemplate(
                $TemplateProvider,
                $OutputProvider,
                $entityId,
                $entityType,
                $template
            );
    
            return $OutputTemplate->getHTML($preview);
    
        /**
         * Get HTML output for a specific document
         *
         * @param string|int $entityId
         * @param string $entityType
         * @param OutputProviderInterface $OutputProvider (optional)
         * @param OutputTemplateProviderInterface $TemplateProvider (optional)
    
         * @param string|null $template (optional)
    
         *
         * @return QUI\HtmlToPdf\Document
         *
         * @throws QUI\Exception
         */
        public static function getDocumentPdf(
            $entityId,
            string $entityType,
            $OutputProvider = null,
            $TemplateProvider = null,
    
    Henning Leutz's avatar
    Henning Leutz committed
            $template = null
    
        ): QUI\HtmlToPdf\Document {
    
            if (empty($OutputProvider)) {
                $OutputProvider = self::getOutputProviderByEntityType($entityType);
    
            if (empty($TemplateProvider)) {
                $TemplateProvider = self::getDefaultOutputTemplateProviderForEntityType($entityType);
            }
    
            $OutputTemplate = new OutputTemplate(
                $TemplateProvider,
                $OutputProvider,
                $entityId,
                $entityType,
                $template
            );
    
            return $OutputTemplate->getPDFDocument();
    
        /**
         * Get HTML output for a specific document
         *
    
         * @param string|int $entityId
    
         * @param string $entityType
         *
         * @return string
         */
    
        public static function getDocumentPdfDownloadUrl($entityId, string $entityType): string
        {
    
    Henning Leutz's avatar
    Henning Leutz committed
            $url = URL_OPT_DIR . 'quiqqer/erp/bin/output/frontend/download.php?';
            $url .= http_build_query([
    
                'id' => $entityId,
    
         * Send document as e-mail with PDF attachment
    
         *
         * @param string|int $entityId
         * @param string $entityType
         * @param OutputProviderInterface $OutputProvider (optional)
         * @param OutputTemplateProviderInterface $TemplateProvider (optional)
    
         * @param string|null $template (optional)
         * @param string|null $recipientEmail (optional)
         * @param string|null $mailSubject (optional)
         * @param string|null $mailContent (optional)
    
         * @param <QUI\Projects\Media\File|QUI\Projects\Media\Image>[] $attachedMediaFiles (optional)
    
         *
         * @return void
         *
         * @throws QUI\Exception
         */
        public static function sendPdfViaMail(
            $entityId,
    
            string $entityType,
    
            $OutputProvider = null,
            $TemplateProvider = null,
    
    Henning Leutz's avatar
    Henning Leutz committed
            $template = null,
            $recipientEmail = null,
            $mailSubject = null,
    
            $mailContent = null,
            $attachedMediaFiles = []
    
            if (empty($OutputProvider)) {
                $OutputProvider = self::getOutputProviderByEntityType($entityType);
    
            if (empty($TemplateProvider)) {
                $TemplateProvider = self::getDefaultOutputTemplateProviderForEntityType($entityType);
            }
    
            $OutputTemplate = new OutputTemplate(
    
                $TemplateProvider,
                $OutputProvider,
                $entityId,
    
                $entityType,
                $template
            );
    
            $pdfFile = $OutputTemplate->getPDFDocument()->createPDF();
    
            $pdfDir = QUI::getPackage('quiqqer/erp')->getVarDir();
    
    Henning Leutz's avatar
    Henning Leutz committed
            $mailFile = $pdfDir . $OutputProvider::getDownloadFileName($entityId) . '.pdf';
            rename($pdfFile, $mailFile);
    
            if (!QUI\Utils\Security\Orthos::checkMailSyntax($recipientEmail)) {
                throw new QUI\ERP\Exception([
                    'quiqqer/erp',
                    'exception.Output.sendPdfViaMail.recpient_address_invalid'
                ]);
            }
    
            if (empty($recipientEmail)) {
    
                $recipientEmail = $OutputProvider::getEmailAddress($entityId);
            }
    
            if (empty($recipientEmail)) {
                throw new QUI\ERP\Exception([
                    'quiqqer/erp',
                    'exception.Output.sendPdfViaMail.missing_recipient'
                ]);
            }
    
    
            // mail send
    
            $Mailer = new QUI\Mail\Mailer();
    
            $Mailer->addRecipient($recipientEmail);
    
            $Mailer->addAttachment($mailFile);
    
            // Additional attachments
            foreach ($attachedMediaFiles as $MediaFile) {
    
                if (
                    !($MediaFile instanceof QUI\Projects\Media\File) &&
                    !($MediaFile instanceof QUI\Projects\Media\Image)
                ) {
    
                    continue;
                }
    
                $Mailer->addAttachment($MediaFile->getFullPath());
            }
    
    
            if (!empty($mailSubject)) {
                $Mailer->setSubject($mailSubject);
            } else {
                $Mailer->setSubject($OutputProvider::getMailSubject($entityId));
            }
    
            if (!empty($mailContent)) {
                $Mailer->setBody($mailContent);
            } else {
                $Mailer->setBody($OutputProvider::getMailBody($entityId));
            }
    
            QUI::getEvents()->fireEvent(
                'quiqqerErpOutputSendMailBefore',
                [$entityId, $entityType, $recipientEmail, $Mailer]
            );
    
            QUI::getEvents()->fireEvent('quiqqerErpOutputSendMail', [$entityId, $entityType, $recipientEmail]);
    
            // Delete PDF file after send
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (file_exists($mailFile)) {
                unlink($mailFile);
    
        }
    
        /**
         * Get available templates for $entityType (e.g. "Invoice", "InvoiceTemporary" etc.)
         *
         * @param string $package
         * @return OutputTemplateProviderInterface|false - OutputProvider class (static) or false if
         */
    
    Patrick Müller's avatar
    Patrick Müller committed
        public static function getOutputTemplateProviderByPackage(string $package)
        {
    
            foreach (self::getAllOutputTemplateProviders() as $provider) {
                if ($provider['package'] === $package) {
                    return $provider['class'];
    
            }
    
            return false;
        }
    
        /**
         * Get available templates for $entityType (e.g. "Invoice", "InvoiceTemporary" etc.)
         *
    
         * @param string|null $entityType (optional) - Restrict to templates of $entityType [default: fetch templates for all entity types]
    
        public static function getTemplates(string $entityType = null): array
    
    Patrick Müller's avatar
    Patrick Müller committed
        {
    
            $outputProviders = [];
    
            if (empty($entityType)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $outputProviders = array_column(self::getAllOutputProviders(), 'class');
    
            } else {
                $OutputProvider = self::getOutputProviderByEntityType($entityType);
    
                if ($OutputProvider) {
                    $outputProviders[] = $OutputProvider;
                }
            }
    
    
            foreach (self::getAllOutputTemplateProviders() as $provider) {
                /** @var OutputTemplateProviderInterface $class */
    
                $class = $provider['class'];
    
                $package = $provider['package'];
    
                /** @var OutputProviderInterface $OutputProvider */
                foreach ($outputProviders as $OutputProvider) {
    
                    $entityType = $OutputProvider::getEntityType();
    
                    $defaultOutputTemplate = self::getDefaultOutputTemplateForEntityType($entityType);
    
                    foreach ($class::getTemplates($entityType) as $providerTemplateId) {
                        $templateTitle = $class::getTemplateTitle($providerTemplateId);
    
                        if ($provider['isSystemDefault']) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                            $templateTitle .= ' ' . QUI::getLocale()->get('quiqqer/erp', 'output.default_template.suffix');
    
                        $isDefault = isset($defaultOutputTemplate['provider']) &&
    
    Henning Leutz's avatar
    Henning Leutz committed
                            $defaultOutputTemplate['provider'] === $provider['package'] &&
                            $defaultOutputTemplate['id'] === $providerTemplateId;
    
                            'id' => $providerTemplateId,
                            'title' => $templateTitle,
                            'provider' => $package,
    
                            'isSystemDefault' => $provider['isSystemDefault'],
    
                            'isDefault' => $isDefault,
                            'entityType' => $entityType,
    
                            'entityTypeTitle' => $OutputProvider::getEntityTypeTitle()
                        ];
    
    
                        $templates[] = $providerTemplate;
                    }
    
            // Sort so that system default is first
    
    Henning Leutz's avatar
    Henning Leutz committed
            usort($templates, function ($a, $b) {
    
                if ($a['isSystemDefault']) {
                    return -1;
                }
    
                if ($b['isSystemDefault']) {
                    return 1;
                }
    
                return 0;
            });
    
    
        /**
         * Return default template id for a specific entity type
         *
         * @param string $entityType
    
         * @return array - Containing template ID and template provider package
    
        public static function getDefaultOutputTemplateForEntityType(string $entityType): array
    
                'id' => 'system_default',
                'provider' => 'quiqqer/erp-accounting-templates',
    
                'hideSystemDefault' => false
            ];
    
            try {
    
                $Conf = QUI::getPackage('quiqqer/erp')->getConfig();
    
                $defaultTemplates = $Conf->get('output', 'default_templates');
    
                if (empty($defaultTemplates)) {
                    return $fallBackTemplate;
                }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                $defaultTemplates = json_decode($defaultTemplates, true);
    
    
                if (empty($defaultTemplates[$entityType])) {
                    return $fallBackTemplate;
                }
    
                return $defaultTemplates[$entityType];
    
    Henning Leutz's avatar
    Henning Leutz committed
            } catch (Exception $Exception) {
    
                QUI\System\Log::writeException($Exception);
    
        /**
         * Return default Output Template provider class for a specific entity type
         *
         * @param string $entityType
         * @return OutputTemplateProviderInterface|false
         */
    
    Patrick Müller's avatar
    Patrick Müller committed
        public static function getDefaultOutputTemplateProviderForEntityType(string $entityType)
        {
    
            $defaultEntityTypeTemplate = self::getDefaultOutputTemplateForEntityType($entityType);
    
            foreach (self::getAllOutputTemplateProviders() as $provider) {
    
                if (isset($defaultEntityTypeTemplate['provider']) && $provider['package'] === $defaultEntityTypeTemplate['provider']) {
    
                    return $provider['class'];
                }
            }
    
            // Fallback: Choose next available provider
    
            foreach (self::getAllOutputTemplateProviders() as $provider) {
                /** @var OutputTemplateProviderInterface $class */
    
                $class = $provider['class'];
    
                $providerTemplates = $class::getTemplates($entityType);
    
                if (!empty($providerTemplates)) {
                    return $class;
    
        /**
         * Get all available ERP Output provider classes
         *
         * @return array - Provider classes
         */
    
        protected static function getAllOutputProviders(): array
    
            $packages = QUI::getPackageManager()->getInstalled();
    
            $providerClasses = [];
    
            foreach ($packages as $installedPackage) {
                try {
                    $Package = QUI::getPackage($installedPackage['name']);
    
                    if (!$Package->isQuiqqerPackage()) {
                        continue;
                    }
    
                    $packageProvider = $Package->getProvider();
    
                    if (empty($packageProvider['erpOutput'])) {
                        continue;
                    }
    
                    /** @var OutputProviderInterface $class */
    
    Patrick Müller's avatar
    Patrick Müller committed
                    foreach ($packageProvider['erpOutput'] as $class) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                        if (!class_exists($class)) {
    
    Patrick Müller's avatar
    Patrick Müller committed
                            continue;
                        }
    
    Patrick Müller's avatar
    Patrick Müller committed
                        $providerClasses[] = [
    
    Patrick Müller's avatar
    Patrick Müller committed
                            'package' => $installedPackage['name']
                        ];
    
                    }
                } catch (QUI\Exception $Exception) {
                    QUI\System\Log::writeException($Exception);
                }
            }
    
            return $providerClasses;
        }
    
    
        /**
         * Get all available ERP Output Template provider classes
         *
         * @return array - Provider classes
         */
    
        protected static function getAllOutputTemplateProviders(): array
    
            $packages = QUI::getPackageManager()->getInstalled();
    
            $providerClasses = [];
    
            foreach ($packages as $installedPackage) {
                try {
                    $Package = QUI::getPackage($installedPackage['name']);
    
                    if (!$Package->isQuiqqerPackage()) {
                        continue;
                    }
    
                    $packageProvider = $Package->getProvider();
    
                    if (empty($packageProvider['erpOutputTemplate'])) {
                        continue;
                    }
    
                    /** @var OutputTemplateProviderInterface $class */
    
    Patrick Müller's avatar
    Patrick Müller committed
                    foreach ($packageProvider['erpOutputTemplate'] as $class) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                        if (!class_exists($class)) {
    
    Patrick Müller's avatar
    Patrick Müller committed
                            continue;
                        }
    
    Patrick Müller's avatar
    Patrick Müller committed
                        $providerClasses[] = [
    
                            'class' => $class,
                            'package' => $installedPackage['name'],
    
                            'isSystemDefault' => $installedPackage['name'] === 'quiqqer/erp-accounting-templates'
    
                    }
                } catch (QUI\Exception $Exception) {
                    QUI\System\Log::writeException($Exception);
                }
    
            // Sort providers that system default is first
    
    Henning Leutz's avatar
    Henning Leutz committed
            usort($providerClasses, function ($a, $b) {
    
                if ($a['isSystemDefault']) {
                    return -1;
                }
    
                if ($b['isSystemDefault']) {
                    return 1;
                }
    
                return 0;
            });
    
    
            return $providerClasses;