diff --git a/debian/changelog b/debian/changelog index 1445da47..251328bf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -hedera-web (22.46.18) stable; urgency=low +hedera-web (22.48.0) stable; urgency=low * Initial Release. diff --git a/forms/account/address-list/index.js b/forms/account/address-list/index.js index 051cde67..a68d195a 100644 --- a/forms/account/address-list/index.js +++ b/forms/account/address-list/index.js @@ -26,17 +26,17 @@ export default new Class({ Htk.Toast.showMessage(_('DefaultAddressModified')); } - ,onRemoveAddressClick(form) { + ,async onRemoveAddressClick(form) { if (confirm(_('AreYouSureDeleteAddress'))) { - form.set('isActive', false); - form.refresh(); + await form.set('isActive', false); + await form.refresh(); } } - ,onEditAddressClick(id) { + ,onEditAddressClick(address) { this.hash.setAll({ form: 'account/address', - address: id + address }); } }); diff --git a/forms/account/conf/index.js b/forms/account/conf/index.js index ba16b087..1cd8855a 100644 --- a/forms/account/conf/index.js +++ b/forms/account/conf/index.js @@ -38,40 +38,35 @@ export default new Class({ throw new Error(_('Passwords doesn\'t match')); var verificationToken = this.hash.$.verificationToken; - var params = {newPassword: newPassword}; + var params = {newPassword}; - if (verificationToken) { - params.verificationToken = verificationToken; - this.conn.send('user/restore-password', params, - this._onPassChange.bind(this)); - } else { - try { + let err; + try { + if (verificationToken) { + params.verificationToken = verificationToken; + await this.conn.send('user/restore-password', params); + } else { let userId = this.gui.user.id; params.oldPassword = oldPassword; - await this.conn.lbSend('PATCH', - `Accounts/${userId}/changePassword`, params, - ); - this._onPassChange(); - } catch(err) { - this._onPassChange(null, err); + await this.conn.patch( + `Accounts/${userId}/changePassword`, params); } - } - } - - ,_onPassChange(json, error) { - if (!error) { - this.$.changePassword.hide(); - this.hash.unset('verificationToken'); - Htk.Toast.showMessage(_('Password changed!')); - this.$.userForm.refresh(); - } else { - Htk.Toast.showError(error.message); + } catch(e) { + err = e; + Htk.Toast.showError(err.message); if (this.hash.$.verificationToken) this.$.newPassword.select(); else this.$.oldPassword.select(); + + return; } + + this.$.changePassword.hide(); + this.hash.unset('verificationToken'); + Htk.Toast.showMessage(_('Password changed!')); + this.$.userForm.refresh(); } ,onPassInfoClick() { diff --git a/forms/admin/connections/index.js b/forms/admin/connections/index.js index 4abece1c..dd2c5c59 100644 --- a/forms/admin/connections/index.js +++ b/forms/admin/connections/index.js @@ -21,12 +21,8 @@ export default new Class({ clearTimeout(this._timeoutId); } - ,onChangeUserClick(userName) { - this.gui.supplantUser(userName, - this._onUserSupplant.bind(this)); - } - - ,_onUserSupplant() { + ,async onChangeUserClick(userName) { + await this.gui.supplantUser(userName); this.hash.setAll({form: 'ecomerce/orders'}); } diff --git a/forms/admin/photos/index.js b/forms/admin/photos/index.js index b56e5392..97ff838e 100644 --- a/forms/admin/photos/index.js +++ b/forms/admin/photos/index.js @@ -13,8 +13,6 @@ export default new Class({ ,filesData: [] ,uploadCount: 0 - ,errors: false - ,uploadQueue: [] ,isUploading: false ,activate() { @@ -77,70 +75,58 @@ export default new Class({ this.setImageStatus(fileData, Status.NONE, 'add', _('Pending upload')); } - ,onUploadClick() { - var filesData = this.filesData; - var count = 0; + ,async onUploadClick() { + if (this.isUploading) return; + + const uploadQueue = []; + let hasFiles = false; - for (var i = 0; i < filesData.length; i++) { - var fileData = filesData[i]; + for (const fileData of this.filesData) { + if (fileData.status !== Status.NONE) continue; + this.setImageStatus( + fileData, Status.WAITING, 'cloud_upload', _('Waiting for upload')); + fileData.name.disabled = true; + uploadQueue.push(fileData); + hasFiles = true; + } - if (fileData.status === Status.NONE) { + if (!hasFiles) { + Htk.Toast.showWarning(_('There are no files to upload')); + return; + } + + this.isUploading = true; + let hasErrors = false; + + for (const fileData of uploadQueue) { + this.setImageStatus( + fileData, Status.UPLOADING, 'upload', _('Uploading file')); + + const formData = new FormData(); + formData.append('updateMatching', this.$.updateMatching.value); + formData.append('image', fileData.file); + formData.append('name', fileData.name.value); + formData.append('schema', this.$.schema.value); + formData.append('srv', 'json:image/upload'); + + try { + await this.conn.sendFormData(formData); this.setImageStatus( - fileData, Status.WAITING, 'cloud_upload', _('Waiting for upload')); - fileData.name.disabled = true; - this.uploadQueue.push(fileData); - count++; + fileData, Status.UPLOADED, 'cloud_done', _('Image uploaded')); + } catch(err) { + this.setImageStatus( + fileData, Status.NONE, 'error', err.message); + fileData.name.disabled = false; + hasErrors = true; } } - if (count === 0) - Htk.Toast.showWarning(_('There are no files to upload')); - else - this.uploadNextFile(); - } - - ,uploadNextFile() { - if (this.isUploading) - return; - - this.isUploading = true; - - var fileData = this.uploadQueue.shift(); - this.setImageStatus( - fileData, Status.UPLOADING, 'upload', _('Uploading file')); - - var formData = new FormData(); - formData.append('updateMatching', this.$.updateMatching.value); - formData.append('image', fileData.file); - formData.append('name', fileData.name.value); - formData.append('schema', this.$.schema.value); - formData.append('srv', 'json:image/upload'); - this.conn.sendFormData(formData, - this.onFileUpload.bind(this, fileData)); - } - - ,onFileUpload(fileData, data, error) { this.isUploading = false; - if (data) { - this.setImageStatus( - fileData, Status.UPLOADED, 'cloud_done', _('Image uploaded')); - } else { - this.setImageStatus( - fileData, Status.NONE, 'error', error.message); - fileData.name.disabled = false; - this.errors = true; - } - - if (this.uploadQueue.length === 0) { - if (this.errors) - Htk.Toast.showError(_('Some errors happened on upload')); - else - Htk.Toast.showMessage(_('Upload finished successfully')); - - this.errors = false; - } else - this.uploadNextFile(); + if (hasErrors) + Htk.Toast.showError(_('Some errors happened on upload')); + else + Htk.Toast.showMessage(_('Upload finished successfully')); } ,setImageStatus(fileData, status, icon, title) { diff --git a/forms/admin/users/index.js b/forms/admin/users/index.js index 708c9f42..37168668 100644 --- a/forms/admin/users/index.js +++ b/forms/admin/users/index.js @@ -12,12 +12,8 @@ export default new Class({ 'block' : 'none'; } - ,onChangeUserClick(userName) { - this.gui.supplantUser(userName, - this.onUserSupplant.bind(this)); - } - - ,onUserSupplant() { + ,async onChangeUserClick(userName) { + await this.gui.supplantUser(userName); this.hash.setAll({form: 'ecomerce/orders'}); } }); diff --git a/forms/cms/contact/index.js b/forms/cms/contact/index.js index 31b1c93c..7bff0faf 100644 --- a/forms/cms/contact/index.js +++ b/forms/cms/contact/index.js @@ -5,11 +5,9 @@ export default new Class({ Template: require('./ui.xml') ,activate() { - var self = this; - this.$.contactForm.onsubmit = function() { - self._onSubmit(); return false; + this.$.contactForm.onsubmit = () => { + this._onSubmit(); return false; }; - this.refreshCaptcha(); } @@ -21,22 +19,21 @@ export default new Class({ this.$.captchaImg.src = '?'+ Vn.Url.makeUri(params); } - ,_onSubmit() { - this.conn.sendForm(this.$.contactForm, - this._onResponse.bind(this)); - } - - ,_onResponse(json) { - var form = this.$.contactForm; - - if (json) { - form.reset(); - Htk.Toast.showMessage(_('DataSentSuccess')); - } else + ,async _onSubmit() { + const form = this.$.contactForm; + + try { + await this.conn.sendForm(this.$.contactForm); + } catch (err) { Htk.Toast.showError(_('ErrorSendingData')); + return; + } finally { + form['captcha'].value = ''; + this.refreshCaptcha(); + } - form['captcha'].value = ''; - this.refreshCaptcha(); + form.reset(); + Htk.Toast.showMessage(_('DataSentSuccess')); } }); diff --git a/forms/cms/location/index.js b/forms/cms/location/index.js index 5fd24122..a0ca3678 100644 --- a/forms/cms/location/index.js +++ b/forms/cms/location/index.js @@ -8,11 +8,12 @@ export default new Class({ ,locations: null - ,activate() { + ,async activate() { this.gui.loaderPush(); var sql = 'SELECT lat, lng, title, address, postcode, city, province, phone, language FROM location'; - this.conn.execQuery(sql, this.onLocationsDone.bind(this)); + const resultSet = await this.conn.execQuery(sql); + this.locations = resultSet.fetchData(); if (!gmapsIsLoaded) { gmapsLoadedCallback = this.gmapsLoaded.bind(this); @@ -25,18 +26,11 @@ export default new Class({ this.gmapsLoaded(); } - ,onLocationsDone(resultSet) { - this.locations = resultSet.fetchData(); - this.allLoaded(); - } - ,gmapsLoaded() { this.gui.loaderPop(); gmapsIsLoaded = true; this.allLoaded(); - } - ,allLoaded() { if (!this.locations || !gmapsIsLoaded) return; diff --git a/forms/ecomerce/basket/index.js b/forms/ecomerce/basket/index.js index 5e09c238..2e2ec1f2 100644 --- a/forms/ecomerce/basket/index.js +++ b/forms/ecomerce/basket/index.js @@ -4,17 +4,9 @@ export default new Class({ Extends: Hedera.Form, Template: require('./ui.xml'), - open() { - this.close(); - this.isOpen = true; - - Hedera.BasketChecker.check(this.conn, this.hash, - this.onBasketCheck.bind(this)); - }, - - onBasketCheck(isOk) { - if (isOk) - this.loadUi(); + async open() { + const isOk = await Hedera.BasketChecker.check(this.conn, this.hash); + if (isOk) await Hedera.Form.prototype.open.call(this); }, activate() { diff --git a/forms/ecomerce/catalog/index.js b/forms/ecomerce/catalog/index.js index edb5aaa0..8b6eddd9 100644 --- a/forms/ecomerce/catalog/index.js +++ b/forms/ecomerce/catalog/index.js @@ -6,22 +6,15 @@ const Catalog = new Class({ ,_menuShown: false - ,open() { - this.close(); - this.isOpen = true; - - if (!localStorage.getItem('hederaGuest')) { - Hedera.BasketChecker.check(this.conn, this.hash, - this.onBasketCheck.bind(this)); - } else { - var query = 'CALL mybasket_configureForGuest'; - this.conn.execQuery(query, this.loadUi.bind(this)); - } - } + ,async open() { + let isOk = true; - ,onBasketCheck(isOk) { - if (isOk) - this.loadUi(); + if (!localStorage.getItem('hederaGuest')) + isOk = await Hedera.BasketChecker.check(this.conn, this.hash); + else + await this.conn.execQuery('CALL mybasket_configureForGuest'); + + if (isOk) await Hedera.Form.prototype.open.call(this); } ,activate() { @@ -289,7 +282,7 @@ const Catalog = new Class({ Htk.Toast.showError(_('NoMoreAmountAvailable')); } - ,onConfirmClick() { + ,async onConfirmClick() { var sql = ''; var query = new Sql.String({query: 'CALL myBasket_addItem(#warehouse, #item, #amount);'}); var amountSum = 0; diff --git a/forms/ecomerce/checkout/index.js b/forms/ecomerce/checkout/index.js index 865e0ed0..8e9668ef 100644 --- a/forms/ecomerce/checkout/index.js +++ b/forms/ecomerce/checkout/index.js @@ -56,16 +56,17 @@ export default new Class({ this.$.assistantBar.disabled = disable; }, - onConfirmClick() { + async onConfirmClick() { this.disableButtons(true); const query = 'CALL myBasket_configure(#date, #method, #agency, #address)'; - this.conn.execQuery(query, - this.onBasketConfigured.bind(this), this.$.lot.$); - }, - - onBasketConfigured(resultSet) { - this.disableButtons(false); + let resultSet; + + try { + resultSet = await this.conn.execQuery(query, this.$.lot.$); + } finally { + this.disableButtons(false); + } if (!resultSet.fetchResult()) return; diff --git a/forms/ecomerce/confirm/index.js b/forms/ecomerce/confirm/index.js index 3c8f1a65..db1e9f78 100644 --- a/forms/ecomerce/confirm/index.js +++ b/forms/ecomerce/confirm/index.js @@ -4,17 +4,9 @@ export default new Class({ Extends: Hedera.Form, Template: require('./ui.xml'), - open() { - this.close(); - this.isOpen = true; - - Hedera.BasketChecker.check(this.conn, this.hash, - this.onBasketCheck.bind(this)); - }, - - onBasketCheck(isOk) { - if (isOk) - this.loadUi(); + async open() { + const isOk = await Hedera.BasketChecker.check(this.conn, this.hash); + if (isOk) await Hedera.Form.prototype.open.call(this); }, onOrderReady(form) { @@ -123,9 +115,9 @@ export default new Class({ window.history.back(); }, - onConfirmClick() { + async onConfirmClick() { this.disableButtons(true); - this.$.confirmQuery.execute(); + await this.$.confirmQuery.execute(); }, onConfirm(query, resultSet) { @@ -135,7 +127,7 @@ export default new Class({ this.$.successDialog.show(); }, - onDialogResponse() { + async onDialogResponse() { if (this.$.payMethod.value === 'CARD') { if (this.$.payAmount.value === 'EXCEEDED') var payAmount = this.$.excessAmount.value; @@ -146,9 +138,8 @@ export default new Class({ conn: this.conn, hash: this.hash }); - tpv.pay(payAmount, this.$.order.companyFk); + await tpv.pay(payAmount, this.$.order.companyFk); } else this.hash.setAll({form: 'ecomerce/orders'}); } }); - diff --git a/forms/ecomerce/orders/index.js b/forms/ecomerce/orders/index.js index d1b3d2e0..bcaa6057 100644 --- a/forms/ecomerce/orders/index.js +++ b/forms/ecomerce/orders/index.js @@ -9,12 +9,8 @@ export default new Class({ conn: this.conn, hash: this.hash }); - this.tpv.check(this._onTpvCheck.bind(this)); - }, - - _onTpvCheck(tpv, tpvOrder, tpvStatus) { - if (tpvStatus === 'ko') - this.$.errorDialog.show(); + const tpvStatus = this.tpv.check(); + if (tpvStatus === 'ko') this.$.errorDialog.show(); }, onBasketClick() { @@ -30,14 +26,14 @@ export default new Class({ // TPV - balanceConditionalFunc(field, value) { + balanceConditionalFunc(_, value) { if (value >= 0) Vn.Node.removeClass(this.$.balance, 'negative'); else Vn.Node.addClass(this.$.balance, 'negative'); }, - onPayButtonClick() { + async onPayButtonClick() { var amount = -this.$.debt.value; amount = amount <= 0 ? null : amount; @@ -50,13 +46,12 @@ export default new Class({ if (amount != null) { amount = parseFloat(amount.replace(',', '.')); - this.tpv.pay(amount, null); + await this.tpv.pay(amount, null); } }, - onDialogResponse(dialog, response) { + async onDialogResponse(_, response) { if (response == Htk.Dialog.Button.RETRY) - this.tpv.retryPay(); + await this.tpv.retryPay(); } }); - diff --git a/forms/ecomerce/ticket/index.js b/forms/ecomerce/ticket/index.js index 430734f2..f171c199 100644 --- a/forms/ecomerce/ticket/index.js +++ b/forms/ecomerce/ticket/index.js @@ -4,12 +4,10 @@ export default new Class({ Extends: Hedera.Form, Template: require('./ui.xml'), - onTicketChange(ticket) { - if (!ticket.value) - return; - - var params = {ticket: ticket.value}; - this.conn.execQuery('CALL myTicket_logAccess(#ticket)', null, params); + async onTicketChange(ticket) { + if (!ticket.value) return; + await this.conn.execQuery('CALL myTicket_logAccess(#ticket)', + {ticket: ticket.value}); }, onPrintClick() { diff --git a/forms/reports/shelves/index.js b/forms/reports/shelves/index.js index be2ab9a6..0cbb379c 100644 --- a/forms/reports/shelves/index.js +++ b/forms/reports/shelves/index.js @@ -2,20 +2,20 @@ import './style.scss'; export default new Class({ Extends: Hedera.Form, - Template: require('./ui.xml') + Template: require('./ui.xml'), - ,activate() { + activate() { this.$.lot.assign({ date: new Date(), useIds: false }); - } + }, - ,onConfigChange() { + onConfigChange() { this.$.lot.assignLot(this.$.config); - } + }, - ,onPreviewClick() { + onPreviewClick() { this.gui.openReport('shelves-report', this.$.lot); } }); diff --git a/import.js b/import.js index 02743d1c..46c8f0d4 100644 --- a/import.js +++ b/import.js @@ -1,4 +1,3 @@ - export const locales = { ca: cb => require([], () => cb(require.context('js', true, /locale\/ca.yml$/))), diff --git a/js/db/connection.js b/js/db/connection.js index 7419895f..badbdd49 100644 --- a/js/db/connection.js +++ b/js/db/connection.js @@ -39,47 +39,12 @@ Connection.implement({ * Runs a SQL query on the database. * * @param {String} sql The SQL statement - * @param {Function} callback The function to call when operation is done + * @return {ResultSet} The result */ - ,execSql(sql, callback) { - this.send('core/query', {'sql': sql}, - this._onExec.bind(this, callback)); - } - - /** - * Runs a stmt on the database. - * - * @param {Sql.Stmt} stmt The statement - * @param {Function} callback The function to call when operation is done - * @param {Object} params The query params - */ - ,execStmt(stmt, callback, params) { - this.execSql(stmt.render(params), callback); - } - - /** - * Runs a query on the database. - * - * @param {String} query The SQL statement - * @param {Function} callback The function to call when operation is done - * @param {Object} params The query params - */ - ,execQuery(query, callback, params) { - this.execStmt(new Sql.String({query: query}), callback, params); - } - - /* - * Parses a value to date. - */ - ,valueToDate(value) { - return fixTz(new Date(value)); - } - - /* - * Called when a query is executed. - */ - ,_onExec(callback, json, error) { + ,async execSql(sql) { + const json = await this.send('core/query', {sql}); const results = []; + let err; if (json) try { @@ -126,11 +91,39 @@ Connection.implement({ } else results.push(json[i]); } catch (e) { - error = e; + err = e; } - if (callback) - callback(new Db.ResultSet(results, error)); + return new Db.ResultSet(results, err); + } + + /** + * Runs a stmt on the database. + * + * @param {Sql.Stmt} stmt The statement + * @param {Object} params The query params + * @return {ResultSet} The result + */ + ,async execStmt(stmt, params) { + return await this.execSql(stmt.render(params)); + } + + /** + * Runs a query on the database. + * + * @param {String} query The SQL statement + * @param {Object} params The query params + * @return {ResultSet} The result + */ + ,async execQuery(query, params) { + return await this.execStmt(new Sql.String({query}), params); + } + + /* + * Parses a value to date. + */ + ,valueToDate(value) { + return fixTz(new Date(value)); } }); diff --git a/js/db/iterator.js b/js/db/iterator.js index 80161459..85d8eb1c 100644 --- a/js/db/iterator.js +++ b/js/db/iterator.js @@ -38,9 +38,9 @@ module.exports = new Class({ ,_model: null ,_row: -1 - ,refresh() { + ,async refresh() { if (this._model) - this._model.refresh(); + await this._model.refresh(); } /** @@ -68,17 +68,17 @@ module.exports = new Class({ this.row = this._model.insertRow(); } - ,performOperations() { + ,async performOperations() { if (this._model) - this._model.performOperations(); + await this._model.performOperations(); } /** * Removes the current row. */ - ,deleteRow() { + ,async deleteRow() { if (this._row >= 0) - this._model.deleteRow(this._row); + await this._model.deleteRow(this._row); } /** @@ -106,8 +106,8 @@ module.exports = new Class({ * @param {String} columnName The column name * @param {Object} value The new value */ - ,set(columnName, value) { - return this._model.set(this._row, columnName, value); + ,async set(columnName, value) { + return await this._model.set(this._row, columnName, value); } /** diff --git a/js/db/model.js b/js/db/model.js index 1afbe03f..6f15bd46 100644 --- a/js/db/model.js +++ b/js/db/model.js @@ -302,25 +302,9 @@ Model.implement({ return true; } - ,lazyRefresh() { + ,async lazyRefresh() { if (this._paramsChanged) - this.refresh(); - } - - /** - * Refresh the model data reexecuting the query on the database. - */ - ,refresh() { - const params = this._getHolderParams(); - - if (this._isReady(params)) { - this._setStatus(Status.LOADING); - this._lastParams = this._getHolderValues(); - this._paramsChanged = false; - this._conn.execStmt(this._stmt, - this._selectDone.bind(this), params); - } else - this.clean(); + await this.refresh(); } ,clean() { @@ -328,14 +312,29 @@ Model.implement({ this._setStatus(Status.CLEAN); } - ,_selectDone(resultSet) { - var result; - var dataResult; + /** + * Refresh the model data reexecuting the query on the database. + */ + ,async refresh() { + const params = this._getHolderParams(); + + if (!this._isReady(params)) { + this.clean(); + return; + } + this._setStatus(Status.LOADING); + this._lastParams = this._getHolderValues(); + this._paramsChanged = false; + + let result; + let dataResult; this._cleanData(); try { - for (var i = 0; result = resultSet.fetchResult(); i++) + const resultSet = await this._conn.execStmt(this._stmt, params); + + for (let i = 0; result = resultSet.fetchResult(); i++) if (i == this._resultIndex) dataResult = result; @@ -357,7 +356,7 @@ Model.implement({ for (column in this._requestedIndexes) this._buildIndex(column); - var sortColumn = null; + let sortColumn = null; if (this._requestedSortName) sortColumn = this._requestedSortName; @@ -560,7 +559,7 @@ Model.implement({ * @param {string} columnName The column name * @param {mixed} value The new value */ - ,set(rowIndex, columnName, value) { + ,async set(rowIndex, columnName, value) { if (!this.checkRowExists(rowIndex) && !this.checkColName(columnName)) return; @@ -605,7 +604,7 @@ Model.implement({ if (this.mode == Mode.ON_CHANGE && !(op.type & Operation.INSERT)) - this.performOperations(); + await this.performOperations(); } /** @@ -631,11 +630,11 @@ Model.implement({ * @param {number} columnIndex The column index * @param {mixed} value The new value */ - ,setByIndex(rowIndex, columnIndex, value) { + ,async setByIndex(rowIndex, columnIndex, value) { var columnName = this.getColumnName(columnIndex); if (columnName) - this.set(rowIndex, columnName, value); + await this.set(rowIndex, columnName, value); else console.warn('Db.Model: Column %d doesn\'t exist', columnIndex); } @@ -645,7 +644,7 @@ Model.implement({ * * @param {number} rowIndex The row index */ - ,deleteRow(rowIndex) { + ,async deleteRow(rowIndex) { if (!this.checkRowExists(rowIndex) || !this._checkTableUpdatable(this._mainTable)) return; @@ -681,7 +680,7 @@ Model.implement({ } if (this.mode === Mode.ON_CHANGE) - this.performOperations(); + await this.performOperations(); } /** @@ -716,28 +715,28 @@ Model.implement({ /** * Performs all model changes on the database. */ - ,performOperations() { - var ops = this._operations; + ,async performOperations() { + const ops = this._operations; if (ops.length === 0) { this.emit('operations-done'); return; } - var stmts = new Sql.MultiStmt(); + const stmts = new Sql.MultiStmt(); - var query = new Sql.String({query: 'START TRANSACTION'}); + let query = new Sql.String({query: 'START TRANSACTION'}); stmts.push(query); - for (var i = 0; i < ops.length; i++) { + for (let i = 0; i < ops.length; i++) { query = null; - var op = ops[i]; + let op = ops[i]; if (op.type & Operation.DELETE) { if (op.type & Operation.INSERT) continue; - var where = this._createWhere(this._mainTable, op, true); + const where = this._createWhere(this._mainTable, op, true); if (where) { query = new Sql.Delete({where}); @@ -746,8 +745,8 @@ Model.implement({ } else if (op.type & (Operation.INSERT | Operation.UPDATE)) { query = new Sql.MultiStmt(); - for (var tableIndex in op.tables) { - var stmt = this._createDmlQuery(op, parseInt(tableIndex)); + for (const tableIndex in op.tables) { + const stmt = this._createDmlQuery(op, parseInt(tableIndex)); query.push(stmt); } } @@ -760,11 +759,72 @@ Model.implement({ } } - var query = new Sql.String({query: 'COMMIT'}); + query = new Sql.String({query: 'COMMIT'}); stmts.push(query); - this._conn.execStmt(stmts, - this._onOperationsDone.bind(this, ops)); + const resultSet = await this._conn.execStmt(stmts); + const error = resultSet.getError(); + + if (error) { + this._operations = this._operations.concat(ops); + + for (let i = 0; i < ops.length; i++) + this._operationsMap[ops[i].row.index] = ops[i]; + + throw error; + } + + resultSet.fetchResult(); + let isOperation = false; + + for (let i = 0; i < ops.length; i++) { + const op = ops[i]; + const row = op.row; + + if (!(op.type & Operation.DELETE + && op.type & Operation.INSERT)) + // eslint-disable-next-line no-unused-vars + isOperation = true; + + if (op.type & Operation.DELETE) { + resultSet.fetchResult(); + } else if (op.type & (Operation.INSERT | Operation.UPDATE)) { + this.emit('row-updated-before', row.index); + + const updatedCols = []; + const cols = this.columns; + + for (let tableIndex in op.tables) { + let j = 0; + tableIndex = parseInt(tableIndex); + + resultSet.fetchResult(); + const newValues = resultSet.fetchRow(); + + if (op.tables[tableIndex] & Operation.INSERT) { + for (let i = 0; i < cols.length; i++) + if (cols[i].table === tableIndex) { + row[cols[i].name] = newValues[j++]; + updatedCols.push(i); + } + } else { + for (let i = 0; i < cols.length; i++) + if (cols[i].table === tableIndex + && op.oldValues[i] !== undefined) { + row[cols[i].name] = newValues[j++]; + updatedCols.push(i); + } + } + } + + this.emit('row-updated', row.index, updatedCols); + } + } + + resultSet.fetchResult(); + +// if (isOperation) + this.emit('operations-done'); this._resetOperations(); } @@ -827,71 +887,6 @@ Model.implement({ return multiStmt; } - ,_onOperationsDone(ops, resultSet) { - var error = resultSet.getError(); - - if (error) { - this._operations = this._operations.concat(ops); - - for (var i = 0; i < ops.length; i++) - this._operationsMap[ops[i].row.index] = ops[i]; - - throw error; - } - - resultSet.fetchResult(); - var isOperation = false; - - for (var i = 0; i < ops.length; i++) { - var op = ops[i]; - var row = op.row; - - if (!(op.type & Operation.DELETE - && op.type & Operation.INSERT)) - // eslint-disable-next-line no-unused-vars - isOperation = true; - - if (op.type & Operation.DELETE) { - resultSet.fetchResult(); - } else if (op.type & (Operation.INSERT | Operation.UPDATE)) { - this.emit('row-updated-before', row.index); - - var updatedCols = []; - var cols = this.columns; - - for (var tableIndex in op.tables) { - var j = 0; - tableIndex = parseInt(tableIndex); - - resultSet.fetchResult(); - var newValues = resultSet.fetchRow(); - - if (op.tables[tableIndex] & Operation.INSERT) { - for (var i = 0; i < cols.length; i++) - if (cols[i].table === tableIndex) { - row[cols[i].name] = newValues[j++]; - updatedCols.push(i); - } - } else { - for (var i = 0; i < cols.length; i++) - if (cols[i].table === tableIndex - && op.oldValues[i] !== undefined) { - row[cols[i].name] = newValues[j++]; - updatedCols.push(i); - } - } - } - - this.emit('row-updated', row.index, updatedCols); - } - } - - resultSet.fetchResult(); - -// if (isOperation) - this.emit('operations-done'); - } - /** * Undoes all unsaved changes made to the model. */ diff --git a/js/db/query.js b/js/db/query.js index fb55d4db..664688cc 100644 --- a/js/db/query.js +++ b/js/db/query.js @@ -80,13 +80,10 @@ module.exports = new Class({ this.query = query; } - ,execute() { - this._conn.execStmt(this._stmt, - this.onQueryDone.bind(this), this._lot); - } - - ,onQueryDone(resultSet) { + ,async execute() { + const resultSet = await this._conn.execStmt(this._stmt, this._lot); this.emit('ready', resultSet); + return resultSet; } ,onChange() { diff --git a/js/hedera/app.js b/js/hedera/app.js index 6a47e6f7..6e7ba1c2 100644 --- a/js/hedera/app.js +++ b/js/hedera/app.js @@ -1,6 +1,5 @@ - -var Login = require('./login'); -var Gui = require('./gui'); +const Login = require('./login'); +const Gui = require('./gui'); module.exports = new Class({ Extends: Vn.Object, @@ -14,23 +13,28 @@ module.exports = new Class({ } ,initialize() { - window.onerror = this._onWindowError.bind(this); - window.onunhandledrejection = e => this._onWindowRejection(e); - window.onunload = this._onWindowUnload.bind(this); + window.addEventListener('error', + e => this._onWindowError(e)); + window.addEventListener('unhandledrejection', + e => this._onWindowRejection(e)); + window.addEventListener('unload', + () => this._onWindowUnload()); this._hash = new Vn.Hash({window: window}); - var conn = new Db.Connection(); + const conn = new Db.Connection(); this.link({_conn: conn}, {'error': this._onConnError}); this.initAutoLogin(); } ,run() { - if (this.tryAutoLogin()) - return; - - var login = this._login = new Login({ + if (this.tryAutoLogin()) return; + this.showLogin(); + } + + ,showLogin() { + const login = this._login = new Login({ conn: this._conn, hash: this._hash }); @@ -38,97 +42,41 @@ module.exports = new Class({ login.show(); } - ,_onLogin() { + ,async _onLogin() { this._freeLogin(); - - if (this._gui) - return; + if (this._gui) return; - var gui = this._gui = new Gui({ + const gui = this._gui = new Gui({ conn: this._conn, hash: this._hash }); gui.on('logout', this._onLogout, this); - gui.show(); + await gui.show(); } - ,_onLogout() { + ,async _onLogout() { this.clearAutoLogin(); - this._freeGui(); - this.run(); + await this._freeGui(); + this.loggingOut = false; + this.showLogin(); } ,_onWindowUnload() { this.unref(); } - ,_onWindowError(message, file, line) { - var error = new Error(message); - error.fileName = file; - error.lineNumber = line; - this._notifyError(error); - } - - ,_onWindowRejection(event) { - const err = event.reason; - this._onConnError(null, err); - event.preventDefault(); - } - - ,_onConnError(conn, error) { - if (error instanceof Vn.JsonException) { - if (error.message) - Htk.Toast.showError(error.message); - else - switch (error.exception) { - case 'BadLogin': - Htk.Toast.showError(_('Invalid login')); - this._logout(); - break; - case 'Forbidden': - Htk.Toast.showError(_('You don\'t have enough privileges')); - break; - case 'UserDisabled': - Htk.Toast.showError(_('User disabled')); - this._logout(); - break; - case 'SessionExpired': - Htk.Toast.showError(_('Session expired')); - this._logout(); - break; - case 'OutdatedVersion': - this._newVersion(error); - break; - default: - Htk.Toast.showError(error.message); - } - } else if (error.statusCode) { - switch (error.statusCode) { - case 401: - Htk.Toast.showError(_('Invalid login')); - this._logout(); - break; - default: - Htk.Toast.showError(error.message); - } - } else { - console.error(error); - this._notifyError(error); + ,async _logout() { + if (this._gui && !this.loggingOut) { + this.loggingOut = true; + await this._gui.logout(); } } - ,_logout() { - if (this._gui) - this._gui.logout(); - } - ,_newVersion() { - if (this.ignoreVersion) - return; - + if (this.ignoreVersion) return; this.ignoreVersion = true; - var dialog = new Htk.Dialog({ + const dialog = new Htk.Dialog({ message: _('New version available') ,buttons: Htk.Dialog.Button.ACCEPT ,icon: 'warning' @@ -141,59 +89,43 @@ module.exports = new Class({ location.reload(); } - ,_notifyError(error) { - Htk.Toast.showError(_('Something went wrong')); - - var params = { - file: error.fileName - ,line: error.lineNumber - ,message: error.message - ,stack: error.stack - ,agent: navigator.userAgent - ,location: location.href - }; - this._conn.send('core/log', params); - } - ,_freeLogin() { - if (this._login) { - this._login.disconnectByInstance(this); - this._login.hide(); - this._login.unref(); - this._login = null; - } + if (!this._login) return; + this._login.disconnectByInstance(this); + this._login.hide(); + this._login.unref(); + this._login = null; } - ,_freeGui() { - if (this._gui) { - this._gui.disconnectByInstance(this); - this._gui.hide(); - this._gui.unref(); - this._gui = null; - } + ,async _freeGui() { + if (!this._gui) return; + this._gui.disconnectByInstance(this); + await this._gui.hide(); + this._gui.unref(); + this._gui = null; } ,_destroy() { this._freeLogin(); this._freeGui(); this.deinitAutoLogin(); - this._conn.unref(); - this._hash.unref(); + if (this._conn) this._conn.unref(); + if (this._hash) this._hash.unref(); } - // Auto login functionality + // Auto login ,_firstLogin: true ,initAutoLogin() { - var isGuest = new Vn.Param({ + const isGuest = new Vn.Param({ lot: this._hash, type: Boolean, name: 'guest' }); this.link({_isGuest: isGuest}, {'changed': this._onGuestChange}); - var token = new Vn.Param({ + const token = new Vn.Param({ lot: this._hash, type: String, name: 'token' @@ -212,12 +144,12 @@ module.exports = new Class({ } ,deinitAutoLogin() { - this._isGuest.unref(); - this._token.unref(); + if (this._isGuest) this._isGuest.unref(); + if (this._token) this._token.unref(); } ,autoLogin() { - var guest = localStorage.getItem('hederaGuest'); + const guest = localStorage.getItem('hederaGuest'); if (this._isGuest.value || guest) { localStorage.setItem('hederaGuest', true); @@ -236,7 +168,7 @@ module.exports = new Class({ } ,tryAutoLogin() { - var ok = this.autoLogin(); + const ok = this.autoLogin(); this._firstLogin = false; this._isGuest.value = undefined; @@ -252,5 +184,69 @@ module.exports = new Class({ ,clearAutoLogin() { localStorage.removeItem('hederaGuest'); } + + // Error management + + ,_onWindowError(event) { + this.globalHandler(event.error); + } + + ,_onWindowRejection(event) { + this.globalHandler(event.reason); + } + + ,async _onConnError(conn, err) { + if (!(err instanceof Vn.JsonException)) return; + switch (err.exception) { + case 'UserDisabled': + Htk.Toast.showError(_('User disabled')); + await this._logout(); + return; + case 'OutdatedVersion': + this._newVersion(); + return; + } + if (err.statusCode == 401 && !this._login) { + Htk.Toast.showError(_('Session expired')); + this._logout(); + } + } + + ,async globalHandler(err) { + try { + if (!err) return; + if (err instanceof Vn.JsonException) { + const statusCode = err.statusCode; + if (statusCode >= 400 && statusCode < 500) { + if (err.statusCode == 403) + Htk.Toast.showError(_('You don\'t have enough privileges')); + else { + switch (err.exception) { + case 'UserDisabled': + case 'OutdatedVersion': + return; + } + if (err.statusCode == 401) + return; + Htk.Toast.showError(err.message); + } + } else + Htk.Toast.showError(err.message); + } else { + Htk.Toast.showError(_('Something went wrong')); + if (this._conn) + await this._conn.send('core/log', { + file: err.fileName + ,line: err.lineNumber + ,message: err.message + ,stack: err.stack + ,agent: navigator.userAgent + ,location: location.href + }); + } + } catch(e) { + console.error(e); + } + } }); diff --git a/js/hedera/basket-checker.js b/js/hedera/basket-checker.js index abef361d..29a6c841 100644 --- a/js/hedera/basket-checker.js +++ b/js/hedera/basket-checker.js @@ -1,25 +1,21 @@ module.exports = { - check(conn, hash, callback) { + async check(conn, hash) { this.hash = hash; - conn.execQuery('CALL myBasket_check', - this._onBasketCheck.bind(this, callback)); - }, - - _onBasketCheck(callback, resultSet) { - var status = resultSet.fetchValue(); - - if (!status) - return; + const resultSet = await conn.execQuery('CALL myBasket_check'); - var isOk = status == 'UPDATED' || status == 'OK'; + const status = resultSet.fetchValue(); + if (!status) return; + + const isOk = status == 'UPDATED' || status == 'OK'; if (status == 'UPDATED') Htk.Toast.showWarning(_('Order items updated')); - if (callback) - callback(isOk); + if (!isOk) this.hash.setAll({form: 'ecomerce/checkout'}); + + return isOk; } }; diff --git a/js/hedera/form.js b/js/hedera/form.js index c8760bb9..518cb3f9 100644 --- a/js/hedera/form.js +++ b/js/hedera/form.js @@ -11,7 +11,7 @@ module.exports = new Class({ this.hash = gui.hash; } - ,loadUi() { + ,async loadUi() { if (!this.isOpen) return; @@ -47,22 +47,22 @@ module.exports = new Class({ this.gui.setForm(this.node); this.gui.setTitle(scope.$.title); this.gui.setActions(scope.$.actions); - this.activate(); + await this.activate(); } this.uiLoaded = true; } - ,unloadUi() { + ,async unloadUi() { if (!this.uiLoaded) return; if (this.node) { - this.deactivate(); + await this.deactivate(); this.gui.setTitle(null); this.gui.setActions(null); Vn.Node.remove(this.node); - this.deactivate(); + await this.deactivate(); this.node = null; } if (this.builder) { @@ -74,32 +74,30 @@ module.exports = new Class({ /** * Called when the form is opened. */ - ,open() { - this.close(); + ,async open() { + await this.close(); this.isOpen = true; - this.loadUi(); + await this.loadUi(); } /** * Called when the form is closed. */ - ,close() { - if (!this.isOpen) - return; - + ,async close() { + if (!this.isOpen) return; this.isOpen = false; - this.unloadUi(); + await this.unloadUi(); } /** * Called when the form is activated. */ - ,activate() {} + ,async activate() {} /** * Called when the form is deactivated. */ - ,deactivate() {} + ,async deactivate() {} ,_destroy() { this.close(); diff --git a/js/hedera/gui.js b/js/hedera/gui.js index 780db85e..20624eec 100644 --- a/js/hedera/gui.js +++ b/js/hedera/gui.js @@ -41,80 +41,23 @@ module.exports = new Class({ }); Vn.Component.prototype.initialize.call(this, props); + } + + ,async show() { + if (this._shown) return; + this._shown = true; - var sql = 'SELECT id, name, nickname FROM account.myUser;' + this.doc.body.appendChild(this.node); + Htk.Toast.pushTop(this.$.formHolder); + + const resultSet = await this._conn.execQuery( + 'SELECT id, name, nickname FROM account.myUser;' +'SELECT defaultForm FROM config;' +'SELECT url FROM imageConfig;' +'SELECT dbproduccion FROM vn.config;' - +'SELECT productionDomain, testDomain FROM config;'; - this._conn.execQuery(sql, this.onMainQueryDone.bind(this)); + +'SELECT productionDomain, testDomain FROM config;' + ); - this.loadMenu(); - } - - ,show() { - if (this._shown) - return; - - this._shown = true; - this.doc.body.appendChild(this.node); - Htk.Toast.pushTop(this.$.formHolder); - - if (Vn.isMobile()) { - this._onScrollHandler = this._onScroll.bind(this); - window.addEventListener('scroll', this._onScrollHandler ); - } - - this.formParam = new Vn.Param({ - lot: this.hash, - name: 'form', - }); - this.formParam.on('changed', this._onFormChange, this); - - if (!localStorage.getItem('hederaCookies')) { - localStorage.setItem('hederaCookies', true); - Htk.Toast.showWarning(_('By using this site you accept cookies')); - } - - this.supplantInit(); - } - - ,hide() { - if (!this._shown) - return; - - this._shown = false; - - if (Vn.isMobile()) - window.removeEventListener('scroll', this._onScrollHandler); - - Htk.Toast.popTop(); - this.formParam.unref(); - this.closeForm(); - this.hideMenu(); - Vn.Node.remove(this.node); - } - - ,logout() { - this.onLogoutClick(); - } - - ,async onLogoutClick() { - try { - await this._conn.close(); - } finally { - this.emit('logout'); - } - } - - ,_onConnLoadChange(conn, isLoading) { - if (isLoading) - this.loaderPush(); - else - this.loaderPop(); - } - - ,onMainQueryDone(resultSet) { // Retrieving the user name this.user = resultSet.fetchObject(); @@ -161,17 +104,70 @@ module.exports = new Class({ } else this.$.testLink.style.display = 'none'; - // Loading the default form + await this.loadMenu(); + + if (Vn.isMobile()) { + this._onScrollHandler = this._onScroll.bind(this); + window.addEventListener('scroll', this._onScrollHandler ); + } - this._onFormChange(); + await this.supplantInit(); + + this.formParam = new Vn.Param({ + lot: this.hash, + name: 'form', + }); + this.formParam.on('changed', this._onFormChange, this); + await this._onFormChange(); + + if (!localStorage.getItem('hederaCookies')) { + localStorage.setItem('hederaCookies', true); + Htk.Toast.showWarning(_('By using this site you accept cookies')); + } } - ,loadMenu() { - var sql = 'SELECT * FROM myMenu'; - this._conn.execQuery(sql, this._onMenuLoad.bind(this)); + ,async hide() { + if (!this._shown) + return; + + this._shown = false; + + if (Vn.isMobile()) + window.removeEventListener('scroll', this._onScrollHandler); + + Htk.Toast.popTop(); + if (this.formParam) { + this.formParam.unref(); + this.formParam = null; + } + await this.closeForm(); + this.hideMenu(); + Vn.Node.remove(this.node); + } + + ,async logout() { + await this.onLogoutClick(); + } + + ,async onLogoutClick() { + try { + if (!localStorage.getItem('hederaGuest')) + this._conn.close(); + } finally { + this.emit('logout'); + } } - ,_onMenuLoad(resultSet) { + ,_onConnLoadChange(conn, isLoading) { + if (isLoading) + this.loaderPush(); + else + this.loaderPop(); + } + + ,async loadMenu() { + const resultSet = await this._conn.execQuery('SELECT * FROM myMenu'); + // Retrieving menu sections var res = resultSet.fetchData(); @@ -359,7 +355,7 @@ module.exports = new Class({ this.hideMenu(); this.loaderPush(); - this.closeForm(); + await this.closeForm(); this.requestedForm = formPath; var newChoosedOption = this.menuOptions[formPath]; @@ -387,7 +383,7 @@ module.exports = new Class({ return; this.activeForm = new FormKlass(this); - this.activeForm.open(); + await this.activeForm.open(); } ,async importForm(path) { @@ -435,10 +431,10 @@ module.exports = new Class({ this.$.actionBar.appendChild(actions); } - ,closeForm() { + ,async closeForm() { if (this.activeForm) { Vn.Node.removeClass(this.$.formHolder, 'show'); - this.activeForm.close(); + await this.activeForm.close(); this.activeForm._destroy(); this.activeForm = null; } @@ -456,64 +452,44 @@ module.exports = new Class({ //++++++++++++++++++++++++++++++++++++++++++++++++++++++ Reports - ,openReport(reportName, lot) { - this.loaderPush(); - - var module = new Module('reports', reportName); - module.addCallback(this._onReportLoad.bind(this, lot)); - } - - ,_onReportLoad(lot, module) { - this.loaderPop(); - - if (module.error) { - Htk.Toast.showError(_('Error loading report')); - return; - } + ,async openReport(reportName, lot) { + try { + this.loaderPush(); + const module = new Module('reports', reportName); + await module.load(); - var report = new module.klass(module, this); - report.open(lot); + const report = new module.klass(module, this); + report.open(lot); + } catch(err) { + Htk.Toast.showError(_('Error loading report')); + } finally { + this.loaderPop(); + } } //++++++++++++++++++++++++++++++++++++++++++++++++++++++ Supplant - ,supplantInit() { + ,async supplantInit() { var user = sessionStorage.getItem('supplantUser'); + if (user == null) return; - if (user != null) - this.supplantUser(user); - } - - ,supplantUser(user, callback) { - this._conn.supplantUser(user, - this._onUserSupplant.bind(this, callback, user)); - } - - ,_onUserSupplant(callback, user, supplantOk, err) { - if (err) throw err; - + await this._conn.supplantUser(user); sessionStorage.setItem('supplantUser', user); - this.loadMenu(); + await this.loadMenu(); - var sql = 'SELECT nickname FROM account.myUser'; - this._conn.execQuery(sql, this._onSupplantName.bind(this)); - - if (callback) - callback(); - } + const res = await this._conn.execQuery( + 'SELECT nickname FROM account.myUser'); - ,_onSupplantName(resultSet) { - var userName = resultSet.fetchValue(); + const userName = res.fetchValue(); Vn.Node.setText(this.$.supplanted, userName); this.$.supplant.classList.toggle('show', true); } - ,onSupplantExitClick() { + ,async onSupplantExitClick() { this.$.supplant.classList.toggle('show', false); - this._conn.supplantEnd(); - sessionStorage.removeItem('supplantUser', - sessionStorage.getItem('supplantUser')); - this.loadMenu(); + await this._conn.supplantEnd(); + sessionStorage.removeItem('supplantUser'); + await this.loadMenu(); this._onFormChange(); } diff --git a/js/hedera/login.js b/js/hedera/login.js index 52d7445a..870518f6 100644 --- a/js/hedera/login.js +++ b/js/hedera/login.js @@ -3,10 +3,8 @@ require('./login.scss'); module.exports = new Class({ Extends: Vn.Component, - Properties: - { - conn: - { + Properties: { + conn: { type: Db.Connection ,set(x) { this.link({_conn: x}, {'loading-changed': this._onConnLoadChange}); @@ -62,7 +60,10 @@ module.exports = new Class({ this.emit('login'); } catch (err) { this._focusUserInput(); - throw err; + if (err.statusCode == 401) + Htk.Toast.showError(_('Invalid login')); + else + throw err; } finally { this.$.pass.value = ''; this._disableUi(false); @@ -85,20 +86,15 @@ module.exports = new Class({ this.$.submit.disabled = disabled; } - ,onPasswordLost() { - var user = this.$.user.value; + ,async onPasswordLost() { + var recoverUser = this.$.user.value; - if (!user) + if (!recoverUser) { Htk.Toast.showError(_('Please write your user name')); - else - this._conn.send('user/recover-password', {recoverUser: user}, - this._onPasswordRecovered.bind(this)); - } - - ,_onPasswordRecovered(json, error) { - if (error) - throw error; - + return; + } + + await this._conn.send('user/recover-password', {recoverUser}); Htk.Toast.showMessage(_('A mail has been sent wich you can recover your password')); } }); diff --git a/js/hedera/login.scss b/js/hedera/login.scss index 5238e4ec..3612484c 100644 --- a/js/hedera/login.scss +++ b/js/hedera/login.scss @@ -60,7 +60,8 @@ $login-margin-top: 50px; $login-margin-between: 55px; .vn-login > .column { - max-width: 300px; + max-width: 250px; + overflow: visible; & > .header { margin-top: $login-margin-top; diff --git a/js/hedera/module.js b/js/hedera/module.js index 66c32a63..dc522dda 100644 --- a/js/hedera/module.js +++ b/js/hedera/module.js @@ -1,77 +1,62 @@ module.exports = new Class({ - basePath: null - ,path: null - ,moduleName: null - ,callbacks: [] - ,localeReady: false - ,jsReady: false - ,uiReady: false - ,error: false - ,ready: false + basePath: null, + path: null, + moduleName: null, + resolvers: null, + status: null, - ,initialize(basePath, path) { - var absPath = basePath +'/'+ path; - - var aux = path.split('/'); - var moduleName = aux[aux.length - 1]; - - Vn.Locale.load(absPath, - this.onLocaleReady.bind(this)); - Vn.includeJs(absPath +'/'+ moduleName +'.js', - this.onJsReady.bind(this)); - Vn.loadXml(absPath +'/ui.xml', - this.onUiReady.bind(this)); + initialize(basePath, path) { + const aux = path.split('/'); + const moduleName = aux[aux.length - 1]; this.basePath = basePath; this.path = path; this.moduleName = moduleName; - } - - ,addCallback(callback) { - if (!this.ready) - this.callbacks.push(callback); - else - callback(this); - } + }, - ,onLocaleReady() { - this.localeReady = true; - this.onReady(); - } - - ,onJsReady(success) { - this.jsReady = true; - this.error = !success; - this.onReady(); - } - - ,onUiReady(success) { - this.uiReady = true; - this.error = !success; - this.onReady(); - } - - ,onReady() { - if (!(this.localeReady && this.jsReady && this.uiReady)) - return; - - this.ready = true; - - var klassName = this.toCamelCase(this.moduleName); - - try { - this.klass = Hedera[klassName]; - } catch (e) { - this.error = true; - console.error(e); + async load() { + switch(this.status) { + case 'ready': + return; + case 'loading': + return new Promise((resolve, reject) => { + this.resolvers.push(status => { + if (status == 'error') + return reject(new Error(`Module could not be loaded`)); + resolve(); + }); + }); } - var callbacks = this.callbacks; - this.callbacks = null; + this.status = 'loading'; + this.resolvers = []; + const absPath = `${this.basePath}/${this.path}`; + const requests = [ + Vn.includeJs(`${absPath}/${this.moduleName}.js`), + Vn.loadXml(`${absPath}/ui.xml`) + ]; - for (var i = 0; i < callbacks.length; i++) - callbacks[i](this); + try { + await Vn.Locale.load(absPath); + } catch(err) { + console.err(err); + } + + try { + await Promise.all(requests); + const klassName = this.toCamelCase(this.moduleName); + this.klass = Hedera[klassName]; + this.status = 'ready'; + } catch (err) { + this.status = 'error'; + console.error(err); + } + + for (const resolver of this.resolvers) + resolver(this.status); + + this.resolvers = null; } ,toCamelCase(dashedName) { diff --git a/js/hedera/report.css b/js/hedera/report.css index eba80e3f..0bb41036 100644 --- a/js/hedera/report.css +++ b/js/hedera/report.css @@ -1,34 +1,26 @@ -@font-face -{ +@font-face { font-family: 'Roboto'; src: url('roboto.ttf') format('truetype'); } -@media print -{ - body - { +@media print { + body { -webkit-print-color-adjust: exact; } - .sheet - { + .sheet { width: 100%; page-break-after: always; } - #topbar - { + #topbar { display: none; } } -@media screen -{ - body - { +@media screen { + body { background-color: #EEE; padding-top: 3.9em; } - .sheet - { + .sheet { width: 210mm; height: 297mm; background-color: white; @@ -36,8 +28,7 @@ box-shadow: 0 1mm 1mm #CCC; padding: 20mm; } - #topbar - { + #topbar { position: fixed; top: 0; left: 0; @@ -47,8 +38,7 @@ z-index: 100; box-shadow: 0 .1em .1em #AAA; } - #topbar > button - { + #topbar > button { float: right; background-color: transparent; color: white; @@ -60,24 +50,20 @@ height: 100%; padding: 0 1em; } - #topbar > button:hover - { + #topbar > button:hover { background-color: rgba(1, 1, 1, 0.2); } } -* -{ +* { font-family: 'Roboto'; } -body -{ +body { position: relative; margin: 0; width: 100%; z-index: -2; } -.sheet -{ +.sheet { position: relative; overflow: hidden; box-sizing: padding-box; @@ -86,35 +72,27 @@ body /* Widgets */ -.htk-grid -{ +.htk-grid { border-collapse: collapse; width: 100%; margin: 0 auto; padding: 0; } -.htk-grid > thead > tr -{ +.htk-grid > thead > tr { border-bottom: 1px solid #333; height: 10mm; } -.htk-grid > thead th -{ +.htk-grid > thead th { text-align: left; font-weight: normal; } -.htk-grid tr -{ +.htk-grid tr { height: 2em; } .htk-grid > thead th, -.htk-grid td -{ +.htk-grid td { padding-left: 3mm; } -.htk-grid .cell-spin -{ +.htk-grid .cell-spin { text-align: right; } - - diff --git a/js/hedera/social-bar.js b/js/hedera/social-bar.js index 5e69e00e..3cbc4306 100644 --- a/js/hedera/social-bar.js +++ b/js/hedera/social-bar.js @@ -33,28 +33,26 @@ module.exports = new Class({ node.className = 'htk-social-bar'; } - ,_refresh() { + ,async _refresh() { if (!this._conn || this._priority === null) return; const params = {priority: this._priority}; - var query = 'SELECT title, link, icon FROM social ' + const query = 'SELECT title, link, icon FROM social ' +'WHERE priority >= #priority ORDER BY priority'; - this._conn.execQuery(query, this._onQueryDone.bind(this), params); - } + const resultSet = await this._conn.execQuery(query, params); - ,_onQueryDone(resultSet) { Vn.Node.removeChilds(this._node); - var res = resultSet.fetchResult(); + const res = resultSet.fetchResult(); while (res.next()) { - var a = this.createElement('a'); + const a = this.createElement('a'); a.href = res.get('link'); a.target = '_blank'; this._node.appendChild(a); - var img = this.createElement('img'); + const img = this.createElement('img'); img.src = 'image/social/'+ res.get('icon'); img.alt = res.get('title'); img.title = res.get('title'); diff --git a/js/hedera/tpv.js b/js/hedera/tpv.js index d49c5160..6ee274bd 100644 --- a/js/hedera/tpv.js +++ b/js/hedera/tpv.js @@ -1,88 +1,75 @@ - module.exports = new Class({ Extends: Vn.Object ,tpvOrder: null ,tpvStatus: null - ,check(callback) { + ,check() { this.tpvOrder = this.hash.$.tpvOrder; this.tpvStatus = this.hash.$.tpvStatus; if (this.tpvStatus) { - const params = { + const query = 'CALL myTpvTransaction_end(#transaction, #status)'; + this.conn.execQuery(query, { transaction: this.tpvOrder, status: this.tpvStatus - }; - const query = 'CALL myTpvTransaction_end(#transaction, #status)'; - this.conn.execQuery(query, null, params); + }); } + + return this.tpvStatus; + } + + ,async pay(amount, company) { + await this._realPay(amount * 100, company); + } + + ,async _realPay(amount, company) { + if (!isNumeric(amount) || amount <= 0) + throw new UserError(_('AmountError')); + + let json; - if (callback) - callback(this, this.tpvOrder, this.tpvStatus); - } - - ,pay(amount, company) { - this._realPay(amount * 100, company); - } - - ,_realPay(amount, company) { - if (isNumeric(amount) && amount > 0) { - const params = { - amount: parseInt(amount) + try { + json = await this.conn.send('tpv/transaction', { + amount: parseInt(amount) ,urlOk: this._makeUrl('ok') ,urlKo: this._makeUrl('ko') ,company: company - }; + }); + } catch(err) { + throw new UserError(_('PayError')); + } + + const postValues = json.postValues; + + const form = document.createElement('form'); + form.method = 'POST'; + form.action = json.url; + document.body.appendChild(form); - this.conn.send('tpv/transaction', params, - this._onTransactionStart.bind(this)); - } else - Htk.Toast.showError(_('AmountError')); - } - - ,_onTransactionStart(json) { - if (json) { - const postValues = json.postValues; - - const form = document.createElement('form'); - form.method = 'POST'; - form.action = json.url; - document.body.appendChild(form); + for (var field in postValues) { + const input = document.createElement('input'); + input.type = 'hidden'; + input.name = field; + form.appendChild(input); - for (var field in postValues) { - const input = document.createElement('input'); - input.type = 'hidden'; - input.name = field; - form.appendChild(input); - - if (postValues[field]) - input.value = postValues[field]; - } - - form.submit(); - } else - Htk.Toast.showWarning(_('PayError')); + if (postValues[field]) + input.value = postValues[field]; + } + + form.submit(); } - ,retryPay() { - const params = {transaction: parseInt(this.tpvOrder)}; - + ,async retryPay() { const query = 'SELECT t.amount, m.companyFk ' +'FROM myTpvTransaction t ' +'JOIN tpvMerchant m ON m.id = t.merchantFk ' +'WHERE t.id = #transaction'; - this.conn.execQuery(query, - this._onRetryPayDone.bind(this), params); - } - - ,_onRetryPayDone(resultSet) { - const res = resultSet.fetchObject(); - - if (res) - this._realPay(res.amount, res.companyFk); - else - Htk.Toast.showError(_('AmountError')); + + const res = await this.conn.execQuery(query, + {transaction: parseInt(this.tpvOrder)}); + const payment = res.fetchObject(); + await this._realPay(payment.amount, payment.companyFk); } ,_makeUrl(status) { diff --git a/js/htk/image-editor/index.js b/js/htk/image-editor/index.js index d646930f..b83ac8ef 100644 --- a/js/htk/image-editor/index.js +++ b/js/htk/image-editor/index.js @@ -21,9 +21,8 @@ module.exports = new Class({ initialize(props) { this.loadTemplateFromString(Tpl); - var self = this; - this.$.form.onsubmit = function() { - self._onSubmit(); return false; + this.$.form.onsubmit = () => { + this._onSubmit(); return false; }; Component.prototype.initialize.call(this, props); @@ -38,24 +37,19 @@ module.exports = new Class({ this.emit('name-changed', newValue); }, - _onSubmit() { + async _onSubmit() { this.$.hiddenName.value = this.$.name.value; this.$.submit.disabled = true; this.$.spinner.start(); - this.conn.sendFormMultipart(this.$.form, - this._onResponse.bind(this)); - }, - - _onResponse(json, error) { - this.$.submit.disabled = false; - this.$.spinner.stop(); - - if (error) - throw error; - - Toast.showMessage(_('ImageAdded')); - this.emit('file-uploaded', this.$.name.value); + try { + await this.conn.sendFormMultipart(this.$.form); + Toast.showMessage(_('ImageAdded')); + this.emit('file-uploaded', this.$.name.value); + } finally { + this.$.submit.disabled = false; + this.$.spinner.stop(); + } }, setData(image, directory) { diff --git a/js/htk/toast/index.js b/js/htk/toast/index.js index 0c624a9c..94e3f9d6 100644 --- a/js/htk/toast/index.js +++ b/js/htk/toast/index.js @@ -83,6 +83,7 @@ module.exports = Vn.Node.remove(this._container); this._container = null; this.nodes = []; + this.lastMessage = null; } ,_createContainer() { @@ -102,6 +103,15 @@ module.exports = } ,_showText(message, className) { + if (!message) return; + + const last = this.lastMessage; + if (last + && last.message == message + && last.className == className) + return; + this.lastMessage = {message, className}; + this._createContainer(); if (this._timeouts.length >= this.maxMessages) diff --git a/js/vn/json-connection.js b/js/vn/json-connection.js index c1b8cbb8..380ce515 100644 --- a/js/vn/json-connection.js +++ b/js/vn/json-connection.js @@ -1,27 +1,27 @@ -var VnObject = require('./object'); -var JsonException = require('./json-exception'); +const VnObject = require('./object'); +const JsonException = require('./json-exception'); /** * Handler for JSON rest connections. */ module.exports = new Class({ - Extends: VnObject + Extends: VnObject, - ,_connected: false - ,_requestsCount: 0 - ,token: null + _connected: false, + _requestsCount: 0, + token: null, /** * Initilizes the connection object. */ - ,initialize() { + initialize() { VnObject.prototype.initialize.call(this); this.fetchToken(); - } + }, - ,fetchToken() { - var token = null; + fetchToken() { + let token = null; if (sessionStorage.getItem('vnToken')) token = sessionStorage.getItem('vnToken'); @@ -29,13 +29,13 @@ module.exports = new Class({ token = localStorage.getItem('vnToken'); this.token = token; - } + }, - ,clearToken() { + clearToken() { this.token = null; localStorage.removeItem('vnToken'); sessionStorage.removeItem('vnToken'); - } + }, /** * Opens the connection to the REST service. @@ -45,22 +45,22 @@ module.exports = new Class({ * @param {Boolean} remember Specifies if the user should be remembered * @return {Promise} Resolved when operation is done */ - ,async open(user, pass, remember) { + async open(user, pass, remember) { let params; if (user !== null && user !== undefined) { params = { - user: user - ,password: pass - ,remember: remember + user: user, + password: pass, + remember: remember }; } else params = null; try { - const json = await this.lbSend('POST', 'Accounts/login', params); + const json = await this.post('Accounts/login', params); - var storage = remember ? localStorage : sessionStorage; + const storage = remember ? localStorage : sessionStorage; storage.setItem('vnToken', json.token); this.token = json.token; @@ -70,153 +70,163 @@ module.exports = new Class({ this._closeClient(); throw err; } - } + }, /** * Closes the connection to the REST service. * * @return {Promise} Resolved when operation is done */ - ,async close() { - await this.lbSend('POST', 'Accounts/logout'); + async close() { + const token = this.token; this._closeClient(); this.emit('closed'); - } + + if (token) { + const config = { + headers: {'Authorization': token} + }; + await this.post('Accounts/logout', null, config); + } + }, - ,_closeClient() { + _closeClient() { this._connected = false; this.clearToken(); - } + }, /** * Supplants another user. * - * @param {String} user The user name - * @param {Function} callback The callback function + * @param {String} supplantUser The user name */ - ,supplantUser(user, callback) { - var params = {supplantUser: user}; - this.send('client/supplant', params, - this._onUserSupplant.bind(this, callback)); - } - - ,_onUserSupplant(callback, json, err) { - if (json) - this.token = json; - - if (callback) - callback(err == null, err); - } + async supplantUser(supplantUser) { + const json = await this.send('client/supplant', {supplantUser}); + this.token = json; + }, /** * Ends the user supplanting and restores the last login. */ - ,supplantEnd() { - this.lbSend('POST', 'Accounts/logout'); + async supplantEnd() { + await this.post('Accounts/logout'); this.fetchToken(); - } + }, /** * Executes the specified REST service with the given params and calls * the callback when response is received. * - * @param {String} restService The service path - * @param {Map} params The params to pass to the service - * @param {Function} callback The response callback + * @param {String} url The service path + * @param {Object} params The params to pass to the service + * @return {Object} The parsed JSON response */ - ,send(restService, params, callback) { - if (!params) - params = {}; + async send(url, params) { + if (!params) params = {}; + params.srv = `json:${url}`; + return await this.sendWithUrl('POST', '.', params); + }, - params.srv = 'json:'+ restService; - - this.sendWithUrl(params, callback, 'POST', '.'); - } - - ,sendForm(form, callback) { - var params = {}; - var elements = form.elements; + async sendForm(form) { + const params = {}; + const elements = form.elements; for (var i = 0; i < elements.length; i++) if (elements[i].name) params[elements[i].name] = elements[i].value; - this.sendWithUrl(params, callback, 'POST', form.action); - } + return await this.sendWithUrl('POST', form.action, params); + }, - ,sendFormMultipart(form, callback) { - var formData = new FormData(form); + async sendFormMultipart(form) { + return await this.request({ + method: 'POST', + url: form.action, + data: new FormData(form) + }); + }, - var request = new XMLHttpRequest(); - request.open('POST', form.action, true); - if (this.token) - request.setRequestHeader('Authorization', this.token); - request.onreadystatechange = - this._onStateChange.bind(this, request, callback); - request.send(formData); - - this._addRequest(); - } - - ,sendFormData(formData, callback) { - var request = new XMLHttpRequest(); - request.open('POST', '', true); - if (this.token) - request.setRequestHeader('Authorization', this.token); - request.onreadystatechange = - this._onStateChange.bind(this, request, callback); - request.send(formData); - - this._addRequest(); - } + async sendFormData(formData) { + return await this.request({ + method: 'POST', + url: '', + data: formData + }); + }, /* * Called when REST response is received. */ - ,sendWithUrl(params, callback, method, url) { - var request = new XMLHttpRequest(); - request.open(method, url, true); - request.setRequestHeader('Content-Type', - 'application/x-www-form-urlencoded'); - if (this.token) - request.setRequestHeader('Authorization', this.token); - request.onreadystatechange = - this._onStateChange.bind(this, request, callback); - request.send(Vn.Url.makeUri(params)); - - this._addRequest(); - } - - ,async lbSend(method, url, params) { - var request = new XMLHttpRequest(); - request.open(method, `api/${url}`, true); - request.setRequestHeader('Content-Type', - 'application/json;charset=utf-8'); - if (this.token) - request.setRequestHeader('Authorization', this.token); - - this._addRequest(); - return await new Promise((resolve, reject) => { - function callback(data, err) { - if (err) return reject(err); - resolve(data); + async sendWithUrl(method, url, params) { + return await this.request({ + method, + url, + data: Vn.Url.makeUri(params), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' } - - request.onreadystatechange = - this._onStateChange.bind(this, request, callback); - request.send(params && JSON.stringify(params)); }); - } + }, - ,_addRequest() { + async get(url, config) { + config = Object.assign({}, config, { + method: 'GET', + url: `api/${url}` + }); + return await this.request(config); + }, + + async post(url, data, config) { + return await this.requestData('POST', url, data, config); + }, + + async patch(url, data, config) { + return await this.requestData('PATCH', url, data, config); + }, + + async requestData(method, url, data, config) { + config = Object.assign({}, config, { + method, + url: `api/${url}`, + data: data && JSON.stringify(data), + }); + + config.headers = Object.assign({}, config.headers, { + 'Content-Type': 'application/json;charset=utf-8' + }); + return await this.request(config); + }, + + async request(config) { + const request = new XMLHttpRequest(); + request.open(config.method, config.url, true); + if (this.token) + request.setRequestHeader('Authorization', this.token); + + const headers = config.headers; + if (headers) + for (const header in headers) + request.setRequestHeader(header, headers[header]); + + const promise = new Promise((resolve, reject) => { + request.onreadystatechange = + () => this._onStateChange(request, resolve, reject); + }); + + request.send(config.data); + this._addRequest(); + return await promise; + }, + + _addRequest() { this._requestsCount++; if (this._requestsCount === 1) this.emit('loading-changed', true); - } + }, - ,_onStateChange(request, callback) { + _onStateChange(request, resolve, reject) { if (request.readyState !== 4) return; @@ -225,17 +235,17 @@ module.exports = new Class({ if (this._requestsCount === 0) this.emit('loading-changed', false); - var data = null; - var error = null; - - try { + let data = null; + let error = null; + try { if (request.status == 0) { - var ex = new JsonException(); - ex.message = _('The server does not respond, please check your Internet connection'); - throw ex; + const err = new JsonException(); + err.message = _('The server does not respond, please check your Internet connection'); + err.statusCode = request.status; + throw err; } - var contentType = null; + let contentType = null; try { contentType = request @@ -247,14 +257,14 @@ module.exports = new Class({ } if (contentType != 'application/json') { - var ex = new JsonException(); - ex.message = request.statusText; - ex.code = request.status; - throw ex; + const err = new JsonException(); + err.message = request.statusText; + err.statusCode = request.status; + throw err; } - var json; - var jsData; + let json; + let jsData; if (request.responseText) json = JSON.parse(request.responseText); @@ -264,8 +274,9 @@ module.exports = new Class({ if (request.status >= 200 && request.status < 300) { data = jsData; } else { - var exception = jsData.exception; - var error = jsData.error; + let exception = jsData.exception; + let error = jsData.error; + let err = new JsonException(); if (exception) { exception = exception @@ -273,41 +284,37 @@ module.exports = new Class({ .replace(/Exception$/, '') .replace(/^Vn\.Web\./, ''); - var ex = new JsonException(); - ex.exception = exception; - ex.message = jsData.message; - ex.code = jsData.code; - ex.file = jsData.file; - ex.line = jsData.line; - ex.trace = jsData.trace; + err.exception = exception; + err.message = jsData.message; + err.code = jsData.code; + err.file = jsData.file; + err.line = jsData.line; + err.trace = jsData.trace; + err.statusCode = request.status; } else if (error) { - var ex = new Error(); - ex.name = error.name; - ex.message = error.message; - ex.code = error.code; - ex.statusCode = request.status; + err.message = error.message; + err.code = error.code; + err.statusCode = request.status; + } else { + err.message = request.statusText; + err.statusCode = request.status; } - throw ex; + throw err; } } catch (e) { data = null; error = e; } - if (callback) - try { - callback(data, error); - error = null; - } catch (e) { - error = e; - } - + if (error) { + reject(error); + if (error.exception == 'SessionExpired') this.clearToken(); this.emit('error', error); - } + } else + resolve(data); } }); - diff --git a/js/vn/json-exception.js b/js/vn/json-exception.js index 03414baa..318cfbc8 100644 --- a/js/vn/json-exception.js +++ b/js/vn/json-exception.js @@ -1,22 +1,15 @@ /** * This class stores the database errors. */ -module.exports = new Class -({ - exception: null - ,message: null - ,code: null - ,file: null - ,line: null - ,trace: null - - ,initialize(exception, message, code, file, line, trace) { +module.exports = class JsonException { + constructor(exception, message, code, file, line, trace, statucCode) { + this.name = 'JsonException'; this.exception = exception; this.message = message; this.code = code; this.file = file; this.line = line; this.trace = trace; + this.statusCode = statucCode; } -}); - +} diff --git a/js/vn/object.js b/js/vn/object.js index 2b2c3668..9ae2306b 100644 --- a/js/vn/object.js +++ b/js/vn/object.js @@ -245,6 +245,7 @@ module.exports = class VnObject { } _unlink(object) { + if (!object) return; object.disconnectByInstance(this); object.unref(); } diff --git a/js/vn/vn.js b/js/vn/vn.js index a53a8431..6546f0b9 100644 --- a/js/vn/vn.js +++ b/js/vn/vn.js @@ -99,27 +99,18 @@ Object.assign(Vn, { ,_createIncludeData(path) { var includeData = { - depCount: 0 - ,success: false - ,loaded: false - ,callbacks: [] - ,dependants: [] + path, + depCount: 0, + success: false, + loaded: false, + callbacks: [], + dependants: [], }; this.includes[path] = includeData; return includeData; } - ,_handleCallback(includeData, callback) { - if (!callback) - return; - - if (includeData.success) - callback(includeData.loaded); - else - includeData.callbacks.push(callback); - } - ,_resolveDeps(includeData) { includeData.success = true; @@ -240,17 +231,29 @@ Object.assign(Vn, { this.currentCallback = callback; } + ,async _handleCallback(includeData) { + if (includeData.success) return; + + return new Promise((resolve, reject) => { + function callback(loaded) { + if (!loaded) + return reject(new Error(`Could not load resource: ${includeData.path}`)); + resolve(); + } + + includeData.callbacks.push(callback); + }); + } + /** * Includes a new Javascript in the current document, if the script * is already included, does nothing and calls the callback. * * @param {string} fileName The script file name - * @param {Function} callback The function to call when script is - * downloaded and included */ - ,includeJs(fileName, callback, skipVersion) { + ,async includeJs(fileName, skipVersion) { var includeData = this._realIncludeJs(fileName, skipVersion); - this._handleCallback(includeData, callback); + return this._handleCallback(includeData); } ,_realIncludeJs(fileName, skipVersion) { @@ -270,11 +273,11 @@ Object.assign(Vn, { script.src = src; script.onload = - this._onScriptLoad.bind(this, includeData, true); + () => this._onScriptLoad(includeData, true); script.onerror = - this._onScriptLoad.bind(this, includeData, false); + () => this._onScriptLoad(includeData, false); script.onreadystatechange = - this._onScriptStateChange.bind(this, includeData, script); + () => this._onScriptStateChange(includeData, script); this.head.appendChild(script); } @@ -314,11 +317,10 @@ Object.assign(Vn, { * Request an XML file. * * @param {string} path The file path - * @param {Function} callback The function to call when file is downloaded */ - ,loadXml(path, callback) { + ,async loadXml(path) { var includeData = this._realLoadXml(path); - this._handleCallback(includeData, callback); + return this._handleCallback(includeData); } ,_realLoadXml(path) { @@ -329,7 +331,7 @@ Object.assign(Vn, { var request = new XMLHttpRequest(); request.onreadystatechange = - this._onXmlReady.bind(this, includeData, request); + () => this._onXmlReady(includeData, request); request.open('get', path + this.getVersion(), true); request.send(); } diff --git a/package.json b/package.json index d5ac76b1..ec82b530 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hedera-web", - "version": "22.46.18", + "version": "22.48.20", "description": "Verdnatura web page", "license": "GPL-3.0", "repository": { diff --git a/reports/shelves-report/shelves-report.js b/reports/shelves-report/shelves-report.js index a19cd10c..d7ff9483 100644 --- a/reports/shelves-report/shelves-report.js +++ b/reports/shelves-report/shelves-report.js @@ -7,18 +7,16 @@ Hedera.ShelvesReport = new Class({ ,trayThickness: 2 ,trayMargin: 5 - ,open(lot) { + ,async open(lot) { this.lot = lot; - var query = + const query = 'SELECT id, name, nTrays, topTrayHeight, trayHeight, width, depth '+ 'FROM shelf WHERE id = #shelf; '+ 'CALL item_listAllocation(#warehouse, #date, #family, #namePrefix, #useIds)'; - this.conn.execQuery(query, this.onQueryExec.bind(this), lot.$); - } - - ,onQueryExec(resultSet) { + const resultSet = await this.conn.execQuery(query, lot.$); + // Fetch query data const row = resultSet.fetchObject();