0
1
Fork 0

refs 3971 Rest requests promisified

This commit is contained in:
Juan Ferrer 2022-11-28 09:51:31 +01:00
parent 922f27e71a
commit 6640314879
38 changed files with 875 additions and 1041 deletions

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
hedera-web (22.46.18) stable; urgency=low
hedera-web (22.48.0) stable; urgency=low
* Initial Release.

View File

@ -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
});
}
});

View File

@ -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() {

View File

@ -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'});
}

View File

@ -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) {

View File

@ -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'});
}
});

View File

@ -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'));
}
});

View File

@ -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;

View File

@ -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() {

View File

@ -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;

View File

@ -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;

View File

@ -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'});
}
});

View File

@ -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();
}
});

View File

@ -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() {

View File

@ -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);
}
});

View File

@ -1,4 +1,3 @@
export const locales = {
ca: cb => require([],
() => cb(require.context('js', true, /locale\/ca.yml$/))),

View File

@ -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));
}
});

View File

@ -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);
}
/**

View File

@ -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.
*/

View File

@ -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() {

View File

@ -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);
}
}
});

View File

@ -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;
}
};

View File

@ -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();

View File

@ -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();
}

View File

@ -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'));
}
});

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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');

View File

@ -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) {

View File

@ -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) {

View File

@ -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)

View File

@ -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);
}
});

View File

@ -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;
}
});
}

View File

@ -245,6 +245,7 @@ module.exports = class VnObject {
}
_unlink(object) {
if (!object) return;
object.disconnectByInstance(this);
object.unref();
}

View File

@ -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();
}

View File

@ -1,6 +1,6 @@
{
"name": "hedera-web",
"version": "22.46.18",
"version": "22.48.20",
"description": "Verdnatura web page",
"license": "GPL-3.0",
"repository": {

View File

@ -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();