From 802f402ec74c015bb1c35cdbbc521cf5a950b4ea Mon Sep 17 00:00:00 2001
From: Henning Leutz <leutz@pcsg.de>
Date: Mon, 19 Sep 2022 08:20:57 +0200
Subject: [PATCH] refactor: price factor stuff

---
 ajax/calcPriceFactor.php                      |  41 +++
 .../controls/articles/BruttoCalcButton.js     |  62 ++++
 .../articles/windows/PriceFactors.Add.html    |  37 +++
 .../articles/windows/PriceFactors.css         |   5 +
 .../articles/windows/PriceFactors.html        |  68 ++++
 .../controls/articles/windows/PriceFactors.js | 301 ++++++++++++++++++
 6 files changed, 514 insertions(+)
 create mode 100644 ajax/calcPriceFactor.php
 create mode 100644 bin/backend/controls/articles/BruttoCalcButton.js
 create mode 100644 bin/backend/controls/articles/windows/PriceFactors.Add.html
 create mode 100644 bin/backend/controls/articles/windows/PriceFactors.css
 create mode 100644 bin/backend/controls/articles/windows/PriceFactors.html
 create mode 100644 bin/backend/controls/articles/windows/PriceFactors.js

diff --git a/ajax/calcPriceFactor.php b/ajax/calcPriceFactor.php
new file mode 100644
index 0000000..0f08849
--- /dev/null
+++ b/ajax/calcPriceFactor.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * This file contains package_quiqqer_erp_ajax_calculatePriceFactor
+ */
+
+/**
+ *
+ */
+
+use QUI\ERP\Currency\Handler as CurrencyHandler;
+use QUI\ERP\Money\Price;
+
+QUI::$Ajax->registerFunction(
+    'package_quiqqer_erp_ajax_calcPriceFactor',
+    function ($price, $vat, $currency) {
+        $Currency = CurrencyHandler::getCurrency($currency);
+        $price    = Price::validatePrice($price);
+        
+        $nettoSum          = $price;
+        $nettoSumFormatted = $Currency->format($price);
+        $sum               = $price * (($vat + 100) / 100);
+        $sumFormatted      = $Currency->format($sum);
+
+        $valueText = $sumFormatted;
+
+        if (strpos($valueText, '+') === false && strpos($valueText, '-') === false) {
+            $valueText = '+' . $valueText;
+        }
+
+        return [
+            'nettoSum'          => $nettoSum,
+            'nettoSumFormatted' => $nettoSumFormatted,
+            'sum'               => $sum,
+            'sumFormatted'      => $sumFormatted,
+            'valueText'         => $valueText
+        ];
+    },
+    ['price', 'vat', 'currency'],
+    'Permission::checkAdminUser'
+);
diff --git a/bin/backend/controls/articles/BruttoCalcButton.js b/bin/backend/controls/articles/BruttoCalcButton.js
new file mode 100644
index 0000000..32179bf
--- /dev/null
+++ b/bin/backend/controls/articles/BruttoCalcButton.js
@@ -0,0 +1,62 @@
+/**
+ * @module package/quiqqer/erp/bin/backend/controls/articles/BruttoCalcButton
+ * @author www.pcsgde (Henning Leutz)
+ */
+define('package/quiqqer/erp/bin/backend/controls/articles/BruttoCalcButton', [
+
+    'qui/QUI',
+    'qui/controls/Control',
+    'package/quiqqer/products/bin/controls/fields/windows/PriceBrutto',
+
+], function (QUI, QUIButton, PriceBruttoWindow) {
+    "use strict";
+
+    return new Class({
+
+        Type   : 'package/quiqqer/erp/bin/backend/controls/articles/BruttoCalcButton',
+        Extends: QUIButton,
+
+        Binds: [
+            'openBruttoWindow'
+        ],
+
+        options: {
+            Price: null
+        },
+
+        initialize: function (options) {
+            this.parent(options);
+        },
+
+        create: function () {
+            this.$Elm = new Element('button');
+            this.$Elm.set('data-quiid', this.getId());
+            this.$Elm.set('data-qui', 'package/quiqqer/erp/bin/backend/controls/articles/BruttoCalcButton');
+            this.$Elm.set('html', '<span class="fa fa-calculator"></span>');
+
+            this.$Elm.addClass('qui-button');
+            this.$Elm.addEvent('click', (e) => {
+                e.stop();
+                this.openBruttoWindow();
+            });
+
+            return this.$Elm;
+        },
+
+        openBruttoWindow: function () {
+            const Price = this.getAttribute('Price');
+
+            new PriceBruttoWindow({
+                events: {
+                    onOpen: function (Win) {
+                        Win.getContent().set('html', '');
+                    },
+
+                    onSubmit: (Win, value) => {
+                        Price.value = value;
+                    }
+                }
+            }).open();
+        }
+    });
+});
\ No newline at end of file
diff --git a/bin/backend/controls/articles/windows/PriceFactors.Add.html b/bin/backend/controls/articles/windows/PriceFactors.Add.html
new file mode 100644
index 0000000..b9d76b7
--- /dev/null
+++ b/bin/backend/controls/articles/windows/PriceFactors.Add.html
@@ -0,0 +1,37 @@
+<form name="price-factor-add">
+    <table class="data-table data-table-flexbox">
+        <tr>
+            <td>
+                <label class="field-container">
+                    <span class="field-container-item">{{titlePrice}}</span>
+                    <input name="price" class="field-container-field"/>
+                </label>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                <label class="field-container">
+                    <span class="field-container-item">{{titleTitle}}</span>
+                    <input name="title" class="field-container-field"/>
+                </label>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                <label class="field-container">
+                    <span class="field-container-item">{{titlePriority}}</span>
+                    <input name="priority" type="number" class="field-container-field"/>
+                </label>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                <label class="field-container">
+                    <span class="field-container-item">{{titleVat}}</span>
+                    <select name="vat" class="field-container-field">
+                    </select>
+                </label>
+            </td>
+        </tr>
+    </table>
+</form>
\ No newline at end of file
diff --git a/bin/backend/controls/articles/windows/PriceFactors.css b/bin/backend/controls/articles/windows/PriceFactors.css
new file mode 100644
index 0000000..333e743
--- /dev/null
+++ b/bin/backend/controls/articles/windows/PriceFactors.css
@@ -0,0 +1,5 @@
+.quiqqer-erp-priceFactors .pricefactor-index {
+    font-weight: bold;
+    font-size: 10px;
+    margin-right: 5px;
+}
\ No newline at end of file
diff --git a/bin/backend/controls/articles/windows/PriceFactors.html b/bin/backend/controls/articles/windows/PriceFactors.html
new file mode 100644
index 0000000..7e4b869
--- /dev/null
+++ b/bin/backend/controls/articles/windows/PriceFactors.html
@@ -0,0 +1,68 @@
+<table class="data-table data-table-flexbox quiqqer-erp-priceFactors">
+    <thead>
+    <tr>
+        <th class="quiqqer-erp-priceFactors-button">
+            <button name="add-pricefactor" disabled class="qui-button" style="float: right">
+                <span class="fa fa plus"></span>
+                <span>{{textAddButton}}</span>
+            </button>
+        </th>
+    </tr>
+    </thead>
+    <tbody>
+    {{#priceFactors}}
+    <tr data-index="{{index}}">
+        <td>
+            <div class="field-container">
+                <label style="width: 100%; display: flex;">
+                    <span class="field-container-item">
+                        <span class="pricefactor-index">#{{priority}}</span>
+                        {{title}}
+                    </span>
+                    <span class="field-container-field">{{valueText}}</span>
+                </label>
+                <button class="qui-button delete" style="width: 50px; cursor: pointer;">
+                    <span class="fa fa-close"></span>
+                </button>
+            </div>
+        </td>
+    </tr>
+    {{/priceFactors}}
+    {{^priceFactors}}
+    <tr>
+        <td>{{textNoFactors}}</td>
+    </tr>
+    {{/priceFactors}}
+    </tbody>
+</table>
+
+<table class="data-table data-table-flexbox quiqqer-erp-backend-temporaryErp-summaryWin-total">
+    <tbody>
+    {{#vatArray}}
+    <tr>
+        <td>
+            <label class="field-container">
+                <span class="field-container-item vat-title">{{text}}</span>
+                <span class="field-container-field vat-value">{{sum}}</span>
+            </label>
+        </td>
+    </tr>
+    {{/vatArray}}
+    <tr>
+        <td>
+            <label class="field-container">
+                <span class="field-container-item netto-title">{{textNetto}}</span>
+                <span class="field-container-field netto-value"></span>
+            </label>
+        </td>
+    </tr>
+    <tr>
+        <td>
+            <label class="field-container">
+                <span class="field-container-item brutto-title">{{textBrutto}}</span>
+                <span class="field-container-field brutto-value"></span>
+            </label>
+        </td>
+    </tr>
+    </tbody>
+</table>
diff --git a/bin/backend/controls/articles/windows/PriceFactors.js b/bin/backend/controls/articles/windows/PriceFactors.js
new file mode 100644
index 0000000..05a3858
--- /dev/null
+++ b/bin/backend/controls/articles/windows/PriceFactors.js
@@ -0,0 +1,301 @@
+/**
+ * @module package/quiqqer/erp/bin/backend/controls/articles/windows/PriceFactors
+ * @author www.pcsg.de (Henning Leutz)
+ */
+define('package/quiqqer/erp/bin/backend/controls/articles/windows/PriceFactors', [
+
+    'qui/QUI',
+    'qui/controls/windows/Popup',
+    'qui/controls/windows/Confirm',
+    'package/quiqqer/currency/bin/Currency',
+    'Ajax',
+    'Locale',
+    'Mustache',
+
+    "text!package/quiqqer/erp/bin/backend/controls/articles/windows/PriceFactors.html",
+    "text!package/quiqqer/erp/bin/backend/controls/articles/windows/PriceFactors.Add.html",
+    "css!package/quiqqer/erp/bin/backend/controls/articles/windows/PriceFactors.css"
+
+], function (QUI, QUIWindow, QUIConfirm, Currency, QUIAjax, QUILocale, Mustache, template, templateAdd) {
+    "use strict";
+
+    const lg = 'quiqqer/erp';
+
+    return new Class({
+
+        Extends: QUIWindow,
+        Type   : 'package/quiqqer/erp/bin/backend/controls/articles/windows/PriceFactors',
+
+        Binds: [
+            '$onOpen'
+        ],
+
+        options: {
+            ArticleList: null
+        },
+
+        initialize: function (option) {
+            this.setAttributes({
+                title    : QUILocale.get(lg, 'pricefactors.summary.window.title'),
+                buttons  : false,
+                maxHeight: 600,
+                maxWidth : 600,
+            });
+
+            this.parent(option);
+
+            this.$Formatter = null;
+
+            this.addEvents({
+                onOpen: this.$onOpen
+            });
+        },
+
+        $onOpen: function () {
+            this.refresh();
+        },
+
+        /**
+         * Return the article list
+         *
+         * @returns {*}
+         */
+        getArticleList: function () {
+            return this.getAttribute('ArticleList');
+        },
+
+        refresh: function () {
+            if (!this.getAttribute('ArticleList')) {
+                this.close();
+                return;
+            }
+
+            this.Loader.show();
+
+            const ArticleList = this.getAttribute('ArticleList');
+            const Content = this.getContent();
+
+            let priceFactors = ArticleList.getPriceFactors();
+            let calculations = ArticleList.getCalculation();
+
+            if (typeof calculations.vatArray === 'undefined') {
+                calculations.vatArray = {};
+            }
+
+            for (let i = 0, len = priceFactors.length; i < len; i++) {
+                priceFactors[i].index = i;
+                priceFactors[i].priority = i + 1;
+            }
+
+            Content.set({
+                html: Mustache.render(template, {
+                    textAddButton: QUILocale.get(lg, 'add.pricefactor.button'),
+                    textNoFactors: QUILocale.get(lg, 'message.pricefactor.empty'),
+                    textNetto    : QUILocale.get(lg, 'article.summary.tpl.labelNet'),
+                    textBrutto   : QUILocale.get(lg, 'article.summary.tpl.labelGross'),
+                    priceFactors : priceFactors,
+                    vatArray     : Object.values(calculations.vatArray)
+                })
+            });
+
+            const PriceFactorButton = Content.getElement('[name="add-pricefactor"]');
+
+            this.getCurrencyFormatter().then((Formatter) => {
+                const Total = Content.getElement('.quiqqer-erp-backend-temporaryErp-summaryWin-total');
+                let calc = calculations.calculations;
+
+                if (!calc) {
+                    calc = {
+                        nettoSum: 0,
+                        sum     : 0
+                    };
+                }
+
+                Total.getElement('.netto-value').set('html', Formatter.format(calc.nettoSum));
+                Total.getElement('.brutto-value').set('html', Formatter.format(calc.sum));
+
+                Content.getElements('.delete').addEvent('click', (e) => {
+                    e.stop();
+                    let index = e.target.getParent('tr').get('data-index');
+
+                    ArticleList.removePriceFactor(index);
+                    this.refresh();
+                });
+
+                PriceFactorButton.addEvent('click', (e) => {
+                    e.stop();
+                    this.addPriceFactor();
+                });
+
+                PriceFactorButton.disabled = false;
+
+                this.fireEvent('quiqqerErpPriceFactorWindow', [this]);
+                QUI.fireEvent('quiqqerErpPriceFactorWindow', [this]);
+
+                this.Loader.hide();
+            });
+        },
+
+        /**
+         * opens the add price factor window
+         */
+        addPriceFactor: function () {
+            const ArticleList = this.getAttribute('ArticleList');
+            let calculations = ArticleList.getCalculation();
+
+            if (typeof calculations.vatArray === 'undefined') {
+                calculations.vatArray = {};
+            }
+
+            new QUIConfirm({
+                icon     : 'fa fa-plus',
+                title    : QUILocale.get(lg, 'pricefactors.summary.window.title'),
+                maxHeight: 400,
+                maxWidth : 580,
+                autoclose: false,
+                events   : {
+                    onOpen: (Win) => {
+                        Win.Loader.show();
+
+                        Win.getContent().set({
+                            html: Mustache.render(templateAdd, {
+                                titlePrice   : QUILocale.get(lg, 'title.price'),
+                                titleTitle   : QUILocale.get(lg, 'title.title'),
+                                titlePriority: QUILocale.get(lg, 'title.priority'),
+                                titleVat     : QUILocale.get(lg, 'title.vat'),
+
+                                calculationBasis          : QUILocale.get(lg, 'calculationBasis'),
+                                calculationBasisNetto     : QUILocale.get(lg, 'calculationBasis.netto'),
+                                calculationBasisCalcPrice : QUILocale.get(lg, 'calculationBasis.calculationBasisCalcPrice'),
+                                calculationBasisCalcBrutto: QUILocale.get(lg, 'calculationBasis.calculationBasisCalcBrutto'),
+                            })
+                        });
+
+                        require([
+                            'package/quiqqer/erp/bin/backend/controls/articles/BruttoCalcButton'
+                        ], (Calc) => {
+                            new Calc({
+                                Price: Win.getContent().getElement('[name="price"]')
+                            }).inject(
+                                Win.getContent().getElement('[name="price"]'),
+                                'after'
+                            );
+
+                            Win.getContent()
+                               .getElement('[name="priority"]')
+                               .set('value', ArticleList.countPriceFactors() + 1);
+
+                            // vat
+                            const VatSelect = Win.getContent().getElement('[name="vat"]');
+
+                            for (let vat in calculations.calculations.vatArray) {
+                                new Element('option', {
+                                    html : vat + '%',
+                                    value: vat
+                                }).inject(VatSelect);
+                            }
+
+
+                            Win.Loader.hide();
+                        });
+                    },
+
+                    onSubmit: (Win) => {
+                        const Form = Win.getContent().getElement('form');
+                        const price = Form.elements.price.value;
+                        const currency = ArticleList.getAttribute('currency');
+
+                        if (!price || price === '') {
+                            return;
+                        }
+
+                        Win.Loader.show();
+
+                        this.getPriceFactorData(
+                            price,
+                            Form.elements.vat.value,
+                            currency
+                        ).then((data) => {
+                            let priority = Form.elements.priority.value;
+
+                            if (priority === '') {
+                                priority = 1;
+                            }
+
+                            let priceFactor = {
+                                calculation      : 2,
+                                calculation_basis: 2,
+                                description      : Form.elements.title.value,
+                                identifier       : "",
+                                index            : priority - 1,
+                                nettoSum         : data.nettoSum,
+                                nettoSumFormatted: data.nettoSumFormatted,
+                                sum              : data.sum,
+                                sumFormatted     : data.sumFormatted,
+                                title            : Form.elements.title.value,
+                                value            : data.sum,
+                                valueText        : data.valueText,
+                                vat              : Form.elements.vat.value,
+                                visible          : 1
+                            };
+
+                            ArticleList.addPriceFactor(priceFactor);
+                            Win.close();
+                            this.refresh();
+                        });
+                    }
+                }
+            }).open();
+        },
+
+        /**
+         * returns the current currency formatter of the article list
+         *
+         * @returns {*}
+         */
+        getCurrencyFormatter: function () {
+            if (this.$Formatter) {
+                return Promise.resolve(this.$Formatter);
+            }
+
+            // admin format
+            return new Promise((resolve) => {
+                let currency = null;
+
+                if (this.getAttribute('currency')) {
+                    currency = this.getAttribute('currency');
+                }
+
+                Currency.getCurrency(currency).then((currency) => {
+                    this.$Formatter = QUILocale.getNumberFormatter({
+                        style                : 'currency',
+                        currency             : currency.code,
+                        minimumFractionDigits: currency.precision,
+                        maximumFractionDigits: currency.precision
+                    });
+
+                    resolve(this.$Formatter);
+                });
+            });
+        },
+
+        /**
+         * Return the data for the price factor
+         *
+         * @param price
+         * @param vat
+         * @param currency
+         * @returns {*}
+         */
+        getPriceFactorData: function (price, vat, currency) {
+            return new Promise(function (resolve) {
+                QUIAjax.get('package_quiqqer_erp_ajax_calcPriceFactor', resolve, {
+                    'package': 'quiqqer/erp',
+                    price    : price,
+                    vat      : vat,
+                    currency : currency
+                });
+            });
+        }
+    });
+});
-- 
GitLab