diff --git a/ajax/calcNettoPrice.php b/ajax/calcNettoPrice.php new file mode 100644 index 0000000000000000000000000000000000000000..693ecba474c91ddab0821bcf7604cd3af9428540 --- /dev/null +++ b/ajax/calcNettoPrice.php @@ -0,0 +1,55 @@ +<?php + +/** + * This file contains package_quiqqer_products_ajax_products_calcNettoPrice + */ + +use QUI\ERP\Products\Utils\Calc; +use QUI\ERP\Tax\TaxEntry; +use QUI\ERP\Tax\TaxType; +use QUI\ERP\Tax\Utils as TaxUtils; + +/** + * Calculate the netto price + * + * @param integer|float $price - Price to calc (brutto price) + * @param bool $formatted - output formatted? + * @param integer $vat - optional + * + * @return float + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_calcNettoPrice', + function ($price, $formatted, $vat) { + $price = QUI\ERP\Money\Price::validatePrice($price); + + if (empty($vat)) { + $Area = QUI\ERP\Defaults::getArea(); + $TaxType = TaxUtils::getTaxTypeByArea($Area); + + if ($TaxType instanceof TaxType) { + $TaxEntry = TaxUtils::getTaxEntry($TaxType, $Area); + } elseif ($TaxType instanceof TaxEntry) { + $TaxEntry = $TaxType; + } else { + if (isset($formatted) && $formatted) { + return QUI\ERP\Defaults::getCurrency()->format($price); + } + + return $price; + } + + $vat = $TaxEntry->getValue(); + } + + $vat = ($vat / 100) + 1; + $price = $price / $vat; + + if (isset($formatted) && $formatted) { + return QUI\ERP\Defaults::getCurrency()->format($price); + } + + return $price; + }, + ['price', 'formatted', 'vat'] +); diff --git a/bin/backend/controls/articles/Article.js b/bin/backend/controls/articles/Article.js index e5c167bbf61cb00cddd768ca89749bf96a984e77..b53cdbef02fa1d69793e008503ba4bc9a9465f52 100644 --- a/bin/backend/controls/articles/Article.js +++ b/bin/backend/controls/articles/Article.js @@ -934,13 +934,37 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [ * event : on quantity edit */ $onEditUnitPriceQuantity: function () { + var self = this; + var List = this.getAttribute('List'); + var netto = List.getAttribute('nettoinput'); + + if (netto === false) { + // open brutto window + require([ + 'package/quiqqer/erp/bin/backend/controls/articles/windows/PriceBrutto' + ], function (PriceBrutto) { + new PriceBrutto({ + vat: self.getAttribute('vat'), + // value : self.getAttribute('unitPrice'), // needs to be brutto + events: { + onSubmit: function (Instance, value) { + if (value) { + self.setUnitPrice(value); + } + } + } + }).open(); + }); + return; + } + this.$createEditField( this.$UnitPrice, this.getAttribute('unitPrice'), 'number' ).then(function (value) { - this.setUnitPrice(value); - }.bind(this)); + self.setUnitPrice(value); + }); }, /** @@ -1085,7 +1109,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [ if (!PreviousArticle) { PreviousArticle = Cell.getParent('.quiqqer-erp-backend-erpItems-items') - .getLast('.article'); + .getLast('.article'); } Next = PreviousArticle.getLast('.cell-editable'); @@ -1104,7 +1128,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [ if (!NextArticle) { NextArticle = Cell.getParent('.quiqqer-erp-backend-erpItems-items') - .getElement('.article'); + .getElement('.article'); } Next = NextArticle.getElement('.cell-editable'); diff --git a/bin/backend/controls/articles/ArticleList.css b/bin/backend/controls/articles/ArticleList.css index d72c86331d662148caa4623900f6cc707b68511d..8669d1cdaa0925542f0e0bcc720619cd1e04072f 100644 --- a/bin/backend/controls/articles/ArticleList.css +++ b/bin/backend/controls/articles/ArticleList.css @@ -13,6 +13,25 @@ min-width: 1100px; } +.quiqqer-erp-backend-erpItems-container-switch { + background: #FAF6D4; + color: #ab8327; + height: 40px; + width: 100%; +} + +.quiqqer-erp-backend-erpItems-container-switch-btn { + display: inline-block; + float: left; + padding: 10px 10px 0 10px; +} + +.quiqqer-erp-backend-erpItems-container-switch-desc { + cursor: pointer; + float: left; + line-height: 40px; +} + .quiqqer-erp-backend-erpItems-header { background: #DEDEDE; float: left; diff --git a/bin/backend/controls/articles/ArticleList.html b/bin/backend/controls/articles/ArticleList.html index edf0dd557aa2bc7eaeaa9880ae344083f91f829f..586f5329ec0dea0c0345a0de31a47d1383a266f0 100644 --- a/bin/backend/controls/articles/ArticleList.html +++ b/bin/backend/controls/articles/ArticleList.html @@ -1,4 +1,8 @@ <div class="quiqqer-erp-backend-erpItems-container"> + <div class="quiqqer-erp-backend-erpItems-container-switch"> + <span class="quiqqer-erp-backend-erpItems-container-switch-btn"></span> + <span class="quiqqer-erp-backend-erpItems-container-switch-desc"></span> + </div> <div class="quiqqer-erp-backend-erpItems-header"> <div class="quiqqer-erp-backend-erpItems-header-pos header-cell"> # diff --git a/bin/backend/controls/articles/ArticleList.js b/bin/backend/controls/articles/ArticleList.js index 1afa33c63c94dbca2022d0bbdebd08c6aad4fc2c..53015942f5ef9d11df7f8503e9da8e1ad12b514a 100644 --- a/bin/backend/controls/articles/ArticleList.js +++ b/bin/backend/controls/articles/ArticleList.js @@ -13,6 +13,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ 'qui/QUI', 'qui/controls/Control', + 'qui/controls/buttons/Switch', 'Mustache', 'Ajax', 'Locale', @@ -23,7 +24,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ 'text!package/quiqqer/erp/bin/backend/controls/articles/ArticleList.sortablePlaceholder.html', 'css!package/quiqqer/erp/bin/backend/controls/articles/ArticleList.css' -], function (QUI, QUIControl, Mustache, QUIAjax, QUILocale, Article, Sortables, template, templateSortablePlaceholder) { +], function (QUI, QUIControl, QUISwitch, Mustache, + QUIAjax, QUILocale, Article, Sortables, template, templateSortablePlaceholder) { "use strict"; var lg = 'quiqqer/erp'; @@ -41,11 +43,13 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ '$onArticleCalc', '$calc', '$onInject', - '$executeCalculation' + '$executeCalculation', + '$refreshNettoBruttoDisplay' ], options: { - currency: false // bool || string -> EUR, USD ... + currency : false, // bool || string -> EUR, USD ... + nettoinput: true }, initialize: function (options) { @@ -72,6 +76,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ this.$Container = null; this.$Sortables = null; this.$priceFactors = []; + this.$Switch = null; this.addEvents({ onInject: this.$onInject @@ -84,8 +89,9 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ * @returns {HTMLDivElement} */ create: function () { - this.$Elm = this.parent(); + var self = this; + this.$Elm = this.parent(); this.$Elm.addClass('quiqqer-erp-backend-erpItems'); this.$Elm.set({ @@ -107,6 +113,28 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ } this.$Container = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-items'); + var SwitchDesc = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-container-switch-desc'); + + this.$Switch = new QUISwitch({ + switchTextOn : 'netto', + switchTextOnIcon : false, + switchTextOff : 'brutto', + switchTextOffIcon: false, + events : { + onChange: function () { + self.setAttribute('nettoinput', !!self.$Switch.getStatus()); + self.$refreshNettoBruttoDisplay(); + } + } + }).inject( + this.$Elm.getElement('.quiqqer-erp-backend-erpItems-container-switch-btn') + ); + + SwitchDesc.addEvent('click', function () { + self.$Switch.toggle(); + }); + + this.$refreshNettoBruttoDisplay(); return this.$Elm; }, @@ -552,8 +580,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ */ $onArticleSetPosition: function (Article) { Article.getElm() - .getElement('.quiqqer-erp-backend-erpArticlePlaceholder-pos') - .set('html', Article.getAttribute('position')); + .getElement('.quiqqer-erp-backend-erpArticlePlaceholder-pos') + .set('html', Article.getAttribute('position')); }, /** @@ -655,6 +683,16 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [ */ getSelectedArticle: function () { return this.$selectedArticle; + }, + + $refreshNettoBruttoDisplay: function () { + var SwitchDesc = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-container-switch-desc'); + + if (this.getAttribute('nettoinput')) { + SwitchDesc.set('html', QUILocale.get(lg, 'control.articleList.netto.message')); + } else { + SwitchDesc.set('html', QUILocale.get(lg, 'control.articleList.brutto.message')); + } } }); }); diff --git a/bin/backend/controls/articles/windows/PriceBrutto.css b/bin/backend/controls/articles/windows/PriceBrutto.css new file mode 100644 index 0000000000000000000000000000000000000000..1a33fa1a580c1858390884f5390d1fc2ed1dbf26 --- /dev/null +++ b/bin/backend/controls/articles/windows/PriceBrutto.css @@ -0,0 +1,16 @@ +.erp-price-brutto-window label { + display: block; + margin: 20px auto 0; + max-width: 400px; + width: 100%; +} + +.erp-price-brutto-window label span { + display: inline-block; + margin-bottom: 5px; + width: 100%; +} + +.erp-price-brutto-window label input { + width: 100%; +} diff --git a/bin/backend/controls/articles/windows/PriceBrutto.html b/bin/backend/controls/articles/windows/PriceBrutto.html new file mode 100644 index 0000000000000000000000000000000000000000..62070b265cb8451218b36058f82d1bcdcb2305e0 --- /dev/null +++ b/bin/backend/controls/articles/windows/PriceBrutto.html @@ -0,0 +1,9 @@ +<form name="price"> + <div class="price-brutto-window-decsription"> + {{{description}}} + </div> + <label> + <span>{{title}}</span> + <input type="text" step="any" autofocus/> + </label> +</form> \ No newline at end of file diff --git a/bin/backend/controls/articles/windows/PriceBrutto.js b/bin/backend/controls/articles/windows/PriceBrutto.js new file mode 100644 index 0000000000000000000000000000000000000000..c70db33fac4a42c05a1f66c6fb9fda73868a3b17 --- /dev/null +++ b/bin/backend/controls/articles/windows/PriceBrutto.js @@ -0,0 +1,104 @@ +/** + * @module package/quiqqer/erp/bin/backend/controls/articles/windows/PriceBrutto + * @author www.pcsg.de (Henning Leutz) + */ +define('package/quiqqer/erp/bin/backend/controls/articles/windows/PriceBrutto', [ + + 'qui/QUI', + 'qui/controls/windows/Confirm', + 'Locale', + 'Ajax', + 'Mustache', + + 'text!package/quiqqer/erp/bin/backend/controls/articles/windows/PriceBrutto.html', + 'css!package/quiqqer/erp/bin/backend/controls/articles/windows/PriceBrutto.css' + +], function (QUI, QUIConfirm, QUILocale, QUIAjax, Mustache, template) { + "use strict"; + + var lg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIConfirm, + Type : 'package/quiqqer/erp/bin/backend/controls/articles/windows/PriceBrutto', + + options: { + value: false, + vat : false // false = shop default vat + }, + + Binds: [ + '$onOpen' + ], + + initialize: function (options) { + this.parent(options); + + this.setAttributes({ + icon : 'fa fa-calculator', + title : QUILocale.get(lg, 'control.window.price.brutto.title'), + maxHeight: 400, + maxWidth : 600 + }); + + this.addEvents({ + onOpen: this.$onOpen + }); + + // admin format + this.$Formatter = QUILocale.getNumberFormatter({ + //style : 'currency', + //currency : 'EUR', + minimumFractionDigits: 8 + }); + }, + + /** + * Return the domnode element + * + * @return {Element} + */ + $onOpen: function () { + var self = this, + Content = this.getContent(); + + Content.set('html', Mustache.render(template, { + title : QUILocale.get(lg, 'control.window.price.brutto.label'), + description: QUILocale.get(lg, 'control.window.price.brutto.description') + })); + + Content.addClass('erp-price-brutto-window'); + Content.getElement('input').placeholder = this.$Formatter.format(1000); + + Content.getElement('form').addEvent('submit', function (event) { + event.stop(); + self.submit(); + }); + + if (this.getAttribute('value')) { + Content.getElement('input').value = this.getAttribute('value'); + } + + this.getContent().getElement('input').focus(); + }, + + /** + * submit the window + */ + submit: function () { + var self = this; + + this.Loader.show(); + + QUIAjax.get('package_quiqqer_erp_ajax_calcNettoPrice', function (price) { + self.fireEvent('submit', [self, price]); + self.close(); + }, { + 'package': 'quiqqer/erp', + price : this.getContent().getElement('input').value, + vat : this.getAttribute('vat') + }); + } + }); +}); diff --git a/locale.xml b/locale.xml index afe28928a6d46131cf23460d0c4e803cd137b5bb..2c000ed29887f129a3f20d78f76c8f68c0aae0b2 100644 --- a/locale.xml +++ b/locale.xml @@ -661,6 +661,36 @@ <en><![CDATA[Article overview calculation]]></en> </locale> + <locale name="control.articleList.netto.message" html="true"> + <de><![CDATA[Die Eingabe und Anzeige der Preise ist zur Zeit in <b>netto</b>.]]></de> + <en><![CDATA[The input and display of the prices is currently in <b>net</b>.]]></en> + </locale> + <locale name="control.articleList.brutto.message" html="true"> + <de><![CDATA[ + Achtung: Die Eingabe der Preise ist zur Zeit in <b>brutto</b>, die Anzeige der Preise in <b>netto</b>. + ]]></de> + <en><![CDATA[ + Attention: The input of prices is currently in <b>gross</b>, but the display of prices is in <b>net</b>. + ]]></en> + </locale> + + <locale name="control.window.price.brutto.title"> + <de><![CDATA[Brutto Preiseingabe]]></de> + <en><![CDATA[Gross price input]]></en> + </locale> + <locale name="control.window.price.brutto.label"> + <de><![CDATA[Preiseingabe]]></de> + <en><![CDATA[Gross price]]></en> + </locale> + <locale name="control.window.price.brutto.description" html="true"> + <de><![CDATA[ + <p>Bitte gebe dein Bruttopreis ein, dieser Preis wird automatisch als Nettopreis umgewandelt und eingefügt.</p> + ]]></de> + <en><![CDATA[ + <p>Please enter your gross price, this price will automatically be converted and inserted as price.</p> + ]]></en> + </locale> + <!-- Controls --> <locale name="controls.OutputDialog.labelEntityId"> <de><![CDATA[Beleg-Nr.]]></de>