partkeepr

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

commit e400db356ff1f7bb1ae6c4b310e11d16062d892a
parent 96f40bb797fb36e8ad016d15a517e77853dec182
Author: Felicitus <felicitus@felicitus.org>
Date:   Thu, 29 Dec 2011 08:14:51 +0100

Added in-line editing of stock levels. Fixes #91

Diffstat:
Msrc/frontend/js/Components/Part/PartsGrid.js | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/frontend/js/Components/Project/ProjectReport.js | 2+-
Asrc/frontend/js/Components/User/Preferences/StockPreferences.js | 29+++++++++++++++++++++++++++++
Rsrc/frontend/js/Components/User/TipOfTheDayPreferences.js -> src/frontend/js/Components/User/Preferences/TipOfTheDayPreferences.js | 0
Rsrc/frontend/js/Components/User/UserPasswordChangePanel.js -> src/frontend/js/Components/User/Preferences/UserPasswordChangePanel.js | 0
Msrc/frontend/js/Components/User/UserPreferences.js | 4++--
Asrc/frontend/js/Dialogs/RememberChoiceMessageBox.js | 37+++++++++++++++++++++++++++++++++++++
7 files changed, 222 insertions(+), 3 deletions(-)

diff --git a/src/frontend/js/Components/Part/PartsGrid.js b/src/frontend/js/Components/Part/PartsGrid.js @@ -55,6 +55,14 @@ Ext.define('PartKeepr.PartsGrid', { } }); + this.editing = Ext.create('Ext.grid.plugin.CellEditing', { + clicksToEdit: 1 + }); + + this.editing.on("edit", this.onEdit, this); + + this.plugins = [ this.editing ]; + // Initialize the panel this.callParent(); @@ -114,6 +122,10 @@ Ext.define('PartKeepr.PartsGrid', { },{ header: i18n("Stock"), dataIndex: 'stockLevel', + editor: { + xtype:'numberfield', + allowBlank:false + }, renderer: this.stockLevelRenderer },{ header: i18n("Min. Stock"), @@ -177,5 +189,146 @@ Ext.define('PartKeepr.PartsGrid', { proxy.extraParams.start = 0; this.store.currentPage = 1; this.store.load({ start: 0}); + }, + /** + * Handles editing of the grid fields. Right now, only the stock level editing is supported. + * + * @param e An edit event, as documented in + * http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.plugin.CellEditing-event-edit + */ + onEdit: function (editor, e) { + switch (e.field) { + case "stockLevel": this.handleStockFieldEdit(e); break; + default: break; + } + }, + /** + * Handles the editing of the stock level field. Checks if the user has opted in to skip the + * online stock edit confirm window, and runs the changes afterwards. + * + * @param e An edit event, as documented in + * http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.plugin.CellEditing-event-edit + */ + handleStockFieldEdit: function (e) { + if (PartKeepr.getApplication().getUserPreference("partkeepr.inline-stock-change.confirm") === false) { + this.handleStockChange(e); + } else { + this.confirmStockChange(e); + } + }, + /** + * Opens the confirm dialog + * + * @param e An edit event, as documented in + * http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.plugin.CellEditing-event-edit + */ + confirmStockChange: function (e) { + var confirmText = ""; + var headerText = ""; + + if (e.value < 0) { + confirmText = sprintf( i18n("You wish to remove <b>%s %s</b> of the part <b>%s</b>. Is this correct?"), + abs(e.value), e.record.get("partUnitName"), e.record.get("name")); + + // Set the stock level to a temporary calculated value. + e.record.set("stockLevel", (e.originalValue - abs(e.value))); + headerText = i18n("Remove Part(s)"); + } else { + confirmText = sprintf( + i18n("You wish to set the stock level to <b>%s %s</b> of part <b>%s</b>. Is this correct?"), + abs(e.value), e.record.get("partUnitName"), e.record.get("name")); + + headerText = i18n("Set Stock Level for Part(s)"); + } + + var j = new PartKeepr.RememberChoiceMessageBox({ + escButtonAction: "cancel", + dontAskAgainProperty: "partkeepr.inlinestockremoval.ask", + dontAskAgainValue: false + }); + + j.show({ + title : headerText, + msg : confirmText, + buttons: Ext.Msg.OKCANCEL, + fn: this.afterConfirmStockChange, + scope : this, + originalOnEdit: e, + dialog: j + }); + }, + /** + * Callback for the stock removal confirm window. + * + * The parameters are documented on: + * http://docs.sencha.com/ext-js/4-0/#!/api/Ext.window.MessageBox-method-show + */ + afterConfirmStockChange: function (buttonId, text, opts) { + if (buttonId == "cancel") { + opts.originalOnEdit.record.set("stockLevel", opts.originalOnEdit.originalValue); + } + + if (buttonId == "ok") { + if (opts.dialog.rememberChoiceCheckbox.getValue() === true) { + PartKeepr.getApplication().setUserPreference("partkeepr.inline-stock-change.confirm", false); + } + + this.handleStockChange(opts.originalOnEdit); + } + }, + /** + * Handles the stock change. Automatically figures out which method to call (deleteStock or addStock) and + * sets the correct quantity. + * + * @param e An edit event, as documented in + * http://docs.sencha.com/ext-js/4-0/#!/api/Ext.grid.plugin.CellEditing-event-edit + */ + handleStockChange: function (e) { + var mode, quantity = 0; + + if (e.value < 0) { + mode = "deleteStock"; + quantity = abs(e.value); + } else { + if (e.originalValue <= e.value) { + mode = "deleteStock"; + quantity = e.originalValue - e.value; + } else { + mode = "addStock"; + quantity = e.value - e.originalValue; + } + } + + var call = new PartKeepr.ServiceCall( + "Part", + mode); + call.setParameter("stock", quantity); + call.setParameter("part", e.record.get("id")); + call.setHandler(Ext.bind(this.reloadPart, this, [ e ])); + call.doCall(); + }, + /** + * Reloads the current part + */ + reloadPart: function (opts) { + this.loadPart(opts.record.get("id"), opts); + }, + /** + * Load the part from the database. + */ + loadPart: function (id, opts) { + PartKeepr.Part.load(id, { + scope: this, + success: this.onPartLoaded + }); + }, + /** + * Callback after the part is loaded + */ + onPartLoaded: function (record, opts) { + var rec = this.store.findRecord("id", record.get("id")); + if (rec) { + rec.set("stockLevel", record.get("stockLevel")); + } } }); \ No newline at end of file diff --git a/src/frontend/js/Components/Project/ProjectReport.js b/src/frontend/js/Components/Project/ProjectReport.js @@ -76,7 +76,7 @@ Ext.define('PartKeepr.ProjectReportView', { header: i18n("Distributor Order Number"), dataIndex: 'distributor_order_number', flex: 1, editor: { - xtype: 'textfield', + xtype: 'textfield' } },{ header: i18n("Price per Item"), dataIndex: 'price', diff --git a/src/frontend/js/Components/User/Preferences/StockPreferences.js b/src/frontend/js/Components/User/Preferences/StockPreferences.js @@ -0,0 +1,28 @@ +Ext.define('PartKeepr.StockPreferencesPanel', { + extend: 'Ext.form.FormPanel', + title: i18n("Stock Preferences"), + bodyStyle: 'background:#DBDBDB;padding: 10px;', + initComponent: function () { + this.confirmInlineStockLevelChangesCheckbox = Ext.create("Ext.form.field.Checkbox", { + boxLabel: i18n("Confirm in-line stock level changes from the parts grid"), + handler: Ext.bind(this.confirmInlineStockLevelChangesHandler, this) + }); + + if (PartKeepr.getApplication().getUserPreference("partkeepr.inline-stock-change.confirm") === false) { + this.confirmInlineStockLevelChangesCheckbox.setValue(false); + } else { + this.confirmInlineStockLevelChangesCheckbox.setValue(true); + } + + this.items = [ this.confirmInlineStockLevelChangesCheckbox ]; + + this.callParent(); + }, + /** + * Handler when the "confirm changes" checkbox was clicked. + */ + confirmInlineStockLevelChangesHandler: function (checkbox, checked) { + PartKeepr.getApplication().setUserPreference("partkeepr.inline-stock-change.confirm", checked); + } +}); + + \ No newline at end of file diff --git a/src/frontend/js/Components/User/TipOfTheDayPreferences.js b/src/frontend/js/Components/User/Preferences/TipOfTheDayPreferences.js diff --git a/src/frontend/js/Components/User/UserPasswordChangePanel.js b/src/frontend/js/Components/User/Preferences/UserPasswordChangePanel.js diff --git a/src/frontend/js/Components/User/UserPreferences.js b/src/frontend/js/Components/User/UserPreferences.js @@ -7,8 +7,8 @@ Ext.define('PartKeepr.UserPreferencePanel', { this.passwordChangePanel = Ext.create("PartKeepr.UserPasswordChangePanel"); this.tipsPanel = Ext.create("PartKeepr.TipOfTheDayPreferencesPanel"); - - this.items = [ this.tipsPanel, this.passwordChangePanel ]; + this.stockPanel = Ext.create("PartKeepr.StockPreferencesPanel"); + this.items = [ this.tipsPanel, this.passwordChangePanel, this.stockPanel ]; this.callParent(); } }); \ No newline at end of file diff --git a/src/frontend/js/Dialogs/RememberChoiceMessageBox.js b/src/frontend/js/Dialogs/RememberChoiceMessageBox.js @@ -0,0 +1,36 @@ +Ext.define('PartKeepr.RememberChoiceMessageBox', { + extend: 'Ext.window.MessageBox', + + escButtonAction: null, + + initComponent: function () { + this.callParent(); + + this.rememberChoiceCheckbox = Ext.create("Ext.form.field.Checkbox", { + margin: { + top: "10px" + }, + boxLabel: i18n("Don't ask again") + }); + + this.topContainer.add(this.rememberChoiceCheckbox); + }, + onEsc: function() { + + if (this.escButtonAction !== null) { + var btnIdx; + + switch (this.escButtonAction) { + case "ok": btnIdx = 0; break; + case "yes": btnIdx = 1; break; + case "no": btnIdx = 2; break; + case "cancel": btnIdx = 3; break; + default: btnIdx = 3; break; + } + + this.btnCallback(this.msgButtons[btnIdx]); + } else { + this.callParent(); + } + } +});+ \ No newline at end of file