partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 9dadcbae2dbfdff59f6864aa28a13570e3b20632
parent 1c2545b830884afa7c8296bd1ea01262a11ec97a
Author: Timo A. Hummel <timo@netraver.de>
Date:   Mon, 23 May 2011 17:43:07 +0200

Changes:
* Calculate stock on setup
* Initial part add window (not functional yet)
* Deleting parts
* Refactored category chooser window

I know I have to do smaller commits in the future.

Diffstat:
Mfrontend/index.html | 5++++-
Afrontend/js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryComboBox.js | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfrontend/js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryEditor.js | 95+++----------------------------------------------------------------------------
Afrontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartDialog.js | 28++++++++++++++++++++++++++++
Afrontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartForm.js | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfrontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerListGrid.js | 50+++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/de/RaumZeitLabor/PartDB2/Footprint/FootprintManager.php | 10++++------
Msrc/de/RaumZeitLabor/PartDB2/Part/Part.php | 7+++++++
Msrc/de/RaumZeitLabor/PartDB2/Part/PartManager.php | 7+++++++
Msrc/de/RaumZeitLabor/PartDB2/Part/PartManagerService.php | 4++++
Msrc/de/RaumZeitLabor/PartDB2/Stock/StockEntry.php | 13++++++++++++-
Asrc/de/RaumZeitLabor/PartDB2/StorageLocation/StorageLocationManager.php | 30++++++++++++++++++++++++++++++
Asrc/de/RaumZeitLabor/PartDB2/StorageLocation/StorageLocationService.php | 16++++++++++++++++
Mtesting/SetupDatabase.php | 1+
14 files changed, 377 insertions(+), 103 deletions(-)

