diff --git a/ajax/output/getEntityData.php b/ajax/output/getEntityData.php new file mode 100644 index 0000000000000000000000000000000000000000..5d1d74652c3ad2b6077b8e228b0e25e8da29016d --- /dev/null +++ b/ajax/output/getEntityData.php @@ -0,0 +1,46 @@ +<?php + +use QUI\ERP\Output\Output as ERPOutput; +use QUI\Utils\Security\Orthos; + +/** + * Returns basic entity data used in OutputDialog + * + * @param string|int $entityId + * @param string $entityType + * @return array|false - Entity data or false + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_output_getEntityData', + function ($entityId, $entityType) { + $OutputProvider = ERPOutput::getOutputProviderByEntityType(Orthos::clear($entityType)); + + if (empty($OutputProvider)) { + return false; + } + + $hideSystemDefaultTemplate = false; + + try { + $Conf = QUI::getPackage('quiqqer/erp')->getConfig(); + $defaultTemplates = $Conf->get('output', 'default_templates'); + + if (!empty($defaultTemplates)) { + $defaultTemplates = \json_decode($defaultTemplates, true); + + if (!empty($defaultTemplates[$entityType])) { + $hideSystemDefaultTemplate = $defaultTemplates[$entityType]['hideSystemDefault']; + } + } + } catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + } + + return [ + 'email' => $OutputProvider::getEmailAddress(Orthos::clear($entityId)), + 'hideSystemDefaultTemplate' => $hideSystemDefaultTemplate + ]; + }, + ['entityId', 'entityType'], + 'Permission::checkAdminUser' +); diff --git a/ajax/output/getMailData.php b/ajax/output/getMailData.php new file mode 100644 index 0000000000000000000000000000000000000000..e7628aa087952c24f3345783a0b1d451ad9c4f1f --- /dev/null +++ b/ajax/output/getMailData.php @@ -0,0 +1,31 @@ +<?php + +use QUI\ERP\Output\Output as ERPOutput; +use QUI\Utils\Security\Orthos; + +/** + * Returns e-mail data for an output document + * + * @return array + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_output_getMailData', + function ($entityId, $entityType) { + $OutputProvider = ERPOutput::getOutputProviderByEntityType(Orthos::clear($entityType)); + $mailData = [ + 'subject' => '', + 'content' => '' + ]; + + if (empty($OutputProvider)) { + return $mailData; + } + + $mailData['subject'] = $OutputProvider::getMailSubject($entityId); + $mailData['content'] = $OutputProvider::getMailBody($entityId); + + return $mailData; + }, + ['entityId', 'entityType'], + 'Permission::checkAdminUser' +); diff --git a/ajax/output/getPreview.php b/ajax/output/getPreview.php new file mode 100644 index 0000000000000000000000000000000000000000..a7a147c1b61d40381db5d0746cab1c084c1337ca --- /dev/null +++ b/ajax/output/getPreview.php @@ -0,0 +1,33 @@ +<?php + +use QUI\ERP\Output\Output as ERPOutput; +use QUI\Utils\Security\Orthos; + +/** + * Returns the invoice templates + * + * @return array + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_output_getPreview', + function ($entity, $template) { + $entity = Orthos::clearArray(\json_decode($entity, true)); + $template = Orthos::clearArray(\json_decode($template, true)); + + try { + return ERPOutput::getDocumentHtml( + $entity['id'], + $entity['type'], + null, + ERPOutput::getOutputTemplateProviderByPackage($template['provider']), + $template['id'], + true + ); + } catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + return ''; + } + }, + ['entity', 'template'], + 'Permission::checkAdminUser' +); diff --git a/ajax/output/getTemplates.php b/ajax/output/getTemplates.php new file mode 100644 index 0000000000000000000000000000000000000000..94d7881d3fc8e593bc4bb6d2abd3827f56230a8b --- /dev/null +++ b/ajax/output/getTemplates.php @@ -0,0 +1,19 @@ +<?php + +use QUI\ERP\Output\Output as ERPOutput; +use QUI\Utils\Security\Orthos; + +/** + * Returns available output templates + * + * @param string $entityType (optional) - Restrict templates to those for $entityType + * @return array + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_output_getTemplates', + function ($entityType = null) { + return ERPOutput::getTemplates(Orthos::clear($entityType)); + }, + ['entityType'], + 'Permission::checkAdminUser' +); diff --git a/ajax/output/sendMail.php b/ajax/output/sendMail.php new file mode 100644 index 0000000000000000000000000000000000000000..70bb39c7c63a642ff58c86e49784daea0bc3fe68 --- /dev/null +++ b/ajax/output/sendMail.php @@ -0,0 +1,56 @@ +<?php + +use QUI\ERP\Output\Output as ERPOutput; +use QUI\Utils\Security\Orthos; + +/** + * Returns e-mail data for an output document + * + * @param string|int $entityId + * @param string $entityType + * @param string $template + * @param string $templateProvider + * @param string $mailSubject (optional) + * @param string $mailContent (optional) + * + * @return void + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_output_sendMail', + function ($entityId, $entityType, $template, $templateProvider, $mailSubject, $mailContent) { + try { + $entityType = Orthos::clear($entityType); + + $OutputProvider = ERPOutput::getOutputProviderByEntityType($entityType); + $TemplateProvider = ERPOutput::getOutputTemplateProviderByPackage(Orthos::clear($templateProvider)); + + if (empty($TemplateProvider)) { + $TemplateProvider = ERPOutput::getDefaultOutputTemplateProviderForEntityType($entityType); + } + + ERPOutput::sendPdfViaMail( + $entityId, + $entityType, + $OutputProvider, + $TemplateProvider, + Orthos::clear($template), + null, + $mailSubject, + $mailContent + ); + } catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + + throw new \QUI\Exception([ + 'quiqqer/erp', + 'exception.ajax.output.sendMail.error' + ]); + } + + QUI::getMessagesHandler()->addSuccess( + QUI::getLocale()->get('quiqqer/erp', 'Output.send.success') + ); + }, + ['entityId', 'entityType', 'template', 'templateProvider', 'mailSubject', 'mailContent'], + 'Permission::checkAdminUser' +); diff --git a/bin/backend/controls/OutputDialog.css b/bin/backend/controls/OutputDialog.css new file mode 100644 index 0000000000000000000000000000000000000000..8a4a10cec9cee0b195fe8e2709796211796f9153 --- /dev/null +++ b/bin/backend/controls/OutputDialog.css @@ -0,0 +1,48 @@ +.quiqqer-erp-outputDialog { + padding: 10px !important; + display: flex; +} + +.quiqqer-erp-outputDialog .field-container-item { + width: 150px !important; +} + +.quiqqer-erp-outputDialog-options { + padding: 5px; + width: 400px; +} + +.quiqqer-erp-outputDialog form table { + border: none; + padding: 0; +} + +.quiqqer-erp-outputDialog select { + width: 100%; +} + +.quiqqer-erp-outputDialog-preview { + background-color: #efefef; + float: left; + height: 100%; + overflow: auto; + padding: 20px; + width: calc(100% - 400px); +} + +.quiqqer-erp-outputDialog-preview { + background: #fff; + box-shadow: 0 0 0 0.75pt #d1d1d1, 0 0 3pt 0.75pt #ccc; + border: none; + display: block; + margin: 0 auto; +} +.quiqqer-erp-outputDialog-openMailEditor { + background-color: #dedede; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + cursor: pointer; + float: right; + padding: 5px; +} + diff --git a/bin/backend/controls/OutputDialog.html b/bin/backend/controls/OutputDialog.html new file mode 100644 index 0000000000000000000000000000000000000000..0b28317d083ac202dae20a7ba197de252a7dfe80 --- /dev/null +++ b/bin/backend/controls/OutputDialog.html @@ -0,0 +1,77 @@ +<div class="quiqqer-erp-outputDialog-options"> + <form> + <table class="data-table data-table-flexbox"> + <tbody> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item" title="{{labelEntityId}}"> + {{labelEntityId}} + </span> + <span class="field-container-field"> + {{entityId}} + </span> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item" title="{{labelTemplate}}"> + {{labelTemplate}} + </span> + <select name="template" class="field-container-field"></select> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item" title="{{labelOutputType}}"> + {{labelOutputType}} + </span> + <span class="field-container-field field-container-field-no-padding field-output"></span> + </label> + </td> + </tr> + <tr style="display: none"> + <td> + <label class="field-container"> + <span class="field-container-item" title="{{labelEmail}}"> + {{labelEmail}} + </span> + <input type="text" + name="recipient" + placeholder="email@domain.com" + class="field-container-field"/> + </label> + {{#mailEditor}} + <div class="quiqqer-erp-outputDialog-openMailEditor"> + <span class="fa fa-envelope"></span> + <span>{{labelOpenMailEditor}}</span> + </div> + {{/mailEditor}} + </td> + </tr> + {{#showMarkAsSentOption}} + <tr> + <td> + <label class="field-container"> + <span class="field-container-item" title="{{labelMarkAsSent}}"> + {{labelMarkAsSent}} + </span> + <div class="field-container-field"> + <input type="checkbox" name="mark_as_sent"/> + </div> + </label> + <div class="field-container-item-desc"> + {{{descMarkAsSent}}} + </div> + </td> + </tr> + {{/showMarkAsSentOption}} + </tbody> + </table> + </form> +</div> +<div class="quiqqer-erp-outputDialog-preview"></div> \ No newline at end of file diff --git a/bin/backend/controls/OutputDialog.js b/bin/backend/controls/OutputDialog.js new file mode 100644 index 0000000000000000000000000000000000000000..0c88ea12746465648559dc7c4d1390ab9162b68e --- /dev/null +++ b/bin/backend/controls/OutputDialog.js @@ -0,0 +1,597 @@ +/** + * @module package/quiqqer/erp/bin/backend/controls/OutputDialog + * @author www.pcsg.de (Patrick Müller) + * + * @event onOuput [FormData, this] - Fires if the user submits the popup with a chosen output format + */ +define('package/quiqqer/erp/bin/backend/controls/OutputDialog', [ + + 'qui/QUI', + 'qui/controls/windows/Confirm', + 'qui/controls/buttons/Select', + 'qui/controls/elements/Sandbox', + + 'qui/utils/Form', + + 'Ajax', + 'Locale', + 'Mustache', + 'Users', + + 'text!package/quiqqer/erp/bin/backend/controls/OutputDialog.html', + 'css!package/quiqqer/erp/bin/backend/controls/OutputDialog.css' + +], function (QUI, QUIConfirm, QUISelect, QUISandbox, QUIFormUtils, QUIAjax, QUILocale, Mustache, Users, template) { + "use strict"; + + var lg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIConfirm, + type : 'package/quiqqer/erp/bin/backend/controls/OutputDialog', + + Binds: [ + '$onOpen', + '$onOutputChange', + '$onPrintFinish', + '$getPreview', + '$onChangeToEmail', + '$onChangeToPDF', + '$onChangeToPrint' + ], + + options: { + entityId : false, // Clean entity ID WITHOUT prefix and suffix + entityType: false, // Entity type (e.g. "Invoice") + + showMarkAsSentOption: false, // show checkbox for "Mark as sent" + mailEditor : true, // shows editable subject and body for mail output + + maxHeight: 800, + maxWidth : 1400 + }, + + initialize: function (options) { + this.parent(options); + + this.setAttributes({ + icon : 'fa fa-print', + title : QUILocale.get(lg, 'controls.OutputDialog.title'), + autoclose : false, + cancel_button: { + textimage: 'fa fa-close', + text : QUILocale.get('quiqqer/system', 'close') + } + }); + + this.$Output = null; + this.$Preview = null; + this.$customerMail = null; + this.$Template = null; + + this.$Mail = { + subject: false, + content: false + }; + + this.addEvents({ + onOpen : this.$onOpen, + onSubmit : this.$onSubmit, + onOpenBegin: function () { + var winSize = QUI.getWindowSize(); + var height = 800; + var width = 1400; + + if (winSize.y * 0.9 < height) { + height = winSize.y * 0.9; + } + + if (winSize.x * 0.9 < width) { + width = winSize.x * 0.9; + } + + this.setAttribute('maxHeight', height); + this.setAttribute('maxWidth', width); + }.bind(this) + }); + }, + + /** + * event: on open + */ + $onOpen: function () { + var self = this, + Content = this.getContent(); + + this.Loader.show(); + this.getContent().set('html', ''); + + var onError = function (error) { + self.close().then(function () { + self.destroy(); + }); + + QUI.getMessageHandler().then(function (MH) { + if (typeof error === 'object' && typeof error.getMessage !== 'undefined') { + MH.addError(error.getMessage()); + return; + } + + MH.addError(error); + }); + }; + + Content.set({ + html: Mustache.render(template, { + entityId : this.getAttribute('entityId'), + labelEntityId : QUILocale.get(lg, 'controls.OutputDialog.labelEntityId'), + labelTemplate : QUILocale.get(lg, 'controls.OutputDialog.labelTemplate'), + labelOutputType : QUILocale.get(lg, 'controls.OutputDialog.labelOutputType'), + labelEmail : QUILocale.get('quiqqer/quiqqer', 'recipient'), + showMarkAsSentOption: this.getAttribute('showMarkAsSentOption') ? true : false, + mailEditor : this.getAttribute('mailEditor') ? true : false, + labelOpenMailEditor : QUILocale.get(lg, 'controls.OutputDialog.labelOpenMailEditor'), + labelMarkAsSent : QUILocale.get(lg, 'controls.OutputDialog.labelMarkAsSent'), + descMarkAsSent : QUILocale.get(lg, 'controls.OutputDialog.descMarkAsSent') + }) + }); + + Content.addClass('quiqqer-erp-outputDialog'); + + // "To mail editor" button + if (this.getAttribute('mailEditor')) { + Content.getElement('.quiqqer-erp-outputDialog-openMailEditor').addEvent('click', function () { + require(['package/quiqqer/erp/bin/backend/controls/OutputMailEditor'], function (OutputMailEditor) { + new OutputMailEditor({ + entityId : self.getAttribute('entityId'), + entityType: self.getAttribute('entityType'), + + mailSubject: self.$Mail.subject, + mailContent: self.$Mail.content, + + events: { + onMailSubmit: function (MailData) { + self.$Mail = MailData; + } + } + }).open(); + }); + }); + } + + this.$Output = new QUISelect({ + localeStorage: 'quiqqer-erp-output-dialog', + name : 'output', + styles : { + border: 'none', + width : '100%' + }, + events : { + onChange: self.$onOutputChange + } + }); + + this.$Output.appendChild( + QUILocale.get(lg, 'controls.OutputDialog.data.output.print'), + 'print', + 'fa fa-print' + ); + + this.$Output.appendChild( + QUILocale.get(lg, 'controls.OutputDialog.data.output.pdf'), + 'pdf', + 'fa fa-file-pdf-o' + ); + + this.$Output.appendChild( + QUILocale.get(lg, 'controls.OutputDialog.data.output.email'), + 'email', + 'fa fa-envelope-o' + ); + + this.$Output.inject(Content.getElement('.field-output')); + + Promise.all([ + this.$getTemplates(), + this.$getEntityData() + ]).then(function (result) { + var templates = result[0]; + var EntityData = result[1]; + + var Form = Content.getElement('form'), + Selected = false; + + if (!templates.length) { + new Element('option', { + value: '#', + html : QUILocale.get(lg, 'controls.OutputDialog.no_templates_found'), + }).inject(Form.elements.template); + + Form.elements.template.disabled = true; + + var PreviewContent = self.getContent().getElement('.quiqqer-erp-outputDialog-preview'); + + new Element('div', { + 'class': 'quiqqer-erp-outputDialog-nopreview', + html : QUILocale.get(lg, 'controls.OutputDialog.no_preview') + }).inject(PreviewContent); + + self.$Output.disable(); + self.getButton('submit').disable(); + + self.Loader.hide(); + return; + } + + for (var i = 0, len = templates.length; i < len; i++) { + var Template = templates[i]; + + if (Template.isSystemDefault && EntityData.hideSystemDefaultTemplate) { + continue; + } + + new Element('option', { + value : Template.id, + html : Template.title, + 'data-provider': Template.provider + }).inject(Form.elements.template); + + if (!Selected && Template.isDefault) { + Selected = Template; + } + } + + Form.elements.template.addEvent('change', function (event) { + self.$Template = { + id : event.target.value, + provider: event.target.getElement('option[value="' + event.target.value + '"]') + .get('data-provider') + }; + + self.$renderPreview(); + }); + + // Set initial template and render preview + Form.elements.template.value = Selected.id; + self.$Template = { + id : Selected.id, + provider: Selected.provider + }; + + self.$renderPreview(); + + // Customer data + self.$customerMail = EntityData.email; + self.$onOutputChange(); + + self.Loader.hide(); + }).catch(function (e) { + onError(e); + }); + }, + + /** + * Render preview with selected template + */ + $renderPreview: function () { + var self = this; + var PreviewContent = this.getContent().getElement('.quiqqer-erp-outputDialog-preview'); + + this.Loader.show(); + + var showPreviewError = function () { + PreviewContent.set('html', ''); + + new Element('div', { + 'class': 'quiqqer-erp-outputDialog-nopreview', + html : QUILocale.get(lg, 'controls.OutputDialog.preview_error') + }).inject(PreviewContent); + }; + + this.$getPreview().then(function (previewHtml) { + self.Loader.hide(); + + if (!previewHtml) { + showPreviewError(); + return; + } + + PreviewContent.set('html', ''); + + new QUISandbox({ + content: previewHtml, + styles : { + height : 1240, + padding: 20, + width : 874 + }, + events : { + onLoad: function (Box) { + Box.getElm().addClass('quiqqer-erp-outputDialog-preview'); + } + } + }).inject(PreviewContent); + }).catch(function () { + self.Loader.hide(); + showPreviewError(); + }); + }, + + /** + * event: on submit + */ + $onSubmit: function () { + var self = this, + Run = Promise.resolve(); + + this.Loader.show(); + + switch (this.$Output.getValue()) { + case 'print': + Run = this.print(); + break; + + case 'pdf': + Run = this.saveAsPdf(); + break; + + case 'email': + Run = this.$sendMail(); + break; + } + + Run.then(function () { + var Form = self.getContent().getElement('form'); + + self.fireEvent('output', [ + QUIFormUtils.getFormData(Form), + self + ]); + + self.Loader.hide(); + }); + }, + + /** + * Print the document + * + * @return {Promise} + */ + print: function () { + var self = this, + entityId = this.getAttribute('entityId'); + + return new Promise(function (resolve) { + var id = 'print-document-' + entityId, + Content = self.getContent(), + Form = Content.getElement('form'); + + self.Loader.show(); + + new Element('iframe', { + src : URL_OPT_DIR + 'quiqqer/erp/bin/output/backend/print.php?' + Object.toQueryString({ + id : entityId, + t : self.getAttribute('entityType'), + oid : self.getId(), + tpl : self.$Template.id, + tplpr: self.$Template.provider + }), + id : id, + styles: { + position: 'absolute', + top : -200, + left : -200, + width : 50, + height : 50 + } + }).inject(document.body); + + self.addEvent('onPrintFinish', function (self, pId) { + if (pId === entityId) { + resolve(); + } + }); + }); + }, + + /** + * event: on print finish + * + * @param {String|Number} id + */ + $onPrintFinish: function (id) { + this.fireEvent('printFinish', [this, id]); + + (function () { + document.getElements('#print-document-' + id).destroy(); + this.close(); + }).delay(1000, this); + }, + + /** + * Export the document as PDF + * + * @return {Promise} + */ + saveAsPdf: function () { + var self = this, + entityId = this.getAttribute('entityId'); + + return new Promise(function (resolve) { + var id = 'download-document-' + entityId, + Content = self.getContent(), + Form = Content.getElement('form'); + + new Element('iframe', { + src : URL_OPT_DIR + 'quiqqer/erp/bin/output/backend/download.php?' + Object.toQueryString({ + id : entityId, + t : self.getAttribute('entityType'), + oid : self.getId(), + tpl : self.$Template.id, + tplpr: self.$Template.provider + }), + id : id, + styles: { + position: 'absolute', + top : -200, + left : -200, + width : 50, + height : 50 + } + }).inject(document.body); + + (function () { + resolve(); + }).delay(2000, this); + + (function () { + document.getElements('#' + id).destroy(); + }).delay(20000, this); + }); + }, + + /** + * event : on output change + * + * @return {Promise} + */ + $onOutputChange: function () { + var Recipient = this.getElm().getElement('[name="recipient"]'); + + Recipient.getParent('tr').setStyle('display', 'none'); + + switch (this.$Output.getValue()) { + case 'print': + this.$onChangeToPrint(); + break; + + case 'pdf': + this.$onChangeToPDF(); + break; + + case 'email': + this.$onChangeToEmail(); + break; + } + }, + + /** + * event: on output change -> to print + */ + $onChangeToPrint: function () { + var Submit = this.getButton('submit'); + + Submit.setAttribute('text', QUILocale.get(lg, 'controls.OutputDialog.data.output.print.btn')); + Submit.setAttribute('textimage', 'fa fa-print'); + }, + + /** + * event: on output change -> to pdf + */ + $onChangeToPDF: function () { + var Submit = this.getButton('submit'); + + Submit.setAttribute('text', QUILocale.get(lg, 'controls.OutputDialog.data.output.pdf.btn')); + Submit.setAttribute('textimage', 'fa fa-file-pdf-o'); + }, + + /** + * event: on output change -> to Email + */ + $onChangeToEmail: function () { + var Submit = this.getButton('submit'); + var Recipient = this.getElm().getElement('[name="recipient"]'); + + Recipient.getParent('tr').setStyle('display', null); + + Submit.setAttribute('text', QUILocale.get(lg, 'controls.OutputDialog.data.output.email.btn')); + Submit.setAttribute('textimage', 'fa fa-envelope-o'); + + if (this.$customerMail && Recipient.value === '') { + Recipient.value = this.$customerMail; + } + + Recipient.focus(); + }, + + /** + * Get data of the entity that is outputted + * + * @return {Promise} + */ + $getEntityData: function () { + var self = this; + + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_output_getEntityData', resolve, { + 'package' : 'quiqqer/erp', + entityId : self.getAttribute('entityId'), + entityType: self.getAttribute('entityType'), + onError : reject + }) + }); + }, + + /** + * Fetch available templates based on entity type + * + * @return {Promise} + */ + $getTemplates: function () { + var self = this; + + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_output_getTemplates', resolve, { + 'package' : 'quiqqer/erp', + entityType: self.getAttribute('entityType'), + onError : reject + }) + }); + }, + + /** + * Fetch available templates based on entity type + * + * @return {Promise} + */ + $getPreview: function () { + var self = this; + + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_output_getPreview', resolve, { + 'package': 'quiqqer/erp', + entity : JSON.encode({ + id : self.getAttribute('entityId'), + type: self.getAttribute('entityType') + }), + template : JSON.encode(self.$Template), + onError : reject + }) + }); + }, + + /** + * Get data of the entity that is outputted + * + * @return {Promise} + */ + $sendMail: function () { + var self = this, + Form = this.getContent().getElement('form'); + + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_output_sendMail', resolve, { + 'package' : 'quiqqer/erp', + entityId : self.getAttribute('entityId'), + entityType : self.getAttribute('entityType'), + template : self.$Template.id, + templateProvider: self.$Template.provider, + mailSubject : self.$Mail.subject, + mailContent : self.$Mail.content, + onError : reject + }) + }); + } + }); +}); \ No newline at end of file diff --git a/bin/backend/controls/OutputMailEditor.css b/bin/backend/controls/OutputMailEditor.css new file mode 100644 index 0000000000000000000000000000000000000000..01cb85d474ed0505d30801b95f5cb03c6925048a --- /dev/null +++ b/bin/backend/controls/OutputMailEditor.css @@ -0,0 +1,19 @@ +.quiqqer-erp-outputMailEditor-mailEditor > label { + display: block; + margin: 10px 0; + width: 100%; +} + +.quiqqer-erp-outputMailEditor-mailEditor-subject { + display: block; + width: 100%; +} + +.quiqqer-erp-outputMailEditor-info { + float: left; + margin-top: 10px; +} + +.quiqqer-erp-outputMailEditor-mailEditor-content { + height: 550px; +} \ No newline at end of file diff --git a/bin/backend/controls/OutputMailEditor.html b/bin/backend/controls/OutputMailEditor.html new file mode 100644 index 0000000000000000000000000000000000000000..d88070ab731ac10991fcf7a827407863c2217f38 --- /dev/null +++ b/bin/backend/controls/OutputMailEditor.html @@ -0,0 +1,13 @@ +<div class="quiqqer-erp-outputMailEditor-mailEditor"> + <label> + <span>{{labelMailSubject}}</span> + <input class="quiqqer-erp-outputMailEditor-mailEditor-subject" type="text"/> + </label> + <label> + <span>{{labelMailContent}}</span> + <div class="quiqqer-erp-outputMailEditor-mailEditor-content"></div> + </label> +</div> +<div class="quiqqer-erp-outputMailEditor-info"> + {{{info}}} +</div> \ No newline at end of file diff --git a/bin/backend/controls/OutputMailEditor.js b/bin/backend/controls/OutputMailEditor.js new file mode 100644 index 0000000000000000000000000000000000000000..8d8c8eac59d8e3d4c71de79fe12236262b370ce4 --- /dev/null +++ b/bin/backend/controls/OutputMailEditor.js @@ -0,0 +1,172 @@ +/** + * Edit the e-mail subject and content of an Output document + * + * @module package/quiqqer/erp/bin/backend/controls/OutputMailEditor + * @author www.pcsg.de (Patrick Müller) + * + * @event onMailSubmit [MailData, this] - Fires if the user submits the mail data + */ +define('package/quiqqer/erp/bin/backend/controls/OutputMailEditor', [ + + 'qui/QUI', + 'qui/controls/windows/Confirm', + 'qui/controls/buttons/Select', + 'qui/controls/elements/Sandbox', + + 'qui/utils/Form', + + 'Ajax', + 'Locale', + 'Mustache', + 'Users', + + 'text!package/quiqqer/erp/bin/backend/controls/OutputMailEditor.html', + 'css!package/quiqqer/erp/bin/backend/controls/OutputMailEditor.css' + +], function (QUI, QUIConfirm, QUISelect, QUISandbox, QUIFormUtils, QUIAjax, QUILocale, Mustache, Users, template) { + "use strict"; + + var lg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIConfirm, + type : 'package/quiqqer/erp/bin/backend/controls/OutputMailEditor', + + Binds: [ + '$onOpen', + '$onSubmit' + ], + + options: { + entityId : false, // Clean entity ID WITHOUT prefix and suffix + entityType: false, // Entity type (e.g. "Invoice") + + mailSubject: false, // Mail subject that is shown initially + mailContent: false, // Mail content that is shown initially + + maxHeight: 820, + maxWidth : 900 + }, + + initialize: function (options) { + this.parent(options); + + this.setAttributes({ + icon : 'fa fa-envelope', + title : QUILocale.get(lg, 'controls.OutputMailEditor.title'), + autoclose : false, + cancel_button: { + textimage: 'fa fa-close', + text : QUILocale.get('quiqqer/system', 'close') + } + }); + + this.$Output = null; + this.$Preview = null; + this.$cutomerMail = null; + this.$Template = null; + + this.$subject = null; + this.$content = null; + + this.$MailSubjectInput = null; + this.$MailContentEditor = null; + + this.addEvents({ + onOpen : this.$onOpen, + onSubmit: this.$onSubmit + }); + }, + + /** + * event: on open + */ + $onOpen: function () { + var self = this, + Content = this.getContent(); + + this.Loader.show(); + + Content.set({ + html: Mustache.render(template, { + entityId : self.getAttribute('entityId'), + labelEntityId : QUILocale.get(lg, 'controls.OutputMailEditor.labelEntityId'), + labelMailSubject: QUILocale.get(lg, 'controls.OutputMailEditor.labelMailSubject'), + labelMailContent: QUILocale.get(lg, 'controls.OutputMailEditor.labelMailContent'), + info : QUILocale.get(lg, 'controls.OutputMailEditor.info') + }) + }); + + Content.addClass('quiqqer-erp-OutputMailEditor'); + + this.$MailSubjectInput = Content.getElement('.quiqqer-erp-outputMailEditor-mailEditor-subject'); + this.$subject = this.getAttribute('mailSubject'); + this.$content = this.getAttribute('mailContent'); + + this.$getMailData().then(function (MailData) { + require(['Editors'], function (Editors) { + Editors.getEditor().then(function (Editor) { + Editor.addEvent('onLoaded', function () { + self.Loader.hide(); + self.fireEvent('load', [self]); + + Editor.resize(); + }); + + Editor.inject( + Content.getElement('.quiqqer-erp-outputMailEditor-mailEditor-content') + ); + + self.$MailContentEditor = Editor; + + if (self.$subject) { + self.$MailSubjectInput.value = self.$subject; + } else { + self.$MailSubjectInput.value = MailData.subject; + } + + if (self.$content) { + self.$MailContentEditor.setContent(self.$content); + } else { + self.$MailContentEditor.setContent(MailData.content); + } + }); + }); + }); + }, + + /** + * Event: onSubmit + */ + $onSubmit: function () { + this.fireEvent('mailSubmit', [ + { + subject: this.$MailSubjectInput.value, + content: this.$MailContentEditor.getContent() + }, + this + ]); + + this.close(); + }, + + /** + * Get data of the entity that is outputted + * + * @return {Promise} + */ + $getMailData: function () { + var self = this; + + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_output_getMailData', resolve, { + 'package' : 'quiqqer/erp', + entityId : self.getAttribute('entityId'), + entityType: self.getAttribute('entityType'), + onError : reject + }) + }); + } + }); +}); \ No newline at end of file diff --git a/bin/backend/controls/Panel.js b/bin/backend/controls/Panel.js index 12bee841db668cdef292e9c4e8cefa609891a250..7f2c306520fbda39addc3e0f13805eeece76c897 100644 --- a/bin/backend/controls/Panel.js +++ b/bin/backend/controls/Panel.js @@ -158,8 +158,6 @@ define('package/quiqqer/erp/bin/backend/controls/Panel', [ return; } - - console.log(typeOf(cls)); }); } }); diff --git a/bin/backend/controls/settings/OutputTemplates.css b/bin/backend/controls/settings/OutputTemplates.css new file mode 100644 index 0000000000000000000000000000000000000000..0569430fb4fbfab7b858cd6d12a31c5975c5403e --- /dev/null +++ b/bin/backend/controls/settings/OutputTemplates.css @@ -0,0 +1,17 @@ +.quiqqer-erp-settings-output-templates__hidden { + display: none !important; +} + +.quiqqer-erp-settings-output-templates-default-select { + width: 100%; +} + +.quiqqer-erp-settings-output-templates-hide-system-default { + display: block; + float: none !important; + width: 100% !important; +} + +.quiqqer-erp-settings-output-templates-hide-system-default > label { + float: none !important; +} \ No newline at end of file diff --git a/bin/backend/controls/settings/OutputTemplates.html b/bin/backend/controls/settings/OutputTemplates.html new file mode 100644 index 0000000000000000000000000000000000000000..b94f79046c9c104521f8eb8ea09aa529aafa6bb6 --- /dev/null +++ b/bin/backend/controls/settings/OutputTemplates.html @@ -0,0 +1,31 @@ +<table class="data-table data-table-flexbox"> + <tbody> + {{#templates}} + <tr> + <td> + <div class="field-container"> + <span class="field-container-item" title="{{entityTypeTitle}}"> + {{title}} + </span> + <div class="field-container-field"> + <select class="quiqqer-erp-settings-output-templates-default-select" data-entitytype="{{entityType}}"> + {{#outputTemplates}} + <option value="{{id}}--{{provider}}" + data-systemdefault="{{isSystemDefault}}" + data-provider="{{provider}}" + > + {{title}} + </option> + {{/outputTemplates}} + </select> + <label class="quiqqer-erp-settings-output-templates-hide-system-default quiqqer-erp-settings-output-templates__hidden"> + <input type="checkbox"/> + <label>{{labelHideSystemDefault}}</label> + </label> + </div> + </div> + </td> + </tr> + {{/templates}} + </tbody> +</table> \ No newline at end of file diff --git a/bin/backend/controls/settings/OutputTemplates.js b/bin/backend/controls/settings/OutputTemplates.js new file mode 100644 index 0000000000000000000000000000000000000000..613c0dc1224522d09c6bb2ee59de5249bf38805c --- /dev/null +++ b/bin/backend/controls/settings/OutputTemplates.js @@ -0,0 +1,202 @@ +/** + * Set default output templates for all output providers + * + * @module package/quiqqer/erp/bin/backend/controls/settings/OutputTemplates + * @author www.pcsg.de (Patrick Müller) + */ +define('package/quiqqer/erp/bin/backend/controls/settings/OutputTemplates', [ + + 'qui/QUI', + 'qui/controls/loader/Loader', + 'qui/controls/Control', + + 'Locale', + 'Mustache', + 'Ajax', + + 'text!package/quiqqer/erp/bin/backend/controls/settings/OutputTemplates.html', + 'css!package/quiqqer/erp/bin/backend/controls/settings/OutputTemplates.css' + +], function (QUI, QUILoader, QUIControl, QUILocale, Mustache, QUIAjax, template) { + "use strict"; + + var lg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIControl, + Type : 'package/quiqqer/erp/bin/backend/controls/settings/OutputTemplates', + + Binds: [ + '$onImport', + '$getTemplates', + '$onTemplateSelectChange', + '$setValue' + ], + + initialize: function (options) { + this.parent(options); + + this.Loader = new QUILoader(); + this.$Input = null; + this.$templateSelects = []; + + this.addEvents({ + onImport: this.$onImport + }); + }, + + /** + * @event: on import + */ + $onImport: function () { + var self = this; + + this.$Input = this.getElm(); + this.$Input.type = 'hidden'; + + var Content = new Element('div', { + 'class': 'quiqqer-erp-settings-output-templates' + }).inject(this.$Input, 'before'); + + this.Loader.inject(Content); + this.Loader.show(); + + this.$getTemplates().then(function (templates) { + self.Loader.hide(); + + var Templates = {}; + var entityType; + + // Parse templates by entity type + for (var i = 0, len = templates.length; i < len; i++) { + var Template = templates[i]; + + if (!(Template.entityType in Templates)) { + Templates[Template.entityType] = { + entityTypeTitle: Template.entityTypeTitle, + outputTemplates: [] + }; + } + + Template.isSystemDefault = Template.isSystemDefault ? 1 : 0; + Templates[Template.entityType].outputTemplates.push(Template); + } + + var renderTemplates = []; + + for (entityType in Templates) { + renderTemplates.push({ + title : Templates[entityType].entityTypeTitle, + entityType : entityType, + outputTemplates: Templates[entityType].outputTemplates + }); + } + + Content.set('html', Mustache.render(template, { + labelHideSystemDefault: QUILocale.get(lg, + 'controls.settings.OutputTemplates.tpl.labelHideSystemDefault' + ), + templates : renderTemplates + })); + + self.$templateSelects = Content.getElements('.quiqqer-erp-settings-output-templates-default-select'); + self.$templateSelects.addEvent('change', self.$onTemplateSelectChange); + + var defaultCheckboxes = Content.getElements('.quiqqer-erp-settings-output-templates-hide-system-default'); + defaultCheckboxes.addEvent('change', self.$setValue); + + // Set values from setting + if (self.$Input.value === '') { + return; + } + + var Setting = JSON.decode(self.$Input.value); + + for (entityType in Setting) { + if (!Setting.hasOwnProperty(entityType)) { + continue; + } + + var EntitySetting = Setting[entityType]; + var Select = Content.getElement('select[data-entitytype="' + entityType + '"]'); + + if (!Select) { + continue; + } + + Select.value = EntitySetting.id + '--' + EntitySetting.provider; + + var DefaultCheckbox = Select.getParent().getElement( + '.quiqqer-erp-settings-output-templates-hide-system-default input' + ); + + var Option = Select.getElement('option[value="' + Select.value + '"]'); + + if (!parseInt(Option.get('data-systemdefault'))) { + DefaultCheckbox.getParent().removeClass('quiqqer-erp-settings-output-templates__hidden'); + } + + DefaultCheckbox.checked = EntitySetting.hideSystemDefault; + } + }); + }, + + /** + * Handle change of selected template + * + * @param {DOMEvent} event + */ + $onTemplateSelectChange: function (event) { + var Select = event.target, + DefaultCheckbox = Select.getParent().getElement('.quiqqer-erp-settings-output-templates-hide-system-default'), + Selected = Select.getElement('option[value="' + Select.value + '"]'); + + if (!parseInt(Selected.get('data-systemdefault'))) { + DefaultCheckbox.removeClass('quiqqer-erp-settings-output-templates__hidden'); + } else { + DefaultCheckbox.addClass('quiqqer-erp-settings-output-templates__hidden'); + } + + this.$setValue(); + }, + + /** + * Set default templates setting value + */ + $setValue: function () { + var DefaultTemplates = {}; + + for (var i = 0, len = this.$templateSelects.length; i < len; i++) { + var Select = this.$templateSelects[i], + DefaultCheckbox = Select.getParent().getElement('.quiqqer-erp-settings-output-templates-hide-system-default input'), + value = Select.value.split('--'); + + DefaultTemplates[Select.get('data-entitytype')] = { + id : value[0], + provider : value[1], + hideSystemDefault: DefaultCheckbox.checked + }; + } + + this.$Input.value = JSON.encode(DefaultTemplates); + }, + + /** + * Fetch available templates for all entity types + * + * @return {Promise} + */ + $getTemplates: function () { + var self = this; + + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_output_getTemplates', resolve, { + 'package': 'quiqqer/erp', + //entityType: self.getAttribute('entityType'), + onError : reject + }) + }); + }, + }); +}); diff --git a/bin/output/backend/download.php b/bin/output/backend/download.php new file mode 100644 index 0000000000000000000000000000000000000000..40baf8406539dd08947ad3fb58467a8192e4dfc8 --- /dev/null +++ b/bin/output/backend/download.php @@ -0,0 +1,68 @@ +<?php + +/** + * This file contains the PDF download for an ERP Output document + * It opens the native download dialog + */ + +define('QUIQQER_SYSTEM', true); +define('QUIQQER_AJAX', true); + +require_once dirname(__FILE__, 6).'/header.php'; + +use QUI\ERP\Output\Output; +use QUI\Utils\Security\Orthos; + +$User = QUI::getUserBySession(); + +if (!$User->canUseBackend()) { + exit; +} + +$Request = QUI::getRequest(); +$entityId = Orthos::clear($Request->query->get('id')); +$entityType = Orthos::clear($Request->query->get('t')); +$template = Orthos::clear($Request->query->get('tpl')); +$templateProvider = Orthos::clear($Request->query->get('tplpr')); +$quiId = Orthos::clear($Request->query->get('oid')); + +$errorOutput = function ($message) use ($quiId) { + echo ' + <script> + var parent = window.parent; + + if (typeof parent.require !== "undefined") { + parent.require(["qui/QUI"], function(QUI) { + QUI.getMessageHandler().then(function(MH) { + MH.addError("'.$message.'"); + }); + + var Control = QUI.Controls.getById(\''.$quiId.'\'); + + if (Control) { + Control.Loader.hide(); + } + }); + } + </script>'; + exit; +}; + +try { + $HtmlPdfDocument = Output::getDocumentPdf( + $entityId, + $entityType, + null, + Output::getOutputTemplateProviderByPackage($templateProvider), + $template ?: null + ); + + $HtmlPdfDocument->download(); +} catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + + $message = $Exception->getMessage(); + $message = QUI\Utils\Security\Orthos::clear($message); + + $errorOutput($message); +} diff --git a/bin/output/backend/print.php b/bin/output/backend/print.php new file mode 100644 index 0000000000000000000000000000000000000000..9dd77eaf7b205b8389aea028046ab11ad1207053 --- /dev/null +++ b/bin/output/backend/print.php @@ -0,0 +1,83 @@ +<?php + +define('QUIQQER_SYSTEM', true); +define('QUIQQER_AJAX', true); + +require_once dirname(__FILE__, 6).'/header.php'; + +use QUI\ERP\Output\Output; +use QUI\Utils\Security\Orthos; + +$User = QUI::getUserBySession(); + +if (!$User->canUseBackend()) { + exit; +} + +$Request = QUI::getRequest(); +$entityId = Orthos::clear($Request->query->get('id')); +$entityType = Orthos::clear($Request->query->get('t')); +$template = Orthos::clear($Request->query->get('tpl')); +$templateProvider = Orthos::clear($Request->query->get('tplpr')); +$quiId = Orthos::clear($Request->query->get('oid')); + +$streamFile = URL_OPT_DIR.'quiqqer/erp/bin/output/backend/printStream.php?'; +$streamFile .= \http_build_query([ + 'id' => $entityId, + 't' => $entityType, + 'tpl' => $template, + 'tplpr' => $templateProvider, + 'oid' => $quiId +]); + +echo ' +<html> +<head> + <style> + body, html { + margin: 0 !important; + padding: 0 !important; + } + + @page { + margin: 0 !important; + } + + .container { + padding: 2.5em; + width: calc(100% - 5em); + } + </style> +</head> +<body> + <div class="container"> + <img + id="pdfDocument" + src="'.$streamFile.'" + style="max-width: 100%;" + + /> + </div> + <script> + var i, len, parts; + + var search = {}; + var sData = window.location.search.replace("?", "").split("&"); + + for (i = 0, len = sData.length; i <len; i++) { + parts = sData[i].split("="); + search[parts[0]] = parts[1]; + } + + var invoiceId = search["invoiceId"]; + var objectId = search["oid"]; + var parent = window.parent; + + window.onload = function() { + window.print(); + parent.QUI.Controls.getById(objectId).$onPrintFinish(invoiceId); + } + </script> +</body> +</html> +<!--<script>window.print()</script>-->'; diff --git a/bin/output/backend/printStream.php b/bin/output/backend/printStream.php new file mode 100644 index 0000000000000000000000000000000000000000..2360550adbbf8646f20232bea4137370fe48dbd9 --- /dev/null +++ b/bin/output/backend/printStream.php @@ -0,0 +1,51 @@ +<?php + +define('QUIQQER_SYSTEM', true); +define('QUIQQER_AJAX', true); + +require_once dirname(__FILE__, 6).'/header.php'; + +use QUI\ERP\Output\Output; +use QUI\Utils\Security\Orthos; + +$User = QUI::getUserBySession(); + +if (!$User->canUseBackend()) { + exit; +} + +$Request = QUI::getRequest(); +$entityId = Orthos::clear($Request->query->get('id')); +$entityType = Orthos::clear($Request->query->get('t')); +$template = Orthos::clear($Request->query->get('tpl')); +$templateProvider = Orthos::clear($Request->query->get('tplpr')); +$quiId = Orthos::clear($Request->query->get('oid')); + +try { + $HtmlPdfDocument = Output::getDocumentPdf( + $entityId, + $entityType, + null, + Output::getOutputTemplateProviderByPackage($templateProvider), + $template ?: null + ); + + $imageFile = $HtmlPdfDocument->createImage( + true, + [ + '-flatten' // removes background + ] + ); +} catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + exit; +} + +$Response = QUI::getGlobalResponse(); +$Response->headers->set('Content-Type', 'image/jpg'); +$Response->setContent(file_get_contents($imageFile)); +$Response->send(); + +if (\file_exists($imageFile)) { + \unlink($imageFile); +} diff --git a/bin/output/frontend/download.php b/bin/output/frontend/download.php new file mode 100644 index 0000000000000000000000000000000000000000..7f2d4c610393f10ddf94539ce4cad7db70111cee --- /dev/null +++ b/bin/output/frontend/download.php @@ -0,0 +1,38 @@ +<?php + +/** + * This file contains the PDF download for an ERP Output document (frontend) + * It opens the native download dialog + */ + +define('QUIQQER_SYSTEM', true); +define('QUIQQER_AJAX', true); + +require_once dirname(__FILE__, 6).'/header.php'; + +use QUI\ERP\Output\Output; +use QUI\Utils\Security\Orthos; + +$User = QUI::getUserBySession(); +$Request = QUI::getRequest(); +$entityId = Orthos::clear($Request->query->get('id')); +$entityType = Orthos::clear($Request->query->get('t')); + +try { + $OutputProvider = Output::getOutputProviderByEntityType($entityType); + + if (empty($OutputProvider)) { + exit; + } + + if (!$OutputProvider::hasDownloadPermission($entityId, $User)) { + exit; + } + + $HtmlPdfDocument = Output::getDocumentPdf($entityId, $entityType, $OutputProvider); + $HtmlPdfDocument->download(); +} catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); +} + +exit; diff --git a/composer.json b/composer.json index 7acc68116e6e1cba14f8879d72ecf65f20ff458d..4b5c3f2627b218607b941a626775551666753eb7 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "quiqqer\/qui-php": "1.*|>=0.11|dev-master|dev-dev", "quiqqer\/smarty3": ">=1.7|dev-master|dev-dev", "quiqqer\/countries": ">=1.3|dev-master|dev-dev", - "quiqqer\/frontend-users": "1.*|dev-master|dev-dev" + "quiqqer\/frontend-users": "1.*|dev-master|dev-dev", + "quiqqer\/erp-accounting-templates": "^1|dev-master|dev-dev" }, "autoload": { "psr-4": { diff --git a/locale.xml b/locale.xml index 1f42692e8d359bdf06c4914a6b23f4f4cbcd4776..88807e8e991cc08b362b21b2be34b03a4a83df43 100644 --- a/locale.xml +++ b/locale.xml @@ -108,9 +108,20 @@ <de><![CDATA[Vorgangsnummer]]></de> <en><![CDATA[Processing-ID]]></en> </locale> + <locale name="output.default_template.suffix"> + <de><![CDATA[(System-Standard)]]></de> + <en><![CDATA[(System default)]]></en> + </locale> + </groups> <groups name="quiqqer/erp" datatype="php"> + + <locale name="exception.ajax.output.sendMail.error"> + <de><![CDATA[Leider ist beim E-Mail-Verand ein unerwarteter Fehler aufgetreten. Bitte wiederholen Sie den Vorgang, prüfen Sie die Fehler-Logs oder kontaktieren Sie einen Administator.]]></de> + <en><![CDATA[Unfortunately, an unexpected error has occurred when sending the e-mail. Please repeat the process, check the error logs or contact an administrator.]]></en> + </locale> + <locale name="user.settings.title"> <de><![CDATA[Rechnungsdaten]]></de> <en><![CDATA[Billing Details]]></en> @@ -155,6 +166,15 @@ <en><![CDATA[Privacy Policy]]></en> </locale> + <locale name="menu.erp.output.title"> + <de><![CDATA[Beleg-Ausgabe / PDF]]></de> + <en><![CDATA[Document output / PDF]]></en> + </locale> + <locale name="menu.erp.output.default_templates"> + <de><![CDATA[Vorausgewählte Templates]]></de> + <en><![CDATA[Preselected templates]]></en> + </locale> + <locale name="shop.settings.general.precision"> <de><![CDATA[Verwendete Nachkommastellen]]></de> <en><![CDATA[Used decimal digits]]></en> @@ -304,6 +324,16 @@ We're sorry, but something went wrong. Please contact an administrator. ]]></en> </locale> + + <locale name="Output.send.success"> + <de><![CDATA[E-Mail erfolgreich versandt.]]></de> + <en><![CDATA[E-Mail sent successfully.]]></en> + </locale> + <locale name="exception.Output.sendPdfViaMail.missing_recipient"> + <de><![CDATA[Das Dokument kann nicht per E-Mail versendet werden, da keine gültige Empfänger E-Mail-Adresse angegeben wurde.]]></de> + <en><![CDATA[The document cannot be sent by e-mail because no valid recipient e-mail address has been specified.]]></en> + </locale> + </groups> <groups name="quiqqer/erp" datatype="js"> @@ -331,6 +361,95 @@ <de><![CDATA[Artikelübersichtsrechnung]]></de> <en><![CDATA[Article overview calculation]]></en> </locale> + + <!-- Controls --> + <locale name="controls.OutputDialog.labelEntityId"> + <de><![CDATA[Beleg-Nr.]]></de> + <en><![CDATA[Document no.]]></en> + </locale> + <locale name="controls.OutputDialog.labelTemplate"> + <de><![CDATA[Vorlage (Template)]]></de> + <en><![CDATA[Template]]></en> + </locale> + <locale name="controls.OutputDialog.labelOutputType"> + <de><![CDATA[Ausgabe]]></de> + <en><![CDATA[Output]]></en> + </locale> + <locale name="controls.OutputDialog.labelMarkAsSent"> + <de><![CDATA[Als versandt markieren]]></de> + <en><![CDATA[Mark as sent]]></en> + </locale> + <locale name="controls.OutputDialog.labelOpenMailEditor"> + <de><![CDATA[E-Mail bearbeiten]]></de> + <en><![CDATA[Edit e-mail]]></en> + </locale> + <locale name="controls.OutputDialog.data.output.print"> + <de><![CDATA[Drucken]]></de> + <en><![CDATA[Print]]></en> + </locale> + <locale name="controls.OutputDialog.data.output.pdf"> + <de><![CDATA[Als PDF speichern]]></de> + <en><![CDATA[Save as PDF]]></en> + </locale> + <locale name="controls.OutputDialog.data.output.email"> + <de><![CDATA[Per E-Mail versenden]]></de> + <en><![CDATA[Send via e-mail]]></en> + </locale> + <locale name="controls.OutputDialog.data.output.print.btn"> + <de><![CDATA[Drucken]]></de> + <en><![CDATA[Print]]></en> + </locale> + <locale name="controls.OutputDialog.data.output.pdf.btn"> + <de><![CDATA[Herunterladen]]></de> + <en><![CDATA[Download]]></en> + </locale> + <locale name="controls.OutputDialog.data.output.email.btn"> + <de><![CDATA[Senden]]></de> + <en><![CDATA[Send]]></en> + </locale> + <locale name="controls.OutputDialog.title"> + <de><![CDATA[Beleg Druck / PDF / Versand]]></de> + <en><![CDATA[Document print / PDF / send]]></en> + </locale> + <locale name="controls.OutputDialog.no_templates_found"> + <de><![CDATA[Keine Vorlagen gefunden]]></de> + <en><![CDATA[No templates found]]></en> + </locale> + <locale name="controls.OutputDialog.no_preview"> + <de><![CDATA[Das Dokument ist aktuell nicht verfügbar, da keine Vorlage ausgewählt oder gefunden wurde.]]></de> + <en><![CDATA[The document is currently not available because no template was selected or found.]]></en> + </locale> + <locale name="controls.OutputDialog.preview_error"> + <de><![CDATA[Die Vorschau konnte leider nicht geladen werden. Bitte prüfen Sie die Fehler-Logs oder kontaktieren Sie einen Administrator.]]></de> + <en><![CDATA[The preview could not loaded. Please check the error logs or contact an administrator.]]></en> + </locale> + <locale name="controls.OutputDialog.descMarkAsSent"> + <de><![CDATA[Markiert den Beleg als versandt, sofern noch kein Versanddatum gesetzt ist.]]></de> + <en><![CDATA[Marks the document as sent, provided that no shipping date has been set.]]></en> + </locale> + + <locale name="controls.OutputMailEditor.title"> + <de><![CDATA[E-Mail für Beleg bearbeiten]]></de> + <en><![CDATA[Edit document e-mail]]></en> + </locale> + <locale name="controls.OutputMailEditor.labelMailSubject"> + <de><![CDATA[Betreff]]></de> + <en><![CDATA[Subject]]></en> + </locale> + <locale name="controls.OutputMailEditor.labelMailContent"> + <de><![CDATA[Inhalt (ohne Kopf- und Fußzeile)]]></de> + <en><![CDATA[Content (without header and footer)]]></en> + </locale> + <locale name="controls.OutputMailEditor.info" html="true"> + <de><![CDATA[<b>Hinweis:</b> Der Beleg wird als PDF-Datei im Anhang der E-Mail mitgesendet.]]></de> + <en><![CDATA[<b>Hint:</b> The document is sent as a PDF file attached to the e-mail.]]></en> + </locale> + + <locale name="controls.settings.OutputTemplates.tpl.labelHideSystemDefault"> + <de><![CDATA[System-Standard Template im Ausgabe-Dialog nicht zur Auswahl anbieten]]></de> + <en><![CDATA[Do not offer System Standard Template for selection in output dialog]]></en> + </locale> + </groups> </locales> diff --git a/settings.xml b/settings.xml index e39fce4e8cfd50caf2375ac87600120f51db4b5d..4be8a4ffa37eb305b837103cb25cee4d1feab988 100644 --- a/settings.xml +++ b/settings.xml @@ -29,6 +29,12 @@ </conf> </section> + <section name="output"> + <conf name="default_templates"> + <type><![CDATA[string]]></type> + </conf> + </section> + <section name="paymentsChangeable"/> <section name="timestampFormat"/> <section name="dateFormat"/> @@ -153,6 +159,20 @@ </text> </input> </settings> + + <settings> + <title> + <locale group="quiqqer/erp" var="menu.erp.output.title"/> + </title> + + <input conf="output.default_templates" + data-qui="package/quiqqer/erp/bin/backend/controls/settings/OutputTemplates"> + <text> + <locale group="quiqqer/erp" var="menu.erp.output.default_templates"/> + </text> + </input> + + </settings> </category> <category name="currencies" index="1"> diff --git a/src/QUI/ERP/Output/Output.php b/src/QUI/ERP/Output/Output.php new file mode 100644 index 0000000000000000000000000000000000000000..e63a8bbbfbdb3cc94582a77da6955d97aa1f259e --- /dev/null +++ b/src/QUI/ERP/Output/Output.php @@ -0,0 +1,477 @@ +<?php + +namespace QUI\ERP\Output; + +use QUI; +use QUI\ERP\Accounting\Invoice\Settings; +use QUI\ERP\Accounting\Invoice\Utils\Invoice as InvoiceUtils; + +/** + * Class Output + * + * Main handler for serving previews, PDFs and downloads for QUIQQER ERP documents + */ +class Output +{ + /** + * 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']; + } + } + + return false; + } + + /** + * 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; + } + } + + return false; + } + + /** + * Get HTML output for a specific document + * + * @param string|int $entityId + * @param string $entityType + * @param OutputProviderInterface $OutputProvider (optional) + * @param OutputTemplateProviderInterface $TemplateProvider (optional) + * @param string $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, + string $template = null, + bool $preview = false + ) { + if (empty($OutputProvider)) { + $OutputProvider = self::getOutputProviderByEntityType($entityType); + } + + if (empty($OutputProvider)) { + throw new QUI\Exception('No output provider found for entity type "'.$entityType.'"'); + } + + if (empty($TemplateProvider)) { + $TemplateProvider = self::getDefaultOutputTemplateProviderForEntityType($entityType); + } + + if (empty($TemplateProvider)) { + 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 $template (optional) + * + * @return QUI\HtmlToPdf\Document + * + * @throws QUI\Exception + */ + public static function getDocumentPdf( + $entityId, + string $entityType, + $OutputProvider = null, + $TemplateProvider = null, + string $template = null + ) { + 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 + ) { + $url = URL_OPT_DIR.'quiqqer/erp/bin/output/frontend/download.php?'; + $url .= \http_build_query([ + 'id' => $entityId, + 't' => $entityType + ]); + + return $url; + } + + /** + * 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 $template (optional) + * @param string $recipientEmail (optional) + * @param string $mailSubject (optional) + * @param string $mailContent (optional) + * + * @return void + * + * @throws QUI\Exception + */ + public static function sendPdfViaMail( + $entityId, + string $entityType, + $OutputProvider = null, + $TemplateProvider = null, + string $template = null, + string $recipientEmail = null, + string $mailSubject = null, + string $mailContent = null + ) { + 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(); + + if (empty($recipientEmail) || !QUI\Utils\Security\Orthos::checkMailSyntax($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($pdfFile); + + if (!empty($mailSubject)) { + $Mailer->setSubject($mailSubject); + } else { + $Mailer->setSubject($OutputProvider::getMailSubject($entityId)); + } + + if (!empty($mailContent)) { + $Mailer->setBody($mailContent); + } else { + $Mailer->setBody($OutputProvider::getMailBody($entityId)); + } + + $Mailer->send(); + + QUI::getEvents()->fireEvent('quiqqerErpOutputSendMail', [$entityId, $entityType, $recipientEmail]); + + // Delete PDF file after send + if (\file_exists($pdfFile)) { + \unlink($pdfFile); + } + } + + /** + * Get available templates for $entityType (e.g. "Invoice", "InvoiceTemporary" etc.) + * + * @param string $package + * @return OutputTemplateProviderInterface|false - OutputProvider class (static) or false if + * @throws QUI\Exception + */ + 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 $entityType (optional) - Restrict to templates of $entityType [default: fetch templates for all entity types] + * @return array + */ + public static function getTemplates(string $entityType = null) + { + $templates = []; + $outputProviders = []; + + if (empty($entityType)) { + $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']) { + $templateTitle .= ' '.QUI::getLocale()->get('quiqqer/erp', 'output.default_template.suffix'); + } + + $isDefault = $defaultOutputTemplate['provider'] === $provider['package'] && + $defaultOutputTemplate['id'] === $providerTemplateId; + + $providerTemplate = [ + '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 + \usort($templates, function ($a, $b) { + if ($a['isSystemDefault']) { + return -1; + } + + if ($b['isSystemDefault']) { + return 1; + } + + return 0; + }); + + return $templates; + } + + /** + * Return default template id for a specific entity type + * + * @param string $entityType + * @return array - Containting template ID and template provider package + */ + public static function getDefaultOutputTemplateForEntityType(string $entityType) + { + $fallBackTemplate = [ + 'id' => 'system_default', + 'provider' => 'quiqqer/invoice-accounting-template', + 'hideSystemDefault' => false + ]; + + try { + $Conf = QUI::getPackage('quiqqer/erp')->getConfig(); + $defaultTemplates = $Conf->get('output', 'default_templates'); + + if (empty($defaultTemplates)) { + return $fallBackTemplate; + } + + $defaultTemplates = \json_decode($defaultTemplates, true); + + if (empty($defaultTemplates[$entityType])) { + return $fallBackTemplate; + } + + return $defaultTemplates[$entityType]; + } catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + return $fallBackTemplate; + } + } + + /** + * Return default Output Template provider class for a specific entity type + * + * @param string $entityType + * @return OutputTemplateProviderInterface|false + */ + public static function getDefaultOutputTemplateProviderForEntityType(string $entityType) + { + foreach (self::getAllOutputTemplateProviders() as $provider) { + /** @var OutputTemplateProviderInterface $class */ + $class = $provider['class']; + $providerTemplates = $class::getTemplates($entityType); + + if (!empty($providerTemplates)) { + return $class; + } + } + + return false; + } + + /** + * Get all available ERP Output provider classes + * + * @return array - Provider classes + */ + protected static function getAllOutputProviders() + { + $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 */ + foreach ($packageProvider['erpOutput'] as $class) { + if (!\class_exists($class)) { + continue; + } + + $providerClasses[] = [ + 'class' => $class, + '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() + { + $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 */ + foreach ($packageProvider['erpOutputTemplate'] as $class) { + if (!\class_exists($class)) { + continue; + } + + $providerClasses[] = [ + 'class' => $class, + 'package' => $installedPackage['name'], + 'isSystemDefault' => $installedPackage['name'] === 'quiqqer/invoice-accounting-template' + ]; + } + } catch (QUI\Exception $Exception) { + QUI\System\Log::writeException($Exception); + } + } + + return $providerClasses; + } +} diff --git a/src/QUI/ERP/Output/OutputProviderInterface.php b/src/QUI/ERP/Output/OutputProviderInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..5816fe82d8e4b769fe9789f741ebefcc86e2f740 --- /dev/null +++ b/src/QUI/ERP/Output/OutputProviderInterface.php @@ -0,0 +1,98 @@ +<?php + +namespace QUI\ERP\Output; + +use QUI\HtmlToPdf\Document; +use QUI\Interfaces\Users\User; +use QUI\Locale; + +/** + * Interface OutputProviderInterface + * + * Main interface for all ERP Output providers + */ +interface OutputProviderInterface +{ + /** + * Get output type + * + * The output type determines the type of templates/providers that are used + * to output documents. + * + * @return string + */ + public static function getEntityType(); + + /** + * Get title for the output entity + * + * @param Locale $Locale (optional) - If ommitted use \QUI::getLocale() + * @return mixed + */ + public static function getEntityTypeTitle(Locale $Locale = null); + + /** + * Get the entity the output is created for + * + * @param string|int $entityId + * @return mixed + */ + public static function getEntity($entityId); + + /** + * Get download filename (without file extension) + * + * @param string|int $entityId + * @return string + */ + public static function getDownloadFileName($entityId); + + /** + * Get output Locale by entity + * + * @param string|int $entityId + * @return Locale + */ + public static function getLocale($entityId); + + /** + * Fill the OutputTemplate with appropriate entity data + * + * @param string|int $entityId + * @return array + */ + public static function getTemplateData($entityId); + + /** + * Checks if $User has permission to download the document of $entityId + * + * @param string|int $entityId + * @param User $User + * @return bool + */ + public static function hasDownloadPermission($entityId, User $User); + + /** + * Get e-mail address of the document recipient + * + * @param string|int $entityId + * @return string|false - E-Mail address or false if no e-mail address available + */ + public static function getEmailAddress($entityId); + + /** + * Get e-mail subject when document is sent via mail + * + * @param string|int $entityId + * @return string + */ + public static function getMailSubject($entityId); + + /** + * Get e-mail body when document is sent via mail + * + * @param string|int $entityId + * @return string + */ + public static function getMailBody($entityId); +} diff --git a/src/QUI/ERP/Output/OutputTemplate.php b/src/QUI/ERP/Output/OutputTemplate.php new file mode 100644 index 0000000000000000000000000000000000000000..9e2d441f71c67ffe7059bd53dbabcdaf1666b631 --- /dev/null +++ b/src/QUI/ERP/Output/OutputTemplate.php @@ -0,0 +1,239 @@ +<?php + +namespace QUI\ERP\Output; + +use QUI; +use QUI\Package\Package; + +use QUI\ERP\Accounting\Invoice\Exception; +use QUI\ERP\Accounting\Invoice\Handler; +use QUI\ERP\Accounting\Invoice\Invoice; +use QUI\ERP\Accounting\Invoice\InvoiceTemporary; + +/** + * Class OutputTemplate + */ +class OutputTemplate +{ + /** + * @var OutputTemplateProviderInterface + */ + protected $TemplateProvider; + + /** + * @var OutputProviderInterface + */ + protected $OutputProvider; + + /** + * @var string + */ + protected $template; + + /** + * @var QUI\Interfaces\Template\EngineInterface + */ + protected $Engine; + + /** + * @var string + */ + protected $entityType; + + /** + * @var string|int + */ + protected $entityId; + + /** + * The entity the output is created for + * + * @var mixed + */ + protected $Entity; + + /** + * @var bool + */ + protected $preview = false; + + /** + * Template constructor. + * + * @param OutputTemplateProviderInterface $TemplateProvider - Template provider class + * @param OutputProviderInterface $OutputProvider - Output provider class + * @param string|int $entityId + * @param string $entityType + * @param string $template (optional) - Template identifier (from template provider) + * + * @throws QUI\Exception + */ + public function __construct( + $TemplateProvider, + $OutputProvider, + $entityId, + string $entityType, + string $template = null + ) { + $this->Engine = QUI::getTemplateManager()->getEngine(); + $this->TemplateProvider = $TemplateProvider; + $this->OutputProvider = $OutputProvider; + + $templates = $this->TemplateProvider::getTemplates($entityType); + + if (empty($template)) { + $template = $templates[0]; + } else { + // Check if $template is provided by template provider + $templateIsProvided = false; + + foreach ($templates as $providerTemplateId) { + if ($providerTemplateId === $template) { + $templateIsProvided = true; + break; + } + } + + if (!$templateIsProvided) { + $template = $templates[0]; + } + } + + $this->template = $template; + $this->entityType = $entityType; + $this->entityId = $entityId; + $this->Entity = $this->OutputProvider::getEntity($entityId); + } + + /** + * Render the html + * + * @param bool $preview (optional) - + * @return string - HTML content + */ + public function getHTML($preview = false) + { + $templateData = $this->OutputProvider::getTemplateData($this->entityId); + $this->Engine->assign($templateData); + $this->preview = $preview; + + return $this->getHTMLHeader(). + $this->getHTMLBody(). + $this->getHTMLFooter(); + } + + /** + * Get PDF output + * + * @return QUI\HtmlToPdf\Document + * @throws QUI\Exception + * @throws QUI\ExceptionStack + */ + public function getPDFDocument() + { + $Locale = $this->OutputProvider::getLocale($this->entityId); + + $Document = new QUI\HtmlToPdf\Document([ + 'marginTop' => 30, // dies ist variabel durch quiqqerInvoicePdfCreate + 'filename' => $this->OutputProvider::getDownloadFileName($this->entityId).'.pdf', + 'marginBottom' => 80, // dies ist variabel durch quiqqerInvoicePdfCreate, + 'pageNumbersPrefix' => $Locale->get('quiqqer/htmltopdf', 'footer.page.prefix') + ]); + + QUI::getEvents()->fireEvent( + 'quiqqerErpOutputPdfCreate', + [$this, $Document] + ); + + try { + $templateData = $this->OutputProvider::getTemplateData($this->entityId); + $this->Engine->assign($templateData); + + $Document->setHeaderHTML($this->getHTMLHeader()); + $Document->setContentHTML($this->getHTMLBody()); + $Document->setFooterHTML($this->getHTMLFooter()); + } catch (QUI\Exception $Exception) { + QUI\System\Log::writeException($Exception); + } + + return $Document; + } + + /** + * @return QUI\Interfaces\Template\EngineInterface + */ + public function getEngine() + { + return $this->Engine; + } + + //region Template Output Helper + + /** + * Return the html header + * + * @return string + */ + public function getHTMLHeader() + { + return $this->TemplateProvider::getHeaderHtml($this->template, $this->entityType, $this->Engine, $this->Entity); + } + + /** + * Return the html body + * + * @return string + */ + public function getHTMLBody() + { + $Output = new QUI\Output(); + $Output->setSetting('use-system-image-paths', true); + + return $Output->parse( + $this->TemplateProvider::getBodyHtml( + $this->template, + $this->entityType, + $this->Engine, + $this->Entity + ) + ); + } + + /** + * Return the html body + * + * @return string + */ + public function getHTMLFooter() + { + $footerHtml = '<div class="quiqqer-erp-output-footer">'; + + $footerHtml .= $this->TemplateProvider::getFooterHtml( + $this->template, + $this->entityType, + $this->Engine, + $this->Entity + ); + + $footerHtml .= '</div>'; + + $css = ''; + + if ($this->preview) { + $css = '<style>'; + $css .= ' + .quiqqer-erp-output-footer { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + } + '; + $css .= '</style>'; + } + + return $css.$footerHtml; + } + + //endregion +} diff --git a/src/QUI/ERP/Output/OutputTemplateProviderInterface.php b/src/QUI/ERP/Output/OutputTemplateProviderInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..6a7c7d829a9caf7c246306be5ca8d2d0f08ad26e --- /dev/null +++ b/src/QUI/ERP/Output/OutputTemplateProviderInterface.php @@ -0,0 +1,72 @@ +<?php + +namespace QUI\ERP\Output; + +use QUI\HtmlToPdf\Document; +use QUI\Interfaces\Template\EngineInterface; +use QUI\Locale; + +/** + * Interface OutputTemplateProviderInterface + * + * Main interface for all ERP Output template providers + */ +interface OutputTemplateProviderInterface +{ + /** + * Get all entity types the template package provides templates for + * + * @return string[] + */ + public static function getEntityTypes(); + + /** + * Get all available templates for $entityType + * + * @param string $entityType + * @return string[]|int[] - Collection of templateIds + */ + public static function getTemplates(string $entityType); + + /** + * Get title of Template + * + * @param string|int $templateId + * @param Locale $Locale (optional) - If omitted use \QUI::getLocale() + * @return string + */ + public static function getTemplateTitle($templateId, Locale $Locale = null); + + /** + * Get HTML for document header area + * + * @param string|int $templateId + * @param string $entityType + * @param EngineInterface $Engine + * @param mixed $Entity - The entity the output is created for + * @return string|false + */ + public static function getHeaderHtml($templateId, string $entityType, EngineInterface $Engine, $Entity); + + /** + * Get HTML for document body area + * + * @param string|int $templateId + * @param string $entityType + * @param EngineInterface $Engine + * @param mixed $Entity - The entity the output is created for + * @return string|false + */ + public static function getBodyHtml($templateId, string $entityType, EngineInterface $Engine, $Entity); + + /** + * Get HTML for document footer area + * + * @param string|int $templateId + * @param string $entityType + * @param EngineInterface $Engine + * @param mixed $Entity - The entity the output is created for + * @return string|false + */ + public static function getFooterHtml($templateId, string $entityType, EngineInterface $Engine, $Entity); +}