From a54c8b9b76ab5ec52ed7bacf616d742f187d15e1 Mon Sep 17 00:00:00 2001 From: Henning Leutz <leutz@pcsg.de> Date: Tue, 28 Feb 2017 08:09:26 +0100 Subject: [PATCH] refactor: development --- ajax/invoices/temporary/product/calc.php | 6 + ajax/invoices/temporary/save.php | 7 + bin/backend/controls/InvoiceItems.css | 9 +- bin/backend/controls/InvoiceItems.html | 3 + bin/backend/controls/InvoiceItems.js | 102 +++++++-- bin/backend/controls/InvoiceItemsProduct.css | 78 ------- bin/backend/controls/InvoiceItemsProduct.html | 7 - bin/backend/controls/articles/Article.css | 84 +++++++ bin/backend/controls/articles/Article.html | 8 + .../Article.js} | 211 +++++++++++------- bin/backend/controls/articles/Text.css | 59 +++++ bin/backend/controls/articles/Text.html | 2 + bin/backend/controls/articles/Text.js | 172 ++++++++++++++ .../panels/TemporaryInvoice.Data.html | 18 +- .../controls/panels/TemporaryInvoice.js | 120 +++++++--- database.xml | 4 +- locale.xml | 48 ++++ .../Accounting/Invoice/Articles/Article.php | 133 +++++++++++ .../Invoice/Articles/ArticleInterface.php | 57 +++++ .../ERP/Accounting/Invoice/Articles/Text.php | 121 ++++++++++ .../Accounting/Invoice/TemporaryInvoice.php | 123 +++++++++- 21 files changed, 1145 insertions(+), 227 deletions(-) delete mode 100644 bin/backend/controls/InvoiceItemsProduct.css delete mode 100644 bin/backend/controls/InvoiceItemsProduct.html create mode 100644 bin/backend/controls/articles/Article.css create mode 100644 bin/backend/controls/articles/Article.html rename bin/backend/controls/{InvoiceItemsProduct.js => articles/Article.js} (64%) create mode 100644 bin/backend/controls/articles/Text.css create mode 100644 bin/backend/controls/articles/Text.html create mode 100644 bin/backend/controls/articles/Text.js create mode 100644 src/QUI/ERP/Accounting/Invoice/Articles/Article.php create mode 100644 src/QUI/ERP/Accounting/Invoice/Articles/ArticleInterface.php create mode 100644 src/QUI/ERP/Accounting/Invoice/Articles/Text.php diff --git a/ajax/invoices/temporary/product/calc.php b/ajax/invoices/temporary/product/calc.php index a83787f..d388f82 100644 --- a/ajax/invoices/temporary/product/calc.php +++ b/ajax/invoices/temporary/product/calc.php @@ -19,6 +19,12 @@ function ($params) { throw new QUI\Exception('Not found'); } + if (empty($params['type'])) { + $Article = new QUI\ERP\Accounting\Invoice\Articles\Article($params); + + return $Article->toArray(); + } + \QUI\System\Log::writeRecursive($params); if ($params['type'] == QUI\ERP\Products\Product\Product::class) { diff --git a/ajax/invoices/temporary/save.php b/ajax/invoices/temporary/save.php index 83034d2..014362f 100644 --- a/ajax/invoices/temporary/save.php +++ b/ajax/invoices/temporary/save.php @@ -17,6 +17,13 @@ function ($invoiceId, $data) { $Invoice = $Invoices->getTemporaryInvoice($invoiceId); $data = json_decode($data, true); + $Invoice->clearArticles(); + + if (isset($data['articles'])) { + $Invoice->importArticles($data['articles']); + unset($data['articles']); + } + $Invoice->setAttributes($data); $Invoice->save(); diff --git a/bin/backend/controls/InvoiceItems.css b/bin/backend/controls/InvoiceItems.css index 78e9a97..617cc3e 100644 --- a/bin/backend/controls/InvoiceItems.css +++ b/bin/backend/controls/InvoiceItems.css @@ -1,6 +1,7 @@ .quiqqer-invoice-backend-invoiceItems { display: block; min-height: 300px; + min-width: 1000px; position: relative; width: 100%; } @@ -22,13 +23,15 @@ } .quiqqer-invoice-backend-invoiceItems-header-description { - width: calc(100% - 600px); + width: calc(100% - 700px); } .quiqqer-invoice-backend-invoiceItems-header-quantity { + text-align: right; width: 100px; } +.quiqqer-invoice-backend-invoiceItems-header-articleNo, .quiqqer-invoice-backend-invoiceItems-header-unitPrice, .quiqqer-invoice-backend-invoiceItems-header-price, .quiqqer-invoice-backend-invoiceItems-header-vat, @@ -40,6 +43,10 @@ white-space: nowrap; } +.quiqqer-invoice-backend-invoiceItems-header-articleNo { + text-align: left; +} + .quiqqer-invoice-backend-invoiceItems-header-total { width: 150px; } diff --git a/bin/backend/controls/InvoiceItems.html b/bin/backend/controls/InvoiceItems.html index 372a250..e294021 100644 --- a/bin/backend/controls/InvoiceItems.html +++ b/bin/backend/controls/InvoiceItems.html @@ -2,6 +2,9 @@ <div class="quiqqer-invoice-backend-invoiceItems-header-pos header-cell"> # </div> + <div class="quiqqer-invoice-backend-invoiceItems-header-articleNo header-cell"> + {{titleArticleNo}} + </div> <div class="quiqqer-invoice-backend-invoiceItems-header-description header-cell"> {{titleDescription}} </div> diff --git a/bin/backend/controls/InvoiceItems.js b/bin/backend/controls/InvoiceItems.js index 78eb304..ae5351a 100644 --- a/bin/backend/controls/InvoiceItems.js +++ b/bin/backend/controls/InvoiceItems.js @@ -17,12 +17,12 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItems', [ 'qui/controls/Control', 'Mustache', 'Locale', - 'package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', + 'package/quiqqer/invoice/bin/backend/controls/articles/Article', 'text!package/quiqqer/invoice/bin/backend/controls/InvoiceItems.html', 'css!package/quiqqer/invoice/bin/backend/controls/InvoiceItems.css' -], function (QUI, QUIControl, Mustache, QUILocale, InvoiceItemsProduct, template) { +], function (QUI, QUIControl, Mustache, QUILocale, Article, template) { "use strict"; var lg = 'quiqqer/invoice'; @@ -30,14 +30,14 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItems', [ return new Class({ Extends: QUIControl, - Type: 'package/quiqqer/invoice/bin/backend/controls/InvoiceItems', + Type : 'package/quiqqer/invoice/bin/backend/controls/InvoiceItems', options: {}, initialize: function (options) { this.parent(options); - this.$products = []; + this.$articles = []; this.$Container = null; }, @@ -54,12 +54,13 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItems', [ this.$Elm.set({ html: Mustache.render(template, { + titleArticleNo : QUILocale.get(lg, 'invoice.products.articleNo'), titleDescription: QUILocale.get(lg, 'invoice.products.description'), - titleQuantity: QUILocale.get(lg, 'invoice.products.quantity'), - titleUnitPrice: QUILocale.get(lg, 'invoice.products.unitPrice'), - titlePrice: QUILocale.get(lg, 'invoice.products.price'), - titleVAT: QUILocale.get(lg, 'invoice.products.vat'), - titleSum: QUILocale.get(lg, 'invoice.products.sum') + titleQuantity : QUILocale.get(lg, 'invoice.products.quantity'), + titleUnitPrice : QUILocale.get(lg, 'invoice.products.unitPrice'), + titlePrice : QUILocale.get(lg, 'invoice.products.price'), + titleVAT : QUILocale.get(lg, 'invoice.products.vat'), + titleSum : QUILocale.get(lg, 'invoice.products.sum') }) }); @@ -68,24 +69,81 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItems', [ return this.$Elm; }, + /** + * Serialize the list + * + * @returns {Object} + */ + serialize: function () { + var articles = this.$articles.map(function (Article) { + var attr = Article.getAttributes(); + attr.control = typeOf(Article); + + return attr; + }); + + return { + articles: articles + }; + }, + + /** + * + */ + unserialize: function (list) { + var data = {}; + + if (typeOf(list) == 'string') { + try { + data = JSON.stringify(list); + } catch (e) { + } + } else { + data = list; + } + + if (!("articles" in data)) { + return; + } + + var needles = data.articles.map(function (entry) { + return entry.control; + }); + + require(needles, function () { + var i, no, len, article, control; + + for (i = 0, len = data.articles.length; i < len; i++) { + article = data.articles[i]; + control = article.control; + + no = needles.indexOf(control); + + this.addArticle( + new arguments[no](article) + ); + } + }.bind(this)); + }, + /** * Add a product to the list * The product must be an instance of InvoiceItemsProduc * * @param {Object} Product */ - addProduct: function (Product) { + addArticle: function (Product) { if (typeof Product !== 'object') { return; } - if (!(Product instanceof InvoiceItemsProduct)) { + if (!(Product instanceof Article)) { return; } - this.$products.push(Product); + this.$articles.push(Product); - Product.setPosition(this.$products.length); + Product.setPosition(this.$articles.length); Product.inject(this.$Container); }, @@ -93,7 +151,23 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItems', [ * Insert a new empty product */ insertNewProduct: function () { - this.addProduct(new InvoiceItemsProduct()); + this.addArticle(new Article()); + }, + + /** + * Return the articles as an array + * + * @return {Array} + */ + save: function () { + console.log('###'); + + return this.$articles.map(function (Article) { + console.log(typeOf(Article)); + console.log(Article.getAttributes()); + + return Article.getAttributes(); + }); } }); }); \ No newline at end of file diff --git a/bin/backend/controls/InvoiceItemsProduct.css b/bin/backend/controls/InvoiceItemsProduct.css deleted file mode 100644 index 2ce8db8..0000000 --- a/bin/backend/controls/InvoiceItemsProduct.css +++ /dev/null @@ -1,78 +0,0 @@ -.quiqqer-invoice-backend-invoiceItemsProduct { - align-items: stretch; - border-bottom: 1px solid #DEDEDE; - clear: both; - display: flex; - flex-direction: row; - float: left; - min-height: 50px; - position: relative; - width: 100%; -} - -.quiqqer-invoice-backend-invoiceItemsProduct .cell { - padding: 10px; - position: relative; -} - -.quiqqer-invoice-backend-invoiceItemsProduct .cell-editable:hover { - background: rgba(0, 0, 0, 0.1); - cursor: pointer; -} - -.quiqqer-invoice-backend-invoiceItemsProduct-pos { - width: 50px; -} - -.quiqqer-invoice-backend-invoiceItemsProduct-text { - width: calc(100% - 550px); -} - -.quiqqer-invoice-backend-invoiceItemsProduct-text-title { - clear: both; - font-weight: bold; - margin-bottom: 5px; - position: relative; - width: 100%; -} - -.quiqqer-invoice-backend-invoiceItemsProduct-text-description { - clear: both; - position: relative; - width: 100%; -} - -.quiqqer-invoice-backend-invoiceItemsProduct-text-description-edit { - background: #EFEFEF; - border: 1px solid #EFEFEF; - height: 100%; - left: 0; - overflow: hidden; - position: absolute; - top: 0; - width: 100% -} - -.quiqqer-invoice-backend-invoiceItemsProduct-text-description-buttons { - height: 50px; - text-align: center; -} - -.quiqqer-invoice-backend-invoiceItemsProduct-quantity { - width: 100px; -} - -.quiqqer-invoice-backend-invoiceItemsProduct-unitPrice, -.quiqqer-invoice-backend-invoiceItemsProduct-price, -.quiqqer-invoice-backend-invoiceItemsProduct-vat, -.quiqqer-invoice-backend-invoiceItemsProduct-total { - overflow: hidden; - text-align: right; - text-overflow: ellipsis; - width: 100px; - white-space: nowrap; -} - -.quiqqer-invoice-backend-invoiceItemsProduct-total { - width: 150px; -} diff --git a/bin/backend/controls/InvoiceItemsProduct.html b/bin/backend/controls/InvoiceItemsProduct.html deleted file mode 100644 index 1148594..0000000 --- a/bin/backend/controls/InvoiceItemsProduct.html +++ /dev/null @@ -1,7 +0,0 @@ -<div class="quiqqer-invoice-backend-invoiceItemsProduct-pos cell"></div> -<div class="quiqqer-invoice-backend-invoiceItemsProduct-text cell"></div> -<div class="quiqqer-invoice-backend-invoiceItemsProduct-quantity cell cell-editable"></div> -<div class="quiqqer-invoice-backend-invoiceItemsProduct-unitPrice cell cell-editable"></div> -<div class="quiqqer-invoice-backend-invoiceItemsProduct-price cell cell-editable"></div> -<div class="quiqqer-invoice-backend-invoiceItemsProduct-vat cell cell-editable"></div> -<div class="quiqqer-invoice-backend-invoiceItemsProduct-total cell"></div> diff --git a/bin/backend/controls/articles/Article.css b/bin/backend/controls/articles/Article.css new file mode 100644 index 0000000..2454453 --- /dev/null +++ b/bin/backend/controls/articles/Article.css @@ -0,0 +1,84 @@ +.quiqqer-invoice-backend-invoiceArticle { + align-items: stretch; + border-bottom: 1px solid #DEDEDE; + clear: both; + display: flex; + flex-direction: row; + float: left; + min-height: 50px; + position: relative; + width: 100%; +} + +.quiqqer-invoice-backend-invoiceArticle .cell { + padding: 10px; + position: relative; +} + +.quiqqer-invoice-backend-invoiceArticle .cell-editable:hover { + background: rgba(0, 0, 0, 0.1); + cursor: pointer; +} + +.quiqqer-invoice-backend-invoiceArticle-pos { + width: 50px; +} + +.quiqqer-invoice-backend-invoiceArticle-text { + width: calc(100% - 700px); +} + +.quiqqer-invoice-backend-invoiceArticle-text-title { + clear: both; + font-weight: bold; + margin-bottom: 5px; + position: relative; + width: 100%; +} + +.quiqqer-invoice-backend-invoiceArticle-text-description { + clear: both; + position: relative; + width: 100%; +} + +.quiqqer-invoice-backend-invoiceArticle-text-description-edit { + background: #EFEFEF; + border: 1px solid #EFEFEF; + height: 100%; + left: 0; + overflow: hidden; + position: absolute; + top: 0; + width: 100% +} + +.quiqqer-invoice-backend-invoiceArticle-text-description-buttons { + height: 50px; + text-align: center; +} + +.quiqqer-invoice-backend-invoiceArticle-quantity { + text-align: right; + width: 100px; +} + +.quiqqer-invoice-backend-invoiceArticle-articleNo, +.quiqqer-invoice-backend-invoiceArticle-unitPrice, +.quiqqer-invoice-backend-invoiceArticle-price, +.quiqqer-invoice-backend-invoiceArticle-vat, +.quiqqer-invoice-backend-invoiceArticle-total { + overflow: hidden; + text-align: right; + text-overflow: ellipsis; + width: 100px; + white-space: nowrap; +} + +.quiqqer-invoice-backend-invoiceArticle-articleNo { + text-align: left; +} + +.quiqqer-invoice-backend-invoiceArticle-total { + width: 150px; +} diff --git a/bin/backend/controls/articles/Article.html b/bin/backend/controls/articles/Article.html new file mode 100644 index 0000000..9bae687 --- /dev/null +++ b/bin/backend/controls/articles/Article.html @@ -0,0 +1,8 @@ +<div class="quiqqer-invoice-backend-invoiceArticle-pos cell"></div> +<div class="quiqqer-invoice-backend-invoiceArticle-articleNo cell cell-editable"></div> +<div class="quiqqer-invoice-backend-invoiceArticle-text cell"></div> +<div class="quiqqer-invoice-backend-invoiceArticle-quantity cell cell-editable"></div> +<div class="quiqqer-invoice-backend-invoiceArticle-unitPrice cell cell-editable"></div> +<div class="quiqqer-invoice-backend-invoiceArticle-price cell cell-editable"></div> +<div class="quiqqer-invoice-backend-invoiceArticle-vat cell cell-editable"></div> +<div class="quiqqer-invoice-backend-invoiceArticle-total cell"></div> diff --git a/bin/backend/controls/InvoiceItemsProduct.js b/bin/backend/controls/articles/Article.js similarity index 64% rename from bin/backend/controls/InvoiceItemsProduct.js rename to bin/backend/controls/articles/Article.js index 9478a33..a5953b4 100644 --- a/bin/backend/controls/InvoiceItemsProduct.js +++ b/bin/backend/controls/articles/Article.js @@ -1,14 +1,20 @@ /** - * @module package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct + * @module package/quiqqer/invoice/bin/backend/controls/articles/Article * * Freies Produkt * - Dieses Produkt kann vom Benutzer komplett selbst bestimmt werden * * @require qui/QUI * @require qui/controls/Control - * @require css!package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct.css + * @require qui/controls/buttons/Button + * @require Mustache + * @require Locale + * @require Ajax + * @require Editors + * @require text!package/quiqqer/invoice/bin/backend/controls/articles/Article.html + * @require css!package/quiqqer/invoice/bin/backend/controls/articles/Article.css */ -define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ +define('package/quiqqer/invoice/bin/backend/controls/articles/Article', [ 'qui/QUI', 'qui/controls/Control', @@ -18,18 +24,16 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ 'Ajax', 'Editors', - 'text!package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct.html', - 'css!package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct.css' + 'text!package/quiqqer/invoice/bin/backend/controls/articles/Article.html', + 'css!package/quiqqer/invoice/bin/backend/controls/articles/Article.css' ], function (QUI, QUIControl, QUIButton, Mustache, QUILocale, QUIAjax, Editors, template) { "use strict"; - var lg = 'quiqqer/invoice'; - return new Class({ Extends: QUIControl, - Type: 'package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', + Type : 'package/quiqqer/invoice/bin/backend/controls/articles/Article', Binds: [ '$onEditTitle', @@ -39,37 +43,39 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ ], options: { - position: 0, - title: '', - description: '', - quantity: 1, - unitPrice: 0, - price: 0, - vat: '', - type: '' + position : 0, + title : '---', + description: '---', + quantity : 1, + unitPrice : 0, + price : 0, + vat : '', + params : false, // mixed value for API Articles + type : 'QUI\\ERP\\Accounting\\Invoice\\Articles\\Article' }, initialize: function (options) { + this.setAttributes(this.__proto__.options); // set the default values this.parent(options); - this.$Position = null; - this.$Quantity = null; + this.$Position = null; + this.$Quantity = null; this.$UnitPrice = null; - this.$Price = null; - this.$VAT = null; - this.$Total = null; + this.$Price = null; + this.$VAT = null; + this.$Total = null; - this.$Text = null; - this.$Title = null; + this.$Text = null; + this.$Title = null; this.$Description = null; - this.$Editor = null; + this.$Editor = null; - this.$Loader = null; + this.$Loader = null; this.$created = false; // admin format this.$Formatter = QUILocale.getNumberFormatter({ - style: 'currency', + style : 'currency', currency: 'EUR' }); }, @@ -82,46 +88,49 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ create: function () { this.$Elm = this.parent(); - this.$Elm.addClass('quiqqer-invoice-backend-invoiceItemsProduct'); + this.$Elm.addClass('quiqqer-invoice-backend-invoiceArticle'); this.$Elm.set({ html: Mustache.render(template) }); - this.$Position = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceItemsProduct-pos'); - this.$Text = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceItemsProduct-text'); - this.$Quantity = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceItemsProduct-quantity'); - this.$UnitPrice = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceItemsProduct-unitPrice'); - this.$Price = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceItemsProduct-price'); - this.$VAT = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceItemsProduct-vat'); - this.$Total = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceItemsProduct-total'); - - if (this.getAttribute('position')) { - this.setPosition(this.getAttribute('position')); - } + this.$Position = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticle-pos'); + this.$Text = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticle-text'); + this.$Quantity = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticle-quantity'); + this.$UnitPrice = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticle-unitPrice'); + this.$Price = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticle-price'); + this.$VAT = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticle-vat'); + this.$Total = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticle-total'); this.$Quantity.addEvent('click', this.$onEditQuantity); this.$UnitPrice.addEvent('click', this.$onUnitPriceQuantity); this.$Loader = new Element('div', { - html: '<span class="fa fa-spinner fa-spin"></span>', + html : '<span class="fa fa-spinner fa-spin"></span>', styles: { background: '#fff', - display: 'none', - left: 0, - padding: 10, - position: 'absolute', - top: 0, - width: '100%' + display : 'none', + left : 0, + padding : 10, + position : 'absolute', + top : 0, + width : '100%' } }).inject(this.$Position); + new Element('span').inject(this.$Position); + + if (this.getAttribute('position')) { + this.setPosition(this.getAttribute('position')); + } + + this.$Title = new Element('div', { - 'class': 'quiqqer-invoice-backend-invoiceItemsProduct-text-title cell-editable' + 'class': 'quiqqer-invoice-backend-invoiceArticle-text-title cell-editable' }).inject(this.$Text); this.$Description = new Element('div', { - 'class': 'quiqqer-invoice-backend-invoiceItemsProduct-text-description cell-editable' + 'class': 'quiqqer-invoice-backend-invoiceArticle-text-description cell-editable' }).inject(this.$Text); this.$Title.addEvent('click', this.$onEditTitle); @@ -130,6 +139,8 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ this.setQuantity(this.getAttribute('quantity')); this.setUnitPrice(this.getAttribute('unitPrice')); this.setVat(this.getAttribute('vat')); + this.setTitle(this.getAttribute('title')); + this.setDescription(this.getAttribute('description')); this.$created = true; this.calc(); @@ -139,6 +150,8 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ /** * Calculates the total price of the invoice and refresh the display + * + * @return {Promise} */ calc: function () { var self = this; @@ -152,34 +165,32 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ return new Promise(function (resolve, reject) { QUIAjax.get('package_quiqqer_invoice_ajax_invoices_temporary_product_calc', function (product) { - var total = self.$Formatter.format(product.calculated_sum); + var total = self.$Formatter.format(product.calculated_sum); var unitPrice = self.$Formatter.format(product.calculated_basisPrice); - var price = self.$Formatter.format(product.calculated_price); + var price = self.$Formatter.format(product.calculated_price); self.$Total.set({ - html: total, + html : total, title: total }); self.$UnitPrice.set({ - html: unitPrice, + html : unitPrice, title: unitPrice }); self.$Price.set({ - html: price, + html : price, title: price }); self.hideLoader(); - console.warn(product); - resolve(product); }, { 'package': 'quiqqer/invoice', - onError: reject, - params: JSON.encode(self.getAttributes()) + onError : reject, + params : JSON.encode(self.getAttributes()) }); }); }, @@ -192,6 +203,10 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ setTitle: function (title) { this.setAttribute('title', title); this.$Title.set('html', title); + + if (title === '') { + this.$Title.set('html', ' '); + } }, /** @@ -202,6 +217,10 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ setDescription: function (description) { this.setAttribute('description', description); this.$Description.set('html', description); + + if (description === '') { + this.$Description.set('html', ' '); + } }, /** @@ -213,7 +232,7 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ this.setAttribute('position', parseInt(pos)); if (this.$Position) { - this.$Position.set('html', this.getAttribute('position')); + this.$Position.getChildren('span').set('html', this.getAttribute('position')); } }, @@ -308,18 +327,18 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ this.showLoader(); var EditorContainer = new Element('div', { - 'class': 'quiqqer-invoice-backend-invoiceItemsProduct-text-description-edit' + 'class': 'quiqqer-invoice-backend-invoiceArticle-text-description-edit' }).inject(this.$Description), - EditorParent = new Element('div', { + EditorParent = new Element('div', { styles: { - height: 'calc(100% - 50px)', + height : 'calc(100% - 50px)', opacity: 0 } }).inject(EditorContainer), - EditorSubmit = new Element('div', { - 'class': 'quiqqer-invoice-backend-invoiceItemsProduct-text-description-buttons' + EditorSubmit = new Element('div', { + 'class': 'quiqqer-invoice-backend-invoiceArticle-text-description-buttons' }).inject(EditorContainer); @@ -339,13 +358,13 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ }; new QUIButton({ - text: QUILocale.get('quiqqer/system', 'accept'), + text : QUILocale.get('quiqqer/system', 'accept'), textimage: 'fa fa-check', - styles: { + styles : { 'float': 'none', - margin: '10px 5px 0 5px' + margin : '10px 5px 0 5px' }, - events: { + events : { onClick: function () { this.setDescription(this.$Editor.getContent()); closeEditor(); @@ -354,10 +373,10 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ }).inject(EditorSubmit); new QUIButton({ - text: QUILocale.get('quiqqer/system', 'cancel'), + text : QUILocale.get('quiqqer/system', 'cancel'), styles: { 'float': 'none', - margin: '10px 5px 0 5px' + margin : '10px 5px 0 5px' }, events: { onClick: closeEditor @@ -383,14 +402,36 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ this.$Editor.setAttribute('buttons', { lines: [ [[ - {type: "button", button: "Bold"}, - {type: "button", button: "Italic"}, - {type: "button", button: "Underline"}, - {type: "seperator"}, - {type: "button", button: "RemoveFormat"}, - {type: "seperator"}, - {type: "button", button: "NumberedList"}, - {type: "button", button: "BulletedList"} + { + type : "button", + button: "Bold" + }, + { + type : "button", + button: "Italic" + }, + { + type : "button", + button: "Underline" + }, + { + type: "seperator" + }, + { + type : "button", + button: "RemoveFormat" + }, + { + type: "seperator" + }, + { + type : "button", + button: "NumberedList" + }, + { + type : "button", + button: "BulletedList" + } ]] ] }); @@ -456,17 +497,17 @@ define('package/quiqqer/invoice/bin/backend/controls/InvoiceItemsProduct', [ return new Promise(function (resolve) { var Edit = new Element('input', { - type: type, - value: value, + type : type, + value : value, styles: { - border: 0, - left: 0, + border : 0, + left : 0, lineHeight: 20, - height: '100%', - padding: 0, - position: 'absolute', - top: 0, - width: '100%' + height : '100%', + padding : 0, + position : 'absolute', + top : 0, + width : '100%' } }).inject(Container); diff --git a/bin/backend/controls/articles/Text.css b/bin/backend/controls/articles/Text.css new file mode 100644 index 0000000..ae2deb7 --- /dev/null +++ b/bin/backend/controls/articles/Text.css @@ -0,0 +1,59 @@ +.quiqqer-invoice-backend-invoiceArticleText { + align-items: stretch; + border-bottom: 1px solid #DEDEDE; + clear: both; + display: flex; + flex-direction: row; + float: left; + min-height: 50px; + position: relative; + width: 100%; +} + +.quiqqer-invoice-backend-invoiceArticleText .cell { + padding: 10px; + position: relative; +} + +.quiqqer-invoice-backend-invoiceArticleText .cell-editable:hover { + background: rgba(0, 0, 0, 0.1); + cursor: pointer; +} + +.quiqqer-invoice-backend-invoiceArticleText-pos { + width: 50px; +} + +.quiqqer-invoice-backend-invoiceArticleText-text { + width: calc(100% - 50px); +} + +.quiqqer-invoice-backend-invoiceArticleText-text-title { + clear: both; + font-weight: bold; + margin-bottom: 5px; + position: relative; + width: 100%; +} + +.quiqqer-invoice-backend-invoiceArticleText-text-description { + clear: both; + position: relative; + width: 100%; +} + +.quiqqer-invoice-backend-invoiceArticleText-text-description-edit { + background: #EFEFEF; + border: 1px solid #EFEFEF; + height: 100%; + left: 0; + overflow: hidden; + position: absolute; + top: 0; + width: 100% +} + +.quiqqer-invoice-backend-invoiceArticleText-text-description-buttons { + height: 50px; + text-align: center; +} diff --git a/bin/backend/controls/articles/Text.html b/bin/backend/controls/articles/Text.html new file mode 100644 index 0000000..db821ac --- /dev/null +++ b/bin/backend/controls/articles/Text.html @@ -0,0 +1,2 @@ +<div class="quiqqer-invoice-backend-invoiceArticleText-pos cell"></div> +<div class="quiqqer-invoice-backend-invoiceArticleText-text cell"></div> diff --git a/bin/backend/controls/articles/Text.js b/bin/backend/controls/articles/Text.js new file mode 100644 index 0000000..272c118 --- /dev/null +++ b/bin/backend/controls/articles/Text.js @@ -0,0 +1,172 @@ +/** + * @module package/quiqqer/invoice/bin/backend/controls/articles/Text + * + * Text Produkt + * - Dieses "Produkt" benhaltet nur text und hat keine Summe oder Preise + * - Dieses Produkt wird verwendet für Hinweise auf der Rechnung + * + * @require qui/QUI + * @require qui/controls/Control + */ +define('package/quiqqer/invoice/bin/backend/controls/articles/Text', [ + + 'package/quiqqer/invoice/bin/backend/controls/articles/Article', + 'Locale', + 'Ajax', + 'Mustache', + + 'text!package/quiqqer/invoice/bin/backend/controls/articles/Text.html', + 'css!package/quiqqer/invoice/bin/backend/controls/articles/Text.css' + +], function (InvoiceArticle, QUILocale, QUIAjax, Mustache, template) { + "use strict"; + + return new Class({ + + Extends: InvoiceArticle, + Type : 'package/quiqqer/invoice/bin/backend/controls/articles/Text', + + Binds: [ + '$onEditTitle', + '$onEditDescription' + ], + + initialize: function (options) { + this.parent(options); + + this.setAttributes({ + type: 'QUI\\ERP\\Accounting\\Invoice\\Articles\\Text' + }); + }, + + /** + * Create the DOMNode element + * + * @returns {HTMLDivElement} + */ + create: function () { + this.$Elm = new Element('div'); + + this.$Elm.addClass('quiqqer-invoice-backend-invoiceArticleText'); + + this.$Elm.set({ + html: Mustache.render(template) + }); + + this.$Position = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticleText-pos'); + this.$Text = this.$Elm.getElement('.quiqqer-invoice-backend-invoiceArticleText-text'); + + this.$Loader = new Element('div', { + html : '<span class="fa fa-spinner fa-spin"></span>', + styles: { + background: '#fff', + display : 'none', + left : 0, + padding : 10, + position : 'absolute', + top : 0, + width : '100%' + } + }).inject(this.$Position); + + new Element('span').inject(this.$Position); + + if (this.getAttribute('position')) { + this.setPosition(this.getAttribute('position')); + } + + // text nodes + this.$Title = new Element('div', { + 'class': 'quiqqer-invoice-backend-invoiceArticleText-text-title cell-editable' + }).inject(this.$Text); + + this.$Description = new Element('div', { + 'class': 'quiqqer-invoice-backend-invoiceArticleText-text-description cell-editable' + }).inject(this.$Text); + + this.$Title.addEvent('click', this.$onEditTitle); + this.$Description.addEvent('click', this.$onEditDescription); + + this.setTitle(this.getAttribute('title')); + this.setDescription(this.getAttribute('description')); + + return this.$Elm; + }, + + /** + * Calculates nothing + * Text Article has no prices + * + * @return {Promise} + */ + calc: function () { + return Promise.resolve(); + }, + + /** + * Set the product title + * + * @param {String} title + */ + setTitle: function (title) { + this.setAttribute('title', title); + this.$Title.set('html', title); + + if (title === '') { + this.$Title.set('html', ' '); + } + }, + + /** + * Set the product description + * + * @param {String} description + */ + setDescription: function (description) { + this.setAttribute('description', description); + this.$Description.set('html', description); + + if (description === '') { + this.$Description.set('html', ' '); + } + }, + + /** + * Set the product quantity + * + * @return {Promise} + */ + setQuantity: function () { + return Promise.resolve(); + }, + + /** + * Set the product unit price + * + */ + setUnitPrice: function () { + return Promise.resolve(); + }, + + /** + * Set the product unit price + **/ + setVat: function () { + return Promise.resolve(); + }, + + /** + * Show the loader + */ + showLoader: function () { + this.$Loader.setStyle('display', null); + }, + + /** + * Hide the loader + */ + hideLoader: function () { + this.$Loader.setStyle('display', 'none'); + } + }); +}); diff --git a/bin/backend/controls/panels/TemporaryInvoice.Data.html b/bin/backend/controls/panels/TemporaryInvoice.Data.html index 7f0cb5c..546687a 100644 --- a/bin/backend/controls/panels/TemporaryInvoice.Data.html +++ b/bin/backend/controls/panels/TemporaryInvoice.Data.html @@ -3,7 +3,7 @@ <table class="data-table data-table-flexbox invoice-data"> <thead> <tr> - <th>Rechnungsdaten</th> + <th>{{textInvoiceData}}</th> </tr> </thead> @@ -11,8 +11,8 @@ <tr> <td> <label class="field-container"> - <span class="field-container-item" title="Rechnungsdatum"> - Rechnungsdatum + <span class="field-container-item" title="{{textInvoiceDate}}"> + {{textInvoiceDate}} </span> <input class="field-container-field" type="datetime" name="date"/> </label> @@ -21,8 +21,8 @@ <tr> <td> <label class="field-container"> - <span class="field-container-item" title="Zahlungsziel"> - Zahlungsziel + <span class="field-container-item" title="{{textTermOfPayment}}"> + {{textTermOfPayment}} </span> <span class="field-container-field"></span> </label> @@ -31,8 +31,8 @@ <tr> <td> <label class="field-container"> - <span class="field-container-item" title="Projektname"> - Projektname + <span class="field-container-item" title="{{textProjectName}}"> + {{textProjectName}} </span> <input class="field-container-field" type="text" name="projectName"/> </label> @@ -41,8 +41,8 @@ <tr> <td> <label class="field-container"> - <span class="field-container-item" title="Bestellt durch"> - Bestellt durch + <span class="field-container-item" title="{{textOrderedBy}}"> + {{textOrderedBy}} </span> <span class="field-container-field field-container-field-no-padding"> <input type="hidden" diff --git a/bin/backend/controls/panels/TemporaryInvoice.js b/bin/backend/controls/panels/TemporaryInvoice.js index e536bce..16b8c34 100644 --- a/bin/backend/controls/panels/TemporaryInvoice.js +++ b/bin/backend/controls/panels/TemporaryInvoice.js @@ -27,6 +27,7 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ 'qui/controls/windows/Confirm', 'controls/users/address/Select', 'package/quiqqer/invoice/bin/Invoices', + 'package/quiqqer/invoice/bin/backend/controls/articles/Text', 'Locale', 'Mustache', 'Users', @@ -35,7 +36,7 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ 'css!package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice.css' ], function (QUI, QUIPanel, QUIButton, QUIButtonMultiple, QUISeparator, QUIConfirm, - AddressSelect, Invoices, QUILocale, Mustache, Users, templateData) { + AddressSelect, Invoices, TextArticle, QUILocale, Mustache, Users, templateData) { "use strict"; var lg = 'quiqqer/invoice'; @@ -48,7 +49,7 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ Binds: [ 'save', 'openData', - 'openProducts', + 'openArticles', 'openVerification', '$openCategory', '$closeCategory', @@ -63,7 +64,8 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ invoiceId : false, data : {}, customer_id: false, - address_id : false + address_id : false, + articles : [] }, initialize: function (options) { @@ -73,10 +75,12 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ this.parent(options); - this.$ProductList = null; - this.$AddProduct = null; + this.$ArticleList = null; + this.$AddProduct = null; this.$AddSeparator = null; + this.$serializedList = {}; + this.addEvents({ onCreate : this.$onCreate, onInject : this.$onInject, @@ -98,7 +102,8 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ return Invoices.saveInvoice(this.getAttribute('invoiceId'), { customer_id: this.getAttribute('customer_id'), - address_id : this.getAttribute('address_id') + address_id : this.getAttribute('address_id'), + articles : this.getAttribute('articles') }).then(function () { this.Loader.hide(); }.bind(this)).catch(function (err) { @@ -125,7 +130,13 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ var Container = self.getContent().getElement('.container'); Container.set({ - html: Mustache.render(templateData) + html: Mustache.render(templateData, { + textInvoiceData : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.data.textInvoiceData'), + textInvoiceDate : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.data.textInvoiceDate'), + textTermOfPayment: QUILocale.get(lg, 'erp.panel.temporary.invoice.category.data.textTermOfPayment'), + textProjectName : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.data.textProjectName'), + textOrderedBy : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.data.textOrderedBy') + }) }); return QUI.parse(Container); @@ -146,7 +157,26 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ self.getAttribute('address_id') ); }).then(function () { + var Container = self.getContent().getElement('.container'); + + new QUIButton({ + textimage: 'fa fa-list', + text : 'Artikel verwalten', + styles : { + display: 'block', + 'float': 'none', + margin : '0 auto' + }, + events : { + onClick: function () { + self.openArticles(); + } + } + }).inject(Container); + + self.getCategory('data').setActive(); self.Loader.hide(); + return self.$openCategory(); }); }, @@ -156,7 +186,7 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ * * @returns {Promise} */ - openProducts: function () { + openArticles: function () { this.Loader.show(); return this.$closeCategory().then(function (Container) { @@ -164,14 +194,33 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ require([ 'package/quiqqer/invoice/bin/backend/controls/InvoiceItems' ], function (InvoiceItems) { - this.$ProductList = new InvoiceItems({ + this.$ArticleList = new InvoiceItems({ events: {} }).inject(Container); + if (this.$serializedList) { + this.$ArticleList.unserialize(this.$serializedList); + } + this.$AddProduct.show(); this.$AddSeparator.show(); this.Loader.hide(); + this.getCategory('articles').setActive(); + + new QUIButton({ + textimage: 'fa fa-check', + text : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.review'), + styles : { + display: 'block', + 'float': 'none', + margin : '0 auto' + }, + events : { + onClick: this.openVerification + } + }).inject(Container); + resolve(); }.bind(this)); }.bind(this)); @@ -192,6 +241,7 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ return this.$closeCategory().then(function () { + this.getCategory('verification').setActive(); this.Loader.hide(); }.bind(this)).then(function () { return self.$openCategory(); @@ -206,14 +256,14 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ require([ 'package/quiqqer/products/bin/controls/products/search/Window', - 'package/quiqqer/products/bin/controls/invoice/Product' - ], function (ProductSearch, Product) { + 'package/quiqqer/products/bin/controls/invoice/Article' + ], function (ProductSearch, Article) { new ProductSearch({ events: { onSubmit: function (Win, products) { for (var i = 0, len = products.length; i < len; i++) { - this.$ProductList.addProduct( - new Product({ + this.$ArticleList.addArticle( + new Article({ productId: products[i] }) ); @@ -257,9 +307,12 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ }, { duration: 200, callback: function () { - if (this.$ProductList) { - this.$ProductList.destroy(); - this.$ProductList = null; + if (this.$ArticleList) { + this.setAttribute('articles', this.$ArticleList.save()); + this.$serializedList = this.$ArticleList.serialize(); + + this.$ArticleList.destroy(); + this.$ArticleList = null; } Container.set('html', ''); @@ -308,10 +361,10 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ this.$AddProduct = new QUIButtonMultiple({ textimage: 'fa fa-plus', - text : 'Artikel hinzufügen', + text : QUILocale.get(lg, 'erp.panel.temporary.invoice.buttonAdd'), events : { onClick: function () { - if (self.$ProductList) { + if (self.$ArticleList) { self.openProductSearch(); } } @@ -321,22 +374,22 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ this.$AddProduct.hide(); this.$AddProduct.appendChild({ - text : 'Freier Artikel', + text : QUILocale.get(lg, 'erp.panel.temporary.invoice.buttonAdd.custom'), events: { onClick: function () { - if (self.$ProductList) { - self.$ProductList.insertNewProduct(); + if (self.$ArticleList) { + self.$ArticleList.insertNewProduct(); } } } }); this.$AddProduct.appendChild({ - text : 'Text', + text : QUILocale.get(lg, 'erp.panel.temporary.invoice.buttonAdd.text'), events: { onClick: function () { - if (self.$ProductList) { - + if (self.$ArticleList) { + self.$ArticleList.addArticle(new TextArticle()); } } } @@ -346,6 +399,7 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ // buttons this.addButton({ + name : 'save', text : QUILocale.get('quiqqer/system', 'save'), textimage: 'fa fa-save', events : { @@ -357,6 +411,7 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ this.addButton(this.$AddProduct); this.addButton({ + name : 'delete', icon : 'fa fa-trash', styles: { 'float': 'right' @@ -368,24 +423,27 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ // categories this.addCategory({ + name : 'data', icon : 'fa fa-info', - text : 'Rechnungsdaten', + text : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.data'), events: { onClick: this.openData } }); this.addCategory({ + name : 'articles', icon : 'fa fa-list', - text : 'Positionen (Artikel)', + text : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.pos'), events: { - onClick: this.openProducts + onClick: this.openArticles } }); this.addCategory({ + name : 'verification', icon : 'fa fa-check', - text : 'Überprüfung', + text : QUILocale.get(lg, 'erp.panel.temporary.invoice.category.review'), events: { onClick: this.openVerification } @@ -407,6 +465,12 @@ define('package/quiqqer/invoice/bin/backend/controls/panels/TemporaryInvoice', [ this.setAttribute('title', data.id); this.setAttributes(data); + if (data.articles.length) { + this.$serializedList = { + articles: data.articles + }; + } + this.refresh(); this.getCategoryBar().firstChild().click(); this.Loader.hide(); diff --git a/database.xml b/database.xml index 119fe26..3b7ab4c 100644 --- a/database.xml +++ b/database.xml @@ -25,7 +25,7 @@ <field type="INT(1) DEFAULT 0">canceled</field> <!-- storno --> <field type="INT NOT NULL">c_user</field> <field type="TEXT NULL">data</field> - <field type="TEXT NOT NULL">products</field> + <field type="TEXT NOT NULL">articles</field> <!--<field type="TEXT NULL">comments</field>--> <!-- als Modul auslagern --> <field type="TEXT NULL">history</field> <field type="TEXT NULL">customer_data</field> @@ -75,7 +75,7 @@ <field type="timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP">date</field> <field type="INT(11) NOT NULL">c_user</field> <field type="TEXT NULL">data</field> - <field type="TEXT NOT NULL">products</field> + <field type="TEXT NOT NULL">articles</field> <field type="TEXT NULL">history</field> <field type="TEXT NULL">customer_data</field> <field type="FLOAT NOT NULL">isbrutto</field> diff --git a/locale.xml b/locale.xml index 6697564..6108fe3 100644 --- a/locale.xml +++ b/locale.xml @@ -46,6 +46,10 @@ <en><![CDATA[Invoice drafts]]></en> </locale> + <locale name="invoice.products.articleNo"> + <de><![CDATA[Artikel Nr.]]></de> + <en><![CDATA[Article No.]]></en> + </locale> <locale name="invoice.products.description"> <de><![CDATA[Produkt Beschreibung]]></de> <en><![CDATA[Product description]]></en> @@ -252,6 +256,50 @@ <de><![CDATA[Rechnungsentwürfe]]></de> <en><![CDATA[Invoice drafts]]></en> </locale> + <locale name="erp.panel.temporary.invoice.buttonAdd"> + <de><![CDATA[Artikel hinzufügen]]></de> + <en><![CDATA[Add Article]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.buttonAdd.custom"> + <de><![CDATA[Freier Artikel]]></de> + <en><![CDATA[Custom Article]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.buttonAdd.text"> + <de><![CDATA[Text]]></de> + <en><![CDATA[Text]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.data"> + <de><![CDATA[Rechnungsdaten]]></de> + <en><![CDATA[Invoice data]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.pos"> + <de><![CDATA[Positionen (Artikel)]]></de> + <en><![CDATA[Position (Article)]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.review"> + <de><![CDATA[Überprüfung]]></de> + <en><![CDATA[Review]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.data.textInvoiceData"> + <de><![CDATA[Rechnungsdaten]]></de> + <en><![CDATA[Invoice data]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.data.textInvoiceDate"> + <de><![CDATA[Rechnung Datum]]></de> + <en><![CDATA[Invoice Date]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.data.textTermOfPayment"> + <de><![CDATA[Zahlungsziel]]></de> + <en><![CDATA[Term of Payment]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.data.textProjectName"> + <de><![CDATA[Projektname]]></de> + <en><![CDATA[Projectname]]></en> + </locale> + <locale name="erp.panel.temporary.invoice.category.data.textOrderedBy"> + <de><![CDATA[Bestellt durch]]></de> + <en><![CDATA[Ordered by]]></en> + </locale> <locale name="dialog.ti.delete.title"> <de><![CDATA[Rechnung löschen]]></de> diff --git a/src/QUI/ERP/Accounting/Invoice/Articles/Article.php b/src/QUI/ERP/Accounting/Invoice/Articles/Article.php new file mode 100644 index 0000000..37c7acf --- /dev/null +++ b/src/QUI/ERP/Accounting/Invoice/Articles/Article.php @@ -0,0 +1,133 @@ +<?php + +/** + * This file contains QUI\ERP\Accounting\Invoice\Articles\Article + */ +namespace QUI\ERP\Accounting\Invoice\Articles; + +use QUI; + +/** + * Article + * An temporary invoice article + * + * - Freier Artikel + * + * @package QUI\ERP\Accounting\Invoice + */ +class Article implements ArticleInterface +{ + /** + * @var array + */ + protected $attributes = array(); + + /** + * Article constructor. + * + * @param array $attributes - (title, description, unitPrice, quantity) + */ + public function __construct($attributes = array()) + { + if (isset($attributes['title'])) { + $this->attributes['title'] = $attributes['title']; + } + + if (isset($attributes['description'])) { + $this->attributes['description'] = $attributes['description']; + } + + if (isset($attributes['unitPrice'])) { + $this->attributes['unitPrice'] = $attributes['unitPrice']; + } + + if (isset($attributes['quantity'])) { + $this->attributes['quantity'] = $attributes['quantity']; + } + } + + /** + * Returns the article title + * + * @param null|QUI\Locale $Locale + * @return string + */ + public function getTitle($Locale = null) + { + if (isset($this->attributes['title'])) { + return $this->attributes['title']; + } + + return ''; + } + + /** + * Returns the article description + * + * @param null|QUI\Locale $Locale + * @return string + */ + public function getDescription($Locale = null) + { + if (isset($this->attributes['description'])) { + return $this->attributes['description']; + } + + return ''; + } + + /** + * Returns the article unit price + * + * @return int|float + */ + public function getUnitPrice() + { + if (isset($this->attributes['unitPrice'])) { + return $this->attributes['unitPrice']; + } + + return 0; + } + + /** + * Returns the article total sum + * + * @return int|float + */ + public function getSum() + { + return 0; + } + + /** + * Returns the article quantity + * + * @return int + */ + public function getQuantity() + { + if (isset($this->attributes['quantity'])) { + return $this->attributes['quantity']; + } + + return 1; + } + + /** + * Return the article as an array + * + * @return array + */ + public function toArray() + { + return array( + 'title' => $this->getTitle(), + 'description' => $this->getDescription(), + 'unitPrice' => $this->getUnitPrice(), + 'quantity' => $this->getQuantity(), + 'sum' => $this->getSum(), + 'control' => 'package/quiqqer/invoice/bin/backend/controls/articles/Article' + ); + } +} diff --git a/src/QUI/ERP/Accounting/Invoice/Articles/ArticleInterface.php b/src/QUI/ERP/Accounting/Invoice/Articles/ArticleInterface.php new file mode 100644 index 0000000..cbd3b29 --- /dev/null +++ b/src/QUI/ERP/Accounting/Invoice/Articles/ArticleInterface.php @@ -0,0 +1,57 @@ +<?php + +/** + * This file contains QUI\ERP\Accounting\Invoice\Articles + */ +namespace QUI\ERP\Accounting\Invoice\Articles; + +use QUI; + +/** + * Article + * An temporary invoice article + * + * @package QUI\ERP\Accounting\Invoice + */ +interface ArticleInterface +{ + /** + * Article constructor. + * + * @param array $attributes - article attributes + * @throws \QUI\Exception + */ + public function __construct($attributes = array()); + + /** + * @param null|QUI\Locale $Locale + * @return string + */ + public function getTitle($Locale = null); + + /** + * @param null|QUI\Locale $Locale + * @return string + */ + public function getDescription($Locale = null); + + /** + * @return integer|float + */ + public function getUnitPrice(); + + /** + * @return integer|float + */ + public function getSum(); + + /** + * @return integer|float + */ + public function getQuantity(); + + /** + * @return array + */ + public function toArray(); +} diff --git a/src/QUI/ERP/Accounting/Invoice/Articles/Text.php b/src/QUI/ERP/Accounting/Invoice/Articles/Text.php new file mode 100644 index 0000000..abc7939 --- /dev/null +++ b/src/QUI/ERP/Accounting/Invoice/Articles/Text.php @@ -0,0 +1,121 @@ +<?php + +/** + * This file contains QUI\ERP\Accounting\Invoice\Articles\Text + */ +namespace QUI\ERP\Accounting\Invoice\Articles; + +use QUI; + +/** + * Article + * An temporary invoice article + * + * - Freier Artikel + * + * @package QUI\ERP\Accounting\Invoice + */ +class Text implements ArticleInterface +{ + /** + * @var array + */ + protected $attributes = array(); + + /** + * Article constructor. + * + * @param array $attributes - (title, description, unitPrice, quantity) + */ + public function __construct($attributes = array()) + { + if (isset($attributes['title'])) { + $this->attributes['title'] = $attributes['title']; + } + + if (isset($attributes['description'])) { + $this->attributes['description'] = $attributes['description']; + } + } + + /** + * Returns the article title + * + * @param null|QUI\Locale $Locale + * @return string + */ + public function getTitle($Locale = null) + { + if (isset($this->attributes['title'])) { + return $this->attributes['title']; + } + + return ''; + } + + /** + * Returns the article description + * + * @param null|QUI\Locale $Locale + * @return string + */ + public function getDescription($Locale = null) + { + if (isset($this->attributes['description'])) { + return $this->attributes['description']; + } + + return ''; + } + + /** + * Returns the article unit price + * + * @return int|float + */ + public function getUnitPrice() + { + if (isset($this->attributes['unitPrice'])) { + return $this->attributes['unitPrice']; + } + + return 0; + } + + /** + * Returns the article total sum + * + * @return int|float + */ + public function getSum() + { + return 0; + } + + /** + * Returns the article quantity + * + * @return int + */ + public function getQuantity() + { + return 1; + } + + /** + * Return the article as an array + * + * @return array + */ + public function toArray() + { + return array( + 'title' => $this->getTitle(), + 'description' => $this->getDescription(), + 'unitPrice' => 0, + 'quantity' => 1, + 'sum' => 0, + 'control' => 'package/quiqqer/invoice/bin/backend/controls/articles/Text' + ); + } +} diff --git a/src/QUI/ERP/Accounting/Invoice/TemporaryInvoice.php b/src/QUI/ERP/Accounting/Invoice/TemporaryInvoice.php index b9ff1c2..a627cdc 100644 --- a/src/QUI/ERP/Accounting/Invoice/TemporaryInvoice.php +++ b/src/QUI/ERP/Accounting/Invoice/TemporaryInvoice.php @@ -24,6 +24,11 @@ class TemporaryInvoice extends QUI\QDOM */ protected $id; + /** + * @var array + */ + protected $articles = array(); + /** * Invoice constructor. * @@ -32,7 +37,19 @@ class TemporaryInvoice extends QUI\QDOM */ public function __construct($id, Handler $Handler) { - $this->setAttributes($Handler->getTemporaryInvoiceData($id)); + $data = $Handler->getTemporaryInvoiceData($id); + + if (isset($data['articles'])) { + $articles = json_decode($data['articles'], true); + + if (is_array($articles)) { + $this->importArticles($articles); + } + + unset($data['articles']); + } + + $this->setAttributes($data); $this->id = (int)str_replace(self::ID_PREFIX, '', $id); } @@ -95,6 +112,17 @@ public function save($User = null) // vat_data // processing_status + // articles + $articles = array_map(function ($Article) { + /* @var $Article QUI\ERP\Accounting\Invoice\Articles\ArticleInterface */ + $result = $Article->toArray(); + + $result['type'] = get_class($Article); + + return $result; + }, $this->articles); + + QUI::getDataBase()->update( Handler::getInstance()->temporaryInvoiceTable(), array( @@ -113,8 +141,8 @@ public function save($User = null) 'canceled' => '', 'date' => '', 'data' => '', - 'products' => '', - 'history' => '', + 'articles' => json_encode($articles), +// 'history' => '', 'customer_data' => '', 'isbrutto' => '', 'currency_data' => '', @@ -219,6 +247,95 @@ public function toArray() $attributes = $this->getAttributes(); $attributes['id'] = $this->getId(); + // articles + $attributes['articles'] = array_map(function ($Article) { + /* @var $Article QUI\ERP\Accounting\Invoice\Articles\ArticleInterface */ + $result = $Article->toArray(); + + $result['type'] = get_class($Article); + + return $result; + }, $this->articles); + return $attributes; } + + /** + * Article + */ + + /** + * Add an article + * + * @param Articles\ArticleInterface $Article + */ + public function addArticle(Articles\ArticleInterface $Article) + { + $this->articles[] = $Article; + } + + /** + * + */ + public function removeArticle() + { + + } + + /** + * Returns the article list + * + * @return array + */ + public function getArticles() + { + return $this->articles; + } + + /** + * Remove all articles from the invoice + */ + public function clearArticles() + { + $this->articles = array(); + } + + /** + * Import an article array + * + * @param array $articles - array of articles, eq: [0] => Array + * ( + * [productId] => 5 + * [type] => QUI\ERP\Products\Product\Product + * [position] => 1 + * [quantity] => 1 + * [unitPrice] => 0 + * [vat] => + * [title] => USS Enterprise NCC-1701-D + * [description] => Raumschiff aus bekannter Serie + * [control] => package/quiqqer/products/bin/controls/invoice/Product + * ) + */ + public function importArticles($articles = array()) + { + if (!is_array($articles)) { + $articles = array(); + } + + foreach ($articles as $article) { + if (!isset($article['type'])) { + continue; + } + + try { + $Article = new $article['type']($article); + + if ($Article instanceof Articles\ArticleInterface) { + $this->addArticle($Article); + } + } catch (QUI\Exception $Exception) { + QUI\System\Log::writeException($Exception); + } + } + } } -- GitLab