diff --git a/frontend/index.html b/frontend/index.html @@ -32,7 +32,7 @@ <script type="text/javascript" src="js/org.jerrymouse.gui.widgets/quicktips.js"></script> <script type="text/javascript" src="js/org.jerrymouse.gui.widgets/contexthelp.js"></script> - <script type="text/javascript" src="js/org.jerrymouse.gui.widgets/window.js"></script> + <script type="text/javascript" src="js/org.jerrymouse.gui.widgets/window.js"></script> <script type="text/javascript" src="js/org.jerrymouse.gui.widgets/MainWindow.js"></script> <script type="text/javascript" src="js/org.jerrymouse.gui.widgets/button.js"></script> <script type="text/javascript" src="js/org.jerrymouse.gui.widgets/menuitem.js"></script> @@ -57,8 +57,11 @@ <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerWindow.js"></script> <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerPartDetail.js"></script> <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerListGrid.js"></script> + <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartDialog.js"></script> + <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartForm.js"></script> <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryEditor.js"></script> + <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryComboBox.js"></script> <script type="text/javascript" src="js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryWidget.js"></script> <script type="text/javascript" src="js/org.jerrymouse.gui.login/login.js"></script> diff --git a/frontend/js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryComboBox.js b/frontend/js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryComboBox.js @@ -0,0 +1,101 @@ +Ext.ns("de.RaumZeitLabor.PartDB2.CategoryEditor"); + +de.RaumZeitLabor.PartDB2.CategoryComboBox = Ext.extend(Ext.form.ComboBox, { + editable:false, + shadow:false, + mode: 'local', + triggerAction:'all', + maxHeight: 400, + width: 200, + listWidth: 400, + selectedClass:'', + lazyInit: false, + onSelect:Ext.emptyFn, + initComponent: function () { + + this.treeDivId = Ext.id(); + + this.tpl = '<tpl for="."><div id="'+this.treeDivId+'" style="overflow: auto;"></div></tpl>', + + this.store = new Ext.data.SimpleStore({fields:[],data:[[]]}); + + this.tree = new de.RaumZeitLabor.PartDB2.CategoryEditor.CategoryWidget(); + + this.on("beforeselect", function () { + return false; + }); + + this.tree.on('click', function (node) { + this.setValue(node.text); + this.collapse(); + this.parentId = node.id; + }.createDelegate(this)); + + this.tree.on("afterrender", function (obj) { + var node = obj.getRootNode().findChild("id", this.parentId, true); + + + if (node) { + node.ensureVisible(); + node.select(); + } else { + obj.getRootNode().select(); + } + + if (this.disabledNode) { + this.disabledNode.enable(); + } + + var node = obj.getRootNode().findChild("id", this.categoryId, true); + + if (node) { + this.disabledNode = node; + node.disable(); + } + + obj.expandAll(); + + }.createDelegate(this)); + + + this.on('expand',function(e){ + if (this.tree.rendered) { + var node = this.tree.getRootNode().findChild("id", this.parentId, true); + + if (node) { + node.ensureVisible(); + node.select(); + } else { + this.tree.getRootNode().select(); + } + + this.tree.getRootNode().eachChild(function (n) { + n.enable(); + }); + + if (this.disabledNode) { + this.disabledNode.enable(); + } + + var node = this.tree.getRootNode().findChild("id", this.categoryId, true); + + if (node) { + this.disabledNode = node; + node.disable(); + } + this.tree.expandAll(); + } else { + this.tree.render(this.treeDivId); + } + + }.createDelegate(this)); + + de.RaumZeitLabor.PartDB2.CategoryComboBox.superclass.initComponent.call(this); + }, + onViewClick: function () { + + }, + loadTree: function () { + this.tree.loadTree(); + } +});+ \ No newline at end of file diff --git a/frontend/js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryEditor.js b/frontend/js/de.RaumZeitLabor.PartDB2/CategoryEditor/CategoryEditor.js @@ -4,104 +4,14 @@ de.RaumZeitLabor.PartDB2.CategoryEditor = Ext.extend(Ext.form.FormPanel, { id: "category-details", categoryId: null, categoryComboBox: null, - parentCategoryTree: null, initComponent: function () { - this.categoryComboBox = new Ext.form.ComboBox({ - store:new Ext.data.SimpleStore({fields:[],data:[[]]}), - editable:false, - shadow:false, - mode: 'local', - triggerAction:'all', - maxHeight: 400, - width: 200, - listWidth: 400, - tpl: '<tpl for="."><div id="tree1" style="overflow: auto;"></div></tpl>', - selectedClass:'', + this.categoryComboBox = new de.RaumZeitLabor.PartDB2.CategoryComboBox({ fieldLabel: '$[de.RaumZeitLabor.PartDB2.CategoryEditor.parentCategory]', name: 'parent', anchor: '100%', - lazyInit: false, - onSelect:Ext.emptyFn }); - this.categoryComboBox.onViewClick = function () { - - }; - - this.categoryComboBox.on("beforeselect", function () { - return false; - }); - - var tree = new de.RaumZeitLabor.PartDB2.CategoryEditor.CategoryWidget(); - - this.parentCategoryTree = tree; - - tree.on('click', function (node) { - this.categoryComboBox.setValue(node.text); - this.categoryComboBox.collapse(); - this.categoryComboBox.parentId = node.id; - }.createDelegate(this)); - - tree.on("afterrender", function (obj) { - var node = obj.getRootNode().findChild("id", this.categoryComboBox.parentId, true); - - - if (node) { - node.ensureVisible(); - node.select(); - } else { - obj.getRootNode().select(); - } - - if (this.disabledNode) { - this.disabledNode.enable(); - } - - var node = obj.getRootNode().findChild("id", this.categoryId, true); - - if (node) { - this.disabledNode = node; - node.disable(); - } - - obj.expandAll(); - - }.createDelegate(this)); - - this.categoryComboBox.on('expand',function(e){ - if (tree.rendered) { - var node = tree.getRootNode().findChild("id", this.categoryComboBox.parentId, true); - - - if (node) { - node.ensureVisible(); - node.select(); - } else { - tree.getRootNode().select(); - } - - tree.getRootNode().eachChild(function (n) { - n.enable(); - }); - - if (this.disabledNode) { - this.disabledNode.enable(); - } - - var node = tree.getRootNode().findChild("id", this.categoryId, true); - - if (node) { - this.disabledNode = node; - node.disable(); - } - tree.expandAll(); - } else { - tree.render('tree1'); - } - - }.createDelegate(this)); - Ext.apply(this, { cls: 'x-panel-mc', bodyStyle:'padding:0px 5px 0', @@ -134,6 +44,7 @@ de.RaumZeitLabor.PartDB2.CategoryEditor = Ext.extend(Ext.form.FormPanel, { setCategoryId: function (id) { this.categoryId = id; + this.categoryComboBox.categoryId = id; }, createCategory: function () { this.getForm().setValues({name: "", description: "", parent: 0}) @@ -188,7 +99,7 @@ de.RaumZeitLabor.PartDB2.CategoryEditor = Ext.extend(Ext.form.FormPanel, { onCategorySaved: function (response) { Ext.getCmp("parts-tree").selectedNode = response.id; Ext.getCmp("parts-tree").loadTree(); - this.parentCategoryTree.loadTree(); + this.categoryComboBox.loadTree(); }, onCategoryLoaded: function (response) { this.getForm().setValues(response); diff --git a/frontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartDialog.js b/frontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartDialog.js @@ -0,0 +1,27 @@ +Ext.ns("de.RaumZeitLabor.PartDB2.PartsManagerAddPartDialog"); + +de.RaumZeitLabor.PartDB2.PartsManagerAddPartDialog = Ext.extend(Ext.Window, { + closeAction: 'hide', + title: "Bauteil erfassen", + width: 400, + border: false, + layout: 'fit', + frame: true, + height: 300, + initComponent: function () { + + this.addPartForm = new de.RaumZeitLabor.PartDB2.PartsManagerAddPartForm(); + + this.items = [ + this.addPartForm + ]; + + this.on("show", function () { + this.addPartForm.reloadStorageLocations(); + this.addPartForm.partName.focus(false, 300); + }.createDelegate(this)); + + de.RaumZeitLabor.PartDB2.PartsManagerAddPartDialog.superclass.initComponent.call(this); + } +}); + + \ No newline at end of file diff --git a/frontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartForm.js b/frontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerAddPartForm.js @@ -0,0 +1,111 @@ +Ext.ns("de.RaumZeitLabor.PartDB2.PartsManagerAddPartForm"); + +de.RaumZeitLabor.PartDB2.PartsManagerAddPartForm = Ext.extend(Ext.form.FormPanel, { + frame: true, + border: false, + monitorValid: true, + initComponent: function () { + + + this.partName = new Ext.form.TextField({ + fieldLabel: "Name", + allowBlank: false, + anchor: '100%' + }); + + this.partQuantity = new Ext.form.NumberField({ + allowDecimals: false, + fieldLabel: "Stück", + allowBlank: false, + flex: 1 + }); + + this.partMinStock = new Ext.form.NumberField({ + allowDecimals: false, + allowBlank: false, + id: Ext.id(), + flex: 1 + }); + + + // @todo Put the storage location combobox into an own component + this.storageLocationCall = new org.jerrymouse.service.Call( + "de.RaumZeitLabor.PartDB2.StorageLocation.StorageLocationService", + "getStorageLocations"); + + this.storageLocationStore = new Ext.data.JsonStore({ + root: 'storageLocations', + totalProperty: 'totalCount', + proxy: new ServiceCallDataProxy(this.storageLocationCall), + idProperty: 'id', + allowBlank: false, + remoteSort: false, + fields: [ + 'id', + 'name' + ] + }); + + this.partStorageLocation = new Ext.form.ComboBox({ + store: this.storageLocationStore, + displayField: "name", + anchor: '100%', + mode: 'local', + valueField: "id", + fieldLabel: "Lagerort" + }); + + // @todo Put the footprint combobox into an own component + this.footprintCall = new org.jerrymouse.service.Call( + "de.RaumZeitLabor.PartDB2.Footprint.FootprintManagerService", + "getFootprints"); + + this.footprintCall.setParameter("limit", -1); + + this.footprintStore = new Ext.data.JsonStore({ + root: 'footprints', + totalProperty: 'totalCount', + proxy: new ServiceCallDataProxy(this.footprintCall), + idProperty: 'id', + remoteSort: false, + fields: [ + 'id', + 'footprint' + ] + }); + + this.footprintCombo = new Ext.form.ComboBox({ + store: this.footprintStore, + displayField: "footprint", + anchor: '100%', + mode: 'local', + valueField: "id", + fieldLabel: "Footprint" + }); + + this.items = [ + this.partName, + { + xtype: "compositefield", + fieldLabel: "Stück", + items: [ + this.partQuantity, + { + xtype: "label", + forId: this.partMinStock.id, + text: "Min. Bestand" + }, + this.partMinStock + ] + }, + this.partStorageLocation, + this.footprintCombo]; + + de.RaumZeitLabor.PartDB2.PartsManagerAddPartForm.superclass.initComponent.call(this); + }, + reloadStorageLocations: function () { + this.storageLocationStore.reload(); + this.footprintStore.reload(); + } +}); + + \ No newline at end of file diff --git a/frontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerListGrid.js b/frontend/js/de.RaumZeitLabor.PartDB2/PartsManager/PartsManagerListGrid.js @@ -23,8 +23,12 @@ de.RaumZeitLabor.PartDB2.PartsManagerListGrid = Ext.extend(Ext.grid.GridPanel, { this.call.setLoadMessage('$[de.RaumZeitLabor.PartDB2.FootPrintManager.loading]'); this.call.setParameter("limit", pageSize); - - this.store = new Ext.data.JsonStore({ + + this.sm = new Ext.grid.RowSelectionModel({ singleSelect: true }); + + this.addPartDialog = new de.RaumZeitLabor.PartDB2.PartsManagerAddPartDialog(); + + this.store = new Ext.data.JsonStore({ root: 'parts', totalProperty: 'totalCount', proxy: new ServiceCallDataProxy(this.call), @@ -71,14 +75,54 @@ de.RaumZeitLabor.PartDB2.PartsManagerListGrid = Ext.extend(Ext.grid.GridPanel, { this.tbStockLevel ] }); + + this.addPartButton = new Ext.Button({ + text: "Bauteil erfassen", + cls:'x-btn-text-icon', + icon: 'resources/silkicons/brick_add.png', + handler: this.onPartAdd.createDelegate(this) + }); + + this.deletePartButton = new Ext.Button({ + text: "Bauteil löschen", + cls:'x-btn-text-icon', + icon: 'resources/silkicons/brick_delete.png', + handler: this.onPartDelete.createDelegate(this) + }); + this.bbar = new Ext.PagingToolbar( { "pageSize": pageSize, store: this.store, - displayInfo: false + displayInfo: false, + items: [ + this.addPartButton, + this.deletePartButton + ] }); de.RaumZeitLabor.PartDB2.PartsManagerListGrid.superclass.initComponent.call(this); }, + onPartAdd: function () { + this.addPartDialog.show(); + }, + onPartDelete: function () { + var r = this.getSelectionModel().getSelected(); + + Ext.Msg.confirm("Bauteil löschen", "Soll das Bauteil <b>"+r.get("name")+"</b>, Lagernd in <b>"+r.get("storagelocation")+"</b>, wirklich gelöscht werden?", function (button) { + if (button == "yes") { + var call = new org.jerrymouse.service.Call( + "de.RaumZeitLabor.PartDB2.Part.PartManagerService", + "deletePart"); + + call.setLoadMessage('$[de.RaumZeitLabor.PartDB2.FootPrintManager.loading]'); + call.setParameter("part", r.get("id")); + call.setHandler(function () { + this.store.reload(); + }.createDelegate(this)); + call.doCall(); + } + }.createDelegate(this)); + }, onBeforeLoad: function (store, options) { this.call.setParameter("category", this.limitCategory); this.call.setParameter("stockmode", this.tbStockLevel.getValue()); diff --git a/src/de/RaumZeitLabor/PartDB2/Footprint/FootprintManager.php b/src/de/RaumZeitLabor/PartDB2/Footprint/FootprintManager.php @@ -18,17 +18,15 @@ class FootprintManager extends Singleton { $qb->setParameter("filter", "%".$filter."%"); } - $qb->setMaxResults($limit); - $qb->setFirstResult($start); + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } $qb->orderBy("f.".$sort, $dir); $query = $qb->getQuery(); - /*if ($filter != "") { - $query->setParameter("filter", "%".$filter."%"); - }*/ - $result = $query->getResult(); $totalQueryBuilder = PartDB2::getEM()->createQueryBuilder(); diff --git a/src/de/RaumZeitLabor/PartDB2/Part/Part.php b/src/de/RaumZeitLabor/PartDB2/Part/Part.php @@ -49,6 +49,13 @@ class Part { */ private $minStockLevel; + /** + * @OneToMany(targetEntity="de\RaumZeitLabor\PartDB2\Stock\StockEntry",mappedBy="part",cascade={"persist", "remove"}) + * Enter description here ... + * @var unknown_type + */ + private $stockLevels; + public function updateStockLevel () { $this->stockLevel = $this->getStockLevel(); } diff --git a/src/de/RaumZeitLabor/PartDB2/Part/PartManager.php b/src/de/RaumZeitLabor/PartDB2/Part/PartManager.php @@ -107,6 +107,13 @@ class PartManager extends Singleton { return array("parts" => $result, "totalCount" => $count); } + public function deletePart ($id) { + $part = PartManager::getInstance()->getPart($id); + + PartDB2::getEM()->remove($part); + PartDB2::getEM()->flush(); + } + public function getPart ($id) { $part = PartDB2::getEM()->find("de\RaumZeitLabor\PartDB2\Part\Part", $id); diff --git a/src/de/RaumZeitLabor/PartDB2/Part/PartManagerService.php b/src/de/RaumZeitLabor/PartDB2/Part/PartManagerService.php @@ -61,6 +61,10 @@ class PartManagerService extends Service { return $this->serializePart($part); } + public function deletePart () { + PartManager::getInstance()->deletePart($this->getParameter("part")); + } + private function serializePart ($part) { return $part->serialize(); } diff --git a/src/de/RaumZeitLabor/PartDB2/Stock/StockEntry.php b/src/de/RaumZeitLabor/PartDB2/Stock/StockEntry.php @@ -4,8 +4,9 @@ declare(encoding = 'UTF-8'); use de\RaumZeitLabor\PartDB2\Part\Part; use de\RaumZeitLabor\PartDB2\Auth\User; +use de\RaumZeitLabor\PartDB2\PartDB2; -/** @Entity **/ +/** @Entity @HasLifecycleCallbacks **/ class StockEntry { /** @@ -47,4 +48,14 @@ class StockEntry { public function setUser (User $user = null) { $this->user = $user; } + + /** + * @PostPersist + */ + public function updateStockLevel () { + $query = PartDB2::getEM()->createQuery('UPDATE de\RaumZeitLabor\PartDB2\Part\Part p SET p.stockLevel = p.stockLevel + :val WHERE p = :part'); + $query->setParameter("val", $this->stockLevel); + $query->setParameter("part", $this->part); + $query->execute(); + } } \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartDB2/StorageLocation/StorageLocationManager.php b/src/de/RaumZeitLabor/PartDB2/StorageLocation/StorageLocationManager.php @@ -0,0 +1,29 @@ +<?php +namespace de\RaumZeitLabor\PartDB2\StorageLocation; +declare(encoding = 'UTF-8'); + +use de\RaumZeitLabor\PartDB2\Util\Singleton, + de\RaumZeitLabor\PartDB2\Footprint\Footprint, + de\RaumZeitLabor\PartDB2\PartDB2, + de\RaumZeitLabor\PartDB2\Category\CategoryManager, + de\RaumZeitLabor\PartDB2\Footprint\Exceptions\FootprintNotFoundException; + +class StorageLocationManager extends Singleton { + public function getStorageLocations () { + $qb = PartDB2::getEM()->createQueryBuilder(); + $qb->select("COUNT(st)")->from("de\RaumZeitLabor\PartDB2\StorageLocation\StorageLocation","st"); + + $countQuery = $qb->getQuery(); + $count = $countQuery->getSingleScalarResult(); + + $qb->select("st.name, st.id"); + + $qb->orderBy("st.name", "asc"); + + $query = $qb->getQuery(); + + $result = $query->getArrayResult(); + + return array("storageLocations" => $result, "totalCount" => $count); + } +}+ \ No newline at end of file diff --git a/src/de/RaumZeitLabor/PartDB2/StorageLocation/StorageLocationService.php b/src/de/RaumZeitLabor/PartDB2/StorageLocation/StorageLocationService.php @@ -0,0 +1,15 @@ +<?php +namespace de\RaumZeitLabor\PartDB2\StorageLocation; +declare(encoding = 'UTF-8'); + +use de\RaumZeitLabor\PartDB2\Service\Service; +use de\RaumZeitLabor\PartDB2\Part\PartManager, + de\RaumZeitLabor\PartDB2\Stock\StockEntry, + de\RaumZeitLabor\PartDB2\PartDB2, + de\RaumZeitLabor\PartDB2\Session\SessionManager; + +class StorageLocationService extends Service { + public function getStorageLocations () { + return StorageLocationManager::getInstance()->getStorageLocations(); + } +}+ \ No newline at end of file diff --git a/testing/SetupDatabase.php b/testing/SetupDatabase.php @@ -132,6 +132,7 @@ foreach ($parts as $part) { $oStock = new StockEntry($oPart, $part["instock"]); PartDB2::getEM()->persist($oStock); + }