diff --git a/ajax/manufacturers/create/getGroups.php b/ajax/manufacturers/create/getGroups.php new file mode 100644 index 0000000000000000000000000000000000000000..4913350ad9f92f3fb8584bc2ce337b5a611981f7 --- /dev/null +++ b/ajax/manufacturers/create/getGroups.php @@ -0,0 +1,29 @@ +<?php + +use QUI\ERP\Manufacturers; + +/** + * Get details of manufacturer groups + * + * @return array + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_manufacturers_create_getGroups', + function () { + $Groups = QUI::getGroups(); + $groups = []; + + foreach (Manufacturers::getManufacturerGroupIds() as $groupId) { + $Group = $Groups->get($groupId); + + $groups[] = [ + 'id' => $Group->getId(), + 'name' => $Group->getName() + ]; + } + + return $groups; + }, + [], + 'Permission::checkAdminUser' +); diff --git a/ajax/manufacturers/create/getNextId.php b/ajax/manufacturers/create/getNextId.php new file mode 100644 index 0000000000000000000000000000000000000000..78af5f4ec8493d27ac062c11df8cf9b7be363ad1 --- /dev/null +++ b/ajax/manufacturers/create/getNextId.php @@ -0,0 +1,28 @@ +<?php + +use QUI\ERP\Manufacturers; + +/** + * Format a price for the admin + * + * @param string|int|float $value + * @return string + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_manufacturers_create_getNextId', + function () { + $result = QUI::getDataBase()->fetch([ + 'from' => QUI::getUsers()->table(), + 'limit' => 1, + 'order' => 'id DESC' + ]); + + if (!isset($result[0])) { + return 1; + } + + return (int)$result[0]['id'] + 1; + }, + [], + 'Permission::checkAdminUser' +); diff --git a/ajax/manufacturers/getGroupIds.php b/ajax/manufacturers/getGroupIds.php new file mode 100644 index 0000000000000000000000000000000000000000..1e753efe6be8ac7b62b03611f9663c3807a26be2 --- /dev/null +++ b/ajax/manufacturers/getGroupIds.php @@ -0,0 +1,18 @@ +<?php + +use QUI\ERP\Manufacturers; + +/** + * Format a price for the admin + * + * @param string|int|float $value + * @return string + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_manufacturers_getGroupIds', + function () { + return Manufacturers::getManufacturerGroupIds(); + }, + [], + 'Permission::checkAdminUser' +); diff --git a/ajax/manufacturers/search.php b/ajax/manufacturers/search.php new file mode 100644 index 0000000000000000000000000000000000000000..4735d7079ee36cdbd6402d7dc70554e23b787f8a --- /dev/null +++ b/ajax/manufacturers/search.php @@ -0,0 +1,27 @@ +<?php + +use QUI\Utils\Security\Orthos; +use QUI\Utils\Grid; +use QUI\ERP\Manufacturers; + +/** + * Execute the customer search + * + * @return array + */ +QUI::$Ajax->registerFunction( + 'package_quiqqer_erp_ajax_manufacturers_search', + function ($params) { + $searchParams = Orthos::clearArray(\json_decode($params, true)); + + $results = Manufacturers::search($searchParams); + $Grid = new Grid($searchParams); + + return $Grid->parseResult( + Manufacturers::parseListForGrid($results), + Manufacturers::search($searchParams, true) + ); + }, + ['params'], + 'Permission::checkAdminUser' +); diff --git a/bin/backend/Manufacturers.js b/bin/backend/Manufacturers.js new file mode 100644 index 0000000000000000000000000000000000000000..9bd6c32237101fce866c17557deb2da08600bdaa --- /dev/null +++ b/bin/backend/Manufacturers.js @@ -0,0 +1,14 @@ +/** + * Manufacturers JavaScript handler + * + * @module package/quiqqer/erp/bin/backend/Manufacturers + * @author www.pcsg.de (Patrick Müller) + */ +define('package/quiqqer/erp/bin/backend/Manufacturers', [ + + 'package/quiqqer/erp/bin/backend/classes/Manufacturers', + +], function (Manufacturers) { + "use strict"; + return new Manufacturers(); +}); diff --git a/bin/backend/classes/Manufacturers.js b/bin/backend/classes/Manufacturers.js new file mode 100644 index 0000000000000000000000000000000000000000..9830e3aaca648f5d500289666eb923379f1c0b8a --- /dev/null +++ b/bin/backend/classes/Manufacturers.js @@ -0,0 +1,50 @@ +/** + * Manufacturers JavaScript handler + * + * @module package/quiqqer/erp/bin/backend/classes/Manufacturers + * @author www.pcsg.de (Patrick Müller) + */ +define('package/quiqqer/erp/bin/backend/classes/Manufacturers', [ + + 'qui/classes/DOM', + 'Ajax' + +], function (QUIDOM, QUIAjax) { + "use strict"; + + var pkg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIDOM, + Type : 'package/quiqqer/erp/bin/backend/classes/Manufacturers', + + /** + * Get IDs of manufacturer groups + * + * @return {Promise} + */ + getManufacturerGroupIds: function () { + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_manufacturers_getGroupIds', resolve, { + 'package': pkg, + onError : reject + }); + }); + }, + + /** + * Get details of manufacturer groups + * + * @return {Promise} + */ + getManufacturerGroups: function () { + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_erp_ajax_manufacturers_create_getGroups', resolve, { + 'package': pkg, + onError : reject + }); + }); + } + }); +}); diff --git a/bin/backend/controls/manufacturers/Administration.css b/bin/backend/controls/manufacturers/Administration.css new file mode 100644 index 0000000000000000000000000000000000000000..b115f5dbd433365dfa8997aebc516e6ea3f98916 --- /dev/null +++ b/bin/backend/controls/manufacturers/Administration.css @@ -0,0 +1,102 @@ +.quiqqer-erp-manufacturers-administration { + display: flex; + flex-direction: column; + height: 100%; + position: relative; +} + +/** header / search / filter + =============================== */ + +.quiqqer-erp-manufacturers-administration-search { + background: #e1e4e9; + clear: both; + padding: 20px; + width: 100%; +} + +.quiqqer-erp-manufacturers-administration-search [name="customer-search"] { + float: left; + width: calc(100% - 100px); +} + +.quiqqer-erp-manufacturers-administration-search [name="add"] { + margin-right: 10px; +} + +.quiqqer-erp-manufacturers-administration-search [name="filter"] { + display: inline-block; + float: initial; + margin-left: 10px; +} + +.quiqqer-erp-manufacturers-administration-search [name="search"] { + float: left; + width: 280px; +} + +.quiqqer-erp-manufacturers-administration-search [name="submit"] { + border: none; +} + +.quiqqer-erp-manufacturers-administration-search-filter { + background: #eff0f3; + clear: both; + display: block; + margin-top: 20px; + padding: 10px; + width: 100%; +} + +.quiqqer-erp-manufacturers-administration-search-filter section { + display: inline-block; + width: 100%; +} + +.quiqqer-erp-manufacturers-administration-search-filter input { + padding: 2px; + font-size: 12px; +} + +.quiqqer-erp-manufacturers-administration-search-filter .title { + display: inline-block; + padding-bottom: 5px; + width: 100%; +} + +.quiqqer-erp-manufacturers-administration-search-filter section + section { + margin-top: 20px; +} + +.quiqqer-erp-manufacturers-administration-search-filter-checks label { + float: left; + width: 25%; +} + +.quiqqer-erp-manufacturers-administration-search-filter-specs label { + float: left; + width: 25%; +} + +/** grid / result + =============================== */ + +.quiqqer-erp-manufacturers-administration-grid { + clear: both; + flex-grow: 1; + overflow: hidden; + padding: 20px; + width: 100%; +} + +/** customer panel in grid + =============================== */ + +.quiqqer-erp-manufacturers-administration-customer { + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; + z-index: 1; +} diff --git a/bin/backend/controls/manufacturers/Administration.html b/bin/backend/controls/manufacturers/Administration.html new file mode 100644 index 0000000000000000000000000000000000000000..e9388b5e35c499f52740fb547283f9445b236b86 --- /dev/null +++ b/bin/backend/controls/manufacturers/Administration.html @@ -0,0 +1,92 @@ +<div class="quiqqer-erp-manufacturers-administration-filter"> +</div> +<div class="quiqqer-erp-manufacturers-administration-search"> + <form name="customer-search"> + <label style="display: inline-block; float: left;"> + <input type="text" + name="search" + placeholder="{{searchPlaceholder}}" + /> + <input type="submit" + name="submit" + value="Search" + class="qui-button" + /> + </label> + + <button class="qui-button" name="filter"> + <span class="fa fa-filter"></span> + </button> + + <div class="quiqqer-erp-manufacturers-administration-search-filter" style="display: none"> + <section class="quiqqer-erp-manufacturers-administration-search-filter-checks"> + <span class="title"> + {{filterTitle}} + </span> + + <label> + <input type="checkbox" name="userId"/> + <span> + {{filterUserId}} + </span> + </label> + + <label> + <input type="checkbox" name="username"/> + <span> + {{filterUsername}} + </span> + </label> + + <label> + <input type="checkbox" name="firstname"/> + <span> + {{filterFirstname}} + </span> + </label> + + <label> + <input type="checkbox" name="lastname"/> + <span> + {{filterLastname}} + </span> + </label> + + <label> + <input type="checkbox" name="email"/> + <span> + {{filterEmail}} + </span> + </label> + + <label> + <input type="checkbox" name="company"/> + <span> + {{filterCompany}} + </span> + </label> + </section> + + <section class="quiqqer-erp-manufacturers-administration-search-filter-specs"> + <span class="title"> + {{dateFilterTitle}} + </span> + + <label> + <span> + {{dateFilterFrom}} + </span> + <input type="date" name="registration-from"/> + </label> + + <label> + <span> + {{dateFilterTo}} + </span> + <input type="date" name="registration-to"/> + </label> + </section> + </div> + </form> +</div> +<div class="quiqqer-erp-manufacturers-administration-grid"></div> diff --git a/bin/backend/controls/manufacturers/Administration.js b/bin/backend/controls/manufacturers/Administration.js new file mode 100644 index 0000000000000000000000000000000000000000..2744b37e5f4cee6cd6517496edb1acc56c8c9579 --- /dev/null +++ b/bin/backend/controls/manufacturers/Administration.js @@ -0,0 +1,725 @@ +/** + * @module package/quiqqer/erp/bin/backend/controls/manufacturers/Administration + * @author www.pcsg.de (Patrick Müller) + * + * @event manufacturerOpenBegin [self, userId] + * @event onManufacturerOpen [self, userId, Panel] + * @event onManufacturerOpenEnd [self, userId, Panel] + * @event onListOpen [self] + */ +define('package/quiqqer/erp/bin/backend/controls/manufacturers/Administration', [ + + 'qui/controls/Control', + 'qui/controls/windows/Confirm', + 'utils/Panels', + + 'package/quiqqer/erp/bin/backend/Manufacturers', + + 'controls/grid/Grid', + 'Mustache', + 'Locale', + 'Ajax', + 'Users', + + 'text!package/quiqqer/erp/bin/backend/controls/manufacturers/Administration.html', + 'css!package/quiqqer/erp/bin/backend/controls/manufacturers/Administration.css' + +], function (QUIControl, QUIConfirm, QUIPanelUtils, Manufacturers, Grid, Mustache, QUILocale, QUIAjax, Users, + template) { + "use strict"; + + var lg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIControl, + Type : 'package/quiqqer/erp/bin/backend/controls/manufacturers/Administration', + + Binds: [ + '$onInject', + '$onDestroy', + '$onUserRefresh', + '$onUserChange', + '$editComplete', + '$gridDblClick', + '$gridClick', + 'refresh', + 'toggleFilter', + 'openDeleteWindow', + 'openAddWindow' + ], + + options: { + page : 1, + perPage : 50, + editable : true, + submittable : false, + add : true, + manufacturerId: false + }, + + initialize: function (options) { + this.parent(options); + + this.$SearchContainer = null; + this.$SearchInput = null; + this.$FilterButton = null; + this.$manufacturerGroupIds = []; + + this.$ManufacturerPanel = null; + this.$GroupSwitch = null; + this.$GridContainer = null; + this.$Grid = null; + + this.addEvents({ + onInject : this.$onInject, + onDestroy: this.$onDestroy + }); + + Users.addEvents({ + onSwitchStatus: this.$onUserChange, + onDelete : this.$onUserChange, + onRefresh : this.$onUserRefresh, + onSave : this.$onUserRefresh + }); + }, + + /** + * Create the DOMNode element + */ + create: function () { + var self = this; + + this.$Elm = new Element('div', { + 'class': 'quiqqer-erp-manufacturers-administration', + html : Mustache.render(template, { + searchPlaceholder: QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.searchPlaceholder'), + filterTitle : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.filterTitle'), + filterUserId : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.filterUserId'), + filterUsername : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.filterUsername'), + filterFirstname : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.filterFirstname'), + filterLastname : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.filterLastname'), + filterEmail : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.filterEmail'), + filterCompany : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.filterCompany'), + dateFilterTitle : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.dateFilterTitle'), + dateFilterFrom : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.dateFilterFrom'), + dateFilterTo : QUILocale.get(lg, 'controls.manufacturers.Administration.tpl.dateFilterTo') + }) + }); + + this.$SearchContainer = this.$Elm.getElement('.quiqqer-erp-manufacturers-administration-search'); + this.$GridContainer = this.$Elm.getElement('.quiqqer-erp-manufacturers-administration-grid'); + this.$SearchInput = this.$Elm.getElement('[name="search"]'); + this.$SubmitButton = this.$Elm.getElement('[name="submit"]'); + this.$FilterButton = this.$Elm.getElement('button[name="filter"]'); + + this.$FilterButton.addEvent('click', function (event) { + event.stop(); + self.toggleFilter(); + }); + + this.$SearchContainer.getElement('form').addEvent('submit', function (event) { + event.stop(); + }); + + this.$SubmitButton.addEvent('click', function () { + self.refresh(); + }); + + this.$SearchInput.addEvent('keydown', function (event) { + if (event.key === 'enter') { + event.stop(); + } + }); + + this.$SearchInput.addEvent('keyup', function (event) { + if (event.key === 'enter') { + self.refresh(); + } + }); + + if (!this.getAttribute('add')) { + this.$AddButton.setStyle('display', 'none'); + } + + // create grid + this.$Container = new Element('div'); + this.$Container.inject(this.$GridContainer); + + var columnModel = []; + + if (this.getAttribute('submittable')) { + columnModel.push({ + header : ' ', + dataIndex: 'submit_button', + dataType : 'node', + width : 60 + }); + } + + columnModel.push({ + header : QUILocale.get(lg, 'controls.manufacturers.Administration.tbl.header.active_status'), + dataIndex: 'active_status', + dataType : 'node', + width : 40 + }); + + columnModel.push({ + header : QUILocale.get('quiqqer/quiqqer', 'id'), + dataIndex: 'id', + dataType : 'integer', + width : 100 + }); + + /*{ + header : QUILocale.get('quiqqer/quiqqer', 'username'), + dataIndex: 'username', + dataType : 'integer', + width : 150, + editable : editable, + className: editable ? 'clickable' : '' + }*/ + + columnModel.push({ + header : QUILocale.get('quiqqer/quiqqer', 'company'), + dataIndex: 'company', + dataType : 'string', + width : 150, + }); + + columnModel.push({ + header : QUILocale.get('quiqqer/quiqqer', 'firstname'), + dataIndex: 'firstname', + dataType : 'string', + width : 150, + }); + + columnModel.push({ + header : QUILocale.get('quiqqer/quiqqer', 'lastname'), + dataIndex: 'lastname', + dataType : 'string', + width : 150, + }); + + columnModel.push({ + header : QUILocale.get('quiqqer/quiqqer', 'email'), + dataIndex: 'email', + dataType : 'string', + width : 150, + }); + + columnModel.push({ + header : QUILocale.get('quiqqer/quiqqer', 'group'), + dataIndex: 'usergroup_display', + dataType : 'string', + width : 150, + }); + + columnModel.push({ + dataIndex: 'usergroup', + dataType : 'string', + hidden : true + }); + + columnModel.push({ + header : QUILocale.get('quiqqer/quiqqer', 'c_date'), + dataIndex: 'regdate', + dataType : 'date', + width : 150 + }); + + this.$Grid = new Grid(this.$Container, { + buttons: [{ + name : 'add', + textimage: 'fa fa-plus', + text : QUILocale.get(lg, 'manufacturer.window.create.title'), + events : { + onClick: self.openAddWindow + } + }/*, { + name : 'delete', + textimage: 'fa fa-trash', + text : QUILocale.get(lg, 'manufacturer.window.delete.title'), + disabled : true, + styles : { + 'float': 'right' + }, + events : { + onClick: self.openDeleteWindow + } + }*/], + + columnModel : columnModel, + pagination : true, + filterInput : true, + perPage : this.getAttribute('perPage'), + page : this.getAttribute('page'), + sortOn : this.getAttribute('field'), + serverSort : true, + showHeader : true, + sortHeader : true, + alternaterows : true, + resizeColumns : true, + selectable : true, + multipleSelection: true, + resizeHeaderOnly : true + }); + + // Events + this.$Grid.addEvents({ + onClick : this.$gridClick, + onDblClick: this.$gridDblClick, + // onBlur : this.$gridBlur, + refresh : this.refresh + }); + + return this.$Elm; + }, + + /** + * event: on inject + */ + $onInject: function () { + var self = this; + + this.$Grid.disable(); + + Manufacturers.getManufacturerGroupIds().then(function (manufacturerGroupIds) { + self.$manufacturerGroupIds = manufacturerGroupIds; + + // Show info if no manufacturer groups have been defined yet + if (!self.$manufacturerGroupIds.length) { + new QUIConfirm({ + maxHeight: 300, + autoclose: true, + + information: QUILocale.get(lg, 'controls.manufacturers.Administration.no_group.information'), + title : QUILocale.get(lg, 'controls.manufacturers.Administration.no_group.title'), + texticon : 'fa fa-exclamation-triangle', + text : QUILocale.get(lg, 'controls.manufacturers.Administration.no_group.text'), + icon : 'fa fa-exclamation-triangle', + + cancel_button: false, + ok_button : { + text : QUILocale.get(lg, 'controls.manufacturers.Administration.no_group.submit'), + textimage: 'icon-ok fa fa-check' + } + }).open(); + + return; + } + + self.refresh().then(function () { + self.$Grid.enable(); + }); + }); + }, + + /** + * Triggers if user double clicks a grid row + */ + $gridDblClick: function () { + var userId = this.$Grid.getSelectedData()[0].id; + QUIPanelUtils.openUserPanel(userId); + }, + + /** + * Is the administration in a qui window? + * + * @return {boolean} + */ + isInWindow: function () { + return !!this.getElm().getParent('.qui-window-popup'); + }, + + /** + * event: on user change + */ + $onUserRefresh: function () { + this.refresh(); + }, + + /** + * event: on user status change + * + * @param Users + * @param ids + */ + $onUserChange: function (Users, ids) { + var i, len; + var data = this.$Grid.getData(); + + if (typeOf(ids) === 'array') { + var tmp = {}; + + for (i = 0, len = ids.length; i < len; i++) { + tmp[ids[i]] = true; + } + + ids = tmp; + } + + for (i = 0, len = data.length; i < len; i++) { + if (typeof ids[data[i].id] === 'undefined') { + continue; + } + + // use is in list, refresh + this.refresh(); + break; + } + }, + + /** + * event: on control destroy + */ + $onDestroy: function () { + Users.removeEvents({ + onSwitchStatus: this.$onUserChange, + onDelete : this.$onUserChange, + onRefresh : this.$onUserRefresh, + onSave : this.$onUserRefresh + }); + }, + + /** + * return all selected manufacturer ids + * + * @return {Array} + */ + getSelectedManufacturerIds: function () { + if (this.$ManufacturerPanel) { + return [this.$ManufacturerPanel.getAttribute('userId')]; + } + + return this.$Grid.getSelectedData().map(function (entry) { + return parseInt(entry.id); + }); + }, + + /** + * return all selected manufacturer + * + * @return {Array} + */ + getSelectedManufacturer: function () { + return this.$Grid.getSelectedData(); + }, + + /** + * Resize the grid + * + * @return {Promise|Promise|Promise|Promise|*} + */ + resize: function () { + if (!this.$Grid) { + return Promise.resolve(); + } + + var size = this.$GridContainer.getSize(); + + return Promise.all([ + this.$Grid.setHeight(size.y - 40), + this.$Grid.setWidth(size.x - 40) + ]); + }, + + /** + * Refresh the grid + */ + refresh: function () { + var self = this, + options = this.$Grid.options, + Form = this.$SearchContainer.getElement('form'); + + var params = { + perPage: options.perPage || 50, + page : options.page || 1, + sortBy : options.sortBy, + sortOn : options.sortOn, + search : this.$SearchInput.value, + filter : { + id : Form.elements.userId.checked ? 1 : 0, + username : Form.elements.username.checked ? 1 : 0, + firstname : Form.elements.firstname.checked ? 1 : 0, + lastname : Form.elements.lastname.checked ? 1 : 0, + email : Form.elements.email.checked ? 1 : 0, + company : Form.elements.company.checked ? 1 : 0, + regdate_from: Form.elements['registration-from'].value, + regdate_to : Form.elements['registration-to'].value + } + }; + + this.fireEvent('refreshBegin', [this]); + + return new Promise(function (resolve) { + QUIAjax.get('package_quiqqer_erp_ajax_manufacturers_search', function (result) { + for (var i = 0, len = result.data.length; i < len; i++) { + // Active status + var activeIcon; + + if (result.data[i].status) { + activeIcon = 'fa fa-check'; + } else { + activeIcon = 'fa fa-remove'; + } + + result.data[i].active_status = new Element('span', { + 'class': activeIcon + }); + } + + self.$Grid.setData(result); + self.fireEvent('refreshEnd', [self]); + resolve(); + }, { + package: 'quiqqer/erp', + params : JSON.encode(params) + }); + }); + }, + + /** + * Set user active status + * + * @param userId + * @param status + * @return {Promise} + */ + $setStatus: function (userId, status) { + var self = this; + + this.$Grid.disable(); + + return new Promise(function (resolve, reject) { + QUIAjax.post('ajax_users_save', function () { + self.$Grid.enable(); + resolve(); + }, { + uid : userId, + attributes: JSON.encode({ + active: status + }), + onError : function (err) { + self.$Grid.enable(); + reject(err); + } + }); + }); + }, + + /** + * Opens the user panel for a manufacturer user + * + * @param {Number} userId + */ + $openManufacturer: function (userId) { + if (!userId) { + return; + } + + var self = this; + + this.fireEvent('manufacturerOpenBegin', [this, userId]); + + require([ + 'package/quiqqer/erp/bin/backend/controls/manufacturers/manufacturer/Panel', + 'utils/Panels' + ], function (Panel, PanelUtils) { + if (self.isInWindow()) { + var Container = new Element('div', { + 'class': 'quiqqer-erp-manufacturers-administration-manufacturer', + styles : { + left : -50, + opacity: 0 + } + }).inject(self.getElm()); + + self.$ManufacturerPanel = new Panel({ + header : false, + userId : userId, + showUserButton : true, + showDeleteButton: false, + events : { + onError: function (Instance) { + if (!Instance.$User) { + self.setAttribute('manufacturerId', false); + } + } + } + }).inject(Container); + + self.fireEvent('manufacturerOpen', [this, userId, self.$ManufacturerPanel]); + + moofx(Container).animate({ + left : 0, + opacity: 1 + }, { + callback: function () { + self.$ManufacturerPanel.fireEvent('show'); + self.fireEvent('manufacturerOpenEnd', [this, userId, self.$ManufacturerPanel]); + } + }); + + return; + } + + PanelUtils.openPanelInTasks( + new Panel({ + userId: userId + }) + ); + }); + }, + + /** + * event: on grid click + */ + $gridClick: function () { + //var selected = this.$Grid.getSelectedData(); + //var Delete = this.$Grid.getButtons().filter(function (Btn) { + // return Btn.getAttribute('name') === 'delete'; + //})[0]; + // + //Delete.disable(); + // + //if (selected.length === 1) { + // Delete.enable(); + //} + }, + + /** + * opens the add manufacturer window + */ + openAddWindow: function () { + var self = this; + + require([ + 'package/quiqqer/erp/bin/backend/controls/manufacturers/create/ManufacturerWindow' + ], function (ManufacturerWindow) { + new ManufacturerWindow({ + events: { + onSubmit: function (Instance, manufacturerId) { + self.refresh(); + self.$openManufacturer(manufacturerId); + } + } + }).open(); + }); + }, + + /** + * opens the manufacturer delete window + */ + openDeleteWindow: function () { + var self = this; + + new QUIConfirm({ + title : QUILocale.get(lg, 'manufacturer.window.delete.title'), + text : QUILocale.get(lg, 'manufacturer.window.delete.text'), + information: QUILocale.get(lg, 'manufacturer.window.delete.information'), + icon : 'fa fa-trash', + texticon : 'fa fa-trash', + maxHeight : 400, + maxWidth : 600, + autoclose : false, + events : { + onSubmit: function (Win) { + Win.Loader.show(); + + var selected = self.$Grid.getSelectedData().map(function (entry) { + return entry.id; + }); + + Users.deleteUsers(selected).then(function () { + Win.close(); + self.refresh(); + }); + } + } + }).open(); + }, + + //region filter + + /** + * Toggle the filter + */ + toggleFilter: function () { + var FilterContainer = this.getElm().getElement('.quiqqer-erp-manufacturers-administration-search-filter'); + + if (FilterContainer.getStyle('display') === 'none') { + this.openFilter(); + } else { + this.closeFilter(); + } + }, + + /** + * Open the filter + */ + openFilter: function () { + var self = this, + FilterContainer = this.getElm().getElement('.quiqqer-erp-manufacturers-administration-search-filter'); + + FilterContainer.setStyle('position', 'absolute'); + FilterContainer.setStyle('opacity', 0); + FilterContainer.setStyle('overflow', 'hidden'); + + // reset + FilterContainer.setStyle('display', null); + FilterContainer.setStyle('height', null); + FilterContainer.setStyle('paddingBottom', null); + FilterContainer.setStyle('paddingTop', null); + + var height = FilterContainer.getSize().y; + + FilterContainer.setStyle('height', 0); + FilterContainer.setStyle('paddingBottom', 0); + FilterContainer.setStyle('paddingTop', 0); + FilterContainer.setStyle('position', null); + + moofx(FilterContainer).animate({ + height : height, + marginTop : 20, + opacity : 1, + paddingBottom: 10, + paddingTop : 10 + }, { + duration: 300, + callback: function () { + self.resize(); + } + }); + }, + + /** + * Close the filter + */ + closeFilter: function () { + var self = this, + FilterContainer = this.getElm().getElement('.quiqqer-erp-manufacturers-administration-search-filter'); + + moofx(FilterContainer).animate({ + height : 0, + marginTop : 0, + opacity : 1, + paddingBottom: 0, + paddingTop : 0 + }, { + duration: 300, + callback: function () { + FilterContainer.setStyle('display', 'none'); + + FilterContainer.setStyle('height', null); + FilterContainer.setStyle('paddingBottom', null); + FilterContainer.setStyle('paddingTop', null); + + self.resize(); + } + }); + } + + //endregion + }); +}); diff --git a/bin/backend/controls/manufacturers/AdministrationPanel.js b/bin/backend/controls/manufacturers/AdministrationPanel.js new file mode 100644 index 0000000000000000000000000000000000000000..3a8253134c7c7d9a78cbe82c67f46663683abde3 --- /dev/null +++ b/bin/backend/controls/manufacturers/AdministrationPanel.js @@ -0,0 +1,76 @@ +/** + * @module package/quiqqer/erp/bin/backend/controls/manufacturers/AdministrationPanel + * @author www.pcsg.de (Patrick Müller) + */ +define('package/quiqqer/erp/bin/backend/controls/manufacturers/AdministrationPanel', [ + + 'qui/controls/desktop/Panel', + 'package/quiqqer/erp/bin/backend/controls/manufacturers/Administration', + 'Locale' + +], function (QUIPanel, Administration, QUILocale) { + "use strict"; + + var lg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIPanel, + Type : 'package/quiqqer/erp/bin/backend/controls/manufacturers/AdministrationPanel', + + Binds: [ + '$onInject' + ], + + initialize: function (options) { + this.parent(options); + + this.setAttributes({ + title: QUILocale.get(lg, 'controls.manufacturers.AdministrationPanel.title'), + icon : 'fa fa-wrench', + name : 'manufacturers-administration' + }); + + this.addEvents({ + onInject : this.$onInject, + onResize : function () { + if (this.$Administration) { + this.$Administration.resize(); + } + + this.Loader.hide(); + }.bind(this), + onDestroy: function () { + if (this.$Administration) { + this.$Administration.destroy(); + } + }.bind(this) + }); + }, + + /** + * Create the DOMNode element + */ + $onInject: function () { + var self = this; + + this.Loader.show(); + this.getContent().set('html', ''); + this.getContent().setStyle('padding', 0); + + this.$Administration = new Administration({ + events: { + onRefreshBegin: function () { + self.Loader.show(); + }, + + onRefreshEnd: function () { + self.Loader.hide(); + } + } + }); + this.$Administration.inject(this.getContent()); + this.$Administration.resize(); + } + }); +}); diff --git a/bin/backend/controls/manufacturers/create/Address.js b/bin/backend/controls/manufacturers/create/Address.js new file mode 100644 index 0000000000000000000000000000000000000000..98c28b78d8c58da7925dcf737465fad3ac84f60b --- /dev/null +++ b/bin/backend/controls/manufacturers/create/Address.js @@ -0,0 +1,15 @@ +define('', [ + + 'qui/QUI', + 'qui/controls/Control' + +], function (QUI, QUIControl) { + "use strict"; + + return new Class({ + + Extends: QUIControl, + Type : '' + + }); +}); \ No newline at end of file diff --git a/bin/backend/controls/manufacturers/create/Details.js b/bin/backend/controls/manufacturers/create/Details.js new file mode 100644 index 0000000000000000000000000000000000000000..98c28b78d8c58da7925dcf737465fad3ac84f60b --- /dev/null +++ b/bin/backend/controls/manufacturers/create/Details.js @@ -0,0 +1,15 @@ +define('', [ + + 'qui/QUI', + 'qui/controls/Control' + +], function (QUI, QUIControl) { + "use strict"; + + return new Class({ + + Extends: QUIControl, + Type : '' + + }); +}); \ No newline at end of file diff --git a/bin/backend/controls/manufacturers/create/Manufacturer.css b/bin/backend/controls/manufacturers/create/Manufacturer.css new file mode 100644 index 0000000000000000000000000000000000000000..97cabbae85b399009f434274d0b1987e48256e42 --- /dev/null +++ b/bin/backend/controls/manufacturers/create/Manufacturer.css @@ -0,0 +1,74 @@ +.quiqqer-erp-manufacturers-create { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; +} + +.quiqqer-erp-manufacturers-create-container { + flex-grow: 1; + overflow: hidden; + position: relative; +} + +.quiqqer-erp-manufacturers-create-button { + background: #dddddd; + clear: both; + height: 50px; + padding: 10px; +} + +.quiqqer-erp-manufacturers-create-button [name="next"] { + float: right; +} + +.quiqqer-erp-manufacturers-create ul { + height: 100%; + margin: 0; + padding: 0; + position: relative; + width: 100%; +} + +.quiqqer-erp-manufacturers-create li { + clear: both; + height: 100%; + list-style-type: none; + margin: 0; + padding: 20px; + width: 100%; +} + +.quiqqer-erp-manufacturers-create section { + height: 100%; + overflow: auto; +} + +.quiqqer-erp-manufacturers-create-manufacturerNo { + align-items: center; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; +} + +.quiqqer-erp-manufacturers-create-manufacturerNo label { + clear: both; + display: block; + margin: 20px auto; + text-align: left; + width: 300px; +} + +.quiqqer-erp-manufacturers-create-manufacturerNo input { + clear: both; + font-size: 16px; + margin-top: 10px; + padding: 10px; + width: 100%; +} + +.quiqqer-erp-manufacturers-create-manufacturerGroups-container table, +.quiqqer-erp-manufacturers-create-manufacturerData-container table { + margin-top: 20px; +} diff --git a/bin/backend/controls/manufacturers/create/Manufacturer.html b/bin/backend/controls/manufacturers/create/Manufacturer.html new file mode 100644 index 0000000000000000000000000000000000000000..6d2cb4bbd23348ed299520ee785e3c0b2eb9f38a --- /dev/null +++ b/bin/backend/controls/manufacturers/create/Manufacturer.html @@ -0,0 +1,126 @@ +<form class="quiqqer-erp-manufacturers-create-container"> + <ul> + <li> + <section class="quiqqer-erp-manufacturers-create-manufacturerNo"> + <h1>{{manufacturerNoHeader}}</h1> + {{{manufacturerNoText}}} + + <label> + <span>{{manufacturerNoInputHeader}}</span> + <input type="text" name="manufacturerId"/> + </label> + </section> + </li> + <li> + <section class="quiqqer-erp-manufacturers-create-manufacturerData"> + <div class="quiqqer-erp-manufacturers-create-manufacturerData-container"> + <h1>{{manufacturerDataHeader}}</h1> + {{{manufacturerDataText}}} + + <table class="data-table data-table-flexbox"> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressCompany}} + </span> + <input type="text" name="address-company" value="" class="field-container-field"> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressSalutation}} + </span> + <input type="text" name="address-salutation" value="" class="field-container-field"> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressFirstname}} + </span> + <input type="text" name="address-firstname" value="" class="field-container-field"> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressLastname}} + </span> + <input type="text" name="address-lastname" value="" class="field-container-field"> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressStreet}} + </span> + <input type="text" name="address-street_no" value="" class="field-container-field"> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressZIP}} + </span> + <input type="text" name="address-zip" value="" class="field-container-field"> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressCity}} + </span> + <input type="text" name="address-city" value="" class="field-container-field"> + </label> + </td> + </tr> + <tr> + <td> + <label class="field-container"> + <span class="field-container-item"> + {{textAddressCountry}} + </span> + <select type="text" name="address-country" class="field-container-field"> + <option value=""></option> + </select> + </label> + </td> + </tr> + </table> + </div> + </section> + </li> + <li> + <section class="quiqqer-erp-manufacturers-create-manufacturerGroups"> + <div class="quiqqer-erp-manufacturers-create-manufacturerGroups-container"> + <h1>{{manufacturerGroupsHeader}}</h1> + {{{manufacturerGroupsText}}} + + <ul class="quiqqer-erp-manufacturers-create-manufacturerGroups-list"></ul> + </div> + </section> + </li> + </ul> +</form> +<div class="quiqqer-erp-manufacturers-create-button"> + <button class="qui-button" name="previous"> + {{previousButton}} + </button> + <button class="qui-button" name="next"> + {{nextButton}} + </button> +</div> diff --git a/bin/backend/controls/manufacturers/create/Manufacturer.js b/bin/backend/controls/manufacturers/create/Manufacturer.js new file mode 100644 index 0000000000000000000000000000000000000000..0755c2f442365e02cafe04deaa2d0339da8c8780 --- /dev/null +++ b/bin/backend/controls/manufacturers/create/Manufacturer.js @@ -0,0 +1,329 @@ +/** + * @module package/quiqqer/erp/bin/backend/controls/manufacturers/create/Manufacturer + * @author www.pcsg.de (Patrick Müller) + */ +define('package/quiqqer/erp/bin/backend/controls/manufacturers/create/Manufacturer', [ + + 'qui/QUI', + 'qui/controls/Control', + 'package/quiqqer/countries/bin/Countries', + 'Locale', + 'Ajax', + 'Mustache', + + 'package/quiqqer/erp/bin/backend/Manufacturers', + + 'text!package/quiqqer/erp/bin/backend/controls/manufacturers/create/Manufacturer.html', + 'css!package/quiqqer/erp/bin/backend/controls/manufacturers/create/Manufacturer.css' + +], function (QUI, QUIControl, Countries, QUILocale, QUIAjax, Mustache, Manufacturers, template) { + "use strict"; + + var lg = 'quiqqer/erp'; + + return new Class({ + + Extends: QUIControl, + Type : 'package/quiqqer/erp/bin/backend/controls/manufacturers/create/Manufacturer', + + Binds: [ + '$onInject', + 'next', + 'previous' + ], + + initialize: function (options) { + this.parent(options); + + this.$Container = null; + this.$List = null; + this.$Form = null; + this.$GroupList = null; + + this.addEvents({ + onInject: this.$onInject + }); + }, + + /** + * event: on create + * + * @return {HTMLDivElement} + */ + create: function () { + this.$Elm = this.parent(); + this.$Elm.addClass('quiqqer-erp-manufacturers-create'); + this.$Elm.set('data-qui', 'package/quiqqer/erp/bin/backend/controls/manufacturers/create/Manufacturer'); + + var lgPrefix = 'controls.manufacturers.create.Manufacturer.tpl.'; + + this.$Elm.set('html', Mustache.render(template, { + manufacturerNoHeader : QUILocale.get(lg, lgPrefix + 'manufacturerNoHeader'), + manufacturerNoText : QUILocale.get(lg, lgPrefix + 'manufacturerNoText'), + manufacturerNoInputHeader: QUILocale.get(lg, lgPrefix + 'manufacturerNoInputHeader'), + manufacturerDataHeader : QUILocale.get(lg, lgPrefix + 'manufacturerDataHeader'), + manufacturerDataText : QUILocale.get(lg, lgPrefix + 'manufacturerDataText'), + manufacturerGroupsHeader : QUILocale.get(lg, lgPrefix + 'manufacturerGroupsHeader'), + manufacturerGroupsText : QUILocale.get(lg, lgPrefix + 'manufacturerGroupsText'), + + textAddressCompany : QUILocale.get('quiqqer/quiqqer', 'company'), + textAddressSalutation: QUILocale.get('quiqqer/quiqqer', 'salutation'), + textAddressFirstname : QUILocale.get('quiqqer/quiqqer', 'firstname'), + textAddressLastname : QUILocale.get('quiqqer/quiqqer', 'lastname'), + textAddressStreet : QUILocale.get('quiqqer/quiqqer', 'street'), + textAddressZIP : QUILocale.get('quiqqer/quiqqer', 'zip'), + textAddressCity : QUILocale.get('quiqqer/quiqqer', 'city'), + textAddressCountry : QUILocale.get('quiqqer/quiqqer', 'country'), + + textGroup : QUILocale.get(lg, lgPrefix + 'textGroup'), + textGroups: QUILocale.get(lg, lgPrefix + 'textGroups'), + + previousButton: QUILocale.get(lg, lgPrefix + 'previousButton'), + nextButton : QUILocale.get(lg, lgPrefix + 'nextButton') + })); + + this.$Form = this.$Elm.getElement('form'); + this.$GroupList = this.$Elm.getElement('.quiqqer-erp-manufacturers-create-manufacturerGroups-list'); + + // key events + var self = this; + var ManufacturerId = this.$Elm.getElement('[name="manufacturerId"]'); + var Company = this.$Elm.getElement('[name="address-company"]'); + var Country = this.$Elm.getElement('[name="address-country"]'); + + ManufacturerId.addEvent('keydown', function (event) { + if (event.key === 'tab') { + event.stop(); + self.next().then(function () { + Company.focus(); + }); + } + }); + + ManufacturerId.addEvent('keyup', function (event) { + if (event.key === 'enter') { + event.stop(); + self.next(); + } + }); + + Company.addEvent('keydown', function (event) { + if (event.key === 'tab' && event.shift) { + event.stop(); + self.previous().then(function () { + ManufacturerId.focus(); + }); + } + }); + + Country.addEvent('keydown', function (event) { + if (event.key === 'tab') { + event.stop(); + self.next(); + } + }); + + this.$Container = this.$Elm.getElement('.quiqqer-erp-manufacturers-create-container'); + this.$List = this.$Elm.getElement('.quiqqer-erp-manufacturers-create-container ul'); + this.$Next = this.$Elm.getElement('[name="next"]'); + this.$Previous = this.$Elm.getElement('[name="previous"]'); + + this.$Next.addEvent('click', this.next); + this.$Previous.addEvent('click', this.previous); + + return this.$Elm; + }, + + /** + * event: on inject + */ + $onInject: function () { + var self = this; + + Promise.all([ + Manufacturers.getManufacturerGroups(), + Countries.getCountries() + ]).then(function (result) { + // Group list + var groups = result[0]; + + for (var i = 0, len = groups.length; i < len; i++) { + var Group = groups[i]; + + new Element('li', { + html: '<label>' + + '<input type="checkbox" data-id="' + Group.id + '"/>' + + '<span>' + Group.name + '</span>' + + '</label>' + }).inject(self.$GroupList); + } + + // Country list + var countries = result[1]; + var CountrySelect = self.$Elm.getElement('[name="address-country"]'); + + for (var code in countries) { + if (!countries.hasOwnProperty(code)) { + continue; + } + + new Element('option', { + value: code, + html : countries[code] + }).inject(CountrySelect); + } + }).then(function () { + return QUI.parse(self.$Elm); + }).then(function () { + self.showManufacturerNumber(); + }); + }, + + /** + * Create the manufacturer + */ + createManufacturer: function () { + var self = this; + var elements = this.$Form.elements; + var manufacturerId = elements.manufacturerId.value; + var groupIds = []; + + var groupInputs = this.$GroupList.getElement('input'); + + groupInputs.forEach(function (Input) { + if (Input.checked) { + groupIds.push(Input.get('data-id')); + } + }); + + var Address = { + 'salutation': elements['address-salutation'].value, + 'firstname' : elements['address-firstname'].value, + 'lastname' : elements['address-lastname'].value, + 'company' : elements['address-company'].value, + 'street_no' : elements['address-street_no'].value, + 'zip' : elements['address-zip'].value, + 'city' : elements['address-city'].value, + 'country' : elements['address-country'].value + }; + + this.fireEvent('createManufacturerBegin', [this]); + + QUIAjax.post('package_quiqqer_manufacturer_ajax_backend_create_createManufacturer', function (manufacturerId) { + self.fireEvent('createManufacturerEnd', [self, manufacturerId]); + }, { + 'package' : 'quiqqer/erp', + manufacturerId: manufacturerId, + address : JSON.encode(Address), + groupIds : JSON.encode(groupIds) + }, function (e) { + console.log("TODO: hide loader"); + }); + }, + + /** + * Show next step + */ + next: function () { + if (this.$Next.get('data-last')) { + return this.createManufacturer(); + } + + var self = this; + var steps = this.$List.getElements('li'); + var pos = this.$List.getPosition(this.$Container); + var top = pos.y; + + var height = this.$Container.getSize().y; + var scrollHeight = this.$Container.getScrollSize().y; + var newTop = this.$roundToStepPos(top - height); + + // change last step button + if (newTop - height <= scrollHeight * -1) { + this.$Next.set('html', QUILocale.get(lg, 'window.manufacturer.creation.create')); + this.$Next.set('data-last', 1); + } + + // check if last step + if (newTop <= steps.length * height * -1) { + return Promise.resolve(); + } + + return new Promise(function (resolve) { + moofx(self.$List).animate({ + top: newTop + }, { + callback: resolve + }); + }); + }, + + /** + * Previous next step + */ + previous: function () { + var self = this; + var pos = this.$List.getPosition(this.$Container); + var top = pos.y; + + var height = this.$Container.getSize().y; + var newTop = this.$roundToStepPos(top + height); + + this.$Next.set('html', QUILocale.get(lg, 'window.manufacturer.creation.next')); + this.$Next.set('data-last', null); + + if (newTop > 0) { + newTop = 0; + } + + return new Promise(function (resolve) { + moofx(self.$List).animate({ + top: newTop + }, { + callback: resolve + }); + }); + }, + + /** + * + * @param currentPos + * @return {number} + */ + $roundToStepPos: function (currentPos) { + var height = this.$Container.getSize().y; + var pos = Math.round(currentPos / height) * -1; + + return pos * height * -1; + }, + + /** + * Show the manufacturer number step + */ + showManufacturerNumber: function () { + var self = this; + + this.$getNextManufacturerNo().then(function (manufacturerNo) { + var Input = self.$Elm.getElement('input'); + + Input.value = manufacturerNo; + Input.focus(); + + self.fireEvent('load', [self]); + }); + }, + + /** + * Get next available QUIQQER user id + * + * @return {Promise} + */ + $getNextManufacturerNo: function () { + return new Promise(function (resolve) { + QUIAjax.get('package_quiqqer_erp_ajax_manufacturers_create_getNextId', resolve, { + 'package': 'quiqqer/erp' + }); + }); + } + }); +}); diff --git a/bin/backend/controls/manufacturers/create/ManufacturerWindow.js b/bin/backend/controls/manufacturers/create/ManufacturerWindow.js new file mode 100644 index 0000000000000000000000000000000000000000..08314614bbf6e4cfe0db813a83637fd47a5183d8 --- /dev/null +++ b/bin/backend/controls/manufacturers/create/ManufacturerWindow.js @@ -0,0 +1,71 @@ +/** + * @module package/quiqqer/erp/bin/backend/controls/manufacturers/create/ManufacturerWindow + * @author www.pcsg.de (Patrick Müller) + */ +define('package/quiqqer/erp/bin/backend/controls/manufacturers/create/ManufacturerWindow', [ + + 'qui/controls/windows/Popup', + 'Locale', + 'package/quiqqer/erp/bin/backend/controls/manufacturers/create/Manufacturer' + +], function (QUIPopup, QUILocale, CreateManufacturer) { + "use strict"; + + var lg = 'quiqqer/manufacturer'; + + return new Class({ + + Extends: QUIPopup, + Type : 'package/quiqqer/erp/bin/backend/controls/manufacturers/create/ManufacturerWindow', + + Binds: [ + '$onOpen' + ], + + options: { + maxHeight: 700, + maxWidth : 600, + buttons : false + }, + + initialize: function (options) { + this.setAttributes({ + icon : 'fa fa-id-card', + title: QUILocale.get(lg, 'controls.manufacturers.create.ManufacturerWindow.title') + }); + + this.parent(options); + + this.addEvents({ + onOpen: this.$onOpen + }); + }, + + /** + * event: on open + */ + $onOpen: function () { + var self = this; + + this.getContent().set('html', ''); + this.getContent().setStyle('padding', 0); + + new CreateManufacturer({ + events: { + onLoad: function () { + self.Loader.hide(); + }, + + onCreateManufacturerBegin: function () { + self.Loader.show(); + }, + + onCreateManufacturerEnd: function (Instance, manufacturerId) { + self.fireEvent('submit', [self, manufacturerId]); + self.close(); + } + } + }).inject(this.getContent()); + } + }); +}); diff --git a/locale.xml b/locale.xml index d781e802ae19708494621966a1616c2a6809e06e..45d4ecc857668eb3763fc6cd603fe21f0794e01f 100644 --- a/locale.xml +++ b/locale.xml @@ -56,6 +56,10 @@ <de><![CDATA[Alle Preise inkl. gesetzl. MwSt.]]></de> <en><![CDATA[All prices include VAT]]></en> </locale> + <locale name="menu.erp.manufacturers.title"> + <de><![CDATA[Hersteller]]></de> + <en><![CDATA[Manufacturers]]></en> + </locale> <locale name="price.starting.from"> <de><![CDATA[ab]]></de> @@ -708,5 +712,80 @@ <de><![CDATA[Der Artikel wird unwiderruflich gelöscht.]]></de> <en><![CDATA[The article is irrevocably deleted.]]></en> </locale> + + <locale name="controls.manufacturers.AdministrationPanel.title"> + <de><![CDATA[Hersteller]]></de> + <en><![CDATA[Manufacturers]]></en> + </locale> + + <locale name="controls.manufacturers.Administration.no_group.information"> + <de><![CDATA[Es können aktuell keine Hersteller gelistet werden, da im Produktfeld "Hersteller" noch keine Gruppen zugewiesen sind. Bitte öffnen Sie die Produktfeld-Verwaltung unter <b>Verwaltung -> Shop -> Produktfelder</b> und editieren das Feld "Hersteller" (ID 8). Dort weisen Sie in den Feld-Optionen mindestens eine Gruppe zu.]]></de> + <en><![CDATA[Currently no manufacturers can be listed because no groups have been assigned in the product field "Manufacturer" yet. Please open the product field administration under <b>Administration -> Shop -> Product fields</b> and edit the field "Manufacturer" (ID 8). There you assign at least one group in the field options.]]></en> + </locale> + <locale name="controls.manufacturers.Administration.no_group.title"> + <de><![CDATA[Hersteller können nicht gelistet werden]]></de> + <en><![CDATA[Manufacturers cannot be listed]]></en> + </locale> + <locale name="controls.manufacturers.Administration.no_group.text"> + <de><![CDATA[Hersteller können nicht gelistet werden]]></de> + <en><![CDATA[Manufacturers cannot be listed]]></en> + </locale> + <locale name="controls.manufacturers.Administration.no_group.submit"> + <de><![CDATA[OK]]></de> + <en><![CDATA[OK]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.searchPlaceholder"> + <de><![CDATA[Hersteller durchsuchen...]]></de> + <en><![CDATA[Search manufacturers...]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.filterTitle"> + <de><![CDATA[Felder bei der Suche beachten]]></de> + <en><![CDATA[Search fields considered]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.filterUserId"> + <de><![CDATA[Benutzer-ID]]></de> + <en><![CDATA[User ID]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.filterUsername"> + <de><![CDATA[Benutzername]]></de> + <en><![CDATA[Username]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.filterFirstname"> + <de><![CDATA[Vorname]]></de> + <en><![CDATA[First name]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.filterLastname"> + <de><![CDATA[Nachname]]></de> + <en><![CDATA[Last name]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.filterEmail"> + <de><![CDATA[E-Mail-Adresse]]></de> + <en><![CDATA[Email address]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.filterCompany"> + <de><![CDATA[Firma]]></de> + <en><![CDATA[Company]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tbl.header.active_status"> + <de><![CDATA[Aktiv]]></de> + <en><![CDATA[Active]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.dateFilterTitle"> + <de><![CDATA[Erstellungsdatum]]></de> + <en><![CDATA[Create date]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.dateFilterFrom"> + <de><![CDATA[von]]></de> + <en><![CDATA[bis]]></en> + </locale> + <locale name="controls.manufacturers.Administration.tpl.dateFilterTo"> + <de><![CDATA[bis]]></de> + <en><![CDATA[to]]></en> + </locale> + <locale name="controls.manufacturers.create.ManufacturerWindow.title"> + <de><![CDATA[Neuen Hersteller anlegen]]></de> + <en><![CDATA[Create new manufacturer]]></en> + </locale> + </groups> </locales> diff --git a/menu.xml b/menu.xml new file mode 100644 index 0000000000000000000000000000000000000000..df313d7bbc015eb17770b2d165cad4b77e6b72aa --- /dev/null +++ b/menu.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<menu> + + <item parent="/apps/" + name="manufacturers" + require="package/quiqqer/erp/bin/backend/controls/manufacturers/AdministrationPanel" + icon="fa fa-wrench" + permission="quiqqer.erp.manufacturers.manage" + > + <locale group="quiqqer/erp" var="menu.erp.manufacturers.title"/> + </item> + +</menu> diff --git a/src/QUI/ERP/Manufacturers.php b/src/QUI/ERP/Manufacturers.php new file mode 100644 index 0000000000000000000000000000000000000000..b98d1bcddfad3e40656aa76214b9f6fe946e9442 --- /dev/null +++ b/src/QUI/ERP/Manufacturers.php @@ -0,0 +1,352 @@ +<?php + +namespace QUI\ERP; + +use QUI; +use QUI\ERP\Products\Handler\Fields; +use QUI\Utils\Security\Orthos; + +/** + * Class Manufacturers + * + * Main handler for manufacturer management + */ +class Manufacturers +{ + /** + * Get all group IDs that are assigned to the manufacturer product field + * + * @return int[] + */ + public static function getManufacturerGroupIds() + { + /** @var QUI\ERP\Products\Field\Types\GroupList $ManufacturerField */ + try { + $ManufacturerField = Fields::getField(Fields::FIELD_MANUFACTURER); + } catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + return []; + } + + $groupIds = $ManufacturerField->getOption('groupIds'); + + if (empty($groupIds) || !\is_array($groupIds)) { + return []; + } + + \array_walk($groupIds, function (&$groupId) { + $groupId = (int)$groupId; + }); + + return $groupIds; + } + + /** + * Search manufacturers + * + * @param array $searchParams + * @param bool $countOnly (optional) - get count for search result only [default: false] + * @return int[]|int - membership user IDs or count + */ + public static function search(array $searchParams, $countOnly = false) + { + $Grid = new QUI\Utils\Grid($searchParams); + $gridParams = $Grid->parseDBParams($searchParams); + $usersTbl = QUI::getDBTableName('users'); + $usersAddressTbl = QUI::getDBTableName('users_address'); + $binds = []; + $where = []; + + if ($countOnly) { + $sql = "SELECT COUNT(*)"; + } else { + $sql = "SELECT u.`id`, u.`firstname`, u.`lastname`, u.`email`, u.`username`, ua.`company`, u.`usergroup`"; + $sql .= ", u.`active`, u.`regdate`"; + } + + $sql .= " FROM `".$usersTbl."` as u LEFT JOIN `".$usersAddressTbl."` as ua ON u.`address` = ua.`id`"; + + // Only fetch users in manufacturer groups + $gc = 0; + $whereOr = []; + + foreach (self::getManufacturerGroupIds() as $groupId) { + $whereOr[] = "u.`usergroup` LIKE :group".$gc; + $bind = 'group'.$gc; + + $binds[$bind] = [ + 'value' => '%,'.$groupId.',%', + 'type' => \PDO::PARAM_STR + ]; + } + + if (!empty($whereOr)) { + $where[] = "(".\implode(" OR ", $whereOr).")"; + } + + // User search + $searchFields = [ + 'id', + 'username', + 'email', + 'company' + ]; + + if (!empty($searchParams['filter']) && \is_array($searchParams['filter'])) { + $searchFields = \array_filter($searchParams['filter'], function ($value) { + return !!(int)$value; + }); + + $searchFields = \array_keys($searchFields); + + // date filters + if (!empty($searchParams['filter']['regdate_from'])) { + $DateFrom = \date_create($searchParams['filter']['regdate_from']); + + if ($DateFrom) { + $DateFrom->setTime(0, 0, 0); + + $bind = 'datefrom'; + $where[] = 'u.`regdate` >= :'.$bind; + + $binds[$bind] = [ + 'value' => $DateFrom->getTimestamp(), + 'type' => \PDO::PARAM_INT + ]; + } + } + + if (!empty($searchParams['filter']['regdate_to'])) { + $DateTo = \date_create($searchParams['filter']['regdate_to']); + + if ($DateTo) { + $DateTo->setTime(23, 59, 59); + + $bind = 'dateto'; + $where[] = 'u.`regdate` <= :'.$bind; + + $binds[$bind] = [ + 'value' => $DateTo->getTimestamp(), + 'type' => \PDO::PARAM_INT + ]; + } + } + } + + if (!empty($searchParams['search'])) { + $searchValue = $searchParams['search']; + $fc = 0; + $whereOr = []; + + // search value filters + foreach ($searchFields as $filter) { + $bind = 'filter'.$fc; + + switch ($filter) { + case 'id': + case 'username': + case 'firstname': + case 'lastname': + case 'email': + $whereOr[] = 'u.`'.$filter.'` LIKE :'.$bind; + break; + + case 'company': + $whereOr[] = 'ua.`'.$filter.'` LIKE :'.$bind; + break; + + default: + continue 2; + } + + $binds[$bind] = [ + 'value' => '%'.$searchValue.'%', + 'type' => \PDO::PARAM_STR + ]; + + $fc++; + } + + if (!empty($whereOr)) { + $where[] = "(".\implode(" OR ", $whereOr).")"; + } + } + + // build WHERE query string + if (!empty($where)) { + $sql .= " WHERE ".implode(" AND ", $where); + } + + // ORDER + if (!empty($searchParams['sortOn'])) { + $sortOn = Orthos::clear($searchParams['sortOn']); + + switch ($sortOn) { + case 'id': + case 'username': + case 'firstname': + case 'lastname': + case 'email': + $sortOn = 'u.`'.$sortOn.'`'; + break; + + case 'company': + $sortOn = 'ua.`'.$sortOn.'`'; + break; + } + + $order = "ORDER BY ".$sortOn; + + if (!empty($searchParams['sortBy'])) { + $order .= " ".Orthos::clear($searchParams['sortBy']); + } else { + $order .= " ASC"; + } + + $sql .= " ".$order; + } + + // LIMIT + if (!empty($gridParams['limit']) && !$countOnly) { + $sql .= " LIMIT ".$gridParams['limit']; + } else { + if (!$countOnly) { + $sql .= " LIMIT ".(int)20; + } + } + + $Stmt = QUI::getPDO()->prepare($sql); + + // bind search values + foreach ($binds as $var => $bind) { + $Stmt->bindValue(':'.$var, $bind['value'], $bind['type']); + } + + try { + $Stmt->execute(); + $result = $Stmt->fetchAll(\PDO::FETCH_ASSOC); + } catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + return []; + } + + if ($countOnly) { + return (int)current(current($result)); + } + + return $result; + } + + /** + * Parse data and prepare for frontend use with GRID + * + * @param array $data - Search result IDs + * @return array + */ + public static function parseListForGrid(array $data) + { + $localeCode = QUI::getLocale()->getLocalesByLang( + QUI::getLocale()->getCurrent() + ); + + $DateFormatter = new \IntlDateFormatter( + $localeCode[0], + \IntlDateFormatter::SHORT, + \IntlDateFormatter::NONE + ); + + $DateFormatterLong = new \IntlDateFormatter( + $localeCode[0], + \IntlDateFormatter::SHORT, + \IntlDateFormatter::SHORT + ); + + $result = []; + $Groups = QUI::getGroups(); + $Users = QUI::getUsers(); + + foreach ($data as $entry) { + $entry['usergroup'] = \trim($entry['usergroup'], ','); + $entry['usergroup'] = \explode(',', $entry['usergroup']); + $entry['usergroup'] = \array_map(function ($groupId) { + return (int)$groupId; + }, $entry['usergroup']); + + $groups = \array_map(function ($groupId) use ($Groups) { + try { + $Group = $Groups->get($groupId); + + return $Group->getName(); + } catch (QUI\Exception $Exception) { + } + + return ''; + }, $entry['usergroup']); + + \sort($groups); + $groups = \implode(', ', $groups); + $groups = \str_replace(',,', '', $groups); + $groups = \trim($groups, ','); + + $addressData = []; + $Address = null; + + try { + $User = $Users->get((int)$entry['id']); + $Address = $User->getStandardAddress(); + } catch (QUI\Exception $Exception) { + } + + if ($Address && (empty($entry['firstname']) || empty($entry['lastname']))) { + $name = []; + + if ($Address->getAttribute('firstname')) { + $entry['firstname'] = $Address->getAttribute('firstname'); + $name[] = $Address->getAttribute('firstname'); + } + + if ($Address->getAttribute('lastname')) { + $entry['lastname'] = $Address->getAttribute('lastname'); + $name[] = $Address->getAttribute('lastname'); + } + + if (!empty($name)) { + $addressData[] = \implode(' ', $name); + } + } + + if ($Address) { + $addressData[] = $Address->getText(); + + if (empty($entry['email'])) { + $mails = $Address->getMailList(); + + if (\count($mails)) { + $entry['email'] = $mails[0]; + } + } + + if (empty($entry['company'])) { + $entry['company'] = $Address->getAttribute('company'); + } + } + + $result[] = [ + 'id' => (int)$entry['id'], + 'status' => !!$entry['active'], + 'username' => $entry['username'], + 'firstname' => $entry['firstname'], + 'lastname' => $entry['lastname'], + 'company' => $entry['company'], + 'email' => $entry['email'], + 'regdate' => $DateFormatterLong->format($entry['regdate']), + + 'usergroup_display' => $groups, + 'usergroup' => $entry['usergroup'], + 'address_display' => \implode(' - ', $addressData) + ]; + } + + return $result; + } +}