var isDebug = true; /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ * * Author RAL * */ /*global console, exports, isDebug, window */ /** * This class activates when StaticResourceComponentJava add the 'isDebug' variable to the javascript generated file * * If a module is in development or the application is running the tests, add the 'isDebug' variable will be set to true * * This option is intended to run additional code (checks, etc) that will not be run while in production * * This improves performance at the same time that the developer have a tool to improve stability. */ var OB = window.OB || {}; OB.UTIL = window.OB.UTIL || {}; OB.UTIL.Debug = window.OB.UTIL.Debug || {}; (function () { var root = this; var debug; if (typeof exports !== 'undefined') { OB.UTIL.Debug = exports; } else { OB.UTIL.Debug = root.OB.UTIL.Debug = {}; } OB.UTIL.Debug.VERSION = "0.1"; OB.UTIL.Debug.isDebug = function () { return (typeof isDebug !== 'undefined'); }; if (OB.UTIL.Debug.isDebug()) { console.error("OB.UTIL.Debug " + OB.UTIL.Debug.VERSION + " is available"); } // add an error handler while in debug if (OB.UTIL.Debug.isDebug()) { window.onerror = function (e, url, line) { var errorInfo; if (typeof (e) === 'string') { errorInfo = e + '. Line number: ' + line + '. File uuid: ' + url + '.'; console.error(errorInfo); } }; } /** * Executes the callback if the 'isDebug' variable is set to true (inserted by the StaticResourceComponentJava.java class) * @param {Function} callback the callback to be executed * @param {[type]} callerThis if the 'this' variable needs to be passed * @return {[type]} nothing */ OB.UTIL.Debug.execute = function (callback, callerThis) { if (OB.UTIL.Debug.isDebug()) { if (!callback) { console.error("You are calling OB.UTIL.Debug.execute without a callback"); return; } callback.call(callerThis); } }; /** * If the objectName is undefined, an exception is shown * @param {[type]} objectName [description] * @param {[type]} message [description] * @return {Boolean} [description] */ OB.UTIL.Debug.isDefined = function (objectName, message) { if (OB.UTIL.Debug.isDebug()) { if (typeof objectName === 'undefined') { if (message) { console.error(message); } else { console.error("Object is undefined"); } return false; } return true; } }; OB.UTIL.Debug.simulateOffline = function () { if (OB.UTIL.Debug.isDebug()) { window.localStorage.setItem('SimulateOffline', true); } }; OB.UTIL.Debug.isSimulateOffline = function () { if (OB.UTIL.Debug.isDebug()) { return false; } var isFlag = window.localStorage.getItem('SimulateOffline'); if (isFlag) { if (isFlag === 'true') { return true; } } return false; }; // OB.UTIL.Debug.isTrue = function (condition, message) { // if (OB.UTIL.Debug.isDebug()) { // if (!OB.UTIL.Debug.isDefined(condition)) { // return; // } // if (condition) { // if (message) { // console.error(message); // } else { // console.error("Object is undefined"); // } // } // } // }; }()); /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ * * Author RAL * */ /*global console, exports, window */ /** * This class is intended for: * - version management * - easily maintain deprecated code * * TODO: * - please, check issue https://issues.openbravo.com/view.php?id=27400 * - in the StaticResourceComponent.java, add code to transfer versions to this class * - add the mobile.core version * - add check to get is the version is up, equal or down the current version */ var OB = window.OB || {}; OB.UTIL = OB.UTIL || {}; (function () { var root = this; if (typeof exports !== 'undefined') { OB.UTIL.VersionManagement = exports; } else { OB.UTIL.VersionManagement = root.OB.UTIL.VersionManagement = {}; } OB.UTIL.VersionManagement.VERSION = "0.2"; // console.log("OB.UTIL.VersionManagement " + OB.UTIL.VersionManagement.VERSION + " is available"); var registeredDeprecations = []; // Current version info OB.UTIL.VersionManagement.current = []; /** * TODO: return if the versionToCheck is the current or a higher version */ // OB.UTIL.VersionManagement.isCurrentOrHigher = function (versionToCheck) { // }; /** * A deprecation must be registered first and loaded when the javascript is loaded. * This provides a fast way to know all the deprecations in the code * @param {[type]} deprecationId each deprecation must provide a unique id * @param {version} introducedInVersion the version in which the deprecation is introduced * @param {string} inDevelopmentMessage the message to show in development * @return {undefined} */ OB.UTIL.VersionManagement.registerDeprecation = function (deprecationId, introducedInVersion, inDevelopmentMessage) { // in development argument checks OB.UTIL.Debug.isDefined(deprecationId, "Missing required argument 'deprecationId' in OB.UTIL.VersionManagement.registerDeprecation"); OB.UTIL.Debug.isDefined(introducedInVersion, "Missing required argument 'introducedInVersion' in OB.UTIL.VersionManagement.registerDeprecation"); OB.UTIL.Debug.isDefined(inDevelopmentMessage, "Missing required argument 'inDevelopmentMessage' in OB.UTIL.VersionManagement.registerDeprecation"); OB.UTIL.Debug.execute(function () { var isAlreadyRegistered = registeredDeprecations.some(function (element) { if (element.deprecationId === deprecationId) { return true; } }); if (isAlreadyRegistered) { console.error("The deprecation id: " + deprecationId + " ('" + inDevelopmentMessage + "'') have already been registered"); } }); // register the deprecation registeredDeprecations.push({ deprecationId: deprecationId, introducedInVersion: introducedInVersion, inDevelopmentMessage: inDevelopmentMessage }); }; /** * Handles deprecated code. * The backwardCompatibleCallback will execute while in production * The inDevelopmentCallback will only be executed while in development * @param {[type]} deprecationId the deprecation id provided when registerDeprecation was call * @param {callback} backwardCompatibleCallback the callback that will always be executed * @param {callback} inDevelopmentCallback the callback to be executed only while in development. use warning to inform the developer * @param {object} callerThis the 'this' of the caller * @return {undefined} */ OB.UTIL.VersionManagement.deprecated = function (deprecationId, backwardCompatibleCallback, inDevelopmentCallback, callerThis) { // in development argument checks OB.UTIL.Debug.isDefined(deprecationId, "Missing required argument 'deprecationId' in OB.UTIL.VersionManagement.deprecated"); OB.UTIL.Debug.isDefined(backwardCompatibleCallback, "Missing required argument 'backwardCompatibleCallback' in OB.UTIL.VersionManagement.deprecated"); // check if its already registered var registeredDeprecation; registeredDeprecations.some(function (element) { if (element.deprecationId === deprecationId) { registeredDeprecation = element; return; } }); OB.UTIL.Debug.isDefined(registeredDeprecation, "The deprecation with id: " + deprecationId + " has not been registered with OB.UTIL.registerDeprecation"); // execute the code that provides the backward compatilibily backwardCompatibleCallback.call(callerThis); // Execute the warning callback only in development. We don't want this warnings to reach production OB.UTIL.Debug.execute(function () { if (!inDevelopmentCallback) { inDevelopmentCallback = function (deprecationMessage) { console.warn(deprecationMessage); }; } var deprecationMessage = "Deprecated (since " + registeredDeprecation.introducedInVersion.rootName + registeredDeprecation.introducedInVersion.major + "." + registeredDeprecation.introducedInVersion.minor + "): " + registeredDeprecation.inDevelopmentMessage; inDevelopmentCallback.call(callerThis, deprecationMessage); }); }; /** * Shows in the console all the registered deprecations */ OB.UTIL.VersionManagement.getDeprecations = function () { registeredDeprecations.forEach(function (element) { console.log(element.deprecationId + " (since " + element.introducedInVersion.rootName + element.introducedInVersion.major + "." + element.introducedInVersion.minor + "): " + element.inDevelopmentMessage); }); }; /** * Global versions for the mobile.core module */ // Add mobileCore version // TODO: pick this information from the backend OB.UTIL.VersionManagement.current.mobileCore = { rootName: 'RR14Q', major: 4, minor: 0 }; // Add WebSQL database version for mobile.core OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase = { name: 'OBMOBCDB', size: 4 * 1024 * 1024, displayName: 'Mobile DB', major: '1', minor: '0' }; /** * Register active deprecations. * Deprecations must be registered before calling the 'deprecated' method */ OB.UTIL.VersionManagement.registerDeprecation(27332, { rootName: 'RR14Q', major: '4', minor: '0' }, "OB.UTILS namespace has been removed"); OB.UTIL.VersionManagement.registerDeprecation(27349, { rootName: 'RR14Q', major: '4', minor: '0' }, "The use of 'OB.MobileApp.model.hookManager' is a child of the model of the terminal. Please use 'OB.UTIL.HookManager'. More info: http://wiki.openbravo.com/wiki/How_to_Add_Hooks"); /** * Global deprecations have to be executed somewhere, this is a good place */ OB.UTIL.VersionManagement.deprecated(27332, function () { OB.UTILS = OB.UTILS || {}; }); }()); /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ * * Author RAL * */ /*global exports, console, Backbone, enyo, document, OB, setTimeout, clearTimeout */ /* The SynchornizationHelper class is intended to watch asynchronous calls in the application This class does only 2 things: - fire a 'synchronizing' event when registered (see below) asynchronous calls in the application starts - fire a 'synchronized' event when all the registered asynchronous calls have finished These events can and should be received by: - ui elements that have to be disabled because the underlying asynchronous calls are blocking its correct behavior (e.g.: the login button or the total to pay button) - model elements that have to wait until underlying asynchronous calls have finished (e.g.: update the local database) Required: - The asynchronous calls to be watched have to be registered by one of the available SynchronizationHelper methods Howto implement the SynchronizationHelper: - find the asynchronous calls that are vital for the application - add a SynchronizationHelper.busyUntilFinishes and get the returning id - add a SynchronizationHelper.finished() when the asynchronous call have finished, success or fail - subscribe to the events 'synchronizing' and 'synchronized', the elements that you want to depend on the SynchronizationHelper status Notes: - to see the SynchronizationHelper log, set verbose = true - console.error is used because it attaches the stacktrace to the message Example of registering/unregistering asynchronous calls (ob-datasource.js): function serviceGET(source, dataparams, callback, callbackError, async) { var synchId = SynchronizationHelper.busyUntilFinishes('serviceGET ' + source); ... var ajaxRequest = new enyo.Ajax({ ... success: function (inSender, inResponse) { SynchronizationHelper.finished(synchId, 'serviceGET'); ... }, fail: function (status, inResponse) { SynchronizationHelper.finished(synchId, 'serviceGET'); ... } }); ajaxRequest.go().response('success').error('fail'); } Example of event subscriptions (ob-login.js): enyo.kind({ name: 'OB.OBPOSLogin.UI.LoginButton', ... handlers: { synchronizing: 'disableButton', synchronized: 'enableButton' }, disableButton: function () { this.setDisabled(true); }, enableButton: function () { this.setDisabled(false); }, initComponents: function () { this.inherited(arguments); ... this.setDisabled(true); } }); */ (function () { var root = this; var SynchronizationHelper; if (typeof exports !== "undefined") { SynchronizationHelper = exports; } else { SynchronizationHelper = root.SynchronizationHelper = {}; } SynchronizationHelper.VERSION = "0.7"; var verbose = false; var delaySynchronizedEvent = 150; var timeoutThreshold = 8000; var eventId = null; var timeoutEventId = null; var clearCount = 0; var busyCount = -1; var watchedModelName = []; var isSynchronizingSent = false; var isTimeout = false; var busyProcessIdCounter = 0; var busyProcessArray = []; var STATUS = { SYNCHRONIZED: 0, SYNCHRONIZING: 1, UNKNOWN: -1 }; var currentStatus = STATUS.UNKNOWN; var lastAccess = new Date().getTime(); if (verbose) { console.log("SynchronizationHelper %s is available and verbosing", SynchronizationHelper.VERSION); } /** * Retrieves the current synchronization state. This is a vital method for the automation tests * @return {Boolean} true: the app is synchronized; false: the app is synchronizing */ SynchronizationHelper.isSynchronized = function () { return currentStatus === STATUS.SYNCHRONIZED; }; var elapsedTime = function () { return (new Date().getTime() - lastAccess); }; /** * Sends the 'syncrhonizing' event */ var sendSynchronizing; sendSynchronizing = function () { setTimeout(function () { // stop trying to synchronize if there has been a timeout if (isTimeout) { isSynchronizingSent = false; return; } // delay the event until the UI has loaded if (document.readyState === "complete") { busyCount += 1; if (OB.MobileApp.view) { OB.MobileApp.view.waterfall('synchronizing'); } if (OB.MobileApp.model) { OB.MobileApp.model.trigger('synchronizing'); } if (verbose) { console.error("SH: (" + busyCount + ") synchronizing sent"); } } else { if (verbose) { console.error("SH: (" + (busyCount + 1) + ") synchronizing delayed"); } sendSynchronizing(); } }, 10); }; /** * Sends the 'syncrhonized' event */ var sendSynchronized = function () { isSynchronizingSent = false; clearCount = 0; currentStatus = STATUS.SYNCHRONIZED; // fired the event when the heap is empty setTimeout(function () { if (SynchronizationHelper.isSynchronized()) { if (OB.MobileApp.model) { OB.MobileApp.model.trigger('synchronized'); } if (OB.MobileApp.view) { OB.MobileApp.view.waterfall('synchronized'); } if (verbose) { console.error("SH: (" + busyCount + ") synchronized sent"); } } }, 1); }; /** * If busy is unable to return to a 'synchronized' state, it was because the 'busyUntilFinishes' and the 'finished' calls are * unpaired. We don't want to be staled in a 'synchronizing' state for ever. So, raise an exception and free the state */ var timeout = function () { isTimeout = true; var s = ""; busyProcessArray.forEach(function (element) { s += "(" + element.busyProcessId + ") " + element.msg + "\n"; }); // this error should never raise in production console.error("SynchronizationHelper timeout error: This process didn't finish: " + s); busyProcessArray = []; sendSynchronized(); }; /** * Main algorithm to watch and update the synchronization state */ var busy = function (msg) { if (SynchronizationHelper.isSynchronized()) { // set to log level error, so it shows in the automated tests browser.log. Have to be updated to debug anytime soon (tm) OB.UTIL.Debug.execute(function () { console.error("SynchronizationHelper: Elapsed time since the last synchronized state (" + elapsedTime() + ")"); }); } lastAccess = new Date().getTime(); currentStatus = STATUS.SYNCHRONIZING; if (isSynchronizingSent === false) { isTimeout = false; isSynchronizingSent = true; sendSynchronizing(); } if (eventId !== null) { clearTimeout(eventId); eventId = null; clearCount += 1; } if (timeoutEventId !== null) { clearTimeout(timeoutEventId); timeoutEventId = null; } // be sure that the synchronizing state is released timeoutEventId = setTimeout(function () { timeout(); }, timeoutThreshold); if (busyProcessArray.length > 0) { return; } clearTimeout(timeoutEventId); timeoutEventId = null; isTimeout = false; eventId = setTimeout(function () { if (isSynchronizingSent === false) { console.error("SynchronizationHelper: A 'synchronized' event should always be preceeded by a 'synchronizing' event"); } sendSynchronized(); }, delaySynchronizedEvent); }; /** * Call this method when want to watch a backbone model. Be careful because it adds a lot of overhead depending on the number of events fired in the model */ SynchronizationHelper.watchModel = function (model, msg, forceWatch) { var modelName = model.modelName || "NA"; // we don't want the LogClient to modify the synchronization state if (modelName === "LogClient") { return; } if (!forceWatch) { busy(modelName + ", " + msg); return; } if (watchedModelName.indexOf(modelName) < 0) { watchedModelName.push(modelName); model.on('all', function (eventName, object, third) { // if (eventName.indexOf('change') >= 0) { // return; // } busy(modelName + ", fired: " + eventName + ", " + msg); }); } }; /** * Call this method when the process you want to add to the SynchronizationHelper watch is not an asynchronous call but, still, vital */ SynchronizationHelper.busy = function (msg) { if (verbose) { console.error("SH.busy (+%sms): '%s'", new Date().getTime() - lastAccess, msg); } busy(msg); }; /** * Call this method before an asynchronous is made and keep the returned id * @return {int} assigned id */ SynchronizationHelper.busyUntilFinishes = function (msg) { var busyProcessId = busyProcessIdCounter; if (verbose) { console.error("SH.busyUntilFinishes (" + busyProcessId + ") " + msg); } busyProcessIdCounter += 1; busyProcessArray.push({ busyProcessId: busyProcessId, msg: msg }); busy(msg); return busyProcessId; }; /** * Call this method when the asynchronous call have finished, providing the id retrieved in the 'busyUntilFinishes' method * @param {int} busyProcessId the id that was assigned by the 'busyUntilFinishes' method */ SynchronizationHelper.finished = function (busyProcessId, msg) { if (verbose) { console.error("SH.finished (" + busyProcessId + ") " + msg); } var index = -1; var i; for (i = 0; i < busyProcessArray.length; i++) { var element = busyProcessArray[i]; if (element.busyProcessId === busyProcessId) { index = i; break; } } if (index < 0) { console.error("SynchronizationHelper: Unbalanced finished. The process '(" + busyProcessId + ") " + msg + "' cannot be found"); return; } busyProcessArray.splice(index, 1); busy(msg); }; /** * Just for logging. With timestamp. Useful to check if a call 'busyUntilFinishes' or 'busy' is needed * The timestamp value should always be less that the 'delaySynchronizedEvent' value is no 'synchronized' event should be fired inbetween */ SynchronizationHelper.log = function (msg, group) { // groups add fine logging. activate to get this functionality // if (!group || group < 1) { // return; // } OB.UTIL.Debug.execute(function () { console.error("SH.log (+%sms): '%s'", elapsedTime(), msg); }); }; /** * Show when enyo and backbone are available */ if (verbose) { var dummyModel = new(Backbone.Model.extend({ initialize: function () { console.log('SH: backbone loaded'); } }))(); enyo.load('', function () { console.log('SH: enyo loaded'); // this gets called when enyo has loaded the library }); } }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global define,_,console, Backbone, enyo */ (function () { OB = window.OB || {}; OB.Cache = window.OB.Cache || {}; function buildIdentifier(obj) { var identifier, p = ''; for (p in obj) { if (obj.hasOwnProperty(p) && obj[p]) { identifier += obj[p] + ';'; } } return identifier; } function saveObj(cacheName, paramObj, value) { OB.Cache.dataStructure[cacheName][buildIdentifier(paramObj)] = value; } OB.Cache.dataStructure = {}; OB.Cache.initCache = function (cacheName) { if (!OB.Cache.dataStructure[cacheName]) { OB.Cache.dataStructure[cacheName] = {}; } }; OB.Cache.putItem = function (cacheName, paramObj, value) { OB.Cache.initCache(cacheName); saveObj(cacheName, paramObj, value); }; OB.Cache.getItem = function (cacheName, paramObj) { OB.Cache.initCache(cacheName); return OB.Cache.dataStructure[cacheName][buildIdentifier(paramObj)]; }; OB.Cache.hasItem = function (cacheName, paramObj) { OB.Cache.initCache(cacheName); return !OB.UTIL.isNullOrUndefined(OB.Cache.getItem(cacheName, paramObj)); }; }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, Backbone, _, enyo, SynchronizationHelper, OB, window */ (function () { OB.DS = window.OB.DS || {}; OB.DS.MAXSIZE = 100; function serviceSuccess(inResponse, callback) { if (inResponse._entityname) { callback([inResponse]); } else { var response = inResponse.response; if (!response) { // the response is empty response = {}; response.error = {}; response.error.message = "Unknown error"; response.status = 501; } var status = response.status; if (response.contextInfo && OB.MobileApp.model.get('context')) { OB.UTIL.checkContextChange(OB.MobileApp.model.get('context'), response.contextInfo); } if (status === 0) { callback(response.data, response.message, response.lastUpdated); return; } OB.error(response); if (response.errors) { if (OB.MobileApp.model.get('isLoggingIn')) { OB.MobileApp.model.set("datasourceLoadFailed", true); OB.UTIL.showConfirmation.display('Error', response.errors.substring(0, 400), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.MobileApp.model.logout(); OB.UTIL.showLoading(true); } }], { onHideFunction: function () { OB.UTIL.showLoading(true); OB.MobileApp.model.logout(); } }); } callback({ exception: { message: response.errors.id, status: response } }); return; } if (response.error && response.error.message) { if (OB.MobileApp.model.get('isLoggingIn')) { OB.MobileApp.model.set("datasourceLoadFailed", true); OB.UTIL.showConfirmation.display('Error', response.error.message.substring(0, 400), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.MobileApp.model.logout(); OB.UTIL.showLoading(true); } }], { onHideFunction: function () { OB.UTIL.showLoading(true); OB.MobileApp.model.logout(); } }); } callback({ exception: { message: response.error.message, status: response } }); return; } callback({ exception: { message: 'Unknown error', status: response } }); } } function serviceError(inResponse, callback, callbackError) { if (callbackError) { callbackError({ exception: { message: OB.I18N.getLabel('OBPOS_MsgApplicationServerNotAvailable'), status: inResponse } }); } else { callback({ exception: { message: OB.I18N.getLabel('OBPOS_MsgApplicationServerNotAvailable'), status: inResponse } }); } } function servicePOST(source, dataparams, callback, callbackError, async, timeout) { if (async !== false) { async = true; } var ajaxRequest = new enyo.Ajax({ url: '../../org.openbravo.mobile.core.service.jsonrest/' + source, cacheBust: false, sync: !async, timeout: timeout, method: 'POST', handleAs: 'json', contentType: 'application/json;charset=utf-8', ignoreForConnectionStatus: dataparams.parameters && dataparams.parameters.ignoreForConnectionStatus ? dataparams.parameters.ignoreForConnectionStatus : false, data: JSON.stringify(dataparams), success: function (inSender, inResponse) { if (this.processHasFailed) { return; } serviceSuccess(inResponse, callback); }, fail: function (inSender, inResponse) { this.processHasFailed = true; inResponse = inResponse || {}; if (inSender && inSender === "timeout") { inResponse.timeout = true; } if (!this.ignoreForConnectionStatus) { OB.MobileApp.model.triggerOffLine(); } serviceError(inResponse, callback, callbackError); } }); ajaxRequest.go(ajaxRequest.data).response('success').error('fail'); } function serviceGET(source, dataparams, callback, callbackError, async) { var synchId = SynchronizationHelper.busyUntilFinishes('serviceGET ' + source); if (async !== false) { async = true; } var ajaxRequest = new enyo.Ajax({ url: '../../org.openbravo.mobile.core.service.jsonrest/' + source + '/' + encodeURI(JSON.stringify(dataparams)), cacheBust: false, sync: !async, method: 'GET', handleAs: 'json', ignoreForConnectionStatus: dataparams.parameters && dataparams.parameters.ignoreForConnectionStatus ? dataparams.parameters.ignoreForConnectionStatus : false, contentType: 'application/json;charset=utf-8', success: function (inSender, inResponse) { SynchronizationHelper.finished(synchId, 'serviceGET'); serviceSuccess(inResponse, callback); }, fail: function (inSender, inResponse) { SynchronizationHelper.finished(synchId, 'serviceGET'); if (!this.ignoreForConnectionStatus) { OB.MobileApp.model.triggerOffLine(); } serviceError(inResponse, callback, callbackError); } }); ajaxRequest.go().response('success').error('fail'); } // Process object OB.DS.Process = function (source) { this.source = source; }; OB.DS.Process.prototype.exec = function (params, callback, callbackError, async, timeout) { var data = {}, i, attr; for (attr in params) { if (params.hasOwnProperty(attr)) { data[attr] = params[attr]; } } if (OB.DS.commonParams) { for (i in OB.DS.commonParams) { if (OB.DS.commonParams.hasOwnProperty(i)) { data[i] = OB.DS.commonParams[i]; } } } data.appName = OB.MobileApp.model.get('appName') || 'OBMOBC'; servicePOST(this.source, data, callback, callbackError, async, timeout); }; // Source object OB.DS.Request = function (source, lastUpdated) { this.model = source && source.prototype && source.prototype.modelName && source; // we're using a Backbone.Model as source this.source = (this.model && this.model.prototype.source) || source; // we're using a plain String as source if (!this.source) { throw 'A Request must have a source'; } this.lastUpdated = lastUpdated; }; OB.DS.Request.prototype.exec = function (params, callback, callbackError, async) { var p, i; var data = {}; if (params) { p = {}; for (i in params) { if (params.hasOwnProperty(i)) { if (typeof params[i] === 'string') { p[i] = { value: params[i], type: 'string' }; } else if (typeof params[i] === 'number') { if (params[i] === Math.round(params[i])) { p[i] = { value: params[i], type: 'long' }; } else { p[i] = { value: params[i], type: 'bigdecimal' }; } } else if (typeof params[i] === 'boolean') { p[i] = { value: params[i], type: 'boolean' }; } else { p[i] = params[i]; } } } data.parameters = p; } if (OB.DS.commonParams) { for (i in OB.DS.commonParams) { if (OB.DS.commonParams.hasOwnProperty(i)) { data[i] = OB.DS.commonParams[i]; } } } if (this.lastUpdated) { data.lastUpdated = this.lastUpdated; } data.appName = OB.MobileApp.model.get('appName') || 'OBMOBC'; serviceGET(this.source, data, callback, callbackError, async); }; function check(elem, filter) { var p; for (p in filter) { if (filter.hasOwnProperty(p)) { if (typeof (filter[p]) === 'object') { return check(elem[p], filter[p]); } else { if (filter[p].substring(0, 2) === '%i') { if (!new RegExp(filter[p].substring(2), 'i').test(elem[p])) { return false; } } else if (filter[p].substring(0, 2) === '%') { if (!new RegExp(filter[p].substring(2)).test(elem[p])) { return false; } } else if (filter[p] !== elem[p]) { return false; } } } } return true; } function findInData(data, filter) { var i, max; if ($.isEmptyObject(filter)) { return { exception: 'filter not defined' }; } else { for (i = 0, max = data.length; i < max; i++) { if (check(data[i], filter)) { return data[i]; } } return null; } } function execInData(data, filter, filterfunction) { var newdata, info, i, max, f, item; if ($.isEmptyObject(filter) && !filterfunction) { return { data: data.slice(0, OB.DS.MAXSIZE), info: (data.length > OB.DS.MAXSIZE ? 'OBPOS_DataMaxReached' : null) }; } else { f = filterfunction || function (item) { return item; }; newdata = []; info = null; for (i = 0, max = data.length; i < max; i++) { if (check(data[i], filter)) { item = f(data[i]); if (item) { if (newdata.length >= OB.DS.MAXSIZE) { info = 'OBPOS_DataMaxReached'; break; } newdata.push(data[i]); } } } return { data: newdata, info: info }; } } // DataSource objects // OFFLINE GOES HERE OB.DS.DataSource = function (request) { this.request = request; this.cache = null; }; _.extend(OB.DS.DataSource.prototype, Backbone.Events); OB.DS.DataSource.prototype.load = function (params, incremental) { var me = this; this.cache = null; this.request.exec(params, function (data, message, lastUpdated) { if (data.exception) { OB.error('Error in datasource', data); if (data.exception.message) { throw data.exception.message; } else { throw data.exception; } } if (lastUpdated) { window.localStorage.setItem('lastUpdatedTimestamp' + me.request.model.prototype.modelName, lastUpdated); } me.cache = data; if (me.request.model && !me.request.model.prototype.online) { OB.Dal.initCache(me.request.model, data, function () { me.trigger('ready'); }, function () { OB.error(arguments, me.request.model.prototype); }, incremental); } else { me.trigger('ready'); } }); }; OB.DS.DataSource.prototype.find = function (filter, callback) { if (this.cache) { callback(findInData(this.cache, filter)); } else { this.on('ready', function () { callback(findInData(this.cache, filter)); }, this); } }; OB.DS.DataSource.prototype.exec = function (filter, callback) { if (this.cache) { var result1 = execInData(this.cache, filter); callback(result1.data, result1.info); } else { this.on('ready', function () { var result2 = execInData(this.cache, filter); callback(result2.data, result2.info); }, this); } }; }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global define,_,console, Backbone, enyo, Uint8Array, SynchronizationHelper, OB, window, setTimeout*/ OB.Dal = OB.Dal || {}; (function () { OB.Dal.EQ = '='; OB.Dal.NEQ = '!='; OB.Dal.CONTAINS = 'contains'; OB.Dal.STARTSWITH = 'startsWith'; OB.Dal.ENDSWITH = 'endsWith'; OB.Dal.stackSize = 0; /** * TODO: localStorage * This is a function to centralize TODO Dal code related to localstorage * As of changes in the issue 27166, this flow is now executed */ OB.Dal.missingLocalStorageLogic = function () { OB.UTIL.Debug.execute(function () { console.error("Critical: Not Implemented"); }); }; OB.Dal.get_uuid = function () { var array; var uuid = "", i, digit = ""; if (window.crypto && window.crypto.getRandomValues) { array = new Uint8Array(16); window.crypto.getRandomValues(array); for (i = 0; i < array.length; i++) { digit = array[i].toString(16).toUpperCase(); if (digit.length === 1) { digit = "0" + digit; } uuid += digit; } return uuid; } function S4() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1).toUpperCase(); } return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4()); }; OB.Dal.transform = function (model, obj) { var tmp = {}, modelProto = model.prototype, val, properties; properties = model.getProperties ? model.getProperties() : modelProto.properties; _.each(properties, function (property) { var prop; if (_.isString(property)) { prop = property; val = obj[modelProto.propertyMap[property]]; } else { prop = property.name; val = obj[property.column]; } if (val === 'false') { tmp[prop] = false; } else if (val === 'true') { tmp[prop] = true; } else { tmp[prop] = val; } }); return new model(tmp); }; OB.Dal.getWhereClause = function (criteria, propertyMap) { var appendWhere = true, firstParam = true, sql = '', params = [], res = {}, orAnd = ' AND '; if (criteria && !_.isEmpty(criteria)) { if (criteria.obdalcriteriaType) { orAnd = ' ' + criteria.obdalcriteriaType + ' '; delete criteria.obdalcriteriaType; } _.each(_.keys(criteria), function (k) { var undef, colName, val = criteria[k], operator = (val !== undef && val !== null && val.operator !== undef) ? val.operator : '=', value = (val !== undef && val !== null && val.value !== undef) ? val.value : val; if (k !== '_orderByClause' && k !== '_limit') { if (appendWhere) { sql = sql + ' WHERE '; params = []; appendWhere = false; } if (_.isArray(propertyMap)) { if (k === '_filter') { colName = '_filter'; } else { colName = _.find(propertyMap, function (p) { return k === p.name; }).column; } } else { colName = propertyMap[k]; } sql = sql + (firstParam ? '' : orAnd) + ' ' + colName + ' '; if (value === null) { sql = sql + ' IS null '; } else { if (operator === OB.Dal.EQ) { sql = sql + ' = ? '; } else if (operator === OB.Dal.NEQ) { sql = sql + ' != ? '; } else { sql = sql + ' like ? '; } if (operator === OB.Dal.CONTAINS) { value = '%' + value + '%'; } else if (operator === OB.Dal.STARTSWITH) { value = value + '%'; } else if (operator === OB.Dal.ENDSWITH) { value = value + '%'; } params.push(value); } if (firstParam) { firstParam = false; } } }); } res.sql = sql; res.params = params; return res; }; OB.Dal.getTableName = function (model) { return model.getTableName ? model.getTableName() : model.prototype.tableName; }; OB.Dal.getPropertyMap = function (model) { return model.getProperties ? model.getProperties() : model.prototype.propertyMap; }; OB.Dal.findUsingCache = function (cacheName, model, whereClause, success, error, args) { if (OB.Cache.hasItem(cacheName, whereClause)) { OB.Dal.stackSize++; if (OB.Dal.stackSize % 50 === 0) { setTimeout(function () { success(OB.Cache.getItem(cacheName, whereClause)); }, 0); } else { success(OB.Cache.getItem(cacheName, whereClause)); } } else { OB.Dal.find(model, whereClause, function (models) { OB.Cache.putItem(cacheName, whereClause, models); success(models); }, error, args); } }; OB.Dal.find = function (model, whereClause, success, error, args) { var tableName = OB.Dal.getTableName(model), propertyMap = OB.Dal.getPropertyMap(model), sql = 'SELECT * FROM ' + tableName, params = null, appendWhere = true, firstParam = true, k, v, undef, colType, xhr, i, criteria, j, params_where, orderBy, limit; if (model.prototype.online) { colType = OB && OB.Collection && OB.Collection[model.prototype.modelName + 'List']; if (undef === colType) { throw 'There is no collection defined at: OB.Data.Collection.' + model.prototype.modelName + 'List'; } xhr = new enyo.Ajax({ url: model.prototype.source, method: 'POST' }); xhr.response(function (inSender, inResponse) { //FIXME: implement error handling success(new colType(inResponse.response.data)); }); params = enyo.clone(whereClause); if (whereClause && _.isNumber(whereClause._limit)) { limit = whereClause._limit; } else { limit = 100; OB.trace('OB.Dal.find used without specific limit. Automatically set to 100.', model, whereClause); } params._noCount = true; params._operationType = 'fetch'; params._startRow = (whereClause && whereClause._offset ? whereClause._offset : 0); params._endRow = params._startRow + limit; params._sortBy = (whereClause && whereClause._sortBy ? whereClause._sortBy : ''); params.isc_dataFormat = 'json'; params.isc_metaDataPrefix = '_'; if (whereClause && whereClause._constructor) { for (i in whereClause) { if (whereClause.hasOwnProperty(i)) { if (i === 'criteria') { params.criteria = []; criteria = whereClause[i]; for (j = 0; j < criteria.length; j++) { params.criteria.push(JSON.stringify(criteria[j])); } } else { params[i] = whereClause[i]; } } } } else { params_where = (whereClause && whereClause._where ? whereClause._where : ''); } xhr.go(params); } else if (OB.Data.localDB) { // websql if (whereClause && whereClause._orderByClause) { orderBy = whereClause._orderByClause; } if (whereClause && whereClause._limit) { limit = whereClause._limit; } else { limit = model.prototype.dataLimit; } if (whereClause && whereClause._whereClause) { whereClause.sql = ' ' + whereClause._whereClause; } else { whereClause = OB.Dal.getWhereClause(whereClause, propertyMap); } sql = sql + whereClause.sql; params = whereClause.params; if (orderBy) { sql = sql + ' ORDER BY ' + orderBy + ' '; } else if (model.propertyList || model.prototype.propertyMap._idx) { sql = sql + ' ORDER BY _idx '; } if (limit) { sql = sql + ' LIMIT ' + limit; } OB.Data.localDB.readTransaction(function (tx) { var synchId; if (model.prototype.modelName !== 'LogClient') { synchId = SynchronizationHelper.busyUntilFinishes('find ' + model.prototype.modelName); } tx.executeSql(sql, params, function (tr, result) { if (synchId) { SynchronizationHelper.finished(synchId, 'find'); } var i, collectionType = OB.Collection[model.prototype.modelName + 'List'] || Backbone.Collection, collection = new collectionType(), len = result.rows.length; if (len === 0) { success(collection, args); } else { for (i = 0; i < len; i++) { collection.add(OB.Dal.transform(model, result.rows.item(i))); } success(collection, args); } }, function () { if (synchId) { SynchronizationHelper.finished(synchId, 'find'); } if (error) { error(); } }); }); } else { this.missingLocalStorageLogic(); } }; OB.Dal.query = function (model, sql, params, success, error, args) { if (OB.Data.localDB) { if (model.prototype.dataLimit) { sql = sql + ' LIMIT ' + model.prototype.dataLimit; } OB.Data.localDB.readTransaction(function (tx) { tx.executeSql(sql, params, function (tr, result) { var i, collectionType = OB.Collection[model.prototype.modelName + 'List'] || Backbone.Collection, collection = new collectionType(), len = result.rows.length; if (len === 0) { success(collection, args); } else { for (i = 0; i < len; i++) { collection.add(OB.Dal.transform(model, result.rows.item(i))); } success(collection, args); } }, _.isFunction(error) ? error : null); }); } else { this.missingLocalStorageLogic(); } }; OB.Dal.save = function (model, success, error, forceInsert) { var modelProto = model.constructor.prototype, modelDefinition = OB.Model[modelProto.modelName], tableName = OB.Dal.getTableName(modelDefinition), primaryKey, primaryKeyProperty = 'id', primaryKeyColumn, sql = '', params = null, firstParam = true, uuid, propertyName, filterVal, xhr, data = {}; forceInsert = forceInsert || false; // TODO: properly check model type if (modelProto && modelProto.online) { if (!model) { throw 'You need to pass a Model instance to save'; } xhr = new enyo.Ajax({ url: modelProto.source, method: 'PUT' }); xhr.response(function (inSender, inResponse) { success(inResponse); }); data.operationType = 'update'; data.data = model.toJSON(); xhr.go(JSON.stringify(data)); } else if (OB.Data.localDB) { // websql if (!tableName) { throw 'Missing table name in model'; } if (modelDefinition.getPrimaryKey) { primaryKey = modelDefinition.getPrimaryKey(); primaryKeyProperty = primaryKey.name; primaryKeyColumn = primaryKey.column; } else { primaryKeyColumn = modelProto.propertyMap[primaryKeyProperty]; } if (model.get(primaryKeyProperty) && forceInsert === false) { if (modelDefinition.getUpdateStatement) { sql = modelDefinition.getUpdateStatement(); params = []; _.each(modelDefinition.getPropertiesForUpdate(), function (property) { //filter doen't have name and always is the last one if (property.name) { params.push(model.get(property.name)); } }); //filter param if (modelDefinition.hasFilter()) { filterVal = ''; _.each(modelDefinition.getFilterProperties(), function (filterProperty) { filterVal = filterVal + (model.get(filterProperty) ? (model.get(filterProperty) + '###') : ''); }); params.push(filterVal); } //Where param params.push(model.get(primaryKeyProperty)); } else { // UPDATE sql = 'UPDATE ' + tableName + ' SET '; _.each(_.keys(modelProto.properties), function (attr) { propertyName = modelProto.properties[attr]; if (attr === 'id') { return; } if (firstParam) { firstParam = false; params = []; } else { sql = sql + ', '; } sql = sql + modelProto.propertyMap[propertyName] + ' = ? '; params.push(model.get(propertyName)); }); if (modelProto.propertiesFilter) { filterVal = ''; _.each(modelProto.propertiesFilter, function (prop) { filterVal = filterVal + model.get(prop) + '###'; }); sql = sql + ', _filter = ? '; params.push(filterVal); } sql = sql + ' WHERE ' + tableName + '_id = ?'; params.push(model.get('id')); } } else { params = []; // INSERT sql = modelDefinition.getInsertStatement ? modelDefinition.getInsertStatement() : modelProto.insertStatement; if (forceInsert === false) { uuid = OB.Dal.get_uuid(); params.push(uuid); if (model.getPrimaryKey) { primaryKey = model.getPrimaryKey(); model.set(primaryKey.name, uuid); } else { model.set('id', uuid); } } //Set params if (modelDefinition.getProperties) { _.each(modelDefinition.getProperties(), function (property) { if (forceInsert === false) { if (property.primaryKey) { return; } } //_filter property doesn't have name. //don't set the filter column. We will do it in the next step if (property.name) { params.push(model.get(property.name) === undefined ? null : model.get(property.name)); } }); } else { _.each(modelProto.properties, function (property) { if (forceInsert === false) { if ('id' === property) { return; } } params.push(model.get(property) === undefined ? null : model.get(property)); }); } //set filter column if (modelDefinition.hasFilter) { if (modelDefinition.hasFilter()) { filterVal = ''; _.each(modelDefinition.getFilterProperties(), function (filterProp) { filterVal = filterVal + (model.get(filterProp) ? (model.get(filterProp) + '###') : ''); }); //Include in the last position but before _idx params.splice(params.length - 1, 0, filterVal); } } else { if (modelProto.propertiesFilter) { filterVal = ''; _.each(modelProto.propertiesFilter, function (prop) { filterVal = filterVal + model.get(prop) + '###'; }); //Include in the last position but before _idx params.splice(params.length - 1, 0, filterVal); } } //OB.info(params.length); } //OB.info(sql); //OB.info(params); OB.Data.localDB.transaction(function (tx) { tx.executeSql(sql, params, function () { if (success) { success(arguments); } }, _.isFunction(error) ? error : null); }); } else { this.missingLocalStorageLogic(); } }; OB.Dal.remove = function (model, success, error) { var modelDefinition = OB.Model[model.constructor.prototype.modelName], modelProto = model.constructor.prototype, tableName = OB.Dal.getTableName(modelDefinition), pk, pkProperty = 'id', pkColumn, sql = '', params = []; if (OB.Data.localDB) { // websql if (!tableName) { throw 'Missing table name in model'; } if (modelDefinition.getPrimaryKey) { pk = modelDefinition.getPrimaryKey() ? modelDefinition.getPrimaryKey() : null; if (pk) { pkProperty = pk.name; pkColumn = pk.column; } else { pkColumn = modelDefinition.propertyMap[pkProperty]; } } if (model.get(pkProperty)) { if (modelDefinition.getDeleteByIdStatement) { sql = modelDefinition.getDeleteByIdStatement(); } else { sql = 'DELETE FROM ' + tableName + ' WHERE ' + modelProto.propertyMap[pkProperty] + ' = ? '; } // UPDATE params.push(model.get(pkProperty)); } else { throw 'An object without primary key cannot be deleted'; } //OB.info(sql); //OB.info(params); OB.Data.localDB.transaction(function (tx) { tx.executeSql(sql, params, _.isFunction(success) ? success : null, _.isFunction(error) ? error : null); }); } else { this.missingLocalStorageLogic(); } }; OB.Dal.removeAll = function (model, criteria, success, error) { var tableName = OB.Dal.getTableName(model), propertyMap = OB.Dal.getPropertyMap(model), sql, params, whereClause; if (OB.Data.localDB) { // websql if (!tableName) { throw 'Missing table name in model'; } sql = 'DELETE FROM ' + tableName; whereClause = OB.Dal.getWhereClause(criteria, propertyMap); sql = sql + whereClause.sql; params = whereClause.params; OB.Data.localDB.transaction(function (tx) { tx.executeSql(sql, params, _.isFunction(success) ? success : null, _.isFunction(error) ? error : null); }); } else { this.missingLocalStorageLogic(); } }; OB.Dal.get = function (model, id, success, error, empty) { var tableName = OB.Dal.getTableName(model), sql = 'SELECT * FROM ' + tableName + ' WHERE ' + tableName + '_id = ?'; if (OB.Data.localDB) { // websql OB.Data.localDB.readTransaction(function (tx) { tx.executeSql(sql, [id], function (tr, result) { if (result.rows.length === 0) { if (empty) { empty(); } else { return null; } } else { success(OB.Dal.transform(model, result.rows.item(0))); } }, _.isFunction(error) ? error : null); }); } else { this.missingLocalStorageLogic(); } }; OB.Dal.initCache = function (model, initialData, success, error, incremental) { if (OB.Data.localDB) { // error must be defined, if not it fails in some android versions error = error || function () {}; if (!model.propertyList && (!model.prototype.createStatement || !model.prototype.dropStatement)) { throw 'Model requires a create and drop statement'; } if (!initialData) { throw 'initialData must be passed as parameter'; } if (!model.prototype.local && !incremental) { OB.Data.localDB.transaction(function (tx) { var st = model.getDropStatement ? model.getDropStatement() : model.prototype.dropStatement; tx.executeSql(st); }, error); } OB.Data.localDB.transaction(function (tx) { var createStatement = model.getCreateStatement ? model.getCreateStatement() : model.prototype.createStatement; var createIndexStatement; tx.executeSql(createStatement, null, function () { //Create Index if (model.hasIndex && model.hasIndex()) { _.each(model.getIndexes(), function (indexDefinition) { createIndexStatement = model.getCreateIndexStatement(indexDefinition); tx.executeSql(createIndexStatement, null, null, function () { OB.error('Error creating index ' + indexDefinition.name + ' for table ' + OB.Dal.getTableName(model)); }); }); } }, null); }, error); if (_.isArray(initialData)) { OB.Data.localDB.transaction(function (tx) { var props = model.getProperties ? model.getProperties() : model.prototype.properties, filterVal, values, _idx = 0, updateRecord = function (tx, model, values) { var deleteStatement; deleteStatement = model.getDeleteByIdStatement ? model.getDeleteByIdStatement() : "DELETE FROM " + model.prototype.tableName + " WHERE " + model.prototype.propertyMap.id + "=?"; tx.executeSql(deleteStatement, [values[0]], function () { var insertSatement; insertSatement = model.getInsertStatement ? model.getInsertStatement() : model.prototype.insertStatement; tx.executeSql(insertSatement, values, null, _.isFunction(error) ? error : null); }, _.isFunction(error) ? error : null); }; _.each(initialData, function (item) { var filterProps, insertStatement; values = []; _.each(props, function (prop) { var propName = typeof prop === 'string' ? prop : prop.name; if (!propName || '_idx' === propName) { return; } values.push(item[propName]); }); if ((model.hasFilter && model.hasFilter()) || model.prototype.propertiesFilter) { filterVal = ''; filterProps = model.getFilterProperties ? model.getFilterProperties() : model.prototype.propertiesFilter; _.each(filterProps, function (prop) { filterVal = filterVal + item[prop] + '###'; }); values.push(filterVal); } values.push(_idx); if (incremental) { updateRecord(tx, model, values); } else { insertStatement = model.getInsertStatement ? model.getInsertStatement() : model.prototype.insertStatement; tx.executeSql(insertStatement, values, null, _.isFunction(error) ? error : null); } _idx++; }); }, error, function () { // transaction success, execute callback if (_.isFunction(success)) { success(); } }); } else { // no initial data throw 'initialData must be an Array'; } } else { this.missingLocalStorageLogic(); } }; /** * Loads a set of models * * */ OB.Dal.loadModels = function (online, models, data, incremental) { function triggerReady(models) { if (models._LoadOnline && OB.UTIL.queueStatus(models._LoadQueue || {})) { // this is only triggered when all models (online and offline) are loaded. // offline models are loaded first but don't trigger this, it is not till // windowModel is going to be rendered when online models are loaded and this // is triggered. if (!OB.MobileApp.model.get('datasourceLoadFailed')) { models.trigger('ready'); } } } var somethigToLoad = false, timestamp = 0; models._LoadOnline = online; if (models.length === 0) { triggerReady(models); return; } _.each(models, function (item) { var ds, load; if (item && item.generatedModel) { item = OB.Model[item.modelName]; } load = item && ((online && item.prototype.online) || (!online && !item.prototype.online)); //TODO: check permissions if (load) { if (item.prototype.local) { OB.Dal.initCache(item, [], function () { // OB.info('init success: ' + item.prototype.modelName); }, function () { OB.error('init error', arguments); }); } else { // OB.info('[sdrefresh] load model ' + item.prototype.modelName + ' ' + (incremental ? 'incrementally' : 'full')); if (incremental && window.localStorage.getItem('lastUpdatedTimestamp' + item.prototype.modelName)) { timestamp = window.localStorage.getItem('lastUpdatedTimestamp' + item.prototype.modelName); } ds = new OB.DS.DataSource(new OB.DS.Request(item, timestamp)); somethigToLoad = true; models._LoadQueue = models._LoadQueue || {}; models._LoadQueue[item.prototype.modelName] = false; ds.on('ready', function () { OB.info('Loading data for ' + item.prototype.modelName); if (data) { data[item.prototype.modelName] = new Backbone.Collection(ds.cache); } models._LoadQueue[item.prototype.modelName] = true; if (incremental) { window.localStorage.setItem('POSLastIncRefresh', new Date().getTime()); } else { window.localStorage.setItem('POSLastTotalRefresh', new Date().getTime()); } triggerReady(models); }); if (item.prototype.includeTerminalDate) { var currentDate = new Date(); item.params = item.params || {}; item.params.terminalTime = currentDate; item.params.terminalTimeOffset = currentDate.getTimezoneOffset(); } ds.load(item.params, incremental); } } }); if (!somethigToLoad) { triggerReady(models); } }; }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, SynchronizationHelper, console, Promise, window, OB */ OB.Data = OB.Data || {}; OB.Model = OB.Model || {}; OB.Collection = OB.Collection || {}; OB.Data.Registry = OB.Data.Registry || {}; OB.Data.BaseModel = Backbone.Model.extend(); (function () { var modelsDelayedUntilLoggedIn = []; function getGeneratedStructureModel(modelParam) { return new Promise(function (resolve, reject) { var modelName = modelParam.prototype.modelName; // argument check if (OB.UTIL.Debug.isDebug()) { if (!modelParam.prototype.generatedStructure) { console.error("The model '" + modelName + "' has not the generatedStructure flag set"); return; } } var url = '../../org.openbravo.client.kernel/OBMOBC_Main/ClientModel'; url += '?entity=' + modelParam.prototype.entityName; url += '&modelName=' + modelName; url += '&source=' + modelParam.prototype.source; var synchId = SynchronizationHelper.busyUntilFinishes('registerModel'); new enyo.Ajax({ url: url, method: 'GET', handleAs: 'text', cacheBust: false }).response(function (inSender, inResponse) { SynchronizationHelper.finished(synchId, 'registerModel'); eval(inResponse); modelParam.prototype.structureLoaded = true; OB.info(modelName, 'is/are loaded'); resolve(modelName); }).error(function (inSender, inResponse) { SynchronizationHelper.finished(synchId, 'registerModel'); reject(modelName); }).go(); }); } OB.Data.Registry.loadModelsDelayedUntilLoggedIn = function () { var promises = []; if (modelsDelayedUntilLoggedIn !== null) { modelsDelayedUntilLoggedIn.forEach(function (modelParam) { promises.push(getGeneratedStructureModel(modelParam)); }); } var promiseAfterErrorCheck = new Promise(function (resolve, reject) { Promise.all(promises).then(function () { // The generated structure models have been properly loaded. Don't try to load them again modelsDelayedUntilLoggedIn = null; resolve(); }, function (values) { OB.error("The model(s) " + values + " can't be created because neither the server is available nor the cache has no data"); reject(); }); }); return promiseAfterErrorCheck; }; OB.Data.Registry.registerModel = function (modelParam) { var modelName, model; if (typeof modelParam === 'string') { // modelParam is the name of the entity modelName = modelParam; model = OB.Data.BaseModel.extend({ modelName: modelName, source: '../../org.openbravo.service.datasource/' + modelName, online: true }); } else if (modelParam.prototype.generatedStructure) { modelsDelayedUntilLoggedIn.push(modelParam); // Comment the previous line and uncomment the below to deactivate the delayed functionality // getGeneratedStructureModel(modelParam).then(function(){ // console.log("model loaded"); // }); return; } else { // modelParam is a Backbone class modelName = modelParam.prototype.modelName; model = modelParam; } if (!modelName) { window.error('Error registering model: no modelName provided', modelParam); } OB.Model[modelName] = model; OB.Collection[modelName + 'List'] = Backbone.Collection.extend({ model: OB.Model[modelName] }); }; }()); OB.Data.ExtensibleModel = Backbone.Model.extend({}, { // class properties propertyList: [], indexList: [], addProperties: function (properties) { // TODO: add validations this.propertyList = this.propertyList.concat(properties); }, addIndex: function (index) { this.indexList = this.indexList.concat(index); }, getProperties: function (options) { var props = _.clone(this.propertyList); if (this.hasFilter()) { props.push({ column: '_filter', type: 'TEXT' }); } if (options && options.skipIdx) { return props; } props.push({ name: '_idx', column: '_idx', type: 'NUMERIC' }); return props; }, getPropertiesForUpdate: function (options) { //all the properties except primary key and _idx var props = []; _.each(this.propertyList, function (property) { if (!property.primaryKey) { props.push(property); } }); if (this.hasFilter()) { props.push({ column: '_filter', type: 'TEXT' }); } return props; }, getTableName: function () { return this.prototype.tableName; }, isOnlineModel: function () { return this.prototype.online; }, isTerminalDateIncluded: function () { return this.prototype.includeTerminalDate; }, getDropStatement: function () { return 'DROP TABLE IF EXISTS ' + this.getTableName(); }, getCreateStatement: function () { return 'CREATE TABLE IF NOT EXISTS ' + this.getTableName() + '\n' + this.getSQLColumns(true); }, getCreateIndexStatement: function (indexToCreate) { if (indexToCreate && indexToCreate.columns) { var indexedColumn = []; _.each(indexToCreate.columns, function (col) { var sort = 'asc'; if (col.sort) { sort = col.sort; } indexedColumn.push(col.name + ' ' + sort); }); return 'CREATE INDEX IF NOT EXISTS ' + indexToCreate.name + ' ON ' + this.getTableName() + ' (' + indexedColumn.join(',') + ')'; } else { OB.warn('A correct object is needed to create indexes'); return ''; } }, getInsertStatement: function () { var i, statement = 'INSERT INTO ' + this.getTableName() + '\n' + this.getSQLColumns() + '\nVALUES\n('; for (i = 0; i < this.getProperties().length; i++) { statement += (i === 0 ? '' : ', ') + '?'; } return statement + ')'; }, getUpdateStatement: function () { var i, j = 0, statement = 'UPDATE ' + this.getTableName() + '\nSET\n '; for (i = 0; i < this.getPropertiesForUpdate().length; i++) { if (!this.getPropertiesForUpdate()[i].primaryKey) { statement += (j === 0 ? '' : ', '); statement += this.getPropertiesForUpdate()[i].column + ' = ?'; j += 1; } } statement += '\n WHERE ' + this.getPrimaryKey().column + ' = ?'; return statement; }, getDeleteByIdStatement: function () { var id; if (this.deleteByIdStatement) { // keep it cached not to compute it every time return this.deleteByIdStatement; } id = this.getPrimaryKey(); // _.find(this.getProperties(), function (p) { // return p.primaryKey // }); this.deleteByIdStatement = "DELETE FROM " + this.getTableName() + " WHERE " + id.column + " = ?"; return this.deleteByIdStatement; }, getPrimaryKey: function () { var pk = null; pk = _.find(this.getProperties(), function (p) { return p.primaryKey; }); return pk; }, getFilterProperties: function () { var filterProps = []; _.each(_.filter(this.propertyList, function (p) { return p.filter; }), function (p) { filterProps.push(p.name); }); return filterProps; }, getIndexes: function () { var indexedProps = []; if (this.indexList && this.indexList.length > 0) { _.each(this.indexList, function (p) { indexedProps.push(p); }); return indexedProps; } else { return []; } }, hasFilter: function () { return this.getFilterProperties().length > 0; }, hasIndex: function () { return this.getIndexes().length > 0; }, getSQLColumns: function (includeType) { var columns = ''; _.each(this.getProperties(), function (p) { if (columns !== '') { columns += ',\n'; } columns += p.column; if (includeType) { columns += ' ' + p.type + (p.primaryKey ? ' PRIMARY KEY' : ''); } }); return '(' + columns + ')'; } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ OB.Model.WindowModel = Backbone.Model.extend({ data: {}, load: function () { var me = this, queue = {}, initIfInit = function () { if (me.init) { me.init(); } }; if (!this.models) { this.models = []; } _.extend(this.models, Backbone.Events); this.models.on('ready', function () { if (!OB.MobileApp.model.get('loggedUsingCache')) { initIfInit(); OB.MobileApp.model.set('isLoggingIn', false); this.trigger('ready'); } }, this); if (!OB.MobileApp.model.get('loggedOffline')) { OB.Dal.loadModels(true, me.models, me.data); if (OB.MobileApp.model.get('loggedUsingCache')) { initIfInit(); this.trigger('ready'); } } else { initIfInit(); this.trigger('ready'); } }, setAllOff: function (model) { var p; if (model.off) { model.off(); } if (model.attributes) { for (p in model.attributes) { if (model.attributes.hasOwnProperty(p) && model.attributes[p]) { this.setAllOff(model); } } } }, setOff: function () { if (!this.data) { return; } if (this.data) { _.forEach(this.data, function (model) { this.setAllOff(model); }, this); } this.data = null; if (this.models) { _.forEach(this.models, function (model) { if (model.off) { model.off(); } }, this); if (this.models.off) { this.models.off(); } } this.models = null; }, getData: function (dsName) { return this.data[dsName]; } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, _, OB, window, document, navigator, setTimeout, clearTimeout */ // Container for the whole application enyo.kind({ name: 'OB.UI.Terminal', events: { onDestroyMenu: '' }, published: { scanning: false }, classes: 'pos-container', style: 'height:700px', components: [{ style: 'height: 10px;' }, { components: [{ name: 'containerLoading', components: [{ classes: 'POSLoadingCenteredBox', components: [{ classes: 'POSLoadingPromptLabel', content: 'Loading...' //OB.I18N.getLabel('OBPOS_LblLoading') }, { classes: 'POSLoadingProgressBar', components: [{ classes: 'POSLoadingProgressBarImg' }] }] }] }, { name: 'containerLoggingOut', showing: false, components: [{ classes: 'POSLoadingCenteredBox', components: [{ classes: 'POSLoadingPromptLabel', content: 'Logging out...' //OB.I18N.getLabel('OBPOS_LblLoggingOut') }, { classes: 'POSLoadingProgressBar', components: [{ classes: 'POSLoadingProgressBarImg' }] }] }] }, { name: 'containerWindow', handlers: { onShowPopup: 'showPopupHandler', onHidePopup: 'hidePopupHandler' }, getRoot: function () { return this.getComponents()[0]; }, showPopupHandler: function (inSender, inEvent) { if (inEvent.popup) { this.showPopup(inEvent.popup, inEvent.args); } }, showPopup: function (popupName, args) { var componentsArray, i; if (OB.MobileApp.view.$[popupName]) { OB.MobileApp.view.$[popupName].show(args); return true; } componentsArray = this.getComponents(); for (i = 0; i < componentsArray.length; i++) { if (componentsArray[i].$[popupName]) { componentsArray[i].$[popupName].show(args); break; } } return true; }, hidePopupHandler: function (inSender, inEvent) { if (inEvent.popup) { this.hidePopup(inEvent.popup, inEvent.args); } }, hidePopup: function (popupName, args) { var componentsArray, i; if (OB.MobileApp.view.$[popupName]) { OB.MobileApp.view.$[popupName].hide(args); return true; } componentsArray = this.getComponents(); for (i = 0; i < componentsArray.length; i++) { if (componentsArray[i].$[popupName]) { componentsArray[i].$[popupName].hide(args); break; } } return true; } }] }, { name: 'dialogsContainer' }, { name: 'alertContainer', components: [{ kind: 'OB.UTIL.showAlert', name: 'alertQueue' }] }, { name: 'confirmationContainer', getCurrentPopup: function () { var comp = this.getComponents(); if (_.isArray(comp) && comp.length > 0) { if (comp.length > 1) { OB.warn('More than 1 component in confirmation container. Returning the first one'); } return comp[0]; } else { return null; } } }, { kind: 'OB.UI.Profile.SessionInfo', name: 'profileSessionInfo' }, { kind: 'OB.UI.Profile.UserInfo', name: 'profileUserInfo' }, { // To globaly handle keypup events when not using focusKeeper kind: enyo.Signals, onkeyup: "keypressHandler" }], /** * When using focus keeper for barcode scanners, keep always the focus there */ keeperBlur: function (inSender, inEvent) { OB.debug('keeperBlur'); OB.MobileApp.view.scanningFocus(this.scanMode); }, /** * Key up on focus keeper. We are using key up event because keydown doesn't work * properly on Android Chrome 26 */ keeperKey: function (k) { OB.debug('keeperKey - keyCode: ' + k.keyCode + " - keyIdentifier: " + k.keyIdentifier + " - charCode: " + k.charCode + " - which: " + k.which); OB.MobileApp.view.waterfall('onGlobalKeypress', { keyboardEvent: k }); }, enterEvent: function (k) { OB.debug('ENTER event for iOS'); OB.MobileApp.view.waterfall('onGlobalKeypress', { keyboardEvent: k, enterEvent: true }); }, /** * Checks whether focus should be places on focusKeeper and puts it there if needed */ scanningFocus: function (scanMode, forced) { var keeper; if (!OB.MobileApp.model.get('useBarcode')) { return; } OB.debug('scanningfocus'); if (scanMode !== undefined) { this.scanMode = scanMode; } // This shouldn't be done in iOS, if done the focuskeeper loses the focus if (this.scanMode && navigator.userAgent.match(/iPhone|iPad|iPod/i)) { OB.debug('scanningfocus. iOS. Focused'); keeper = document.getElementById('_focusKeeper'); keeper.disabled = false; keeper.focus(); } if (!this.scanMode && forced) { return; } // using timeout due problems in android stock browser because of 2 reasons: // 1. need to set the focus back to keeper even if not in scanMode, if not, // when in a non scanMode tab using scanner writes in the URL tab. So // it is not keep in keeper only in case the destination element is a input // to know the destination timeout is needed // 2. if timeout is not used, on-screen keyboard is shown when settin focus in // keeper setTimeout(function () { if (this.scanMode || (document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'SELECT')) { keeper = document.getElementById('_focusKeeper'); keeper.focus(); } }, 500); }, /** * Global key up event. Used when not using focusKeeper */ keypressHandler: function (inSender, inEvent) { OB.debug('keypressHandler - keyCode: ' + inEvent.keyCode + " - keyIdentifier: " + inEvent.keyIdentifier + " - charCode: " + inEvent.charCode + " - which: " + inEvent.which); if (OB.MobileApp.model.get('useBarcode') && this.scanMode) { return; } //Issue 25013. This flag is set by globalKeypressHandler function in ob-keyboard.js if (OB.MobileApp.model.get('useBarcode') && OB.MobileApp.keyPressProcessed) { delete OB.MobileApp.keyPressProcessed; return; } this.waterfall('onGlobalKeypress', { keyboardEvent: inEvent }); }, resizeWindow: function () { var winHeight = window.innerHeight, winWidth = window.innerWidth, percentage, appHeight = 700; // resize in case of window rotation but not if virtual keyboard appears // hack: virtual keyboard is detected because only y is resized but not x if (!this.sizeProperties || (this.sizeProperties.x !== winWidth && this.sizeProperties.y !== winHeight)) { //When the window is resized we need to close the menu //to avoid a strange problem when rotating mobile devices //See issue https://issues.openbravo.com/view.php?id=23669 this.waterfall('onDestroyMenu'); this.sizeProperties = { x: window.innerWidth, y: window.innerHeight }; percentage = window.innerHeight * 100 / appHeight; percentage = Math.floor(percentage) / 100; document.body.style.zoom = percentage; // after zooming, force render again // if this is not done, iPad's Safari messes the layout when going from 1 to 2 columns this.render(); } }, rendered: function () { var keeper; this.inherited(arguments); // Creating focus keeper. This needs to be done in this way instead of using enyo components // because currently, it is not possible to place focus (in iOS) keeper = document.getElementById('_focusKeeper'); if (!keeper) { keeper = document.createElement('input'); keeper.setAttribute('id', '_focusKeeper'); keeper.setAttribute('style', 'position: fixed; top: -100px; left: -100px;'); keeper.setAttribute('onblur', 'OB.MobileApp.view.keeperBlur()'); // Avoid the use of Alt + Left Arrow, Alt + Right Arrow, Shift + Backspace: Navigate Back/Next in the browser document.body.onkeydown = function (k) { if ((k.keyCode === 37 && k.altKey) || (k.keyCode === 39 && k.altKey) || (k.keyCode === 8 && k.shiftKey)) { return false; } }; // Fixed 25288: key up is not working fine in IOS7. Because of that we are // listening to keypress and then sending it to the standard flow. if (OB.UTIL.isIOS()) { keeper.addEventListener('keypress', function (k) { OB.debug('init timeout'); if (OB.testtimeoutid) { OB.debug('timeout cleared'); clearTimeout(OB.testtimeoutid); } //OB.MobileApp.view.keeperKey(k); OB.testtimeoutid = setTimeout(function () { OB.debug('timeout happened'); OB.MobileApp.view.enterEvent(k); }, 400); }); } keeper.addEventListener('keyup', function (k) { OB.debug('keyup happened: which:' + k.which); if (OB.UTIL.isIOS() && (k.keyCode === 13 || k.which === 13)) { return; } OB.MobileApp.view.keeperKey(k); }); document.body.appendChild(keeper); } this.scanningFocus(); }, initComponents: function () { window.OB = OB || {}; window.OB.MobileApp = OB.MobileApp || {}; window.OB.MobileApp.view = this; var args = arguments, initialized = false; //this.inherited(args); this.terminal.on('initializedCommonComponents', function () { var me = this; if (!initialized) { this.inherited(args); initialized = true; this.terminal.on('change:context', function () { var ctx = this.terminal.get('context'); if (!ctx) { return; } if (this.$.dialogsContainer.$.profileDialog) { this.$.dialogsContainer.$.profileDialog.destroy(); } if (OB.UI.ModalProfile) { this.$.dialogsContainer.createComponent({ kind: 'OB.UI.ModalProfile', name: 'profileDialog' }); } }, this); this.terminal.on('change:connectedToERP', function (model) { if (model.get('loggedOffline') !== undefined) { if (model.get('connectedToERP')) { //We will do an additional request to verify whether the connection is still active or not new OB.DS.Request('org.openbravo.mobile.core.login.Context').exec({ ignoreForConnectionStatus: true }, function (inResponse) { if (inResponse && !inResponse.exception) { OB.MobileApp.model.returnToOnline(); } else { if (model.get('supportsOffline')) { OB.UTIL.showConfirmation.display( OB.I18N.getLabel('OBMOBC_Online'), OB.I18N.getLabel('OBMOBC_OnlineConnectionHasReturned'), [{ label: OB.I18N.getLabel('OBMOBC_LblLoginAgain'), action: function () { OB.MobileApp.model.lock(); OB.UTIL.showLoading(true); } }], { autoDismiss: false, onHideFunction: function () { OB.MobileApp.model.lock(); OB.UTIL.showLoading(true); } }); } else { OB.MobileApp.model.triggerLogout(); } } }); } else { if (model.get('supportsOffline')) { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_OfflineModeWarning')); } } } }, this); // TODO: POS specific, move it to somewhere else this.terminal.on('change:terminal change:bplocation change:location change:pricelist change:pricelistversion', function () { var name = ''; var clientname = ''; var orgname = ''; var pricelistname = ''; var currencyname = ''; var locationname = ''; if (this.terminal.get('terminal')) { name = this.terminal.get('terminal')._identifier; clientname = this.terminal.get('terminal')['client' + OB.Constants.FIELDSEPARATOR + '_identifier']; orgname = this.terminal.get('terminal')['organization' + OB.Constants.FIELDSEPARATOR + '_identifier']; } if (this.terminal.get('pricelist')) { pricelistname = this.terminal.get('pricelist')._identifier; currencyname = this.terminal.get('pricelist')['currency' + OB.Constants.FIELDSEPARATOR + '_identifier']; } if (this.terminal.get('location')) { locationname = this.terminal.get('location')._identifier; } }, this); } this.$.dialogsContainer.destroyComponents(); if (OB.UI.ModalLogout) { this.$.dialogsContainer.createComponent({ kind: 'OB.UI.ModalLogout', name: 'logoutDialog' }); } this.render(); this.resizeWindow(); window.onresize = function () { me.resizeWindow(); }; // forced trigger to show online status //this.terminal.trigger('change:connectedToERP', this.terminal); }, this); OB.MobileApp.model.navigate(''); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global $LAB, _, $, enyo, Backbone, CryptoJS, console, SynchronizationHelper, window, setInterval, clearInterval, alert, OB */ OB.Model = window.OB.Model || {}; OB.MobileApp = OB.MobileApp || {}; OB.MobileApp.windowRegistry = new(Backbone.Model.extend({ registeredWindows: [], registerWindow: function (window) { this.registeredWindows.push(window); } }))(); OB.Model.Collection = Backbone.Collection.extend({ constructor: function (data) { this.ds = data.ds; Backbone.Collection.prototype.constructor.call(this); }, inithandler: function (init) { if (init) { init.call(this); } }, exec: function (filter) { var me = this; if (this.ds) { this.ds.exec(filter, function (data, info) { var i; me.reset(); me.trigger('info', info); if (data.exception) { OB.UTIL.showError(data.exception.message); } else { for (i in data) { if (data.hasOwnProperty(i)) { me.add(data[i]); } } } }); } } }); // Terminal model. OB.Model.Terminal = Backbone.Model.extend({ defaults: { terminal: null, context: null, permissions: null, businesspartner: null, location: null, pricelist: null, pricelistversion: null, currency: null, connectedToERP: null, loginUtilsUrl: '../../org.openbravo.mobile.core.loginutils', loginUtilsParams: {}, supportsOffline: false, loginHandlerUrl: '../../org.openbravo.mobile.core/LoginHandler', applicationFormatUrl: '../../org.openbravo.client.kernel/OBCLKER_Kernel/Application', logConfiguration: { deviceIdentifier: '', logPropertiesExtension: [] }, windows: null, appName: 'OBMOBC', appDisplayName: 'Openbravo Mobile', useBarcode: false, profileOptions: { showOrganization: true, showWarehouse: true, defaultProperties: { role: null, organization: null, warehouse: null, languagage: null } }, localDB: { size: OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.size, name: OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.name, displayName: OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.displayName, version: OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.major + '.' + OB.UTIL.VersionManagement.current.mobileCore.WebSQLDatabase.minor }, propertiesLoaders: [], dataSyncModels: [] }, initialize: function () { // navigation logic var OBRouter = Backbone.Router.extend({ terminal: null, initialize: function (associatedTerminal) { if (!associatedTerminal) { OB.error("The router needs to be associated to a terminal"); return; } this.terminal = associatedTerminal; }, routes: { // list of possible navigation routes // also new routes are added on the fly when registeredWindows are loaded (check: loginRegisteredWindows) '': 'root', 'login': 'login', '*route': 'any' }, any: function (route) { // the developer should check routes if this error shows up OB.error(route + ' route is missing. you should use the registerWindow method to register the window'); }, root: function () { this.terminal.initializeCommonComponents(); }, login: function () { this.terminal.renderLogin(); }, renderGenericWindow: function (windowName, params) { // the registered windows are rendered within this function this.terminal.renderGenericWindow(windowName, params); } }); // expose terminal globally window.OB = OB || {}; window.OB.MobileApp = OB.MobileApp || {}; window.OB.MobileApp.model = this; OB.UTIL.VersionManagement.deprecated(27349, function () { this.hookManager = OB.UTIL.HookManager; }, function (deprecationMessage) { this.hookManager = { registerHook: function (qualifier, func) { OB.warn(deprecationMessage); OB.UTIL.HookManager.registerHook(qualifier, func); }, executeHooks: function (qualifier, args, callback) { OB.warn(deprecationMessage); OB.UTIL.HookManager.executeHooks(qualifier, args, callback); } }; }, this); this.windowRegistry = OB.MobileApp.windowRegistry; // DEVELOPER: activate this to see all the events that are being fired by the backbone components of the terminal // this.on('all', function(eventName, object, third) { // if (eventName.indexOf('change') >= 0) { // return; // } // var enyoName = object ? object.name : ''; // OB.info('event fired: ' + eventName + ', ' + enyoName + ', ' + third); // }); // model events this.on('window:ready', this.renderContainerWindow); // When the active window is loaded, the window is rendered with the renderContainerWindow function this.on('terminalInfoLoaded', this.processPropertyLoaders); this.on('propertiesLoadersReady', function () { this.loadRegisteredWindows(); this.renderMain(); this.postLoginActions(); }, this); this.router = new OBRouter(this); // if the user refresh the page (f5, etc), be sure that the terminal navigates to the starting page if (window.location.toString().indexOf('#') > 0) { OB.info('Redirecting to the starting page'); window.location = ''; return; } // explicitly setting pushState to false tries to ensure... // that future default modes will not activate the pushState... // breaking the POS navigation Backbone.history.start({ root: '', pushState: false }); }, /** * Cleans the local storage and reloads */ cleanLocalStorageAndReload: function () { console.error("The local storage has been cleaned and the web page reloaded."); window.localStorage.clear(); window.localStorage.setItem('terminalName', OB.MobileApp.model.get('terminalName')); // delete the active user record from the ad_user table. this is done not to have further errors var sql = "DELETE FROM ad_user WHERE name = '" + this.user + "'"; if (OB.Data.localDB) { OB.Data.localDB.transaction(function (tx) { tx.executeSql(sql, null, function () { OB.MobileApp.model.navigate('login'); }); }); return; } window.location = ''; }, cleanTerminalData: function () { _.each(this.get('propertiesLoaders'), function (curPropertiesToLoadProcess) { _.each(curPropertiesToLoadProcess.properties, function (curProperty) { this.set(curProperty, null); }, this); }, this); }, returnToOnline: function () { //DEVELOPERS: overwrite this function to perform actions when it happens OB.info('The system has come back to online'); }, //DEVELOPER: This function allow us to execute some code to add properties to to terminal model. Each position of the array // must identify the properties which are set and needs to define a loadFunction which will be executed to get the data. // when the data is ready terminalModel.propertiesReady(properties) should be executed. addPropertiesLoader: function (obj) { this.get('propertiesLoaders').push(obj); this.syncAllPropertiesLoaded = _.after(this.get('propertiesLoaders').length, this.allPropertiesLoaded); }, propertiesReady: function (properties) { OB.info(properties, 'is/are loaded'); this.syncAllPropertiesLoaded(); }, processPropertyLoaders: function () { var termInfo; if (this.get('loggedOffline') || this.get('loggedUsingCache')) { termInfo = JSON.parse(this.usermodel.get('terminalinfo')); if (termInfo) { //Load from termInfo //TODO load all the recovered properties not only the array ones _.each(this.get('propertiesLoaders'), function (curPropertiesToLoadProcess) { _.each(curPropertiesToLoadProcess.properties, function (curProperty) { this.set(curProperty, termInfo[curProperty]); }, this); }, this); this.set('useBarcode', termInfo.useBarcode); //Not included into array this.set('permissions', termInfo.permissions); this.set('orgUserId', termInfo.orgUserId); this.allPropertiesLoaded(); } else { // the cache is corrupted OB.MobileApp.model.cleanLocalStorageAndReload(); } return; } //Set array properties as null except terminal this.cleanTerminalData(); this.set('loggedOffline', false); //Loading the properties of the array OB.info('Starting to load properties based on properties loaders', this.get('propertiesLoaders')); if (this.get('propertiesLoaders') && this.get('propertiesLoaders').length > 0) { _.each(this.get('propertiesLoaders'), function (curProperty) { //each loadFunction will call to propertiesReady function. This function will trigger //allPropertiesLoaded when all of the loadFunctions are done. curProperty.loadFunction(this); }, this); } else { this.allPropertiesLoaded(); } }, //DEVELOPER: this function will be automatically called when all the properties defined in //this.get('propertiesLoaders') are loaded. To indicate that a property is loaded //me.propertiesReady(properties) should be executed by loadFunction of each property allPropertiesLoaded: function () { var me = this; OB.Data.Registry.loadModelsDelayedUntilLoggedIn().then(function () { // when the delayed models have been loaded, continue OB.info('properties has been loaded successfully', me.attributes); var undef; me.loggingIn = false; //core if (!me.get('loggedOffline') && !me.get('loggedUsingCache')) { //In online mode, we save the terminal information in the local db me.usermodel.set('terminalinfo', JSON.stringify(me)); OB.Dal.save(me.usermodel, function () {}, function () { OB.error(arguments); }); } if (!OB.MobileApp.model.get('datasourceLoadFailed')) { me.trigger('propertiesLoadersReady'); } }, function () { // if the delayed models failed to load, the application will not work. try to load them again OB.MobileApp.model.cleanLocalStorageAndReload(); }); }, navigate: function (route) { this.router.navigate(route, { trigger: true }); }, /** * Loads registered windows and calls renderMain method implemented by each app */ renderTerminalMain: function () { OB.UTIL.Debug.execute(function () { if (!this.renderMain) { OB.error('There is no renderMain method in Terminal Model'); } }, this); this.loadTerminalInfo(); }, /** * Loads all needed stuff for the terminal such as permissions, Application... */ loadTerminalInfo: function () { var me = this, loadQueue = {}; function triggerLoadTerminalInfoReady() { if (OB.UTIL.queueStatus(loadQueue)) { me.setUserModelOnline(function () { me.trigger('terminalInfoLoaded'); }); } } if (window.openDatabase) { this.initLocalDB(loadQueue, triggerLoadTerminalInfoReady); } if (OB.MobileApp.model.get('loggedOffline') || OB.MobileApp.model.get('loggedUsingCache')) { triggerLoadTerminalInfoReady(); OB.Format = JSON.parse(window.localStorage.getItem('AppFormat')); OB.I18N.labels = JSON.parse(window.localStorage.getItem('I18NLabels_' + window.localStorage.getItem('languageForUser_' + me.usermodel.get('id')))); return; } loadQueue.preferences = false; new OB.DS.Request('org.openbravo.mobile.core.login.RolePermissions').exec({ appModuleId: this.get('appModuleId') }, function (data) { var i, max, separator, permissions = {}; if (data) { for (i = 0, max = data.length; i < max; i++) { permissions[data[i].key] = data[i].value; // Add the permission value. separator = data[i].key.indexOf('_'); if (separator >= 0) { permissions[data[i].key.substring(separator + 1)] = data[i].value; // if key has a DB prefix, add also the permission value without this prefix } } me.set('permissions', permissions); // TODO: offline + usermodel loadQueue.preferences = true; triggerLoadTerminalInfoReady(); } }); loadQueue.application = false; new enyo.Ajax({ url: this.get('applicationFormatUrl'), method: 'GET', handleAs: 'text' }).response(function (inSender, inResponse) { eval(inResponse); //...we have an OB variable local to this function // we want to 'export' some properties to global OB window.OB.Application = OB.Application; window.OB.Format = OB.Format; window.localStorage.setItem('AppFormat', JSON.stringify(OB.Format)); window.OB.Constants = OB.Constants; loadQueue.application = true; triggerLoadTerminalInfoReady(); window.localStorage.setItem('cacheAvailableForUser:' + me.user, true); }).go(); }, isSafeToResetDatabase: function (callbackIsSafe, callbackIsNotSafe) { callbackIsSafe(); }, databaseCannotBeResetAction: function () { //Will never happen in standard mobile core. Should be overwritten in applications if isSafeToResetDatabase is implemented }, initLocalDB: function (loadQueue, triggerLoadTerminalInfoReady) { loadQueue.localDB = false; var undef; var dbInfo = this.get('localDB'); var wsql = window.openDatabase !== undef; var db; if (wsql === false) { // Support should get this error. Show it in productionn console.error("WebSQL error: Unable find the database engine"); } try { db = (wsql && window.openDatabase(dbInfo.name, '', dbInfo.displayName, dbInfo.size)); } catch (e) { // if the database could not be created, logging with OB.error is not available // Support should get this error. Show it in productionn console.error("Web SQL error: " + e); return; } if (!db) { // if the database could not be created, logging with OB.error is not available // Support should get this error. Show it in productionn console.error("Web SQL error"); return; } function dropTable(db, sql) { var synchId = SynchronizationHelper.busyUntilFinishes('dropTable'); db.transaction(function (tx) { tx.executeSql(sql, {}, function () { SynchronizationHelper.finished(synchId, 'dropTable'); OB.info('succesfully dropped table: ' + sql); }, function () { SynchronizationHelper.finished(synchId, 'dropTable'); OB.error(arguments); }); }); } function dropTables() { var model; var modelObj; OB.info('Updating database model. Tables will be dropped:'); for (model in OB.Model) { if (OB.Model.hasOwnProperty(model)) { modelObj = OB.Model[model]; if ((modelObj.prototype && modelObj.prototype.dropStatement) || modelObj.getDropStatement) { //There is a dropStatement, executing it dropTable(db, modelObj.getDropStatement ? modelObj.getDropStatement() : modelObj.prototype.dropStatement); } } } } db.changeVersion(db.version, dbInfo.version, function (t) { var model, modelObj; if (db.version === dbInfo.version) { //Database version didn't change. //Will check if terminal id has changed if (window.localStorage.getItem('terminalName')) { if (window.localStorage.getItem('terminalName') !== OB.MobileApp.model.get('terminalName')) { OB.MobileApp.model.isSafeToResetDatabase(function () { OB.info('Terminal has been changed. Resetting database and local storage information.'); dropTables(); window.localStorage.clear(); window.localStorage.setItem('terminalName', OB.MobileApp.model.get('terminalName')); }, OB.MobileApp.model.databaseCannotBeResetAction); } } loadQueue.localDB = true; triggerLoadTerminalInfoReady(); return; } OB.MobileApp.model.isSafeToResetDatabase(function () { //Version of the database changed, we need to drop the tables so they can be created again dropTables(); loadQueue.localDB = true; triggerLoadTerminalInfoReady(); }, OB.MobileApp.model.databaseCannotBeResetAction); }, function (e) { console.error("WebSQL error: changeVersion failed: " + e); }); // exposing DB globally window.OB = OB || {}; window.OB.Data = OB.Data || {}; window.OB.Data.localDB = db; }, /** * initActions actions is executed before initializeCommonComponents. * * Override this in case you app needs to do something special * Do not forget to execute callback when overriding the method */ initActions: function (callback) { callback(); }, /** * PreLoadContext actions is executed before loading the context. * * Override this in case you app needs to do something special * Do not forget to execute callback when overriding the method */ preLoadContext: function (callback) { callback(); }, /** Recursively syncs models. * Should not be called directly. syncAllModels should be used instead. **/ syncModel: function (index, successCallback, errorCallback) { var me = this, modelObj, model, criteria = { hasBeenProcessed: 'Y' }; if (index === this.get('dataSyncModels').length) { if (successCallback) { successCallback(); } return; } modelObj = this.get('dataSyncModels')[index]; if (modelObj.criteria) { criteria = modelObj.criteria; } model = modelObj.model; OB.Dal.find(model, criteria, function (dataToSync) { var className = modelObj.className; var timeout = modelObj.timeout || 7000; var proc; var dataToSend = []; if (dataToSync.length === 0) { return me.syncModel(index + 1, successCallback, errorCallback); } if (model === OB.Model.ChangedBusinessPartners && OB.UTIL.processCustomerClass) { className = OB.UTIL.processCustomerClass; } else if (model === OB.Model.Order && OB.UTIL.processOrderClass) { className = OB.UTIL.processOrderClass; } proc = new OB.DS.Process(className); dataToSync.each(function (record) { if (record.get('json')) { dataToSend.push(JSON.parse(record.get('json'))); } else if (record.get('objToSend')) { dataToSend.push(JSON.parse(record.get('objToSend'))); } else { dataToSend.push(record); } }); proc.exec({ data: dataToSend }, function (data, message) { var removeSyncedElemsCallback = function () { dataToSync.each(function (record) { if (modelObj.isPersistent) { // Persistent model. Do not delete, just mark it as processed. record.set('isbeingprocessed', 'Y'); OB.Dal.save(record, null, function (tx, err) { OB.UTIL.showError(err); }); } else { // No persistent model (Default). OB.Dal.remove(record, null, function (tx, err) { OB.UTIL.showError(err); }); } }); me.syncModel(index + 1, successCallback, errorCallback); }; if (data && data.exception) { //Error if (errorCallback) { errorCallback(); } } else { //Success. Elements can be now deleted from the database if (modelObj.postProcessingFunction) { modelObj.postProcessingFunction(dataToSync, removeSyncedElemsCallback); } else { removeSyncedElemsCallback(); } } }, null, null, timeout); }, function () { OB.error('Error while synchronizing model:', model); if (errorCallback) { errorCallback(); } }); }, /** Automatically synchronizes all dataSyncModels * **/ syncAllModels: function (successCallback, errorCallback) { if (!this.get('dataSyncModels') || this.get('dataSyncModels').length === 0) { return; } this.syncModel(0, successCallback, errorCallback); }, /** * If any module needs to perform operations with properties coming from the server * this function must be overwritten */ isUserCacheAvailable: function () { return true; }, /** * Invoked from initComponents in terminal view */ initializeCommonComponents: function () { var me = this, params = {}; window.localStorage.setItem('LOGINTIMER', new Date().getTime()); params = this.get('loginUtilsParams') || {}; params.command = 'preRenderActions'; // initialize labels and other common stuff var ajaxRequest = new enyo.Ajax({ url: this.get('loginUtilsUrl'), cacheBust: false, timeout: 60000, method: 'GET', handleAs: 'json', contentType: 'application/json;charset=utf-8', data: params, success: function (inSender, inResponse) { OB.appCaption = inResponse.appCaption; if (_.isEmpty(inResponse.labels) || _.isNull(inResponse.labels) || _.isUndefined(inResponse.labels)) { OB.I18N.labels = JSON.parse(window.localStorage.getItem('I18NLabels')); } else { OB.I18N.labels = inResponse.labels; if (inResponse.activeSession) { // The labels will only be saved in the localStorage if they come from an active session // We do this to prevent the labels loaded in the login page from being stored here and overwritting // the labels in the correct language (see issue 23613) window.localStorage.setItem('languageForUser_' + inResponse.labels.userId, inResponse.labels.languageId); window.localStorage.setItem('I18NLabels', JSON.stringify(OB.I18N.labels)); window.localStorage.setItem('I18NLabels_' + inResponse.labels.languageId, JSON.stringify(OB.I18N.labels)); } } if (_.isEmpty(inResponse.dateFormats) || _.isNull(inResponse.dateFormats) || _.isUndefined(inResponse.dateFormats)) { OB.Format = JSON.parse(window.localStorage.getItem('AppFormat')); } else { OB.Format = inResponse.dateFormats; } me.trigger('initializedCommonComponents'); me.preLoadContext(function () { new OB.DS.Request('org.openbravo.mobile.core.login.Context').exec({ ignoreForConnectionStatus: true }, function (inResponse) { OB.MobileApp.model.triggerOnLine(); if (inResponse && !inResponse.exception) { OB.MobileApp.model.user = inResponse[0].user.username; if (me.isUserCacheAvailable() && window.localStorage.getItem('cacheAvailableForUser:' + OB.MobileApp.model.user)) { me.loginUsingCache(); } else { OB.MobileApp.model.set('orgUserId', inResponse[0].user.id); OB.UTIL.showLoading(true); me.set('context', inResponse[0]); me.renderTerminalMain(); } } else { me.navigate('login'); } }, function () { me.navigate('login'); }); }); }, fail: function (inSender, inResponse) { // we are likely offline. Attempt to navigate to the login page OB.I18N.labels = JSON.parse(window.localStorage.getItem('I18NLabels')); OB.Format = JSON.parse(window.localStorage.getItem('AppFormat')); me.trigger('initializedCommonComponents'); if (!OB.I18N.labels || !OB.Format) { // These 2 objects are needed for the application to show i18n messages and date and number formats OB.UTIL.showLoading(false); var errorMsg = "The server is not available and the cache has not enough data. Connect to the server and try again."; OB.error(errorMsg); OB.UTIL.showConfirmation.display('Error', errorMsg, [{ label: 'Retry', isConfirmButton: true, action: function () { // Retry. If the server is not available, the message will open again me.initializeCommonComponents(); } }], { onHideFunction: function () { // Retry. If the server is not available, the message will open again me.initializeCommonComponents(); } }); return; } me.navigate('login'); } }); ajaxRequest.go(ajaxRequest.data).response('success').error('fail'); }, renderLogin: function () { if (!OB.Data.localDB && window.openDatabase) { this.initLocalDB({}, function () {}); } if (!OB.MobileApp.view.$.containerWindow) { OB.UTIL.Debug.execute(function () { console.error("containerWindow is missing"); }); return; } OB.MobileApp.view.$.containerWindow.destroyComponents(); OB.MobileApp.view.$.containerWindow.createComponent({ kind: OB.OBPOSLogin.UI.Login }).render(); OB.UTIL.showLoading(false); }, loadModels: function (windowv, incremental) { var windows, i, windowName, windowClass, datasources, timestamp = 0, w, c, path; if (OB.MobileApp.model.get('loggedOffline')) { return; } if (windowv) { windows = [windowv]; } else { windows = []; _.each(this.windowRegistry.registeredWindows, function (windowp) { windows.push(windowp); }); } OB.info('[sdrefresh] Load models ' + (incremental ? 'incrementally' : 'full') + '.'); for (i = 0; i < windows.length; i++) { windowClass = windows[i].windowClass; windowName = windows[i].route; if (OB && OB.DATA && OB.DATA[windowName]) { // old way of defining datasources... datasources = OB.DATA[windowName]; } else if (windowClass.prototype && windowClass.prototype.windowmodel && windowClass.prototype.windowmodel.prototype && windowClass.prototype.windowmodel.prototype.models) { datasources = windowClass.prototype.windowmodel.prototype.models; } else if (typeof windowClass === 'string') { w = window; // global window path = windowClass.split('.'); for (c = 0; c < path.length; c++) { w = w[path[c]]; } if (w.prototype && w.prototype.windowmodel && w.prototype.windowmodel.prototype && w.prototype.windowmodel.prototype.models) { datasources = w.prototype.windowmodel.prototype.models; } } _.extend(datasources, Backbone.Events); OB.info('[sdrefresh] window: ' + windowName); OB.Dal.loadModels(false, datasources, null, incremental); } }, cleanWindows: function () { this.windows = new(Backbone.Collection.extend({ comparator: function (window) { // sorts by menu position, 0 if not defined var position = window.get('menuPosition'); return position ? position : 0; } }))(); }, registerWindow: function (window) { this.windowRegistry.registerWindow(window); }, /** * Iterates over all registered windows loading their models */ loadRegisteredWindows: function () { this.cleanWindows(); setInterval(OB.UTIL.processLogClientAll, 10000); var countOfLoadedWindows = 0; _.each(this.windowRegistry.registeredWindows, function (windowp) { var datasources = [], windowClass, windowName = windowp.route, minTotalRefresh, minIncRefresh, lastTotalRefresh, lastIncRefresh, intervalTotal, intervalInc, now, terminalType; this.windows.add(windowp); // if (!OB.POS.windowObjs) { // OB.POS.windowObjs = []; // } // OB.POS.windowObjs.push(windowp); // this.loadModels(windowp, false); // if (false) { terminalType = OB.MobileApp.model.get('terminal') && OB.MobileApp.model.get('terminal').terminalType; if (terminalType) { minTotalRefresh = OB.MobileApp.model.get('terminal').terminalType.minutestorefreshdatatotal * 60 * 1000; minIncRefresh = OB.MobileApp.model.get('terminal').terminalType.minutestorefreshdatainc * 60 * 1000; lastTotalRefresh = window.localStorage.getItem('POSLastTotalRefresh'); lastIncRefresh = window.localStorage.getItem('POSLastIncRefresh'); } if ((!minTotalRefresh && !minIncRefresh) || (!lastTotalRefresh && !lastIncRefresh)) { // If no configuration of the masterdata loading has been done, // or an initial load has not been done, then always do // a total refresh during the login this.loadModels(windowp, false); } else { now = new Date().getTime(); intervalTotal = lastTotalRefresh ? (now - lastTotalRefresh - minTotalRefresh) : 0; intervalInc = lastIncRefresh ? (now - lastIncRefresh - minIncRefresh) : 0; if (intervalTotal > 0) { this.set('FullRefreshWasDone', true); //It's time to do a full refresh this.loadModels(windowp, false); } } //} this.router.route(windowName, windowName, function () { this.renderGenericWindow(windowName); }); this.router.route(windowName + "/:params", windowName, function (params) { this.renderGenericWindow(windowName, params); }); countOfLoadedWindows += 1; }, this); // checks if the windows loaded are more than the windows registered, which never should happen var countOfRegisteredWindows = this.windowRegistry.registeredWindows.length; console.assert(countOfRegisteredWindows === countOfLoadedWindows, 'DEVELOPER: There are ' + countOfRegisteredWindows + ' registered windows but ' + countOfLoadedWindows + ' are being loaded'); }, isWindowOnline: function (route) { var i, windows; windows = this.windows.toArray(); for (i = 0; i < windows.length; i++) { if (windows[i].get('route') === route) { return windows[i].get('online'); } } return false; }, renderGenericWindow: function (windowName, params) { OB.UTIL.showLoading(true); var terminal = OB.MobileApp.model.get('terminal'), windowClass; windowClass = this.windows.where({ route: windowName })[0].get('windowClass'); OB.MobileApp.view.$.containerWindow.destroyComponents(); OB.MobileApp.view.$.containerWindow.createComponent({ kind: windowClass, params: params }); }, renderContainerWindow: function () { OB.MobileApp.view.$.containerWindow.render(); OB.UTIL.showLoading(false); OB.MobileApp.view.$.containerWindow.resized(); //enyo.dispatcher.capture(OB.MobileApp.view, false); }, updateSession: function (user) { OB.Dal.find(OB.Model.Session, { 'user': user.get('id') }, function (sessions) { var session; if (sessions.models.length === 0) { session = new OB.Model.Session(); session.set('user', user.get('id')); session.set('terminal', OB.MobileApp.model.get('terminalName')); session.set('active', 'Y'); OB.Dal.save(session, function () {}, function () { OB.error(arguments); }); } else { session = sessions.models[0]; session.set('active', 'Y'); OB.Dal.save(session, function () {}, function () { OB.error(arguments); }); } OB.MobileApp.model.set('session', session.get('id')); }, function () { OB.error(arguments); }); }, /** * This method is invoked when closing session, it is in charge * of dealing with all stuff needed to close session. After it is * done it MUST do triggerLogout */ postCloseSession: function (session) { OB.MobileApp.model.triggerLogout(); }, closeSession: function () { var sessionId = OB.MobileApp.model.get('session'), me = this; if (!this.get('supportsOffline') || !OB.Model.Session) { OB.MobileApp.model.triggerLogout(); return; } OB.Dal.get(OB.Model.Session, sessionId, function (session) { session.set('active', 'N'); OB.Dal.save(session, function () { me.postCloseSession(session); }, function () { OB.error(arguments); OB.MobileApp.model.triggerLogout(); }); }, function () { OB.error(arguments); OB.MobileApp.model.triggerLogout(); }); }, generate_sha1: function (theString) { return CryptoJS.enc.Hex.stringify(CryptoJS.SHA1(theString)); }, attemptToLoginOffline: function () { var me = this; OB.MobileApp.model.set('windowRegistered', undefined); OB.MobileApp.model.set('loggedOffline', true); OB.Dal.find(OB.Model.User, { 'name': me.user }, function (users) { var user; if (users.models.length === 0) { alert(OB.I18N.getLabel('OBMOBC_OfflinePasswordNotCorrect')); window.location.reload(); } else { if (users.models[0].get('password') === me.generate_sha1(me.password + users.models[0].get('created'))) { me.usermodel = users.models[0]; me.set('orgUserId', users.models[0].id); me.updateSession(me.usermodel); me.renderTerminalMain(); } else { alert(OB.I18N.getLabel('OBMOBC_OfflinePasswordNotCorrect')); window.location.reload(); } } }, function () {}); }, postLoginActions: function () { }, loginUsingCache: function () { var me = this; if (!OB.Data.localDB && window.openDatabase) { this.initLocalDB({}, function () {}); } OB.Dal.find(OB.Model.User, { 'name': me.user }, function (users) { if (!users.models[0]) { // the data for the user is not valid, recreate it OB.MobileApp.model.cleanLocalStorageAndReload(); return; } me.usermodel = users.models[0]; me.set('orgUserId', users.models[0].id); OB.MobileApp.model.set('windowRegistered', undefined); OB.MobileApp.model.set('loggedUsingCache', true); me.updateSession(me.usermodel); me.renderTerminalMain(); }, function () { // if the cache is corrupted OB.MobileApp.model.cleanLocalStorageAndReload(); }); }, /** * Prelogin actions is executed before login, it should take care of * removing all session values specific by application. * * Override this in case you app needs to do something special */ preLoginActions: function () { }, login: function (user, password, mode) { var params; OB.UTIL.showLoading(true); var me = this; me.user = user; me.password = password; // invoking app specific actions this.preLoginActions(); this.set('isLoggingIn', true); params = this.get('loginUtilsParams') || {}; params.user = user; params.password = password; params.Command = 'DEFAULT'; params.IsAjaxCall = 1; params.appName = this.get('appName'); var ajaxRequest = new enyo.Ajax({ url: this.get('loginHandlerUrl'), cacheBust: false, method: 'POST', timeout: 5000, contentType: 'application/x-www-form-urlencoded; charset=UTF-8', data: params, success: function (inSender, inResponse) { var pos, baseUrl; if (this.alreadyProcessed) { return; } this.alreadyProcessed = true; if (OB.MobileApp.model.get('timeoutWhileLogin')) { OB.MobileApp.model.set('timeoutWhileLogin', false); return; } if (inResponse && inResponse.showMessage) { me.triggerLoginFail(401, mode, inResponse); return; } OB.MobileApp.model.set('orgUserId', inResponse.userId); me.set('loggedOffline', false); if (me.get('supportsOffline')) { me.setUserModelOnline(); } if (me.isUserCacheAvailable() && window.localStorage.getItem('cacheAvailableForUser:' + user)) { me.loginUsingCache(); } else { me.initializeCommonComponents(); } }, fail: function (inSender, inResponse) { if (this.alreadyProcessed) { return; } this.alreadyProcessed = true; me.attemptToLoginOffline(); } }); ajaxRequest.go(ajaxRequest.data).response('success').error('fail'); }, setUserModelOnline: function (callback) { var me = this; OB.Dal.initCache(OB.Model.User, [], null, null); OB.Dal.initCache(OB.Model.LogClient, [], null, null); OB.Dal.initCache(OB.Model.Session, [], null, null); OB.Dal.find(OB.Model.User, { 'name': me.user }, function (users) { var user, session, date, savedPass; if (users.models.length === 0) { date = new Date().toString(); user = new OB.Model.User(); user.set('name', me.user); user.set('id', OB.MobileApp.model.get('orgUserId')); savedPass = me.generate_sha1(me.password + date); user.set('password', savedPass); user.set('created', date); user.set('formatInfo', JSON.stringify(OB.Format)); me.usermodel = user; OB.Dal.save(user, function () { if (callback) { callback(); } }, function () { OB.error(arguments); OB.MobileApp.model.cleanLocalStorageAndReload(); return; }, true); } else { user = users.models[0]; me.usermodel = user; if (me.password) { //The password will only be recomputed in case it was properly entered //(that is, if the call comes from the login page directly) savedPass = me.generate_sha1(me.password + user.get('created')); user.set('password', savedPass); } user.set('formatInfo', JSON.stringify(OB.Format)); OB.Dal.save(user, function () { me.updateSession(user); if (callback) { callback(); } }, function () { OB.error(arguments); OB.MobileApp.model.cleanLocalStorageAndReload(); return; }); } }, function () { OB.error(arguments); }); }, /** * Set of app specific actions executed before loging out. * * Override this method if your app needs to do something special */ preLogoutActions: function () { }, logout: function () { var me = this; this.preLogoutActions(); var ajaxRequest = new enyo.Ajax({ url: '../../org.openbravo.mobile.core.logout', cacheBust: false, method: 'GET', handleAs: 'json', timeout: 5000, contentType: 'application/json;charset=utf-8', success: function (inSender, inResponse) { me.closeSession(); }, fail: function (inSender, inResponse) { me.closeSession(); } }); ajaxRequest.go().response('success').error('fail'); }, lock: function () { var me = this; this.preLogoutActions(); var ajaxRequest = new enyo.Ajax({ url: '../../org.openbravo.mobile.core.logout', cacheBust: false, method: 'GET', handleAs: 'json', timeout: 5000, contentType: 'application/json;charset=utf-8', success: function (inSender, inResponse) { me.triggerLogout(); }, fail: function (inSender, inResponse) { me.triggerLogout(); } }); ajaxRequest.go().response('success').error('fail'); }, triggerLogout: function () { this.trigger('logout'); var params, paramsStr = null; if (this.get('logoutUrlParams')) { var keyParams; params = this.get('logoutUrlParams'); keyParams = _.keys(params); if (keyParams.length > 0) { paramsStr = '?'; _.each(keyParams, function (key, index) { if (index > 0) { paramsStr = paramsStr + '&'; } paramsStr = paramsStr + key.toString() + '=' + window.encodeURIComponent(params[key]); }); } } window.location = paramsStr ? window.location.pathname + paramsStr : window.location.pathname; }, triggerLoginSuccess: function () { this.trigger('loginsuccess'); }, triggerOnLine: function () { if (!OB.MobileApp.model.loggingIn) { this.set('connectedToERP', true); if (this.pingId) { clearInterval(this.pingId); this.pingId = null; } } }, triggerOffLine: function () { if (!OB.MobileApp.model.loggingIn) { this.set('connectedToERP', false); if (!this.pingId) { this.pingId = setInterval(OB.UTIL.checkConnectivityStatus, 60000); } } }, triggerLoginFail: function (e, mode, data) { OB.UTIL.showLoading(false); if (mode === 'userImgPress') { this.trigger('loginUserImgPressfail', e); } else { this.trigger('loginfail', e, data); } }, hasPermission: function (p, checkForAutomaticRoles) { return (!checkForAutomaticRoles && !this.get('context').role.manual) || this.get('permissions')[p]; }, supportLogClient: function () { var supported = true; if ((OB.MobileApp && OB.MobileApp.model && OB.MobileApp.model.get('supportsOffline')) === false) { supported = false; } return supported; }, saveTerminalInfo: function () { OB.info('saving terminal info:', this.attributes); //In online mode, we save the terminal information in the local db this.usermodel.set('terminalinfo', JSON.stringify(this)); OB.Dal.save(this.usermodel, function () {}, function () { OB.error(arguments); }); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var LogClient = OB.Data.ExtensibleModel.extend({ modelName: 'LogClient', tableName: 'obmobc_logclient', entityName: 'LogClient', source: 'org.openbravo.mobile.core.master.LogClient', local: true, createStatement: 'CREATE TABLE IF NOT EXISTS obmobc_logclient (obmobc_logclient_id TEXT PRIMARY KEY, deviceId TEXT, msg TEXT, json CLOB, created TEXT, createdby TEXT)', dropStatement: 'DROP TABLE IF EXISTS obmobc_logclient', insertStatement: 'INSERT INTO obmobc_logclient (obmobc_logclient_id, deviceId, msg, json, created, createdby) VALUES (?,?,?,?,?,?)', serializeToJSON: function () { return JSON.parse(JSON.stringify(this.toJSON())); } }); LogClient.addProperties([{ name: 'id', column: 'obmobc_logclient_id', primaryKey: true, type: 'TEXT' }, { name: 'deviceId', column: 'deviceId', type: 'TEXT' }, { name: 'msg', column: 'msg', type: 'TEXT' }, { name: 'json', column: 'json', type: 'CLOB' }, { name: 'created', column: 'created', type: 'TEXT' }, { name: 'createdby', column: 'createdby', type: 'TEXT' }]); OB.Data.Registry.registerModel(LogClient); }()); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _, $ */ enyo.kind({ name: 'OB.UI.Button', kind: 'enyo.Button', handlers: { onkeydown: 'keydownHandler' }, keydownHandler: function (inSender, inEvent) { var keyCode = inEvent.keyCode; if (keyCode === 13 || keyCode === 32) { //Handle ENTER and SPACE keys in buttons this.executeTapAction(); return true; } return false; }, executeTapAction: function () { if (this && this.ontap && this.owner && this.owner[this.ontap]) { this.owner[this.ontap](); } else { this.tap(); } }, focus: function () { // Enyo doesn't have "focus" function in buttons, so it has to be implemented if (this.hasNode()) { this.hasNode().focus(); } }, initComponents: function () { this.inherited(arguments); if (this.i18nContent) { this.setContent(OB.I18N.getLabel(this.i18nContent)); } else if (this.i18nLabel) { this.setContent(OB.I18N.getLabel(this.i18nLabel)); } else if (this.label) { this.setContent(this.label); } } /*, Removed to investigate if btn-over/btn-down are still needed due to enyo/onyx adoption handlers: { onmouseover: 'mouseOverOut', onmouseout: 'mouseOverOut' }, //TODO: support windows 7 setTimeout(function() { me.$el.removeClass('btn-down'); }, 125); mouseOverOut: function (inSender, inEvent) { this.addRemoveClass('btn-over', inEvent.type === 'mouseover'); }*/ }); enyo.kind({ name: 'OB.UI.RegularButton', kind: 'OB.UI.Button', icon: '', iconright: '', label: '', classes: 'btnlink' }); enyo.kind({ name: 'OB.UI.SmallButton', kind: 'OB.UI.RegularButton', classes: 'btnlink-small' }); enyo.kind({ name: 'OB.UI.MediumButton', kind: 'OB.UI.RegularButton', classes: 'btnlink-medium' }); enyo.kind({ name: 'OB.UI.ModalDialogButton', kind: 'OB.UI.RegularButton', events: { onHideThisPopup: '' }, classes: 'btnlink-gray modal-dialog-button' }); enyo.kind({ name: 'OB.UI.Popup', kind: "onyx.Popup", centered: true, floating: true, closeOnEscKey: true, scrim: true, autoDismiss: true, handlers: { onkeydown: 'keydownHandler', onHideThisPopup: 'hideFromInside' }, keydownHandler: function (inSender, inEvent) { var keyCode = inEvent.keyCode; if (keyCode === 27 && this.showing && this.closeOnEscKey) { //Handle ESC key to hide the popup this.hide(); return true; } else if (keyCode === 13 && this.defaultActionButton) { //Handle ENTER key to execute the default action (if exists) this.defaultActionButton.executeTapAction(); return true; } else { return false; } }, _addArgsToComponent: function (args) { if (args) { this.args = this.args || {}; _.each(args, function (arg, key) { this.args[key] = arg; }, this); } }, showingChanged: function () { this.inherited(arguments); if (this.showing) { OB.MobileApp.view.openedPopup = this; } else { OB.MobileApp.view.openedPopup = null; } }, show: function (args) { var resp = true; // While in poup, disable focusKeeper this.originalScanMode = OB.MobileApp.view.scanMode; OB.MobileApp.view.scanningFocus(false); this.args = {}; //reset; this._addArgsToComponent(args); if (this.executeOnShow) { resp = this.executeOnShow(); if (_.isUndefined(resp) || _.isNull(resp)) { resp = true; } } if (resp) { var me = this; if (me.autoDismiss) { me.autoDismiss = false; this.inherited(arguments); setTimeout(function () { //The autoDismiss is activated only after a small delay, to prevent issue 24582 from happening me.autoDismiss = true; }, 100); } else { this.inherited(arguments); } this.setDefaultActionButton(); this.focusInPopup(); if (this.executeOnShown) { this.executeOnShown(); } } }, hideFromInside: function (inSender, inEvent) { this.hide(inEvent.args); }, hide: function (args) { var resp = true; this._addArgsToComponent(args); if (this.executeBeforeHide) { resp = this.executeBeforeHide(); if (_.isUndefined(resp) || _.isNull(resp)) { resp = true; } } if (resp) { this.inherited(arguments); // This line will remove the popup in case hasNode doesn't return a valid component. // This is needed because after a resize, if not done, the popups stop working correctly if (!this.hasNode()) { var element = document.getElementById(this.id); // only remove from the parent if the element is there if (element) { element.parentNode.removeChild(element); } } // Restore focus keeper OB.MobileApp.view.scanningFocus(this.originalScanMode); if (this.executeOnHide) { this.executeOnHide(); } } delete this.originalScanMode; }, focusInPopup: function () { var allChildsArray = OB.UTIL.getAllChildsSorted(this), isFirstFocusableElementObtained = false, tagName, element, i; for (i = 0; i < allChildsArray.length; i++) { if (allChildsArray[i].hasNode() && allChildsArray[i].hasNode().tagName) { tagName = allChildsArray[i].hasNode().tagName.toUpperCase(); } else { tagName = ''; } if ((tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA' || tagName === 'BUTTON') && allChildsArray[i].showing && !isFirstFocusableElementObtained) { element = allChildsArray[i]; isFirstFocusableElementObtained = true; } else if (allChildsArray[i].isFirstFocus) { element = allChildsArray[i]; break; } } if (element) { element.focus(); } return true; }, setDefaultActionButton: function (element) { var allChildsArray, tagName, i; if (element) { allChildsArray = [element]; } else { allChildsArray = OB.UTIL.getAllChildsSorted(this); } for (i = 0; i < allChildsArray.length; i++) { if (allChildsArray[i].hasNode() && allChildsArray[i].hasNode().tagName) { tagName = allChildsArray[i].hasNode().tagName.toUpperCase(); } else { tagName = ''; } if (tagName === 'BUTTON' && allChildsArray[i].isDefaultAction) { element = allChildsArray[i]; break; } } if (element) { this.defaultActionButton = element; } return true; }, updatePosition: function () { if (!this.centered || !this.floating) { this.inherited(arguments); return true; } // Improve of enyo "updatePosition" function to proper manage of % and absolute top and left positions var top, left, t = this.getBounds(); if (this.topPosition) { top = this.topPosition.toString(); } else if (this.centered) { top = '50%'; } else { top = '0'; } if (top.indexOf('px') !== -1) { top = top.replace('px', ''); } if (this.leftPosition) { left = this.leftPosition.toString(); } else if (this.centered) { left = '50%'; } else { left = '0'; } if (left.indexOf('px') !== -1) { left = left.replace('px', ''); } if (top.indexOf('%') !== -1) { this.addStyles('top: ' + top); this.addStyles('margin-top: -' + Math.max(t.height / 2, 0).toString() + 'px;'); } else { this.addStyles('top: ' + top + 'px'); } if (left.indexOf('%') !== -1) { this.addStyles('left: ' + left); this.addStyles('margin-left: -' + Math.max(t.width / 2, 0).toString() + 'px;'); } else { this.addStyles('left: ' + left + 'px'); } return true; } }); enyo.kind({ //TODO: maxheight name: 'OB.UI.Modal', kind: 'OB.UI.Popup', classes: 'modal modal-poup', published: { header: '' }, components: [{ tag: 'div', classes: 'modal-header', components: [{ name: 'closebutton', tag: 'div', classes: 'modal-header-closebutton', components: [{ tag: 'span', ontap: 'hide', allowHtml: true, content: '×' }] }, { name: 'header', classes: 'modal-header-text' }] }, { tag: 'div', name: 'body', classes: 'modal-body' }], headerChanged: function () { this.$.header.setContent(this.i18nHeader ? OB.I18N.getLabel(this.i18nHeader) : this.header); }, initComponents: function () { this.inherited(arguments); if (this.modalClass) { this.addClass(this.modalClass); } this.$.header.setContent(this.i18nHeader ? OB.I18N.getLabel(this.i18nHeader) : this.header); if (this.bodyClass) { this.$.body.addClass(this.bodyClass); } this.$.body.createComponent(this.body); } }); enyo.kind({ name: 'OB.UI.RenderEmpty', style: 'border-bottom: 1px solid #cccccc; padding: 20px; text-align: center; font-weight: bold; font-size: 30px; color: #cccccc', initComponents: function () { this.inherited(arguments); this.setContent(this.label || OB.I18N.getLabel('OBMOBC_SearchNoResults')); } }); enyo.kind({ name: 'OB.UI.SelectButton', kind: 'OB.UI.Button', classes: 'btnselect', tap: function () { this.model.trigger('selected', this.model); this.model.trigger('click', this.model); } }); //Automated test. new kind to extend list item buttons. enyo.kind({ kind: 'OB.UI.SelectButton', name: 'OB.UI.listItemButton', classes: 'btnselect', tap: function () { this.model.trigger('selected', this.model); this.model.trigger('click', this.model); }, getValueByFieldName: function (fieldName) { if (this.$[fieldName] && this.$[fieldName].getValue) { return this.$[fieldName].getValue(); } else if (this.$[fieldName] && this.$[fieldName].content) { return this.$[fieldName].content; } else { OB.warn('No way found to return field name. Overwrite this method in the component to do it'); } return null; }, getValueByIndex: function (index) { if (this.columns) { if (this.getValueByFieldName) { return this.getValueByFieldName(this.columns[index]); } else { OB.warn(this.name + ' must implement getValueByFieldName'); } } else { OB.warn('columns array is not present in ' + this.name + ' And it is needed to execute getValueByIndex'); } return null; }, getValue: function (arg) { if (_.isNumber(arg)) { if (this.getValueByIndex) { return this.getValueByIndex(arg); } else { OB.warn('getValueByIndex is not present in ' + this.name); return null; } } else if (_.isString(arg)) { if (this.getValueByFieldName) { return this.getValueByFieldName(arg); } else { OB.warn('getValueByFieldName is not present in ' + this.name); return null; } } } }); enyo.kind({ name: 'OB.UI.CancelButton', kind: 'OB.UI.SmallButton', classes: 'btnlink-white btnlink-fontgray', events: { onShowPopup: '' }, tap: function () { this.doShowPopup({ popup: 'modalCancel' }); }, initComponents: function () { this.inherited(arguments); this.setContent(this.label || OB.I18N.getLabel('OBMOBC_LblCancel')); } }); enyo.kind({ name: 'OB.UI.RadioButton', kind: "onyx.Checkbox", classes: 'btn btn-radio', style: 'padding: 0px 0px 0px 40px; margin: 10px;', activeRadio: function () { this.addClass('active'); this.setChecked(true); }, disableRadio: function () { this.setNodeProperty('checked', false); this.setAttribute('checked', ''); this.removeClass('active'); this.active = false; this.checked = false; }, tap: function () { this.inherited(arguments); this.activeRadio(); }, initComponents: function () { this.inherited(arguments); } }); // Toolbar Button enyo.kind({ name: 'OB.UI.ToolbarButton', kind: 'OB.UI.RegularButton', classes: 'btnlink-toolbar', initComponents: function () { this.inherited(arguments); if (this.icon) { this.addClass(this.icon); } } }); enyo.kind({ name: 'OB.UI.CheckboxButton', kind: 'OB.UI.Button', classes: 'btn-check', checked: false, tap: function () { if (this.readOnly) { return; } this.checked = !this.checked; this.addRemoveClass('active', this.checked); }, toggle: function () { this.checked = !this.checked; this.addRemoveClass('active', this.checked); }, check: function () { this.addClass('active'); this.checked = true; }, unCheck: function () { this.removeClass('active'); this.checked = false; } }); // Order list enyo.kind({ kind: 'OB.UI.Button', name: 'OB.UI.ButtonTab', initComponents: function () { var label; this.inherited(arguments); this.addClass('btnlink btnlink-gray'); label = this.i18nLabel ? OB.I18N.getLabel(this.i18nLabel) : this.label; if (label) { this.createComponent({ name: 'lbl', tag: 'span', content: label }); } //TODO //this.receipt.on('change:gross', function() { // this.render(); //}, this) } }); // Order list enyo.kind({ name: 'OB.UI.ToolbarButtonTab', kind: 'OB.UI.ButtonTab', events: { onTabChange: '' }, initComponents: function () { this.inherited(arguments); this.addClass('btnlink-toolbar'); } }); enyo.kind({ name: 'OB.UI.TabPane', classes: 'postab-pane', executeOnShow: function (params) { var components = this.getComponents(); if (components.length > 0) { if (this.$[components[0].getName()].executeOnShow) { this.$[components[0].getName()].executeOnShow(params); } } } }); enyo.kind({ //TODO: maxheight name: 'OB.UI.ModalAction', kind: 'OB.UI.Popup', classes: 'modal-dialog', bodyContentClass: 'modal-dialog-body-content', bodyButtonsClass: 'modal-dialog-body-buttons', components: [{ classes: 'modal-dialog-header', components: [{ name: 'headerCloseButton', classes: 'modal-dialog-header-closebutton', components: [{ tag: 'span', ontap: 'hide', allowHtml: true, content: '×' }] }, { name: 'header', classes: 'modal-dialog-header-text' }] }, { classes: 'modal-dialog-body', name: 'bodyParent', components: [{ name: 'bodyContent' }, { name: 'bodyButtons' }] }], setHeader: function (headerText) { this.$.header.setContent(headerText); }, initComponents: function () { this.inherited(arguments); if (this.i18nHeader) { this.$.header.setContent(OB.I18N.getLabel(this.i18nHeader)); } else { this.$.header.setContent(this.header); } if (this.maxheight) { this.$.bodyParent.setStyle('max-height: ' + this.maxheight + ';'); } this.$.bodyContent.setClasses(this.bodyContentClass); if (this.bodyContent && this.bodyContent.i18nContent) { this.$.bodyContent.setContent(OB.I18N.getLabel(this.bodyContent.i18nContent)); } else { this.$.bodyContent.createComponent(this.bodyContent); } this.$.bodyButtons.setClasses(this.bodyButtonsClass); this.$.bodyButtons.createComponent(this.bodyButtons); } }); enyo.kind({ //TODO: maxheight name: 'OB.UI.ActionPopup', kind: 'OB.UI.Popup', classes: 'modal-dialog', bodyContentClass: 'modal-dialog-body-content', bodyButtonsClass: 'modal-dialog-body-buttons', components: [{ classes: 'modal-dialog-header', components: [{ name: 'headerCloseButton', classes: 'modal-dialog-header-closebutton', components: [{ tag: 'span', ontap: 'hide', allowHtml: true, content: '×' }] }, { name: 'header', classes: 'modal-dialog-header-text' }] }, { classes: 'modal-dialog-body', name: 'bodyParent', components: [{ name: 'bodyContent' }, { name: 'bodyButtons' }] }], setHeader: function (headerText) { this.$.header.setContent(headerText); }, initComponents: function () { this.inherited(arguments); if (this.i18nHeader) { this.$.header.setContent(OB.I18N.getLabel(this.i18nHeader)); } else { this.$.header.setContent(this.header); } if (this.maxheight) { this.$.bodyParent.setStyle('max-height: ' + this.maxheight + ';'); } this.$.bodyContent.setClasses(this.bodyContentClass); if (this.bodyContent && this.bodyContent.i18nContent) { this.$.bodyContent.setContent(OB.I18N.getLabel(this.bodyContent.i18nContent)); } else { this.$.bodyContent.createComponent(this.bodyContent, { owner: this }); } this.$.bodyButtons.setClasses(this.bodyButtonsClass); this.$.bodyButtons.createComponent(this.bodyButtons, { owner: this }); } }); enyo.kind({ name: 'OB.UI.SearchInput', kind: 'enyo.Input', type: 'text', classes: 'input', attributes: { 'x-webkit-speech': 'x-webkit-speech' } }); enyo.kind({ name: 'OB.UI.SearchInputAutoFilter', kind: 'enyo.Input', type: 'text', classes: 'input', attributes: { 'x-webkit-speech': 'x-webkit-speech' }, events: { onFiltered: '' }, minLengthToSearch: 0, handlers: { onblur: 'blur' }, blur: function () { // blurring from input: check if it needed to set focus keeper in order // focus not to be out of an input tag // This shouldn't be done in iOS, if done the focuskeeper loses the focus if (!navigator.userAgent.match(/iPhone|iPad|iPod/i)) { OB.MobileApp.view.scanningFocus(); } }, input: function () { var temp = this.getValue(), me = this; if (temp.length >= this.minLengthToSearch || this.minLengthToSearch === 0) { setTimeout(function () { if (temp === me.getValue()) { me.doFiltered(); } }, 1000); } } }); enyo.kind({ name: 'OB.UI.ModalInfo', kind: 'OB.UI.ModalAction', bodyButtons: { components: [{ kind: 'OB.UI.AcceptDialogButton' }] }, events: { onShowPopup: '' }, closeOnAcceptButton: true, initComponents: function () { this.inherited(arguments); this.$.bodyButtons.$.acceptDialogButton.dialogContainer = this; } }); enyo.kind({ name: 'OB.UI.InfoPopup', kind: 'OB.UI.ActionPopup', bodyButtons: { components: [{ kind: 'OB.UI.AcceptDialogButton' }] }, events: { onShowPopup: '' }, closeOnAcceptButton: true, initComponents: function () { this.inherited(arguments); this.$.acceptDialogButton.dialogContainer = this; } }); enyo.kind({ name: 'OB.UI.AcceptDialogButton', kind: 'OB.UI.ModalDialogButton', classes: 'btnlink btnlink-gray modal-dialog-button', events: { onHideThisPopup: '' }, tap: function () { if (this.dialogContainer.acceptCallback) { this.dialogContainer.acceptCallback(); } if (this.dialogContainer.closeOnAcceptButton) { this.doHideThisPopup(); } }, initComponents: function () { if (this.label) { this.setContent(this.label); } else { this.setContent(OB.I18N.getLabel('OBMOBC_LblOk')); } this.inherited(arguments); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.CancelDialogButton', tap: function () { this.doHideThisPopup(); }, initComponents: function () { this.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); this.inherited(arguments); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, OB, window, navigator, alert, setTimeout */ enyo.kind({ name: 'OB.OBPOSLogin.UI.UserButton', classes: 'login-user-button', user: null, userImage: null, userConnected: null, showConnectionStatus: true, events: { onUserImgClick: '' }, components: [{ classes: 'login-user-button-bottom', components: [{ name: 'bottomIcon', classes: 'login-user-button-bottom-icon', content: ['.'] }, { name: 'bottomText', classes: 'login-user-button-bottom-text' }] }], tap: function () { this.doUserImgClick(); }, create: function () { var me = this; this.inherited(arguments); if (this.userImage && this.userImage !== 'none') { this.applyStyle('background-image', 'url(' + this.userImage + ')'); } if (!this.showConnectionStatus) { this.$.bottomIcon.hide(); } if (this.showConnectionStatus && this.userConnected === 'true') { this.$.bottomIcon.applyStyle('background-image', 'url(../org.openbravo.mobile.core/assets/img/iconOnlineUser.png)'); } if (this.showConnectionStatus && OB.MobileApp.model.get('supportsOffline')) { OB.Dal.initCache(OB.Model.User, [], null, null); OB.Dal.find(OB.Model.User, { 'name': this.user }, function (users) { var user; if (users.models.length !== 0) { user = users.models[0]; OB.Dal.find(OB.Model.Session, { 'user': user.get('id') }, function (sessions) { var session; if (sessions.models.length !== 0) { session = sessions.models[0]; if (session.get('active') === 'Y') { me.$.bottomIcon.applyStyle('background-image', 'url(../org.openbravo.mobile.core/assets/img/iconAwayUser.png)'); } else { me.$.bottomIcon.applyStyle('background-image', 'url(../org.openbravo.mobile.core/assets/img/iconOfflineUser.png)'); } } }, function () { OB.error(arguments); }); } }, function () { OB.error(arguments); }); } if (this.user) { this.$.bottomText.setContent(this.user); } } }); enyo.kind({ name: 'OB.OBPOSLogin.UI.LoginButton', kind: 'OB.UI.ModalDialogButton', style: 'min-width: 115px;', handlers: { synchronizing: 'disableButton', synchronized: 'enableButton' }, disableButton: function () { this.setDisabled(true); }, enableButton: function () { this.setDisabled(false); }, initComponents: function () { this.inherited(arguments); this.content = OB.I18N.getLabel('OBMOBC_LoginButton'); this.setDisabled(true); } }); enyo.kind({ kind: 'enyo.Ajax', name: 'OB.OBPOSLogin.UI.LoginRequest', url: '../../org.openbravo.retail.posterminal.service.loginutils', method: 'GET', handleAs: 'json', contentType: 'application/json;charset=utf-8' }); enyo.kind({ name: 'OB.OBPOSLogin.UI.Login', tag: 'section', components: [{ kind: 'OB.UI.ModalInfo', name: 'DatabaseDialog', header: 'DB version change', // TODO: OB.I18N.getLabel('OBPOS_DatabaseVersionChange'), bodyContent: { content: 'DB version change' // TODO:OB.I18N.getLabel('OBPOS_DatabaseVersionChangeLong') } }, { classes: 'login-header-row', components: [{ name: 'loginHeaderCompany', classes: 'login-header-company' }, { classes: 'login-header-caption', name: 'appCaption' }, { classes: 'login-header-ob', name: 'appName' }] }, { style: 'height: 600px', components: [{ classes: 'span6', components: [{ kind: 'Scroller', thumb: true, horizontal: 'hidden', name: 'loginUserContainer', classes: 'login-user-container', content: ['.'] }] }, { classes: 'span6', components: [{ classes: 'login-inputs-container', components: [{ name: 'loginInputs', classes: 'login-inputs-browser-compatible', components: [{ components: [{ classes: 'login-status-info', style: 'float: left;', name: 'connectStatus' }, { classes: 'login-status-info', name: 'screenLockedLbl' }] }, { components: [{ kind: 'enyo.Input', type: 'text', name: 'username', classes: 'input-login', onkeydown: 'inputKeydownHandler' }] }, { components: [{ kind: 'enyo.Input', type: 'password', name: 'password', classes: 'input-login', onkeydown: 'inputKeydownHandler' }] }, { classes: 'login-inputs-loginbutton', components: [{ kind: 'OB.OBPOSLogin.UI.LoginButton', ontap: 'loginButtonAction' }] }] }, { name: 'loginBrowserNotSupported', style: 'display: none;', components: [{ components: [{ name: 'LoginBrowserNotSupported_Title_Lbl', classes: 'login-browsernotsupported-title' }] }, { components: [{ classes: 'span8', components: [{ name: 'LoginBrowserNotSupported_P1_Lbl', classes: 'login-browsernotsupported-content' }, { name: 'LoginBrowserNotSupported_P2_Lbl', classes: 'login-browsernotsupported-content' }, { name: 'LoginBrowserNotSupported_P3_Lbl', classes: 'login-browsernotsupported-content' }] }, { classes: 'span4', style: 'padding: 78px 0px 0px 0px', components: [{ kind: 'OB.UI.Clock', classes: 'login-clock' }] }] }] }] }] }] }], setConnectedStatus: function () { var me = this; if (!this.$.connectStatus) { // don't try to set it, when it is not already built return; } OB.UTIL.checkConnectivityStatus(function () { if (me && me.$ && me.$.connectStatus) { me.$.connectStatus.setContent(OB.I18N.getLabel('OBMOBC_Online')); } }, function () { if (me && me.$ && me.$.connectStatus) { me.$.connectStatus.setContent(OB.I18N.getLabel('OBMOBC_Offline')); } }); }, initComponents: function () { this.inherited(arguments); this.$.screenLockedLbl.setContent(OB.I18N.getLabel('OBMOBC_LoginScreenLocked')); this.$.username.attributes.placeholder = OB.I18N.getLabel('OBMOBC_LoginUserInput'); this.$.password.attributes.placeholder = OB.I18N.getLabel('OBMOBC_LoginPasswordInput'); this.$.LoginBrowserNotSupported_Title_Lbl.setContent(OB.I18N.getLabel('OBMOBC_LoginBrowserNotSupported')); this.$.LoginBrowserNotSupported_P1_Lbl.setContent(OB.I18N.getLabel('OBMOBC_LoginBrowserNotSupported_P1')); this.$.LoginBrowserNotSupported_P2_Lbl.setContent(OB.I18N.getLabel('OBMOBC_LoginBrowserNotSupported_P2', ['Chrome, Safari, Safari (iOS)', 'Android'])); this.$.LoginBrowserNotSupported_P3_Lbl.setContent(OB.I18N.getLabel('OBMOBC_LoginBrowserNotSupported_P3')); this.$.appName.setContent(OB.MobileApp.model.get('appDisplayName')); this.$.appCaption.setContent(OB.appCaption || ''); this.setConnectedStatus(); OB.MobileApp.model.on('change:connectedToERP', function () { if (OB.MobileApp.model.get('supportsOffline')) { this.setConnectedStatus(); } }, this); this.postRenderActions(); }, handlers: { onUserImgClick: 'handleUserImgClick' }, handleUserImgClick: function (inSender, inEvent) { var u = inEvent.originator.user; this.$.username.setValue(u); this.$.password.setValue('openbravo'); this.$.loginButton.bubble('ontap'); return true; }, inputKeydownHandler: function (inSender, inEvent) { var keyCode = inEvent.keyCode; if (keyCode === 13) { //Handle ENTER key this.loginButtonAction(); return true; } return false; }, loginButtonAction: function () { var u = this.$.username.getValue(), p = this.$.password.getValue(); if (!u || !p) { alert('Please enter your username and password'); } else { OB.MobileApp.model.login(u, p); } }, setCompanyLogo: function (inSender, inResponse) { if (!inResponse.logoUrl) { return; } if (this.$.loginHeaderCompany) { this.$.loginHeaderCompany.applyStyle('background-image', 'url(' + inResponse.logoUrl + ')'); } return true; }, setUserImages: function (inSender, inResponse) { var name = [], userName = [], image = [], connected = [], target = this.$.loginUserContainer, me = this, jsonImgData, i; if (!target) { return; } if (!inResponse.data) { OB.Dal.find(OB.Model.User, {}, function (users) { var i, user, session; for (i = 0; i < users.models.length; i++) { user = users.models[i]; name.push(user.get('name')); userName.push(user.get('name')); connected.push(false); } me.renderUserButtons(name, userName, image, connected, target); }, function () { OB.error(arguments); }); return true; } jsonImgData = inResponse.data; enyo.forEach(jsonImgData, function (v) { name.push(v.name); userName.push(v.userName); image.push(v.image); connected.push(v.connected); }); this.renderUserButtons(name, userName, image, connected, target); }, renderUserButtons: function (name, userName, image, connected, target) { var i; for (i = 0; i < name.length; i++) { target.createComponent({ kind: 'OB.OBPOSLogin.UI.UserButton', user: userName[i], userImage: image[i], userConnected: connected[i] }); } target.render(); OB.UTIL.showLoading(false); return true; }, postRenderActions: function () { var params; OB.UTIL.showLoggingOut(false); OB.MobileApp.model.on('loginfail', function (status, data) { var msg; if (data && data.messageTitle) { msg = data.messageTitle; } if (data && data.messageText) { msg += (msg ? '\n' : '') + data.messageText; } msg = msg || 'Invalid user name or password.\nPlease try again.'; alert(msg); if (this.$.password) { this.$.password.setValue(''); } if (this.$.username) { this.$.username.focus(); } }, this); OB.MobileApp.model.on('loginUserImgPressfail', function (status) { //If the user image press (try to login with default password) fails, then no alert is shown and the focus goes directly to the password input if (this.$.password) { this.$.password.setValue(''); this.$.password.focus(); } }, this); if (!OB.UTIL.isSupportedBrowser()) { //If the browser is not supported, show message and finish. this.$.loginInputs.setStyle('display: none'); this.$.loginBrowserNotSupported.setStyle('display: block'); OB.UTIL.showLoading(false); return true; } params = OB.MobileApp.model.get('loginUtilsParams') || {}; params.appName = OB.MobileApp.model.get('appName'); params.command = 'companyLogo'; new OB.OBPOSLogin.UI.LoginRequest({ url: OB.MobileApp.model.get('loginUtilsUrl') }).response(this, 'setCompanyLogo').go(params); params.command = 'userImages'; new OB.OBPOSLogin.UI.LoginRequest({ url: OB.MobileApp.model.get('loginUtilsUrl') }).response(this, 'setUserImages').go(params); this.$.username.focus(); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B,_*/ (function () { OB = window.OB || {}; OB.UTIL = window.OB.UTIL || {}; OB.UTIL.processLogClientAll = function () { // Processes log client var me = this, criteria = {}; if (OB.MobileApp.model.get('connectedToERP')) { OB.Dal.find(OB.Model.LogClient, criteria, function (logClientsNotProcessed) { var successCallback, errorCallback, lastrecord; if (!logClientsNotProcessed || logClientsNotProcessed.length === 0) { return; } errorCallback = function () { return; }; OB.UTIL.processLogClients(logClientsNotProcessed, null, errorCallback); }); } }; OB.UTIL.processLogClientClass = 'org.openbravo.mobile.core.utils.LogClientLoader'; OB.UTIL.processLogClients = function (logClients, successCallback, errorCallback) { var logClientsToJson = []; logClients.each(function (logClient) { logClientsToJson.push(logClient.serializeToJSON()); OB.Dal.remove(logClient, null, function (tx, err) { OB.UTIL.showError(err); }); }); this.proc = new OB.DS.Process(OB.UTIL.processLogClientClass); if (OB.MobileApp.model.get('connectedToERP')) { this.proc.exec({ logclient: logClientsToJson }, function (data, message) { if (data && data.exception) { if (errorCallback) { errorCallback(); } } else { if (successCallback) { successCallback(); } } }, null, null, 4000); } }; }()); /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ * * Author RAL * */ /*global OB, console, enyo, exports, document */ /* Information about TestRegistry The content is lazy loaded so it does not consum any resources until invoqued The generated ids are unique The generated id can be seen in testeable DOM objects in the 'idtest' attribute. if you can't see them, execute TestRegistry.registry() Good practices in the enyo components for the TestRegistry to work properly are: - make sure no ids are set Concepts used: - a segment is the text in between the '_' in the DOM id. e.g: if id = 'terminal_control', the segments are 'terminal' and 'control' Troubleshooting: - if the idTest you need is not in the DOM, check if its untesteable executing printUnstableIds(). if so, change the enyo component name for a unique name or use the replacementsTable or add a parent to the enyo component - if the algorithm is no longer viable or needs a lot of changes in the algorithm, read the futureAlgorithm() function */ (function () { var root = this; var TestRegistry; if (typeof exports !== "undefined") { TestRegistry = exports; } else { TestRegistry = root.TestRegistry = {}; } TestRegistry.VERSION = "1.0.2"; console.log("TestRegistry %s is available", TestRegistry.VERSION); // add to this replacements table parts of the idDOM that will be replaced // the goal is to get generated ids without 'pointOfSale', etc; the segments of the top parent window var replacementsTable = [ // ['tbody_', ''], // ['stockDetailList_scrollListStockDetails', 'stockList'], ]; var checksTable = ["pointOfSale", "cashUp", "cashManagement"]; var minimumSegments = 2; // the minimum segments the idTest will have, if possible. if you change this number you will not be able to reference many objects that you referenced before var checkForRepeated = false; var enyoNodes = null; var testeableIdTests = null; var untesteableIdTests = null; // statistics var totalEnyoObjects = null; var nullCount = null; var enyoObjectsCount = null; var validEnyoObjects = null; var maxSegments = null; var idModifications = null; var needsTheIdToBeRemovedInEnyoComponentCreation = 0; var init = function () { enyoNodes = []; testeableIdTests = []; untesteableIdTests = []; // statistics totalEnyoObjects = 0; nullCount = 0; enyoObjectsCount = 0; validEnyoObjects = 0; maxSegments = -1; idModifications = 0; needsTheIdToBeRemovedInEnyoComponentCreation = 0; }; function EnyoNode(enyoGeneratedIdDOM, preGeneratedIdTest) { this.idDOM = enyoGeneratedIdDOM; this.enyoObject = enyo.$[enyoGeneratedIdDOM]; // this.DOMObject = document.getElementById(enyoGeneratedIdDOM); var isInNeedOfNewId = preGeneratedIdTest === undefined; var idDOMForAlgorithm = preGeneratedIdTest; var firstUniqueSegment = null; var segments = null; var idTest = null; var resetIdTest = function () { idTest = null; }; var initIdTest = function () { idTest = { chunkRemoved: null, id: null, isAlgorithmGenerated: null, isUnique: false, // true if unique, false if not isTesteable: null // true if a unit test can reference this object, false if not }; }; var checkIdTest = function () { if (idTest === null) { throw { name: "Fatal Error", message: "You must generate the idTest object first. execute getIdTest()" }; } }; var getSegments = function () { if (segments === null) { segments = idDOMForAlgorithm.split(/_/); } return segments; }; var getLastSegmentIndex = function () { return getSegments().length - 1; }; this.init = function () { if (isInNeedOfNewId) { idDOMForAlgorithm = this.idDOM; // do replacements var idWithReplacements = idDOMForAlgorithm; replacementsTable.forEach(function (element) { idWithReplacements = idWithReplacements.split(element[0]).join(element[1]); }); // just count them for stats idDOMForAlgorithm = idWithReplacements; if (this.idDOM.length !== idDOMForAlgorithm.length) { idModifications += 1; } } // initialization of some variables var segmentCount = getLastSegmentIndex(); firstUniqueSegment = segmentCount; if (segmentCount > maxSegments) { maxSegments = segmentCount; } }; this.isSegmentsLeft = function () { return firstUniqueSegment < getLastSegmentIndex(); }; this.setFirstInvertedUniqueSegment = function (invertedIndex) { if (isInNeedOfNewId) { resetIdTest(); var newFirstUniqueSegment = getLastSegmentIndex() - invertedIndex; if (newFirstUniqueSegment + minimumSegments < 0) { // this could happen if there are repeated ids in the DOM // must be handle by the caller throw { name: "Fatal Error", message: "Your are trying to set the first valid segment to a non existant segment" }; } firstUniqueSegment = newFirstUniqueSegment; } }; this.setIsUnique = function () { if (!checkIdTest) { throw { name: "Fatal Error", message: "Your are trying to set it to unique before generating it" }; } idTest.isUnique = true; }; this.getIdTest = function () { var i = 0; if (idTest === null) { initIdTest(); idTest.isAlgorithmGenerated = isInNeedOfNewId; if (isInNeedOfNewId) { var removed = ""; var id = ""; if (firstUniqueSegment === null) { throw { name: "Fatal Error", message: "The firstUniqueSegment variable must be set. Init() set an initial value so you have, most probably, broken the flow" }; } var lastSegmentIndex = getLastSegmentIndex(); for (i = 0; i < lastSegmentIndex; i++) { var segment = getSegments()[i]; if (i < firstUniqueSegment) { removed += segment + "_"; } else { id += segment + "_"; } } idTest.chunkRemoved = removed; idTest.id = id + getSegments()[lastSegmentIndex]; } else { idTest.chunkRemoved = ""; idTest.id = idDOMForAlgorithm; } } return idTest; }; this.toString = function () { var idTest = this.getIdTest(); if (idTest.isTesteable) { return "idDOM:\t\t" + this.idDOM + " =>\n\tidTest:\t'" + idTest.id + "'"; } return "idDOM:\t\t" + this.idDOM + " =>\n\tidTest:\t'" + idTest.chunkRemoved + "' / '" + idTest.id + "'" + (idTest.isTesteable ? "" : " (*)"); }; this.isEqual = function (to) { return this.getIdTest().id === to.getIdTest().id; }; /** * Checks for untesteable string chunks in the id */ this.isValidForUnitTesting = function () { checkIdTest(); var isNumeric = function (s) { return !isNaN(s); }; var isTesteable = true; var incompatibleString = null; var idTest = this.getIdTest(); if (idTest.isUnique) { var id = idTest.id; checksTable.forEach(function (element) { var index = id.indexOf(element); if (index >= 0) { var nextChar = id.charAt(index + element.length); if (nextChar === "_" || isNumeric(nextChar)) { isTesteable = false; incompatibleString = element; return; } } }); } else { isTesteable = false; incompatibleString = "not unique"; } idTest.isTesteable = isTesteable; return { isTesteable: idTest.isTesteable, incompatibleString: incompatibleString }; }; this.init(); } function scan() { /** * get all enyo objects in the webpage, check that they are valid and have a findable DOM id */ init(); var addNode = function (id, idTest) { totalEnyoObjects += 1; enyoObjectsCount += 1; if (enyo.$[id] === null) { nullCount += 1; return; } if (!document.getElementById(id)) { return; } if (id.indexOf('OB.UI.id') >= 0 || id.indexOf('org.openbravo') >= 0) { needsTheIdToBeRemovedInEnyoComponentCreation += 1; return; } validEnyoObjects += 1; enyoNodes.push(new EnyoNode(id, idTest)); }; // generate ids for tables var enyoRoot = enyo.$.terminal; var count = 0; var recurseLi; recurseLi = function (enyoParent, tablePrefix, liIndex) { count += 1; if (enyoParent.children.length === 0) { return; } enyoParent.children.forEach(function (element) { addNode(element.id, tablePrefix + "_row" + liIndex + "_" + element.name); recurseLi(element, tablePrefix, liIndex); }); }; var recurseTable; recurseTable = function (enyoParent, tablePrefix, liIndex) { count += 1; if (enyoParent.children.length === 0) { return; } enyoParent.children.forEach(function (element) { if (element.tag === "li") { liIndex += 1; addNode(element.id, tablePrefix + "_row" + liIndex); recurseLi(element, tablePrefix, liIndex); } else { addNode(element.id, tablePrefix + "_" + element.name); recurseTable(element, tablePrefix, liIndex); } }); }; var getChildren; getChildren = function (enyoParent) { count += 1; if (enyoParent.children.length === 0) { return; } enyoParent.children.forEach(function (element) { if (element.kind && (typeof (element.kind) !== "function") && (element.kind.indexOf("OB.UI.Table") === 0 || element.kind.indexOf("OB.UI.ScrollableTable") === 0)) { addNode(element.id, "table_" + element.name); recurseTable(element, element.name, 0); } else { addNode(element.id); getChildren(element); } }); }; getChildren(enyoRoot); // build the list of objects to compute with the algorithm var enyoNodesToProcess = []; enyoNodes.forEach(function (element, index) { enyoNodesToProcess.push(index); }); var segmentIndex = minimumSegments - 1; var loops = 0; /** * This is the algorithm to infere ids */ while (enyoNodesToProcess.length > 0) { // create the array of segments of the segmentIndex segment var segmentsToProcess = []; var nodeToProcessIndex; for (nodeToProcessIndex in enyoNodesToProcess) { if (enyoNodesToProcess.hasOwnProperty(nodeToProcessIndex)) { var nodeIndex = enyoNodesToProcess[nodeToProcessIndex]; var enyoNode2 = enyoNodes[nodeIndex]; if (!enyoNode2.isSegmentsLeft) { continue; } enyoNode2.setFirstInvertedUniqueSegment(segmentIndex); var tail = enyoNode2.getIdTest().id; var isFound = false; var segmentToProcessIndex; for (segmentToProcessIndex = 0; segmentToProcessIndex < segmentsToProcess.length; segmentToProcessIndex++) { var segmentToProcess = segmentsToProcess[segmentToProcessIndex]; var segmentNameToCompare = segmentToProcess.tail; if (tail === segmentNameToCompare) { segmentToProcess.enyoNodeToProcessNodeIndex = null; segmentToProcess.enyoNode = null; segmentToProcess.count += 1; isFound = true; break; } } if (!isFound) { var segmentToProcess2 = { tail: tail, count: 1, enyoNodeToProcessNodeIndex: nodeIndex, // this is only used when its unique enyoNode: enyoNode2 // this is only used when its unique }; segmentsToProcess.push(segmentToProcess2); } } } // set uniques as ready // create the exclude table var j; for (j = 0; j < segmentsToProcess.length; j++) { var segmentToProcess3 = segmentsToProcess[j]; if (segmentToProcess3.count === 1) { segmentToProcess3.enyoNode.setIsUnique(); var nodeIndexToRemove = enyoNodesToProcess.indexOf(segmentToProcess3.enyoNodeToProcessNodeIndex++); enyoNodesToProcess.splice(nodeIndexToRemove, 1); } } // check that the algorithm is not in an infinite loop // discard the remaining ids if (loops >= maxSegments) { enyoNodesToProcess = []; // OB.info("IMPOSIBLE TO GENERATE THIS IDs"); // for (j = 0; j < enyoNodesToProcess; j++) { // var nodeIndex3 = enyoNodesToProcess[j]; // var enyoNode4 = enyoNodes[nodeIndex3]; // OB.info(enyoNode4.toString()); // } // throw { // name: "Fatal Error", // message: "Infinite loop" // }; } loops += 1; segmentIndex += 1; } /** * this could be used to refactor the algorithm * and make it, probably, faster and more readeable * idea: if we build a sorted list of reversed strings, we could get the same result cycling through the chars of the list and check when the char changes * its the same idea as the actual one, but simplified */ // var futureAlgorith = function () { // var sortedIdList = []; // var k; // for (k = 0; k < enyoNodes.length; k++) { // var id2 = enyoNodes[k].getIdTest().id; // id2 = id2.split("").reverse().join(""); // sortedIdList.push(id2); // } // sortedIdList.sort(); // var sortedIdIndex; // for (sortedIdIndex = 0; sortedIdIndex < sortedIdList.length; sortedIdIndex++) { // OB.info(sortedIdList[sortedIdIndex]); // } // }; // check if the EnyoNode is testeable and save the state var o; for (o = 0; o < enyoNodes.length; o++) { var id = enyoNodes[o].getIdTest().id; if (enyoNodes[o].isValidForUnitTesting().isTesteable) { testeableIdTests.push(id); } else { untesteableIdTests.push({ enyoNodeIndex: o, incompatibleStringDetected: enyoNodes[o].isValidForUnitTesting().incompatibleString, id: id }); } } // create the list of untesteable objects and remove them from the final enyoNodes list if (untesteableIdTests.length > 0) { OB.info("found %s ids of %s that are not valid for unit tests. execute printUntesteableIds() to get the list\n", untesteableIdTests.length, validEnyoObjects); untesteableIdTests.sort(function (a, b) { if (a.incompatibleStringDetected !== b.incompatibleStringDetected) { a.incompatibleStringDetected.localeCompare(b.incompatibleStringDetected); } return a.id.localeCompare(b.id); }); var enyoNodesToRemove = []; var notValidForUnitTestIndex; for (notValidForUnitTestIndex = 0; notValidForUnitTestIndex < untesteableIdTests.length; notValidForUnitTestIndex++) { var notValidForUnitTestRow = untesteableIdTests[notValidForUnitTestIndex]; enyoNodesToRemove.push(notValidForUnitTestRow.enyoNodeIndex); } enyoNodesToRemove.sort(function (a, b) { return a - b; }); enyoNodesToRemove.reverse(); var enyoNodeToRemoveIndex; for (enyoNodeToRemoveIndex = 0; enyoNodeToRemoveIndex < enyoNodesToRemove.length; enyoNodeToRemoveIndex++) { enyoNodes.splice(enyoNodesToRemove[enyoNodeToRemoveIndex], 1); } } // check if all the generated ids are unique. this is not needed as the actual flow can't reach this point if there is a single repeated id if (checkForRepeated) { OB.info(""); OB.info("Checking uniqueness..."); var isRepeated = false; var i; for (i = 0; i < enyoNodes.length; i++) { var enyoNode6 = enyoNodes[i]; var idTest = enyoNode6.getIdTest(); if (!idTest.isUnique) { OB.info("REPEATED:\n\t%s\n\t%s", enyoNode6.toString()); isRepeated = true; } } if (isRepeated) { throw { name: "Error", message: "all ids must be unique" }; } else { OB.info("all the ids are unique"); } } } function getList() { // 'lazy load' function that contains all the enyo objects in the webpage if (enyoNodes === null) { OB.info("lazy loading..."); scan(); OB.info("totalObjects: %s, enyoObjects: %s, nullCount: %s, enyo ids to change: %s, validObjects: %s, id modifications: %s, maxSegments: %s\n", totalEnyoObjects, enyoObjectsCount, nullCount, needsTheIdToBeRemovedInEnyoComponentCreation, validEnyoObjects, idModifications, maxSegments); OB.info("... lazy load complete"); } return enyoNodes; } function findWhere(idTest) { // finds the register with the specified idTest var list = getList(); var enyoNode = null; list.some(function (element) { if (element.getIdTest().id === idTest) { enyoNode = element; return; } }); if (enyoNode !== null) { // check if the DOM changed since the last scan var DOMObject = document.getElementById(enyoNode.idDOM); if (DOMObject) { return enyoNode; } } return null; } TestRegistry.help = function () { OB.info("List of TestRegistry properties:"); var publicProperties = Object.getOwnPropertyNames(this); publicProperties.sort(); publicProperties.forEach(function (element) { OB.info(" - " + element); }); }; TestRegistry.printTesteableIds = function () { getList(); OB.info("final list of ids:"); testeableIdTests.sort(function (a, b) { if (a === b) { a.localeCompare(b); } return a.localeCompare(b); }); var index; for (index = 0; index < testeableIdTests.length; index++) { OB.info(testeableIdTests[index]); } OB.info("Total testeable ids: %s\n", testeableIdTests.length); }; TestRegistry.printUntesteableIds = function () { getList(); var index; for (index = 0; index < untesteableIdTests.length; index++) { var notValidForUnitTestRow = untesteableIdTests[index]; OB.info("'%s' in '%s'", notValidForUnitTestRow.incompatibleStringDetected, notValidForUnitTestRow.id); } OB.info("Total untesteable ids: %s\n", untesteableIdTests.length); }; // TestRegistry.findById = function(idDOM) { // // finds the registered object with a DOM id // var list = getList(); // var found = null; // list.some(function(element, index, array) { // if (element.idDOM == idDOM) { // found = element; // return true; // } // }); // return found; // }; /** * Returns the EnyoNode that has the provided idTest * @param {string} idTest the idTest as shown in the DOM * @param {boolean} silent an error will not be shown in the console (added for better test logs) * @return {EnyoNode} the EnyoNode if found */ TestRegistry.registry = function (idTest, silent) { var enyoNode = null; var rescan = true; if (enyoNodes === null) { rescan = false; } enyoNode = findWhere(idTest); if (enyoNode === null && rescan) { scan(); enyoNode = findWhere(idTest); } if (enyoNode !== null) { return enyoNode; } if (!silent) { OB.error("Cannot find any object with idTest = '" + idTest + "'"); } return null; }; TestRegistry.appendIdTestToDOM = function () { scan(); // append the idTest attribute to the DOM objects var attributeAppendErrors = 0; OB.info("adding idTests to the DOM"); var enyoNodesIndex; for (enyoNodesIndex = 0; enyoNodesIndex < enyoNodes.length; enyoNodesIndex++) { var enyoNode3 = enyoNodes[enyoNodesIndex]; var idTest2 = enyoNode3.getIdTest(); if (idTest2.isTesteable && idTest2.isUnique) { var DOMnode = document.getElementById(enyoNode3.idDOM); if (DOMnode) { DOMnode.setAttribute("idtest", idTest2.id); } else { attributeAppendErrors += 1; OB.info(enyoNode3.idDOM, enyoNode3); } } } if (attributeAppendErrors > 0) { OB.info("DOM append errors: %s\n", attributeAppendErrors); } }; }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, console, _ */ OB = window.OB || {}; OB.UTIL = window.OB.UTIL || {}; enyo.kind({ name: 'OB.UI.Thumbnail', published: { img: null, imgUrl: null }, tag: 'div', classes: 'image-wrap', contentType: 'image/png', width: '49px', height: '49px', 'default': '../org.openbravo.mobile.core/assets/img/box.png', components: [{ tag: 'div', name: 'image', style: 'margin: auto; height: 100%; width: 100%; background-size: contain;' }], initComponents: function () { this.inherited(arguments); this.applyStyle('height', this.height); this.applyStyle('width', this.width); this.imgChanged(); }, drawImage: function () { var url; if (this.img || this.imgUrl) { if (this.img === 'iconBestSellers') { url = 'img/iconBestSellers.png'; } else if (this.img) { url = 'data:' + this.contentType + ';base64,' + this.img; } else if (this.imgUrl) { url = this.imgUrl; } } else { url = this['default']; } this.$.image.applyStyle('background', '#ffffff url(' + url + ') center center no-repeat'); this.$.image.applyStyle('background-size', 'contain'); }, imgChanged: function () { this.drawImage(); }, imgUrlChanged: function () { this.drawImage(); } }); enyo.kind({ name: 'OB.UTIL.showAlert', classes: 'alert alert-fade', style: 'right:0; top:0; padding:2px; margin:0; cursor:pointer; border:0;', tap: function () { this.hide(); }, statics: { /** * Adds a new message to the bubble of messages * @param {[type]} txt the message to be shown * @param {[type]} title the title (deprecated) * @param {[type]} type alert-success, alert-warning, alert-error * @param {[type]} keepVisible false: the message will be hiden after some time. true: you will execute the hide() function of the returned object when the line must dissapear * @param {[type]} idMessage a unique identifier for this message * @param {[type]} hidesIdMessage destroys any message present in the bubble of messages with this id * @return {[type]} the OB.UTIL.alertLine created and added to the bubble of messages */ display: function (txt, title, type, keepVisible, idMessage, hidesIdMessage) { if (!type) { type = 'alert-warning'; } var componentsArray = OB.MobileApp.view.$.alertQueue.getComponents(), i; // iterate the existing messages in the bubble for (i = 0; i < componentsArray.length; i++) { var element = componentsArray[i]; // if this message hides another idMessage, destroy that message if (element.idMessage === hidesIdMessage) { element.destroy(); continue; } // we don't want to annoy the user... do not repeat error and warning messages in the bubble if (type === 'alert-warning' || type === 'alert-error') { if (element.txt === txt) { element.destroy(); } } } // add a new line to the bubble of messages OB.MobileApp.view.$.alertQueue.show(); var alertLine = OB.MobileApp.view.$.alertQueue.createComponent({ kind: 'OB.UTIL.alertLine', title: title, txt: txt, type: type, keepVisible: keepVisible, idMessage: idMessage }).render(); OB.UTIL.showAlert.showOrHideMessagesBubble(); return alertLine; }, showOrHideMessagesBubble: function () { var componentsArray = OB.MobileApp.view.$.alertQueue.getComponents(); if (componentsArray.length === 0) { OB.MobileApp.view.$.alertQueue.removeClass('alert-fade-in'); } else { OB.MobileApp.view.$.alertQueue.addClass('alert-fade-in'); } } } }); enyo.kind({ name: 'OB.UTIL.alertLine', classes: '', style: 'padding:2px;', components: [{ name: 'title', style: 'display:none; float: left; margin-right:10px;' // hiden because is obvious info but still there for future use }, { name: 'txt' }], initComponents: function () { var me = this, destroyTimeout; this.inherited(arguments); this.$.title.setContent(this.title); this.$.txt.setContent(this.txt); this.addClass(this.type); // Define the timeout of the message. These values should be moved taken from global settings switch (this.type) { case 'alert-success': destroyTimeout = 2000; break; case 'alert-warning': destroyTimeout = 2000; break; case 'alert-error': destroyTimeout = 4000; break; default: OB.error("DEVELOPER: The message of type '" + this.type + "' needs more code to be processed"); } if (!this.keepVisible) { setTimeout(function () { me.hide(); OB.UTIL.showAlert.showOrHideMessagesBubble(); }, destroyTimeout); } }, /** * Hides this particular message of the bubble of messages * @return undefined */ hide: function () { this.destroy(); } }); /** * Shows a confirmation box. * * arguments: * title: string with the title of the dialog * text: string with the text of the dialog * buttons: (optional) array of buttons. If this parameter is not present, * a OK button will be shown, clicking on it will just close the * confirmation dialog box. * Each button in the array should have these attributes: * label: text to be shown within the button * action: (optional) function to be executed when the button * is tapped. If this attribute is not specified, the * action will be just to close the popup. * options: (optional) array of options. * - options.autoDismiss // if true, any click outside the popup, closes it; if false, it behaves as if it was modal * - options.onHideFunction: function () {} // to be executed when the popup is closed with the close (X) button * - options.style * */ enyo.kind({ name: 'OB.UTIL.showConfirmation', statics: { display: function (title, text, buttons, options) { var container = OB.MobileApp.view.$.confirmationContainer, components = container.getComponents(), i, dialog; function getDialog() { // Allow display in a confirmation message a literal or a list of components var bodyContent; if (Array.isArray(text)) { bodyContent = { kind: 'enyo.Control', components: text }; } else { bodyContent = { kind: 'enyo.Control', content: text }; } var box = { kind: 'OB.UI.ModalAction', name: 'dynamicConfirmationPopup', header: title, bodyContent: bodyContent, autoDismiss: !OB.UTIL.isNullOrUndefined(options) && !OB.UTIL.isNullOrUndefined(options.autoDismiss) ? options.autoDismiss : true, executeOnShow: function () { if (options && options.onShowFunction) { options.onShowFunction(this); } return true; }, executeOnHide: function () { //the hide function only will be executed when //a button without action is used or when popup //is closed using background or x button if (options && !this.args.actionExecuted && options.onHideFunction) { options.onHideFunction(this); } return true; }, bodyButtons: {} }; if (options && options.style) { box.style = options.style; } //Test if (options && options.confirmFunction) { box.confirm = options.confirmFunction; } if (!buttons) { box.bodyButtons = { kind: 'OB.UI.ModalDialogButton', name: 'confirmationPopup_btnOk', content: OB.I18N.getLabel('OBMOBC_LblOk'), tap: function () { this.doHideThisPopup(); } }; box.confirm = function () { if (this.$.bodyButtons.$.confirmationPopup_btnOk) { this.$.bodyButtons.$.confirmationPopup_btnOk.tap(); } }; } else { box.bodyButtons.components = []; _.forEach(buttons, function (btn) { var componentName; if (btn && btn.name) { componentName = btn.name; } else { componentName = 'confirmationPopup_btn' + btn.label; } var button = { kind: 'OB.UI.ModalDialogButton', name: componentName, content: btn.label, tap: function () { var params = { actionExecuted: false }; if (btn.action) { params.actionExecuted = true; btn.action(); } this.doHideThisPopup({ args: params }); } }; box.bodyButtons.components.push(button); if (btn.isConfirmButton) { box.confirm = function () { this.$.bodyButtons.$[button.name].tap(); }; } }, this); } return box; } // remove old confirmation box for (i = 0; i < components.length; i++) { components[i].destroy(); } dialog = OB.MobileApp.view.$.confirmationContainer.createComponent(getDialog()); dialog.show(); OB.UTIL.showLoading(false); } } }); OB.UTIL.isSupportedBrowser = function () { if (navigator.userAgent.toLowerCase().indexOf('webkit') !== -1 && window.openDatabase) { // If the browser is not supported, show // message and finish. return true; } else { return false; } }; OB.UTIL.showLoading = function (value) { if (value) { OB.MobileApp.view.$.containerWindow.hide(); OB.MobileApp.view.$.containerLoading.show(); } else { if (!OB.UTIL.isNullOrUndefined(OB.MobileApp.view)) { OB.MobileApp.view.$.containerLoading.hide(); OB.MobileApp.view.$.containerWindow.show(); } } }; OB.UTIL.showLoggingOut = function (value) { if (value) { OB.MobileApp.view.$.containerWindow.hide(); OB.MobileApp.view.$.containerLoggingOut.show(); } else { OB.MobileApp.view.$.containerLoggingOut.hide(); OB.MobileApp.view.$.containerWindow.show(); } }; OB.UTIL.showLoggingOut = function (value) { if (value) { OB.MobileApp.view.$.containerWindow.hide(); OB.MobileApp.view.$.containerLoggingOut.show(); } else { OB.MobileApp.view.$.containerLoggingOut.hide(); OB.MobileApp.view.$.containerWindow.show(); } }; OB.UTIL.showLoggingOut = function (value) { if (value) { OB.MobileApp.view.$.containerWindow.hide(); OB.MobileApp.view.$.containerLoggingOut.show(); } else { OB.MobileApp.view.$.containerLoggingOut.hide(); OB.MobileApp.view.$.containerWindow.show(); } }; OB.UTIL.showSuccess = function (s) { return OB.UTIL.showAlert.display(s, OB.I18N.getLabel('OBMOBC_LblSuccess'), 'alert-success'); }; OB.UTIL.showWarning = function (s) { return OB.UTIL.showAlert.display(s, OB.I18N.getLabel('OBMOBC_LblWarning'), 'alert-warning'); }; OB.UTIL.showStatus = function (s) { return OB.UTIL.showAlert.display(s, 'Wait', ''); }; OB.UTIL.showError = function (s) { OB.UTIL.showLoading(false); return OB.UTIL.showAlert.display(s, OB.I18N.getLabel('OBMOBC_LblError'), 'alert-error'); }; /** * Shows a success type message in the bubble of messages * @param string idLabel the id of the label to be shown * @param string hidesIdLabel the id of the message to be destroyed when this new message is shown. leave empty fo no effect */ OB.UTIL.showI18NSuccess = function (idLabel, hidesIdLabel) { return OB.UTIL.showAlert.display(OB.I18N.getLabel(idLabel), OB.I18N.getLabel('OBMOBC_LblSuccess'), 'alert-success', false, idLabel, hidesIdLabel); }; /** * Shows a warning type message in the bubble of messages * @param string idLabel the id of the label to be shown * @param string hidesIdLabel the id of the message to be destroyed when this new message is shown. leave empty fo no effect */ OB.UTIL.showI18NWarning = function (idLabel, hidesIdLabel) { return OB.UTIL.showAlert.display(OB.I18N.getLabel(idLabel), OB.I18N.getLabel('OBMOBC_LblWarning'), 'alert-warning', false, idLabel, hidesIdLabel); }; // This funtion returns an array of Enyo components (the object and its // children) sorted // in the same way it they are rendered in the html OB.UTIL.getAllChildsSorted = function (component, result) { var i; if (Object.prototype.toString.call(component) !== '[object Array]') { component = [component]; } if (!result) { result = []; } for (i = 0; i < component.length; i++) { result.push(component[i]); if (typeof component[i].children !== 'undefined' && component[i].children.length !== 0) { result = OB.UTIL.getAllChildsSorted(component[i].children, result); } } return result; }; /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, _, console */ (function () { OB = window.OB || {}; OB.DEC = window.OB.DEC || {}; var scale = 2; var roundingmode = BigDecimal.prototype.ROUND_HALF_UP; var toBigDecimal = function (a) { return new BigDecimal(a.toString()); }; var toNumber = function (big, arg_scale) { var localscale = arg_scale || scale; if (big.scale) { return parseFloat(big.setScale(localscale, roundingmode).toString(), 10); } else { if (_.isNumber(big)) { return big; } else { OB.error("toNumber: Argument cannot be converted toNumber", big); } } }; OB.DEC.Zero = toNumber(BigDecimal.prototype.ZERO); OB.DEC.One = toNumber(BigDecimal.prototype.ONE); OB.DEC.getScale = function () { return scale; }; OB.DEC.getRoundingMode = function () { return roundingmode; }; OB.DEC.isNumber = function (a) { return typeof (a) === 'number' && !isNaN(a); }; OB.DEC.add = function (a, b, arg_scale) { return toNumber(toBigDecimal(a).add(toBigDecimal(b)), arg_scale); }; OB.DEC.sub = function (a, b, arg_scale) { return toNumber(toBigDecimal(a).subtract(toBigDecimal(b)), arg_scale); }; OB.DEC.mul = function (a, b, arg_scale) { return toNumber(toBigDecimal(a).multiply(toBigDecimal(b)), arg_scale); }; OB.DEC.div = function (a, b, arg_scale) { return toNumber(toBigDecimal(a).divide(toBigDecimal(b), scale, roundingmode), arg_scale); }; OB.DEC.compare = function (a) { return toBigDecimal(a).compareTo(BigDecimal.prototype.ZERO); }; OB.DEC.number = function (jsnumber) { return jsnumber; // toNumber(toBigDecimal(jsnumber)); }; OB.DEC.setContext = function (s, r) { scale = s; roundingmode = r; }; OB.DEC.toBigDecimal = function (a) { return toBigDecimal(a); }; OB.DEC.toNumber = function (a, arg_scale) { return toNumber(a, arg_scale); }; OB.DEC.abs = function (a, arg_scale) { return toNumber(toBigDecimal(a).abs(), arg_scale); }; }()); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, console, Backbone, $, _, enyo, OB, window, navigator */ (function () { OB.UTIL = window.OB.UTIL || {}; OB.UTIL.getParameterByName = function (name) { var n = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regexS = '[\\?&]' + n + '=([^&#]*)'; var regex = new RegExp(regexS); var results = regex.exec(window.location.search); return (results) ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : ''; }; OB.UTIL.escapeRegExp = function (text) { return text.replace(/[\-\[\]{}()+?.,\\\^$|#\s]/g, '\\$&'); }; function S4() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1).toUpperCase(); } OB.UTIL.get_UUID = function () { return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4()); }; OB.UTIL.padNumber = function (n, p) { var s = n.toString(); while (s.length < p) { s = '0' + s; } return s; }; OB.UTIL.encodeXMLComponent = function (s, title, type) { return s.replace(/\&/g, '&').replace(//g, '>').replace(/\'/g, ''').replace(/\"/g, '"'); }; OB.UTIL.decodeXMLComponent = function (s) { return s.replace(/\&\;/g, '&').replace(/\<\;/g, '<').replace(/\>\;/g, '>').replace(/\&apos\;/g, '\'').replace(/\"\;/g, '\"'); }; /** * Prepares multi line string to be printed with HW Manager format */ OB.UTIL.encodeXMLMultiLineComponent = function (str, width) { var startBlock = '', endBlock = '\n', lines = str.split('\n'), l, line, result = ''; for (l = 0; l < lines.length; l++) { line = lines[l].trim(); if (width && line.length > width) { result += OB.UTIL.encodeXMLMultiLineComponent(OB.UTIL.wordwrap(line, width)); } else { result += startBlock + OB.UTIL.encodeXMLComponent(line) + endBlock; } } return result; }; /** * Wraps words in several lines with width length */ OB.UTIL.wordwrap = function (str, width) { if (!str || !width) { return str; } return str.match(RegExp('.{1,' + width + '}(\\s|$)|\\S+?(\\s|$)', 'g')).join('\n'); }; OB.UTIL.loadResource = function (res, callback, context) { var ajaxRequest = new enyo.Ajax({ url: res, cacheBust: false, method: 'GET', handleAs: 'text', contentType: 'application/x-www-form-urlencoded; charset=UTF-8', success: function (inSender, inResponse) { callback.call(context || this, inResponse); }, fail: function (inSender, inResponse) { callback.call(context || this); } }); ajaxRequest.go().response('success').error('fail'); }; OB.UTIL.queueStatus = function (queue) { // Expects an object where the value element is true/false depending if is processed or not if (!_.isObject(queue)) { throw 'Object expected'; } return _.reduce(queue, function (memo, val) { return memo && val; }, true); }; OB.UTIL.checkContextChange = function (oldContext, newContext, successCallback) { if (newContext.userId !== oldContext.user.id || newContext.orgId !== oldContext.organization.id || newContext.clientId !== oldContext.client.id || newContext.roleId !== oldContext.role.id) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBMOBC_ContextChanged'), OB.I18N.getLabel('OBMOBC_ContextChangedMessage'), [{ isConfirmButton: true, label: OB.I18N.getLabel('OBMOBC_LblOk'), action: function () { OB.POS.modelterminal.lock(); return true; } }]); } else { if (successCallback) { successCallback(); } } }; OB.UTIL.checkConnectivityStatus = function (connectedCallback, notConnectedCallback) { var ajaxParams, currentlyConnected = OB.MobileApp.model.get('connectedToERP'); var oldContext = OB.MobileApp.model.get('context'); if (currentlyConnected && oldContext) { new OB.DS.Request('org.openbravo.mobile.core.login.ContextInformation').exec({ terminal: OB.MobileApp.model.get('terminalName'), ignoreForConnectionStatus: true }, function (data) { var newContext; if (data && data.exception) { OB.MobileApp.model.lock(); } if (data[0]) { newContext = data[0]; OB.UTIL.checkContextChange(oldContext, newContext, connectedCallback); } }, function () { if (OB.MobileApp.model && OB.MobileApp.model.get('connectedToERP')) { OB.MobileApp.model.triggerOffLine(); } if (notConnectedCallback) { notConnectedCallback(); } }); return; } else if (navigator.onLine) { // It can be a false positive, make sure with the ping var ajaxRequest = new enyo.Ajax({ url: '../../security/SessionActive?id=0', cacheBust: true, timeout: 5000, method: 'GET', handleAs: 'json', contentType: 'application/x-www-form-urlencoded; charset=UTF-8', success: function (inSender, inResponse) { if (currentlyConnected !== true) { if (OB.MobileApp.model) { OB.MobileApp.model.triggerOnLine(); } } if (connectedCallback) { connectedCallback(); } }, fail: function (inSender, inResponse) { if (currentlyConnected !== false) { if (OB.MobileApp.model) { OB.MobileApp.model.triggerOffLine(); } } if (notConnectedCallback) { notConnectedCallback(); } } }); ajaxRequest.go().response('success').error('fail'); } else { if (currentlyConnected) { if (OB.MobileApp.model) { OB.MobileApp.model.triggerOffLine(); } } } }; OB.UTIL.updateDocumentSequenceInDB = function (documentNo) { var docSeqModel, criteria = { 'posSearchKey': OB.MobileApp.model.get('terminal').searchKey }; OB.Dal.find(OB.Model.DocumentSequence, criteria, function (documentSequenceList) { var posDocumentNoPrefix = OB.MobileApp.model.get('terminal').docNoPrefix, orderDocumentSequence = parseInt(documentNo.substr(posDocumentNoPrefix.length + 1), 10) + 1, docSeqModel; if (documentSequenceList && documentSequenceList.length !== 0) { docSeqModel = documentSequenceList.at(0); if (orderDocumentSequence > docSeqModel.get('documentSequence')) { docSeqModel.set('documentSequence', orderDocumentSequence); } } else { docSeqModel = new OB.Model.DocumentSequence(); docSeqModel.set('posSearchKey', OB.MobileApp.model.get('terminal').searchKey); docSeqModel.set('documentSequence', orderDocumentSequence); } OB.Dal.save(docSeqModel, null, null); }); }; OB.UTIL.isWritableOrganization = function (orgId) { if (OB.MobileApp.model.get('writableOrganizations')) { var result = false; result = _.find(OB.MobileApp.model.get('writableOrganizations'), function (curOrg) { if (orgId === curOrg) { return true; } }); if (result) { return true; } else { return false; } } else { return false; } }; OB.UTIL.getCharacteristicValues = function (characteristicDescripcion) { var ch_desc = ''; _.each(characteristicDescripcion.split(','), function (character, index, collection) { ch_desc = ch_desc + character.substring(character.indexOf(':') + 2); if (index !== collection.length - 1) { ch_desc = ch_desc + ', '; } }, this); return ch_desc; }; //Returns true if the value is null or undefined OB.UTIL.isNullOrUndefined = function (value) { if (_.isNull(value) || _.isUndefined(value)) { return true; } return false; }; //Returns the first Not null and not undefined value. //Can be used in the same way as we use a = b || c; But using this function 0 will be a valid value for b OB.UTIL.getFirstValidValue = function (valuesToCheck) { var valueToReturn = _.find(valuesToCheck, function (value) { if (!OB.UTIL.isNullOrUndefined(value)) { return true; } }); return valueToReturn; }; OB.trace = function () { try { if (OB.UTIL.checkPermissionLog("Trace", "save") || OB.UTIL.checkPermissionLog("Trace", "console")) { var msg = OB.UTIL.composeMessage(arguments); if (OB.UTIL.checkPermissionLog("Trace", "save")) { OB.UTIL.saveLogClient(msg, "Trace"); } if (OB.UTIL.checkPermissionLog("Trace", "console")) { console.log.apply(console, OB.UTIL.argumentsWithLink(arguments)); } } } catch (e) { console.log.apply(console, arguments); } }; OB.debug = function () { try { if (OB.UTIL.checkPermissionLog("Debug", "save") || OB.UTIL.checkPermissionLog("Debug", "console")) { var msg = OB.UTIL.composeMessage(arguments); if (OB.UTIL.checkPermissionLog("Debug", "save")) { OB.UTIL.saveLogClient(msg, "Debug"); } if (OB.UTIL.checkPermissionLog("Debug", "console")) { console.log.apply(console, OB.UTIL.argumentsWithLink(arguments)); } } } catch (e) { console.log.apply(console, arguments); } }; OB.info = function () { try { if (OB.UTIL.checkPermissionLog("Info", "save") || OB.UTIL.checkPermissionLog("Info", "console")) { var msg = OB.UTIL.composeMessage(arguments); if (OB.UTIL.checkPermissionLog("Info", "save")) { OB.UTIL.saveLogClient(msg, "Info"); } if (OB.UTIL.checkPermissionLog("Info", "console")) { console.info.apply(console, OB.UTIL.argumentsWithLink(arguments)); } } } catch (e) { console.info.apply(console, arguments); } }; OB.warn = function () { try { if (OB.UTIL.checkPermissionLog("Warn", "save") || OB.UTIL.checkPermissionLog("Warn", "console")) { var msg = OB.UTIL.composeMessage(arguments); if (OB.UTIL.checkPermissionLog("Warn", "save")) { OB.UTIL.saveLogClient(msg, "Warn"); } if (OB.UTIL.checkPermissionLog("Warn", "console")) { console.warn.apply(console, OB.UTIL.argumentsWithLink(arguments)); } } } catch (e) { console.warn.apply(console, arguments); } }; OB.error = function () { try { if (OB.UTIL.checkPermissionLog("Error", "save") || OB.UTIL.checkPermissionLog("Error", "console")) { var msg = OB.UTIL.composeMessage(arguments); if (OB.UTIL.checkPermissionLog("Error", "save")) { OB.UTIL.saveLogClient(msg, "Error"); } if (OB.UTIL.checkPermissionLog("Error", "console")) { console.error.apply(console, OB.UTIL.argumentsWithLink(arguments)); } } } catch (e) { console.error.apply(console, arguments); } }; OB.critical = function () { try { if (OB.UTIL.checkPermissionLog("Critical", "save") || OB.UTIL.checkPermissionLog("Critical", "console")) { var msg = OB.UTIL.composeMessage(arguments); if (OB.UTIL.checkPermissionLog("Critical", "save")) { OB.UTIL.saveLogClient(msg, "Critical"); } if (OB.UTIL.checkPermissionLog("Critical", "console")) { console.error.apply(console, OB.UTIL.argumentsWithLink(arguments)); } } } catch (e) { console.error.apply(console, arguments); } }; // this function receive as arguments first the level of log, the rest of the arguments are the message OB.log = function () { var level, argsWithoutFirst, i, msg; try { level = arguments[0]; argsWithoutFirst = []; for (i = 1; i < arguments.length; i++) { argsWithoutFirst[i - 1] = arguments[i]; } msg = OB.UTIL.composeMessage(argsWithoutFirst); if (OB.UTIL.checkPermissionLog(level, "save")) { OB.UTIL.saveLogClient(msg, level); } if (OB.UTIL.checkPermissionLog(level, "console")) { if (level === "Info") { console.info.apply(console, OB.UTIL.argumentsWithLink(argsWithoutFirst)); } else if (level === "Warn") { console.warn.apply(console, OB.UTIL.argumentsWithLink(argsWithoutFirst)); } else if (level === "Error" || level === "Critical") { console.error.apply(console, OB.UTIL.argumentsWithLink(argsWithoutFirst)); } else { console.log.apply(console, OB.UTIL.argumentsWithLink(argsWithoutFirst)); } } } catch (e) { console.error.apply(console, arguments); } }; OB.UTIL.saveLogClient = function (msg, level) { try { if (OB.POS && OB.POS.modelterminal && OB.MobileApp.model.supportLogClient()) { var date, json, logClientModel = new OB.Model.LogClient(); date = new Date(); logClientModel.set('obmobc_logclient_id', OB.UTIL.get_UUID()); logClientModel.set('created', date.getTime()); logClientModel.set('createdby', OB.POS.modelterminal.get('orgUserId')); logClientModel.set('loglevel', level); logClientModel.set('msg', msg); logClientModel.set('deviceId', OB.MobileApp.model.get('logConfiguration').deviceIdentifier); logClientModel.set('link', OB.UTIL.getStackLink()); _.each(OB.MobileApp.model.get('logConfiguration').logPropertiesExtension, function (f) { logClientModel.set(f()); }); logClientModel.set('json', JSON.stringify(logClientModel.toJSON())); OB.Dal.save(logClientModel, null, null); } } catch (e) { return; } }; OB.UTIL.composeMessage = function (args) { var msg = ''; _.each(args, function (arg) { if (msg !== '') { msg += ' '; } if ((!(_.isNull(arg) || _.isUndefined(arg))) && _.isObject(arg)) { var stringifyed = JSON.stringify(arg); if (stringifyed) { // add the stringifyed arg to the msg. if the stringify string is too long, cut it msg += (stringifyed.length < 1000) ? stringifyed : stringifyed.substring(0, 1000); } } }); return msg; }; // it checks if the log should be saved in backend (property 'OBMOBC_logClient.saveLog') and the level saved (property 'OBMOBC_logClient.levelLog') // or the level of log should be displayed in console (property 'OBMOBC_logClient.consoleLevelLog') // "type "will be "save" to check if the log should be saved in backend or "console" to check if the log should be displayed in console OB.UTIL.checkPermissionLog = function (level, type) { try { if ((OB.MobileApp && OB.MobileApp.model && OB.MobileApp.model.get('permissions') !== null) === false) { return true; } if (type === "save") { if (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.saveLog'] === false) { return false; } if (level === "Trace") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Trace'); } if (level === "Debug") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Debug'); } if (level === "Info") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Info'); } if (level === "Warn") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Info' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Warn'); } if (level === "Error") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Info' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Warn' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Error'); } if (level === "Critical") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Info' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Warn' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Error' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.levelLog'] === 'Critical'); } } else { if (level === "Trace") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Trace'); } if (level === "Debug") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Debug'); } if (level === "Info") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Info'); } if (level === "Warn") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Info' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Warn'); } if (level === "Error") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Info' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Warn' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Error'); } if (level === "Critical") { return (OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Trace' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Debug' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Info' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Warn' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Error' || OB.MobileApp.model.get('permissions')['OBMOBC_logClient.consoleLevelLog'] === 'Critical'); } } return true; } catch (e) { return true; } }; OB.UTIL.getStackLink = function () { try { var errorobj = new Error(); var link = errorobj.stack.split('\n')[4].split('(')[1]; if (link) { return link.substring(0, link.length - 2); } return ''; } catch (e) { return ''; } }; OB.UTIL.argumentsWithLink = function (args) { var arrayArgs, i; try { arrayArgs = []; for (i = 0; i < args.length; i++) { arrayArgs.push(args[i]); } arrayArgs.push(OB.UTIL.getStackLink()); return arrayArgs; } catch (e) { return ''; } }; OB.UTIL.isIOS = function () { return navigator.userAgent.match(/iPhone|iPad|iPod/i); }; OB.UTIL.clone = function (object, copyObject) { var clonedObject, tmpObj, tmpCollection, tmpModel; if (typeof (object) === 'object') { if (copyObject) { clonedObject = copyObject; } else if (object.constructor) { tmpObj = object.constructor; clonedObject = new tmpObj(); } else { clonedObject = {}; } _.each(_.keys(object.attributes), function (key) { if (!_.isUndefined(object.get(key))) { if (object.get(key) === null) { clonedObject.set(key, null); } else if (object.get(key).at) { //collection if (!clonedObject.get(key)) { tmpCollection = object.get(key).constructor; clonedObject.set(key, new tmpCollection()); } clonedObject.get(key).reset(); object.get(key).forEach(function (elem) { clonedObject.get(key).add(OB.UTIL.clone(elem)); }); } else if (object.get(key).get) { //backboneModel if (!clonedObject.get(key)) { tmpModel = object.get(key).constructor; clonedObject.set(key, new tmpModel()); } clonedObject.set(key, OB.UTIL.clone(object.get(key))); } else if (_.isArray(object)) { //Array clonedObject.set(key, []); object.get(key).forEach(function (elem) { clonedObject.get(key).push(OB.UTIL.clone(elem)); }); } else { //property clonedObject.set(key, object.get(key)); } } }); } _.each(_.keys(clonedObject.attributes), function (key) { if (_.isUndefined(object.get(key))) { clonedObject.set(key, null); } }); return clonedObject; }; }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _, enyo */ /** * HookManager (available at OB.UTIL.HookManager) is a lightweight way of * allow extension points in the code. These extensions points will be used by external * modules to inject their code. * * Extensions points are identified by a qualifier string. Modules register the function * to execute at this point. */ OB.UTIL.HookManager = new(Backbone.Model.extend({ /** * External modules can define the hook to execute (func) for a concrete extension * point (qualifier). * * The function has always 2 parameters: * - args: it is any javascript object the base module can send as parameter * - callback: it is an array of callback functions, it should be managed by * invoking to OB.UTIL.HookManager.executeHooks(callback) function * once the execution is finished */ registerHook: function (qualifier, func) { var qualifierFuncs; if (!enyo.isFunction(func)) { window.error('Error trying to register hook for', qualifier, 'func', func, 'is not a function'); return; } qualifierFuncs = this.get(qualifier) || []; qualifierFuncs.unshift(func); this.set(qualifier, qualifierFuncs); }, /** * Base modules execute hooks for a qualifier, after execution of all hooks, callback * function will be invoked */ executeHooks: function (qualifier, args, callback) { var hooks; if (callback && !enyo.isFunction(callback)) { window.error('Error while executing hooks for', qualifier, 'callback is not a function', callback); return; } hooks = _.clone(this.get(qualifier)) || []; if (callback) { hooks.unshift(callback); } this.callbackExecutor(args, hooks); }, /** * Convenience method that should be invoked by hook implementors once they are done * in order to continue with the hook chain */ callbackExecutor: function (args, callbacks) { var func; func = callbacks.pop(); if (func) { func(args, callbacks); } } }))(); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.UI.Clock', tag: 'div', components: [{ tag: 'div', classes: 'clock-time', name: 'clock' }, { tag: 'div', classes: 'clock-date', name: 'date' }], initComponents: function () { var me = this, updateClock = function () { var d = new Date(); if (!me.$.clock) { return; } me.$.clock.setContent(OB.I18N.formatHour(d)); me.$.date.setContent(OB.I18N.formatDate(d)); }; this.inherited(arguments); updateClock(); setInterval(updateClock, 15000); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo console _ */ enyo.kind({ name: 'OB.UI.WindowView', windowmodel: null, create: function () { this.inherited(arguments); this.model = new this.windowmodel(); this.model.on('ready', function () { if (this.init) { this.init(); } OB.UTIL.HookManager.executeHooks('ModelReady:' + this.name, null, function () { OB.MobileApp.model.trigger('window:ready', this); window.localStorage.setItem('LOGINTIMER', (new Date().getTime()) - window.localStorage.getItem('LOGINTIMER')); OB.info("Total time to log in: ", window.localStorage.getItem('LOGINTIMER')); }); }, this); this.model.load(); }, statics: { initChildren: function (view, model) { if (!view || !view.getComponents) { return; } enyo.forEach(view.getComponents(), function (child) { OB.UI.WindowView.initChildren(child, model); if (child.init) { child.init(model); } }); }, registerPopup: function (windowClass, dialogToAdd) { var kind; kind = enyo.getObject(windowClass); if (!_.isEmpty(kind)) { kind.prototype.popups.push({ dialog: dialogToAdd, windowClass: windowClass }); } else { OB.UTIL.showWarning("An error occurs adding the pop up " + dialogToAdd.kind + ". The window class " + windowClass + " cannot be found."); } }, destroyModels: function (view) { var p; if (!view) { return; } for (p in view) { if (view.hasOwnProperty(p) && view[p] && view[p].off) { view[p].off(); delete view[p]; } } if (!view.getComponents) { return; } enyo.forEach(view.getComponents(), function (child) { OB.UI.WindowView.destroyModels(child); }); } }, popups: [], init: function () { //Modularity //Add new dialogs enyo.forEach(this.popups, function (dialog) { if (dialog.windowClass === this.kindName) { this.createComponent(dialog.dialog); } }, this); // Calling init in sub components OB.UI.WindowView.initChildren(this, this.model); }, destroy: function () { if (this.model) { this.model.setOff(); } this.model = null; OB.UI.WindowView.destroyModels(this); try { this.inherited(arguments); } catch (e) { OB.error('error destroying components', e); } } }); OB.Customizations = {}; OB.Customizations.pointOfSale = {}; OB.Customizations.pointOfSale.dialogs = { push: function (kind) { //developers help OB.warn('WARNING! OB.Customizations.pointOfSale.dialogs has been deprecated. Use OB.UI.WindowView.registerPopup() instead.'); OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', kind); } }; OB.Customizations.pointOfSale.dialogs = OB.Customizations.pointOfSale.dialogs || []; /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _*/ /** * Multi (2) columns layout. Each of this columns consists on a toolbar and a * panel. When the screen is narrow, the layout shows only one column and adds * a button to switch between them */ enyo.kind({ name: 'OB.UI.MultiColumn', isRightSideShown: true, handlers: { onSwitchColumn: 'switchColumn', onpostresize: 'panelsResized', onShowColumn: 'showColumn' }, events: { onNarrowChanged: '' }, published: { leftToolbar: null, leftPanel: null, rightToolbar: null, rightPanel: null }, components: [{ kind: 'Panels', name: 'panels', arrangerKind: 'CollapsingArranger', style: 'height: 690px;', //TODO: height is needed, how to calculate?? components: [{ name: 'left', classes: 'menu-option', components: [{ classes: 'row', style: 'margin-bottom: 5px;', name: 'leftToolbar' }, { classes: 'span12', name: 'leftPanel' }] }, { name: 'right', classes: 'menu-option', components: [{ classes: 'row', style: 'margin-bottom: 5px;', name: 'rightToolbar' }, { classes: 'span12', name: 'rightPanel' }] }] }], statics: { isSingleColumn: function () { return enyo.Panels.isScreenNarrow(); } }, menuChanged: function () { this.$.leftMenu.setMenu(this.menu); }, panelsResized: function () { var newNarrow = enyo.Panels.isScreenNarrow(), i, panels, zoom; if (window.innerHeight) { // resetting height to prevent scrollbar depending on resolution zoom = document.body.style.zoom || 1; this.$.panels.applyStyle('height', (window.innerHeight - 14) / zoom + 'px'); } if (this.narrow === newNarrow) { // no change in window size, do nothing return false; } this.narrow = newNarrow; if (newNarrow) { this.$.panels.draggable = this.isRightSideShown; } else { this.$.panels.draggable = false; this.$.panels.setIndex(0); } panels = this.$.panels.getPanels(); for (i = 0; i < panels.length; i++) { if (newNarrow) { panels[i].removeClass('menu-option-transparent'); panels[i].addClass('menu-option'); } else { panels[i].removeClass('menu-option'); panels[i].addClass('menu-option-transparent'); } } this.waterfall('onNarrowChanged'); }, switchColumn: function () { var idx = this.$.panels.getIndex(); if (!this.isRightSideShown) { return; } idx = idx === 0 ? 1 : 0; this.$.panels.setIndex(idx); }, showColumn: function (inSender, inEvent) { var idx = inEvent.colNum; if (!enyo.Panels.isScreenNarrow()) { // no columns to navigate return; } if (!idx) { this.switchColumn(); } else { this.$.panels.setIndex(idx); } }, setRightShowing: function (showing) { this.isRightSideShown = showing; this.$.rightToolbar.setShowing(showing); this.$.rightPanel.setShowing(showing); this.$.panels.draggable = showing; if (!showing) { this.$.panels.setIndex(0); } if (this.$.leftToolbar.$.leftToolbar) { this.$.leftToolbar.$.leftToolbar.$.rightHolder.$.colswitcher.$.button.setDisabled(!showing); } }, initComponents: function () { var leftToolbar, rightToolbar, emptyPanel = { kind: 'Component' }, emptyToolbar = { kind: 'OB.UI.MultiColumn.Toolbar' }; this.leftToolbar = this.leftToolbar || emptyToolbar; this.leftPanel = this.leftPanel || emptyPanel; this.rightToolbar = this.rightToolbar || emptyToolbar; if (!this.rightPanel) { this.rightPanel = emptyPanel; this.leftToolbar.emptyRightPanel = true; } leftToolbar = _.clone(this.leftToolbar); rightToolbar = _.clone(this.rightToolbar); this.inherited(arguments); leftToolbar.position = 'left'; rightToolbar.position = 'right'; this.$.leftToolbar.createComponent(leftToolbar); this.$.rightToolbar.createComponent(rightToolbar); this.$.leftPanel.createComponent(this.leftPanel); this.$.rightPanel.createComponent(this.rightPanel); this.setRightShowing(this.isRightSideShown); } }); /** * Toolbar for OB.UI.MultiColumn layout. Handles column switcher button that * is shown when in narrow screen */ enyo.kind({ name: 'OB.UI.MultiColumn.Toolbar', handlers: { onNarrowChanged: 'toolbarResized' }, components: [{ classes: 'span12', components: [{ name: 'theToolbar', components: [{ name: 'leftHolder' }, { name: 'standardToolbar', components: [{ name: 'toolbar', tag: 'ul', classes: 'unstyled nav-pos row-fluid' }] }, { name: 'rightHolder' }] }] }], initComponents: function () { this.inherited(arguments); if (this.position === 'left') { if (!this.emptyRightPanel) { this.$.rightHolder.createComponent({ kind: 'OB.UI.OB.UI.MultiColumn.Toolbar.ColumnSwitcher', name: 'colswitcher' }); } if (this.showMenu) { this.$.leftHolder.createComponent({ kind: 'OB.UI.MainMenu', customMenuEntries: this.menuEntries, showWindowsMenu: this.showWindowsMenu }); } } enyo.forEach(this.buttons, function (btn) { if (!btn.span) { btn.width = 100 / this.buttons.length; } this.$.toolbar.createComponent({ kind: 'OB.UI.OB.UI.MultiColumn.Toolbar.Button', button: btn }); }, this); if (this.position === 'right') { this.$.leftHolder.createComponent({ kind: 'OB.UI.OB.UI.MultiColumn.Toolbar.ColumnSwitcher', name: 'colswitcher' }); } }, /** * If it is narrow screen, column switcher button is shown and the toolbar is * resized to fit it. */ toolbarResized: function () { var isNarrow = enyo.Panels.isScreenNarrow(), hasMenu = this.position === 'left' && this.showMenu; if (isNarrow && !this.emptyRightPanel) { if (hasMenu) { this.$.standardToolbar.removeClass('span10'); this.$.standardToolbar.addClass('span8'); } else { this.$.standardToolbar.removeClass('span12'); this.$.standardToolbar.addClass('span10'); } if (this.$.leftHolder.$.colswitcher) { this.$.leftHolder.$.colswitcher.$.button.show(); } if (this.$.rightHolder.$.colswitcher) { this.$.rightHolder.$.colswitcher.$.button.show(); } } else { if (hasMenu) { this.$.standardToolbar.removeClass('span8'); this.$.standardToolbar.addClass('span10'); } else { this.$.standardToolbar.removeClass('span10'); this.$.standardToolbar.addClass('span12'); } if (this.$.leftHolder.$.colswitcher) { this.$.leftHolder.$.colswitcher.$.button.hide(); } if (this.$.rightHolder.$.colswitcher) { this.$.rightHolder.$.colswitcher.$.button.hide(); } } return true; } }); /** * Button to switch between columns when in narrow screen */ enyo.kind({ name: 'OB.UI.OB.UI.MultiColumn.Toolbar.ColumnSwitcher', events: { onSwitchColumn: '' }, classes: 'span2', components: [{ // column switcher components: [{ attributes: { style: 'margin: 0px 5px 0px 5px;' }, components: [{ kind: 'OB.UI.ToolbarButton', name: 'button', icon: 'btn-icon btn-icon-switchColumn', tap: function () { this.bubble('onSwitchColumn'); } }] }] }] }); enyo.kind({ name: 'OB.UI.OB.UI.MultiColumn.Toolbar.Button', tag: 'li', components: [{ name: 'theButton', attributes: { style: 'margin: 0px 5px 0px 5px;' } }], initComponents: function () { var span = this.button.span || (this.button.kind === 'OB.UI.MultiColumn.EmptyToolbar' ? '12' : '4'); this.inherited(arguments); if (this.button.width) { this.setStyle('width: ' + this.button.width + '% !important;'); } else { this.addClass('span' + span); } this.$.theButton.createComponent(this.button); } }); enyo.kind({ name: 'OB.UI.MultiColumn.EmptyToolbar', kind: 'OB.UI.ToolbarButton', classes: 'btnlink-gray', style: 'font-weight: bold; font-size: 130%;', initComponents: function () { this.inherited(arguments); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global _, Backbone, $, enyo */ enyo.kind({ name: 'OB.UI.ScrollableTableHeader', style: 'border-bottom: 1px solid #cccccc;', handlers: { onScrollableTableHeaderChanged: 'scrollableTableHeaderChanged_handler' } }); enyo.kind({ name: 'OB.UI.ScrollableTable', published: { collection: null, listStyle: null }, getValue: function (arg, lineIndex) { //Automated test if (this.$.tbody.children[lineIndex].children[0].getValue) { return this.$.tbody.children[lineIndex].children[0].getValue(arg); } else { OB.warn('getValue is not present in line ' + lineIndex + ' component of ' + this.name); return null; } }, getNumberOfLines: function () { //Automated test return this.$.tbody.children.length; }, getLineByIndex: function (lineIndex) { //Automated test if (this.$.tbody.children[lineIndex].children[0]) { return this.$.tbody.children[lineIndex].children[0]; } else { return undefined; } }, getLineByIndexAndClick: function (lineIndex) { //Automated test var selectedLine = this.getLineByIndex(lineIndex); if (!_.isUndefined(selectedLine)) { selectedLine.tap(); } return selectedLine; }, getLineByValue: function (arg, value) { //Automated test var selectedLine; selectedLine = _.find(this.$.tbody.children, function (line) { if (line.children[0].getValue && line.children[0].getValue(arg) === value) { return true; } }); if (!_.isUndefined(selectedLine)) { return selectedLine.children[0]; } else { return undefined; } }, getLineByValueAndClick: function (arg, value) { var selectedLine = this.getLineByValue(arg, value); if (!_.isUndefined(selectedLine)) { selectedLine.tap(); } return selectedLine; }, isSelectableLine: function (model) { return true; }, components: [{ name: 'theader' }, { components: [{ kind: 'Scroller', name: 'scrollArea', thumb: true, horizontal: 'hidden', components: [{ name: 'tbody', tag: 'ul', classes: 'unstyled', showing: false }] }] }, { name: 'tlimit', showing: false, style: 'border-bottom: 1px solid #cccccc; padding: 15px; text-align:center; font-weight: bold; color: #a1a328' }, { name: 'tinfo', showing: false, style: 'border-bottom: 1px solid #cccccc; padding: 15px; font-weight: bold; color: #cccccc' }, { name: 'tempty' }], create: function () { var tableName = this.name || ''; this.inherited(arguments); // helping developers if (!this.renderLine) { throw enyo.format('Your list %s needs to define a renderLine kind', tableName); } if (!this.renderEmpty) { throw enyo.format('Your list %s needs to define a renderEmpty kind', tableName); } if (this.collection) { this.collectionChanged(null); } this.$.tlimit.setContent(OB.I18N.getLabel('OBMOBC_DataLimitReached')); }, listStyleChanged: function (oldSTyle) { if (this.listStyle === 'checkboxlist') { this.collection.trigger('unSelectAll'); } }, collectionChanged: function (oldCollection) { this.selected = null; if (this.renderHeader && this.$.theader.getComponents().length === 0) { this.$.theader.createComponent({ kind: this.renderHeader }); } if (this.renderEmpty && this.$.tempty.getComponents().length === 0) { this.$.tempty.createComponent({ kind: this.renderEmpty }); } if (this.scrollAreaMaxHeight) { this.$.scrollArea.setMaxHeight(this.scrollAreaMaxHeight); } if (!this.collection) { // set to null? return; } /*selected*/ this.func_selected = function (model) { //if the same collection is used by different components and one of them has been destroyed, the event is ignored if (this.destroyed) { this.collection.off('selected', this.func_selected); return true; } if (!model && this.listStyle && this.listStyle !== 'checkboxlist') { if (this.selected) { this.selected.addRemoveClass('selected', false); } this.selected = null; } }; this.collection.on('selected', this.func_selected, this); /*unSelectAll*/ this.func_unSelectAll = function (col) { //if the same collection is used by different components and one of them has been destroyed, the event is ignored if (this.destroyed) { this.collection.off('unSelectAll', this.func_unSelectAll); return true; } this.collection.each(function (model) { model.trigger('unselected'); }); }; this.collection.on('unSelectAll', this.func_unSelectAll, this); /*checkAll*/ this.func_checkAll = function (col) { //if the same collection is used by different components and one of them has been destroyed, the event is ignored if (this.destroyed) { this.collection.off('checkAll', this.func_checkAll); return true; } this.collection.each(function (model) { model.trigger('check'); }); }; this.collection.on('checkAll', this.func_checkAll, this); /*unCheckAll*/ this.func_unCheckAll = function (col) { //if the same collection is used by different components and one of them has been destroyed, the event is ignored if (this.destroyed) { this.collection.off('unCheckAll', this.func_unCheckAll); return true; } this.collection.each(function (model) { model.trigger('uncheck'); }); }; this.collection.on('unCheckAll', this.func_unCheckAll, this); /*add*/ this.func_add = function (model, prop, options) { //if the same collection is used by different components and one of them has been destroyed, the event is ignored if (this.destroyed) { this.collection.off('add', this.func_add); return true; } this.$.tempty.hide(); this.$.tbody.show(); this._addModelToCollection(model, options.index); if (this.listStyle === 'list') { if (!this.selected) { model.trigger('selected', model); } } else if (this.listStyle === 'edit') { model.trigger('selected', model); } this.setScrollAfterAdd(); }; this.collection.on('add', this.func_add, this); /*remove*/ this.func_remove = function (model, prop, options) { var index = options.index, indexToPoint = index - 1; //if the same collection is used by different components and one of them has been destroyed, the event is ignored if (this.destroyed) { this.collection.off('remove', this.func_remove); return true; } this.$.tbody.getComponents()[index].destroy(); // controlAtIndex ? if (index >= this.collection.length) { if (this.collection.length === 0) { this.collection.trigger('selected'); } else { this.collection.at(this.collection.length - 1).trigger('selected', this.collection.at(this.collection.length - 1)); } } else { this.collection.at(index).trigger('selected', this.collection.at(index)); } if (this.collection.length === 0) { this.$.tbody.hide(); this.$.tempty.show(); } else { //Put scroller in the previous item of deleted one //Issue 0021835 except when the deleted is the first one. if (indexToPoint < 0) { indexToPoint = 0; } this.getScrollArea().scrollToControl(this.$.tbody.getComponents()[indexToPoint]); } }; this.collection.on('remove', this.func_remove, this); /*reset*/ this.func_reset = function (a, b, c) { var modelsel, dataLimit; //if the same collection is used by different components and one of them has been destroyed, the event is ignored if (this.destroyed) { this.collection.off('reset', this.func_reset); return true; } this.$.tlimit.hide(); this.$.tbody.hide(); this.$.tempty.show(); this.$.tbody.destroyComponents(); if (this.collection.size() === 0) { this.$.tbody.hide(); this.$.tempty.show(); this.collection.trigger('selected'); } else { this.$.tempty.hide(); this.$.tbody.show(); this.collection.each(function (model) { this._addModelToCollection(model); }, this); // added to fix bug 25287 this.getScrollArea().render(); dataLimit = this.collection.at(0).dataLimit; if (dataLimit && dataLimit <= this.collection.length) { this.$.tlimit.show(); } if (this.listStyle === 'list') { modelsel = this.collection.at(0); modelsel.trigger('selected', modelsel); } else if (this.listStyle === 'edit') { modelsel = this.collection.at(this.collection.size() - 1); modelsel.trigger('selected', modelsel); } } }; this.collection.on('reset', this.func_reset, this); /*info*/ this.func_info = function (info) { //if the same collection is used by different components and one of them has been destroyed. if (this.destroyed) { this.collection.off('info', this.func_info); return true; } if (info) { this.$.tinfo.setContent(OB.I18N.getLabel(info)); this.$.tinfo.show(); } else { this.$.tinfo.hide(); } }; this.collection.on('info', this.func_info, this); // XXX: Reseting to show the collection if registered with data this.collection.trigger('reset'); }, getScrollArea: function () { return this.$.scrollArea; }, setScrollAfterAdd: function(){ //Put scroller in the position of new item this.getScrollArea().scrollToBottom(); }, getHeader: function () { var tableName = this.name || ''; if (this.$.theader.getComponents()) { if (this.$.theader.getComponents().length > 0) { if (this.$.theader.getComponents().length === 1) { return this.$.theader.getComponents()[0]; } else { //developers help throw enyo.format('Each scrolleable table ahould have only one component as header', tableName); } } } return null; }, getHeaderValue: function () { var header = this.getHeader(); if (header) { if (header.getValue) { return header.getValue(); } else { return header.getContent(); } } return ''; }, _addModelToCollection: function (model, index) { var i, models = []; var components = this.$.tbody.getComponents(); if (!(_.isUndefined(index)) && !(_.isNull(index)) && index < components.length) { //refresh components collection, inserting new model... // get the models from current components for (i = 0; i < components.length; i++) { models[i] = { renderlinemodel: components[i].renderline.model, checked: components[i].checked }; } this.$.tbody.destroyComponents(); // rebuild component for (i = 0; i < models.length; i++) { if (i === index) { this._createComponentForModel(model); } this._createComponentForModel(models[i].renderlinemodel, models[i].checked); } } else { // add to the end... this._createComponentForModel(model); } }, _createComponentForModel: function (model, checked) { var tr = this.$.tbody.createComponent({ tag: 'li' }).render(); //columns added for Automated test tr.renderline = tr.createComponent({ kind: this.renderLine, model: model, columns: this.columns }).render(); tr.checked = checked; model.on('change', function () { if (tr.destroyed) { return; } tr.destroyComponents(); tr.renderline = tr.createComponent({ kind: this.renderLine, model: model }).render(); }, this); model.on('selected', function () { if (this.listStyle && this.listStyle === 'nonselectablelist') { //do nothing in this case, we don't want to select anything return; } else if (this.listStyle && this.listStyle !== 'checkboxlist') { var selectedCssClass = this.selectedCssClass ? this.selectedCssClass : 'selected'; if (tr.destroyed) { return; } if (this.selected) { this.selected.addRemoveClass(selectedCssClass, false); } this.selected = tr; this.selected.addRemoveClass(selectedCssClass, true); // FIXME: OB.UTIL.makeElemVisible(this.node, this.selected); } else if (this.listStyle === 'checkboxlist') { if (tr.destroyed) { return; } var components = tr.getComponents(); if (components.length === 1) { if (components[0].$.checkBoxColumn.checked) { model.trigger('uncheck', model); } else { model.trigger('check', model); } } } }, this); model.on('unselected', function () { if (this.selected) { this.selected.removeClass('selected', false); } // FIXME: OB.UTIL.makeElemVisible(this.node, this.selected); this.selected = null; }, this); model.on('check', function () { var me = this; if (tr && tr.destroyed) { return; } // this line can not be selected if (!me.isSelectableLine(model)) { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_LineCanNotBeSelected')); return; } if (this.listStyle === 'checkboxlist') { var components = tr.getComponents(), allChecked = null, checkedLines = []; if (components.length === 1) { components[0].$.checkBoxColumn.check(); tr.checked = true; _.each(tr.getParent().getComponents(), function (comp) { if (comp.checked) { checkedLines.push(comp.getComponents()[0].model); if (allChecked !== false) { allChecked = true; } } else { allChecked = false; } }); components[0].doLineChecked({ action: 'check', line: model, checkedLines: checkedLines, allChecked: allChecked }); } } }, this); model.on('uncheck', function () { if (tr && tr.destroyed) { return; } if (this.listStyle === 'checkboxlist') { var components = tr.getComponents(), checkedLines = []; if (components.length === 1) { components[0].$.checkBoxColumn.unCheck(); tr.checked = false; _.each(tr.getParent().getComponents(), function (comp) { if (comp.checked) { checkedLines.push(comp.getComponents()[0].model); } }); components[0].doLineChecked({ action: 'uncheck', line: model, checkedLines: checkedLines, allChecked: false }); } } }, this); return tr; } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, moment */ (function () { // Mockup for OB.I18N OB = window.OB || {}; OB.I18N = window.OB.I18N || {}; // Quantity scale. OB.I18N.qtyScale = function () { return OB.Format.formats.qtyEdition.length - OB.Format.formats.qtyEdition.indexOf('.') - 1; }; OB.I18N.formatCurrency = function (number) { var maskNumeric = OB.Format.formats.priceInform, decSeparator = OB.Format.defaultDecimalSymbol, groupSeparator = OB.Format.defaultGroupingSymbol, groupInterval = OB.Format.defaultGroupingSize; maskNumeric = maskNumeric.replace(',', 'dummy').replace('.', decSeparator).replace('dummy', groupSeparator); return OB.Utilities.Number.JSToOBMasked(number, maskNumeric, decSeparator, groupSeparator, groupInterval); }; OB.I18N.formatCurrencyWithSymbol = function (number, symbol, currencySymbolToTheRight) { if (currencySymbolToTheRight) { return OB.I18N.formatCurrency(number) + symbol; } else { return symbol + OB.I18N.formatCurrency(number); } }; OB.I18N.formatCoins = function (number) { var val = OB.I18N.formatCurrency(number); var decSeparator = OB.Format.defaultDecimalSymbol; return val.replace(new RegExp('[' + decSeparator + '][0]+$'), ''); }; OB.I18N.formatRate = function (number) { var symbol = '%', maskNumeric = OB.Format.formats.taxInform || OB.Format.formats.euroEdition, decSeparator = OB.Format.defaultDecimalSymbol, groupSeparator = OB.Format.defaultGroupingSymbol, groupInterval = OB.Format.defaultGroupingSize; maskNumeric = maskNumeric.replace(',', 'dummy').replace('.', decSeparator).replace('dummy', groupSeparator); var formattedNumber = OB.Utilities.Number.JSToOBMasked(number, maskNumeric, decSeparator, groupSeparator, groupInterval); formattedNumber = formattedNumber + symbol; return formattedNumber; }; OB.I18N.formatDate = function (JSDate) { if (!OB.Format) { OB.error("OB.I18N.formatDate() requires OB.Format to be initialized"); return null; } if (!OB.Format.date) { OB.error("OB.I18N.formatDate() requires OB.Format.date to be initialized"); return null; } var dateFormat = OB.Format.date; if (OB.Utilities && OB.Utilities.Date) { return OB.Utilities.Date.JSToOB(JSDate, dateFormat); } else { return JSDate; } }; OB.I18N.formatDateISO = function (d) { var curr_date = d.getDate(); var curr_month = d.getMonth(); var curr_year = d.getFullYear(); var curr_hour = d.getHours(); var curr_min = d.getMinutes(); var curr_sec = d.getSeconds(); var curr_mill = d.getMilliseconds(); return OB.UTIL.padNumber(curr_year, 4) + '-' + OB.UTIL.padNumber(curr_month + 1, 2) + '-' + OB.UTIL.padNumber(curr_date, 2) + ' ' + OB.UTIL.padNumber(curr_hour, 2) + ':' + OB.UTIL.padNumber(curr_min, 2) + ':' + OB.UTIL.padNumber(curr_sec, 2) + '.' + OB.UTIL.padNumber(curr_mill, 3); }; OB.I18N.formatHour = function (d, includeSeconds) { var curr_date = d.getDate(); var curr_month = d.getMonth(); var curr_year = d.getFullYear(); var curr_hour = d.getHours(); var curr_min = d.getMinutes(); var curr_sec = d.getSeconds(); var formattedHour = OB.UTIL.padNumber(curr_hour, 2) + ':' + OB.UTIL.padNumber(curr_min, 2); if (includeSeconds) { formattedHour += ":" + OB.UTIL.padNumber(curr_sec, 2); } return formattedHour; }; OB.I18N.parseServerDate = function (d) { // for example if server and client are in different time zones // parserServerDate("2014-02-05T00:00:00+01:00") returns Wed Feb 05 2014 00:00:00 GMT-0500 (CET) return moment(d, "YYYY-MM-DD").toDate(); }; OB.I18N.parseNumber = function (s) { if (OB.Format.defaultDecimalSymbol !== '.') { s = s.toString(); while (s.indexOf(OB.Format.defaultDecimalSymbol) !== -1) { s = s.replace(OB.Format.defaultDecimalSymbol, '.'); } } return parseFloat(s, 10); }; OB.I18N.getLabel = function (key, params, object, property) { if (key === '') { return ''; } if (key.indexOf('OBUIAPP_GroupBy') === 0) { // Don't show error for GroupBy* labels, they are used by core's decimal // but don't really needed return ''; } if (!OB.I18N.labels) { OB.UTIL.Debug.execute (function () { OB.error('labels not loaded. key asked: ' + key); }); return 'UNDEFINED ' + key; } if (!OB.I18N.labels[key]) { OB.UTIL.Debug.execute (function () { OB.warn('not found label: ' + key); }); return 'UNDEFINED ' + key; } var label = OB.I18N.labels[key], i; if (params && params.length && params.length > 0) { for (i = 0; i < params.length; i++) { label = label.replace("%" + i, params[i]); } } if (object && property) { if (Object.prototype.toString.call(object[property]) === '[object Function]') { object[property](label); } else { object[property] = label; } } return label; }; OB.I18N.hasLabel = function (key, params, object, property) { return OB.I18N.labels[key] ? true : false; }; OB.I18N.getDateFormatLabel = function () { var year, month, day, label = '', i, char, format; year = OB.I18N.getLabel('OBMOBC_YearCharLbl'); month = OB.I18N.getLabel('OBMOBC_MonthCharLbl'); day = OB.I18N.getLabel('OBMOBC_DayCharLbl'); format = OB.Format.date.toLowerCase(); for (i = 0; i < format.length; i++) { char = format[i]; switch (char) { case 'y': label += year; break; case 'm': label += month; break; case 'd': label += day; break; default: label += char; } } return label; }; }()); /* ************************************************************************* * The contents of this file are subject to the Openbravo Public License * Version 1.1 (the "License"), being the Mozilla Public License * Version 1.1 with a permitted attribution clause; you may not use this * file except in compliance with the License. You may obtain a copy of * the License at http://www.openbravo.com/legal/license.html * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU * All portions are Copyright (C) 2011-2014 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************ */ OB = window.OB || {}; OB.Utilities = window.OB.Utilities || {}; // = Openbravo Number Utilities = // Defines utility methods related to handling numbers on the client, for // example formatting. OB.Utilities.Number = {}; // ** {{{ OB.Utilities.Number.roundJSNumber }}} ** // // Function that rounds a JS number to a given decimal number // // Parameters: // * {{{num}}}: the JS number // * {{{dec}}}: the JS number of decimals // Return: // * The rounded JS number OB.Utilities.Number.roundJSNumber = function (num, dec) { var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec); return result; }; // ** {{{ OB.Utilities.Number.OBMaskedToOBPlain }}} ** // // Function that returns a plain OB number just with the decimal Separator // // Parameters: // * {{{number}}}: the formatted OB number // * {{{decSeparator}}}: the decimal separator of the OB number // * {{{groupSeparator}}}: the group separator of the OB number // Return: // * The plain OB number OB.Utilities.Number.OBMaskedToOBPlain = function (number, decSeparator, groupSeparator) { number = number.toString(); var plainNumber = number, decimalNotation = (number.indexOf('E') === -1 && number.indexOf('e') === -1); // Remove group separators if (groupSeparator) { var groupRegExp = new RegExp('\\' + groupSeparator, 'g'); plainNumber = plainNumber.replace(groupRegExp, ''); } //Check if the number is not on decimal notation if (!decimalNotation) { plainNumber = OB.Utilities.Number.ScientificToDecimal(number, decSeparator); } // Catch sign var numberSign = ''; if (plainNumber.substring(0, 1) === '+') { numberSign = ''; plainNumber = plainNumber.substring(1, number.length); } else if (plainNumber.substring(0, 1) === '-') { numberSign = '-'; plainNumber = plainNumber.substring(1, number.length); } // Remove ending decimal '0' if (plainNumber.indexOf(decSeparator) !== -1) { while (plainNumber.substring(plainNumber.length - 1, plainNumber.length) === '0') { plainNumber = plainNumber.substring(0, plainNumber.length - 1); } } // Remove starting integer '0' while (plainNumber.substring(0, 1) === '0' && plainNumber.substring(1, 2) !== decSeparator && plainNumber.length > 1) { plainNumber = plainNumber.substring(1, plainNumber.length); } // Remove decimal separator if is the last character if (plainNumber.substring(plainNumber.length - 1, plainNumber.length) === decSeparator) { plainNumber = plainNumber.substring(0, plainNumber.length - 1); } // Re-set sign if (plainNumber !== '0') { plainNumber = numberSign + plainNumber; } // Return plain number return plainNumber; }; // ** {{{ OB.Utilities.Number.OBPlainToOBMasked }}} ** // // Function that transform a OB plain number into a OB formatted one (by // applying a mask). // // Parameters: // * {{{number}}}: The OB plain number // * {{{maskNumeric}}}: The numeric mask of the OB number // * {{{decSeparator}}}: The decimal separator of the OB number // * {{{groupSeparator}}}: The group separator of the OB number // * {{{groupInterval}}}: The group interval of the OB number // Return: // * The OB formatted number. OB.Utilities.Number.OBPlainToOBMasked = function (number, maskNumeric, decSeparator, groupSeparator, groupInterval) { if (number === '' || number === null || number === undefined) { return number; } if (groupInterval === null || groupInterval === undefined) { groupInterval = OB.Format.defaultGroupingSize; } // Management of the mask if (maskNumeric.indexOf('+') === 0 || maskNumeric.indexOf('-') === 0) { maskNumeric = maskNumeric.substring(1, maskNumeric.length); } if (groupSeparator && maskNumeric.indexOf(groupSeparator) !== -1 && maskNumeric.indexOf(decSeparator) !== -1 && maskNumeric.indexOf(groupSeparator) > maskNumeric.indexOf(decSeparator)) { var fixRegExp = new RegExp('\\' + groupSeparator, 'g'); maskNumeric = maskNumeric.replace(fixRegExp, ''); } var maskLength = maskNumeric.length; var decMaskPosition = maskNumeric.indexOf(decSeparator); if (decMaskPosition === -1) { decMaskPosition = maskLength; } var intMask = maskNumeric.substring(0, decMaskPosition); var decMask = maskNumeric.substring(decMaskPosition + 1, maskLength); if ((groupSeparator && decMask.indexOf(groupSeparator) !== -1) || decMask.indexOf(decSeparator) !== -1) { if (groupSeparator) { var fixRegExp_1 = new RegExp('\\' + groupSeparator, 'g'); decMask = decMask.replace(fixRegExp_1, ''); } var fixRegExp_2 = new RegExp('\\' + decSeparator, 'g'); decMask = decMask.replace(fixRegExp_2, ''); } // Management of the number number = number.toString(); number = OB.Utilities.Number.OBMaskedToOBPlain(number, decSeparator, groupSeparator); var numberSign = ''; if (number.substring(0, 1) === '+') { numberSign = ''; number = number.substring(1, number.length); } else if (number.substring(0, 1) === '-') { numberSign = '-'; number = number.substring(1, number.length); } // //Splitting the number var formattedNumber = ''; var numberLength = number.length; var decPosition = number.indexOf(decSeparator); if (decPosition === -1) { decPosition = numberLength; } var intNumber = number.substring(0, decPosition); var decNumber = number.substring(decPosition + 1, numberLength); // //Management of the decimal part if (decNumber.length > decMask.length) { decNumber = '0.' + decNumber; decNumber = OB.Utilities.Number.roundJSNumber(decNumber, decMask.length); decNumber = decNumber.toString(); // Check if the number is on Scientific notation if (decNumber.indexOf('e') !== -1 || decNumber.indexOf('E') !== -1) { decNumber = OB.Utilities.Number.ScientificToDecimal(decNumber, decSeparator); } if (decNumber.substring(0, 1) === '1') { intNumber = parseFloat(intNumber); intNumber = intNumber + 1; intNumber = intNumber.toString(); } decNumber = decNumber.substring(2, decNumber.length); } if (decNumber.length < decMask.length) { var decNumber_temp = '', decMaskLength = decMask.length, i; for (i = 0; i < decMaskLength; i++) { if (decMask.substring(i, i + 1) === '#') { if (decNumber.substring(i, i + 1) !== '') { decNumber_temp = decNumber_temp + decNumber.substring(i, i + 1); } } else if (decMask.substring(i, i + 1) === '0') { if (decNumber.substring(i, i + 1) !== '') { decNumber_temp = decNumber_temp + decNumber.substring(i, i + 1); } else { decNumber_temp = decNumber_temp + '0'; } } } decNumber = decNumber_temp; } // Management of the integer part var isGroup = false; if (groupSeparator) { if (intMask.indexOf(groupSeparator) !== -1) { isGroup = true; } var groupRegExp = new RegExp('\\' + groupSeparator, 'g'); intMask = intMask.replace(groupRegExp, ''); } var intNumber_temp; if (intNumber.length < intMask.length) { intNumber_temp = ''; var diff = intMask.length - intNumber.length, j; for (j = intMask.length; j > 0; j--) { if (intMask.substring(j - 1, j) === '#') { if (intNumber.substring(j - 1 - diff, j - diff) !== '') { intNumber_temp = intNumber.substring(j - 1 - diff, j - diff) + intNumber_temp; } } else if (intMask.substring(j - 1, j) === '0') { if (intNumber.substring(j - 1 - diff, j - diff) !== '') { intNumber_temp = intNumber.substring(j - 1 - diff, j - diff) + intNumber_temp; } else { intNumber_temp = '0' + intNumber_temp; } } } intNumber = intNumber_temp; } if (isGroup === true) { intNumber_temp = ''; var groupCounter = 0, k; for (k = intNumber.length; k > 0; k--) { intNumber_temp = intNumber.substring(k - 1, k) + intNumber_temp; groupCounter++; if (groupCounter.toString() === groupInterval.toString() && k !== 1) { groupCounter = 0; intNumber_temp = groupSeparator + intNumber_temp; } } intNumber = intNumber_temp; } // Building the final number if (intNumber === '' && decNumber !== '') { intNumber = '0'; } formattedNumber = numberSign + intNumber; if (decNumber !== '') { formattedNumber += decSeparator + decNumber; } return formattedNumber; }; // ** {{{ OB.Utilities.Number.OBMaskedToJS }}} ** // // Function that returns a JS number just with the decimal separator which // always is '.'. It is used for math operations // // Parameters: // * {{{number}}}: The OB formatted (or plain) number // * {{{decSeparator}}}: The decimal separator of the OB number // * {{{groupSeparator}}}: The group separator of the OB number // Return: // * The JS number. OB.Utilities.Number.OBMaskedToJS = function (numberStr, decSeparator, groupSeparator) { if (!numberStr || numberStr.trim() === '') { return null; } var calcNumber = OB.Utilities.Number.OBMaskedToOBPlain(numberStr, decSeparator, groupSeparator); calcNumber = calcNumber.replace(decSeparator, '.'); var numberResult = parseFloat(calcNumber); if (isNaN(numberResult)) { return numberStr; } return numberResult; }; // ** {{{ OB.Utilities.Number.JSToOBMasked }}} ** // // Function that returns a OB formatted number given as input a JS number just // with the decimal separator which always is '.' // // Parameters: // * {{{number}}}: The JS number // * {{{maskNumeric}}}: The numeric mask of the OB number // * {{{decSeparator}}}: The decimal separator of the OB number // * {{{groupSeparator}}}: The group separator of the OB number // * {{{groupInterval}}}: The group interval of the OB number // Return: // * The OB formatted number. OB.Utilities.Number.JSToOBMasked = function (number, maskNumeric, decSeparator, groupSeparator, groupInterval) { var isANumber = Object.prototype.toString.call(number) === '[object Number]'; if (!isANumber) { return number; } var formattedNumber = number; formattedNumber = formattedNumber.toString(); formattedNumber = formattedNumber.replace('.', decSeparator); formattedNumber = OB.Utilities.Number.OBPlainToOBMasked(formattedNumber, maskNumeric, decSeparator, groupSeparator, groupInterval); return formattedNumber; }; OB.Utilities.Number.IsValidValueString = function (type, numberStr) { var maskNumeric = type.maskNumeric; // note 0 is also okay to return true if (!numberStr) { return true; } var bolNegative = true; if (maskNumeric.indexOf('+') === 0) { bolNegative = false; maskNumeric = maskNumeric.substring(1, maskNumeric.length); } var bolDecimal = true; if (maskNumeric.indexOf(type.decSeparator) === -1) { bolDecimal = false; } var checkPattern = ''; checkPattern += '^'; if (bolNegative) { checkPattern += '([+]|[-])?'; } checkPattern += '(\\d+)?((\\' + type.groupSeparator + '\\d{' + OB.Format.defaultGroupingSize + '})?)+'; if (bolDecimal) { checkPattern += '(\\' + type.decSeparator + '\\d+)?'; } checkPattern += '$'; var checkRegExp = new RegExp(checkPattern); if (numberStr.match(checkRegExp) && numberStr.substring(0, 1) !== type.groupSeparator) { return true; } return false; }; OB.Utilities.Number.Grouping = { getGroupingModes: function () { return this.groupingModes; }, groupingModes: { byDecimal10: OB.I18N.getLabel('OBUIAPP_GroupByDecimal10'), by1: OB.I18N.getLabel('OBUIAPP_GroupBy1'), by10: OB.I18N.getLabel('OBUIAPP_GroupBy10'), by100: OB.I18N.getLabel('OBUIAPP_GroupBy100'), by1000: OB.I18N.getLabel('OBUIAPP_GroupBy1000'), by10000: OB.I18N.getLabel('OBUIAPP_GroupBy10000'), by100000: OB.I18N.getLabel('OBUIAPP_GroupBy100000') }, defaultGroupingMode: 'by10', //default grouping mode groupingMode: 'by10', getGroupingMultiplier: function (groupingMode) { switch (groupingMode) { case 'byDecimal10': return 0.1; case 'by1': return 1; case 'by10': return 10; case 'by100': return 100; case 'by1000': return 1000; case 'by10000': return 10000; case 'by100000': return 100000; } // default return 10; }, getGroupValue: function (value, record, field, fieldName, grid) { var returnValue, groupingMode = (field.groupingMode || OB.Utilities.Number.Grouping.defaultGroupingMode), multiplier = this.getGroupingMultiplier(groupingMode); if (!isc.isA.Number(value) || !groupingMode) { return value; } returnValue = value / multiplier; // round down returnValue = Math.round(returnValue - 0.49); returnValue = returnValue * multiplier; return returnValue; }, getGroupTitle: function (value, record, field, fieldName, grid) { var groupValue = this.getGroupValue(value, record, field, fieldName, grid), groupingMode = (field.groupingMode || OB.Utilities.Number.Grouping.defaultGroupingMode), multiplier = this.getGroupingMultiplier(groupingMode); return groupValue + ' - ' + (groupValue + multiplier); } }; //** {{{ OB.Utilities.Number.ScientificToDecimal }}} ** // // Convert a number from Scientific notation to decimal notation // // Parameters: // * {{{number}}}: the number on scientific notation // * {{{decSeparator}}}: the decimal separator of the OB number // Return: // * The OB number on decimal notation OB.Utilities.Number.ScientificToDecimal = function (number, decSeparator) { number = number.toString(); var coeficient, exponent, numberOfZeros, zeros = '', i, split, index; // Look for 'e' or 'E' if (number.indexOf('e') !== -1) { index = number.indexOf('e'); } else if (number.indexOf('E') !== -1) { index = number.indexOf('E'); } else { // Number is not expressed in scientific notation return number; } // Set the number before and after e coeficient = number.substring(0, index); exponent = number.substring(index + 1, number.length); //Remove the decimal separator if (coeficient.indexOf(decSeparator) !== -1) { split = coeficient.split(decSeparator); coeficient = split[0] + split[1]; } if (exponent.indexOf('-') !== -1) { // Case the number is smaller than 1 numberOfZeros = exponent.substring(1, exponent.length); //Create the string of zeros for (i = 1; i < numberOfZeros; i++) { zeros = zeros + '0'; } //Create the final number number = '0.' + zeros + coeficient; } else if (exponent.indexOf('+') !== -1) { // Case the number is bigger than 1 numberOfZeros = exponent.substring(1, exponent.length); if (split) { numberOfZeros = numberOfZeros - split[1].length; } //Create the string of zeros for (i = 0; i < numberOfZeros; i++) { zeros = zeros + '0'; } //Create the final number number = coeficient + zeros; } return number; }; /* ************************************************************************* * The contents of this file are subject to the Openbravo Public License * Version 1.1 (the "License"), being the Mozilla Public License * Version 1.1 with a permitted attribution clause; you may not use this * file except in compliance with the License. You may obtain a copy of * the License at http://www.openbravo.com/legal/license.html * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU * All portions are Copyright (C) 2009-2014 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************ */ OB = window.OB || {}; OB.Utilities = window.OB.Utilities || {}; // = Openbravo Date Utilities = // Defines utility methods related to handling date, incl. formatting. OB.Utilities.Date = {}; // ** {{{ OB.Utilities.Date.centuryReference }}} ** // For a two-digit year display format, it establishes where is the frontier // between the 20th and the 21st century // The range is taken between 1900+centuryReference and 2100-centuryReference-1 OB.Utilities.Date.centuryReference = 50; // Notice that change this value // implies that also the QUnit test // case should be changed // ** {{{ OB.Utilities.Date.normalizeDisplayFormat }}} ** // Repairs the displayFormat definition (passed in as a parameter) to a value // expected by the rest of the system. For example mm is replaced by MM, // dd is replacecd by DD, YYYY to %Y. // // Parameters: // * {{{displayFormat}}}: the string displayFormat definition to repair. OB.Utilities.Date.normalizeDisplayFormat = function (displayFormat) { var newFormat = ''; displayFormat = displayFormat.replace('mm', 'MM').replace('dd', 'DD').replace('yyyy', 'YYYY').replace('yy', 'YY'); displayFormat = displayFormat.replace('%D', '%d').replace('%M', '%m'); if (displayFormat !== null && displayFormat !== '') { newFormat = displayFormat; newFormat = newFormat.replace('YYYY', '%Y'); newFormat = newFormat.replace('YY', '%y'); newFormat = newFormat.replace('MM', '%m'); newFormat = newFormat.replace('DD', '%d'); newFormat = newFormat.substring(0, 8); } displayFormat = displayFormat.replace('hh', 'HH').replace('HH24', 'HH').replace('mi', 'MI').replace('ss', 'SS'); displayFormat = displayFormat.replace('%H', 'HH').replace('HH:%m', 'HH:MI').replace('HH.%m', 'HH.MI').replace('%S', 'SS'); displayFormat = displayFormat.replace('HH:mm', 'HH:MI').replace('HH.mm', 'HH.MI'); displayFormat = displayFormat.replace('HH:MM', 'HH:MI').replace('HH.MM', 'HH.MI'); if (displayFormat.indexOf(' HH:MI:SS') !== -1) { newFormat += ' %H:%M:%S'; } else if (displayFormat.indexOf(' HH:MI') !== -1) { newFormat += ' %H:%M'; } else if (displayFormat.indexOf(' HH.MI.SS') !== -1) { newFormat += ' %H.%M.%S'; } else if (displayFormat.indexOf(' HH.MI') !== -1) { newFormat += ' %H.%M'; } if (displayFormat.indexOf(' a') !== -1) { newFormat += ' A'; } return newFormat; }; //** {{{ OB.Utilities.getTimeFormat }}} ** // // Returns an object with the timeformatter, a boolean if 24 hours // time clock are being used and the timeformat itself OB.Utilities.getTimeFormatDefinition = function () { var timeFormat, is24h = true; if (OB.Format.dateTime.indexOf(' ') === -1) { return 'to24HourTime'; } timeFormat = OB.Format.dateTime.substring(OB.Format.dateTime.indexOf(' ') + 1); if (timeFormat && timeFormat.toUpperCase().lastIndexOf(' A') !== -1 && timeFormat.toUpperCase().lastIndexOf(' A') === timeFormat.length - 2) { is24h = false; } if (timeFormat.toLowerCase().contains('ss')) { return { timeFormat: timeFormat, is24h: is24h, timeFormatter: is24h ? 'to24HourTime' : 'toTime' }; } return { timeFormat: timeFormat, is24h: is24h, timeFormatter: is24h ? 'toShort24HourTime' : 'toShortTime' }; }; // ** {{{ OB.Utilities.Date.OBToJS }}} ** // // Converts a String to a Date object. // // Parameters: // * {{{OBDate}}}: the date string to convert // * {{{dateFormat}}}: the dateFormat pattern to use // Return: // * a Date object or null if conversion was not possible. OB.Utilities.Date.OBToJS = function (OBDate, dateFormat) { if (!OBDate) { return null; } // if already a date then return true var isADate = Object.prototype.toString.call(OBDate) === '[object Date]', PMIndicator = ' PM', AMIndicator = ' AM', is24h = true, isPM = false; if (isADate) { return OBDate; } if (window.isc && isc.Time && isc.Time.PMIndicator) { PMIndicator = isc.Time.PMIndicator; } if (window.isc && isc.Time && isc.Time.AMIndicator) { AMIndicator = isc.Time.AMIndicator; } dateFormat = OB.Utilities.Date.normalizeDisplayFormat(dateFormat); dateFormat = dateFormat.replace(' A', ''); var dateSeparator = dateFormat.substring(2, 3); var timeSeparator = dateFormat.substring(11, 12); var isFullYear = (dateFormat.indexOf('%Y') !== -1); if (OBDate.indexOf(PMIndicator) !== 1 || OBDate.indexOf(AMIndicator) !== 1) { is24h = false; } if (!is24h && OBDate.indexOf(PMIndicator) !== -1) { isPM = true; } OBDate = OBDate.replace(AMIndicator, '').replace(PMIndicator, ''); if ((isFullYear ? OBDate.length - 2 : OBDate.length) !== dateFormat.length) { return null; } if (isFullYear) { dateFormat = dateFormat.replace('%Y', '%YYY'); } if (dateFormat.indexOf('-') !== -1 && OBDate.indexOf('-') === -1) { return null; } else if (dateFormat.indexOf('/') !== -1 && OBDate.indexOf('/') === -1) { return null; } else if (dateFormat.indexOf(':') !== -1 && OBDate.indexOf(':') === -1) { return null; } else if (dateFormat.indexOf('.') !== -1 && OBDate.indexOf('.') === -1) { return null; } var year = dateFormat.indexOf('%y') !== -1 ? OBDate.substring(dateFormat.indexOf('%y'), dateFormat.indexOf('%y') + 2) : 0; var fullYear = dateFormat.indexOf('%Y') !== -1 ? OBDate.substring(dateFormat.indexOf('%Y'), dateFormat.indexOf('%Y') + 4) : 0; var month = dateFormat.indexOf('%m') !== -1 ? OBDate.substring(dateFormat.indexOf('%m'), dateFormat.indexOf('%m') + 2) : 0; var day = dateFormat.indexOf('%d') !== -1 ? OBDate.substring(dateFormat.indexOf('%d'), dateFormat.indexOf('%d') + 2) : 0; var hours = dateFormat.indexOf('%H') !== -1 ? OBDate.substring(dateFormat.indexOf('%H'), dateFormat.indexOf('%H') + 2) : 0; var minutes = dateFormat.indexOf('%M') !== -1 ? OBDate.substring(dateFormat.indexOf('%M'), dateFormat.indexOf('%M') + 2) : 0; var seconds = dateFormat.indexOf('%S') !== -1 ? OBDate.substring(dateFormat.indexOf('%S'), dateFormat.indexOf('%S') + 2) : 0; // Check that really all date parts (if they are present) are numbers var digitRegExp = ['^\\d+$', 'gm']; if ((year && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(year))) || (fullYear && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(fullYear))) || (month && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(month))) || (day && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(day))) || (hours && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(hours))) || (minutes && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(minutes))) || (seconds && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(seconds)))) { return null; } month = parseInt(month, 10); day = parseInt(day, 10); hours = parseInt(hours, 10); minutes = parseInt(minutes, 10); seconds = parseInt(seconds, 10); if (!is24h) { if (!isPM && hours === 12) { hours = 0; } if (isPM && hours !== 12) { hours = hours + 12; } } if (day < 1 || day > 31 || month < 1 || month > 12 || year > 99 || fullYear > 9999) { return null; } if (hours > 23 || minutes > 59 || seconds > 59) { return null; } // alert('year: ' + year + '\n' + 'fullYear: ' + fullYear + '\n' + 'month: ' + // month + '\n' + 'day: ' + day + '\n' + 'hours: ' + hours + '\n' + 'minutes: // ' + minutes + '\n' + 'seconds: ' + seconds); // var JSDate = isc.Date.create(); /**It doesn't work in IE**/ var JSDate = new Date(); var centuryReference = OB.Utilities.Date.centuryReference; if (!isFullYear) { if (parseInt(year, 10) < centuryReference) { fullYear = '20' + year; } else { fullYear = '19' + year; } } fullYear = parseInt(fullYear, 10); JSDate.setFullYear(fullYear, month - 1, day); // https://issues.openbravo.com/view.php?id=22505 if (day !== JSDate.getDate()) { return null; } JSDate.setHours(hours); JSDate.setMinutes(minutes); JSDate.setSeconds(seconds); JSDate.setMilliseconds(0); if (JSDate.toString() === 'Invalid Date' || JSDate.toString() === 'NaN') { return null; } else { return JSDate; } }; // ** {{{ OB.Utilities.Date.JSToOB }}} ** // // Converts a Date to a String // // Parameters: // * {{{JSDate}}}: the javascript Date object // * {{{dateFormat}}}: the dateFormat pattern to use // Return: // * a String or null if the JSDate is not a date. OB.Utilities.Date.JSToOB = function (JSDate, dateFormat) { dateFormat = OB.Utilities.Date.normalizeDisplayFormat(dateFormat); var isADate = Object.prototype.toString.call(JSDate) === '[object Date]', PMIndicator = ' PM', AMIndicator = ' AM', is24h = true, isPM = false; if (!isADate) { return null; } if (window.isc && isc.Time && isc.Time.PMIndicator) { PMIndicator = isc.Time.PMIndicator; } if (window.isc && isc.Time && isc.Time.AMIndicator) { AMIndicator = isc.Time.AMIndicator; } if (dateFormat.toUpperCase().lastIndexOf(' A') !== -1 && dateFormat.toUpperCase().lastIndexOf(' A') === dateFormat.length - 2) { is24h = false; } var year = JSDate.getYear().toString(); var fullYear = JSDate.getFullYear().toString(); var month = (JSDate.getMonth() + 1).toString(); var day = JSDate.getDate().toString(); var hours = JSDate.getHours().toString(); var minutes = JSDate.getMinutes().toString(); var seconds = JSDate.getSeconds().toString(); var centuryReference = OB.Utilities.Date.centuryReference; if (dateFormat.indexOf('%y') !== -1) { if (parseInt(fullYear, 10) >= 1900 + centuryReference && parseInt(fullYear, 10) < 2100 - centuryReference) { if (parseInt(year, 10) >= 100) { year = parseInt(year, 10) - 100; year = year.toString(); } } else { return null; } } if (!is24h) { hours = parseInt(hours, 10); if (hours >= 12) { isPM = true; } if (hours > 12) { hours = hours - 12; } if (hours === 0) { hours = 12; } hours = hours.toString(); } while (year.length < 2) { year = '0' + year; } while (fullYear.length < 4) { fullYear = '0' + fullYear; } while (month.length < 2) { month = '0' + month; } while (day.length < 2) { day = '0' + day; } while (hours.length < 2) { hours = '0' + hours; } while (minutes.length < 2) { minutes = '0' + minutes; } while (seconds.length < 2) { seconds = '0' + seconds; } var OBDate = dateFormat; OBDate = OBDate.replace('%y', year); OBDate = OBDate.replace('%Y', fullYear); OBDate = OBDate.replace('%m', month); OBDate = OBDate.replace('%d', day); OBDate = OBDate.replace('%H', hours); OBDate = OBDate.replace('%M', minutes); OBDate = OBDate.replace('%S', seconds); if (!is24h) { if (isPM) { OBDate = OBDate.replace(' A', PMIndicator); } else { OBDate = OBDate.replace(' A', AMIndicator); } } return OBDate; }; //** {{{ OB.Utilities.Date.getTimeFields }}} ** // // Returns an array with the names of the time fields. // // Parameters: // * {{{allFields}}}: complete list of fields // Return: // * an array with the names of the time fields contained in allFields. OB.Utilities.Date.getTimeFields = function (allFields) { var i, field, timeFields = [], length = allFields.length; for (i = 0; i < length; i++) { field = allFields[i]; if (field.type === '_id_24') { timeFields.push(field); } } return timeFields; }; //** {{{ OB.Utilities.Date.convertUTCTimeToLocalTime }}} ** // // Converts the value of time fields from UTC to local time // // Parameters: // * {{{newData}}}: records to be converted // * {{{allFields}}}: array with the fields of the records // Return: // * Nothing. newData, after converting its time fields from UTC timezone the the client side timezone OB.Utilities.Date.convertUTCTimeToLocalTime = function (newData, allFields) { var textField, fieldToDate, i, j, UTCOffsetInMiliseconds = OB.Utilities.Date.getUTCOffsetInMiliseconds(), timeFields = OB.Utilities.Date.getTimeFields(allFields), timeFieldsLength = timeFields.length, convertedData = isc.clone(newData), convertedDataLength = convertedData.length; for (i = 0; i < timeFieldsLength; i++) { for (j = 0; j < convertedDataLength; j++) { textField = convertedData[j][timeFields[i].name]; if (!textField) { continue; } if (isc.isA.String(textField)) { fieldToDate = isc.Time.parseInput(textField); } else if (isc.isA.Date(textField)) { fieldToDate = textField; } fieldToDate.setTime(fieldToDate.getTime() + UTCOffsetInMiliseconds); convertedData[j][timeFields[i].name] = fieldToDate.getHours() + ':' + fieldToDate.getMinutes() + ':' + fieldToDate.getSeconds(); } } return convertedData; }; //** {{{ OB.Utilities.Date.addTimezoneOffset }}} ** // // Adds to a date its timezone offset // // Parameters: // * {{{date}}}: date in which it be added its timezone offset OB.Utilities.Date.addTimezoneOffset = function (date) { var newDate; if (Object.prototype.toString.call(date) !== '[object Date]') { return date; } newDate = new Date(date.getTime() + (date.getTimezoneOffset() * 60000)); return newDate; }; //** {{{ OB.Utilities.Date.substractTimezoneOffset }}} ** // // Substracts to a date its timezone offset // // Parameters: // * {{{date}}}: date in which it be substracted its timezone offset OB.Utilities.Date.substractTimezoneOffset = function (date) { var newDate; if (Object.prototype.toString.call(date) !== '[object Date]') { return date; } newDate = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)); return newDate; }; //** {{{ OB.Utilities.Date.getUTCOffsetInMiliseconds }}} ** // // Return the offset with UTC measured in miliseconds OB.Utilities.Date.getUTCOffsetInMiliseconds = function () { var UTCHourOffset = isc.Time.getUTCHoursDisplayOffset(new Date()), UTCMinuteOffset = isc.Time.getUTCMinutesDisplayOffset(new Date()); return (UTCHourOffset * 60 * 60 * 1000) + (UTCMinuteOffset * 60 * 1000); }; //** {{{ OB.Utilities.Date.roundToNextQuarter }}} ** // // Round any date to the next quarter OB.Utilities.Date.roundToNextQuarter = function (date) { var newDate = new Date(date), minutes = newDate.getMinutes(), timeBreak = 15; if (newDate.getMilliseconds() === 0 && newDate.getSeconds() === 0 && minutes % timeBreak === 0) { return newDate; } var roundedMinutes = (parseInt((minutes + timeBreak) / timeBreak, 10) * timeBreak) % 60; newDate.setMilliseconds(0); newDate.setSeconds(0); newDate.setMinutes(roundedMinutes); if (roundedMinutes === 0) { newDate.setHours(newDate.getHours() + 1); } return newDate; }; //** {{{ OB.Utilities.Date.roundToNextHalfHour }}} ** // // Round any date to the next half hour OB.Utilities.Date.roundToNextHalfHour = function (date) { var newDate = new Date(date), minutes = newDate.getMinutes(), timeBreak = 30; if (newDate.getMilliseconds() === 0 && newDate.getSeconds() === 0 && minutes % timeBreak === 0) { return newDate; } var roundedMinutes = (parseInt((minutes + timeBreak) / timeBreak, 10) * timeBreak) % 60; newDate.setMilliseconds(0); newDate.setSeconds(0); newDate.setMinutes(roundedMinutes); if (roundedMinutes === 0) { newDate.setHours(newDate.getHours() + 1); } return newDate; }; /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, Backbone, _ */ enyo.kind({ name: 'OB.UI.Keyboard', commands: {}, buttons: {}, maxButtons: 6, status: '', sideBarEnabled: false, destroy: function () { this.buttons = null; this.commands = null; this.inherited(arguments); }, keyMatcher: /^([0-9]|\.|,| |%|[a-z]|[A-Z])$/, classes: 'row-fluid', components: [{ kind: 'OB.UI.MoreButtons', name: 'OB_UI_MoreButtons' }, { name: 'toolbarcontainer', classes: 'span3' }, { classes: 'span9', components: [{ classes: 'row-fluid', components: [{ classes: 'span8', components: [{ style: 'margin:5px', components: [{ style: 'text-align: right; width: 100%; height: 40px;', components: [{ tag: 'pre', style: 'margin: 0px 0px 9px 0px; background-color: whiteSmoke; border: 1px solid #CCC; word-wrap: break-word; font-size: 35px; height: 33px; padding: 22px 5px 0px 0px;', components: [ // ' ', XXX:??? { name: 'editbox', tag: 'span', style: 'margin-left: -10px;' }] }] }] }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_backspace', classButton: 'btn-icon btn-icon-backspace', command: 'del' }] }, { classes: 'row-fluid', name: 'OBKeyBoard_centerAndRightSideContainer', components: [{ // keypadcontainer classes: 'span8', name: 'keypadcontainer' }, { name: 'OBKeyBoard_rightSideToolbar', classes: 'span4', components: [{ // rigth toolbar with qty, discount... buttons name: 'sideenabled', components: [{ classes: 'row-fluid', components: [{ classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', label: '-', classButton: 'btnkeyboard-num btnkeyboard-minus', command: '-', name: 'minusBtn' }] }, { classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', label: '+', classButton: 'btnkeyboard-num btnkeyboard-plus', command: '+', name: 'plusBtn' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'btnQty', kind: 'OB.UI.ButtonKey', command: 'line:qty' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'btnPrice', permission: 'OBPOS_order.changePrice', command: 'line:price' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'btnDiscount', permission: 'OBPOS_order.discount', command: 'line:dto', init: function (model) { var receipt = model.get('order'); if (receipt) { if (OB.MobileApp.model.get('permissions')["OBPOS_retail.discountkeyboard"] === false) { this.command = 'line:dto'; } else { receipt.get('lines').on('add remove', function () { if (model.get('leftColumnViewManager') && model.get('leftColumnViewManager').isMultiOrder()) { this.waterfall('onDisableButton', { disabled: true }); } if (OB.UTIL.isDisableDiscount) { if (OB.UTIL.isDisableDiscount(receipt)) { this.waterfall('onDisableButton', { disabled: true }); } else { this.waterfall('onDisableButton', { disabled: false }); } } }, this); this.command = 'screen:dto'; } } } }] }] }] }, { // empty right toolbar used in case the keyboard // shouldn't support these buttons name: 'sidedisabled', components: [{ classes: 'row-fluid', components: [{ classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_disabled_A' }] }, { classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_disabled_B' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_disabled_C' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_disabled_D' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_disabled_E' }] }] }] }, { // right toolbar for ticket discounts name: 'ticketDiscountsToolbar', components: [{ classes: 'row-fluid', components: [{ classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_discounts_A' }] }, { classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_discounts_B' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_discounts_C' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_discounts_D' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_discounts_E', description: 'Discount button when discounts sidebar is used', permission: 'OBPOS_retail.advDiscounts', command: 'ticket:discount' }] }] }] }, { // rigth toolbar with plus and minus (Cash upr side toolbar) name: 'sidecashup', components: [{ classes: 'row-fluid', components: [{ classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', label: '-', classButton: 'btnkeyboard-num btnkeyboard-minus', command: '-', name: 'OBKEY_right_cashup_A', description: '+ button used for cashup' }] }, { classes: 'span6', components: [{ kind: 'OB.UI.ButtonKey', label: '+', classButton: 'btnkeyboard-num btnkeyboard-plus', command: '+', name: 'OBKEY_right_cashup_B', description: '- button used for cashup' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_cashup_C' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_cashup_D' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_right_cashup_E' }] }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btn-icon btn-icon-enter', command: 'OK', name: 'btnEnter' }] }] }] }] }] }] }], events: { onCommandFired: '', onStatusChanged: '', onHoldActiveCmd: '' }, handlers: { onGlobalKeypress: 'globalKeypressHandler', onCommandFired: 'commandHandler', onRegisterButton: 'registerButton', onKeyboardDisabled: 'keyboardDisabled', onClearEditBox: 'clearInput' }, isEnabled: true, disableCommandKey: function (inSender, inEvent) { this.waterfall('onDisableButton', inEvent); }, keyboardDisabled: function (inSender, inEvent) { if (inEvent.status) { _.each(this.buttons, function (btn) { if (!btn.hasClass('btnkeyboard-inactive')) { btn.setDisabled(true); btn.addClass('btnkeyboard-inactive'); } }); this.isEnabled = false; } else { _.each(this.buttons, function (btn) { if (btn.disabled) { btn.setDisabled(false); btn.removeClass('btnkeyboard-inactive'); } }); this.isEnabled = true; } }, /** * Managing key up events. KeyDown or KeyPress is not properly * working in Android Chrome 26 */ globalKeypressHandler: function (inSender, inEvent) { var which = inEvent.keyboardEvent.which, actualStatus = null, actualChar, keeper; //Issue 25013. This flag is checked by keypressHandler function in ob-terminal-component.js if (OB && OB.MobileApp && OB.MobileApp.model && OB.MobileApp.model.get('useBarcode')) { OB.MobileApp.keyPressProcessed = true; } if (which >= 96 && which <= 105) { which -= 48; } if (which === 46) { //Handle DELETE key this.doCommandFired({ key: "line:delete" }); } actualChar = String.fromCharCode(which); if (which === 107) { actualChar = '+'; } if (which === 111 || which === 191) { actualChar = '/'; } if (which === 186) { actualChar = ':'; } if (which === 109 || which === 189) { actualChar = '-'; } if (which === 8) { //Handle BACKSPACE key OB.MobileApp.view.scanningFocus(); this.writeCharacter('del'); return; } else if (which === 110) { //Handle numeric keypad dot (.) this.writeCharacter(OB.Format.defaultDecimalSymbol); return; } else if (which === 190) { //Handle keyboard dot (.) character this.writeCharacter(OB.Format.defaultDecimalSymbol); return; } if (actualChar && actualChar.match(this.keyMatcher)) { this.writeCharacter(actualChar); } else if ((which === 13 && !OB.UTIL.isIOS()) || (OB.UTIL.isIOS() && inEvent.enterEvent)) { //Handle ENTER key actualStatus = this.getStatus(); keeper = document.getElementById('_focusKeeper'); if (OB.MobileApp.view.scanMode) { // scanning using focusKeeper, take the value in the focusKeeper // some scanners do not send events for each character, that's why // the whole contents of focusKeeper are taken if (keeper) { this.$.editbox.setContent(keeper.value); keeper.value = ''; } } else { if (keeper) { keeper.value = ''; this.$.editbox.setContent(this.$.editbox.getContent()); } } if (this.$.editbox.getContent() === '0') { this.doCommandFired({ key: "OK" }); } else if (actualStatus) { this.execCommand(actualStatus, this.getString()); } else { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_KeypadTargetMissing')); } } else if (which === 107 || which === 109) { //Handle + and - keys if (!OB.MobileApp.view.scanMode || !OB.MobileApp.scanning) { this.doCommandFired({ key: actualChar }); } } else if (OB.Format.defaultDecimalSymbol === '.') { //Handle any keypress except any kind of dot (.) this.writeCharacter(actualChar); } }, virtualKeypressHandler: function (key, options) { var t; if (options && options.fromPopup) { this.waterfall('onCloseAllPopups'); } if (key.match(this.keyMatcher) || (key === 'del')) { this.writeCharacter(key); } else { this.doCommandFired({ key: key }); } }, writeCharacter: function (character) { var t; if (character.match(this.keyMatcher) && this.isEnabled) { t = this.$.editbox.getContent(); this.$.editbox.setContent(t + character); } else if (character === 'del') { t = this.$.editbox.getContent(); if (t.length > 0) { this.$.editbox.setContent(t.substring(0, t.length - 1)); } } }, setStatus: function (newstatus) { var btn = this.buttons[this.status]; if (btn && (btn.classButtonActive || (btn.owner && btn.owner.classButtonActive))) { btn.removeClass(btn.classButtonActive || btn.owner.classButtonActive); } this.status = newstatus; // sending the event to the components bellow this one this.waterfall('onStatusChanged', { status: newstatus }); // sending the event to the components above this one this.doStatusChanged({ payment: OB.MobileApp.model.paymentnames[this.status], status: this.status }); // set the right keypad by default if (this.namedkeypads[this.status]) { this.showKeypad(this.namedkeypads[this.status]); } else { this.showKeypad('basic'); } btn = this.buttons[this.status]; if (btn && (btn.classButtonActive || (btn.owner && btn.owner.classButtonActive))) { btn.addClass(btn.classButtonActive || btn.owner.classButtonActive); } }, getStatus: function () { //returns the current status of the keyboard. If the keyboard doesn't have any status then //the function returns the default action for the keyboard. if (this.status) { if (this.status === "") { return this.defaultcommand; } else { return this.status; } } return this.defaultcommand; }, execCommand: function (cmd, txt) { var cmddefinition = this.commands[cmd]; //if (!cmddefinition.permission || OB.POS.modelterminal.hasPermission(cmddefinition.permission)) { cmddefinition.action(this, txt); //} }, execStatelessCommand: function (cmd, txt) { this.commands[cmd].action(this, txt); }, getNumber: function () { return OB.I18N.parseNumber(this.getString()); }, getString: function () { var s = this.$.editbox.getContent(); this.$.editbox.setContent(''); return s; }, clearInput: function () { this.$.editbox.setContent(''); this.setStatus(''); }, commandHandler: function (inSender, inEvent) { var txt, me = this, cmd = inEvent.key; if (cmd === 'OK') { txt = this.getString(); // Shortcut to lock screen // Check for preference to disable lock screen, pass second parameter "true" to avoid false // positives on automatic roles. // hasPermission only loads preferences that belong to the mobile application in use. The // preference is defined using a posterminal preference property. Other applications that // want to disable the shortcut should deliver its own preference property and add it to // this if clause. if (txt === '0' && this.status === '' && !OB.POS.modelterminal.hasPermission('OBPOS_DisableLockShortcut', true)) { OB.MobileApp.model.lock(); return; } if (txt && this.status === '') { if (this.defaultcommand) { this.execCommand(this.defaultcommand, txt); } else { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_KeypadTargetMissing')); } } else if (txt && this.status !== '') { this.execCommand(this.status, txt); if (this.commands[this.status] && !this.commands[this.status].holdActive) { this.setStatus(''); } } } else if (this.commands[cmd]) { txt = this.getString(); if (this.commands[cmd].stateless) { // Stateless commands: add, subs, ... this.execStatelessCommand(cmd, txt); } else { // Statefull commands: quantity, price, discounts, payments ... if (txt && this.status === '') { // Short cut: type + action this.execCommand(cmd, txt); } else if (this.status === cmd && txt) { this.execCommand(cmd, txt); } else if (this.status === cmd) { // Reset status this.setStatus(''); } else { this.setStatus(cmd); } } if (this.commands[cmd].holdActive) { this.doHoldActiveCmd({ cmd: cmd }); } } else { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_NoActionDefined')); } }, registerButton: function (inSender, inEvent) { var me = this, button = inEvent.originator; if (button.command) { if (button.definition) { this.addCommand(button.command, button.definition); } if (button.command === '---') { // It is the null command button.command = false; } else if (!button.command.match(this.keyMatcher) && button.command !== 'OK' && button.command !== 'del' && button.command !== String.fromCharCode(13) && !this.commands[button.command]) { // is not a key and does not exists the command button.command = false; } else if (button.permission && !OB.MobileApp.model.hasPermission(button.permission)) { // does not have permissions. button.command = false; } } if (button.command) { button.$.button.tap = function () { if (button && button.definition && button.definition.includedInPopUp) { me.virtualKeypressHandler(button.command, { fromPopup: button.definition.includedInPopUp }); } else { me.virtualKeypressHandler(button.command); } }; this.addButton(button.command, button.$.button); button.$.button.removeClass('btnkeyboard-inactive'); } else { button.disableButton(button, { disabled: true }); } }, initComponents: function () { var me = this, undef; this.buttons = {}; // must be intialized before calling super, not after. this.activekeypads = []; this.namedkeypads = {}; this.inherited(arguments); // setting labels this.$.btnQty.$.button.setContent(OB.I18N.getLabel('OBMOBC_KbQuantity')); this.$.btnPrice.$.button.setContent(OB.I18N.getLabel('OBMOBC_KbPrice')); this.$.btnDiscount.$.button.setContent(OB.I18N.getLabel('OBMOBC_KbDiscount')); this.$.OBKEY_right_discounts_E.$.button.setContent(OB.I18N.getLabel('OBMOBC_KbDiscount')); if (this.buttonsDef) { if (this.buttonsDef.sideBar) { if (this.buttonsDef.sideBar.plusI18nLbl !== undef) { this.$.plusBtn.setLabel(OB.I18N.getLabel(this.buttonsDef.sideBar.plusI18nLbl)); } if (this.buttonsDef.sideBar.minusI18nLbl !== undef) { this.$.minusBtn.setLabel(OB.I18N.getLabel(this.buttonsDef.sideBar.minusI18nLbl)); } if (this.buttonsDef.sideBar.qtyI18nLbl !== undef) { this.$.btnQty.setLabel(OB.I18N.getLabel(this.buttonsDef.sideBar.qtyI18nLbl)); } if (this.buttonsDef.sideBar.priceI18nLbl !== undef) { this.$.btnPrice.setLabel(OB.I18N.getLabel(this.buttonsDef.sideBar.priceI18nLbl)); } if (this.buttonsDef.sideBar.discountI18nLbl !== undef) { this.$.btnDiscount.setLabel(OB.I18N.getLabel(this.buttonsDef.sideBar.discountI18nLbl)); } } } this.state = new Backbone.Model(); this.$.toolbarcontainer.destroyComponents(); this.$.keypadcontainer.destroyComponents(); this.showSidepad('sidedisabled'); if (this.sideBarEnabled) { this.$.sideenabled.show(); this.$.sidedisabled.hide(); this.$.ticketDiscountsToolbar.hide(); this.$.sidecashup.hide(); } else { this.$.ticketDiscountsToolbar.hide(); this.$.sidecashup.hide(); this.$.sideenabled.hide(); this.$.sidedisabled.show(); } this.addKeypad('OB.UI.KeypadBasic'); this.showKeypad('basic'); }, addToolbar: function (newToolbar) { var toolbar = this.$.toolbarcontainer.createComponent({ toolbarName: newToolbar.name, shown: newToolbar.shown, keboard: this }); var emptyBtn = { kind: 'OB.UI.BtnSide', btn: {} }, i = 0, hasMore = newToolbar.buttons.length > this.maxButtons, displayedButtons = hasMore ? this.maxButtons - 1 : newToolbar.buttons.length, displayedEmptyButtons = hasMore ? 0 : this.maxButtons - newToolbar.buttons.length, btnDef, dialogButtons = {}; for (i = 0; i < newToolbar.buttons.length; i++) { btnDef = newToolbar.buttons[i]; if (i < displayedButtons) { // Send button to toolbar if (btnDef.command) { toolbar.createComponent({ kind: 'OB.UI.BtnSide', btn: btnDef }); } else { toolbar.createComponent(emptyBtn); } } else { // Send button to dialog. dialogButtons[btnDef.command] = btnDef; this.addCommand(btnDef.command, btnDef.definition); // It needs to register command before showing the button. } } if (hasMore) { // Add the button More.. toolbar.createComponent({ name: 'btnMore', keyboard: this, dialogButtons: dialogButtons, kind: 'OB.UI.ToolbarMore' }); } // populate toolbar up to maxButtons with empty buttons for (i = 0; i < displayedEmptyButtons; i++) { toolbar.createComponent(emptyBtn); } //A toolbar could be create async, so we will hide it after creation. toolbar.hide(); }, addToolbarComponent: function (newToolbar) { this.$.toolbarcontainer.createComponent({ kind: newToolbar, keyboard: this }); }, showToolbar: function (toolbarName) { this.show(); enyo.forEach(this.$.toolbarcontainer.getComponents(), function (toolbar) { if (toolbar.toolbarName === toolbarName) { toolbar.render(); toolbar.show(); if (toolbar.shown) { toolbar.shown(); } } else { toolbar.hide(); } }, this); }, addCommand: function (cmd, definition) { this.commands[cmd] = definition; }, addButton: function (cmd, btn) { if (this.buttons[cmd]) { if (this.buttons[cmd].add) { this.buttons[cmd] = this.buttons[cmd].add(btn); } } else { this.buttons[cmd] = btn; } }, addKeypad: function (keypad) { var keypadconstructor = enyo.constructorForKind(keypad); this.activekeypads.push(keypadconstructor.prototype.padName); if (keypadconstructor.prototype.padPayment) { this.namedkeypads[keypadconstructor.prototype.padPayment] = keypadconstructor.prototype.padName; } this.$.keypadcontainer.createComponent({ kind: keypad, keyboard: this }).render().hide(); }, showKeypad: function (keypadName) { var firstLabel = null, foundLabel = false, existsLabel = false; enyo.forEach(this.$.keypadcontainer.getComponents(), function (pad) { if (!firstLabel) { firstLabel = pad.label; } else if (foundLabel) { this.state.set('keypadNextLabel', pad.label); foundLabel = false; } if (pad.padName === keypadName) { this.state.set('keypadName', keypadName); foundLabel = true; existsLabel = true; pad.show(); // Set the right payment status. If needed. if (pad.padPayment && this.status !== pad.padPayment) { this.setStatus(pad.padPayment); } } else { pad.hide(); } }, this); if (foundLabel) { this.state.set('keypadNextLabel', firstLabel); } // if keypadName does not exists show the 'basic' panel that always exists if (!existsLabel) { this.showKeypad('basic'); } }, showNextKeypad: function () { var i, max, current = this.state.get('keypadName'), pad; for (i = 0, max = this.activekeypads.length; i < max; i++) { if (this.activekeypads[i] === current) { this.showKeypad(i < this.activekeypads.length - 1 ? this.activekeypads[i + 1] : this.activekeypads[0]); break; } } }, showSidepad: function (sidepadname) { this.$.sideenabled.hide(); this.$.sidedisabled.hide(); this.$.ticketDiscountsToolbar.hide(); this.$.sidecashup.hide(); this.$[sidepadname].show(); } }); enyo.kind({ name: 'OB.UI.BtnSide', style: 'display:table; width:100%', handlers: { onGlobalKeypress: 'changeScanningMode' }, changeScanningMode: function () { if (this.btn.command === 'code') { OB.MobileApp.scanning = this.children[0].children[0].hasClass(this.btn.classButtonActive); } }, initComponents: function () { this.createComponent({ kind: 'OB.UI.ButtonKey', name: this.btn.command, label: this.btn.i18nLabel ? OB.I18N.getLabel(this.btn.i18nLabel) : this.btn.label, command: this.btn.command, permission: this.btn.permission, definition: this.btn.definition, classButtonActive: this.btn.classButtonActive || 'btnactive-green' }); } }); /** * Abstract class to handle barcode scan, findProductByBarcode and addProductToReceipt * methods need to be implemented */ enyo.kind({ name: 'OB.UI.AbstractBarcodeActionHandler', kind: enyo.Object, action: function (keyboard, txt) { if (keyboard.receipt && keyboard.receipt.get('isEditable') === false) { keyboard.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } var me = this; OB.debug("AbstractBarcodeActionHandler - txt: " + txt); this.findProductByBarcode(txt, function (product) { me.addProductToReceipt(keyboard, product); }, keyboard); } }); enyo.kind({ name: 'OB.UI.ToolbarMore', style: 'display:table; width:100%;', handlers: { onStatusChanged: 'statusChanged' }, components: [{ style: 'margin: 5px;', components: [{ kind: 'OB.UI.Button', classes: 'btnkeyboard', name: 'btn', label: '' }] }], initComponents: function () { this.inherited(arguments); this.$.btn.setContent(OB.I18N.getLabel('OBMOBC_More')); this.activegreen = false; }, tap: function () { if (this.activegreen) { this.keyboard.setStatus(''); } else { this.keyboard.$.OB_UI_MoreButtons.showMoreButtons(this.dialogButtons); } }, statusChanged: function (inSender, inEvent) { var status = inEvent.status; // Hide the More actions dialog if visible. if (this.keyboard.$.OB_UI_MoreButtons.hasNode()) { this.keyboard.$.OB_UI_MoreButtons.hide(); } if (this.activegreen) { this.$.btn.setContent(OB.I18N.getLabel('OBMOBC_More')); this.$.btn.removeClass('btnactive-green'); this.activegreen = false; } if (this.dialogButtons[status]) { this.$.btn.setContent(this.dialogButtons[status].label); this.$.btn.addClass('btnactive-green'); this.activegreen = true; } } }); enyo.kind({ name: 'OB.UI.MoreButtons', kind: 'OB.UI.Modal', topPosition: '125px', i18nHeader: 'OBMOBC_MoreButtons', sideButtons: [], body: { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;', classes: 'row-fluid', components: [{ name: 'morebuttonslist', classes: 'span12' }] }] }] }, showMoreButtons: function (dialogButtons) { // Destroy previous buttons this.$.body.$.morebuttonslist.destroyComponents(); // Create the new buttons. _.each(dialogButtons, function (btnDef) { this.$.body.$.morebuttonslist.createComponent({ kind: 'OB.UI.BtnSide', btn: btnDef }); }, this); // Render the new components created this.$.body.$.morebuttonslist.render(); // Finally show the dialog. this.show(); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.UI.ButtonContextMenu', kind: 'OB.UI.ToolbarButton', icon: 'btn-icon btn-icon-menu', handlers: { onLeftToolbarDisabled: 'disabledButton' }, disabledButton: function (inSender, inEvent) { this.setDisabled(inEvent.status); }, components: [{ name: 'leftIcon' }, { tag: 'span', style: 'display: inline-block;' }, { name: 'rightIcon' }], ontap: 'onButtonTap' }); enyo.kind({ name: 'OB.UI.ToolbarMenu', components: [{ kind: 'onyx.MenuDecorator', name: 'btnContextMenu', components: [{ kind: 'OB.UI.ButtonContextMenu', name: 'toolbarButton' }, { kind: 'onyx.Menu', classes: 'dropdown', name: 'menu', maxHeight: 600, scrolling: false, floating: true }] }], onButtonTap: function () { if (this.$.toolbarButton.hasClass('btn-over')) { this.$.toolbarButton.removeClass('btn-over'); } }, initComponents: function () { this.inherited(arguments); enyo.forEach(this.menuEntries, function (entry) { this.$.menu.createComponent(entry); }, this); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ enyo.kind({ name: 'OB.UI.KeypadBasic', padName: 'basic', components: [{ classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '/', command: '/', name: 'toolbarBtn1' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '*', command: '*', name: 'toolbarBtn2' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '%', command: '%', name: 'toolbarBtn3' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '7', command: '7', name: 'keypadBtn7' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '8', command: '8', name: 'keypadBtn8' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '9', command: '9', name: 'keypadBtn9' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '4', command: '4', name: 'keypadBtn4' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '5', command: '5', name: 'keypadBtn5' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '6', command: '6', name: 'keypadBtn6' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '1', command: '1', name: 'keypadBtn1' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '2', command: '2', name: 'keypadBtn2' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '3', command: '3', name: 'keypadBtn3' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span8', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '0', command: '0', name: 'keypadBtn0' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', name: 'decimalSymbol' }] }] }], initComponents: function () { var decimalButton, i; this.inherited(arguments); this.label = OB.I18N.getLabel('OBMOBC_KeypadBasic'); if (this.toolbarButtons) { i = 0; _.forEach(this.toolbarButtons, function (btn) { var btnName; i += 1; btnName = 'toolbarBtn' + i; this.$[btnName].setLabel(btn.i18nLabel ? OB.I18N.getLabel(btn.i18nLabel) : btn.label); if (btn.command) { this.$[btnName].command = btn.command; } this.$[btnName].doRegisterButton(); }, this); } // hack to set label and command after creation decimalButton = this.$.decimalSymbol; decimalButton.label = OB.Format.defaultDecimalSymbol; decimalButton.command = OB.Format.defaultDecimalSymbol; this.keyboard.registerButton(null, { originator: decimalButton }); decimalButton.$.button.setContent(OB.Format.defaultDecimalSymbol); decimalButton.$.button.setDisabled(false); decimalButton.$.button.removeClass('btnkeyboard-inactive'); } }); enyo.kind({ name: 'OB.UI.ButtonKey', events: { onAddCommand: '', onAddButton: '', onKeyCommandPressed: '', onRegisterButton: '' }, handlers: { onDisableButton: 'disableButton' }, style: 'margin: 5px;', classButtonActive: 'btnactive', classButton: '', classButtonDisabled: 'btnkeyboard-inactive', command: false, permission: null, label: null, components: [{ kind: 'OB.UI.Button', name: 'button', classes: 'btnkeyboard' }], disableButton: function (inSender, inEvent) { if (inSender === this || _.indexOf(inEvent.commands, this.command) !== -1) { this.$.button.setDisabled(inEvent.disabled); if (inEvent.disabled) { this.$.button.addClass(this.classButtonDisabled); } else { this.$.button.removeClass(this.classButtonDisabled); } } return true; }, setLabel: function (lbl) { this.$.button.setContent(lbl); }, initComponents: function () { var me = this; this.inherited(arguments); this.doRegisterButton(); this.$.button.addClass(this.classButton); this.$.button.setContent(this.label); if (this.isDisabled) { this.$.button.setDisabled(true); this.$.button.addClass(this.classButtonDisabled); } } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global _, Backbone, $, enyo */ enyo.kind({ name: 'OB.UI.iterateArray', published: { collection: null }, create: function () { var listName = this.name || ''; this.inherited(arguments); // helping developers if (!this.renderLine) { throw enyo.format('Your list %s needs to define a renderLine kind', listName); } if (!this.renderEmpty) { throw enyo.format('Your list %s needs to define a renderEmpty kind', listName); } if (this.collection) { this.collectionChanged(null); } }, collectionChanged: function (oldCollection) { var int = 0; this.destroyComponents(); if (!this.collection) { // set to null ? return; } for (int; int < this.collection.length; int++) { this._addModelToCollection(this.collection[int]); } this.render(); }, _addModelToCollection: function (model, index) { var tr = this.createComponent({ kind: this.renderLine, model: model, lblProperty: this.lblProperty, qtyProperty: this.qtyProperty }); tr.render(); //FIXME: can we add a model in the middle of a collection? // if (_.isNumber(index) && index < this.collection.length - 1) { // this.$el.children().eq(index + this.header).before(tr); // } else { // this.$el.append(tr); // } } }); enyo.kind({ name: 'OB.UI.List', kind: 'enyo.Select', published: { collection: null }, focus: function () { if (this.hasNode()) { this.hasNode().focus(); } }, create: function () { var listName = this.name || ''; this.inherited(arguments); // helping developers if (!this.renderLine) { throw enyo.format('Your list %s needs to define a renderLine kind', listName); } if (!this.renderEmpty) { throw enyo.format('Your list %s needs to define a renderEmpty kind', listName); } this.header = this.renderHeader ? 1 : 0; if (this.collection) { this.collectionChanged(null); } }, collectionChanged: function (oldCollection) { if (!this.collection) { // set to null ? return; } this.collection.on('change', function (model, prop) { var index = this.collection.indexOf(model); // FIXME: instead of recreate the item, we call changed? init ? // repeated items needs to reset the values // e.g. this.controlAtIndex(index + this.header).changed(); }, this); this.collection.on('add', function (model, prop, options) { this._addModelToCollection(model, options.index); }, this); this.collection.on('remove', function (model, prop, options) { var index = options.index; this.controlAtIndex(index + this.header).destroy(); }, this); this.collection.on('reset', function () { this.destroyComponents(); if (this.renderHeader) { this.createComponent({ kind: this.renderHeader }).render(); } this.collection.each(function (model) { this._addModelToCollection(model); }, this); }, this); }, _addModelToCollection: function (model, index) { var tr = this.createComponent({ kind: this.renderLine, model: model }); tr.render(); //FIXME: can we add a model in the middle of a collection? // if (_.isNumber(index) && index < this.collection.length - 1) { // this.$el.children().eq(index + this.header).before(tr); // } else { // this.$el.append(tr); // } } }); enyo.kind({ name: 'OB.UI.Table', published: { collection: null }, components: [{ name: 'theader' }, { name: 'tbody', tag: 'ul', classes: 'unstyled', showing: false }, { name: 'tinfo', showing: false, style: 'border-bottom: 1px solid #cccccc; padding: 15px; font-weight: bold; color: #cccccc' }, { name: 'tempty' }], create: function () { var tableName = this.name || ''; this.inherited(arguments); // helping developers if (!this.renderLine) { throw enyo.format('Your list %s needs to define a renderLine kind', tableName); } if (!this.renderEmpty) { throw enyo.format('Your list %s needs to define a renderEmpty kind', tableName); } if (this.collection) { this.collectionChanged(null); } }, collectionChanged: function (oldCollection) { this.selected = null; if (this.renderHeader && this.$.theader.getComponents().length === 0) { this.$.theader.createComponent({ kind: this.renderHeader }); } if (this.renderEmpty && this.$.tempty.getComponents().length === 0) { this.$.tempty.createComponent({ kind: this.renderEmpty }); } if (!this.collection) { // set to null? return; } this.collection.on('selected', function (model) { if (!model && this.listStyle) { if (this.selected) { this.selected.addRemoveClass('selected', false); } this.selected = null; } }, this); this.collection.on('add', function (model, prop, options) { this.$.tempty.hide(); this.$.tbody.show(); this._addModelToCollection(model, options.index); if (this.listStyle === 'list') { if (!this.selected) { model.trigger('selected', model); } } else if (this.listStyle === 'edit') { model.trigger('selected', model); } }, this); this.collection.on('remove', function (model, prop, options) { var index = options.index; this.$.tbody.getComponents()[index].destroy(); // controlAtIndex ? if (index >= this.collection.length) { if (this.collection.length === 0) { this.collection.trigger('selected'); } else { this.collection.at(this.collection.length - 1).trigger('selected', this.collection.at(this.collection.length - 1)); } } else { this.collection.at(index).trigger('selected', this.collection.at(index)); } if (this.collection.length === 0) { this.$.tbody.hide(); this.$.tempty.show(); } }, this); this.collection.on('reset', function (a, b, c) { var modelsel; this.$.tbody.hide(); this.$.tempty.show(); this.$.tbody.destroyComponents(); if (this.collection.size() === 0) { this.$.tbody.hide(); this.$.tempty.show(); this.collection.trigger('selected'); } else { this.$.tempty.hide(); this.$.tbody.show(); this.collection.each(function (model) { this._addModelToCollection(model); }, this); if (this.listStyle === 'list') { modelsel = this.collection.at(0); modelsel.trigger('selected', modelsel); } else if (this.listStyle === 'edit') { modelsel = this.collection.at(this.collection.size() - 1); modelsel.trigger('selected', modelsel); } } }, this); this.collection.on('info', function (info) { if (info) { this.$.tinfo.setContent(OB.I18N.getLabel(info)); this.$.tinfo.show(); } else { this.$.tinfo.hide(); } }, this); // XXX: Reseting to show the collection if registered with data this.collection.trigger('reset'); }, _addModelToCollection: function (model, index) { var tr = this.$.tbody.createComponent({ tag: 'li' }); tr.createComponent({ kind: this.renderLine, model: model }); tr.render(); model.on('change', function () { tr.destroyComponents(); tr.createComponent({ kind: this.renderLine, model: model }).render(); }, this); model.on('selected', function () { if (this.listStyle) { if (this.selected) { this.selected.addRemoveClass('selected', false); } this.selected = tr; this.selected.addRemoveClass('selected', true); // FIXME: OB.UTIL.makeElemVisible(this.node, this.selected); } }, this); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, window, OB */ enyo.kind({ name: 'OB.UI.ModalProfile', kind: 'OB.UI.ModalAction', handlers: { onSelectRole: 'roleSelected', onSelectOrganization: 'orgSelected' }, bodyContent: { style: 'background-color: #ffffff;', components: [{ components: [{ classes: 'properties-label', components: [{ name: 'roleLbl', style: 'padding: 5px 8px 0px 0px; font-size: 15px;' }] }, { kind: 'OB.UI.ModalProfile.Role', classes: 'properties-field', name: 'roleList' }] }, { style: 'clear: both' }, { name: 'orgSelector', components: [{ classes: 'properties-label', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'orgLbl' }] }, { kind: 'OB.UI.ModalProfile.Organization', classes: 'properties-field', name: 'orgList' }] }, { style: 'clear: both' }, { name: 'warehouseSelector', components: [{ classes: 'properties-label', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'warehouseLbl' }] }, { components: [{ kind: 'OB.UI.List', name: 'warehouseList', tag: 'select', classes: 'modal-dialog-profile-combo', renderEmpty: enyo.Control, renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get('id')); this.setContent(this.model.get('_identifier')); if (OB.MobileApp.model.get('context') && OB.MobileApp.model.get('context').user && OB.MobileApp.model.get('context').user.defaultWarehouse && this.model.get('id') === OB.MobileApp.model.get('context').user.defaultWarehouse) { this.parent.setSelected(this.parent.children.length - 1); } } }) }] }] }, { style: 'clear: both' }, { components: [{ classes: 'properties-label', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'langLbl' }] }, { name: 'lang', components: [{ kind: 'OB.UI.List', name: 'langList', tag: 'select', classes: 'modal-dialog-profile-combo', renderEmpty: enyo.Control, renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get('id')); this.setContent(this.model.get('_identifier')); if (OB.Application && this.model.get('id') === OB.Application.language) { this.parent.setSelected(this.parent.children.length - 1); } } }) }] }] }, { style: 'clear: both' }, { components: [{ classes: 'properties-label', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'setAsDefaultLbl' }] }, { components: [{ classes: 'modal-dialog-profile-checkbox', components: [{ kind: 'OB.UI.CheckboxButton', name: 'defaultBox', classes: 'modal-dialog-btn-check' }] }] }] }, { style: 'clear: both' }] }, bodyButtons: { components: [{ style: 'clear: both' }, { kind: 'OB.UI.ProfileDialogApply' }, { kind: 'OB.UI.ProfileDialogCancel', name: 'profileCancelButton' }] }, roleSelected: function (inSender, inEvent) { // This code can be used to replace _.filter when underscore is upgraded to 1.4.4 // this.selectedRoleOptions = _.findWhere(this.availableRoles, { // id: inEvent.newRoleId // }); this.selectedRoleOptions = _.filter(this.availableRoles, function (role) { return role.id === inEvent.newRoleId; })[0]; this.organizations.reset(this.selectedRoleOptions.organizationValueMap); if (this.$.bodyContent) { this.$.bodyContent.$.orgList.changeOrganization(); // force redraw of warehouse list } }, orgSelected: function (inSender, inEvent) { // This code can be used to replace _.filter when underscore is upgraded to 1.4.4 // var whMap = _.findWhere(this.selectedRoleOptions.warehouseOrgMap, { // orgId: inEvent.newOrgId // }).warehouseMap; var whMap = _.filter(this.selectedRoleOptions.warehouseOrgMap, function (orgMap) { return orgMap.orgId === inEvent.newOrgId; })[0].warehouseMap; this.warehouses.reset(whMap); }, initComponents: function () { var proc, languages = new Backbone.Collection(), options, profileHandler = OB.MobileApp.model.get('profileHandlerUrl') || 'org.openbravo.mobile.core.login.ProfileUtils'; proc = new OB.DS.Process(profileHandler); this.inherited(arguments); this.roles = new Backbone.Collection(); this.organizations = new Backbone.Collection(); this.warehouses = new Backbone.Collection(); this.$.bodyContent.$.roleList.setCollection(this.roles); this.$.bodyContent.$.orgList.setCollection(this.organizations); this.$.bodyContent.$.warehouseList.setCollection(this.warehouses); this.$.bodyContent.$.langList.setCollection(languages); proc.exec({}, enyo.bind(this, function (response) { if (response.exception) { // we are offline... return; } this.availableRoles = response.role.roles; this.roles.reset(response.role.valueMap); if (this.$.bodyContent) { this.$.bodyContent.$.roleList.changeRole(); // force redraw of org list } languages.reset(response.language.valueMap); })); this.ctx = OB.MobileApp.model.get('context'); // labels this.$.bodyContent.$.roleLbl.setContent(OB.I18N.getLabel('OBMOBC_Role')); this.$.bodyContent.$.orgLbl.setContent(OB.I18N.getLabel('OBMOBC_Org')); this.$.bodyContent.$.warehouseLbl.setContent(OB.I18N.getLabel('OBMOBC_Warehouse')); this.$.bodyContent.$.langLbl.setContent(OB.I18N.getLabel('OBMOBC_Language')); this.$.bodyContent.$.setAsDefaultLbl.setContent(OB.I18N.getLabel('OBMOBC_SetAsDefault')); options = OB.MobileApp.model.get('profileOptions'); if (options) { this.$.bodyContent.$.orgSelector.setShowing(options.showOrganization); this.$.bodyContent.$.warehouseSelector.setShowing(options.showWarehouse); } this.setHeader(OB.I18N.getLabel('OBMOBC_ProfileDialogTitle')); }, show: function () { this.inherited(arguments); // Focus will be set on a button to avoid a redraw which will make // the focuskeeper visible this.$.bodyButtons.$.profileCancelButton.focus(); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ProfileDialogApply', isActive: true, isDefaultAction: true, tap: function () { var ajaxRequest, widgetForm = this.owner.owner.$.bodyContent.$, options = OB.MobileApp.model.get('profileOptions'), newLanguageId = widgetForm.langList.getValue(), newRoleId = widgetForm.roleList.getValue(), isDefault = widgetForm.defaultBox.checked, actionURL = '../../org.openbravo.client.kernel?command=save&_action=org.openbravo.client.application.navigationbarcomponents.UserInfoWidgetActionHandler', postData = { language: newLanguageId, role: newRoleId, 'default': isDefault }; if (!this.isActive) { return; } this.isActive = false; if (options) { if (options.showOrganization) { postData.organization = widgetForm.orgList.getValue(); } if (options.showWarehouse) { postData.warehouse = widgetForm.warehouseList.getValue(); } if (isDefault) { postData.defaultProperties = options.defaultProperties; } } window.localStorage.setItem('POSlanguageId', newLanguageId); ajaxRequest = new enyo.Ajax({ url: actionURL, cacheBust: false, method: 'POST', handleAs: 'json', contentType: 'application/json;charset=utf-8', data: JSON.stringify(postData), success: function (inSender, inResponse) { if (inResponse.result === 'success') { window.location.reload(); } else { OB.UTIL.showError(inResponse.result); } this.isActive = true; }, fail: function (inSender, inResponse) { OB.UTIL.showError(inResponse); this.isActive = true; } }); ajaxRequest.go(ajaxRequest.data).response('success').error('fail'); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ProfileDialogCancel', tap: function () { this.doHideThisPopup(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); } }); enyo.kind({ name: 'OB.UI.ModalProfile.Role', kind: 'OB.UI.List', classes: 'modal-dialog-profile-combo', events: { onSelectRole: '' }, handlers: { onchange: 'changeRole' }, renderEmpty: enyo.Control, renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get('id')); this.setContent(this.model.get('_identifier')); if (OB.MobileApp.model.get('context') && OB.MobileApp.model.get('context').role && this.model.get('id') === OB.MobileApp.model.get('context').role.id) { this.parent.setSelected(this.parent.children.length - 1); } } }), changeRole: function (inSender, inEvent) { var id = this.children[this.getSelected()]; if (OB.UTIL.isNullOrUndefined(id)) { return; } this.doSelectRole({ newRoleId: id.getValue() }); } }); enyo.kind({ name: 'OB.UI.ModalProfile.Organization', kind: 'OB.UI.List', classes: 'modal-dialog-profile-combo', events: { onSelectOrganization: '' }, handlers: { onchange: 'changeOrganization' }, renderEmpty: enyo.Control, renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get('id')); this.setContent(this.model.get('_identifier')); if (OB.MobileApp.model.get('context') && OB.MobileApp.model.get('context').organization && this.model.get('id') === OB.MobileApp.model.get('context').organization.id) { this.parent.setSelected(this.parent.children.length - 1); } } }), changeOrganization: function (inSender, inEvent) { var id = this.children[this.getSelected()]; if (OB.UTIL.isNullOrUndefined(id)) { return; } this.doSelectOrganization({ newOrgId: id.getValue() }); } }); enyo.kind({ name: 'OB.UI.Profile.SessionInfo', kind: 'OB.UI.Popup', classes: 'modal', components: [{ classes: 'widget-profile-title widget-profile-title-connection', name: 'connStatus' }, { style: 'height: 5px;' }, { kind: 'OB.UI.MenuAction', name: 'lockOption', allowHtml: true, tap: function () { this.owner.hide(); OB.MobileApp.model.lock(); } }, { style: 'height: 5px;' }, { kind: 'OB.UI.MenuAction', name: 'endSessionButton', i18nLabel: 'OBMOBC_EndSession', tap: function () { var me = this; if (this.owner.args && ((this.owner.args.model.get('order') && this.owner.args.model.get('order').get('lines').length > 0) || (this.owner.args.model.get('orderList') && this.owner.args.model.get('orderList').length > 1))) { this.owner.hide(); OB.UTIL.Approval.requestApproval( this.owner.args.model, 'OBPOS_approval.removereceipts', function (approved, supervisor, approvalType) { if (approved) { me.owner.hide(); OB.MobileApp.view.$.dialogsContainer.$.logoutDialog.show(); } }); } else { this.owner.hide(); OB.MobileApp.view.$.dialogsContainer.$.logoutDialog.show(); } } }, { style: 'height: 5px;' }], setConnectionStatus: function () { var connected = OB.MobileApp.model.get('connectedToERP'); this.$.connStatus.setContent(OB.I18N.getLabel(connected ? 'OBMOBC_Online' : 'OBMOBC_Offline')); this.$.connStatus.addRemoveClass('onlineicon', connected); this.$.connStatus.addRemoveClass('offlineicon', !connected); }, initComponents: function () { this.inherited(arguments); this.$.lockOption.setShowing(OB.MobileApp.model.get('supportsOffline')); this.$.lockOption.setLabel(OB.I18N.getLabel('OBMOBC_LogoutDialogLock') + '0\u21B5'); OB.MobileApp.model.on('change:connectedToERP', function () { this.setConnectionStatus(); }, this); this.setConnectionStatus(); } }); enyo.kind({ name: 'OB.UI.Profile.UserInfo', kind: 'OB.UI.Popup', classes: 'modal', components: [{ name: 'userWidget', kind: 'OB.UI.Profile.UserWidget' }, { style: 'height: 5px;' }, { kind: 'OB.UI.MenuAction', i18nLabel: 'OBMOBC_Profile', name: 'profileButton', tap: function () { this.owner.hide(); // Manual dropdown menu closure OB.MobileApp.view.$.dialogsContainer.$.profileDialog.show(); } }], show: function () { this.$.profileButton.setShowing(OB.MobileApp.model.hasPermission('OBMOBC_ChangeProfile')); this.inherited(arguments); }, initComponents: function () { this.inherited(arguments); OB.MobileApp.model.on('change:context', function () { var ctx = OB.MobileApp.model.get('context'); if (!ctx) { return; } this.$.userWidget.setUserName(ctx.user._identifier); this.$.userWidget.setUserRole(ctx.role._identifier); this.$.userWidget.setUserImg(ctx.img); }, this); } }); enyo.kind({ name: 'OB.UI.Profile.UserWidget', style: 'width: 100%', published: { userName: '', userRole: '', userImg: '' }, components: [{ //style: 'height: 60px; background-color: #FFF899;', classes: 'widget-profile-title ', components: [{ style: 'float: left; width: 55px; margin: -15px 0px 0px 6px;', components: [{ kind: 'OB.UI.Thumbnail', 'default': '../org.openbravo.mobile.core/assets/img/anonymous-icon.png', name: 'img' }] }, { style: 'float: left; margin: 6px 0px 0px 0px; line-height: 150%;', components: [{ components: [{ components: [{ tag: 'span', style: 'font-weight: 800; margin: 0px 0px 0px 5px;', name: 'username' }] }] }] }, { style: 'float: left; margin: 6px 0px 0px 0px; line-height: 150%;', components: [{ components: [{ components: [{ tag: 'span', style: 'font-weight: 800; margin: 0px 0px 0px 5px;', content: '-' }] }] }] }, { style: 'float: left; margin: 6px 0px 0px 0px; line-height: 150%;', components: [{ components: [{ components: [{ tag: 'span', style: 'font-weight: 800; margin: 0px 0px 0px 5px;', name: 'role' }] }] }] }] }], userNameChanged: function () { this.$.username.setContent(this.userName); }, userRoleChanged: function () { this.$.role.setContent(this.userRole); }, userImgChanged: function () { this.$.img.setImg(this.userImg); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalOnline', bodyContent: { content: '' }, bodyButtons: { components: [{ kind: 'OB.UI.ModalDialogButton', content: '', isDefaultAction: true, tap: function () { this.doHideThisPopup(); OB.MobileApp.model.lock(); } }, { kind: 'OB.UI.ModalDialogButton', content: '', tap: function () { this.doHideThisPopup(); } }] }, initComponents: function () { this.header = OB.I18N.getLabel('OBMOBC_Online'); this.bodyContent.content = OB.I18N.getLabel('OBMOBC_OnlineConnectionHasReturned'); this.bodyButtons.components[0].content = OB.I18N.getLabel('OBMOBC_LblLoginAgain'); this.bodyButtons.components[1].content = OB.I18N.getLabel('OBMOBC_LblCancel'); this.inherited(arguments); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.UI.ModalLogout', kind: 'OB.UI.ModalAction', bodyContent: { kind: 'enyo.Control', name: 'label' }, bodyButtons: { components: [{ kind: 'OB.UI.LogoutDialogLogout' }, //,{ kind: 'OB.UI.LogoutDialogLock' //Disabled until feature be ready} { kind: 'OB.UI.LogoutDialogCancel' }] }, initComponents: function () { this.inherited(arguments); this.setHeader(OB.I18N.getLabel('OBMOBC_LogoutDialogLogout')); this.$.bodyContent.$.label.setContent(OB.I18N.getLabel('OBMOBC_LogoutDialogText')); } }); enyo.kind({ name: 'OB.UI.LogoutDialogCancel', kind: 'OB.UI.ModalDialogButton', tap: function () { this.doHideThisPopup(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); } }); enyo.kind({ name: 'OB.UI.LogoutDialogLogout', kind: 'OB.UI.ModalDialogButton', isDefaultAction: true, tap: function () { this.doHideThisPopup(); OB.UTIL.showLoggingOut(true); OB.MobileApp.model.logout(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LogoutDialogLogout')); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.LogoutDialogLock', tap: function () { this.doHideThisPopup(); OB.MobileApp.model.lock(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LogoutDialogLock')); } }); /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ enyo.kind({ name: 'OB.UI.ToolbarMenuComponent', kind: 'onyx.Menu', show: function (args) { var me = this; if (me.autoDismiss) { me.autoDismiss = false; this.inherited(arguments); setTimeout(function () { //The autoDismiss is activated only after a small delay, to prevent issue 24582 from happening me.autoDismiss = true; }, 100); } else { this.inherited(arguments); } } }); enyo.kind({ name: 'OB.UI.ToolbarMenu', published: { disabled: false }, components: [{ kind: 'onyx.MenuDecorator', name: 'btnContextMenu', components: [{ kind: 'OB.UI.ButtonContextMenu', name: 'mainMenuButton' }, { handlers: { onDestroyMenu: 'destroyMenu' }, destroyMenu: function () { // This function will be called when the window is resized, // to avoid a strange problem which happens when a device is rotated // while the menu is open (see issue https://issues.openbravo.com/view.php?id=23669) this.hide(); var element = document.getElementById(this.id); if (element && element.parentNode) { element.parentNode.removeChild(element); } }, kind: 'OB.UI.ToolbarMenuComponent', classes: 'dropdown', name: 'menu', maxHeight: 600, scrolling: false, floating: true, autoDismiss: true, components: [{ name: "menuScroller", kind: "enyo.Scroller", defaultKind: "onyx.MenuItem", vertical: "auto", classes: "enyo-unselectable", maxHeight: "600px", horizontal: 'hidden', strategyKind: "TouchScrollStrategy" }] }] }], onButtonTap: function () { // disable focus keeper while showing the menu this.originalSanMode = OB.MobileApp.view.scanMode; OB.MobileApp.view.scanningFocus(false, true); if (this.$.mainMenuButton.hasClass('btn-over')) { this.$.mainMenuButton.removeClass('btn-over'); } }, disabledChanged: function () { this.$.mainMenuButton.setDisabled(this.disabled); }, initComponents: function () { this.inherited(arguments); if (this.disabled !== undefined) { this.$.mainMenuButton.setDisabled(this.disabled); } enyo.forEach(this.menuEntries, function (entry) { this.$.menuScroller.createComponent(entry); }, this); } }); enyo.kind({ name: 'OB.UI.MenuAction', permission: null, published: { label: null }, handlers: { onHideButton: 'doHideButton' }, components: [{ name: 'lbl', allowHtml: true, style: 'padding: 12px 5px 12px 15px;', classes: 'dropdown-menuitem' }], tap: function () { if (this.disabled) { return true; } // restore focus keeper to its previous status OB.MobileApp.view.scanningFocus(this.parent.parent.parent.parent.parent.parent.originalSanMode); this.parent.parent.parent.parent.hide(); // Manual dropdown menu closure if (this.eventName) { this.bubble(this.eventName); } }, setDisabled: function (value) { this.disabled = value; if (value) { this.addClass('disabled'); } else { this.removeClass('disabled'); } }, labelChanged: function () { this.$.lbl.setContent(this.label); }, adjustVisibilityBasedOnPermissions: function () { if (this.permission && !OB.MobileApp.model.hasPermission(this.permission)) { this.hide(); } }, doHideButton: function (inSender, inEvent) { var isException = false; if (this.fixed) { // Fixed menu entries cannot be hidden. return; } if (inEvent && inEvent.exceptions) { isException = inEvent.exceptions.indexOf(this.name) !== -1; } if (!isException) { this.hide(); } }, initComponents: function () { this.inherited(arguments); this.$.lbl.setContent(this.i18nLabel ? OB.I18N.getLabel(this.i18nLabel) : this.label); this.adjustVisibilityBasedOnPermissions(); } }); enyo.kind({ kind: 'OB.UI.MenuAction', name: 'OB.UI.MenuWindowItem', init: function (model) { this.model = model; }, tap: function () { var me = this; if (this.disabled) { return true; } this.parent.parent.parent.parent.hide(); // Manual dropdown menu closure if (OB.POS.modelterminal.isWindowOnline(this.route) === true) { if (!OB.MobileApp.model.get('connectedToERP')) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowRequiresOnline')); return; } if (OB.MobileApp.model.get('loggedOffline') === true) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowOfflineLogin')); return; } } if (!OB.MobileApp.model.hasPermission(this.route)) { return; } OB.UTIL.HookManager.executeHooks('OBMOBC_PreWindowOpen', { context: this, windows: OB.MobileApp.windowRegistry.registeredWindows }, function (args) { if (args && args.cancellation && args.cancellation === true) { return true; } if (me.route) { OB.MobileApp.model.navigate(me.route); } if (me.url) { window.open(me.url, '_blank'); } }); } }); enyo.kind({ name: 'OB.UI.ButtonContextMenu', kind: 'OB.UI.ToolbarButton', icon: 'btn-icon btn-icon-menu', handlers: { onLeftToolbarDisabled: 'disabledButton' }, disabledButton: function (inSender, inEvent) { this.setDisabled(inEvent.status); }, components: [{ name: 'leftIcon' }, { tag: 'span', style: 'display: inline-block;' }, { name: 'rightIcon' }], ontap: 'onButtonTap', initComponents: function () { this.inherited(arguments); if (this.icon) { this.$.leftIcon.addClass(this.icon); } if (this.iconright) { this.$.rightIcon.addClass(this.iconright); } } }); /** * This is the standard menu showing online and user info. * It can be extended to include window's custom entries. */ enyo.kind({ name: 'OB.UI.MainMenu', classes: 'span2', initComponents: function () { this.inherited(arguments); this.createComponent({ kind: 'OB.UI.MainMenuContents', name: 'menuHolder', style: 'margin-left:5px; margin-right:5px', customMenuEntries: this.customMenuEntries, showWindowsMenu: this.showWindowsMenu }); } }); enyo.kind({ name: 'OB.UI.MenuSeparator', classes: 'dropdown-menudivider' }); enyo.kind({ name: 'OB.UI.MainMenuContents', kind: 'OB.UI.ToolbarMenu', menuEntries: [], init: function (model) { this.model = model; }, handlers: { onSessionInfo: 'showSession', onUserInfo: 'showUser', onDisableMenuEntry: 'disableMenuEntry', onHideButtons: 'doHideButtons' }, events: { onShowPopup: '' }, showSession: function () { this.doShowPopup({ popup: 'profileSessionInfo', args: { model: this.model } }); }, showUser: function () { this.doShowPopup({ popup: 'profileUserInfo' }); }, setConnected: function () { var menuEntry, connected; if (!this.$.menu) { // menu is not already built... return; } menuEntry = this.$.menuScroller.$.connStatusButton; connected = OB.MobileApp.model.get('connectedToERP'); menuEntry.$.lbl.setStyle('padding: 12px 5px 12px 15px; margin-left: 20px;'); menuEntry.setLabel(OB.I18N.getLabel(connected ? 'OBMOBC_Online' : 'OBMOBC_Offline')); menuEntry.addRemoveClass('onlineicon', connected); menuEntry.addRemoveClass('offlineicon', !connected); }, disableMenuEntry: function (inSender, inEvent) { var entry = this.$.menu.$[inEvent.entryName], disable; if (!entry) { return true; } disable = inEvent.disable !== false; entry.setDisabled(disable); return true; }, doHideButtons: function (inSender, inEvent) { this.waterfall('onHideButton', inEvent); }, getMenuComponent: function (componentName) { var objComp; objComp = _.find(this.$.menuScroller.controls, function (item) { if (!OB.UTIL.isNullOrUndefined(item.$.lbl) && !OB.UTIL.isNullOrUndefined(item.$.lbl.content) && item.$.lbl.content === componentName) { return true; } }); return objComp; }, initComponents: function () { this.menuEntries = []; this.menuEntries.push({ kind: 'OB.UI.MenuAction', name: 'connStatusButton', classes: 'menu-connection', eventName: 'onSessionInfo' }); if (this.customMenuEntries && this.customMenuEntries.length > 0) { this.menuEntries.push({ kind: 'OB.UI.MenuSeparator' }); _.forEach(this.customMenuEntries, function (entry) { this.menuEntries.push(entry); }, this); } if (this.showWindowsMenu) { // show entries for all registered windows this.menuEntries.push({ kind: 'OB.UI.MenuSeparator' }); enyo.forEach(OB.MobileApp.model.windows.filter(function (window) { // show in menu only the ones with menuPosition return window.get('menuPosition'); }), function (window) { this.menuEntries.push({ name: 'OB.UI.MenuWindowItem.' + window.get('menuI18NLabel'), kind: 'OB.UI.MenuWindowItem', label: window.get('menuLabel'), i18nLabel: window.get('menuI18NLabel'), route: window.get('route'), permission: window.get('permission') }); }, this); } this.menuEntries.push({ kind: 'OB.UI.MenuSeparator' }); this.menuEntries.push({ name: 'OB.UI.MenuUserInfo', kind: 'OB.UI.MenuAction', classes: 'dropdown-menuitem', i18nLabel: 'OBMOBC_User', eventName: 'onUserInfo' }); this.inherited(arguments); OB.MobileApp.model.on('change:connectedToERP', function () { this.setConnected(); }, this); this.setConnected(); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _*/ enyo.kind({ name: 'OB.UI.ModalReceiptProperties', kind: 'OB.UI.ModalAction', handlers: { onApplyChanges: 'applyChanges' }, bodyContent: { kind: 'Scroller', maxHeight: '225px', style: 'background-color: #ffffff;', thumb: true, horizontal: 'hidden', components: [{ name: 'attributes' }] }, bodyButtons: { components: [{ kind: 'OB.UI.ReceiptPropertiesDialogApply' }, { kind: 'OB.UI.ReceiptPropertiesDialogCancel' }] }, loadValue: function (mProperty) { this.waterfall('onLoadValue', { model: this.model, modelProperty: mProperty }); }, applyChanges: function (inSender, inEvent) { this.waterfall('onApplyChange', {}); return true; }, initComponents: function () { this.inherited(arguments); this.attributeContainer = this.$.bodyContent.$.attributes; enyo.forEach(this.newAttributes, function (natt) { this.$.bodyContent.$.attributes.createComponent({ kind: 'OB.UI.PropertyEditLine', name: 'line_' + natt.name, newAttribute: natt }); }, this); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ReceiptPropertiesDialogApply', isDefaultAction: true, events: { onApplyChanges: '' }, tap: function () { if (this.doApplyChanges()) { this.doHideThisPopup(); } }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ReceiptPropertiesDialogCancel', tap: function () { this.doHideThisPopup(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); } }); enyo.kind({ name: 'OB.UI.PropertyEditLine', components: [{ //style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', classes: 'properties-label', name: 'label', components: [{ name: 'labelLine', style: 'padding: 5px 8px 0px 0px; font-size: 15px;', content: '' }] }, { style: 'border: 1px solid #F0F0F0; float: left; width: 57%;', components: [{ name: 'newAttribute', classes: 'modal-dialog-receipt-properties-text', style: 'width: 98%' }] }, { style: 'clear: both' }], initComponents: function () { this.inherited(arguments); this.propertycomponent = this.$.newAttribute.createComponent(this.newAttribute); if (this.propertycomponent.height) { this.$.label.applyStyle('height', this.propertycomponent.height); } if (this.newAttribute.i18nLabel) { this.$.labelLine.content = OB.I18N.getLabel(this.newAttribute.i18nLabel); } else { this.$.labelLine.content = this.newAttribute.label; } } }); enyo.kind({ name: 'OB.UI.renderTextProperty', kind: 'enyo.Input', type: 'text', classes: 'input', style: 'width: 100%;', handlers: { onLoadValue: 'loadValue', onApplyChange: 'applyChange' }, events: { onSetProperty: '', onSetLineProperty: '' }, loadValue: function (inSender, inEvent) { if (this.modelProperty === inEvent.modelProperty) { if (inEvent.model && inEvent.model.get(this.modelProperty)) { this.setValue(inEvent.model.get(this.modelProperty)); } else { this.setValue(''); } } }, applyChange: function (inSender, inEvent) { return this.applyValue(inEvent.orderline); }, applyValue: function (orderline) { if (orderline) { this.doSetLineProperty({ line: orderline, property: this.modelProperty, value: this.getValue(), extraProperties: this.extraProperties }); } else { this.doSetProperty({ property: this.modelProperty, value: this.getValue(), extraProperties: this.extraProperties }); } return true; }, initComponents: function () { if (this.readOnly) { this.setAttribute('readonly', 'readonly'); } } }); enyo.kind({ name: 'OB.UI.renderTextMultiLineProperty', kind: 'enyo.TextArea', type: 'text', height: '90px', classes: 'input', style: 'width: 100%; height: 80px', handlers: { onLoadValue: 'loadValue', onApplyChange: 'applyChange', onkeydown: 'keydownHandler' }, events: { onSetProperty: '', onSetLineProperty: '' }, loadValue: function (inSender, inEvent) { if (this.modelProperty === inEvent.modelProperty) { if (inEvent.model && inEvent.model.get(this.modelProperty)) { this.setValue(inEvent.model.get(this.modelProperty)); } else { this.setValue(''); } } }, keydownHandler: function (inSender, inEvent) { if (inEvent.keyCode === 13) { // to allow multi line, prevent enter key to execute default command return true; } }, applyChange: function (inSender, inEvent) { return this.applyValue(inEvent.orderline); }, applyValue: function (orderline) { if (orderline) { this.doSetLineProperty({ line: orderline, property: this.modelProperty, value: this.getValue(), extraProperties: this.extraProperties }); } else { this.doSetProperty({ property: this.modelProperty, value: this.getValue(), extraProperties: this.extraProperties }); } return true; }, initComponents: function () { if (this.readOnly) { this.setAttribute('readonly', 'readonly'); } } }); enyo.kind({ name: 'OB.UI.renderBooleanProperty', kind: 'OB.UI.CheckboxButton', classes: 'modal-dialog-btn-check', handlers: { onLoadValue: 'loadValue', onApplyChange: 'applyChange', onLoadContent: 'loadContent' }, events: { onSetProperty: '', onSetLineProperty: '' }, loadValue: function (inSender, inEvent) { var i, splitResult, contentProperty, contentInModel; if (this.modelProperty === inEvent.modelProperty) { if (inEvent.model.get(this.modelProperty) !== undefined) { this.checked = inEvent.model.get(this.modelProperty); } if (this.checked) { this.addClass('active'); } else { this.removeClass('active'); } } if (this.modelContent !== undefined && this.modelContent !== "") { splitResult = this.modelContent.split(':'); if (splitResult.length > 0) { contentProperty = splitResult[0]; if (contentProperty === inEvent.modelProperty) { contentInModel = inEvent.model; for (i = 0; i < splitResult.length; i++) { contentInModel = contentInModel.get(splitResult[i]); } if (contentInModel !== undefined) { this.content = contentInModel; } } } } }, applyChange: function (inSender, inEvent) { if (this.disabled) { return true; } if (inEvent.orderline) { this.doSetLineProperty({ line: inEvent.orderline, property: this.modelProperty, value: this.checked, extraProperties: this.extraProperties }); } else { this.doSetProperty({ property: this.modelProperty, value: this.checked, extraProperties: this.extraProperties }); } }, initComponents: function () { if (this.readOnly) { this.setDisabled(true); this.setAttribute('disabled', 'disabled'); } } }); enyo.kind({ name: 'OB.UI.renderComboProperty', handlers: { onLoadValue: 'loadValue', onApplyChange: 'applyChange' }, events: { onSaveProperty: '' }, components: [{ kind: 'OB.UI.List', name: 'renderCombo', classes: 'combo', style: 'width: 100%; margin:0;', renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get(this.parent.parent.retrievedPropertyForValue)); this.setContent(this.model.get(this.parent.parent.retrievedPropertyForText)); } }), renderEmpty: 'enyo.Control' }], loadValue: function (inSender, inEvent) { if (this.modelProperty === inEvent.modelProperty) { this.$.renderCombo.setCollection(this.collection); this.fetchDataFunction(inEvent); } }, dataReadyFunction: function (data, inEvent) { var index = 0, result = null; if (data) { this.collection.reset(data.models); } else { this.collection.reset(null); return; } result = _.find(this.collection.models, function (option) { if (inEvent.model) { //Edit: select actual value if (option.get(this.retrievedPropertyForValue) === inEvent.model.get(this.modelProperty)) { return true; } } else { //New: select default value if (option.get(this.retrievedPropertyForValue) === this.defaultValue) { return true; } } index += 1; }, this); if (result) { this.$.renderCombo.setSelected(index); } else { this.$.renderCombo.setSelected(0); } }, applyChange: function (inSender, inEvent) { var selected = this.collection.at(this.$.renderCombo.getSelected()); if (selected) { inSender.model.set(this.modelProperty, selected.get(this.retrievedPropertyForValue)); } if (this.modelPropertyText) { inSender.model.set(this.modelPropertyText, selected.get(this.retrievedPropertyForText)); } }, initComponents: function () { this.inherited(arguments); if (this.readOnly) { this.setAttribute('readonly', 'readonly'); } } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var Session = Backbone.Model.extend({ modelName: 'Session', tableName: 'ad_session', entityName: 'Session', source: 'org.openbravo.retail.posterminal.Session', properties: ['id', 'user', 'terminal', 'active', '_identifier', '_idx'], propertyMap: { 'id': 'ad_session_id', 'user': 'ad_user_id', 'terminal': 'terminal', 'active': 'active', '_identifier': '_identifier', '_idx': '_idx' }, createStatement: 'CREATE TABLE IF NOT EXISTS ad_session (ad_session_id TEXT PRIMARY KEY , ad_user_id TEXT, terminal TEXT, active TEXT, _identifier TEXT , _idx NUMERIC)', dropStatement: 'DROP TABLE IF EXISTS ad_session', insertStatement: 'INSERT INTO ad_session(ad_session_id, ad_user_id, terminal, active, _identifier, _idx) VALUES (?, ?, ?, ?, ?, ?)', updateStatement: '', local: true }); OB.Data.Registry.registerModel(Session); }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var User = Backbone.Model.extend({ modelName: 'User', tableName: 'ad_user', entityName: 'User', source: 'org.openbravo.retail.posterminal.User', properties: ['id', 'name', 'password', 'terminalinfo', 'formatInfo', 'created', '_identifier', '_idx'], propertyMap: { 'id': 'ad_user_id', 'name': 'name', 'password': 'password', 'terminalinfo': 'terminalinfo', 'formatInfo': 'formatInfo', 'created': 'created', '_identifier': '_identifier', '_idx': '_idx' }, createStatement: 'CREATE TABLE IF NOT EXISTS ad_user (ad_user_id TEXT PRIMARY KEY , name TEXT , password TEXT , terminalinfo TEXT, formatInfo TEXT, created TEXT, _identifier TEXT , _idx NUMERIC)', dropStatement: 'DROP TABLE IF EXISTS ad_user', insertStatement: 'INSERT INTO ad_user(ad_user_id, name, password, terminalinfo, formatInfo, created, _identifier, _idx) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', updateStatement: '', local: true }); OB.Data.Registry.registerModel(User); }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ enyo.kind({ name: 'OB.UI.RenderProduct', kind: 'OB.UI.SelectButton', components: [{ style: 'float: left; width: 25%', components: [{ kind: 'OB.UI.Thumbnail', name: 'thumbnail' }] }, { style: 'float: left; width: 55%;', components: [{ name: 'identifier', style: 'padding-left: 5px;' }] }, { name: 'price', style: 'float: left; width: 20%; text-align: right; font-weight:bold;' }, { style: 'clear:both;' }], initComponents: function () { this.inherited(arguments); this.$.identifier.setContent(this.model.get('_identifier')); this.$.price.setContent(OB.I18N.formatCurrency(this.model.get('standardPrice'))); var image; if (OB.MobileApp.model.get('permissions')["OBPOS_retail.productImages"]) { image = OB.UTIL.getImageURL(this.model.get('id')); this.$.thumbnail.setImgUrl(image); } else { image = this.model.get('img'); this.$.thumbnail.setImg(image); } } }); enyo.kind({ name: 'OB.UI.RenderCategory', kind: 'OB.UI.SelectButton', components: [{ style: 'float: left; width: 25%', components: [{ kind: 'OB.UI.Thumbnail', name: 'thumbnail' }] }, { style: 'float: left; width: 75%;', components: [{ name: 'identifier', style: 'padding-left: 5px;' }, { style: 'clear:both;' }] }], initComponents: function () { this.inherited(arguments); this.addClass('btnselect-browse'); this.$.identifier.setContent(this.model.get('_identifier')); this.$.thumbnail.setImg(this.model.get('img')); } }); enyo.kind({ name: 'OB.UI.ProductBrowser', useCharacteristics: true, classes: 'row-fluid', components: [{ classes: 'span6', components: [{ kind: 'OB.UI.BrowseProducts', name: 'browseProducts' }] }, { classes: 'span6', components: [{ kind: 'OB.UI.BrowseCategories', name: 'browseCategories' }] }], init: function () { this.$.browseProducts.$.listProducts.useCharacteristics = this.useCharacteristics; this.$.browseCategories.$.listCategories.categories.on('selected', function (category) { this.$.browseProducts.$.listProducts.loadCategory(category); }, this); } }); enyo.kind({ name: 'OB.UI.BrowseCategories', style: 'overflow:auto; height: 612px; margin: 5px;', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px', components: [{ kind: 'OB.UI.ListCategories', name: 'listCategories' }] }] }); enyo.kind({ name: 'OB.UI.BrowseProducts', style: 'margin: 5px;', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px', components: [{ kind: 'OB.UI.ListProducts', name: 'listProducts' }] }] }); enyo.kind({ kind: 'OB.UI.ScrollableTableHeader', name: 'OB.UI.CategoryListHeader', style: 'padding: 10px; border-bottom: 1px solid #cccccc;', components: [{ style: 'line-height: 27px; font-size: 18px; font-weight: bold;', name: 'title', content: '' }], initComponents: function () { this.inherited(arguments); this.$.title.setContent(OB.I18N.getLabel('OBMOBC_LblCategories')); } }); enyo.kind({ name: 'OB.UI.ListCategories', components: [{ name: 'categoryTable', scrollAreaMaxHeight: '574px', listStyle: 'list', kind: 'OB.UI.ScrollableTable', renderHeader: 'OB.UI.CategoryListHeader', renderEmpty: 'OB.UI.RenderEmpty', renderLine: 'OB.UI.RenderCategory', columns: ['thumbnail', 'identifier'] }], init: function () { var me = this; this.categories = new OB.Collection.ProductCategoryList(); this.$.categoryTable.setCollection(this.categories); function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackBestSellerProducts(products, context) { if (products && products.length > 0) { var virtualBestSellerCateg = new OB.Model.ProductCategory(); virtualBestSellerCateg.createBestSellerCategory(); context.categories.add(virtualBestSellerCateg, { at: 0 }); } context.me.categories.reset(context.categories.models); } function successCallbackCategories(dataCategories, me) { var bestSellerCriteria, context; if (dataCategories && dataCategories.length > 0) { //search products bestSellerCriteria = { 'bestseller': 'true' }; context = { me: me, categories: dataCategories }; OB.Dal.find(OB.Model.Product, bestSellerCriteria, successCallbackBestSellerProducts, errorCallback, context); } else { me.categories.reset(); } } OB.Dal.find(OB.Model.ProductCategory, null, successCallbackCategories, errorCallback, this); } }); //This header is set dynamically //use scrollableTableHeaderChanged_handler method of scrollableTable to manage changes //me.$.productTable.setHeaderText(category.get('_identifier')); enyo.kind({ kind: 'OB.UI.ScrollableTableHeader', name: 'OB.UI.ProductListHeader', style: 'padding: 10px; border-bottom: 1px solid #cccccc;', components: [{ style: 'line-height: 27px; font-size: 18px; font-weight: bold;', name: 'title' }], setHeader: function (valueToSet) { this.$.title.setContent(valueToSet); }, getValue: function () { return this.$.title.getContent(); } }); enyo.kind({ name: 'OB.UI.ListProducts', events: { onAddProduct: '', onShowLeftSubWindow: '', onTabChange: '' }, components: [{ kind: 'OB.UI.ScrollableTable', name: 'productTable', scrollAreaMaxHeight: '574px', renderHeader: 'OB.UI.ProductListHeader', renderEmpty: 'OB.UI.RenderEmpty', renderLine: 'OB.UI.RenderProduct', columns: ['thumbnail', 'identifier', 'price', 'generic'] }], init: function () { var me = this; this.inherited(arguments); this.products = new OB.Collection.ProductList(); this.$.productTable.setCollection(this.products); this.products.on('click', function (model) { if (this.useCharacteristics) { if (!model.get('isGeneric')) { me.doAddProduct({ product: model }); } else { me.doTabChange({ tabPanel: 'searchCharacteristic', keyboard: false, edit: false, options: model }); } } else { me.doAddProduct({ product: model }); } }, this); }, loadCategory: function (category) { var criteria, me = this; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackProducts(dataProducts) { if (dataProducts && dataProducts.length > 0) { me.products.reset(dataProducts.models); } else { me.products.reset(); } // TODO me.$.productTable.getHeader().setHeader(category.get('_identifier')); } if (category) { if (category.get('id') === 'OBPOS_bestsellercategory') { criteria = { 'bestseller': 'true' }; if (this.useCharacteristics) { criteria.generic_product_id = null; } } else { criteria = { 'productCategory': category.get('id') }; if (this.useCharacteristics) { criteria.generic_product_id = null; } } criteria._orderByClause = 'upper(_identifier) asc'; OB.Dal.find(OB.Model.Product, criteria, successCallbackProducts, errorCallback); } else { this.products.reset(); this.title.text(OB.I18N.getLabel('OBMOBC_LblNoCategory')); } } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.UI.SearchProductHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onSearchAction: '', onClearAction: '' }, handlers: { onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px 10px 5px 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'productname', style: 'width: 100%;', minLengthToSearch: 2 }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }, { style: 'margin: 5px 0px 0px 0px;', components: [{ kind: 'OB.UI.List', name: 'productcategory', classes: 'combo', style: 'width: 100%', renderHeader: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue('__all__'); this.setContent(OB.I18N.getLabel('OBMOBC_SearchAllCategories')); } }), renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get('id')); this.setContent(this.model.get('_identifier')); } }), renderEmpty: 'enyo.Control' }] }] }], setHeaderCollection: function (valueToSet) { this.$.productcategory.setCollection(valueToSet); }, searchAction: function () { this.doSearchAction({ productCat: this.$.productcategory.getValue(), productName: this.$.productname.getValue() }); return true; }, clearAction: function () { this.$.productname.setValue(''); this.$.productcategory.setSelected(0); this.doClearAction(); } }); enyo.kind({ name: 'OB.UI.SearchProduct', style: 'margin: 5px; background-color: #ffffff; color: black; padding: 5px', published: { receipt: null }, handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, events: { onAddProduct: '' }, executeOnShow: function () { var me = this; setTimeout(function () { me.$.products.$.theader.$.searchProductHeader.$.productname.focus(); }, 400); }, components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ classes: 'row-fluid', style: 'border-bottom: 1px solid #cccccc;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.ScrollableTable', name: 'products', scrollAreaMaxHeight: '482px', renderHeader: 'OB.UI.SearchProductHeader', renderEmpty: 'OB.UI.RenderEmpty', renderLine: 'OB.UI.RenderProduct' }] }] }] }] }] }], init: function () { var me = this; this.inherited(arguments); this.categories = new OB.Collection.ProductCategoryList(); this.products = new OB.Collection.ProductList(); //first the main collection of the component this.$.products.setCollection(this.products); this.$.products.getHeader().setHeaderCollection(this.categories); function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackCategories(dataCategories, me) { if (dataCategories && dataCategories.length > 0) { me.categories.reset(dataCategories.models); } else { me.categories.reset(); } } this.products.on('click', function (model) { this.doAddProduct({ product: model }); }, this); OB.Dal.find(OB.Model.ProductCategory, null, successCallbackCategories, errorCallback, this); }, receiptChanged: function () { this.receipt.on('clear', function () { this.$.products.$.theader.$.searchProductHeader.$.productname.setContent(''); this.$.products.$.theader.$.searchProductHeader.$.productcategory.setContent(''); //A filter should be set before show products. -> Big data!! //this.products.exec({priceListVersion: OB.POS.modelterminal.get('pricelistversion').id, product: {}}); }, this); }, clearAction: function (inSender, inEvent) { this.products.reset(); }, searchAction: function (inSender, inEvent) { var criteria = {}, me = this; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } // Initializing combo of categories without filtering function successCallbackProducts(dataProducts) { if (dataProducts && dataProducts.length > 0) { me.products.reset(dataProducts.models); me.products.trigger('reset'); } else { OB.UTIL.showWarning("No products found"); me.products.reset(); } } if (inEvent.productName) { criteria._filter = { operator: OB.Dal.CONTAINS, value: inEvent.productName }; } if (inEvent.productCat && inEvent.productCat !== '__all__') { criteria.productCategory = inEvent.productCat; } OB.Dal.find(OB.Model.Product, criteria, successCallbackProducts, errorCallback); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.UI.BrandButton', style: 'width: 86%; padding: 0px;', classes: 'btnlink-white-simple', events: { onShowPopup: '' }, tap: function () { if (!this.disabled) { this.doShowPopup({ popup: 'modalproductbrand' }); } }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblBrand')); } }); enyo.kind({ name: 'OB.UI.SearchProductCharacteristicHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onSearchAction: '' }, handlers: { onFiltered: 'searchAction', onClearAllAction: 'clearAllAction' }, components: [{ style: 'padding: 10px 10px 5px 10px;', components: [{ style: 'display: table; width: 100%;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'productname', style: 'width: 100%;' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAllAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }, { style: 'margin: 5px 0px 0px 0px;', components: [{ kind: 'OB.UI.List', name: 'productcategory', classes: 'combo', style: 'width: 100%', renderHeader: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue('__all__'); this.setContent(OB.I18N.getLabel('OBMOBC_SearchAllCategories')); } }), renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get('id')); this.setContent(this.model.get('_identifier')); } }), renderEmpty: 'enyo.Control' }] }, { name: 'filteringBy', style: 'text-align: left; font-weight: bold; font-size: 15px; color: #aaaaaa' }] }], setHeaderCollection: function (valueToSet) { this.$.productcategory.setCollection(valueToSet); }, searchAction: function () { this.doSearchAction({ productCat: this.$.productcategory.getValue(), productName: this.$.productname.getValue(), skipProduct: false, skipProductCharacteristic: false }); return true; }, clearAllAction: function () { this.$.productname.setValue(''); this.$.productcategory.setSelected(0); this.$.filteringBy.setContent(''); this.parent.$.brandButton.removeClass('btnlink-yellow-bold'); this.parent.model.set('filter', []); this.parent.model.set('brandFilter', []); this.parent.genericParent = null; this.parent.products.reset(); this.doSearchAction({ productCat: this.$.productcategory.getValue(), productName: this.$.productname.getValue(), skipProduct: true, skipProductCharacteristic: false }); }, init: function () { var me = this; this.inherited(arguments); this.categories = new OB.Collection.ProductCategoryList(); this.products = new OB.Collection.ProductList(); //first the main collection of the component // this.$.products.setCollection(this.products); this.setHeaderCollection(this.categories); function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackCategories(dataCategories, me) { if (dataCategories && dataCategories.length > 0) { me.categories.reset(dataCategories.models); } else { me.categories.reset(); } } this.products.on('click', function (model) { this.doAddProduct({ product: model }); }, this); OB.Dal.find(OB.Model.ProductCategory, null, successCallbackCategories, errorCallback, this); } }); enyo.kind({ name: 'OB.UI.SearchProductCharacteristic', classes: 'span12', style: 'background-color: #ffffff; color: black; ', published: { receipt: null, genericParent: null }, handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction', onUpdateFilter: 'filterUpdate', onUpdateBrandFilter: 'brandFilterUpdate' }, events: { onAddProduct: '', onSearchAction: '', onClearAction: '', onTabChange: '' }, filterUpdate: function (inSender, inEvent) { var i, j, valuesIds, index, chValue = inEvent.value.value; valuesIds = this.model.get('filter').map(function (e) { return e.id; }); for (j = 0; j < chValue.length; j++) { index = valuesIds.indexOf(chValue[j].get('id')); if (index === -1) { if (chValue[j].get('checked')) { this.model.get('filter').push({ characteristic_id: chValue[j].get('characteristic_id'), id: chValue[j].get('id'), name: chValue[j].get('name'), checked: chValue[j].get('checked'), selected: chValue[j].get('selected') }); } } else { if (!chValue[j].get('checked')) { this.model.get('filter').splice(index, 1); } else { this.model.get('filter')[index] = { characteristic_id: chValue[j].get('characteristic_id'), id: chValue[j].get('id'), name: chValue[j].get('name'), checked: chValue[j].get('checked'), selected: chValue[j].get('selected') }; } } } this.model.set('filter', _.sortBy(this.model.get('filter'), function (e) { return e.characteristic_id; })); this.filteringBy(); this.doSearchAction({ productCat: this.$.searchProductCharacteristicHeader.$.productcategory.getValue(), productName: this.$.searchProductCharacteristicHeader.$.productname.getValue(), filter: this.model.get('filter'), skipProduct: false, skipProductCharacteristic: false }); return true; }, brandFilterUpdate: function (inSender, inEvent) { var i, j, valuesIds, index, brandValue = inEvent.value.value; valuesIds = this.model.get('brandFilter').map(function (e) { return e.id; }); for (j = 0; j < brandValue.length; j++) { index = valuesIds.indexOf(brandValue[j].get('id')); if (index === -1 && brandValue[j].get('checked')) { this.model.get('brandFilter').push({ id: brandValue[j].get('id'), name: brandValue[j].get('name') }); } else if (index !== -1 && (_.isUndefined(brandValue[j].get('checked')) || !brandValue[j].get('checked'))) { this.model.get('brandFilter').splice(index, 1); } } this.model.set('filter', _.sortBy(this.model.get('filter'), function (e) { return e.characteristic_id; })); this.filteringBy(); if (this.model.get('brandFilter').length > 0) { this.$.brandButton.addClass('btnlink-yellow-bold'); } else { this.$.brandButton.removeClass('btnlink-yellow-bold'); } this.doSearchAction({ productCat: this.$.searchProductCharacteristicHeader.$.productcategory.getValue(), productName: this.$.searchProductCharacteristicHeader.$.productname.getValue(), filter: this.model.get('filter'), skipProduct: false, skipProductCharacteristic: false }); return true; }, filteringBy: function () { var filteringBy = OB.I18N.getLabel('OBMOBC_FilteringBy'), selectedItems, i; selectedItems = _.compact(this.model.get('filter').map(function (e) { if (e.selected) { return e.name; } })); if ((_.isUndefined(this.genericParent) || _.isNull(this.genericParent)) && selectedItems.length === 0 && this.model.get('brandFilter').length === 0) { this.$.searchProductCharacteristicHeader.$.filteringBy.setContent(''); return true; } if (!_.isUndefined(this.genericParent) && !_.isNull(this.genericParent)) { filteringBy = filteringBy + ' ' + this.genericParent.get('_identifier'); if (selectedItems.length + this.model.get('brandFilter').length > 0) { filteringBy = filteringBy + ', '; } } for (i = 0; i < selectedItems.length; i++) { filteringBy = filteringBy + ' ' + selectedItems[i]; if (i !== selectedItems.length - 1 || (i === selectedItems.length - 1 && this.model.get('brandFilter').length > 0)) { filteringBy = filteringBy + ', '; } } for (i = 0; i < this.model.get('brandFilter').length; i++) { filteringBy = filteringBy + ' ' + this.model.get('brandFilter')[i].name; if (i !== this.model.get('brandFilter').length - 1) { filteringBy = filteringBy + ', '; } } this.$.searchProductCharacteristicHeader.$.filteringBy.setContent(filteringBy); }, executeOnShow: function (model) { var me = this, criteria = {}; this.doClearAction(); this.genericParent = model; this.doSearchAction({ productCat: this.$.searchProductCharacteristicHeader.$.productcategory.getValue(), productName: this.$.searchProductCharacteristicHeader.$.productname.getValue(), filter: this.model.get('filter'), skipProduct: !this.genericParent, skipProductCharacteristic: false }); this.filteringBy(); setTimeout(function () { me.parent.$.searchCharacteristicTabContent.$.searchProductCharacteristicHeader.$.productname.focus(); }, 200); }, components: [{ kind: 'OB.UI.SearchProductCharacteristicHeader', classes: 'span12', style: 'display: table-cell; ' }, { style: 'display: table; width:100%', components: [{ style: 'display: table-cell; width:30%', classes: 'row-fluid', components: [{ components: [{ kind: 'OB.UI.BrandButton', name: 'brandButton' }, { kind: 'OB.UI.ScrollableTable', name: 'productsCh', scrollAreaMaxHeight: '415px', renderEmpty: 'OB.UI.RenderEmptyCh', renderLine: 'OB.UI.RenderProductCh' }] }] }, { style: 'display: table-cell; width:70%; padding-right:5px; border-bottom: 1px solid #cccccc;', classes: 'row-fluid ', components: [{ classes: 'row-fluid', components: [{ kind: 'OB.UI.ScrollableTable', name: 'products', scrollAreaMaxHeight: '415px', renderEmpty: 'OB.UI.RenderEmpty', renderLine: 'OB.UI.RenderProduct' }] }] }] }], init: function (model) { this.model = model; var me = this, params = [], whereClause = ''; this.inherited(arguments); this.categories = new OB.Collection.ProductCategoryList(); this.products = new OB.Collection.ProductList(); this.productsCh = new OB.Collection.ProductCharacteristicList(); //first the main collection of the component this.$.products.setCollection(this.products); this.$.productsCh.setCollection(this.productsCh); // this.$.products.getHeader().setHeaderCollection(this.categories); function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackCategories(dataCategories, me) { if (dataCategories && dataCategories.length > 0) { me.categories.reset(dataCategories.models); } else { me.categories.reset(); } } function successCallbackProductCh(dataProductCh, me) { if (dataProductCh && dataProductCh.length > 0) { me.productsCh.reset(dataProductCh.models); } else { me.productsCh.reset(); } } this.products.on('click', function (model) { if (!model.get('isGeneric')) { me.doAddProduct({ product: model }); } else { me.doTabChange({ tabPanel: 'searchCharacteristic', keyboard: false, edit: false, options: model }); } }, this); OB.Dal.find(OB.Model.ProductCategory, null, successCallbackCategories, errorCallback, this); OB.Dal.query(OB.Model.ProductCharacteristic, 'select distinct(characteristic_id), _identifier from m_product_ch order by UPPER(_identifier) asc', [], successCallbackProductCh, errorCallback, this); }, receiptChanged: function () { this.receipt.on('clear', function () { this.$.searchProductCharacteristicHeader.$.productname.setContent(''); this.$.searchProductCharacteristicHeader.$.productcategory.setContent(''); //A filter should be set before show products. -> Big data!! //this.products.exec({priceListVersion: OB.POS.modelterminal.get('pricelistversion').id, product: {}}); }, this); }, clearAction: function (inSender, inEvent) { this.waterfall('onClearAllAction'); }, addWhereFilter: function (values) { if (values.productName) { this.whereClause = this.whereClause + ' and _filter like ?'; this.params.push('%' + values.productName + '%'); } if (values.productCat && values.productCat !== '__all__') { this.whereClause = this.whereClause + ' and m_product_category_id = ?'; this.params.push(values.productCat); } }, searchAction: function (inSender, inEvent) { this.params = []; this.whereClause = ''; var criteria = {}, me = this, filterWhereClause = '', valuesString = '', brandString = '', i, j; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } // Initializing combo of categories without filtering function successCallbackProducts(dataProducts) { if (dataProducts && dataProducts.length > 0) { me.products.reset(dataProducts.models); me.products.trigger('reset'); } else { OB.UTIL.showWarning("No products found"); me.products.reset(); } } function successCallbackProductCh(dataProductCh, me) { if (dataProductCh && dataProductCh.length > 0) { for (i = 0; i < dataProductCh.length; i++) { for (j = 0; j < me.model.get('filter').length; j++) { if (dataProductCh.models[i].get('characteristic_id') === me.model.get('filter')[j].characteristic_id) { dataProductCh.models[i].set('filtering', true); } } } me.productsCh.reset(dataProductCh.models); } else { me.productsCh.reset(); } } this.whereClause = this.whereClause + " where isGeneric = 'false'"; this.addWhereFilter(inEvent); if (this.genericParent) { this.whereClause = this.whereClause + ' and generic_product_id = ?'; this.params.push(this.genericParent.get('id')); } if (this.model.get('filter').length > 0) { for (i = 0; i < this.model.get('filter').length; i++) { if (i !== 0 && (this.model.get('filter')[i].characteristic_id !== this.model.get('filter')[i - 1].characteristic_id)) { filterWhereClause = filterWhereClause + ' and exists (select * from m_product_ch as char where ch_value_id in (' + valuesString + ') and char.m_product = product.m_product_id)'; valuesString = ''; } if (valuesString !== '') { valuesString = valuesString + ', ' + "'" + this.model.get('filter')[i].id + "'"; } else { valuesString = "'" + this.model.get('filter')[i].id + "'"; } if (i === this.model.get('filter').length - 1) { //last iteration filterWhereClause = filterWhereClause + ' and exists (select * from m_product_ch as char where ch_value_id in (' + valuesString + ') and char.m_product = product.m_product_id)'; valuesString = ''; } } } if (this.model.get('brandFilter').length > 0) { for (i = 0; i < this.model.get('brandFilter').length; i++) { brandString = brandString + "'" + this.model.get('brandFilter')[i].id + "'"; if (i !== this.model.get('brandFilter').length - 1) { brandString = brandString + ', '; } } filterWhereClause = filterWhereClause + ' and product.brand in (' + brandString + ')'; } if (!inEvent.skipProduct) { OB.Dal.query(OB.Model.Product, 'select * from m_product as product' + this.whereClause + filterWhereClause, this.params, successCallbackProducts, errorCallback, this); } if (!inEvent.skipProductCharacteristic) { if (this.model.get('filter').length > 0) { OB.Dal.query(OB.Model.ProductCharacteristic, 'select distinct(characteristic_id), _identifier from m_product_ch as prod_ch where exists (select * from m_product as product where 1=1 ' + filterWhereClause + ' and prod_ch.m_product = product.m_product_id) order by UPPER(_identifier) asc', [], successCallbackProductCh, errorCallback, this); } else { OB.Dal.query(OB.Model.ProductCharacteristic, 'select distinct(characteristic_id), _identifier from m_product_ch as prod_ch where exists (select * from m_product as product' + this.whereClause + ' and prod_ch.m_product = product.m_product_id) order by UPPER(_identifier) asc', this.params, successCallbackProductCh, errorCallback, this); } } } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone console _*/ // Promotion rules module depends directly on client kernel module so it is not necessary // to install Web POS to work with it, this makes dependency chain not to be as it should: // this code depending on WebPOS that provides OB.Model.Discounts. Hacking it here to allow // this dependency. window.OB = window.OB || {}; OB.Model = OB.Model || {}; OB.Model.Discounts = OB.Model.Discounts || {}; OB.Model.Discounts.discountRules = OB.Model.Discounts.discountRules || {}; //Fixed Percentage Discount OB.Model.Discounts.discountRules['697A7AB9FD9C4EE0A3E891D3D3CCA0A7'] = { async: false, implementation: function (discountRule, receipt, line) { var linePrice, totalDiscount, qty = OB.DEC.toBigDecimal(line.get('qty')), discount = OB.DEC.toBigDecimal(discountRule.get('discount')), discountedLinePrice, oldDiscountedLinePrice; linePrice = OB.DEC.toBigDecimal(line.get('discountedLinePrice') || line.get('price')); discountedLinePrice = linePrice.multiply(new BigDecimal('100').subtract(OB.DEC.toBigDecimal(discountRule.get('discount'))).divide(new BigDecimal('100'), 20, OB.DEC.getRoundingMode())); discountedLinePrice = OB.DEC.toNumber(discountedLinePrice); totalDiscount = OB.DEC.sub(OB.DEC.mul(OB.DEC.toNumber(linePrice), qty), OB.DEC.mul(discountedLinePrice, qty)); oldDiscountedLinePrice = !_.isNull(line.get('discountedLinePrice')) ? line.get('discountedLinePrice') : line.get('price'); if (oldDiscountedLinePrice < OB.DEC.div(totalDiscount, line.getQty())) { totalDiscount = OB.DEC.mul(oldDiscountedLinePrice, line.getQty()); } receipt.addPromotion(line, discountRule, { amt: OB.DEC.toNumber(totalDiscount) }); line.set('discountedLinePrice', discountedLinePrice); } }; /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone _*/ // Buy X and get Y as gift OB.Model.Discounts.discountRules['94AEA884F5AD4EABB72322832B9C5172'] = { async: true, implementation: function (discountRule, receipt, line, listener) { var applyingToLines = new Backbone.Collection(), criteria, promotionCandidates = line.get('promotionCandidates') || []; // This line is candidate for this promotion if (promotionCandidates.indexOf(discountRule.id) === -1) { promotionCandidates.push(discountRule.id); } line.set('promotionCandidates', promotionCandidates); // look for other lines that are candidates to apply this same rule receipt.get('lines').forEach(function (l) { if (l.get('promotionCandidates')) { l.get('promotionCandidates').forEach(function (candidateRule) { if (candidateRule === discountRule.id) { applyingToLines.add(l); } }); } }); // Query local DB to know detail about the rule (products and quantities) criteria = { priceAdjustment: discountRule.id }; OB.Dal.find(OB.Model.DiscountFilterProduct, criteria, function (products) { var chunks, distributed, totalAmt, promotionAmt = 0, alerts = ''; if (applyingToLines.length !== products.length) { // rule can't be applied because not all products are matched listener.trigger('completed'); return; } products.forEach(function (product) { var i, line, applyNtimes, qtyToGetGift, qtyAsGift; if (chunks === 0) { // already decided not to apply return; } for (i = 0; i < applyingToLines.length; i++) { if (applyingToLines.at(i).get('product').id === product.get('product')) { line = applyingToLines.at(i); break; } } if (!line) { // cannot apply the rule chunks = 0; return; } product.set('receiptLine', line); if (_.isUndefined(product.get('obdiscQty')) || _.isNull(product.get('obdiscQty'))) { qtyToGetGift = 0; } else { qtyToGetGift = product.get('obdiscQty'); } if (product.get('obdiscIsGift')) { if (_.isUndefined(product.get('obdiscGifqty')) || _.isNull(product.get('obdiscGifqty'))) { qtyAsGift = 0; } else { qtyAsGift = product.get('obdiscGifqty'); } applyNtimes = Math.floor(line.get('qty') / (qtyToGetGift + qtyAsGift || 1)); } else { applyNtimes = Math.floor(line.get('qty') / (qtyToGetGift || 1)); } if (!chunks || applyNtimes < chunks) { chunks = applyNtimes; } }); if (chunks === 0) { // Cannot apply, ensure the promotion is not applied applyingToLines.forEach(function (ln) { receipt.removePromotion(ln, discountRule); }); listener.trigger('completed', { alerts: OB.I18N.getLabel('OBPOS_DiscountAlert', [line.get('product').get('_identifier'), discountRule.get('printName') || discountRule.get('name')]) }); return; } // There are products enough to apply the rule // Enforce stop cascade after applying this rule discountRule.set('applyNext', false, { silent: true }); distributed = discountRule.get('oBDISCDistribute'); if (distributed) { totalAmt = products.reduce(function (total, product) { var l = product.get('receiptLine'); return OB.DEC.add(total, OB.DEC.mul(l.get('qty'), l.get('discountedLinePrice') || l.get('price'))); }, OB.DEC.Zero); // Apply N chunks to the free products products.where({ obdiscIsGift: true }).forEach(function (product) { var l = product.get('receiptLine'), lineAmt; lineAmt = OB.DEC.mul(OB.DEC.mul((l.get('discountedLinePrice') || l.get('price')), chunks), (product.get('obdiscQty') || 1)); if (distributed) { promotionAmt += lineAmt; } }); } // first loop calculated the total discount, now let's apply it products.forEach(function (product) { var l = product.get('receiptLine'), price = l.get('discountedLinePrice') || l.get('price'), actualAmt, giftQty; if (distributed) { actualAmt = l.get('qty') * price * promotionAmt / (totalAmt); if (product.get('obdiscIsGift')) { giftQty = product.get('obdiscGifqty'); if (giftQty) { // gift products are shown to user as free discountRule.set('qtyOffer', OB.DEC.mul(OB.DEC.toNumber(giftQty), chunks)); receipt.addPromotion(l, discountRule, { amt: OB.DEC.mul(OB.DEC.mul(price, chunks), giftQty), actualAmt: actualAmt }); } else { window.console.warn(OB.I18N.getLabel('OBPOS_DISCbuyXgiftYNotDefineGiftQty', [discountRule.get('printName') || discountRule.get('name'), l.get('product').get('_identifier')])); alerts += '\n' + OB.I18N.getLabel('OBPOS_DISCbuyXgiftYNotDefineGiftQty', [discountRule.get('printName') || discountRule.get('name'), l.get('product').get('_identifier')]); } } else { discountRule.set('qtyOffer', OB.DEC.mul(OB.DEC.toNumber(product.get('obdiscQty') || 1), chunks)); receipt.addPromotion(l, discountRule, { actualAmt: actualAmt }); } } else { // not distributed if (product.get('obdiscIsGift')) { giftQty = product.get('obdiscGifqty'); if (giftQty) { // apply just to free products N chunks discountRule.set('qtyOffer', OB.DEC.mul(OB.DEC.toNumber(giftQty), chunks)); receipt.addPromotion(l, discountRule, { amt: OB.DEC.mul(OB.DEC.mul(price, chunks), (product.get('obdiscGifqty') || 0)) }); } else { window.console.warn(OB.I18N.getLabel('OBPOS_DISCbuyXgiftYNotDefineGiftQty', [discountRule.get('printName') || discountRule.get('name'), l.get('product').get('_identifier')])); alerts += '\n' + OB.I18N.getLabel('OBPOS_DISCbuyXgiftYNotDefineGiftQty', [discountRule.get('printName') || discountRule.get('name'), l.get('product').get('_identifier')]); } } else { // create a fake discount to prevent cascade discountRule.set('qtyOffer', OB.DEC.mul(OB.DEC.toNumber(product.get('obdiscQty') || 1), chunks)); receipt.addPromotion(l, discountRule, { actualAmt: 0, hidden: true }); } } }); if (alerts) { listener.trigger('completed', { alerts: alerts }); } else { listener.trigger('completed'); } }, function () { window.console.error('Error querying for products', discountRule, receipt, line, arguments); listener.trigger('completed'); }); } }; /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone*/ // Buy X pay Y of different product OB.Model.Discounts.discountRules['312D41071ED34BA18B748607CA679F44'] = { async: false, implementation: function (discountRule, receipt, line) { var qty = BigDecimal.prototype.ZERO, x, y, chunks, i, ln, price, subtype, totalPrice = BigDecimal.prototype.ZERO, distributed, amt, distributionAmt = BigDecimal.prototype.ZERO, distributionQty = 0, distribution = [], applyingToLinesCollection = Backbone.Collection.extend({ comparator: function (line) { // To group sort by price desc, so we generate the best (for client) possible group return -(line.get('discountedLinePrice') || line.get('price')); } }), group, lQty, checkedQty, nextY, chunksInThisGroup, alerts, unitsToDiscount, unitsToCheck, discountedQty, avgPrice, applyingToLines = new applyingToLinesCollection(), promotionCandidates = line.get('promotionCandidates') || []; // This line is candidate for this promotion if (promotionCandidates.indexOf(discountRule.id) === -1) { promotionCandidates.push(discountRule.id); } line.set('promotionCandidates', promotionCandidates); // look for other lines that are candidates to apply this same rule receipt.get('lines').forEach(function (l) { if (l.get('promotionCandidates')) { l.get('promotionCandidates').forEach(function (candidateRule) { if (candidateRule === discountRule.id) { applyingToLines.add(l); qty = qty.add(OB.DEC.toBigDecimal(l.get('qty'))); } }); } }); // apply the rule x = discountRule.get('oBDISCX'); y = discountRule.get('oBDISCY'); subtype = discountRule.get('oBDISCSubtype') || 'CHEAPEST'; if (OB.DEC.toNumber(qty) >= x) { // Enforce stop cascade after applying this rule discountRule.set('applyNext', false, { silent: true }); chunks = OB.DEC.toNumber(qty.divideInteger(OB.DEC.toBigDecimal(x))); // Do the group unitsToCheck = chunks * x; group = new applyingToLinesCollection(); for (i = 0; i < applyingToLines.length; i++) { ln = applyingToLines.at(i); if (unitsToCheck > 0) { if (ln.get('qty') > unitsToCheck) { discountedQty = unitsToCheck; } else { discountedQty = ln.get('qty'); } unitsToCheck -= discountedQty; totalPrice = totalPrice.add(OB.DEC.toBigDecimal(ln.get('discountedLinePrice') || ln.get('price')).multiply(OB.DEC.toBigDecimal(discountedQty))); ln.set('qtyToApplyDisc', discountedQty); group.add(ln); } else { // discount has been completely applied, now ensure there's no other lines with it applyingToLines.remove(ln); i = i - 1; receipt.removePromotion(ln, discountRule); } } // calculate discount unitsToDiscount = chunks * (x - y); if (subtype === 'AVG') { avgPrice = totalPrice.divide(OB.DEC.toBigDecimal(chunks * x)); unitsToCheck = chunks * x; } distributed = discountRule.get('oBDISCDistribute'); nextY = x; checkedQty = BigDecimal.prototype.ZERO; for (i = 0; i < group.length; i++) { ln = group.at(i); price = OB.DEC.toBigDecimal(ln.get('discountedLinePrice') || ln.get('price')); lQty = OB.DEC.toBigDecimal(ln.get('qty')); checkedQty = checkedQty.add(lQty); if (subtype === 'CHEAPEST') { if (OB.DEC.toNumber(checkedQty) < nextY) { // Create a fake discount to mark this line as used by a discount // preventing cascade in this way discountRule.set('qtyOffer', OB.DEC.toNumber(checkedQty)); receipt.addPromotion(ln, discountRule, { actualAmt: 0, hidden: true }); } else { chunksInThisGroup = 0; while (nextY <= OB.DEC.toNumber(checkedQty)) { chunksInThisGroup += x - y; nextY += x; } amt = price.multiply(OB.DEC.toBigDecimal(chunksInThisGroup)); if (distributed) { distributionAmt = distributionAmt.add(amt); distributionQty += chunksInThisGroup; distribution[i] = OB.DEC.toNumber(amt); } else { discountRule.set('qtyOffer', discountedQty); receipt.addPromotion(ln, discountRule, { amt: OB.DEC.toNumber(amt) }); } } } else { // Discount AVG if (ln.get('qty') > unitsToCheck) { discountedQty = unitsToCheck; } else { discountedQty = ln.get('qty'); } unitsToCheck -= discountedQty; discountedQty = OB.DEC.toBigDecimal(discountedQty); discountRule.set('qtyOffer', discountedQty); receipt.addPromotion(ln, discountRule, { amt: OB.DEC.toNumber(discountedQty.multiply(price).multiply(OB.DEC.toBigDecimal(unitsToDiscount)).multiply(avgPrice).divide(totalPrice)) }); } } // Distribute the discount among all lines, but display to the user the same info as it was not distributed // distribution is just to be internally managed if (distributed && (subtype === 'CHEAPEST')) { unitsToDiscount = chunks * (x - y); var totalQty = chunks * x; var pendingQty = totalQty; var qtyOffer = 0; var partialAmt = 0; for (i = 0; i < applyingToLines.length; i++) { ln = applyingToLines.at(i); price = OB.DEC.toBigDecimal(ln.get('discountedLinePrice') || ln.get('price')); amt = OB.DEC.toNumber(OB.DEC.toBigDecimal(ln.get('qtyToApplyDisc')).multiply(price).multiply(distributionAmt).multiply(OB.DEC.toBigDecimal(unitsToDiscount)).divide(totalPrice.multiply(OB.DEC.toBigDecimal(distributionQty)))); if ((i === applyingToLines.length - 1) && ((partialAmt + amt) !== distributionAmt)) { amt = OB.DEC.toNumber(distributionAmt.subtract(OB.DEC.toBigDecimal(partialAmt))); } else { partialAmt = OB.DEC.add(partialAmt, amt); } // calculate the qty of line is used in this discount if (pendingQty <= ln.get('qtyToApplyDisc')) { qtyOffer = pendingQty; pendingQty = 0; } else { qtyOffer = ln.get('qtyToApplyDisc'); pendingQty -= ln.get('qtyToApplyDisc'); } discountRule.set('qtyOffer', qtyOffer); receipt.addPromotion(ln, discountRule, { actualAmt: amt, amt: distribution[i] }); } } } else { // Cannot apply discount, not enough qty, ensure there is no line with this discount applyingToLines.forEach(function (ln) { receipt.removePromotion(ln, discountRule); }); } if (OB.DEC.toNumber(qty) % x !== 0) { alerts = OB.I18N.getLabel('OBPOS_DiscountAlert', [line.get('product').get('_identifier'), discountRule.get('printName') || discountRule.get('name')]); } return { alerts: alerts }; } }; /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ // Buy X pay Y of same product OB.Model.Discounts.discountRules.E08EE3C23EBA49358A881EF06C139D63 = { async: false, implementation: function (discountRule, receipt, line) { var alerts, qty, x, y, mod, chunks, price, finalPrice; x = discountRule.get('oBDISCX'); y = discountRule.get('oBDISCY'); if (!x || !y || x === 0) { window.console.warn('Discount incorrectly defined, missing x or y', discountRule); } qty = line.get('qty'); mod = qty % x; if (mod !== 0) { alerts = OB.I18N.getLabel('OBPOS_DISCAlertXYSameProduct', [x - mod, line.get('product').get('_identifier'), discountRule.get('printName') || discountRule.get('name')]); } if (qty >= x) { chunks = Math.floor(qty / x); price = line.get('discountedLinePrice') || line.get('price'); // note discountedLinePrice is not updated since this rule shouldn't change it finalPrice = OB.DEC.add(OB.DEC.mul(OB.DEC.mul(chunks, y), price), OB.DEC.mul(mod, price)); discountRule.set('qtyOffer', OB.DEC.toNumber(OB.DEC.mul(chunks, x))); receipt.addPromotion(line, discountRule, { amt: OB.DEC.sub(OB.DEC.mul(qty, price), finalPrice) }); } return { alerts: alerts }; } }; /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone console _*/ // Pack OB.Model.Discounts.discountRules.BE5D42E554644B6AA262CCB097753951 = { async: true, implementation: function (discountRule, receipt, line, listener) { var applyingToLines = new Backbone.Collection(), criteria, promotionCandidates = line.get('promotionCandidates') || [], finalAmt, lineNum, previousAmt; // This line is candidate for this promotion if (promotionCandidates.indexOf(discountRule.id) === -1) { promotionCandidates.push(discountRule.id); } line.set('promotionCandidates', promotionCandidates); // look for other lines that are candidates to apply this same rule receipt.get('lines').forEach(function (l) { if (l.get('promotionCandidates')) { l.get('promotionCandidates').forEach(function (candidateRule) { if (candidateRule === discountRule.id) { //Using _idx to check the priority if (!(l.isAffectedByPack() && l.isAffectedByPack().ruleId !== discountRule.get('id')) || (l.isAffectedByPack() && l.isAffectedByPack().ruleId !== discountRule.get('id') && l.isAffectedByPack()._idx > discountRule.get('_idx'))) { // The promotion will be applied if the line is not affected by other pack or if the priority of // the new pack is greater applyingToLines.add(l); } } }); } }); // Query local DB to know detail about the rule (products and quantities) criteria = { priceAdjustment: discountRule.id }; OB.Dal.find(OB.Model.DiscountFilterProduct, criteria, function (products) { var chunks, distributed, totalAmt, promotionAmt = 0, outOfComboAmt; if (applyingToLines.length !== products.length) { // rule can't be applied because not all products are matched listener.trigger('completed'); return; } products.forEach(function (product) { var i, line, applyNtimes; if (chunks === 0) { // already decided not to apply return; } for (i = 0; i < applyingToLines.length; i++) { if (applyingToLines.at(i).get('product').id === product.get('product')) { line = applyingToLines.at(i); break; } } if (!line) { // cannot apply the rule chunks = 0; return; } product.set('receiptLine', line); applyNtimes = Math.floor(line.get('qty') / (product.get('obdiscQty') || 1)); if (!chunks || applyNtimes < chunks) { chunks = applyNtimes; } }); if (chunks === 0) { // Cannot apply, ensure the promotion is not applied applyingToLines.forEach(function (ln) { receipt.removePromotion(ln, discountRule); }); listener.trigger('completed', { alerts: OB.I18N.getLabel('OBPOS_DiscountAlert', [line.get('product').get('_identifier'), discountRule.get('printName') || discountRule.get('name')]) }); return; } // There are products enough to apply the rule // Enforce stop cascade after applying this rule discountRule.set('applyNext', false, { silent: true }); totalAmt = products.reduce(function (total, product) { var l = product.get('receiptLine'); return OB.DEC.add(total, OB.DEC.mul(l.get('qty'), l.get('discountedLinePrice') || l.get('price'))); }, OB.DEC.Zero); outOfComboAmt = products.reduce(function (total, product) { var l = product.get('receiptLine'), unitsOutOfCombo = l.get('qty') - (chunks * (product.get('obdiscQty') || 1)); return OB.DEC.add(total, OB.DEC.mul(unitsOutOfCombo, l.get('discountedLinePrice') || l.get('price'))); }, OB.DEC.Zero); finalAmt = OB.DEC.mul(chunks, discountRule.get('obdiscPrice').toFixed(OB.POS.modelterminal.get('currency').obposPosprecision || OB.POS.modelterminal.get('currency').pricePrecision)) + outOfComboAmt; promotionAmt = totalAmt - finalAmt; // first loop calculated the total discount, now let's apply it lineNum = 0; previousAmt = 0; products.forEach(function (product) { var l = product.get('receiptLine'), price = l.get('discountedLinePrice') || l.get('price'), actualAmt; lineNum += 1; if (lineNum < products.length) { actualAmt = OB.DEC.div(OB.DEC.mul(OB.DEC.mul(l.get('qty'), price), promotionAmt), (totalAmt)); previousAmt += OB.DEC.sub(OB.DEC.mul(l.get('qty'), price), actualAmt); } else { // last line with discount: calculate discount based on pending amt to be discounted actualAmt = OB.DEC.sub(OB.DEC.mul(l.get('qty'), price), OB.DEC.sub(finalAmt, previousAmt)); } discountRule.set('qtyOffer', OB.DEC.mul(OB.DEC.toNumber(product.get('obdiscQty')), chunks)); receipt.addPromotion(l, discountRule, { amt: actualAmt, pack: true }); }); listener.trigger('completed'); }, function () { window.console.error('Error querying for products', discountRule, receipt, line, arguments); listener.trigger('completed'); }); }, addProductToOrder: function (order, productToAdd) { var criteria; function errorCallback(error) { console.error('OBDAL error: ' + error, arguments); } OB.Dal.get(OB.Model.Discount, productToAdd.get('id'), function (pack) { if (pack.get('endingDate') && pack.get('endingDate').length > 0) { var objDate = new Date(pack.get('endingDate')); var now = new Date(); var nowWithoutTime = new Date(now.toISOString().split('T')[0]); if (nowWithoutTime > objDate) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_PackExpired_header'), OB.I18N.getLabel('OBPOS_PackExpired_body', [pack.get('_identifier'), objDate.toLocaleDateString()])); return; } } criteria = { priceAdjustment: pack.get('id') }; OB.Dal.find(OB.Model.DiscountFilterProduct, criteria, function (productsOfPromotion) { productsOfPromotion.forEach(function (promotionProduct) { OB.Dal.get(OB.Model.Product, promotionProduct.get('product'), function (product) { if (product) { product.set('price', product.get('standardPrice')); order.addProduct(product, promotionProduct.get('obdiscQty'), { packId: promotionProduct.get('priceAdjustment') }); } }, errorCallback); }); }, errorCallback); }, function () { }); } }; /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _, enyo*/ // Manual discounts (function () { function add(receipt, line, promotion) { var definition = promotion.definition, price, pctg, discPrice, unitDiscount, oldDiscountedLinePrice; definition.manual = true; definition._idx = -1; definition.lastApplied = true; if (definition.percentage) { price = line.get('price'); price = OB.DEC.toBigDecimal(price); pctg = OB.DEC.toBigDecimal(definition.percentage); discPrice = price.multiply(new BigDecimal('100').subtract(pctg).divide(new BigDecimal('100'), 20, OB.DEC.getRoundingMode())); discPrice = new BigDecimal((String)(OB.DEC.toNumber(discPrice))); definition.amt = OB.DEC.mul(OB.DEC.abs(line.get('qty')), OB.DEC.toNumber(price.subtract(discPrice))); } else { definition.amt = definition.userAmt; } oldDiscountedLinePrice = !_.isNull(line.get('discountedLinePrice')) ? line.get('discountedLinePrice') : line.get('price'); if (oldDiscountedLinePrice < OB.DEC.abs(OB.DEC.div(definition.amt, line.getQty()))) { definition.amt = OB.DEC.mul(oldDiscountedLinePrice, OB.DEC.abs(line.getQty())); } unitDiscount = OB.DEC.div(definition.amt, OB.DEC.abs(line.get('qty'))); // if Qty is negative, then the discount should be added instead of substract if (line.getQty() < BigDecimal.prototype.ZERO) { definition.amt = OB.DEC.mul(definition.amt, new BigDecimal("-1")); } line.set('discountedLinePrice', line.get('price') - unitDiscount); receipt.addPromotion(line, promotion.rule, definition); } function addPercentage(receipt, line, promotion) { promotion.definition.percentage = promotion.definition.userAmt; add(receipt, line, promotion); } // User Defined Amount OB.Model.Discounts.discountRules.D1D193305A6443B09B299259493B272A = { addManual: function (receipt, line, promotion) { add(receipt, line, promotion); } }; // Discretionary Discount Fixed Amount OB.Model.Discounts.discountRules['7B49D8CC4E084A75B7CB4D85A6A3A578'] = { addManual: function (receipt, line, promotion) { add(receipt, line, promotion); } }; // User Defined Percentage OB.Model.Discounts.discountRules['20E4EC27397344309A2185097392D964'] = { addManual: function (receipt, line, promotion) { addPercentage(receipt, line, promotion); } }; // Discretionary Discount Fixed Percentage OB.Model.Discounts.discountRules['8338556C0FBF45249512DB343FEFD280'] = { addManual: function (receipt, line, promotion) { addPercentage(receipt, line, promotion); } }; OB.Model.Discounts.onLoadActions = OB.Model.Discounts.onLoadActions || []; OB.Model.Discounts.onLoadActions.push({ execute: function () { /** * Checks if approval is required to pay this ticket. If required, a popup is shown requesting it. */ OB.UTIL.HookManager.registerHook('OBPOS_CheckPaymentApproval', function (args, callbacks) { // Checking if applied discretionary discounts require approval var discretionaryDiscountTypes = OB.Model.Discounts.getManualPromotions(true), discountsToCheck = [], requiresApproval = false, i; if (OB.POS.modelterminal.hasPermission('OBPOS_approval.discounts', true)) { // current user is a supervisor, no need to check further permissions OB.UTIL.HookManager.callbackExecutor(args, callbacks); return; } args.context.get('order').get('lines').each(function (l) { var p, promotions; promotions = l.get('promotions'); if (promotions) { for (p = 0; p < promotions.length; p++) { if (_.contains(discretionaryDiscountTypes, promotions[p].discountType) && !_.contains(discountsToCheck, promotions[p].ruleId)) { discountsToCheck.push(promotions[p].ruleId); } } } }, args.context); if (discountsToCheck.length > 0) { OB.Dal.find(OB.Model.Discount, { obdiscApprovalRequired: true }, enyo.bind(args.context, function (discountsWithApproval) { for (i = 0; i < discountsToCheck.length; i++) { if (discountsWithApproval.where({ id: discountsToCheck[i] }).length > 0) { requiresApproval = true; break; } } if (requiresApproval) { args.approvals.push('OBPOS_approval.discounts'); } OB.UTIL.HookManager.callbackExecutor(args, callbacks); })); } else { OB.UTIL.HookManager.callbackExecutor(args, callbacks); return; } }); } }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, _, Backbone, window, confirm, console, localStorage */ var OB = window.OB || {}; (function () { // alert all errors window.onerror = function (e, url, line) { var errorInfo; if (typeof (e) === 'string') { errorInfo = e + '. Line number: ' + line + '. File uuid: ' + url + '.'; OB.UTIL.showError(errorInfo); OB.error(errorInfo); } }; // Add the current WebPOS version OB.UTIL.VersionManagement.current.posterminal = { rootName: 'RR14Q', major: '4', minor: '0' }; // Add the current WebSQL database version for WebPOS OB.UTIL.VersionManagement.current.posterminal.WebSQLDatabase = { name: 'WEBPOS', size: 4 * 1024 * 1024, displayName: 'Openbravo Web POS', major: '0', minor: '7' }; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var ChangedBusinessPartners = Backbone.Model.extend({ modelName: 'ChangedBusinessPartners', tableName: 'changedbusinesspartners', entityName: '', source: '', local: true, properties: ['id', 'json', 'c_bpartner_id', 'isbeingprocessed'], propertyMap: { 'id': 'changedbusinesspartners_id', 'json': 'json', 'c_bpartner_id': 'c_bpartner_id', 'isbeingprocessed': 'isbeingprocessed' }, createStatement: 'CREATE TABLE IF NOT EXISTS changedbusinesspartners (changedbusinesspartners_id TEXT PRIMARY KEY, json TEXT, c_bpartner_id TEXT, isbeingprocessed TEXT)', dropStatement: 'DROP TABLE IF EXISTS changedbusinesspartners', insertStatement: 'INSERT INTO changedbusinesspartners(changedbusinesspartners_id, json, c_bpartner_id, isbeingprocessed) VALUES (?,?,?,?)' }); OB.Data.Registry.registerModel(ChangedBusinessPartners); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global Backbone */ (function () { var ChangedBPlocation = Backbone.Model.extend({ modelName: 'ChangedBPlocation', tableName: 'changedbplocation', entityName: '', source: '', local: true, properties: ['id', 'json', 'c_bpartner_location_id', 'isbeingprocessed'], propertyMap: { 'id': 'changedbplocation_id', 'json': 'json', 'c_bpartner_location_id': 'c_bpartner_location_id', 'isbeingprocessed': 'isbeingprocessed' }, createStatement: 'CREATE TABLE IF NOT EXISTS changedbplocation (changedbplocation_id TEXT PRIMARY KEY, json TEXT, c_bpartner_location_id TEXT, isbeingprocessed TEXT)', dropStatement: 'DROP TABLE IF EXISTS changedbplocation', insertStatement: 'INSERT INTO changedbplocation(changedbplocation_id, json, c_bpartner_location_id, isbeingprocessed) VALUES (?,?,?,?)' }); OB.Data.Registry.registerModel(ChangedBPlocation); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B,_,moment,Backbone,localStorage, enyo */ (function () { // Sales.OrderLine Model var OrderLine = Backbone.Model.extend({ modelName: 'OrderLine', defaults: { product: null, productidentifier: null, uOM: null, qty: OB.DEC.Zero, price: OB.DEC.Zero, priceList: OB.DEC.Zero, gross: OB.DEC.Zero, net: OB.DEC.Zero, description: '' }, initialize: function (attributes) { if (attributes && attributes.product) { this.set('product', new OB.Model.Product(attributes.product)); this.set('productidentifier', attributes.productidentifier); this.set('uOM', attributes.uOM); this.set('qty', attributes.qty); this.set('price', attributes.price); this.set('priceList', attributes.priceList); this.set('gross', attributes.gross); this.set('net', attributes.net); this.set('promotions', attributes.promotions); this.set('priceIncludesTax', attributes.priceIncludesTax); if (!attributes.grossListPrice && attributes.product && attributes.product.listPrice) { this.set('grossListPrice', attributes.product.listPrice); } } }, getQty: function () { return this.get('qty'); }, printQty: function () { return this.get('qty').toString(); }, printPrice: function () { return OB.I18N.formatCurrency(this.get('_price') || this.get('nondiscountedprice') || this.get('price')); }, printDiscount: function () { var disc = OB.DEC.sub(this.get('product').get('standardPrice'), this.get('price')); var prom = this.getTotalAmountOfPromotions(); // if there is a discount no promotion then only discount no promotion is shown // if there is not a discount no promotion and there is a promotion then promotion is shown if (OB.DEC.compare(disc) === 0) { if (OB.DEC.compare(prom) === 0) { return ''; } else { return OB.I18N.formatCurrency(prom); } } else { return OB.I18N.formatCurrency(disc); } }, // returns the discount to substract in total discountInTotal: function () { var disc = OB.DEC.sub(this.get('product').get('standardPrice'), this.get('price')); // if there is a discount no promotion then total is price*qty // otherwise total is price*qty - discount if (OB.DEC.compare(disc) === 0) { return this.getTotalAmountOfPromotions(); } else { return 0; } }, calculateGross: function () { if (this.get('priceIncludesTax')) { this.set('gross', OB.DEC.mul(this.get('qty'), this.get('price'))); } else { this.set('net', OB.DEC.mul(this.get('qty'), this.get('price'))); } }, getGross: function () { return this.get('gross'); }, getNet: function () { return this.get('net'); }, printGross: function () { return OB.I18N.formatCurrency(this.get('_gross') || this.getGross()); }, printNet: function () { return OB.I18N.formatCurrency(this.get('nondiscountednet') || this.getNet()); }, getTotalAmountOfPromotions: function () { var memo = 0; if (this.get('promotions') && this.get('promotions').length > 0) { return _.reduce(this.get('promotions'), function (memo, prom) { if (OB.UTIL.isNullOrUndefined(prom.amt)) { return memo; } return memo + prom.amt; }, memo, this); } else { return 0; } }, isAffectedByPack: function () { return _.find(this.get('promotions'), function (promotion) { if (promotion.pack) { return true; } }, this); }, stopApplyingPromotions: function () { var promotions = this.get('promotions'), i; if (promotions) { if (OB.POS.modelterminal.get('terminal').bestDealCase && promotions.length > 0) { // best deal case can only apply one promotion per line return true; } for (i = 0; i < promotions.length; i++) { if (!promotions[i].applyNext) { return true; } } } return false; }, lastAppliedPromotion: function () { var promotions = this.get('promotions'), i; if (this.get('promotions')) { for (i = 0; i < promotions.length; i++) { if (promotions[i].lastApplied) { return promotions[i]; } } } return null; } }); // Sales.OrderLineCol Model. var OrderLineList = Backbone.Collection.extend({ model: OrderLine, isProductPresent: function (product) { var result = null; if (this.length > 0) { result = _.find(this.models, function (line) { if (line.get('product').get('id') === product.get('id')) { return true; } }, this); if (_.isUndefined(result) || _.isNull(result)) { return false; } else { return true; } } else { return false; } } }); // Sales.Payment Model var PaymentLine = Backbone.Model.extend({ modelName: 'PaymentLine', defaults: { 'amount': OB.DEC.Zero, 'origAmount': OB.DEC.Zero, 'paid': OB.DEC.Zero, // amount - change... 'date': null }, printAmount: function () { if (this.get('rate')) { return OB.I18N.formatCurrency(OB.DEC.mul(this.get('amount'), this.get('rate'))); } else { return OB.I18N.formatCurrency(this.get('amount')); } }, printForeignAmount: function () { return '(' + OB.I18N.formatCurrency(this.get('amount')) + ' ' + this.get('isocode') + ')'; } }); // Sales.OrderLineCol Model. var PaymentLineList = Backbone.Collection.extend({ model: PaymentLine }); // Sales.Order Model. var Order = Backbone.Model.extend({ modelName: 'Order', tableName: 'c_order', entityName: 'Order', source: '', dataLimit: 300, properties: ['id', 'json', 'session', 'hasbeenpaid', 'isbeingprocessed'], propertyMap: { 'id': 'c_order_id', 'json': 'json', 'session': 'ad_session_id', 'hasbeenpaid': 'hasbeenpaid', 'isbeingprocessed': 'isbeingprocessed' }, defaults: { hasbeenpaid: 'N', isbeingprocessed: 'N' }, createStatement: 'CREATE TABLE IF NOT EXISTS c_order (c_order_id TEXT PRIMARY KEY, json CLOB, ad_session_id TEXT, hasbeenpaid TEXT, isbeingprocessed TEXT)', dropStatement: 'DROP TABLE IF EXISTS c_order', insertStatement: 'INSERT INTO c_order(c_order_id, json, ad_session_id, hasbeenpaid, isbeingprocessed) VALUES (?,?,?,?,?)', local: true, _id: 'modelorder', initialize: function (attributes) { var orderId; if (attributes && attributes.id && attributes.json) { // The attributes of the order are stored in attributes.json // Makes sure that the id is copied orderId = attributes.id; attributes = JSON.parse(attributes.json); attributes.id = orderId; } if (attributes && attributes.documentNo) { this.set('id', attributes.id); this.set('client', attributes.client); this.set('organization', attributes.organization); this.set('documentType', attributes.documentType); this.set('createdBy', attributes.createdBy); this.set('updatedBy', attributes.updatedBy); this.set('orderType', attributes.orderType); // 0: Sales order, 1: Return order this.set('generateInvoice', attributes.generateInvoice); this.set('isQuotation', attributes.isQuotation); this.set('oldId', attributes.oldId); this.set('priceList', attributes.priceList); this.set('priceIncludesTax', attributes.priceIncludesTax); this.set('currency', attributes.currency); this.set('currency' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, attributes['currency' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER]); this.set('session', attributes.session); this.set('warehouse', attributes.warehouse); this.set('salesRepresentative', attributes.salesRepresentative); this.set('salesRepresentative' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, attributes['salesRepresentative' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER]); this.set('posTerminal', attributes.posTerminal); this.set('posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, attributes['posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER]); this.set('orderDate', new Date(attributes.orderDate)); this.set('documentNo', attributes.documentNo); this.set('undo', attributes.undo); this.set('bp', new Backbone.Model(attributes.bp)); this.set('lines', new OrderLineList().reset(attributes.lines)); this.set('payments', new PaymentLineList().reset(attributes.payments)); this.set('payment', attributes.payment); this.set('change', attributes.change); this.set('qty', attributes.qty); this.set('gross', attributes.gross); this.trigger('calculategross'); this.set('net', attributes.net); this.set('taxes', attributes.taxes); this.set('hasbeenpaid', attributes.hasbeenpaid); this.set('isbeingprocessed', attributes.isbeingprocessed); this.set('description', attributes.description); this.set('print', attributes.print); this.set('sendEmail', attributes.sendEmail); this.set('isPaid', attributes.isPaid); this.set('isLayaway', attributes.isLayaway); this.set('isEditable', attributes.isEditable); this.set('openDrawer', attributes.openDrawer); _.each(_.keys(attributes), function (key) { if (!this.has(key)) { this.set(key, attributes[key]); } }, this); } else { this.clearOrderAttributes(); } }, save: function () { var undoCopy; if (this.attributes.json) { delete this.attributes.json; // Needed to avoid recursive inclusions of itself !!! } undoCopy = this.get('undo'); this.unset('undo'); this.set('json', JSON.stringify(this.toJSON())); if (!OB.POS.modelterminal.get('preventOrderSave')) { OB.Dal.save(this, function () {}, function () { OB.error(arguments); }); } this.set('undo', undoCopy); }, calculateTaxes: function (callback, doNotSave) { var tmp = new OB.DATA.OrderTaxes(this); this.calculateTaxes(callback); }, prepareToSend: function (callback) { var me = this; this.calculateTaxes(function () { me.adjustPrices(); callback(me); }); }, adjustPrices: function () { // Apply calculated discounts and promotions to price and gross prices // so ERP saves them in the proper place this.get('lines').each(function (line) { var price = line.get('price'), gross = line.get('gross'), totalDiscount = 0, grossListPrice = line.get('priceList'), grossUnitPrice, discountPercentage, base; // Calculate inline discount: discount applied before promotions if (line.get('product').get('standardPrice') !== price || (_.isNumber(line.get('discountedLinePrice')) && line.get('discountedLinePrice') !== line.get('product').get('standardPrice'))) { grossUnitPrice = new BigDecimal(price.toString()); if (OB.DEC.compare(grossListPrice) === 0) { discountPercentage = OB.DEC.Zero; } else { discountPercentage = OB.DEC.toBigDecimal(grossListPrice).subtract(grossUnitPrice).multiply(new BigDecimal('100')).divide(OB.DEC.toBigDecimal(grossListPrice), 2, BigDecimal.prototype.ROUND_HALF_UP); discountPercentage = parseFloat(discountPercentage.setScale(2, BigDecimal.prototype.ROUND_HALF_UP).toString(), 10); } } else { discountPercentage = OB.DEC.Zero; } line.set({ discountPercentage: discountPercentage }, { silent: true }); // Calculate prices after promotions base = line.get('price'); _.forEach(line.get('promotions') || [], function (discount) { var discountAmt = discount.actualAmt || discount.amt || 0; discount.basePrice = base; discount.unitDiscount = OB.DEC.div(discountAmt, line.get('qtyToApplyDisc') || line.get('qty')); totalDiscount = OB.DEC.add(totalDiscount, discountAmt); base = OB.DEC.sub(base, totalDiscount); }, this); gross = OB.DEC.sub(gross, totalDiscount); price = OB.DEC.div(gross, line.get('qty')); if (this.get('priceIncludesTax')) { line.set({ net: OB.UTIL.getFirstValidValue([OB.DEC.toNumber(line.get('discountedNet')), line.get('net'), OB.DEC.div(gross, line.get('linerate'))]), pricenet: line.get('discountedNet') ? OB.DEC.div(line.get('discountedNet'), line.get('qty')) : OB.DEC.div(OB.DEC.div(gross, line.get('linerate')), line.get('qty')), listPrice: OB.DEC.div((grossListPrice || price), line.get('linerate')), standardPrice: OB.DEC.div((grossListPrice || price), line.get('linerate')), grossListPrice: grossListPrice || price, grossUnitPrice: price, lineGrossAmount: gross }, { silent: true }); } else { line.set({ nondiscountedprice: line.get('price'), nondiscountednet: line.get('net'), standardPrice: line.get('price'), net: line.get('discountedNet'), pricenet: OB.DEC.toNumber(line.get('discountedNetPrice')), listPrice: line.get('priceList'), grossListPrice: 0, lineGrossAmount: 0 }, { silent: true }); if (!this.get('isQuotation')) { line.set('price', 0, { silent: true }); } } }, this); var totalnet = this.get('lines').reduce(function (memo, e) { var netLine = e.get('discountedNet'); if (e.get('net')) { return memo.add(new BigDecimal(String(e.get('net')))); } else { return memo.add(new BigDecimal('0')); } }, new BigDecimal(String(OB.DEC.Zero))); totalnet = OB.DEC.toNumber(totalnet); this.set('net', totalnet); }, getTotal: function () { return this.getGross(); }, getNet: function () { return this.get('net'); }, printTotal: function () { return OB.I18N.formatCurrency(this.getTotal()); }, getLinesByProduct: function (productId) { var affectedLines; if (this.get('lines') && this.get('lines').length > 0) { affectedLines = _.filter(this.get('lines').models, function (line) { return line.get('product').id === productId; }); } return affectedLines ? affectedLines : null; }, calculateGross: function () { var me = this; if (this.get('priceIncludesTax')) { this.calculateTaxes(function () { var gross = me.get('lines').reduce(function (memo, e) { var grossLine = e.getGross(); if (e.get('promotions')) { grossLine = e.get('promotions').reduce(function (memo, e) { return OB.DEC.sub(memo, e.actualAmt || e.amt || 0); }, grossLine); } return OB.DEC.add(memo, grossLine); }, OB.DEC.Zero); me.set('gross', gross); me.adjustPayment(); me.trigger('calculategross'); me.trigger('saveCurrent'); }); } else { this.calculateTaxes(function () { //If the price doesn't include tax, the discounted gross has already been calculated var gross = me.get('lines').reduce(function (memo, e) { if (_.isUndefined(e.get('discountedGross'))) { return memo; } var grossLine = e.get('discountedGross'); if (grossLine) { return OB.DEC.add(memo, grossLine); } else { return memo; } }, 0); me.set('gross', gross); var net = me.get('lines').reduce(function (memo, e) { var netLine = e.get('discountedNet'); if (netLine) { return OB.DEC.add(memo, netLine); } else { return memo; } }, OB.DEC.Zero); me.set('net', net); me.adjustPayment(); me.trigger('calculategross'); me.trigger('saveCurrent'); }); } //total qty var qty = this.get('lines').reduce(function (memo, e) { var qtyLine = e.getQty(); if (qtyLine > 0) { return OB.DEC.add(memo, qtyLine, OB.I18N.qtyScale()); } else { return memo; } }, OB.DEC.Zero); this.set('qty', qty); }, getQty: function () { return this.get('qty'); }, getGross: function () { return this.get('gross'); }, printGross: function () { return OB.I18N.formatCurrency(this.getGross()); }, getPayment: function () { return this.get('payment'); }, getChange: function () { return this.get('change'); }, getPending: function () { return OB.DEC.sub(OB.DEC.abs(this.getTotal()), this.getPayment()); }, printPending: function () { return OB.I18N.formatCurrency(this.getPending()); }, getPaymentStatus: function () { var total = OB.DEC.abs(this.getTotal()), pay = this.getPayment(), isReturn = true; _.each(this.get('lines').models, function (line) { if (line.get('qty') > 0) { isReturn = false; } }, this); return { 'done': (this.get('lines').length > 0 && OB.DEC.compare(total) >= 0 && OB.DEC.compare(OB.DEC.sub(pay, total)) >= 0), 'total': OB.I18N.formatCurrency(total), 'pending': OB.DEC.compare(OB.DEC.sub(pay, total)) >= 0 ? OB.I18N.formatCurrency(OB.DEC.Zero) : OB.I18N.formatCurrency(OB.DEC.sub(total, pay)), 'change': OB.DEC.compare(this.getChange()) > 0 ? OB.I18N.formatCurrency(this.getChange()) : null, 'overpayment': OB.DEC.compare(OB.DEC.sub(pay, total)) > 0 ? OB.I18N.formatCurrency(OB.DEC.sub(pay, total)) : null, 'isReturn': isReturn, 'isNegative': this.get('gross') < 0 ? true : false, 'changeAmt': this.getChange(), 'pendingAmt': OB.DEC.compare(OB.DEC.sub(pay, total)) >= 0 ? OB.DEC.Zero : OB.DEC.sub(total, pay), 'payments': this.get('payments') }; }, // returns true if the order is a Layaway, otherwise false isLayaway: function () { return this.getOrderType() === 2 || this.getOrderType() === 3 || this.get('isLayaway'); }, clear: function () { this.clearOrderAttributes(); this.trigger('change'); this.trigger('clear'); }, clearOrderAttributes: function () { this.set('id', null); this.set('client', null); this.set('organization', null); this.set('createdBy', null); this.set('updatedBy', null); this.set('documentType', null); this.set('orderType', 0); // 0: Sales order, 1: Return order this.set('generateInvoice', false); this.set('isQuotation', false); this.set('oldId', null); this.set('priceList', null); this.set('priceIncludesTax', null); this.set('currency', null); this.set('currency' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, null); this.set('session', null); this.set('warehouse', null); this.set('salesRepresentative', null); this.set('salesRepresentative' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, null); this.set('posTerminal', null); this.set('posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, null); this.set('orderDate', new Date()); this.set('documentNo', ''); this.set('undo', null); this.set('bp', null); this.set('lines', this.get('lines') ? this.get('lines').reset() : new OrderLineList()); this.set('payments', this.get('payments') ? this.get('payments').reset() : new PaymentLineList()); this.set('payment', OB.DEC.Zero); this.set('change', OB.DEC.Zero); this.set('qty', OB.DEC.Zero); this.set('gross', OB.DEC.Zero); this.set('net', OB.DEC.Zero); this.set('taxes', null); this.trigger('calculategross'); this.set('hasbeenpaid', 'N'); this.set('isbeingprocessed', 'N'); this.set('description', ''); this.set('print', true); this.set('sendEmail', false); this.set('isPaid', false); this.set('paidOnCredit', false); this.set('isLayaway', false); this.set('isEditable', true); this.set('openDrawer', false); this.set('totalamount', null); this.set('approvals', []); }, clearWith: function (_order) { var me = this, undf; // we set first this property to avoid that the apply promotions is triggered this.set('isNewReceipt', _order.get('isNewReceipt')); //we need this data when IsPaid, IsLayaway changes are triggered this.set('documentType', _order.get('documentType')); this.set('isPaid', _order.get('isPaid')); this.set('paidOnCredit', _order.get('paidOnCredit')); this.set('isLayaway', _order.get('isLayaway')); if (!_order.get('isEditable')) { // keeping it no editable as much as possible, to prevent // modifications to trigger editable events incorrectly this.set('isEditable', _order.get('isEditable')); } OB.UTIL.clone(_order, this); this.set('isEditable', _order.get('isEditable')); this.trigger('calculategross'); this.trigger('change'); this.trigger('clear'); }, removeUnit: function (line, qty) { if (!OB.DEC.isNumber(qty)) { qty = OB.DEC.One; } this.setUnit(line, OB.DEC.sub(line.get('qty'), qty, OB.I18N.qtyScale()), OB.I18N.getLabel('OBPOS_RemoveUnits', [qty, line.get('product').get('_identifier')])); }, addUnit: function (line, qty) { if (!OB.DEC.isNumber(qty)) { qty = OB.DEC.One; } this.setUnit(line, OB.DEC.add(line.get('qty'), qty, OB.I18N.qtyScale()), OB.I18N.getLabel('OBPOS_AddUnits', [OB.DEC.toNumber(new BigDecimal((String)(qty.toString()))), line.get('product').get('_identifier')])); }, setUnit: function (line, qty, text, doNotSave) { if (OB.DEC.isNumber(qty) && qty !== 0) { var oldqty = line.get('qty'); if (line.get('product').get('groupProduct') === false) { this.addProduct(line.get('product')); return true; } else { var me = this; // sets the new quantity line.set('qty', qty); line.calculateGross(); // sets the undo action this.set('undo', { text: text || OB.I18N.getLabel('OBPOS_SetUnits', [line.get('qty'), line.get('product').get('_identifier')]), oldqty: oldqty, line: line, undo: function () { line.set('qty', oldqty); line.calculateGross(); me.set('undo', null); } }); } this.adjustPayment(); if (!doNotSave) { this.save(); } } else { this.deleteLine(line); } }, setPrice: function (line, price, options) { options = options || {}; options.setUndo = (_.isUndefined(options.setUndo) || _.isNull(options.setUndo) || options.setUndo !== false) ? true : options.setUndo; if (!OB.UTIL.isNullOrUndefined(line.get('originalOrderLineId'))) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_CannotChangePrice')); } else if (OB.DEC.isNumber(price)) { var oldprice = line.get('price'); if (OB.DEC.compare(price) >= 0) { var me = this; // sets the new price line.set('price', price); line.calculateGross(); // sets the undo action if (options.setUndo) { this.set('undo', { text: OB.I18N.getLabel('OBPOS_SetPrice', [line.printPrice(), line.get('product').get('_identifier')]), oldprice: oldprice, line: line, undo: function () { line.set('price', oldprice); line.calculateGross(); me.set('undo', null); } }); } } this.adjustPayment(); } this.save(); }, setLineProperty: function (line, property, value) { var me = this; var index = this.get('lines').indexOf(line); this.get('lines').at(index).set(property, value); }, deleteLine: function (line, doNotSave) { var me = this; var index = this.get('lines').indexOf(line); var pack = line.isAffectedByPack(), productId = line.get('product').id; if (pack) { // When deleting a line, check lines with other product that are affected by // same pack than deleted one and merge splitted lines created for those this.get('lines').forEach(function (l) { var affected; if (productId === l.get('product').id) { return; //continue } affected = l.isAffectedByPack(); if (affected && affected.ruleId === pack.ruleId) { this.mergeLines(l); } }, this); } // trigger line.trigger('removed', line); // remove the line this.get('lines').remove(line); // set the undo action this.set('undo', { text: OB.I18N.getLabel('OBPOS_DeleteLine', [line.get('qty'), line.get('product').get('_identifier')]), line: line, undo: function () { me.get('lines').add(line, { at: index }); me.calculateGross(); me.set('undo', null); } }); this.adjustPayment(); if (!doNotSave) { this.save(); this.calculateGross(); } }, //Attrs is an object of attributes that will be set in order _addProduct: function (p, qty, options, attrs) { var me = this; if (enyo.Panels.isScreenNarrow()) { OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_AddLine', [qty ? qty : 1, p.get('_identifier')])); } if (p.get('ispack')) { OB.Model.Discounts.discountRules[p.get('productCategory')].addProductToOrder(this, p); return; } if (this.get('orderType') === 1) { qty = qty ? -qty : -1; } else { qty = qty || 1; } if (this.get('isQuotation') && this.get('hasbeenpaid') === 'Y') { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_QuotationClosed')); return; } if (p.get('obposScale')) { OB.POS.hwserver.getWeight(function (data) { if (data.exception) { alert(data.exception.message); } else if (data.result === 0) { alert(OB.I18N.getLabel('OBPOS_WeightZero')); } else { me.createLine(p, data.result, options, attrs); } }); } else { if (p.get('groupProduct') || (options && options.packId)) { var affectedByPack, line; if (options && options.line) { line = options.line; } else { line = this.get('lines').find(function (l) { if (l.get('product').id === p.id && l.get('qty') > 0) { affectedByPack = l.isAffectedByPack(); if (!affectedByPack) { return true; } else if ((options && options.packId === affectedByPack.ruleId) || !(options && options.packId)) { return true; } } }); } OB.UTIL.HookManager.executeHooks('OBPOS_GroupedProductPreCreateLine', { receipt: this, line: line, allLines: this.get('lines'), p: p, qty: qty, options: options, attrs: attrs }, function (args) { if (args && args.cancelOperation) { return; } if (args.line) { args.receipt.addUnit(args.line, args.qty); args.line.trigger('selected', args.line); } else { args.receipt.createLine(args.p, args.qty, args.options, args.attrs); } }); } else { //remove line even it is a grouped line if (options && options.line && qty === -1) { this.addUnit(options.line, qty); } else { this.createLine(p, qty, options, attrs); } } } this.save(); }, _drawLinesDistribution: function (data) { if (data && data.linesToModify && data.linesToModify.length > 0) { _.each(data.linesToModify, function (lineToChange) { var line = this.get('lines').getByCid(lineToChange.lineCid); var unitsToAdd = lineToChange.newQty - line.get('qty'); if (unitsToAdd > 0) { this.addUnit(line, unitsToAdd); } else if (unitsToAdd < 0) { this.removeUnit(line, -unitsToAdd); } this.setPrice(line, lineToChange.newPrice, { setUndo: false }); _.each(lineToChange.productProperties, function (propToSet) { line.get('product').set(propToSet.name, propToSet.value); }); _.each(lineToChange.lineProperties, function (propToSet) { line.set(propToSet.name, propToSet.value); }); }, this); } if (data && data.linesToRemove && data.linesToRemove.length > 0) { _.each(data.linesToRemove, function (lineCidToRemove) { var line = this.get('lines').getByCid(lineCidToRemove); this.deleteLine(line); }, this); } if (data && data.linesToAdd && data.linesToAdd.length > 0) { _.each(data.linesToAdd, function (lineToAdd) { this.createLine(lineToAdd.product, lineToAdd.qtyToAdd); }, this); } }, //Attrs is an object of attributes that will be set in order addProduct: function (p, qty, options, attrs) { OB.debug('_addProduct'); var me = this; OB.UTIL.HookManager.executeHooks('OBPOS_AddProductToOrder', { receipt: this, productToAdd: p, qtyToAdd: qty, options: options }, function (args) { // do not allow generic products to be added to the receipt if (args && args.productToAdd && args.productToAdd.get('isGeneric')) { OB.UTIL.showI18NWarning('OBPOS_GenericNotAllowed'); return; } if (args && args.useLines) { me._drawLinesDistribution(args); return; } me._addProduct(p, qty, options, attrs); }); }, /** * Splits a line from the ticket keeping in the line the qtyToKeep quantity, * the rest is moved to another line with the same product and no packs, or * to a new one if there's no other line. In case a new is created it is returned. */ splitLine: function (line, qtyToKeep) { var originalQty = line.get('qty'), newLine, p, qtyToMove; if (originalQty === qtyToKeep) { return; } qtyToMove = originalQty - qtyToKeep; this.setUnit(line, qtyToKeep, null, true); p = line.get('product'); newLine = this.get('lines').find(function (l) { return l !== line && l.get('product').id === p.id && !l.isAffectedByPack(); }); if (!newLine) { newLine = line.clone(); newLine.set({ promotions: null, addedBySplit: true }); this.get('lines').add(newLine); this.setUnit(newLine, qtyToMove, null, true); return newLine; } else { this.setUnit(newLine, newLine.get('qty') + qtyToMove, null, true); } }, /** * Checks other lines with the same product to be merged in a single one */ mergeLines: function (line) { var p = line.get('product'), lines = this.get('lines'), merged = false; line.set('promotions', null); lines.forEach(function (l) { var promos = l.get('promotions'); if (l === line) { return; } if (l.get('product').id === p.id && l.get('price') === line.get('price')) { line.set({ qty: line.get('qty') + l.get('qty'), promotions: null }); lines.remove(l); merged = true; } }, this); if (merged) { line.calculateGross(); } }, /** * It looks for different lines for same product with exactly the same promotions * to merge them in a single line */ mergeLinesWithSamePromotions: function () { var lines = this.get('lines'), l, line, i, j, k, p, otherLine, toRemove = [], matches, otherPromos, found, compareRule; compareRule = function (p) { var basep = line.get('promotions')[k]; return p.ruleId === basep.ruleId && ((!p.family && !basep.family) || (p.family && basep.family && p.family === basep.family)); }; for (i = 0; i < lines.length; i++) { line = lines.at(i); for (j = i + 1; j < lines.length; j++) { otherLine = lines.at(j); if (otherLine.get('product').id !== line.get('product').id) { continue; } if ((!line.get('promotions') || line.get('promotions').length === 0) && (!otherLine.get('promotions') || otherLine.get('promotions').length === 0)) { line.set('qty', line.get('qty') + otherLine.get('qty')); line.calculateGross(); toRemove.push(otherLine); } else if (line.get('promotions') && otherLine.get('promotions') && line.get('promotions').length === otherLine.get('promotions').length && line.get('price') === otherLine.get('price')) { matches = true; otherPromos = otherLine.get('promotions'); for (k = 0; k < line.get('promotions').length; k++) { found = _.find(otherPromos, compareRule); if (!found) { matches = false; break; } } if (matches) { line.set('qty', line.get('qty') + otherLine.get('qty')); for (k = 0; k < line.get('promotions').length; k++) { found = _.find(otherPromos, compareRule); line.get('promotions')[k].amt += found.amt; line.get('promotions')[k].displayedTotalAmount += found.displayedTotalAmount; } toRemove.push(otherLine); line.calculateGross(); } } } } _.forEach(toRemove, function (l) { lines.remove(l); }); }, addPromotion: function (line, rule, discount) { var promotions = line.get('promotions') || [], disc = {}, i, replaced = false; disc.name = discount.name || rule.get('printName') || rule.get('name'); disc.ruleId = rule.id || rule.get('ruleId'); disc.amt = discount.amt; disc.fullAmt = discount.amt ? discount.amt : 0; disc.actualAmt = discount.actualAmt; disc.pack = discount.pack; disc.discountType = rule.get('discountType'); disc.priority = rule.get('priority'); disc.manual = discount.manual; disc.userAmt = discount.userAmt; disc.lastApplied = discount.lastApplied; disc.obdiscQtyoffer = rule.get('qtyOffer') ? OB.DEC.toNumber(rule.get('qtyOffer')) : line.get('qty'); disc.qtyOffer = disc.obdiscQtyoffer; disc.doNotMerge = discount.doNotMerge; disc.hidden = discount.hidden === true || (discount.actualAmt && !disc.amt); if (OB.UTIL.isNullOrUndefined(discount.actualAmt) && !disc.amt && disc.pack) { disc.hidden = true; } if (disc.hidden) { disc.displayedTotalAmount = 0; } else { disc.displayedTotalAmount = disc.amt || discount.actualAmt; } if (discount.percentage) { disc.percentage = discount.percentage; } if (discount.family) { disc.family = discount.family; } if (typeof discount.applyNext !== 'undefined') { disc.applyNext = discount.applyNext; } else { disc.applyNext = rule.get('applyNext'); } if (!disc.applyNext) { disc.qtyOfferReserved = disc.obdiscQtyoffer; } else { disc.qtyOfferReserved = 0; } disc._idx = discount._idx || rule.get('_idx'); for (i = 0; i < promotions.length; i++) { if (disc._idx !== -1 && disc._idx < promotions[i]._idx) { // Trying to apply promotions in incorrect order: recalculate whole line again if (OB.POS.modelterminal.hasPermission('OBPOS_discount.newFlow', true)) { OB.Model.Discounts.applyPromotionsImp(this, line, true); } else { OB.Model.Discounts.applyPromotionsImp(this, line, false); } return; } } for (i = 0; i < promotions.length; i++) { if (promotions[i].ruleId === rule.id) { promotions[i] = disc; replaced = true; break; } } if (!replaced) { promotions.push(disc); } line.set('promotions', promotions); line.trigger('change'); }, removePromotion: function (line, rule) { var promotions = line.get('promotions'), ruleId = rule.id, removed = false, res = [], i; if (!promotions) { return; } for (i = 0; i < promotions.length; i++) { if (promotions[i].ruleId === rule.id) { removed = true; } else { res.push(promotions[i]); } } if (removed) { line.set('promotions', res); line.trigger('change'); this.save(); // Recalculate promotions for all lines affected by this same rule, // because this rule could have prevented other ones to be applied this.get('lines').forEach(function (ln) { if (ln.get('promotionCandidates')) { ln.get('promotionCandidates').forEach(function (candidateRule) { if (candidateRule === ruleId) { OB.Model.Discounts.applyPromotions(this, line); } }, this); } }, this); } }, //Attrs is an object of attributes that will be set in order line createLine: function (p, units, options, attrs) { var me = this; if (OB.POS.modelterminal.get('permissions').OBPOS_NotAllowSalesWithReturn) { var negativeLines = _.filter(this.get('lines').models, function (line) { return line.get('qty') < 0; }).length; if (this.get('lines').length > 0) { if (units > 0 && negativeLines > 0) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgCannotAddPositive')); return; } else if (units < 0 && negativeLines !== this.get('lines').length) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgCannotAddNegative')); return; } } } var newline = new OrderLine({ product: p, uOM: p.get('uOM'), qty: OB.DEC.number(units), price: OB.DEC.number(p.get('standardPrice')), priceList: OB.DEC.number(p.get('listPrice')), priceIncludesTax: this.get('priceIncludesTax'), warehouse: { id: OB.POS.modelterminal.get('warehouses')[0].warehouseid, warehousename: OB.POS.modelterminal.get('warehouses')[0].warehousename } }); if (!_.isUndefined(attrs)) { _.each(_.keys(attrs), function (key) { newline.set(key, attrs[key]); }); } newline.calculateGross(); //issue 25655: ungroup feature is just needed when the line is created. Then lines work as grouped lines. newline.get('product').set("groupProduct", true); //issue 25448: Show stock screen is just shown when a new line is created. if (newline.get('product').get("showstock") === true) { newline.get('product').set("showstock", false); newline.get('product').set("_showstock", true); } // add the created line this.get('lines').add(newline, options); newline.trigger('created', newline); // set the undo action this.set('undo', { text: OB.I18N.getLabel('OBPOS_AddLine', [newline.get('qty'), newline.get('product').get('_identifier')]), line: newline, undo: function () { me.get('lines').remove(newline); me.set('undo', null); } }); this.adjustPayment(); return newline; }, returnLine: function (line, options, skipValidaton) { var me = this; if (OB.POS.modelterminal.get('permissions').OBPOS_NotAllowSalesWithReturn && !skipValidaton) { //The value of qty need to be negate because we want to change it var negativeLines = _.filter(this.get('lines').models, function (line) { return line.get('qty') < 0; }).length; if (this.get('lines').length > 0) { if (-line.get('qty') > 0 && negativeLines > 0) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgCannotAddPositive')); return; } else if (-line.get('qty') < 0 && negativeLines !== this.get('lines').length) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgCannotAddNegative')); return; } } } if (line.get('qty') > 0) { line.get('product').set('ignorePromotions', true); } else { line.get('product').set('ignorePromotions', false); } line.set('qty', -line.get('qty')); line.calculateGross(); // set the undo action this.set('undo', { text: OB.I18N.getLabel('OBPOS_ReturnLine', [line.get('product').get('_identifier')]), line: line, undo: function () { line.set('qty', -line.get('qty')); me.set('undo', null); } }); this.adjustPayment(); if (line.get('promotions')) { line.unset('promotions'); } me.calculateGross(); this.save(); }, setBPandBPLoc: function (businessPartner, showNotif, saveChange) { var me = this, undef; var oldbp = this.get('bp'); this.set('bp', businessPartner); // set the undo action if (showNotif === undef || showNotif === true) { this.set('undo', { text: businessPartner ? OB.I18N.getLabel('OBPOS_SetBP', [businessPartner.get('_identifier')]) : OB.I18N.getLabel('OBPOS_ResetBP'), bp: businessPartner, undo: function () { me.set('bp', oldbp); me.set('undo', null); } }); } if (saveChange) { this.save(); } }, setOrderType: function (permission, orderType, options) { var me = this; if (orderType === OB.DEC.One) { this.set('documentType', OB.POS.modelterminal.get('terminal').terminalType.documentTypeForReturns); _.each(this.get('lines').models, function (line) { if (line.get('qty') > 0) { me.returnLine(line, null, true); } }, this); } else { this.set('documentType', OB.POS.modelterminal.get('terminal').terminalType.documentType); } this.set('orderType', orderType); // 0: Sales order, 1: Return order, 2: Layaway, 3: Void Layaway if (orderType !== 3) { //Void this Layaway, do not need to save if (!(options && !OB.UTIL.isNullOrUndefined(options.saveOrder) && options.saveOrder === false)) { this.save(); } } else { this.set('layawayGross', this.getGross()); this.set('gross', this.get('payment')); this.set('payment', OB.DEC.Zero); this.get('payments').reset(); } // remove promotions if (!(options && !OB.UTIL.isNullOrUndefined(options.applyPromotions) && options.applyPromotions === false)) { OB.Model.Discounts.applyPromotions(this); } }, // returns the ordertype: 0: Sales order, 1: Return order, 2: Layaway, 3: Void Layaway getOrderType: function () { return this.get('orderType'); }, shouldApplyPromotions: function () { // Do not apply promotions in return tickets return this.get('orderType') !== 1; }, hasOneLineToIgnoreDiscounts: function () { return _.some(this.get('lines').models, function (line) { return line.get('product').get('ignorePromotions'); }); }, setOrderInvoice: function () { if (OB.POS.modelterminal.hasPermission('OBPOS_receipt.invoice')) { this.set('generateInvoice', true); this.save(); } }, updatePrices: function (callback) { var order = this, newAllLinesCalculated; function allLinesCalculated() { callback(order); } newAllLinesCalculated = _.after(this.get('lines').length, allLinesCalculated); this.get('lines').each(function (line) { //remove promotions line.unset('promotions'); var successCallbackPrices, criteria = { 'id': line.get('product').get('id') }; successCallbackPrices = function (dataPrices, line) { dataPrices.each(function (price) { order.setPrice(line, price.get('standardPrice', { setUndo: false })); }); newAllLinesCalculated(); }; OB.Dal.find(OB.Model.Product, criteria, successCallbackPrices, function () { // TODO: Report error properly. }, line); }); }, createQuotation: function () { if (OB.POS.modelterminal.hasPermission('OBPOS_receipt.quotation')) { this.set('isQuotation', true); this.set('generateInvoice', false); this.set('documentType', OB.POS.modelterminal.get('terminal').terminalType.documentTypeForQuotations); this.save(); } }, createOrderFromQuotation: function (updatePrices) { var documentseq, documentseqstr; this.get('lines').each(function (line) { //issue 25055 -> If we don't do the following prices and taxes are calculated //wrongly because the calculation starts with discountedNet instead of //the real net. //It only happens if the order is created from quotation just after save the quotation //(without load the quotation from quotations window) if (!this.get('priceIncludesTax')) { line.set('net', line.get('nondiscountednet')); } //issues 24994 & 24993 //if the order is created from quotation just after save the quotation //(without load the quotation from quotations window). The order has the fields added //by adjust prices. We need to work without these values //price not including taxes line.unset('nondiscountedprice'); line.unset('nondiscountednet'); //price including taxes line.unset('netFull'); line.unset('grossListPrice'); line.unset('grossUnitPrice'); line.unset('lineGrossAmount'); }, this); this.set('id', null); this.set('isQuotation', false); this.set('generateInvoice', OB.POS.modelterminal.get('terminal').terminalType.generateInvoice); this.set('documentType', OB.POS.modelterminal.get('terminal').terminalType.documentType); this.set('createdBy', OB.POS.modelterminal.get('orgUserId')); this.set('salesRepresentative', OB.POS.modelterminal.get('context').user.id); this.set('hasbeenpaid', 'N'); this.set('isPaid', false); this.set('isEditable', true); this.set('orderDate', new Date()); documentseq = OB.POS.modelterminal.get('documentsequence') + 1; documentseqstr = OB.UTIL.padNumber(documentseq, 7); OB.POS.modelterminal.set('documentsequence', documentseq); this.set('documentNo', OB.POS.modelterminal.get('terminal').docNoPrefix + '/' + documentseqstr); this.set('posTerminal', OB.POS.modelterminal.get('terminal').id); this.save(); if (updatePrices) { this.updatePrices(function (order) { OB.Model.Discounts.applyPromotions(order); OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_QuotationCreatedOrder')); order.trigger('orderCreatedFromQuotation'); }); } else { OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_QuotationCreatedOrder')); this.calculateGross(); this.trigger('orderCreatedFromQuotation'); } }, reactivateQuotation: function () { this.set('hasbeenpaid', 'N'); this.set('isEditable', true); this.set('createdBy', OB.POS.modelterminal.get('orgUserId')); this.set('oldId', this.get('id')); this.set('id', null); this.save(); }, rejectQuotation: function () { alert('reject!!'); }, resetOrderInvoice: function () { if (OB.POS.modelterminal.hasPermission('OBPOS_receipt.invoice')) { this.set('generateInvoice', false); this.save(); } }, adjustPayment: function () { var i, max, p; var payments = this.get('payments'); var total = OB.DEC.abs(this.getTotal()); var nocash = OB.DEC.Zero; var cash = OB.DEC.Zero; var origCash = OB.DEC.Zero; var auxCash = OB.DEC.Zero; var prevCash = OB.DEC.Zero; var paidCash = OB.DEC.Zero; var pcash; for (i = 0, max = payments.length; i < max; i++) { p = payments.at(i); if (p.get('rate') && p.get('rate') !== '1') { p.set('origAmount', OB.DEC.mul(p.get('amount'), p.get('rate'))); } else { p.set('origAmount', p.get('amount')); } p.set('paid', p.get('origAmount')); if (p.get('kind') === OB.POS.modelterminal.get('paymentcash')) { // The default cash method cash = OB.DEC.add(cash, p.get('origAmount')); pcash = p; paidCash = OB.DEC.add(paidCash, p.get('origAmount')); } else if (OB.POS.modelterminal.hasPayment(p.get('kind')) && OB.POS.modelterminal.hasPayment(p.get('kind')).paymentMethod.iscash) { // Another cash method origCash = OB.DEC.add(origCash, p.get('origAmount')); pcash = p; paidCash = OB.DEC.add(paidCash, p.get('origAmount')); } else { nocash = OB.DEC.add(nocash, p.get('origAmount')); } } // Calculation of the change.... //FIXME if (pcash) { if (pcash.get('kind') !== OB.POS.modelterminal.get('paymentcash')) { auxCash = origCash; prevCash = cash; } else { auxCash = cash; prevCash = origCash; } if (OB.DEC.compare(nocash - total) > 0) { pcash.set('paid', OB.DEC.Zero); this.set('payment', nocash); this.set('change', OB.DEC.add(cash, origCash)); } else if (OB.DEC.compare(OB.DEC.sub(OB.DEC.add(OB.DEC.add(nocash, cash), origCash), total)) > 0) { pcash.set('paid', OB.DEC.sub(total, OB.DEC.add(nocash, OB.DEC.sub(paidCash, pcash.get('origAmount'))))); this.set('payment', total); //The change value will be computed through a rounded total value, to ensure that the total plus change //add up to the paid amount without any kind of precission loss this.set('change', OB.DEC.sub(OB.DEC.add(OB.DEC.add(nocash, cash), origCash), OB.Utilities.Number.roundJSNumber(total, 2))); } else { pcash.set('paid', auxCash); this.set('payment', OB.DEC.add(OB.DEC.add(nocash, cash), origCash)); this.set('change', OB.DEC.Zero); } } else { if (payments.length > 0) { if (this.get('payment') === 0 || nocash > 0) { this.set('payment', nocash); } } else { this.set('payment', OB.DEC.Zero); } this.set('change', OB.DEC.Zero); } }, addPayment: function (payment) { var payments, total; var i, max, p, order; if (!OB.DEC.isNumber(payment.get('amount'))) { alert(OB.I18N.getLabel('OBPOS_MsgPaymentAmountError')); return; } payments = this.get('payments'); total = OB.DEC.abs(this.getTotal()); order = this; OB.UTIL.HookManager.executeHooks('OBPOS_preAddPayment', { paymentToAdd: payment, payments: payments, receipt: this }, function () { if (!payment.get('paymentData')) { // search for an existing payment only if there is not paymentData info. // this avoids to merge for example card payments of different cards. for (i = 0, max = payments.length; i < max; i++) { p = payments.at(i); if (p.get('kind') === payment.get('kind') && !p.get('isPrePayment')) { p.set('amount', OB.DEC.add(payment.get('amount'), p.get('amount'))); if (p.get('rate') && p.get('rate') !== '1') { p.set('origAmount', OB.DEC.add(payment.get('origAmount'), OB.DEC.mul(p.get('origAmount'), p.get('rate')))); } order.adjustPayment(); order.trigger('displayTotal'); return; } } } if (payment.get('openDrawer') && (payment.get('allowOpenDrawer') || payment.get('isCash'))) { order.set('openDrawer', payment.get('openDrawer')); } payment.set('date', new Date()); payments.add(payment); order.adjustPayment(); order.trigger('displayTotal'); }); // call with callback, no args }, overpaymentExists: function () { return this.getPaymentStatus().overpayment ? true : false; }, removePayment: function (payment) { var payments = this.get('payments'); payments.remove(payment); if (payment.get('openDrawer')) { this.set('openDrawer', false); } this.adjustPayment(); this.save(); }, serializeToJSON: function () { // this.toJSON() generates a collection instance for members like "lines" // We need a plain array object var jsonorder = JSON.parse(JSON.stringify(this.toJSON())); // remove not needed members delete jsonorder.undo; delete jsonorder.json; _.forEach(jsonorder.lines, function (item) { delete item.product.img; }); // convert returns if (jsonorder.gross < 0) { _.forEach(jsonorder.payments, function (item) { item.amount = -item.amount; item.origAmount = -item.origAmount; item.paid = -item.paid; }); } return jsonorder; }, changeSignToShowReturns: function () { this.set('change', OB.DEC.mul(this.get('change'), -1)); this.set('gross', OB.DEC.mul(this.get('gross'), -1)); this.set('net', OB.DEC.mul(this.get('net'), -1)); this.set('qty', OB.DEC.mul(this.get('qty'), -1)); //lines _.each(this.get('lines').models, function (line) { line.set('gross', OB.DEC.mul(line.get('gross'), -1)); line.set('qty', OB.DEC.mul(line.get('qty'), -1)); }, this); //payments _.each(this.get('payments').models, function (payment) { payment.set('amount', OB.DEC.mul(payment.get('amount'), -1)); payment.set('origAmount', OB.DEC.mul(payment.get('origAmount'), -1)); }, this); //taxes _.each(this.get('taxes'), function (tax) { tax.amount = OB.DEC.mul(tax.amount, -1); tax.gross = OB.DEC.mul(tax.gross, -1); tax.net = OB.DEC.mul(tax.net, -1); }, this); }, setProperty: function (_property, _value) { this.set(_property, _value); this.save(); }, hasIntegrity: function () { // checks if the sum of the amount of every line is the same as the total gross var gross = this.attributes.gross; var grossOfSummedLines = 0; var countOfLines = 1; _.each(this.get('lines').models, function (line) { var lineGross = line.attributes.gross; grossOfSummedLines = OB.DEC.add(grossOfSummedLines, lineGross); countOfLines += 1; }, this); // allow up to 2 cents of deviation per line if (OB.DEC.abs(gross - grossOfSummedLines) <= (0.01 * countOfLines)) { return true; } OB.error("Receipt " + this.attributes.documentNo + " failed in the integrity test; gross: " + gross + " <> lineGross: " + grossOfSummedLines); return false; }, groupLinesByProduct: function () { var me = this, lineToMerge, lines = this.get('lines'), auxLines = lines.models.slice(0), localSkipApplyPromotions; localSkipApplyPromotions = this.get('skipApplyPromotions'); this.set('skipApplyPromotions', true); _.each(auxLines, function (l) { lineToMerge = _.find(lines.models, function (line) { if (l !== line && l.get('product').id === line.get('product').id && l.get('price') === line.get('price') && line.get('qty') > 0 && l.get('qty') > 0 && !_.find(line.get('promotions'), function (promo) { return promo.manual; }) && !_.find(l.get('promotions'), function (promo) { return promo.manual; })) { return line; } }); if (lineToMerge) { lineToMerge.set({ qty: lineToMerge.get('qty') + l.get('qty') }, { silent: true }); lines.remove(l); } }); this.set('skipApplyPromotions', localSkipApplyPromotions); }, fillPromotionsWith: function (groupedOrder, isFirstTime) { var me = this, copiedPromo, pendingQtyOffer, undf, linesToMerge, auxPromo, idx, actProm, linesToCreate = [], qtyToReduce, lineToEdit, lineProm, linesToReduce, linesCreated = false, localSkipApplyPromotions; localSkipApplyPromotions = this.get('skipApplyPromotions'); this.set('skipApplyPromotions', true); //reset pendingQtyOffer value of each promotion groupedOrder.get('lines').forEach(function (l) { _.each(l.get('promotions'), function (promo) { promo.pendingQtyOffer = promo.qtyOffer; }); //copy lines from virtual ticket to original ticket when they have promotions which avoid us to merge lines if (_.find(l.get('promotions'), function (promo) { return promo.doNotMerge; })) { //First, try to find lines with the same qty lineToEdit = _.find(me.get('lines').models, function (line) { if (l !== line && l.get('product').id === line.get('product').id && l.get('price') === line.get('price') && line.get('qty') === l.get('qty') && !_.find(line.get('promotions'), function (promo) { return promo.manual; }) && !_.find(line.get('promotions'), function (promo) { return promo.doNotMerge; })) { return line; } }); //if we cannot find lines with same qty, find lines with qty > 0 if (!lineToEdit) { lineToEdit = _.find(me.get('lines').models, function (line) { if (l !== line && l.get('product').id === line.get('product').id && l.get('price') === line.get('price') && line.get('qty') > 0 && !_.find(line.get('promotions'), function (promo) { return promo.manual; })) { return line; } }); } //if promotion affects only to few quantities of the line, create a new line with quantities not affected by the promotion if (lineToEdit.get('qty') > l.get('qty')) { linesToCreate.push({ product: lineToEdit.get('product'), qty: l.get('qty'), attrs: { promotions: l.get('promotions'), promotionCandidates: l.get('promotionCandidates'), qtyToApplyDiscount: l.get('qtyToApplyDiscount') } }); lineToEdit.set('qty', OB.DEC.sub(lineToEdit.get('qty'), l.get('qty')), { silent: true }); //if promotion affects to several lines, edit first line with the promotion info and then remove the affected lines } else if (lineToEdit.get('qty') < l.get('qty')) { qtyToReduce = OB.DEC.sub(l.get('qty'), lineToEdit.get('qty')); linesToReduce = _.filter(me.get('lines').models, function (line) { if (l !== line && l.get('product').id === line.get('product').id && l.get('price') === line.get('price') && line.get('qty') > 0 && !_.find(line.get('promotions'), function (promo) { return promo.manual || promo.doNotMerge; })) { return line; } }); lineProm = linesToReduce.shift(); lineProm.set('qty', l.get('qty')); lineProm.set('promotions', l.get('promotions')); lineProm.set('promotionCandidates', l.get('promotionCandidates')); lineProm.set('qtyToApplyDiscount', l.get('qtyToApplyDiscount')); lineProm.trigger('change'); _.each(linesToReduce, function (line) { if (line.get('qty') > qtyToReduce) { line.set({ qty: line.get('qty') - qtyToReduce }, { silent: true }); qtyToReduce = OB.DEC.Zero; } else if (line.get('qty') === qtyToReduce) { me.get('lines').remove(line); qtyToReduce = OB.DEC.Zero; } else { qtyToReduce = qtyToReduce - line.get('qty'); me.get('lines').remove(line); } }); //when qty of the promotion is equal to the line qty, we copy line info. } else { lineToEdit.set('qty', l.get('qty')); lineToEdit.set('promotions', l.get('promotions')); lineToEdit.set('promotionCandidates', l.get('promotionCandidates')); lineToEdit.set('qtyToApplyDiscount', l.get('qtyToApplyDiscount')); lineToEdit.trigger('change'); } } else { //Filter lines which can be merged linesToMerge = _.filter(me.get('lines').models, function (line) { var qtyReserved = 0; (line.get('promotions') || []).forEach( function (p) { qtyReserved = OB.DEC.add(qtyReserved, p.qtyOfferReserved || 0); }); if (l !== line && l.get('product').id === line.get('product').id && l.get('price') === line.get('price') && OB.DEC.sub(line.get('qty'), qtyReserved) > 0 && !_.find(line.get('promotions'), function (promo) { return promo.manual || promo.doNotMerge; })) { return line; } }); if (linesToMerge.length > 0) { _.each(linesToMerge, function (line) { line.set('promotionCandidates', l.get('promotionCandidates')); line.set('promotionMessages', me.showMessagesPromotions(line.get('promotionMessages'), l.get('promotionMessages'))); line.set('qtyToApplyDiscount', l.get('qtyToApplyDiscount')); _.each(l.get('promotions'), function (promo) { copiedPromo = JSON.parse(JSON.stringify(promo)); //when ditributing the promotion between different lines, we save accumulated amount promo.distributedAmt = promo.distributedAmt ? promo.distributedAmt : OB.DEC.Zero; //pendingQtyOffer is the qty of the promotion which need to be apply (we decrease this qty in each loop) promo.pendingQtyOffer = !_.isUndefined(promo.pendingQtyOffer) ? promo.pendingQtyOffer : promo.qtyOffer; if (promo.pendingQtyOffer && promo.pendingQtyOffer >= line.get('qty')) { //if _.isUndefined(promo.actualAmt) is true we do not distribute the discount if (_.isUndefined(promo.actualAmt)) { if (promo.pendingQtyOffer !== promo.qtyOffer) { copiedPromo.hidden = true; copiedPromo.amt = OB.DEC.Zero; } } else { copiedPromo.actualAmt = (promo.fullAmt / promo.qtyOffer) * line.get('qty'); copiedPromo.amt = (promo.fullAmt / promo.qtyOffer) * line.get('qty'); copiedPromo.obdiscQtyoffer = line.get('qty'); promo.distributedAmt = OB.DEC.add(promo.distributedAmt, OB.DEC.toNumber(OB.DEC.toBigDecimal((promo.fullAmt / promo.qtyOffer) * line.get('qty')))); } if (promo.pendingQtyOffer === line.get('qty')) { if (!_.isUndefined(promo.actualAmt) && promo.actualAmt && promo.actualAmt !== promo.distributedAmt) { copiedPromo.actualAmt = OB.DEC.add(copiedPromo.actualAmt, OB.DEC.sub(promo.actualAmt, promo.distributedAmt)); copiedPromo.amt = promo.amt ? OB.DEC.add(copiedPromo.amt, OB.DEC.sub(promo.amt, promo.distributedAmt)) : promo.amt; } promo.pendingQtyOffer = null; } else { promo.pendingQtyOffer = promo.pendingQtyOffer - line.get('qty'); } if (line.get('promotions')) { auxPromo = _.find(line.get('promotions'), function (promo) { return promo.ruleId === copiedPromo.ruleId; }); if (auxPromo) { idx = line.get('promotions').indexOf(auxPromo); line.get('promotions').splice(idx, 1, copiedPromo); } else { line.get('promotions').push(copiedPromo); } } else { line.set('promotions', [copiedPromo]); } } else if (promo.pendingQtyOffer) { if (_.isUndefined(promo.actualAmt)) { if (promo.pendingQtyOffer !== promo.qtyOffer) { copiedPromo.hidden = true; copiedPromo.amt = OB.DEC.Zero; } } else { copiedPromo.actualAmt = (promo.fullAmt / promo.qtyOffer) * promo.pendingQtyOffer; copiedPromo.amt = (promo.fullAmt / promo.qtyOffer) * promo.pendingQtyOffer; copiedPromo.obdiscQtyoffer = promo.pendingQtyOffer; promo.distributedAmt = OB.DEC.add(promo.distributedAmt, OB.DEC.toNumber(OB.DEC.toBigDecimal((promo.fullAmt / promo.qtyOffer) * promo.pendingQtyOffer))); } if (!_.isUndefined(promo.actualAmt) && promo.actualAmt && promo.actualAmt !== promo.distributedAmt) { copiedPromo.actualAmt = OB.DEC.add(copiedPromo.actualAmt, OB.DEC.sub(promo.actualAmt, promo.distributedAmt)); copiedPromo.amt = promo.amt ? OB.DEC.add(copiedPromo.amt, OB.DEC.sub(promo.amt, promo.distributedAmt)) : promo.amt; } if (line.get('promotions')) { auxPromo = _.find(line.get('promotions'), function (promo) { return promo.ruleId === copiedPromo.ruleId; }); if (auxPromo) { idx = line.get('promotions').indexOf(auxPromo); line.get('promotions').splice(idx, 1, copiedPromo); } else { line.get('promotions').push(copiedPromo); } } else { line.set('promotions', [copiedPromo]); } promo.pendingQtyOffer = null; //if it is the first we enter in this method, promotions which are not in the virtual ticket are deleted. } else if (isFirstTime) { actProm = _.find(line.get('promotions'), function (prom) { return prom.ruleId === promo.ruleId; }); if (actProm) { idx = line.get('promotions').indexOf(actProm); if (idx > -1) { line.get('promotions').splice(idx, 1); } } } }); line.trigger('change'); }); } } }); if (!linesCreated) { _.each(linesToCreate, function (line) { me.createLine(line.product, line.qty, null, line.attrs); }); linesCreated = true; } this.get('lines').forEach(function (l) { l.calculateGross(); }); this.calculateGross(); this.trigger('promotionsUpdated'); this.set('skipApplyPromotions', localSkipApplyPromotions); }, // for each line, decrease the qtyOffer of promotions and remove the lines with qty 0 removeQtyOffer: function () { var linesPending = new Backbone.Collection(); this.get('lines').forEach(function (l) { var promotionsApplyNext = [], promotionsCascadeApplied = [], qtyReserved = 0, qtyPending; if (l.get('promotions')) { promotionsApplyNext = []; promotionsCascadeApplied = []; l.get('promotions').forEach(function (p) { if (p.qtyOfferReserved > 0) { qtyReserved = OB.DEC.add(qtyReserved, p.qtyOfferReserved); } // if it is a promotions with applyNext, the line is related to the promotion, so, when applyPromotions is called again, // if the promotion is similar to this promotion, then no changes have been done, then stop if (p.applyNext) { promotionsApplyNext.push(p); promotionsCascadeApplied.push(p); } }); } qtyPending = OB.DEC.sub(l.get('qty'), qtyReserved); l.set('qty', qtyPending); l.set('promotions', promotionsApplyNext); l.set('promotionsCascadeApplied', promotionsCascadeApplied); }); _.each(this.get('lines').models, function (line) { if (line.get('qty') > 0) { linesPending.add(line); } }); this.get('lines').reset(linesPending.models); }, removeLinesWithoutPromotions: function () { var linesPending = new Backbone.Collection(); _.each(this.get('lines').models, function (l) { if (l.get('promotions') && l.get('promotions').length > 0) { linesPending.push(l); } }); this.set('lines', linesPending); }, hasPromotions: function () { var hasPromotions = false; this.get('lines').forEach(function (l) { if (l.get('promotions') && l.get('promotions').length > 0) { hasPromotions = true; } }); return hasPromotions; }, isSimilarLine: function (line1, line2) { var equalPromotions = function (x, y) { var isEqual = true; if (x.length !== y.length) { isEqual = false; } else { x.forEach(function (p1, ind) { if (p1.amt !== y[ind].amt || p1.displayedTotalAmount !== y[ind].displayedTotalAmount || p1.qtyOffer !== y[ind].qtyOffer || p1.qtyOfferReserved !== y[ind].qtyOfferReserved || p1.ruleId !== y[ind].ruleId || p1.obdiscQtyoffer !== y[ind].obdiscQtyoffer) { isEqual = false; } }); } return isEqual; }; if (line1.get('product').get('id') === line2.get('product').get('id') && line1.get('price') === line2.get('price') && line1.get('discountedLinePrice') === line2.get('discountedLinePrice') && line1.get('qty') === line2.get('qty')) { return equalPromotions(line1.get('promotions') || [], line2.get('promotions') || []); } else { return false; } }, // if there is a promtion of type "applyNext" that it has been applied previously in the line, then It is replaced // by the first promotion applied. Ex: // Ex: prod1 - qty 5 - disc3x2 & discPriceAdj -> priceAdj is applied first to 5 units // it is called to applyPromotions, with the 2 units frees, and priceAdj is applied again to this 2 units // it is wrong, only to 5 units should be applied priceAdj, no 5 + 2 units removePromotionsCascadeApplied: function () { this.get('lines').forEach(function (l) { if (!OB.UTIL.isNullOrUndefined(l.get('promotions')) && l.get('promotions').length > 0 && !OB.UTIL.isNullOrUndefined(l.get('promotionsCascadeApplied')) && l.get('promotionsCascadeApplied').length > 0) { l.get('promotions').forEach(function (p, ind) { l.get('promotionsCascadeApplied').forEach(function (pc) { if (p.ruleId === pc.ruleId) { l.get('promotions')[ind] = pc; } }); }); } }); }, showMessagesPromotions: function (arrayMessages1, arrayMessages2) { arrayMessages1 = arrayMessages1 || []; (arrayMessages2 || []).forEach(function (m2) { if (_.filter(arrayMessages1, function (m1) { return m1 === m2; }).length === 0) { arrayMessages1.push(m2); OB.UTIL.showAlert.display(m2); } }); return arrayMessages1; }, getOrderDescription: function () { var desc = 'Id: ' + this.get('id') + ". Docno: " + this.get('documentNo') + ". Total gross: " + this.get('gross') + ". Lines: ["; var i = 0; this.get('lines').forEach(function (l) { if (i !== 0) { desc += ","; } desc += '{Product: ' + l.get('product').get('_identifier') + ', Quantity: ' + l.get('qty') + ' Gross: ' + l.get('gross') + '}'; i++; }); desc += ']'; return desc; } }); var OrderList = Backbone.Collection.extend({ model: Order, constructor: function (modelOrder) { if (modelOrder) { //this._id = 'modelorderlist'; this.modelorder = modelOrder; } Backbone.Collection.prototype.constructor.call(this); }, initialize: function () { var me = this; this.current = null; if (this.modelorder) { this.modelorder.on('saveCurrent', function () { me.saveCurrent(); }); } }, newOrder: function () { var order = new Order(), me = this, documentseq, documentseqstr, receiptProperties, i, p; // reset in new order properties defined in Receipt Properties dialog if (OB.MobileApp.view.$.containerWindow && OB.MobileApp.view.$.containerWindow.getRoot() && OB.MobileApp.view.$.containerWindow.getRoot().$.receiptPropertiesDialog) { receiptProperties = OB.MobileApp.view.$.containerWindow.getRoot().$.receiptPropertiesDialog.newAttributes; for (i = 0; i < receiptProperties.length; i++) { if (receiptProperties[i].modelProperty) { order.set(receiptProperties[i].modelProperty, ''); } if (receiptProperties[i].extraProperties) { for (p = 0; p < receiptProperties[i].extraProperties.length; p++) { order.set(receiptProperties[i].extraProperties[p], ''); } } } } order.set('client', OB.POS.modelterminal.get('terminal').client); order.set('organization', OB.POS.modelterminal.get('terminal').organization); order.set('createdBy', OB.POS.modelterminal.get('orgUserId')); order.set('updatedBy', OB.POS.modelterminal.get('orgUserId')); order.set('documentType', OB.POS.modelterminal.get('terminal').terminalType.documentType); order.set('orderType', 0); // 0: Sales order, 1: Return order, 2: Layaway, 3: Void Layaway order.set('generateInvoice', false); order.set('isQuotation', false); order.set('oldId', null); order.set('session', OB.POS.modelterminal.get('session')); order.set('priceList', OB.POS.modelterminal.get('terminal').priceList); order.set('priceIncludesTax', OB.POS.modelterminal.get('pricelist').priceIncludesTax); if (OB.POS.modelterminal.hasPermission('OBPOS_receipt.invoice')) { if (OB.POS.modelterminal.hasPermission('OBPOS_retail.restricttaxidinvoice') && !OB.POS.modelterminal.get('businessPartner').get('taxID')) { order.set('generateInvoice', false); } else { order.set('generateInvoice', OB.POS.modelterminal.get('terminal').terminalType.generateInvoice); } } else { order.set('generateInvoice', false); } order.set('currency', OB.POS.modelterminal.get('terminal').currency); order.set('currency' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, OB.POS.modelterminal.get('terminal')['currency' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER]); order.set('warehouse', OB.POS.modelterminal.get('terminal').warehouse); order.set('salesRepresentative', OB.POS.modelterminal.get('context').user.id); order.set('salesRepresentative' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, OB.POS.modelterminal.get('context').user._identifier); order.set('posTerminal', OB.POS.modelterminal.get('terminal').id); order.set('posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, OB.POS.modelterminal.get('terminal')._identifier); order.set('orderDate', new Date()); order.set('isPaid', false); order.set('paidOnCredit', false); order.set('isLayaway', false); order.set('taxes', null); documentseq = OB.POS.modelterminal.get('documentsequence') + 1; documentseqstr = OB.UTIL.padNumber(documentseq, 7); OB.POS.modelterminal.set('documentsequence', documentseq); order.set('documentNo', OB.POS.modelterminal.get('terminal').docNoPrefix + '/' + documentseqstr); order.set('bp', OB.POS.modelterminal.get('businessPartner')); order.set('print', true); order.set('sendEmail', false); order.set('openDrawer', false); return order; }, newPaidReceipt: function (model, callback) { var order = new Order(), lines, me = this, documentseq, documentseqstr, bp, newline, prod, payments, curPayment, taxes, bpId, bpLocId, numberOfLines = model.receiptLines.length, orderQty = 0; // Call orderLoader plugings to adjust remote model to local model first // ej: sales on credit: Add a new payment if total payment < total receipt // ej: gift cards: Add a new payment for each gift card discount _.each(OB.Model.modelLoaders, function (f) { f(model); }); //model.set('id', null); lines = new Backbone.Collection(); // set all properties coming from the model order.set(model); // setting specific properties order.set('isbeingprocessed', 'N'); order.set('hasbeenpaid', 'Y'); order.set('isEditable', false); order.set('checked', model.checked); //TODO: what is this for, where it comes from? order.set('paidOnCredit', false); if (model.isQuotation) { order.set('isQuotation', true); order.set('oldId', model.orderid); order.set('id', null); order.set('documentType', OB.POS.modelterminal.get('terminal').terminalType.documentTypeForQuotations); } if (model.isLayaway) { order.set('isLayaway', true); order.set('id', model.orderid); order.set('createdBy', OB.MobileApp.model.usermodel.id); order.set('hasbeenpaid', 'N'); order.set('session', OB.POS.modelterminal.get('session')); } else { order.set('isPaid', true); if (model.receiptPayments.length === 0 && model.totalamount > 0 && !model.isQuotation) { order.set('paidOnCredit', true); } order.set('id', model.orderid); if (order.get('documentType') === OB.POS.modelterminal.get('terminal').terminalType.documentTypeForReturns) { //return order.set('orderType', 1); } } bpLocId = model.bpLocId; bpId = model.bp; OB.Dal.get(OB.Model.BusinessPartner, bpId, function (bp) { OB.Dal.get(OB.Model.BPLocation, bpLocId, function (bpLoc) { bp.set('locName', bpLoc.get('name')); bp.set('locId', bpLoc.get('id')); order.set('bp', bp); order.set('gross', model.totalamount); order.set('net', model.totalNetAmount); order.trigger('calculategross'); _.each(model.receiptLines, function (iter) { var price; if (order.get('priceIncludesTax')) { price = OB.DEC.number(iter.unitPrice); } else { price = OB.DEC.number(iter.baseNetUnitPrice); } OB.Dal.get(OB.Model.Product, iter.id, function (prod) { newline = new OrderLine({ product: prod, uOM: iter.uOM, qty: OB.DEC.number(iter.quantity), price: price, priceList: prod.get('listPrice'), promotions: iter.promotions, priceIncludesTax: order.get('priceIncludesTax'), warehouse: { id: iter.warehouse, warehousename: iter.warehousename } }); newline.calculateGross(); // add the created line lines.add(newline); numberOfLines--; orderQty = OB.DEC.add(iter.quantity, orderQty); if (numberOfLines === 0) { order.set('lines', lines); order.set('qty', orderQty); if (order.get('orderType') === 1) { order.changeSignToShowReturns(); } order.set('json', JSON.stringify(order.toJSON())); callback(order); } }); }); order.set('orderDate', moment(model.orderDate.toString(), "YYYY-MM-DD").toDate()); order.set('creationDate', moment(model.creationDate.toString(), "YYYY-MM-DD hh:m:ss.s").toDate()); //order.set('payments', model.receiptPayments); payments = new PaymentLineList(); _.each(model.receiptPayments, function (iter) { var paymentProp; curPayment = new PaymentLine(); for (paymentProp in iter) { if (iter.hasOwnProperty(paymentProp)) { if (paymentProp === "paymentDate") { if (!OB.UTIL.isNullOrUndefined(iter[paymentProp]) && moment(iter[paymentProp]).isValid()) { curPayment.set(paymentProp, new Date(iter[paymentProp])); } else { curPayment.set(paymentProp, null); } } else { curPayment.set(paymentProp, iter[paymentProp]); } } } payments.add(curPayment); }); order.set('payments', payments); order.adjustPayment(); taxes = {}; _.each(model.receiptTaxes, function (iter) { var taxProp; taxes[iter.taxid] = {}; for (taxProp in iter) { if (iter.hasOwnProperty(taxProp)) { taxes[iter.taxid][taxProp] = iter[taxProp]; } } }); order.set('taxes', taxes); }, function () { // TODO: Report errors properly }); }, function () { // TODO: Report errors properly }); }, newDynamicOrder: function (model, callback) { var order = new Backbone.Model(), undf; _.each(_.keys(model), function (key) { if (model[key] !== undf) { if (model[key] === null) { order.set(key, null); } else { order.set(key, model[key]); } } }); callback(order); }, addNewOrder: function () { this.saveCurrent(); this.current = this.newOrder(); this.add(this.current); this.loadCurrent(true); }, addFirstOrder: function () { this.addNewOrder(); }, addPaidReceipt: function (model) { this.saveCurrent(); this.current = model; this.add(this.current); this.loadCurrent(true); // OB.Dal.save is done here because we want to force to save with the original od, only this time. OB.Dal.save(model, function () {}, function () { OB.error(arguments); }, model.get('isLayaway')); }, addMultiReceipt: function (model) { OB.Dal.save(model, function () {}, function () { OB.error(arguments); }, model.get('isLayaway')); }, addNewQuotation: function () { var documentseq, documentseqstr; this.saveCurrent(); this.current = this.newOrder(); OB.POS.modelterminal.set('documentsequence', OB.POS.modelterminal.get('documentsequence') - 1); this.current.set('isQuotation', true); this.current.set('generateInvoice', false); this.current.set('documentType', OB.POS.modelterminal.get('terminal').terminalType.documentTypeForQuotations); documentseq = OB.POS.modelterminal.get('quotationDocumentSequence') + 1; documentseqstr = OB.UTIL.padNumber(documentseq, 7); OB.POS.modelterminal.set('quotationDocumentSequence', documentseq); this.current.set('documentNo', OB.POS.modelterminal.get('terminal').quotationDocNoPrefix + '/' + documentseqstr); this.add(this.current); this.loadCurrent(); }, deleteCurrentFromDatabase: function (orderToDelete) { OB.Dal.remove(orderToDelete, function () { return true; }, function () { OB.UTIL.showError('Error removing'); }); }, deleteCurrent: function (forceCreateNew) { var isNew = false; if (this.current) { this.remove(this.current); if (this.length > 0 && !forceCreateNew) { this.current = this.at(this.length - 1); } else { this.current = this.newOrder(); this.add(this.current); isNew = true; } this.loadCurrent(isNew); } }, load: function (model) { // Workaround to prevent the pending receipts moder window from remaining open // when the current receipt is selected from the list if (model && this.current && model.get('documentNo') === this.current.get('documentNo')) { return; } this.saveCurrent(); this.current = model; this.loadCurrent(); }, saveCurrent: function () { if (this.current) { this.current.clearWith(this.modelorder); } }, loadCurrent: function (isNew) { if (this.current) { if (isNew) { //set values of new attrs in current, //this values will be copied to modelOrder //in the next instruction this.modelorder.trigger('beforeChangeOrderForNewOne', this.current); this.current.set('isNewReceipt', true); } this.modelorder.clearWith(this.current); this.modelorder.set('isNewReceipt', false); } } }); var MultiOrders = Backbone.Model.extend({ modelName: 'MultiOrders', defaults: { total: OB.DEC.Zero, payment: OB.DEC.Zero, pending: OB.DEC.Zero, change: OB.DEC.Zero, openDrawer: false, additionalInfo: null }, initialize: function () { this.set('multiOrdersList', new Backbone.Collection()); this.set('payments', new Backbone.Collection()); // ISSUE 24487: Callbacks of this collection still exists if you come back from other page. // Force to remove callbacks this.get('multiOrdersList').off(); }, getPaymentStatus: function () { var total = OB.DEC.abs(this.getTotal()); var pay = this.getPayment(); return { 'total': OB.I18N.formatCurrency(total), 'pending': OB.DEC.compare(OB.DEC.sub(pay, total)) >= 0 ? OB.I18N.formatCurrency(OB.DEC.Zero) : OB.I18N.formatCurrency(OB.DEC.sub(total, pay)), 'change': OB.DEC.compare(this.getChange()) > 0 ? OB.I18N.formatCurrency(this.getChange()) : null, 'overpayment': OB.DEC.compare(OB.DEC.sub(pay, total)) > 0 ? OB.I18N.formatCurrency(OB.DEC.sub(pay, total)) : null, 'isReturn': this.get('gross') < 0 ? true : false, 'isNegative': this.get('gross') < 0 ? true : false, 'changeAmt': this.getChange(), 'pendingAmt': OB.DEC.compare(OB.DEC.sub(pay, total)) >= 0 ? OB.DEC.Zero : OB.DEC.sub(total, pay), 'payments': this.get('payments') }; }, adjustPayment: function () { var i, max, p; var payments = this.get('payments'); var total = OB.DEC.abs(this.getTotal()); var nocash = OB.DEC.Zero; var cash = OB.DEC.Zero; var origCash = OB.DEC.Zero; var auxCash = OB.DEC.Zero; var prevCash = OB.DEC.Zero; var paidCash = OB.DEC.Zero; var pcash; for (i = 0, max = payments.length; i < max; i++) { p = payments.at(i); if (p.get('rate') && p.get('rate') !== '1') { p.set('origAmount', OB.DEC.mul(p.get('amount'), p.get('rate'))); } else { p.set('origAmount', p.get('amount')); } p.set('paid', p.get('origAmount')); if (p.get('kind') === OB.POS.modelterminal.get('paymentcash')) { // The default cash method cash = OB.DEC.add(cash, p.get('origAmount')); pcash = p; paidCash = OB.DEC.add(paidCash, p.get('origAmount')); } else if (OB.POS.modelterminal.hasPayment(p.get('kind')) && OB.POS.modelterminal.hasPayment(p.get('kind')).paymentMethod.iscash) { // Another cash method origCash = OB.DEC.add(origCash, p.get('origAmount')); pcash = p; paidCash = OB.DEC.add(paidCash, p.get('origAmount')); } else { nocash = OB.DEC.add(nocash, p.get('origAmount')); } } // Calculation of the change.... //FIXME if (pcash) { if (pcash.get('kind') !== OB.POS.modelterminal.get('paymentcash')) { auxCash = origCash; prevCash = cash; } else { auxCash = cash; prevCash = origCash; } if (OB.DEC.compare(nocash - total) > 0) { pcash.set('paid', OB.DEC.Zero); this.set('payment', nocash); this.set('change', OB.DEC.add(cash, origCash)); } else if (OB.DEC.compare(OB.DEC.sub(OB.DEC.add(OB.DEC.add(nocash, cash), origCash), total)) > 0) { pcash.set('paid', OB.DEC.sub(total, OB.DEC.add(nocash, OB.DEC.sub(paidCash, pcash.get('origAmount'))))); this.set('payment', total); //The change value will be computed through a rounded total value, to ensure that the total plus change //add up to the paid amount without any kind of precission loss this.set('change', OB.DEC.sub(OB.DEC.add(OB.DEC.add(nocash, cash), origCash), OB.Utilities.Number.roundJSNumber(total, 2))); } else { pcash.set('paid', auxCash); this.set('payment', OB.DEC.add(OB.DEC.add(nocash, cash), origCash)); this.set('change', OB.DEC.Zero); } } else { if (payments.length > 0) { if (this.get('payment') === 0 || nocash > 0) { this.set('payment', nocash); } } else { this.set('payment', OB.DEC.Zero); } this.set('change', OB.DEC.Zero); } }, addPayment: function (payment) { var payments, total; var i, max, p, order; if (!OB.DEC.isNumber(payment.get('amount'))) { alert(OB.I18N.getLabel('OBPOS_MsgPaymentAmountError')); return; } payments = this.get('payments'); total = OB.DEC.abs(this.getTotal()); order = this; OB.UTIL.HookManager.executeHooks('OBPOS_preAddPayment', { paymentToAdd: payment, payments: payments, receipt: this }, function () { if (!payment.get('paymentData')) { // search for an existing payment only if there is not paymentData info. // this avoids to merge for example card payments of different cards. for (i = 0, max = payments.length; i < max; i++) { p = payments.at(i); if (p.get('kind') === payment.get('kind') && !p.get('isPrePayment')) { p.set('amount', OB.DEC.add(payment.get('amount'), p.get('amount'))); if (p.get('rate') && p.get('rate') !== '1') { p.set('origAmount', OB.DEC.add(payment.get('origAmount'), OB.DEC.mul(p.get('origAmount'), p.get('rate')))); } order.adjustPayment(); order.trigger('displayTotal'); return; } } } if (payment.get('openDrawer') && (payment.get('allowOpenDrawer') || payment.get('isCash'))) { order.set('openDrawer', payment.get('openDrawer')); } payment.set('date', new Date()); payments.add(payment); order.adjustPayment(); order.trigger('displayTotal'); }); }, removePayment: function (payment) { var payments = this.get('payments'); payments.remove(payment); if (payment.get('openDrawer')) { this.set('openDrawer', false); } this.adjustPayment(); }, printGross: function () { return OB.I18N.formatCurrency(this.getTotal()); }, getTotal: function () { return this.get('total'); }, getChange: function () { return this.get('change'); }, getPayment: function () { return this.get('payment'); }, getPending: function () { return OB.DEC.sub(OB.DEC.abs(this.getTotal()), this.getPayment()); }, toInvoice: function (status) { if (status === false) { this.unset('additionalInfo'); _.each(this.get('multiOrdersList').models, function (order) { order.unset('generateInvoice'); }, this); return; } this.set('additionalInfo', 'I'); _.each(this.get('multiOrdersList').models, function (order) { order.set('generateInvoice', true); }, this); }, resetValues: function () { //this.set('isMultiOrders', false); this.get('multiOrdersList').reset(); this.set('total', OB.DEC.Zero); this.set('payment', OB.DEC.Zero); this.set('pending', OB.DEC.Zero); this.set('change', OB.DEC.Zero); this.get('payments').reset(); this.set('openDrawer', false); this.set('additionalInfo', null); }, hasDataInList: function () { if (this.get('multiOrdersList') && this.get('multiOrdersList').length > 0) { return true; } return false; } }); var TaxLine = Backbone.Model.extend(); OB.Data.Registry.registerModel(OrderLine); OB.Data.Registry.registerModel(PaymentLine); // order model is not registered using standard Registry method becasue list is // becasue collection is specific window.OB.Model.Order = Order; window.OB.Collection.OrderList = OrderList; window.OB.Model.TaxLine = TaxLine; window.OB.Model.MultiOrders = MultiOrders; window.OB.Model.modelLoaders = []; }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var CashUp = OB.Data.ExtensibleModel.extend({ modelName: 'CashUp', tableName: 'cashup', entityName: 'CashUp', source: '', local: true }); CashUp.addProperties([{ name: 'id', column: 'cashup_id', primaryKey: true, type: 'TEXT' }, { name: 'netSales', column: 'netSales', type: 'NUMERIC' }, { name: 'grossSales', column: 'grossSales', type: 'NUMERIC' }, { name: 'netReturns', column: 'netReturns', type: 'NUMERIC' }, { name: 'grossReturns', column: 'grossReturns', type: 'NUMERIC' }, { name: 'totalRetailTransactions', column: 'totalRetailTransactions', type: 'NUMERIC' }, { name: 'createdDate', column: 'createdDate', type: 'TEXT' }, { name: 'userId', column: 'userId', type: 'TEXT' }, { name: 'objToSend', column: 'objToSend', type: 'TEXT' }, { name: 'isbeingprocessed', column: 'isbeingprocessed', type: 'TEXT' }]); OB.Data.Registry.registerModel(CashUp); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var CashManagement = OB.Data.ExtensibleModel.extend({ modelName: 'CashManagement', tableName: 'cashmanagement', entityName: 'CashManagement', source: '', local: true }); CashManagement.addProperties([{ name: 'id', column: 'cashmanagement_id', primaryKey: true, type: 'TEXT' }, { name: 'description', column: 'description', type: 'TEXT' }, { name: 'amount', column: 'amount', type: 'NUMERIC' }, { name: 'origAmount', column: 'origAmount', type: 'NUMERIC' }, { name: 'type', column: 'type', type: 'TEXT' }, { name: 'reasonId', column: 'reasonId', type: 'TEXT' }, { name: 'paymentMethodId', column: 'paymentMethodId', type: 'TEXT' }, { name: 'user', column: 'user', type: 'TEXT' }, { name: 'userId', column: 'userId', type: 'TEXT' }, { name: 'time', column: 'time', type: 'TEXT' }, { name: 'isocode', column: 'isocode', type: 'TEXT' }, { name: 'cashup_id', column: 'cashup_id', type: 'TEXT' }, { name: 'glItem', column: 'glItem', type: 'TEXT' }, { name: 'isbeingprocessed', column: 'isbeingprocessed', type: 'TEXT' }]); CashManagement.addIndex([{ name: 'cashmgmt_idx', columns: [{ name: 'cashup_id', sort: 'desc' }, { name: 'paymentMethodId', sort: 'desc' }] }]); OB.Data.Registry.registerModel(CashManagement); }()); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, _, console, enyo, Backbone, window, confirm, $LAB, SynchronizationHelper, OB, BigDecimal, document, setTimeout, setInterval */ (function () { var executeWhenDOMReady; OB.Model.POSTerminal = OB.Model.Terminal.extend({ initialize: function () { var me = this; me.set({ appName: 'WebPOS', appModuleId: 'FF808181326CC34901326D53DBCF0018', terminalName: window.localStorage.getItem('terminalAuthentication') === 'Y' ? window.localStorage.getItem('terminalName') : OB.UTIL.getParameterByName("terminal"), supportsOffline: true, loginUtilsUrl: '../../org.openbravo.retail.posterminal.service.loginutils', loginHandlerUrl: '../../org.openbravo.retail.posterminal/POSLoginHandler', applicationFormatUrl: '../../org.openbravo.client.kernel/OBPOS_Main/ApplicationFormats', logoutUrlParams: window.localStorage.getItem('terminalAuthentication') === 'Y' ? {} : { terminal: OB.UTIL.getParameterByName("terminal") }, logConfiguration: { deviceIdentifier: window.localStorage.getItem('terminalAuthentication') === 'Y' ? window.localStorage.getItem('terminalName') : OB.UTIL.getParameterByName("terminal"), logPropertiesExtension: [ function () { return { online: OB.MobileApp.model.get('connectedToERP') }; }] }, profileOptions: { showOrganization: false, showWarehouse: false, defaultProperties: { role: 'oBPOSDefaultPOSRole' } }, // setting here the localDB, overrides the OB.MobileApp.model localDB default localDB: { size: OB.UTIL.VersionManagement.current.posterminal.WebSQLDatabase.size, name: OB.UTIL.VersionManagement.current.posterminal.WebSQLDatabase.name, displayName: OB.UTIL.VersionManagement.current.posterminal.WebSQLDatabase.displayName, version: OB.UTIL.VersionManagement.current.posterminal.WebSQLDatabase.major + '.' + OB.UTIL.VersionManagement.current.posterminal.WebSQLDatabase.minor }, logDBTrxThreshold: 300, logDBStmtThreshold: 1000 }); this.initActions(function () { me.set('terminalName', window.localStorage.getItem('terminalAuthentication') === 'Y' ? window.localStorage.getItem('terminalName') : OB.UTIL.getParameterByName("terminal")); me.set('logoutUrlParams', window.localStorage.getItem('terminalAuthentication') === 'Y' ? {} : { terminal: OB.UTIL.getParameterByName("terminal") }); me.set('logConfiguration', { deviceIdentifier: window.localStorage.getItem('terminalAuthentication') === 'Y' ? window.localStorage.getItem('terminalName') : OB.UTIL.getParameterByName("terminal"), logPropertiesExtension: [ function () { return { online: OB.MobileApp.model.get('connectedToERP') }; }] }); }); this.addPropertiesLoader({ properties: ['terminal'], loadFunction: function (terminalModel) { var synchId = SynchronizationHelper.busyUntilFinishes('addPropertiesLoader'); OB.info('Loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.Terminal').exec(null, function (data) { SynchronizationHelper.finished(synchId, 'addPropertiesLoader'); if (data.exception) { if (OB.I18N.hasLabel(data.exception.message)) { OB.UTIL.showLoading(false); OB.UTIL.showConfirmation.display('Error', OB.I18N.getLabel(data.exception.message), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { terminalModel.logout(); OB.UTIL.showLoading(true); } }], { onHideFunction: function () { OB.UTIL.showLoading(true); terminalModel.logout(); } }); } else { var msg = ""; if (data.exception.message !== undefined) { msg = " Error: " + data.exception.message; } OB.UTIL.showConfirmation.display('Error', OB.I18N.getLabel('OBPOS_errorLoadingTerminal') + msg, [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.UTIL.showLoading(true); terminalModel.logout(); } }], { onHideFunction: function () { OB.UTIL.showLoading(true); terminalModel.logout(); } }); } } else if (data[0]) { terminalModel.set(me.properties[0], data[0]); window.localStorage.setItem('terminalId', data[0].id); terminalModel.set('useBarcode', terminalModel.get('terminal').terminalType.usebarcodescanner); OB.MobileApp.view.scanningFocus(true); if (!terminalModel.usermodel) { terminalModel.setUserModelOnline(); } else { terminalModel.propertiesReady(me.properties); } OB.UTIL.HookManager.executeHooks('OBPOS_TerminalLoadedFromBackend', { data: data[0] }); } else { OB.UTIL.showError("Terminal does not exists: " + 'params.terminal'); } }); } }); this.addPropertiesLoader({ properties: ['context'], sync: false, loadFunction: function (terminalModel) { OB.info('Loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.mobile.core.login.Context').exec({ terminal: OB.MobileApp.model.get('terminalName'), ignoreForConnectionStatus: true }, function (data) { if (data[0]) { terminalModel.set(me.properties[0], data[0]); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['payments'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.Payments').exec(null, function (data) { if (data) { var i, max, paymentlegacy, paymentcash, paymentcashcurrency; terminalModel.set(me.properties[0], data); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['cashMgmtDepositEvents'], loadFunction: function (terminalModel) { console.log('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.CashMgmtDepositEvents').exec(null, function (data) { if (data) { terminalModel.set(me.properties[0], data); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['cashMgmtDropEvents'], loadFunction: function (terminalModel) { console.log('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.CashMgmtDropEvents').exec(null, function (data) { if (data) { terminalModel.set(me.properties[0], data); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['businesspartner'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.BusinessPartner').exec(null, function (data) { if (data[0]) { //TODO set backbone model terminalModel.set(me.properties[0], data[0].id); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['location'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.Location').exec(null, function (data) { if (data[0]) { terminalModel.set(me.properties[0], data[0]); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['pricelist'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.PriceList').exec(null, function (data) { if (data[0]) { terminalModel.set(me.properties[0], data[0]); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['warehouses'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.Warehouses').exec(null, function (data) { if (data && data.exception) { //MP17 terminalModel.set(me.properties[0], []); } else { terminalModel.set(me.properties[0], data); } terminalModel.propertiesReady(me.properties); }); } }); this.addPropertiesLoader({ properties: ['writableOrganizations'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; new OB.DS.Process('org.openbravo.retail.posterminal.term.WritableOrganizations').exec(null, function (data) { if (data.length > 0) { terminalModel.set(me.properties[0], data); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['pricelistversion'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; var params = {}; var currentDate = new Date(); params.terminalTime = currentDate; params.terminalTimeOffset = currentDate.getTimezoneOffset(); new OB.DS.Request('org.openbravo.retail.posterminal.term.PriceListVersion').exec(params, function (data) { if (data[0]) { terminalModel.set(me.properties[0], data[0]); terminalModel.propertiesReady(me.properties); } }); } }); this.addPropertiesLoader({ properties: ['currency'], loadFunction: function (terminalModel) { OB.info('loading... ' + this.properties); var me = this; new OB.DS.Request('org.openbravo.retail.posterminal.term.Currency').exec(null, function (data) { if (data[0]) { terminalModel.set(me.properties[0], data[0]); //Precision used by arithmetics operations is set using the currency terminalModel.propertiesReady(me.properties); } }); } }); this.get('dataSyncModels').push({ model: OB.Model.ChangedBusinessPartners, className: 'org.openbravo.retail.posterminal.CustomerLoader', criteria: {} }); this.get('dataSyncModels').push({ model: OB.Model.ChangedBPlocation, className: 'org.openbravo.retail.posterminal.CustomerAddrLoader', criteria: {} }); this.get('dataSyncModels').push({ model: OB.Model.Order, className: 'org.openbravo.retail.posterminal.OrderLoader', timeout: 60000, criteria: { hasbeenpaid: 'Y' } }); this.get('dataSyncModels').push({ model: OB.Model.CashManagement, isPersistent: true, className: 'org.openbravo.retail.posterminal.ProcessCashMgmt', criteria: { 'isbeingprocessed': 'N' } }); this.get('dataSyncModels').push({ model: OB.Model.CashUp, className: 'org.openbravo.retail.posterminal.ProcessCashClose', timeout: 600000, criteria: { isbeingprocessed: 'Y' }, postProcessingFunction: function (data, callback) { OB.UTIL.initCashUp(function () { OB.UTIL.deleteCashUps(data); callback(); }); } }); this.on('ready', function () { var terminal = this.get('terminal'); // Set Hardware.. OB.POS.hwserver = new OB.DS.HWServer(terminal.hardwareurl, terminal.scaleurl); // Set Arithmetic properties: OB.DEC.setContext(OB.UTIL.getFirstValidValue([me.get('currency').obposPosprecision, me.get('currency').pricePrecision]), BigDecimal.prototype.ROUND_HALF_UP); // Set disable promotion discount property OB.Dal.find(OB.Model.Discount, { _whereClause: "where m_offer_type_id in (" + OB.Model.Discounts.getManualPromotions() + ")" }, function (promos) { if (promos.length === 0) { me.set('isDisableDiscount', true); } else { me.set('isDisableDiscount', false); } }, function () { return true; }); OB.UTIL.HookManager.executeHooks('OBPOS_LoadPOSWindow', {}, function () { OB.POS.navigate('retail.pointofsale'); }); if (me.get('loggedOffline') === true) { OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_OfflineLogin')); } OB.POS.hwserver.print(new OB.DS.HWResource(OB.OBPOSPointOfSale.Print.WelcomeTemplate), {}); }); this.on('logout', function () { // Logged out. go to login window me.off('loginfail'); // Redirect to login window window.localStorage.setItem('target-window', window.location.href); //window.location = window.location.pathname + '?terminal=' + window.encodeURIComponent(OB.POS.paramTerminal); }); OB.Model.Terminal.prototype.initialize.call(me); }, runSyncProcess: function (successCallback, errorCallback) { var me = this; if (window.localStorage.getItem('terminalAuthentication') === 'Y') { var process = new OB.DS.Process('org.openbravo.retail.posterminal.CheckTerminalAuth'); process.exec({ terminalName: window.localStorage.getItem('terminalName'), terminalKeyIdentifier: window.localStorage.getItem('terminalKeyIdentifier'), terminalAuthentication: window.localStorage.getItem('terminalAuthentication') }, function (data, message) { if (data && data.exception) { //ERROR or no connection OB.error(OB.I18N.getLabel('OBPOS_TerminalAuthError')); } else if (data && (data.isLinked === false || data.terminalAuthentication)) { if (data.isLinked === false) { window.localStorage.removeItem('terminalName'); window.localStorage.removeItem('terminalKeyIdentifier'); } if (data.terminalAuthentication) { window.localStorage.setItem('terminalAuthentication', data.terminalAuthentication); } OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_TerminalAuthChange'), OB.I18N.getLabel('OBPOS_TerminalAuthChangeMsg'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.UTIL.showLoading(true); me.logout(); } }], { onHideFunction: function () { OB.UTIL.showLoading(true); me.logout(); } }); } else { OB.UTIL.HookManager.executeHooks('OBPOS_PreSynchData', {}, function () { OB.UTIL.showI18NWarning('OBPOS_SynchronizingDataMessage', 'OBPOS_SynchronizationWasSuccessfulMessage'); OB.MobileApp.model.syncAllModels(function () { OB.UTIL.showI18NSuccess('OBPOS_SynchronizationWasSuccessfulMessage', 'OBPOS_SynchronizingDataMessage'); if (successCallback) { successCallback(); } }, errorCallback); }); } }); } else { OB.UTIL.HookManager.executeHooks('OBPOS_PreSynchData', {}, function () { OB.UTIL.showI18NWarning('OBPOS_SynchronizingDataMessage', 'OBPOS_SynchronizationWasSuccessfulMessage'); OB.MobileApp.model.syncAllModels(function () { OB.UTIL.showI18NSuccess('OBPOS_SynchronizationWasSuccessfulMessage', 'OBPOS_SynchronizingDataMessage'); if (successCallback) { successCallback(); } }, errorCallback); }); } }, returnToOnline: function () { //The session is fine, we don't need to warn the user //but we will attempt to send all pending orders automatically this.runSyncProcess(); }, renderMain: function () { var i, paymentcashcurrency, paymentcash, paymentlegacy, max, me = this; if (!OB.UTIL.isSupportedBrowser()) { OB.MobileApp.model.renderLogin(); return false; } OB.DS.commonParams = OB.DS.commonParams || {}; OB.DS.commonParams = { client: this.get('terminal').client, organization: this.get('terminal').organization, pos: this.get('terminal').id, terminalName: this.get('terminalName') }; //LEGACY this.paymentnames = {}; for (i = 0, max = this.get('payments').length; i < max; i++) { this.paymentnames[this.get('payments')[i].payment.searchKey] = this.get('payments')[i]; if (this.get('payments')[i].payment.searchKey === 'OBPOS_payment.cash') { paymentlegacy = this.get('payments')[i].payment.searchKey; } if (this.get('payments')[i].paymentMethod.iscash) { paymentcash = this.get('payments')[i].payment.searchKey; } if (this.get('payments')[i].paymentMethod.iscash && this.get('payments')[i].paymentMethod.currency === this.get('terminal').currency) { paymentcashcurrency = this.get('payments')[i].payment.searchKey; } } // sets the default payment method this.set('paymentcash', paymentcashcurrency || paymentcash || paymentlegacy); // add the currency converters _.each(OB.POS.modelterminal.get('payments'), function (paymentMethod) { var fromCurrencyId = parseInt(OB.POS.modelterminal.get('currency').id, 10); var toCurrencyId = parseInt(paymentMethod.paymentMethod.currency, 10); if (fromCurrencyId !== toCurrencyId) { OB.UTIL.currency.addConversion(toCurrencyId, fromCurrencyId, paymentMethod.rate); OB.UTIL.currency.addConversion(fromCurrencyId, toCurrencyId, paymentMethod.mulrate); } }, this); OB.UTIL.initCashUp(OB.UTIL.calculateCurrentCash); OB.MobileApp.model.on('window:ready', function () { if (window.localStorage.getItem('terminalAuthentication') === 'Y') { var process = new OB.DS.Process('org.openbravo.retail.posterminal.CheckTerminalAuth'); process.exec({ terminalName: window.localStorage.getItem('terminalName'), terminalKeyIdentifier: window.localStorage.getItem('terminalKeyIdentifier'), terminalAuthentication: window.localStorage.getItem('terminalAuthentication') }, function (data, message) { if (data && data.exception) { //ERROR or no connection OB.error(OB.I18N.getLabel('OBPOS_TerminalAuthError')); } else if (data && (data.isLinked === false || data.terminalAuthentication)) { if (data.isLinked === false) { window.localStorage.removeItem('terminalName'); window.localStorage.removeItem('terminalKeyIdentifier'); } if (data.terminalAuthentication) { window.localStorage.setItem('terminalAuthentication', data.terminalAuthentication); } OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_TerminalAuthChange'), OB.I18N.getLabel('OBPOS_TerminalAuthChangeMsg'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.UTIL.showLoading(true); me.logout(); } }], { onHideFunction: function () { OB.UTIL.showLoading(true); me.logout(); } }); } }); } }); this.on('seqNoReady', function () { this.trigger('ready'); //NAVIGATE }, this); this.setDocumentSequence(); }, postLoginActions: function () { var me = this, loadModelsIncFunc; //MASTER DATA REFRESH var minIncRefresh = this.get('terminal').terminalType.minutestorefreshdatainc * 60 * 1000; if (minIncRefresh) { if (this.get('loggedUsingCache')) { OB.MobileApp.model.set('minIncRefreshSynchronized', false); OB.MobileApp.model.on('synchronized', function () { if (OB.MobileApp.model.get('minIncRefreshSynchronized')) { return; } OB.MobileApp.model.set('minIncRefreshSynchronized', true); OB.MobileApp.model.loadModels(null, true); if (me.get('loggedUsingCache')) { me.set('loggedUsingCache', false); me.renderTerminalMain(); } }); } else { if (me.get('loggedUsingCache')) { me.set('loggedUsingCache', false); me.renderTerminalMain(); } } loadModelsIncFunc = function () { OB.MobileApp.model.loadModels(null, true); }; setInterval(loadModelsIncFunc, minIncRefresh); } else if (me.get('loggedUsingCache')) { me.set('loggedUsingCache', false); me.renderTerminalMain(); } }, cleanSessionInfo: function () { this.cleanTerminalData(); }, preLoginActions: function () { this.cleanSessionInfo(); }, preLogoutActions: function () { if (OB.POS.hwserver !== undefined) { OB.POS.hwserver.print(new OB.DS.HWResource(OB.OBPOSPointOfSale.Print.GoodByeTemplate), {}); } this.cleanSessionInfo(); }, postCloseSession: function (session) { //All pending to be paid orders will be removed on logout OB.Dal.find(OB.Model.Order, { 'session': session.get('id'), 'hasbeenpaid': 'N' }, function (orders) { var i, j, order, orderlines, orderline, errorFunc = function () { OB.error(arguments); }; var triggerLogoutFunc = function () { OB.MobileApp.model.triggerLogout(); }; if (orders.models.length === 0) { //If there are no orders to remove, a logout is triggered OB.MobileApp.model.triggerLogout(); } for (i = 0; i < orders.models.length; i++) { order = orders.models[i]; OB.Dal.removeAll(OB.Model.Order, { 'order': order.get('id') }, null, errorFunc); //Logout will only be triggered after last order OB.Dal.remove(order, i < orders.models.length - 1 ? null : triggerLogoutFunc, errorFunc); } }, function () { OB.error(arguments); OB.MobileApp.model.triggerLogout(); }); }, compareDocSeqWithPendingOrdersAndSave: function (maxDocumentSequence, maxQuotationDocumentSequence) { var orderDocNo, quotationDocNo; // compare the last document number returned from the ERP with // the last document number of the unprocessed pending lines (if any) OB.Dal.find(OB.Model.Order, {}, function (fetchedOrderList) { var criteria, maxDocumentSequencePendingOrders; if (!fetchedOrderList || fetchedOrderList.length === 0) { // There are no pending orders, the initial document sequence // will be the one fetched from the database OB.MobileApp.model.saveDocumentSequenceAndGo(maxDocumentSequence, maxQuotationDocumentSequence); } else { // There are pending orders. The document sequence will be set // to the maximum of the pending order document sequence and the // document sequence retrieved from the server maxDocumentSequencePendingOrders = OB.MobileApp.model.getMaxDocumentSequenceFromPendingOrders(fetchedOrderList.models); if (maxDocumentSequencePendingOrders.orderDocNo > maxDocumentSequence) { orderDocNo = maxDocumentSequencePendingOrders.orderDocNo; } else { orderDocNo = maxDocumentSequence; } if (maxDocumentSequencePendingOrders.quotationDocNo > maxQuotationDocumentSequence) { quotationDocNo = maxDocumentSequencePendingOrders.quotationDocNo; } else { quotationDocNo = maxQuotationDocumentSequence; } OB.MobileApp.model.saveDocumentSequenceAndGo(orderDocNo, quotationDocNo); } }, function () { // If c_order does not exist yet, go with the sequence // number fetched from the server OB.MobileApp.model.saveDocumentSequenceAndGo(maxDocumentSequence, maxQuotationDocumentSequence); }); }, getMaxDocumentSequenceFromPendingOrders: function (pendingOrders) { var nPreviousOrders = pendingOrders.length, maxDocumentSequence = OB.MobileApp.model.get('terminal').lastDocumentNumber, maxQuotationDocumentSequence = OB.MobileApp.model.get('terminal').lastQuotationDocumentNumber, orderCompleteDocumentNo, orderDocumentSequence, i; for (i = 0; i < nPreviousOrders; i++) { orderCompleteDocumentNo = pendingOrders[i].get('documentNo'); if (!pendingOrders[i].get('isQuotation')) { orderDocumentSequence = OB.UTIL.getNumberOfSequence(pendingOrders[i].get('documentNo'), false); if (orderDocumentSequence > maxDocumentSequence) { maxDocumentSequence = orderDocumentSequence; } } else { orderDocumentSequence = OB.UTIL.getNumberOfSequence(pendingOrders[i].get('documentNo'), true); if (orderDocumentSequence > maxQuotationDocumentSequence) { maxQuotationDocumentSequence = orderDocumentSequence; } } } return { orderDocNo: maxDocumentSequence, quotationDocNo: maxQuotationDocumentSequence }; }, saveDocumentSequenceAndGo: function (documentSequence, quotationDocumentSequence) { this.set('documentsequence', documentSequence); this.set('quotationDocumentSequence', quotationDocumentSequence); this.trigger('seqNoReady'); }, setDocumentSequence: function () { // Obtains the persisted document number (documentno of the last processed order) OB.Dal.find(OB.Model.DocumentSequence, { 'posSearchKey': OB.MobileApp.model.terminalName }, function (documentsequence) { var lastInternalDocumentSequence, lastInternalQuotationSequence, max, maxquote; if (documentsequence && documentsequence.length > 0) { lastInternalDocumentSequence = documentsequence.at(0).get('documentSequence'); lastInternalQuotationSequence = documentsequence.at(0).get('quotationDocumentSequence'); // Compares the persisted document number with the fetched from the server if (lastInternalDocumentSequence > OB.MobileApp.model.get('terminal').lastDocumentNumber) { max = lastInternalDocumentSequence; } else { max = OB.MobileApp.model.get('terminal').lastDocumentNumber; } if (lastInternalQuotationSequence > OB.MobileApp.model.get('terminal').lastQuotationDocumentNumber) { maxquote = lastInternalQuotationSequence; } else { maxquote = OB.MobileApp.model.get('terminal').lastQuotationDocumentNumber; } // Compares the maximum with the document number of the paid pending orders OB.MobileApp.model.compareDocSeqWithPendingOrdersAndSave(max, maxquote); } else { max = OB.MobileApp.model.get('terminal').lastDocumentNumber; maxquote = OB.MobileApp.model.get('terminal').lastQuotationDocumentNumber; // Compares the maximum with the document number of the paid pending orders OB.MobileApp.model.compareDocSeqWithPendingOrdersAndSave(max, maxquote); } }, function () { var max = OB.MobileApp.model.get('terminal').lastDocumentNumber, maxquote = OB.MobileApp.model.get('terminal').lastQuotationDocumentNumber; // Compares the maximum with the document number of the paid pending orders OB.MobileApp.model.compareDocSeqWithPendingOrdersAndSave(max, maxquote); }); }, saveDocumentSequenceInDB: function () { var me = this, documentSequence = this.get('documentsequence'), quotationDocumentSequence = this.get('quotationDocumentSequence'), criteria = { 'posSearchKey': this.get('terminal').searchKey }; OB.Dal.find(OB.Model.DocumentSequence, criteria, function (documentSequenceList) { var docSeq; if (documentSequenceList && documentSequenceList.length !== 0) { // There can only be one documentSequence model in the list (posSearchKey is unique) docSeq = documentSequenceList.models[0]; // There exists already a document sequence, update it docSeq.set('documentSequence', documentSequence); docSeq.set('quotationDocumentSequence', quotationDocumentSequence); } else { // There is not a document sequence for the pos, create it docSeq = new OB.Model.DocumentSequence(); docSeq.set('posSearchKey', me.get('terminal').searchKey); docSeq.set('documentSequence', documentSequence); docSeq.set('quotationDocumentSequence', quotationDocumentSequence); } OB.Dal.save(docSeq, null, function () { OB.error(arguments); }); }); }, getPaymentName: function (key) { if (this.paymentnames[key] && this.paymentnames[key].payment && this.paymentnames[key].payment._identifier) { return this.paymentnames[key].payment._identifier; } return null; }, hasPayment: function (key) { return this.paymentnames[key]; }, isSafeToResetDatabase: function (callbackIsSafe, callbackIsNotSafe) { OB.Dal.find(OB.Model.Order, { hasbeenpaid: 'Y' }, function (models) { if (models.length > 0) { callbackIsNotSafe(); return; } OB.Dal.find(OB.Model.CashManagement, { 'isbeingprocessed': 'N' }, function (models) { if (models.length > 0) { callbackIsNotSafe(); return; } OB.Dal.find(OB.Model.CashUp, { isbeingprocessed: 'Y' }, function (models) { if (models.length > 0) { callbackIsNotSafe(); return; } OB.Dal.find(OB.Model.ChangedBusinessPartners, null, function (models) { if (models.length > 0) { callbackIsNotSafe(); return; } callbackIsSafe(); }, callbackIsSafe); }, callbackIsSafe); }, callbackIsSafe); }, callbackIsSafe); }, databaseCannotBeResetAction: function () { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_ResetNeededNotSafeTitle'), OB.I18N.getLabel('OBPOS_ResetNeededNotSafeMessage', [window.localStorage.getItem('terminalName')])); }, dialog: null, preLoadContext: function (callback) { if (!window.localStorage.getItem('terminalKeyIdentifier') && !window.localStorage.getItem('terminalName') && window.localStorage.getItem('terminalAuthentication') === 'Y') { OB.UTIL.showLoading(false); if (OB.UI.ModalSelectTerminal) { this.dialog = OB.MobileApp.view.$.confirmationContainer.createComponent({ kind: 'OB.UI.ModalSelectTerminal', name: 'modalSelectTerminal', callback: callback, context: this }); this.dialog.show(); } } else { callback(); } }, linkTerminal: function (terminalData, callback) { var params = this.get('loginUtilsParams') || {}, me = this; params.command = 'preLoginActions'; params.params = terminalData; new OB.OBPOSLogin.UI.LoginRequest({ url: OB.MobileApp.model.get('loginUtilsUrl') }).response(this, function (inSender, inResponse) { if (inResponse.exception) { OB.UTIL.showConfirmation.display('Error', OB.I18N.getLabel(inResponse.exception), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { if (OB.UI.ModalSelectTerminal) { me.dialog = OB.MobileApp.view.$.confirmationContainer.createComponent({ kind: 'OB.UI.ModalSelectTerminal', name: 'modalSelectTerminal', callback: callback, context: me }); me.dialog.show(); } } }], { onHideFunction: function () { if (OB.UI.ModalSelectTerminal) { me.dialog = OB.MobileApp.view.$.confirmationContainer.createComponent({ kind: 'OB.UI.ModalSelectTerminal', name: 'modalSelectTerminal', callback: callback, context: me }); me.dialog.show(); } } }); } else { OB.appCaption = inResponse.appCaption; OB.MobileApp.model.set('terminalName', inResponse.terminalName); OB.POS.modelterminal.get('loginUtilsParams').terminalName = OB.MobileApp.model.get('terminalName'); // OB.MobileApp.model.get('loginUtilsParams').terminalName = OB.MobileApp.model.get('terminalName'); window.localStorage.setItem('terminalName', OB.MobileApp.model.get('terminalName')); window.localStorage.setItem('terminalKeyIdentifier', inResponse.terminalKeyIdentifier); callback(); } }).error(function (inSender, inResponse) { callback(); }).go(params); }, initActions: function (callback) { var params = this.get('loginUtilsParams') || {}, me = this; params.command = 'initActions'; new OB.OBPOSLogin.UI.LoginRequest({ url: '../../org.openbravo.retail.posterminal.service.loginutils' }).response(this, function (inSender, inResponse) { window.localStorage.setItem('terminalAuthentication', inResponse.terminalAuthentication); OB.MobileApp.model.set('terminalName', window.localStorage.getItem('terminalAuthentication') === 'Y' ? window.localStorage.getItem('terminalName') : OB.UTIL.getParameterByName("terminal")); OB.POS.modelterminal.set('loginUtilsParams', { terminalName: OB.MobileApp.model.get('terminalName') }); callback(); }).error(function (inSender, inResponse) { callback(); }).go(params); } }); OB.POS = { modelterminal: new OB.Model.POSTerminal(), paramWindow: OB.UTIL.getParameterByName("window") || "retail.pointofsale", paramTerminal: window.localStorage.getItem('terminalAuthentication') === 'Y' ? window.localStorage.getItem('terminalName') : OB.UTIL.getParameterByName("terminal"), hrefWindow: function (windowname) { return '?terminal=' + window.encodeURIComponent(OB.MobileApp.model.get('terminalName')) + '&window=' + window.encodeURIComponent(windowname); }, logout: function (callback) { this.modelterminal.logout(); }, lock: function (callback) { this.modelterminal.lock(); }, windows: null, navigate: function (route) { this.modelterminal.navigate(route); }, registerWindow: function (window) { OB.MobileApp.windowRegistry.registerWindow(window); }, cleanWindows: function () { this.modelterminal.cleanWindows(); } }; OB.POS.modelterminal.set('loginUtilsParams', { terminalName: OB.MobileApp.model.get('terminalName') }); OB.Constants = { FIELDSEPARATOR: '$', IDENTIFIER: '_identifier' }; OB.Format = window.OB.Format || {}; OB.I18N = window.OB.I18N || {}; OB.I18N.labels = {}; executeWhenDOMReady = function () { if (document.readyState === "interactive" || document.readyState === "complete") { OB.POS.modelterminal.off('loginfail'); } else { setTimeout(function () { executeWhenDOMReady(); }, 50); } }; executeWhenDOMReady(); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, Backbone, _, enyo, Audio */ // HWServer: TODO: this should be implemented in HW Manager module OB.DS.HWResource = function (res) { this.resource = res; this.resourcedata = null; }; OB.DS.HWResource.prototype.getData = function (callback) { if (this.resourcedata) { callback(this.resourcedata); } else { OB.UTIL.loadResource(this.resource, function (data) { this.resourcedata = data; callback(this.resourcedata); }, this); } }; OB.DS.HWServer = function (url, scaleurl) { this.url = url; this.scaleurl = scaleurl; }; OB.DS.HWServer.prototype.getWeight = function (callback) { if (this.scaleurl) { var me = this; var ajaxRequest = new enyo.Ajax({ url: me.scaleurl, cacheBust: false, method: 'GET', handleAs: 'json', contentType: 'application/x-www-form-urlencoded; charset=UTF-8', success: function (inSender, inResponse) { callback(inResponse); }, fail: function (inSender, inResponse) { if (callback) { callback({ exception: { message: (OB.I18N.getLabel('OBPOS_MsgScaleServerNotAvailable')) }, result: 1 }); } } }); ajaxRequest.go().response('success').error('fail'); } else { callback({ result: 1 }); } }; OB.DS.HWServer.prototype.openDrawerTemplate = 'res/opendrawer.xml'; OB.DS.HWServer.prototype.openDrawer = function (popup, timeout) { var template = new OB.DS.HWResource(this.openDrawerTemplate); this.print(template, null, function (args) { if (args && args.exception && args.exception.message) { OB.info('Error opening the drawer'); } }); if (OB.MobileApp.model.get('permissions').OBPOS_closeDrawerBeforeContinue) { this.drawerClosed = false; OB.POS.hwserver.isDrawerClosed(popup, timeout); } }; OB.DS.HWServer.prototype.openCheckDrawer = function (popup, timeout) { this.checkDrawer(function () { this.openDrawer(popup, timeout); }, this); }; OB.DS.HWServer.prototype.checkDrawer = function (callback, context) { if (!OB.MobileApp.model.get('permissions').OBPOS_closeDrawerBeforeContinue || this.drawerClosed) { if (context) { return callback.apply(context); } else { return callback(); } } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_drawerOpened')); return false; } }; OB.DS.HWServer.prototype.isDrawerClosedTemplate = 'res/checkdrawerstatus.xml'; OB.DS.HWServer.prototype.isDrawerClosed = function (popup, timeout) { var statusChecker, beepTimeout, sound = new Audio('sounds/drawerAlert.mp3'), template = new OB.DS.HWResource(this.isDrawerClosedTemplate), me = this, errorCounter = 0, symbol, symbolAtRight, popupDrawerOpened = OB.MobileApp.view.$.confirmationContainer.$.popupDrawerOpened; if (timeout && !isNaN(parseInt(timeout, 10))) { beepTimeout = setTimeout(function () { sound.loop = true; sound.play(); }, parseInt(timeout, 10)); } if (popup) { if (!popupDrawerOpened) { popupDrawerOpened = OB.MobileApp.view.$.confirmationContainer.createComponent({ kind: 'OB.UI.PopupDrawerOpened' }); } if (popup.receipt) { var paymentStatus = popup.receipt.getPaymentStatus(); popupDrawerOpened.$.table.setStyle('position:relative; top: 0px;'); if (paymentStatus.isReturn || paymentStatus.isNegative) { popupDrawerOpened.$.bodyContent.$.label.setContent(OB.I18N.getLabel('OBPOS_ToReturn') + ':'); _.each(popup.receipt.get('payments').models, function (payment) { if (payment.get('isCash')) { symbol = OB.MobileApp.model.paymentnames[payment.get('kind')].symbol; symbolAtRight = OB.MobileApp.model.paymentnames[payment.get('kind')].currencySymbolAtTheRight; popupDrawerOpened.$.bodyContent.$.label.setContent(popupDrawerOpened.$.bodyContent.$.label.getContent() + ' ' + OB.I18N.formatCurrencyWithSymbol(payment.get('paid'), symbol, symbolAtRight)); } }); } else { if (!paymentStatus.change) { popupDrawerOpened.$.bodyContent.$.label.setContent(OB.I18N.getLabel('OBPOS_PaymentsExact')); } else { popupDrawerOpened.$.bodyContent.$.label.setContent(OB.I18N.getLabel('OBPOS_ticketChange') + ': ' + OB.MobileApp.model.get('changeReceipt')); } } } else { popupDrawerOpened.$.bodyContent.$.label.setContent(''); popupDrawerOpened.$.table.setStyle('position:relative; top: 35px;'); } if (popup.openFirst) { OB.UTIL.showLoading(false); popupDrawerOpened.show(); } } statusChecker = setInterval(function () { me.print(template, null, function (args) { if (args && args.exception && args.exception.message) { OB.info('Error checking the status of the drawer'); me.drawerClosed = true; } else { if (args.resultData === "Closed") { me.drawerClosed = true; errorCounter = 0; } else if (args.resultData === "Opened") { me.drawerClosed = false; errorCounter = 0; if (popup && !popupDrawerOpened.showing) { OB.UTIL.showLoading(false); popupDrawerOpened.show(); } } else if (args.resultData === "Error") { errorCounter++; if (popup) { if (errorCounter >= 15) { me.drawerClosed = true; OB.info('Error checking the status of the drawer'); } else { me.drawerClosed = false; if (!popupDrawerOpened.showing) { OB.UTIL.showLoading(false); popupDrawerOpened.show(); } } } else { if (errorCounter >= 4) { me.drawerClosed = true; OB.info('Error checking the status of the drawer'); } else { me.drawerClosed = false; } } } else { me.drawerClosed = true; OB.info('Error checking the status of the drawer'); } } if (me.drawerClosed) { clearTimeout(beepTimeout); sound.pause(); clearInterval(statusChecker); if (popup && popupDrawerOpened.showing) { popupDrawerOpened.hide(); } } }); }, 700); }; OB.DS.HWServer.prototype.print = function (template, params, callback) { if (template) { if (template.getData) { var me = this; template.getData(function (data) { me.print(data, params, callback); }); } else { this._print(template, params, callback); } } }; OB.DS.HWServer.prototype._print = function (templatedata, params, callback) { this._send(this._template(templatedata, params), callback); }; OB.DS.HWServer.prototype._template = function (templatedata, params) { return params ? _.template(templatedata, params) : templatedata; }; OB.DS.HWServer.prototype._send = function (data, callback) { if (this.url) { var me = this; var ajaxRequest = new enyo.Ajax({ url: me.url, cacheBust: false, method: 'POST', handleAs: 'json', timeout: 6000, contentType: 'application/xml;charset=utf-8', data: data, success: function (inSender, inResponse) { if (callback) { callback(inResponse); } }, fail: function (inSender, inResponse) { // prevent more than one entry. if (this.failed) { return; } this.failed = true; if (callback) { callback({ data: data, exception: { message: (OB.I18N.getLabel('OBPOS_MsgHardwareServerNotAvailable')) } }); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgHardwareServerNotAvailable')); } } }); ajaxRequest.go(ajaxRequest.data).response('success').error('fail'); } }; OB.DS.HWServer.prototype._printPDF = function (params, callback) { this._sendPDF(JSON.stringify(params), callback); }; OB.DS.HWServer.prototype._sendPDF = function (data, callback) { if (this.url) { var me = this; var ajaxRequest = new enyo.Ajax({ url: me.url + 'pdf', cacheBust: false, method: 'POST', handleAs: 'json', timeout: 3000, contentType: 'application/json;charset=utf-8', data: data, success: function (inSender, inResponse) { if (callback) { callback(inResponse); } }, fail: function (inSender, inResponse) { // prevent more than one entry. if (this.failed) { return; } this.failed = true; if (callback) { callback({ exception: { data: data, message: (OB.I18N.getLabel('OBPOS_MsgHardwareServerNotAvailable')) } }); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgHardwareServerNotAvailable')); } } }); ajaxRequest.go(ajaxRequest.data).response('success').error('fail'); } }; /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, console, _ */ OB = window.OB || {}; OB.UTIL = window.OB.UTIL || {}; OB.UTIL.isDisableDiscount = function (receipt) { if (receipt.get('lines').length > 0) { return OB.POS.modelterminal.get('isDisableDiscount'); } else { return true; } }; OB.UTIL.getImageURL = function (id) { var imageUrl = 'productImages/'; var i; for (i = 0; i < id.length; i += 3) { if (i !== 0) { imageUrl += "/"; } imageUrl += id.substring(i, ((i + 3) < id.length) ? (i + 3) : id.length); } imageUrl += "/" + id; return imageUrl; }; OB.UTIL.getNumberOfSequence = function (documentNo, isQuotation) { if (!OB.UTIL.isNullOrUndefined(OB.MobileApp.model.get('terminal')) && !OB.UTIL.isNullOrUndefined(OB.MobileApp.model.get('terminal')).docNoPrefix) { var posDocumentNoPrefix = OB.MobileApp.model.get('terminal').docNoPrefix; if (isQuotation) { posDocumentNoPrefix = OB.MobileApp.model.get('terminal').quotationDocNoPrefix; } return parseInt(documentNo.substr(posDocumentNoPrefix.length + 1), 10); } else { return null; } }; /** * Facilitates to work reliably with currency conversions * in the easiest way, you will just need to do like this: * add the conversor: * OB.UTIL.currency.addConversion(fromCurrencyId, toCurrencyId) * * get the conversor, depending on what you want: * var cD = OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, amount) * var cF = OB.UTIL.currency.toForeignCurrency(toCurrencyId, amount) * * * expert use: * case 1: retail * when selling, to get the converted amount of a good, you should use getTangibleOf(amount) * e.g: the Avalanche Transceiver in sampledata cost 150.5€ or getTangibleOf(150.5) = 197.81$ * * case 2: doble conversion * when you have already converted one currency to another and want to convert the resulted amount again you will want to convert it back with full precision. use getFinancialAmountOf(amount) * e.g: when showing a foreign value to the user * * case 3: financial accounts (a doble conversion with sensitive data) * when you deposit foreign money in a local financial account you should use getFinancialAmountOf(amount) * e.g: when you deposit a 100$ bill in a bank account that is in euros -> getFinancialAmountOf(100) = 74.082324€ * */ OB.UTIL.currency = { conversions: [], webPOSDefaultCurrencyId: function () { return parseInt(OB.POS.modelterminal.get('currency').id, 10); }, isDefaultCurrencyId: function (currencyId) { currencyId = parseInt(currencyId, 10); return currencyId === OB.UTIL.currency.webPOSDefaultCurrencyId(); }, /** * add a conversion rate from the fromCurrencyId currency to the toCurrencyId currency into the conversions array * @param {currencyId} fromCurrencyId currencyId of the original amount * @param {currencyId} toCurrencyId currencyId of the resulting amount * @param {float} rate exchange rate to calculate the resulting amount */ addConversion: function (fromCurrencyId, toCurrencyId, rate) { fromCurrencyId = parseInt(fromCurrencyId, 10); toCurrencyId = parseInt(toCurrencyId, 10); rate = parseFloat(rate, 10); if (fromCurrencyId === toCurrencyId) { OB.error('DEVELOPER: there is no point in converting a currencyId to itself'); return; } var conversionAlreadyExists = this.findConverter(fromCurrencyId, toCurrencyId); if (conversionAlreadyExists) { if (conversionAlreadyExists.rate !== rate) { OB.error('DEVELOPER: The rate for a currency is trying to be changed. If you are not trying to change the rate, something needs critical and inmediate fixing. If you really want to change the rate and know what you are doing, clean the OB.UTIL.currency.conversions array and fill it again.'); } return; // the conversor is already present. this is fine, unless a lot of calls are finishing here } this.conversions.push({ fromCurrencyId: fromCurrencyId, toCurrencyId: toCurrencyId, rate: rate, toCurrencyIdPrecision: OB.DEC.getScale(), // TODO: get, from the backend, the precisions for the currency with the id = toCurrencyId isToCurrencyIdForeign: toCurrencyId !== OB.UTIL.currency.webPOSDefaultCurrencyId(), /** * Get a rounded exchanged amount that indicates the amount in the real world, say money, card tickets, etc * e.g: the Avalanche Transceiver in sampledata cost 150.5€ or getTangibleOf(150.5) = 197.81$ * @param {float} amountToRound the amount to be converted to toCurrencyId * @return {float} the converted amount using the exchange rate rounded to the precision set in preferences for toCurrencyId */ getTangibleOf: function (amountToRound) { if (this.toCurrencyId === OB.UTIL.currency.webPOSDefaultCurrencyId()) { OB.error('DEVELOPER: You cannot get a tangible of a foreign currency because it has already a value in local currency. If you are trying to get the amount for a financial account, use the getFinancialAmountOf function'); return; } return OB.DEC.mul(amountToRound, rate, OB.UTIL.currency.toCurrencyIdPrecision); }, /** * Get a full precision converted amount which origin is real money and will and will be added to a local currency financial account * e.g: when you deposit a 100$ bill in a bank account that is in euros -> getExchangeOfTangible(100) = 74.082€ * @param {float} amountToRound the amount to be converted to toCurrencyId * @return {float} the converted amount using the exchange rate rounded to the precision set in preferences for toCurrencyId */ getFinancialAmountOf: function (amount) { if (this.fromCurrencyId === OB.UTIL.currency.webPOSDefaultCurrencyId()) { OB.error('DEVELOPER: You are trying to get a financial amount value that is not from a foreign currency'); return; } return OB.DEC.mul(amount, rate); }, toString: function () { return this.fromCurrencyId + ' -> ' + this.toCurrencyId + '; rate:' + this.rate.toFixed(5); } }); }, /** * get all the converters available in the internal converters array * @return {array of converters} the converters available in the internal converters array */ getConversions: function () { return this.conversions; }, /** * Find the converter with the indicated fromCurrencyId and toCurrencyId in the internal converters array * Developer: you, most likely, won't need this function. If so, change this comment */ findConverter: function (fromCurrencyId, toCurrencyId) { return _.find(this.conversions, function (c) { return (c.fromCurrencyId === fromCurrencyId) && (c.toCurrencyId === toCurrencyId); }); }, /** * Returns a converter to operate with amounts that will be converted from fromCurrencyId to toCurrencyId * @param {currencyId} fromCurrencyId the original currencyId * @param {currencyId} toCurrencyId the destination currencyId * @return {converter} the converter to convert amounts from the fromCurrencyId currency to the toCurrencyId currency */ getConverter: function (fromCurrencyId, toCurrencyId) { fromCurrencyId = parseInt(fromCurrencyId, 10); toCurrencyId = parseInt(toCurrencyId, 10); var found = this.findConverter(fromCurrencyId, toCurrencyId); if (!found) { OB.error('DEVELOPER: Currency converter not added: ' + fromCurrencyId + ' -> ' + toCurrencyId); } return found; }, /** * Returns a converter whose original currency is not the WebPOS currency. e.g: USD in sampledata * and whose destiny curency is the WebPOS default currency. i.e: OB.POS.modelterminal.get('currency').id return this.getConverter(webPOSDefaultCurrencyId(), toCurrencyId); * @param {currencyId} fromCurrencyId the currencyId of the original currency * @return {converter} the converter to convert amounts from fromCurrencyId to the WebPOS default currency */ getToLocalConverter: function (fromCurrencyId) { fromCurrencyId = parseInt(fromCurrencyId, 10); return this.getConverter(fromCurrencyId, this.webPOSDefaultCurrencyId()); }, /** * Returns a converter whose destiny currency is not the WebPOS currency. e.g: USD in sampledata * and whose original curency is the WebPOS default currency. i.e: OB.POS.modelterminal.get('currency').id * @param {currencyId} toCurrencyId the currencyId of the destiny currency * @return {converter} the converter to convert amounts from WebPOS default currency to toCurrencyId */ getFromLocalConverter: function (toCurrencyId) { toCurrencyId = parseInt(toCurrencyId, 10); return this.getConverter(this.webPOSDefaultCurrencyId(), toCurrencyId); }, /** * converts an amount to the WebPOS amount currency * @param {currencyId} fromCurrencyId the currencyId of the amount to be converted * @param {float} amount the amount to be converted * @return {float} the converted amount */ toDefaultCurrency: function (fromCurrencyId, amount) { if (OB.UTIL.isNullOrUndefined(amount)) { OB.error('DEVELOPER: you are missing one parameter'); } fromCurrencyId = parseInt(fromCurrencyId, 10); if (fromCurrencyId === this.webPOSDefaultCurrencyId()) { return amount; } var converter = this.getToLocalConverter(fromCurrencyId); var foreignAmount = converter.getFinancialAmountOf(amount); return foreignAmount; }, /** * converts an amount from the WebPOS currency to the toCurrencyId currency * @param {currencyId} toCurrencyId the currencyId of the final amount * @param {float} amount the amount to be converted * @return {float} the converted amount */ toForeignCurrency: function (toCurrencyId, amount) { if (OB.UTIL.isNullOrUndefined(amount)) { OB.error('DEVELOPER: you are missing one parameter'); } toCurrencyId = parseInt(toCurrencyId, 10); if (toCurrencyId === this.webPOSDefaultCurrencyId()) { return amount; } var converter = this.getFromLocalConverter(toCurrencyId); var foreignAmount = converter.getTangibleOf(amount); return foreignAmount; } }; /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var BPCategory = OB.Data.ExtensibleModel.extend({ modelName: 'BPCategory', tableName: 'c_bp_group', entityName: 'BPCategory', source: 'org.openbravo.retail.posterminal.master.BPCategory', dataLimit: 300 }); BPCategory.addProperties([{ name: 'id', column: 'c_bp_group_id', primaryKey: true, type: 'TEXT' }, { name: 'searchKey', column: 'value', type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); OB.Data.Registry.registerModel(BPCategory); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global Backbone, _ */ (function () { var BPLocation = OB.Data.ExtensibleModel.extend({ modelName: 'BPLocation', tableName: 'c_bpartner_location', entityName: 'BPLocation', source: 'org.openbravo.retail.posterminal.master.BPLocation', dataLimit: 300, local: false, saveCustomerAddr: function (silent) { var nameLength, newSk; this.set('_identifier', this.get('name')); this.trigger('customerAddrSaved'); return true; //datacustomeraddrsave will catch this event and save this locally with changed = 'Y' //Then it will try to send to the backend }, loadById: function (CusAddrId, userCallback) { //search data in local DB and load it to this var me = this, criteria = { id: CusAddrId }; OB.Dal.find(OB.Model.BPLocation, criteria, function (customerAddr) { //OB.Dal.find success var successCallback, errorCallback; if (!customerAddr || customerAddr.length === 0) { me.clearModelWith(null); userCallback(me); } else { me.clearModelWith(customerAddr.at(0)); userCallback(me); } }); }, newCustomerAddr: function () { //set values of new attrs in bplocation model //this values will be copied to the created one //in the next instruction this.trigger('beforeChangeCustomerAddrForNewOne', this); this.clearModelWith(null); }, clearModelWith: function (cusToLoad) { var me = this, undf; if (cusToLoad === null) { this.set('id', null); this.set('bpartner', null); this.set('name', null); this.set('postalCode', null); this.set('cityName', null); this.set('countryId', OB.POS.modelterminal.get('terminal').defaultbp_bpcountry); this.set('countryName', OB.POS.modelterminal.get('terminal').defaultbp_bpcountry_name); this.set('client', OB.POS.modelterminal.get('terminal').client); this.set('organization', OB.POS.modelterminal.get('terminal').defaultbp_bporg); this.set('_identifier', null); } else { _.each(_.keys(cusToLoad.attributes), function (key) { if (cusToLoad.get(key) !== undf) { if (cusToLoad.get(key) === null) { me.set(key, null); } else if (cusToLoad.get(key).at) { //collection me.get(key).reset(); cusToLoad.get(key).forEach(function (elem) { me.get(key).add(elem); }); } else { //property me.set(key, cusToLoad.get(key)); } } }); } }, loadByJSON: function (obj) { var me = this, undf; _.each(_.keys(me.attributes), function (key) { if (obj[key] !== undf) { if (obj[key] === null) { me.set(key, null); } else { me.set(key, obj[key]); } } }); }, serializeToJSON: function () { return JSON.parse(JSON.stringify(this.toJSON())); } }); BPLocation.addProperties([{ name: 'id', column: 'c_bpartner_location_id', primaryKey: true, type: 'TEXT' }, { name: 'bpartner', column: 'c_bpartner_id', type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: 'postalCode', column: 'postalCode', type: 'TEXT' }, { name: 'cityName', column: 'cityName', type: 'TEXT' }, { name: 'countryName', column: 'countryName', type: 'TEXT' }, { name: 'countryId', column: 'countryId', type: 'TEXT' }, { name: 'regionName', column: 'regionName', type: 'TEXT' }, { name: 'regionId', column: 'regionId', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); BPLocation.addIndex([{ name: 'bploc_name_idx', columns: [{ name: 'name', sort: 'desc' }] }]); OB.Data.Registry.registerModel(BPLocation); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var CurrencyPanel = OB.Data.ExtensibleModel.extend({ modelName: 'CurrencyPanel', tableName: 'obpos_currency_panel', entityName: 'OBPOS_CurrencyPanel', source: 'org.openbravo.retail.posterminal.master.CurrencyPanel' }); CurrencyPanel.addProperties([{ name: 'id', column: 'obpos_currency_panel_id', primaryKey: true, type: 'TEXT' }, { name: 'currency', column: 'c_currency_id', type: 'TEXT' }, { name: 'amount', column: 'amount', type: 'NUMERIC' }, { name: 'backcolor', column: 'backcolor', type: 'TEXT' }, { name: 'bordercolor', column: 'bordercolor', type: 'TEXT' }, { name: 'lineNo', column: 'line', type: 'NUMERIC' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); CurrencyPanel.addIndex([{ name: 'currency_panel_idx', columns: [{ name: 'c_currency_id', sort: 'desc' }] }]); OB.Data.Registry.registerModel(CurrencyPanel); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var SalesRepresentative = OB.Data.ExtensibleModel.extend({ modelName: 'SalesRepresentative', tableName: 'ad_sales_representative', entityName: 'SalesRepresentative', source: 'org.openbravo.retail.posterminal.master.SalesRepresentative', dataLimit: 300 }); SalesRepresentative.addProperties([{ name: 'id', column: 'ad_sales_representative_id', primaryKey: true, type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: 'username', column: 'username', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); SalesRepresentative.addIndex([{ name: 'salesrep_identifier_idx', columns: [{ name: '_identifier', sort: 'desc' }] }]); OB.Data.Registry.registerModel(SalesRepresentative); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var ProductCharacteristic = OB.Data.ExtensibleModel.extend({ modelName: 'ProductCharacteristic', tableName: 'm_product_ch', entityName: 'ProductCharacteristic', source: 'org.openbravo.retail.posterminal.master.ProductCharacteristic', dataLimit: 300 }); ProductCharacteristic.addProperties([{ name: 'm_product_ch_id', column: 'm_product_id', primaryKey: true, type: 'TEXT' }, { name: 'm_product', column: 'm_product', type: 'TEXT' }, { name: 'characteristic_id', column: 'characteristic_id', type: 'TEXT' }, { name: 'characteristic', column: 'characteristic', type: 'TEXT' }, { name: 'ch_value_id', column: 'ch_value_id', type: 'TEXT' }, { name: 'ch_value', column: 'ch_value', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); OB.Data.Registry.registerModel(ProductCharacteristic); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var ProductChValue = OB.Data.ExtensibleModel.extend({ modelName: 'ProductChValue', tableName: 'm_ch_value', entityName: 'ProductChValue', source: 'org.openbravo.retail.posterminal.master.ProductChValue', dataLimit: 300 }); ProductChValue.addProperties([{ name: 'id', column: 'id', primaryKey: true, type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: 'characteristic_id', column: 'characteristic_id', type: 'TEXT' }, { name: 'parent', column: 'parent', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); OB.Data.Registry.registerModel(ProductChValue); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var Brand = OB.Data.ExtensibleModel.extend({ modelName: 'Brand', tableName: 'm_brand', entityName: 'Brand', source: 'org.openbravo.retail.posterminal.master.Brand', dataLimit: 300 }); Brand.addProperties([{ name: 'id', column: 'm_product_id', primaryKey: true, type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: '_identifier', column: '_identifier', filter: true, type: 'TEXT' }]); OB.Data.Registry.registerModel(Brand); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var ReturnReason = OB.Data.ExtensibleModel.extend({ modelName: 'ReturnReason', tableName: 'c_return_reason', entityName: 'ReturnReason', source: 'org.openbravo.retail.posterminal.master.ReturnReason', dataLimit: 300 }); ReturnReason.addProperties([{ name: 'id', column: 'c_return_reason_id', primaryKey: true, type: 'TEXT' }, { name: 'searchKey', column: 'searchKey', type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); OB.Data.Registry.registerModel(ReturnReason); }()); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, console, _, SynchronizationHelper */ /** * OB.Model.Executor provides a mechanism to execute actions synchronously even each of * these actions are not synchronous. It is managed with two queues: one for events and * another one for actions. Each event has a series of actions to be executed synchronously, * when all actions in the event are finished, next event is started. */ OB.Model.Executor = Backbone.Model.extend({ defaults: { executing: false }, initialize: function () { var eventQueue = new Backbone.Collection(); this.set('eventQueue', eventQueue); this.set('actionQueue', new Backbone.Collection()); eventQueue.on('add', function () { if (!this.get('executing')) { // Adding an event to an empty queue, firing it this.nextEvent(); } }, this); }, removeGroup: function (groupId) { var evtQueue = this.get('eventQueue'); evtQueue.where({ groupId: groupId }).forEach(function (evt) { evt.reportSynchronizationHelper(); evtQueue.remove(evt); }, this); this.set('eventQueue', evtQueue); }, addEvent: function (event, replaceExistent) { var synchId = SynchronizationHelper.busyUntilFinishes('executor'); var evtQueue = this.get('eventQueue'), currentEvt, actionQueue, currentExecutionQueue; if (replaceExistent && evtQueue) { currentEvt = this.get('currentEvent'); evtQueue.where({ id: event.get('id') }).forEach(function (evt) { if (currentEvt === evt) { this.set('eventQueue'); actionQueue.remove(actionQueue.models); } evtQueue.remove(evt); currentExecutionQueue = (this.get('exec') || 0) - 1; this.set('exec', currentExecutionQueue); }, this); } this.set('exec', (this.get('exec') || 0) + 1); event.reportSynchronizationHelper = function () { SynchronizationHelper.finished(synchId, 'executor'); }; event.on('finish', function () { event.reportSynchronizationHelper(); var currentExecutionQueue = (this.get('exec') || 0) - 1; this.set('exec', currentExecutionQueue); OB.info('event execution time', (new Date().getTime()) - event.get('start'), currentExecutionQueue); if (currentExecutionQueue === 0 && event.get('receipt')) { event.get('receipt').trigger('eventExecutionDone'); } }, this); evtQueue.add(event); }, preEvent: function () { // Logic to implement before the event is created }, postEvent: function () { // Logic to implement after the event is created }, nextEvent: function () { var evt = this.get('eventQueue').shift(), previousEvt = this.get('currentEvent'); if (previousEvt) { previousEvt.trigger('finish'); this.postEvent(); } if (evt) { this.preEvent(); this.set('executing', true); this.set('currentEvent', evt); evt.set('start', new Date().getTime()); evt.on('actionsCreated', function () { this.preAction(evt); this.nextAction(evt); }, this); this.createActions(evt); } else { this.set('executing', false); this.set('currentEvent', null); } }, preAction: function (event) { // actions executed before the actions for the event }, nextAction: function (event) { var action = this.get('actionQueue').shift(); if (action) { action.get('action').call(this, action.get('args'), event); } else { // queue of action is empty this.postAction(event); this.nextEvent(); } }, postAction: function (event) { // actions executed after all actions for the event have been executed }, createActions: function (event) { // To be implemented by subclasses. It should populate actionQueue with the // series of actions to be executed for this event. Note each of the actions // is in charge of synchronization by invoking nextAction method. } }); OB.Model.DiscountsExecutor = OB.Model.Executor.extend({ // parameters that will be used in the SQL to get promotions, in case this SQL is extended, // these parameters might be required to be extended too criteriaParams: ['bpId', 'bpId', 'bpId', 'bpId', 'productId', 'productId', 'productId', 'productId'], // defines the property each of the parameters in criteriaParams is translated to, in case of // different parameters than standard ones this should be extended paramsTranslation: { bpId: { model: 'receipt', property: 'bp' }, productId: { model: 'line', property: 'product' } }, convertParams: function (evt, line, receipt, pTrl) { var translatedParams = []; _.forEach(this.criteriaParams, function (param) { var paraTrl, model; paraTrl = pTrl[param]; if (!paraTrl) { window.console.error('Not found param to calculate discounts', param); return; } if (paraTrl.model === 'receipt') { model = receipt; } else if (paraTrl.model === 'line') { model = line; } else { model = evt.get(paraTrl.model); } translatedParams.push(model.get(paraTrl.property).id); }); return translatedParams; }, createActions: function (evt) { var line = evt.get('line'), receipt = evt.get('receipt'), bpId = receipt.get('bp').id, productId = line.get('product').id, actionQueue = this.get('actionQueue'), me = this, criteria, t0 = new Date().getTime(), whereClause = OB.Model.Discounts.standardFilter + " AND M_OFFER_TYPE_ID NOT IN (" + OB.Model.Discounts.getManualPromotions() + ")"; if (!receipt.shouldApplyPromotions() || line.get('product').get('ignorePromotions')) { // Cannot apply promotions, leave actions empty evt.trigger('actionsCreated'); return; } criteria = { '_whereClause': whereClause, params: this.convertParams(evt, line, receipt, this.paramsTranslation) }; OB.Dal.find(OB.Model.Discount, criteria, function (d) { d.forEach(function (disc) { actionQueue.add({ action: me.applyRule, args: disc }); }); evt.trigger('actionsCreated'); }, function () { OB.error('Error getting promotions', arguments); }); }, applyRule: function (disc, evt) { var receipt = evt.get('receipt'), line = evt.get('line'), rule = OB.Model.Discounts.discountRules[disc.get('discountType')], ds, ruleListener; if (line.stopApplyingPromotions()) { this.nextAction(evt); return; } if (rule && rule.implementation) { if (rule.async) { // waiting listener to trigger completed to move to next action ruleListener = new Backbone.Model(); ruleListener.on('completed', function (obj) { if (obj && obj.alerts) { // in the new flow discount, the messages are stored in array, so only will be displayed the first time if (OB.POS.modelterminal.hasPermission('OBPOS_discount.newFlow', true)) { var localArrayMessages = line.get('promotionMessages') || []; localArrayMessages.push(obj.alerts); line.set('promotionMessages', localArrayMessages); } else { OB.UTIL.showAlert.display(obj.alerts); } } ruleListener.off('completed'); this.nextAction(evt); }, this); } ds = rule.implementation(disc, receipt, line, ruleListener); if (ds && ds.alerts) { // in the new flow discount, the messages are stored in array, so only will be displayed the first time if (OB.POS.modelterminal.hasPermission('OBPOS_discount.newFlow', true)) { var localArrayMessages = line.get('promotionMessages') || []; localArrayMessages.push(ds.alerts); line.set('promotionMessages', localArrayMessages); } else { OB.UTIL.showAlert.display(ds.alerts); } } if (!rule.async) { // done, move to next action this.nextAction(evt); } } else { OB.warn('No POS implementation for discount ' + disc.get('discountType')); this.nextAction(evt); } }, preEvent: function () { // Logic to implement before the event is created }, postEvent: function () { // Logic to implement after the event is created }, preAction: function (evt) { var line = evt.get('line'), order = evt.get('receipt'), manualPromotions = [], appliedPromotions, appliedPack; // Keep discretionary discounts at the beginning, recalculate them based on // new info in line appliedPromotions = line.get('promotions'); if (appliedPromotions) { if (line.lastAppliedPromotion() && !line.lastAppliedPromotion().applyNext) { manualPromotions.push(line.lastAppliedPromotion()); } else { _.forEach(appliedPromotions, function (promotion) { if (promotion.manual) { manualPromotions.push(promotion); } }); } } appliedPack = line.isAffectedByPack(); if (appliedPack) { // we need to remove this pack from other lines in order to warranty consistency order.get('lines').forEach(function (l) { var promos = l.get('promotions'), newPromos = []; if (!promos) { return; } promos.forEach(function (p) { if (p.ruleId !== appliedPack.ruleId) { newPromos.push(p); } }); l.set('promotions', newPromos); }); } if (!line.get('originalOrderLineId')) { line.set({ promotions: null, discountedLinePrice: null, promotionCandidates: null }); } _.forEach(manualPromotions, function (promo) { var promotion = { rule: new Backbone.Model(promo), definition: { userAmt: promo.userAmt, applyNext: promo.applyNext, lastApplied: promo.lastApplied }, alreadyCalculated: true // to prevent loops }; OB.Model.Discounts.addManualPromotion(order, [line], promotion); }); }, postAction: function (evt) { // if new flow of discounts, then discountsApplied is triggered if (OB.POS.modelterminal.hasPermission('OBPOS_discount.newFlow', true)) { if (this.get('eventQueue').filter(function (p) { return p.get('receipt') === evt.get('receipt'); }).length === 0) { evt.get('receipt').trigger('discountsApplied'); } } else { evt.get('receipt').calculateGross(); } // Forcing local db save. Rule implementations could (should!) do modifications // without persisting them improving performance in this manner. if (!evt.get('skipSave') && evt.get('receipt') && evt.get('receipt').get('lines') && evt.get('receipt').get('lines').length > 0) { evt.get('receipt').save(); } } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, Backbone, enyo, $, _ */ (function () { OB.Model.TerminalWindowModel = OB.Model.WindowModel.extend({ /** * Abstract function that concrete classes must overwrite to perform actions * after a supervisor approves an action * or if not overwritten, provide a callback in OB.UTIL.Approval.requestApproval invocation */ approvedRequest: function (approved, supervisor, approvalType, callback) { if (enyo.isFunction(callback)) { callback(approved, supervisor, approvalType); } }, /** * Generic approval checker. It validates user/password can approve the approvalType. * It can work online in case that user has done at least once the same approvalType * in this same browser. Data regarding privileged users is stored in supervisor table */ checkApproval: function (approvalType, username, password, callback) { OB.Dal.initCache(OB.Model.Supervisor, [], null, null); new OB.DS.Process('org.openbravo.retail.posterminal.utility.CheckApproval').exec({ u: username, p: password, approvalType: JSON.stringify(approvalType) }, enyo.bind(this, function (response, message) { var approved = false; if (response.exception) { OB.UTIL.showError(response.exception.message); this.approvedRequest(false, null, null, callback); } else { approved = response.canApprove; if (!approved) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_UserCannotApprove')); } // saving supervisor in local so next time it is possible to approve offline OB.Dal.find(OB.Model.Supervisor, { 'id': response.userId }, enyo.bind(this, function (users) { var supervisor, date, permissions = []; if (users.models.length === 0) { // new user if (response.canApprove) { // insert in local db only in case it is supervisor for current type date = new Date().toString(); supervisor = new OB.Model.Supervisor(); supervisor.set('id', response.userId); supervisor.set('name', username); supervisor.set('password', OB.MobileApp.model.generate_sha1(password + date)); supervisor.set('created', date); supervisor.set('permissions', JSON.stringify(approvalType)); OB.Dal.save(supervisor, null, null, true); } } else { // update existent user granting or revoking permission supervisor = users.models[0]; supervisor.set('password', OB.MobileApp.model.generate_sha1(password + supervisor.get('created'))); if (supervisor.get('permissions')) { permissions = JSON.parse(supervisor.get('permissions')); } if (response.canApprove) { // grant permission if it does not exist _.each(approvalType, function (perm) { if (!_.contains(permissions, perm)) { permissions.push(perm); } }, this); } else { // revoke permission if it exists _.each(approvalType, function (perm) { if (_.contains(permissions, perm)) { permissions = _.without(permissions, perm); } }, this); } supervisor.set('permissions', JSON.stringify(permissions)); OB.Dal.save(supervisor); } this.approvedRequest(approved, supervisor, approvalType, callback); })); } }), enyo.bind(this, function () { // offline OB.Dal.find(OB.Model.Supervisor, { 'name': username }, enyo.bind(this, function (users) { var supervisor, countApprovals = 0, approved = false; if (users.models.length === 0) { countApprovals = 0; OB.Dal.find(OB.Model.User, null, enyo.bind(this, function (users) { _.each(users.models, function (user) { if (username === user.get('name') && user.get('password') === OB.MobileApp.model.generate_sha1(password + user.get('created'))) { _.each(approvalType, function (perm) { if (JSON.parse(user.get('terminalinfo')).permissions[perm]) { countApprovals += 1; supervisor = user; } }, this); } }); if (countApprovals === approvalType.length) { approved = true; this.approvedRequest(approved, supervisor, approvalType, callback); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_UserCannotApprove')); } }), function () {}); } else { supervisor = users.models[0]; if (supervisor.get('password') === OB.MobileApp.model.generate_sha1(password + supervisor.get('created'))) { _.each(approvalType, function (perm) { if (_.contains(JSON.parse(supervisor.get('permissions')), perm)) { countApprovals += 1; } }, this); if (countApprovals === approvalType.length) { approved = true; this.approvedRequest(approved, supervisor, approvalType, callback); } else { countApprovals = 0; OB.Dal.find(OB.Model.User, null, enyo.bind(this, function (users) { _.each(users.models, function (user) { if (username === user.get('name') && user.get('password') === OB.MobileApp.model.generate_sha1(password + user.get('created'))) { _.each(approvalType, function (perm) { if (JSON.parse(user.get('terminalinfo')).permissions[perm]) { countApprovals += 1; supervisor = user; } }, this); } }); if (countApprovals === approvalType.length) { approved = true; this.approvedRequest(approved, supervisor, approvalType, callback); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_UserCannotApprove')); } }), function () {}); } } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_InvalidUserPassword')); } } }), function () {}); })); } }); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var PaymentMethodCashUp = OB.Data.ExtensibleModel.extend({ modelName: 'PaymentMethodCashUp', tableName: 'paymentmethodcashup', entityName: '', source: '', local: true }); PaymentMethodCashUp.addProperties([{ name: 'id', column: 'paymentmethodcashup_id', primaryKey: true, type: 'TEXT' }, { name: 'paymentmethod_id', column: 'paymentmethod_id', type: 'TEXT' }, { name: 'searchKey', column: 'searchKey', type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: 'startingCash', column: 'startingCash', type: 'NUMERIC' }, { name: 'totalSales', column: 'totalSales', type: 'NUMERIC' }, { name: 'totalReturns', column: 'totalReturns', type: 'NUMERIC' }, { name: 'rate', column: 'rate', type: 'NUMERIC' }, { name: 'cashup_id', column: 'cashup_id', type: 'TEXT' }, { name: 'isocode', column: 'isocode', type: 'TEXT' }]); OB.Data.Registry.registerModel(PaymentMethodCashUp); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var TaxCashUp = OB.Data.ExtensibleModel.extend({ modelName: 'TaxCashUp', tableName: 'taxcashup', entityName: '', source: '', local: true }); TaxCashUp.addProperties([{ name: 'id', column: 'taxcashup_id', primaryKey: true, type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: 'amount', column: 'amount', type: 'NUMERIC' }, { name: 'orderType', column: 'orderType', type: 'TEXT' }, { name: 'cashup_id', column: 'cashup_id', type: 'TEXT' }]); OB.Data.Registry.registerModel(TaxCashUp); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var ReturnReason = OB.Data.ExtensibleModel.extend({ modelName: 'ReturnReason', tableName: 'c_return_reason', entityName: 'ReturnReason', source: 'org.openbravo.retail.posterminal.master.ReturnReason', dataLimit: 300 }); ReturnReason.addProperties([{ name: 'id', column: 'c_return_reason_id', primaryKey: true, type: 'TEXT' }, { name: 'searchKey', column: 'searchKey', type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); OB.Data.Registry.registerModel(ReturnReason); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _ */ (function () { var OfflinePrinter = OB.Data.ExtensibleModel.extend({ modelName: 'OfflinePrinter', tableName: 'OfflinePrinter', entityName: 'OfflinePrinter', source: '', local: true }); OfflinePrinter.addProperties([{ name: 'id', column: 'offline_id', primaryKey: true, type: 'TEXT' }, { name: 'data', column: 'data', type: 'TEXT' }, { name: 'sendfunction', column: 'sendfunction', type: 'TEXT' }]); OfflinePrinter.printPendingJobs = function () { OB.Dal.find(OB.Model.OfflinePrinter, {}, function (jobs) { OB.Model.OfflinePrinter._printPendingJobs(jobs); }); }; OfflinePrinter._printPendingJobs = function (jobs) { var job, sendfunction; if (jobs.length > 0) { job = jobs.at(0); OB.POS.hwserver[job.get('sendfunction')](job.get('data'), function (result) { if (result && result.exception) { OB.UTIL.showError(result.exception.message); } else { // success. delete job and continue printing remaining jobs... OB.Dal.remove(job); jobs.remove(job); OB.Model.OfflinePrinter._printPendingJobs(jobs); } }); } }; OB.Data.Registry.registerModel(OfflinePrinter); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalCancel', popup: 'modalCancel', i18nHeader: 'OBMOBC_LblCancel', bodyContent: { i18nContent: 'OBPOS_ProcessCancelDialog' }, bodyButtons: { components: [{ //OK button kind: 'OB.UI.ModalCancel_OkButton' }, { //Cancel button kind: 'OB.UI.ModalCancel_CancelButton' }] } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ModalCancel_OkButton', i18nContent: 'OBMOBC_LblOk', isDefaultAction: true, popup: 'modalCancel', tap: function () { this.doHideThisPopup(); OB.POS.navigate('retail.pointofsale'); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ModalCancel_CancelButton', i18nContent: 'OBMOBC_LblCancel', popup: 'modalCancel', tap: function () { this.doHideThisPopup(); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo $ */ enyo.kind({ name: 'OB.UI.Subwindow', kind: 'enyo.Popup', modal: false, autoDismiss: false, floating: false, events: { onChangeSubWindow: '' }, classes: 'subwindow', showing: false, handlers: { onkeydown: 'keydownHandler' }, keydownHandler: function (inSender, inEvent) { var keyCode = inEvent.keyCode; if (keyCode === 27 && this.showing) { //Handle ESC key to hide the popup //TODO: Improve the way the "close" action is defined this.$.subWindowHeader.getComponents()[0].onTapCloseButton(); return true; } else if (keyCode === 13 && this.defaultActionButton) { //Handle ENTER key to execute the default action (if exists) this.defaultActionButton.executeTapAction(); return true; } else { return false; } }, showingChanged: function () { this.inherited(arguments); if (this.showing) { this.originalScanMode = OB.MobileApp.view.scanMode; OB.MobileApp.view.scanningFocus(false); OB.MobileApp.view.openedSubwindow = this; this.setDefaultActionButton(); } else { OB.MobileApp.view.scanningFocus(this.originalScanMode); OB.MobileApp.view.openedSubwindow = null; } }, focusInPopup: function () { var allChildsArray = OB.UTIL.getAllChildsSorted(this), isFirstFocusableElementObtained = false, tagName, element, i; for (i = 0; i < allChildsArray.length; i++) { if (allChildsArray[i].hasNode() && allChildsArray[i].hasNode().tagName) { tagName = allChildsArray[i].hasNode().tagName.toUpperCase(); } else { tagName = ''; } if ((tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA' || tagName === 'BUTTON') && allChildsArray[i].showing && !isFirstFocusableElementObtained) { element = allChildsArray[i]; isFirstFocusableElementObtained = true; } else if (allChildsArray[i].isFirstFocus) { element = allChildsArray[i]; break; } } if (element) { element.focus(); } return true; }, setDefaultActionButton: function (element) { var allChildsArray, tagName, i; if (element) { allChildsArray = [element]; } else { allChildsArray = OB.UTIL.getAllChildsSorted(this); } for (i = 0; i < allChildsArray.length; i++) { if (allChildsArray[i].hasNode() && allChildsArray[i].hasNode().tagName) { tagName = allChildsArray[i].hasNode().tagName.toUpperCase(); } else { tagName = ''; } if (tagName === 'BUTTON' && allChildsArray[i].isDefaultAction) { element = allChildsArray[i]; break; } } if (element) { this.defaultActionButton = element; } return true; }, mainBeforeSetShowing: function (args) { var valueToReturn = true; if (args.caller) { this.caller = args.caller; } if (args.navigateOnClose) { this.navigateOnClose = args.navigateOnClose; } else { this.navigateOnClose = this.defaultNavigateOnClose; } if (this.beforeSetShowing) { valueToReturn = this.beforeSetShowing(args); } return valueToReturn; }, mainAfterShow: function (args) { this.focusInPopup(); if (this.afterShow) { this.afterShow(args); } }, mainBeforeClose: function (dest) { var valueToReturn = true; if (dest) { this.lastLeaveTo = dest; } if (this.beforeClose) { valueToReturn = this.beforeClose(dest); } return valueToReturn; }, header: {}, body: {}, goBack: function () { //navigate to this.caller }, components: [{ name: 'subWindowHeader' }, { name: 'subWindowBody' }], relComponentsWithSubWindow: function (comp, subWin) { if (!comp || !comp.getComponents) { return; } enyo.forEach(comp.getComponents(), function (child) { subWin.relComponentsWithSubWindow(child, subWin); child.subWindow = subWin; }); }, initComponents: function () { this.inherited(arguments); //set header this.$.subWindowHeader.createComponent(this.header); //set body this.$.subWindowBody.createComponent(this.body); this.relComponentsWithSubWindow(this, this); } }); enyo.kind({ name: 'OB.UI.SubwindowHeader', classes: 'subwindowheader', components: [{ name: "closebutton", tag: 'div', classes: 'subwindow-closebutton', components: [{ tag: 'span', allowHtml: true, content: '×' }] }, { classes: 'subwindowheadertext', name: 'headermessage' }], initComponents: function () { this.inherited(arguments); if (this.i18nHeaderMessage) { this.$.headermessage.setContent(OB.I18N.getLabel(this.i18nHeaderMessage)); } else if (this.headerMessage) { this.$.headermessage.setContent(this.headermessage); } else { this.$.headermessage.setContent(OB.I18N.getLabel('OBPOS_TitleCustomerAdvancedSearch')); } this.$.closebutton.headerContainer = this.$.closebutton.parent; this.$.closebutton.tap = this.onTapCloseButton; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone */ enyo.kind({ name: 'OB.UI.LeftSubWindow', classes: 'span6', showing: false, events: { onShowLeftSubWindow: '', onCloseLeftSubWindow: '' }, components: [{ style: 'margin: 5px; height: 612px; background-color: white;', components: [{ name: 'leftSubWindowHeader' }, { name: 'leftSubWindowBody' }] }], mainBeforeSetShowing: function (params) { //TODO if (this.beforeSetShowing) { return this.beforeSetShowing(params); } return true; }, mainBeforeSetHidden: function (params) { //TODO if (this.beforeSetHidden) { return this.beforeSetHidden(params); } return true; }, relComponentsWithLeftSubWindow: function (comp, leftSubWin) { if (!comp || !comp.getComponents) { return; } enyo.forEach(comp.getComponents(), function (child) { leftSubWin.relComponentsWithLeftSubWindow(child, leftSubWin); child.leftSubWindow = leftSubWin; }); }, initComponents: function () { this.inherited(arguments); if (this.header) { this.$.leftSubWindowHeader.createComponent(this.header); this.headerComponent = this.$.leftSubWindowHeader.getComponents()[0]; } if (this.body) { this.$.leftSubWindowBody.createComponent(this.body); this.bodyComponent = this.$.leftSubWindowBody.getComponents()[0]; } this.relComponentsWithLeftSubWindow(this, this); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ enyo.kind({ name: 'OB.UI.ModalReceiptPropertiesImpl', kind: 'OB.UI.ModalReceiptProperties', newAttributes: [{ kind: 'OB.UI.renderTextProperty', name: 'receiptDescription', modelProperty: 'description', i18nLabel: 'OBPOS_LblDescription' }, { kind: 'OB.UI.renderBooleanProperty', name: 'printBox', checked: true, classes: 'modal-dialog-btn-check active', modelProperty: 'print', i18nLabel: 'OBPOS_Lbl_RP_Print' }, { kind: 'OB.UI.renderComboProperty', name: 'salesRepresentativeBox', modelProperty: 'salesRepresentative', i18nLabel: 'OBPOS_SalesRepresentative', permission: 'OBPOS_salesRepresentative.receipt', permissionOption: 'OBPOS_SR.comboOrModal', retrievedPropertyForValue: 'id', retrievedPropertyForText: '_identifier', init: function (model) { this.collection = new OB.Collection.SalesRepresentativeList(); this.model = model; if (!OB.POS.modelterminal.hasPermission(this.permission)) { this.parent.parent.parent.hide(); } else { if (OB.POS.modelterminal.hasPermission(this.permissionOption)) { this.parent.parent.parent.hide(); } } }, fetchDataFunction: function (args) { var me = this, actualUser; OB.Dal.find(OB.Model.SalesRepresentative, null, function (data, args) { if (data.length > 0) { me.dataReadyFunction(data, args); } else { actualUser = new OB.Model.SalesRepresentative(); actualUser.set('_identifier', me.model.get('order').get('salesRepresentative$_identifier')); actualUser.set('id', me.model.get('order').get('salesRepresentative')); data.models = [actualUser]; me.dataReadyFunction(data, args); } }, function (error) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_ErrorGettingSalesRepresentative')); me.dataReadyFunction(null, args); }, args); } }, { kind: 'OB.UI.SalesRepresentative', name: 'salesrepresentativebutton', i18nLabel: 'OBPOS_SalesRepresentative', permission: 'OBPOS_salesRepresentative.receipt', permissionOption: 'OBPOS_SR.comboOrModal' }], resetProperties: function () { var p, att; // reset all properties for (p in this.newAttributes) { if (this.newAttributes.hasOwnProperty(p)) { att = this.$.bodyContent.$.attributes.$['line_' + this.newAttributes[p].name].$.newAttribute.$[this.newAttributes[p].name]; if (att && att.setValue) { att.setValue(''); } } } }, init: function (model) { this.setHeader(OB.I18N.getLabel('OBPOS_ReceiptPropertiesDialogTitle')); this.model = model.get('order'); this.model.bind('change', function () { var diff = this.model.changedAttributes(), att; for (att in diff) { if (diff.hasOwnProperty(att)) { this.loadValue(att); } } }, this); this.model.bind('paymentAccepted', function () { this.resetProperties(); }, this); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, $ */ enyo.kind({ name: 'OB.UI.ModalReceiptLinesProperties', kind: 'OB.UI.ModalAction', handlers: { onApplyChanges: 'applyChanges' }, executeOnShow: function () { this.autoDismiss = true; if (this && this.args && this.args.autoDismiss === false) { this.autoDismiss = false; } }, executeOnHide: function () { if (this.args && this.args.requiredFiedls && this.args.requiredFieldNotPresentFunction) { var smthgPending = _.find(this.args.requiredFiedls, function (fieldName) { return OB.UTIL.isNullOrUndefined(this.currentLine.get(fieldName)); }, this); if (smthgPending) { this.args.requiredFieldNotPresentFunction(this.currentLine, smthgPending); } } }, i18nHeader: 'OBPOS_ReceiptLinePropertiesDialogTitle', bodyContent: { kind: 'Scroller', maxHeight: '225px', style: 'background-color: #ffffff;', thumb: true, horizontal: 'hidden', components: [{ name: 'attributes' }] }, bodyButtons: { components: [{ kind: 'OB.UI.ReceiptPropertiesDialogApply', name: 'receiptLinePropertiesApplyBtn' }, { kind: 'OB.UI.ReceiptPropertiesDialogCancel', name: 'receiptLinePropertiesCancelBtn' }] }, loadValue: function (mProperty, component) { this.waterfall('onLoadValue', { model: this.currentLine, modelProperty: mProperty }); // Make it visible or not... if (component.showProperty) { component.showProperty(this.currentLine, function (value) { component.owner.owner.setShowing(value); }); } // else make it visible... }, applyChanges: function (inSender, inEvent) { var diff, att, result = true; diff = this.propertycomponents; for (att in diff) { if (diff.hasOwnProperty(att)) { if (diff[att].owner.owner.getShowing()) { result = result && diff[att].applyValue(this.currentLine); } } } return result; }, validationMessage: function (args) { this.owner.doShowPopup({ popup: 'modalValidateAction', args: args }); }, initComponents: function () { this.inherited(arguments); this.attributeContainer = this.$.bodyContent.$.attributes; this.setHeader(OB.I18N.getLabel(this.i18nHeader)); this.propertycomponents = {}; enyo.forEach(this.newAttributes, function (natt) { var editline = this.$.bodyContent.$.attributes.createComponent({ kind: 'OB.UI.PropertyEditLine', name: 'line_' + natt.name, newAttribute: natt }); this.propertycomponents[natt.modelProperty] = editline.propertycomponent; this.propertycomponents[natt.modelProperty].propertiesDialog = this; }, this); }, init: function (model) { this.model = model; this.model.get('order').get('lines').on('selected', function (lineSelected) { var diff, att; this.currentLine = lineSelected; if (lineSelected) { diff = this.propertycomponents; for (att in diff) { if (diff.hasOwnProperty(att)) { this.loadValue(att, diff[att]); } } } }, this); } }); enyo.kind({ name: 'OB.UI.ModalReceiptLinesPropertiesImpl', kind: 'OB.UI.ModalReceiptLinesProperties', newAttributes: [{ kind: 'OB.UI.renderTextProperty', name: 'receiptLineDescription', modelProperty: 'description', i18nLabel: 'OBPOS_LblDescription' }] }); enyo.kind({ kind: 'OB.UI.ModalInfo', name: 'OB.UI.ValidateAction', header: '', isDefaultAction: true, bodyContent: { name: 'message', content: '' }, executeOnShow: function () { this.$.header.setContent(this.args.header); this.$.bodyContent.$.message.setContent(this.args.message); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, $, confirm */ enyo.kind({ name: 'OB.UI.Modalnoteditableorder', kind: 'OB.UI.ModalInfo', i18nHeader: 'OBPOS_modalNoEditableHeader', bodyContent: { i18nContent: 'OBPOS_modalNoEditableBody' } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, $, confirm */ enyo.kind({ name: 'OB.UI.ModalNotEditableLine', kind: 'OB.UI.ModalInfo', i18Header: 'OBPOS_modalNoEditableLineHeader', bodyContent: { i18nContent: 'OBPOS_modalNoEditableLineBody' } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _ */ enyo.kind({ name: 'OB.UTIL.Approval', kind: 'OB.UI.ModalAction', statics: { /** * Static method to display the approval popup. * * When the approval is requested and checked, 'approvalChecked' event is * triggered in model parameter. This event has a boolean parameter 'approved' * that determines whether the approval was accepted or rejected. */ requestApproval: function (model, approvalType, callback) { var dialog; var haspermission; if (_.isArray(approvalType)) { haspermission = _.every(approvalType, function (a) { return OB.POS.modelterminal.hasPermission(a, true); }); } else { haspermission = OB.POS.modelterminal.hasPermission(approvalType, true); } if (haspermission) { model.approvedRequest(true, new Backbone.Model(OB.POS.modelterminal.get('context').user), approvalType, callback); // I'am a supervisor } else { dialog = OB.MobileApp.view.$.confirmationContainer.createComponent({ kind: 'OB.UTIL.Approval', model: model, approvalType: approvalType, callback: callback }); dialog.show(); } } }, handlers: { onCheckCredentials: 'checkCredentials', onUserImgClick: 'handleUserImgClick' }, i18nHeader: 'OBPOS_ApprovalRequiredTitle', bodyContent: { components: [{ name: 'explainApprovalTxt' }, { classes: 'login-header-row', style: 'color:black; line-height: 20px;', components: [{ classes: 'span6', components: [{ kind: 'Scroller', thumb: true, horizontal: 'hidden', name: 'loginUserContainer', classes: 'login-user-container', style: 'background-color:#5A5A5A; margin: 5px;', content: ['.'] }] }, { classes: 'span6', components: [{ classes: 'login-inputs-container', components: [{ name: 'loginInputs', classes: 'login-inputs-browser-compatible', components: [{ components: [{ kind: 'OB.UTIL.Approval.Input', name: 'username' }] }, { components: [{ kind: 'OB.UTIL.Approval.Input', name: 'password', type: 'password' }] }] }] }] }] }] }, bodyButtons: { components: [{ kind: 'OB.UTIL.Approval.ApproveButton' }, { kind: 'OB.UI.ModalDialogButton', i18nLabel: 'OBPOS_Cancel', tap: function () { this.bubble('onHideThisPopup'); } }] }, handleUserImgClick: function (inSender, inEvent) { var u = inEvent.originator.user; this.$.bodyContent.$.username.setValue(u); this.$.bodyContent.$.password.setValue(''); this.$.bodyContent.$.password.focus(); return true; }, initComponents: function () { var msg = ''; this.inherited(arguments); this.$.bodyContent.$.username.attributes.placeholder = OB.I18N.getLabel('OBMOBC_LoginUserInput'); this.$.bodyContent.$.password.attributes.placeholder = OB.I18N.getLabel('OBMOBC_LoginPasswordInput'); if (!Array.isArray(this.approvalType)) { this.approvalType = [this.approvalType]; } _.each(this.approvalType, function (approval) { msg = msg + ' ' + (OB.I18N.labels[approval] || OB.I18N.getLabel('OBPOS_ApprovalTextHeader')); }); this.$.bodyContent.$.explainApprovalTxt.setContent(msg); this.postRenderActions(); }, setUserImages: function (inSender, inResponse) { var name = [], userName = [], image = [], connected = [], me = this, jsonImgData, i; if (!inResponse.data) { OB.Dal.find(OB.Model.User, {}, function (users) { var i, user, session; for (i = 0; i < users.models.length; i++) { user = users.models[i]; name.push(user.get('name')); userName.push(user.get('name')); connected.push(false); } me.renderUserButtons(name, userName, image, connected); }, function () { OB.error(arguments); }); return true; } jsonImgData = inResponse.data; enyo.forEach(jsonImgData, function (v) { name.push(v.name); userName.push(v.userName); image.push(v.image); }); this.renderUserButtons(name, userName, image, connected); }, renderUserButtons: function (name, userName, image) { var i, target = this.$.bodyContent.$.loginUserContainer; for (i = 0; i < name.length; i++) { target.createComponent({ kind: 'OB.OBPOSLogin.UI.UserButton', user: userName[i], userImage: image[i], showConnectionStatus: false }); } target.render(); return true; }, postRenderActions: function () { var params = OB.MobileApp.model.get('loginUtilsParams') || {}; params.appName = OB.MobileApp.model.get('appName'); params.command = 'userImages'; params.approvalType = JSON.stringify(this.approvalType); new OB.OBPOSLogin.UI.LoginRequest({ url: OB.MobileApp.model.get('loginUtilsUrl') }).response(this, 'setUserImages').go(params); }, checkCredentials: function () { var u = this.$.bodyContent.$.username.getValue(), p = this.$.bodyContent.$.password.getValue(); if (!u || !p) { alert(OB.I18N.getLabel('OBPOS_EmptyUserPassword')); } else { this.model.checkApproval(this.approvalType, u, p, this.callback); this.waterfall('onHideThisPopup', {}); } } }); enyo.kind({ name: 'OB.UTIL.Approval.ApproveButton', kind: 'OB.UI.ModalDialogButton', i18nLabel: 'OBPOS_Approve', events: { onCheckCredentials: '' }, tap: function () { this.doCheckCredentials(); } }); enyo.kind({ name: 'OB.UTIL.Approval.Input', kind: 'enyo.Input', type: 'text', classes: 'input-login', handlers: { onkeydown: 'inputKeydownHandler' }, events: { onCheckCredentials: '' }, inputKeydownHandler: function (inSender, inEvent) { var keyCode = inEvent.keyCode; if (keyCode === 13) { //Handle ENTER key this.doCheckCredentials(); return true; } return false; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B,_*/ (function () { OB = window.OB || {}; OB.UTIL = window.OB.UTIL || {}; function findAndSave(cashuptaxes, i, finishCallback) { if (i < cashuptaxes.length) { OB.Dal.find(OB.Model.TaxCashUp, { 'cashup_id': cashuptaxes[i].cashupID, 'name': cashuptaxes[i].taxName, 'orderType': cashuptaxes[i].taxOrderType }, function (tax) { if (tax.length === 0) { OB.Dal.save(new OB.Model.TaxCashUp({ name: cashuptaxes[i].taxName, amount: cashuptaxes[i].taxAmount, orderType: cashuptaxes[i].taxOrderType, cashup_id: cashuptaxes[i].cashupID }), function () { findAndSave(cashuptaxes, i + 1, finishCallback); }, null); } else { tax.at(0).set('amount', OB.DEC.add(tax.at(0).get('amount'), cashuptaxes[i].taxAmount)); OB.Dal.save(tax.at(0), function () { findAndSave(cashuptaxes, i + 1, finishCallback); }, null); } }); } else { if (finishCallback) { finishCallback(); } } } function updateCashUpInfo(cashUp, receipt, j, callback) { var cashuptaxes, order, orderType, gross, i, taxOrderType, taxAmount, auxPay; if (j < receipt.length) { order = receipt[j]; orderType = order.get('orderType'); if (cashUp.length !== 0) { _.each(order.get('lines').models, function (line) { if (order.get('priceIncludesTax')) { gross = line.get('lineGrossAmount'); } else { gross = line.get('discountedGross'); } //Sales order: Positive line if (line.get('qty') > 0 && orderType !== 3 && !order.get('isLayaway')) { cashUp.at(0).set('netSales', OB.DEC.add(cashUp.at(0).get('netSales'), line.get('net'))); cashUp.at(0).set('grossSales', OB.DEC.add(cashUp.at(0).get('grossSales'), gross)); //Return from customer or Sales with return: Negative line } else if (line.get('qty') < 0 && orderType !== 3 && !order.get('isLayaway')) { cashUp.at(0).set('netReturns', OB.DEC.add(cashUp.at(0).get('netReturns'), -line.get('net'))); cashUp.at(0).set('grossReturns', OB.DEC.add(cashUp.at(0).get('grossReturns'), -gross)); //Void Layaway } else if (orderType === 3) { if (line.get('qty') > 0) { cashUp.at(0).set('netSales', OB.DEC.add(cashUp.at(0).get('netSales'), -line.get('net'))); cashUp.at(0).set('grossSales', OB.DEC.add(cashUp.at(0).get('grossSales'), -gross)); } else { cashUp.at(0).set('netReturns', OB.DEC.add(cashUp.at(0).get('netReturns'), line.get('net'))); cashUp.at(0).set('grossReturns', OB.DEC.add(cashUp.at(0).get('grossReturns'), gross)); } } }); cashUp.at(0).set('totalRetailTransactions', OB.DEC.sub(cashUp.at(0).get('grossSales'), cashUp.at(0).get('grossReturns'))); OB.Dal.save(cashUp.at(0), null, null); // group and sum the taxes cashuptaxes = []; order.get('lines').each(function (line, taxIndex) { var taxLines, taxLine; taxLines = line.get('taxLines'); if (orderType === 1 || line.get('qty') < 0) { taxOrderType = 1; } else { taxOrderType = 0; } _.each(taxLines, function (taxLine) { if (line.get('qty') > 0 && orderType !== 3) { taxAmount = taxLine.amount; } else { taxAmount = -taxLine.amount; } cashuptaxes.push({ taxName: taxLine.name, taxAmount: taxAmount, taxOrderType: taxOrderType.toString(), cashupID: cashUp.at(0).get('id') }); }); }); OB.Dal.find(OB.Model.PaymentMethodCashUp, { 'cashup_id': cashUp.at(0).get('id') }, function (payMthds) { //OB.Dal.find success _.each(order.get('payments').models, function (payment) { auxPay = payMthds.filter(function (payMthd) { return payMthd.get('searchKey') === payment.get('kind') && !payment.get('isPrePayment'); })[0]; if (!auxPay) { //We cannot find this payment in local database, it must be a new payment method, we skip it. return; } if (order.getGross() > 0 && (orderType === 0 || orderType === 2)) { auxPay.set('totalSales', OB.DEC.add(auxPay.get('totalSales'), payment.get('amount'))); } else if (order.getGross() < 0 || orderType === 1) { auxPay.set('totalReturns', OB.DEC.add(auxPay.get('totalReturns'), payment.get('amount'))); } else if (orderType === 3) { auxPay.set('totalSales', OB.DEC.sub(auxPay.get('totalSales'), payment.get('amount'))); } OB.Dal.save(auxPay, null, null); }, this); findAndSave(cashuptaxes, 0, function () { updateCashUpInfo(cashUp, receipt, j + 1, callback); }); }); } } else if (typeof callback === 'function') { callback(); } } OB.UTIL.cashUpReport = function (receipt, callback) { var auxPay, orderType, taxOrderType, taxAmount, gross; if (!Array.isArray(receipt)) { receipt = [receipt]; } OB.Dal.find(OB.Model.CashUp, { 'isbeingprocessed': 'N' }, function (cashUp) { updateCashUpInfo(cashUp, receipt, 0, callback); }); }; OB.UTIL.deleteCashUps = function (cashUpModels) { var deleteCallback = function (models) { models.each(function (model) { OB.Dal.remove(model, null, function (tx, err) { OB.UTIL.showError(err); }); }); }; _.each(cashUpModels.models, function (cashup) { var cashUpId = cashup.get('id'); OB.Dal.find(OB.Model.TaxCashUp, { cashup_id: cashUpId }, deleteCallback, null); OB.Dal.find(OB.Model.CashManagement, { cashup_id: cashUpId }, deleteCallback, null); OB.Dal.find(OB.Model.PaymentMethodCashUp, { cashup_id: cashUpId }, deleteCallback, null); OB.Dal.remove(cashup, null, function (tx, err) { OB.UTIL.showError(err); }); }); }; OB.UTIL.initCashUp = function (callback) { var criteria = { 'isbeingprocessed': 'N' }, lastCashUpPayments; OB.Dal.find(OB.Model.CashUp, criteria, function (cashUp) { //OB.Dal.find success var uuid; if (cashUp.length === 0) { criteria = { 'isbeingprocessed': 'Y', '_orderByClause': 'createdDate desc' }; OB.Dal.find(OB.Model.CashUp, criteria, function (lastCashUp) { if (lastCashUp.length !== 0) { lastCashUpPayments = JSON.parse(lastCashUp.at(0).get('objToSend')).cashCloseInfo; } uuid = OB.Dal.get_uuid(); if (!OB.UTIL.isNullOrUndefined(OB.MobileApp.model.get('terminal'))) { OB.MobileApp.model.get('terminal').cashUpId = uuid; } OB.Dal.save(new OB.Model.CashUp({ id: uuid, netSales: OB.DEC.Zero, grossSales: OB.DEC.Zero, netReturns: OB.DEC.Zero, grossReturns: OB.DEC.Zero, totalRetailTransactions: OB.DEC.Zero, createdDate: new Date(), userId: null, objToSend: null, isbeingprocessed: 'N' }), function () { _.each(OB.POS.modelterminal.get('payments'), function (payment) { var startingCash = payment.currentBalance, pAux; if (lastCashUpPayments) { pAux = lastCashUpPayments.filter(function (payMthd) { return payMthd.paymentTypeId === payment.payment.id; })[0]; if (!OB.UTIL.isNullOrUndefined(pAux)) { startingCash = pAux.paymentMethod.amountToKeep; } } OB.Dal.save(new OB.Model.PaymentMethodCashUp({ id: OB.Dal.get_uuid(), paymentmethod_id: payment.payment.id, searchKey: payment.payment.searchKey, name: payment.payment._identifier, startingCash: startingCash, totalSales: OB.DEC.Zero, totalReturns: OB.DEC.Zero, rate: payment.rate, isocode: payment.isocode, cashup_id: uuid }), null, null, true); }, this); if (callback) { callback(); } }, null, true); }, null, this); } else { if (!OB.UTIL.isNullOrUndefined(OB.MobileApp.model.get('terminal'))) { OB.MobileApp.model.get('terminal').cashUpId = cashUp.at(0).get('id'); } if (callback) { callback(); } } }); }; OB.UTIL.calculateCurrentCash = function (callback) { var me = this; OB.Dal.find(OB.Model.CashUp, { 'isbeingprocessed': 'N' }, function (cashUp) { OB.Dal.find(OB.Model.PaymentMethodCashUp, { 'cashup_id': cashUp.at(0).get('id') }, function (payMthds) { //OB.Dal.find success var payMthdsCash; _.each(OB.POS.modelterminal.get('payments'), function (paymentType, index) { var cash = 0, auxPay = payMthds.filter(function (payMthd) { return payMthd.get('paymentmethod_id') === paymentType.payment.id; })[0]; if (!auxPay) { //We cannot find this payment in local database, it must be a new payment method, we skip it. return; } auxPay.set('_id', paymentType.payment.searchKey); auxPay.set('isocode', paymentType.isocode); auxPay.set('paymentMethod', paymentType.paymentMethod); auxPay.set('id', paymentType.payment.id); OB.Dal.find(OB.Model.CashManagement, { 'cashup_id': cashUp.at(0).get('id'), 'paymentMethodId': paymentType.payment.id }, function (cashMgmts, args) { var startingCash = auxPay.get('startingCash'), rate = auxPay.get('rate'), totalSales = auxPay.get('totalSales'), totalReturns = auxPay.get('totalReturns'), cashMgmt = _.reduce(cashMgmts.models, function (accum, trx) { if (trx.get('type') === 'deposit') { return OB.DEC.add(accum, trx.get('origAmount')); } else { return OB.DEC.sub(accum, trx.get('origAmount')); } }, 0); var payment = OB.MobileApp.model.paymentnames[paymentType.payment.searchKey]; cash = OB.DEC.add(OB.DEC.add(startingCash, OB.DEC.sub(totalSales, totalReturns)), cashMgmt); payment.currentCash = OB.UTIL.currency.toDefaultCurrency(payment.paymentMethod.currency, cash); payment.foreignCash = OB.UTIL.currency.toForeignCurrency(payment.paymentMethod.currency, cash); if (typeof callback === 'function') { callback(); } }, null, { me: me }); }, this); }); }); }; }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.UI.KeypadCoinsLegacy', padName: 'Coins-102', padPayment: 'OBPOS_payment.cash', components: [{ classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', name: 'OBKEY_legacy_A1', classButton: 'btnkeyboard-num', label: '/', command: '/' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', name: 'OBKEY_legacy_B1', label: '*', command: '*' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', name: 'OBKEY_legacy_C1', label: '%', command: '%' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_A2', amount: 10, background: '#e9b7c3' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_B2', amount: 20, background: '#bac3de' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_C2', amount: 50, background: '#f9bb92' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_A3', amount: 1, background: '#e4e0e3', bordercolor: '#f9e487' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_B3', amount: 2, background: '#f9e487', bordercolor: '#e4e0e3' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_C3', amount: 5, background: '#bccdc5' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_A4', amount: 0.10, background: '#f9e487' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_B4', amount: 0.20, background: '#f9e487' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_C4', amount: 0.50, background: '#f9e487' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_A5', amount: 0.01, background: '#f3bc9e' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', paymenttype: 'OBPOS_payment.cash', name: 'OBKEY_OBPOS_payment.cash_B5', amount: 0.02, background: '#f3bc9e' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.PaymentButton', name: 'OBKEY_OBPOS_payment.cash_C5', paymenttype: 'OBPOS_payment.cash', amount: 0.05, background: '#f3bc9e' }] }] }], initComponents: function () { this.inherited(arguments); this.label = OB.I18N.getLabel('OBPOS_KeypadCoins'); } }); enyo.kind({ name: 'OB.UI.PaymentButton', style: 'margin: 5px;', components: [{ kind: 'OB.UI.Button', classes: 'btnkeyboard', name: 'btn' }], background: '#6cb33f', initComponents: function () { var btn; this.inherited(arguments); btn = this.$.btn; btn.setContent(this.label || OB.I18N.formatCoins(this.amount)); btn.applyStyle('background-color', this.background); btn.applyStyle('border', '10px solid ' + (this.bordercolor || this.background)); }, tap: function () { if (OB.POS.modelterminal.hasPermission(this.paymenttype)) { var me = this, myWindowModel = this.owner.owner.owner.owner.owner.owner.model; //FIXME: TOO MANY OWNERS var i, max, p, receipt = myWindowModel.get('order'), multiOrders = myWindowModel.get('multiOrders'), openDrawer = false, isCash = false, allowOpenDrawer = false, printtwice = false; for (i = 0, max = OB.POS.modelterminal.get('payments').length; i < max; i++) { p = OB.POS.modelterminal.get('payments')[i]; if (p.payment.searchKey === me.paymenttype) { if (p.paymentMethod.openDrawer) { openDrawer = p.paymentMethod.openDrawer; } if (p.paymentMethod.iscash) { isCash = p.paymentMethod.iscash; } if (p.paymentMethod.allowopendrawer) { allowOpenDrawer = p.paymentMethod.allowopendrawer; } if (p.paymentMethod.printtwice) { printtwice = p.paymentMethod.printtwice; } break; } } myWindowModel.addPayment(new OB.Model.PaymentLine({ kind: me.paymenttype, name: OB.POS.modelterminal.getPaymentName(me.paymenttype), amount: OB.DEC.number(me.amount), rate: p.rate, mulrate: p.mulrate, isocode: p.isocode, isCash: isCash, allowOpenDrawer: allowOpenDrawer, openDrawer: openDrawer, printtwice: printtwice })); } } }); /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B,_*/ (function () { OB = window.OB || {}; OB.DATA = window.OB.DATA || {}; OB.DATA.OrderSave = function (model) { this.context = model; this.receipt = model.get('order'); this.ordersToSend = OB.DEC.Zero; this.hasInvLayaways = false; this.receipt.on('closed', function (eventParams) { this.receipt = model.get('order'); OB.warn('Ticket closed. ' + this.receipt.getOrderDescription()); var me = this, docno = this.receipt.get('documentNo'), isLayaway = (this.receipt.get('orderType') === 2 || this.receipt.get('isLayaway')), json = this.receipt.serializeToJSON(), receiptId = this.receipt.get('id'), creationDate = new Date(), creationDateTransformed = new Date(creationDate.getUTCFullYear(), creationDate.getUTCMonth(), creationDate.getUTCDate(), creationDate.getUTCHours(), creationDate.getUTCMinutes(), creationDate.getUTCSeconds()); if (this.receipt.get('isbeingprocessed') === 'Y') { //The receipt has already been sent, it should not be sent again return; } this.receipt.set('hasbeenpaid', 'Y'); // check receipt integrity // sum the amounts of the lines var oldGross = this.receipt.getGross(); var realGross = 0; this.receipt.get('lines').forEach(function (line) { line.calculateGross(); if (line.get('priceIncludesTax')) { realGross = OB.DEC.add(realGross, line.get('lineGrossAmount')); } else { realGross = OB.DEC.add(realGross, line.get('discountedGross')); } }); // check if the amount of the lines is different from the gross if (oldGross !== realGross) { OB.error("Receipt integrity: FAILED"); if (OB.POS.modelterminal.hasPermission('OBPOS_TicketIntegrityCheck', true)) { if (this.receipt.get('id')) { OB.Dal.remove(model.get('orderList').current, null, null); } model.get('orderList').deleteCurrent(); OB.UTIL.showConfirmation.display('Error', OB.I18N.getLabel('OBPOS_ErrorOrderIntegrity'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () {} }]); return; } } OB.trace("Receipt integrity: OK"); OB.UTIL.updateDocumentSequenceInDB(docno); delete this.receipt.attributes.json; this.receipt.set('timezoneOffset', creationDate.getTimezoneOffset()); this.receipt.set('created', creationDate.getTime()); this.receipt.set('obposCreatedabsolute', OB.I18N.formatDateISO(creationDate)); // Absolute date in ISO format OB.UTIL.HookManager.executeHooks('OBPOS_PreOrderSave', { context: this, model: model, receipt: model.get('order') }, function (args) { var receipt = args.context.receipt, auxReceipt = new OB.Model.Order(), currentDocNo = receipt.get('documentNo') || docno; receipt.set('obposAppCashup', OB.MobileApp.model.get('terminal').cashUpId); // convert returns if (receipt.get('qty') < 0) { _.forEach(receipt.get('payments').models, function (item) { item.set('amount', -item.get('amount')); item.set('origAmount', -item.get('origAmount')); item.set('paid', -item.get('paid')); }); } receipt.set('json', JSON.stringify(receipt.toJSON())); auxReceipt.clearWith(receipt); OB.UTIL.cashUpReport(auxReceipt, OB.UTIL.calculateCurrentCash); OB.Dal.save(receipt, function () { var successCallback = function (model) { //In case the processed document is a quotation, we remove its id so it can be reactivated if (model && !_.isNull(model)) { if (model.get('order') && model.get('order').get('isQuotation')) { model.get('order').set('oldId', model.get('order').get('id')); model.get('order').set('id', null); model.get('order').set('isbeingprocessed', 'N'); OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_QuotationSaved', [currentDocNo])); } else { if (isLayaway) { OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgLayawaySaved', [currentDocNo])); } else { OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgReceiptSaved', [currentDocNo])); } } } }; if (OB.UTIL.HookManager.get('OBPOS_PostSyncReceipt')) { //If there are elements in the hook, we are forced to execute the callback only after the synchronization process //has been executed, to prevent race conditions with the callback processes (printing and deleting the receipt) OB.MobileApp.model.runSyncProcess(function () { OB.UTIL.HookManager.executeHooks('OBPOS_PostSyncReceipt', { receipt: auxReceipt }, function (args) { successCallback(); if (eventParams && eventParams.callback) { eventParams.callback(); } }); }, function () { OB.UTIL.HookManager.executeHooks('OBPOS_PostSyncReceipt', { receipt: auxReceipt }, function (args) { if (eventParams && eventParams.callback) { eventParams.callback(); } }); }); } else { //If there are no elements in the hook, we can execute the callback asynchronusly with the synchronization process OB.MobileApp.model.runSyncProcess(function () { successCallback(); }); if (eventParams && eventParams.callback) { eventParams.callback(); } } }, function () { //We do nothing: we don't need to alert the user, as the order is still present in the database, so it will be resent as soon as the user logs in again }); }); }, this); this.context.get('multiOrders').on('closed', function (receipt) { if (!_.isUndefined(receipt)) { this.receipt = receipt; } var me = this, docno = this.receipt.get('documentNo'), isLayaway = (this.receipt.get('orderType') === 2 || this.receipt.get('isLayaway')), json = this.receipt.serializeToJSON(), receiptId = this.receipt.get('id'), creationDate = new Date(), creationDateTransformed = new Date(creationDate.getUTCFullYear(), creationDate.getUTCMonth(), creationDate.getUTCDate(), creationDate.getUTCHours(), creationDate.getUTCMinutes(), creationDate.getUTCSeconds()); this.receipt.set('hasbeenpaid', 'Y'); OB.UTIL.updateDocumentSequenceInDB(docno); delete this.receipt.attributes.json; this.receipt.set('timezoneOffset', creationDate.getTimezoneOffset()); this.receipt.set('created', creationDate.getTime()); this.receipt.set('obposCreatedabsolute', OB.I18N.formatDateISO(creationDate)); // Absolute date in ISO format this.receipt.set('obposAppCashup', OB.MobileApp.model.get('terminal').cashUpId); this.receipt.set('json', JSON.stringify(this.receipt.toJSON())); OB.UTIL.HookManager.executeHooks('OBPOS_PreOrderSave', { context: this, model: model, receipt: this.receipt }, function (args) { if (args && args.cancellation && args.cancellation === true) { args.context.receipt.set('isbeingprocessed', 'N'); return true; } OB.Dal.save(me.receipt, function () { OB.Dal.get(OB.Model.Order, receiptId, function (receipt) { var successCallback, errorCallback; successCallback = function () { OB.UTIL.showLoading(false); if (me.hasInvLayaways) { OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_noInvoiceIfLayaway')); me.hasInvLayaways = false; } OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgAllReceiptSaved')); }; errorCallback = function () { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgAllReceiptNotSaved')); }; if (!_.isUndefined(receipt.get('amountToLayaway')) && !_.isNull(receipt.get('amountToLayaway')) && receipt.get('generateInvoice')) { me.hasInvLayaways = true; } model.get('orderList').current = receipt; model.get('orderList').deleteCurrent(); me.ordersToSend += 1; if (model.get('multiOrders').get('multiOrdersList').length === me.ordersToSend) { model.get('multiOrders').resetValues(); OB.MobileApp.model.runSyncProcess(successCallback); me.ordersToSend = OB.DEC.Zero; } }, null); }, function () { //We do nothing: we don't need to alert the user, as the order is still present in the database, so it will be resent as soon as the user logs in again }); }); }, this); }; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B,_ */ (function () { OB = window.OB || {}; OB.DATA = window.OB.DATA || {}; // Order taxes in descent order by lineNo // OB.Collection.TaxRateList.prototype.comparator = function (tax) { // return tax.get('lineNo'); // }; OB.DATA.OrderTaxes = function (modelOrder) { this._id = 'logicOrderTaxes'; this.receipt = modelOrder; this.receipt.calculateTaxes = function (callback) { var me = this, bpTaxCategory = this.get('bp').get('taxCategory'), bpIsExempt = this.get('bp').get('taxExempt'), fromRegionOrg = OB.MobileApp.model.get('terminal').organizationRegionId, fromCountryOrg = OB.MobileApp.model.get('terminal').organizationCountryId, lines = this.get('lines'), len = lines.length, taxes = {}, taxesline = {}, totalnet = OB.DEC.Zero, queue = {}, triggerNext = false, discountedNet, gross = OB.DEC.Zero, discountedLinePriceNet, roundedDiscountedLinePriceNet, calculatedDiscountedNet; if (len === 0) { me.set('taxes', {}); if (callback) { callback(); } return; } if (this.get('priceIncludesTax')) { _.each(lines.models, function (element, index, list) { var product = element.get('product'); var sql = "select c_tax.c_tax_id, c_tax.name, c_tax.description, c_tax.taxindicator, c_tax.validfrom, c_tax.issummary, c_tax.rate, c_tax.parent_tax_id, (case when c_tax.c_country_id = '" + fromCountryOrg + "' then c_tax.c_country_id else tz.from_country_id end) as c_country_id, (case when c_tax.c_region_id = '" + fromRegionOrg + "' then c_tax.c_region_id else tz.from_region_id end) as c_region_id, (case when c_tax.to_country_id = bpl.countryId then c_tax.to_country_id else tz.to_country_id end) as to_country_id, (case when c_tax.to_region_id = bpl.regionId then c_tax.to_region_id else tz.to_region_id end) as to_region_id, c_tax.c_taxcategory_id, c_tax.isdefault, c_tax.istaxexempt, c_tax.sopotype, c_tax.cascade, c_tax.c_bp_taxcategory_id, c_tax.line, c_tax.iswithholdingtax, c_tax.isnotaxable, c_tax.deducpercent, c_tax.originalrate, c_tax.istaxundeductable, c_tax.istaxdeductable, c_tax.isnovat, c_tax.baseamount, c_tax.c_taxbase_id, c_tax.doctaxamount, c_tax.iscashvat, c_tax._identifier, c_tax._idx, (case when (c_tax.to_country_id = bpl.countryId or tz.to_country_id= bpl.countryId) then 0 else 1 end) as orderCountryTo, (case when (c_tax.to_region_id = bpl.regionId or tz.to_region_id = bpl.regionId) then 0 else 1 end) as orderRegionTo, (case when coalesce(c_tax.c_country_id, tz.from_country_id) is null then 1 else 0 end) as orderCountryFrom, (case when coalesce(c_tax.c_region_id, tz.from_region_id) is null then 1 else 0 end) as orderRegionFrom from c_tax left join c_tax_zone tz on tz.c_tax_id = c_tax.c_tax_id join c_bpartner_location bpl on bpl.c_bpartner_location_id = '" + me.get('bp').get('locId') + "' where c_tax.sopotype in ('B', 'S') "; if (bpIsExempt) { sql = sql + " and c_tax.istaxexempt = 'true'"; } else { sql = sql + " and c_tax.c_taxCategory_id = '" + product.get('taxCategory') + "'"; if (bpTaxCategory) { sql = sql + " and c_tax.c_bp_taxcategory_id = '" + bpTaxCategory + "'"; } else { sql = sql + " and c_tax.c_bp_taxcategory_id is null"; } } sql = sql + " and c_tax.validFrom <= date()"; sql = sql + " and (c_tax.to_country_id = bpl.countryId or tz.to_country_id = bpl.countryId or (c_tax.to_country_id is null and (not exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_country_id = bpl.countryId) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_country_id is null))))"; sql = sql + " and (c_tax.to_region_id = bpl.regionId or tz.to_region_id = bpl.regionId or (c_tax.to_region_id is null and (not exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_region_id = bpl.regionId) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_region_id is null))))"; sql = sql + " order by orderRegionTo, orderRegionFrom, orderCountryTo, orderCountryFrom, c_tax.validFrom desc, c_tax.isdefault desc"; // the query is ordered by countryId desc and regionId desc // (so, the first record will be the tax with the same country or region that the customer, // or if toCountryId and toRegionId are nulls then will be ordered by validfromdate) OB.UTIL.HookManager.executeHooks('OBPOS_FindTaxRate', { context: me, line: element, sql: sql }, function (args) { OB.Dal.query(OB.Model.TaxRate, args.sql, [], function (coll, args) { // success var rate, taxAmt, net, gross, pricenet, pricenetcascade, amount, taxId; if (coll && coll.length > 0) { var discountedGross = null; if (element.get('promotions')) { discountedGross = element.get('gross'); discountedGross = element.get('promotions').reduce(function (memo, element) { return OB.DEC.sub(memo, element.actualAmt || element.amt || 0); }, discountedGross); } var orggross = OB.DEC.mul(element.get('grossUnitPrice') || element.get('price'), element.get('qty')); // First calculate the line rate. var linerate = BigDecimal.prototype.ONE; var linetaxid = coll.at(0).get('id'); var validFromDate = coll.at(0).get('validFromDate'); var taxamt = new BigDecimal(String(orggross)); var taxamtdc; if (!(_.isNull(discountedGross) || _.isUndefined(discountedGross))) { taxamtdc = new BigDecimal(String(discountedGross)); } var fromCountryId = coll.at(0).get('country'); var fromRegionId = coll.at(0).get('region'); var toCountryId = coll.at(0).get('destinationCountry'); var toRegionId = coll.at(0).get('destinationRegion'); coll = _.filter(coll.models, function (taxRate) { var isOK = true; isOK = isOK && (taxRate.get('destinationCountry') === toCountryId); isOK = isOK && (taxRate.get('destinationRegion') === toRegionId); isOK = isOK && (taxRate.get('country') === fromCountryId); isOK = isOK && (taxRate.get('region') === fromRegionId); return isOK && ((taxRate.get('validFromDate') === validFromDate)); }); _.each(coll, function (taxRate, taxIndex) { if (!taxRate.get('summaryLevel')) { rate = new BigDecimal(String(taxRate.get('rate'))); // 10 rate = rate.divide(new BigDecimal('100'), 20, BigDecimal.prototype.ROUND_HALF_UP); // 0.10 if (taxRate.get('cascade')) { linerate = linerate.multiply(rate.add(BigDecimal.prototype.ONE)); taxamt = taxamt.multiply(new BigDecimal(String(OB.DEC.add(1, rate)))); if (!(_.isNull(discountedGross) || _.isUndefined(discountedGross))) { taxamtdc = taxamtdc.multiply(new BigDecimal(String(OB.DEC.add(1, rate)))); } } else { linerate = linerate.add(rate); taxamt = taxamt.add(new BigDecimal(String(orggross)).multiply(rate)); if (!(_.isNull(discountedGross) || _.isUndefined(discountedGross))) { taxamtdc = taxamtdc.add(new BigDecimal(String(new BigDecimal(String(discountedGross)).multiply(rate)))); } } } else { linetaxid = taxRate.get('id'); } }, this); // the line net price is calculated by doing price*price/(price*rate), as it is done in // the database function c_get_net_price_from_gross var linenet, calculatedLineNet, roundedLinePriceNet, linepricenet, linegross; if (orggross === 0) { linenet = new BigDecimal('0'); linepricenet = new BigDecimal('0'); roundedLinePriceNet = 0; linegross = 0; calculatedLineNet = 0; } else { linenet = new BigDecimal(String(orggross)).multiply(new BigDecimal(String(orggross))).divide(new BigDecimal(String(taxamt)), 20, BigDecimal.prototype.ROUND_HALF_UP); linepricenet = linenet.divide(new BigDecimal(String(element.get('qty'))), 20, BigDecimal.prototype.ROUND_HALF_UP); //round and continue with rounded values roundedLinePriceNet = OB.DEC.toNumber(linepricenet); calculatedLineNet = OB.DEC.mul(roundedLinePriceNet, new BigDecimal(String(element.get('qty')))); linegross = element.get('lineGrossAmount') || element.get('gross'); } element.set('linerate', OB.DEC.toNumber(linerate)); element.set('tax', linetaxid); element.set('taxAmount', OB.DEC.sub(linegross, linenet)); element.set('net', calculatedLineNet); element.set('pricenet', roundedLinePriceNet); totalnet = OB.DEC.add(totalnet, calculatedLineNet); //We follow the same formula of function c_get_net_price_from_gross to compute the discounted net if (!(_.isNull(discountedGross) || _.isUndefined(discountedGross))) { if (taxamtdc && OB.DEC.toNumber(taxamtdc) !== 0) { discountedNet = new BigDecimal(String(discountedGross)).multiply(new BigDecimal(String(discountedGross))).divide(new BigDecimal(String(taxamtdc)), 20, BigDecimal.prototype.ROUND_HALF_UP); discountedLinePriceNet = discountedNet.divide(new BigDecimal(String(element.get('qty'))), 20, BigDecimal.prototype.ROUND_HALF_UP); roundedDiscountedLinePriceNet = OB.DEC.toNumber(discountedLinePriceNet); calculatedDiscountedNet = OB.DEC.mul(roundedDiscountedLinePriceNet, new BigDecimal(String(element.get('qty')))); //In advance we will work with rounded prices pricenet = roundedDiscountedLinePriceNet; //discounted rounded NET unit price discountedNet = calculatedDiscountedNet; //discounted rounded NET line price //pricenet = new BigDecimal(String(discountedGross)).multiply(new BigDecimal(String(discountedGross))).divide(taxamtdc, 20, BigDecimal.prototype.ROUND_HALF_UP).divide(new BigDecimal(String(element.get('qty'))), 20, BigDecimal.prototype.ROUND_HALF_UP); } else { //taxamtdc === 0 discountedNet = 0; pricenet = 0; } } else { //net unit price (rounded) pricenet = roundedLinePriceNet; // 2 decimals properly rounded. } //pricenet = OB.DEC.toNumber(pricenet); element.set('discountedNet', OB.DEC.mul(pricenet, new BigDecimal(String(element.get('qty'))))); discountedNet = element.get('discountedNet'); pricenetcascade = pricenet; // second calculate tax lines. taxesline = {}; _.each(coll, function (taxRate, taxIndex) { if (!taxRate.get('summaryLevel')) { taxId = taxRate.get('id'); rate = new BigDecimal(String(taxRate.get('rate'))); rate = rate.divide(new BigDecimal('100'), 20, BigDecimal.prototype.ROUND_HALF_UP); if (taxRate.get('cascade')) { pricenet = pricenetcascade; } net = OB.DEC.mul(pricenet, element.get('qty')); //=== discountedNet amount = OB.DEC.mul(net, rate); pricenetcascade = OB.DEC.mul(pricenet, rate.add(BigDecimal.prototype.ONE)); taxesline[taxId] = {}; taxesline[taxId].name = taxRate.get('name'); taxesline[taxId].rate = taxRate.get('rate'); taxesline[taxId].net = OB.DEC.toNumber(new BigDecimal(String(pricenet)).multiply(new BigDecimal(String(element.get('qty'))))); taxesline[taxId].amount = amount; } }, this); // We need to make a final adjustment: we will sum all the tax lines, // and if the net amount of the line plus this sum is not equal to the gross, // we will adjust the tax line with the greatest amount var summedTaxAmt = 0; var expectedGross; if (!(_.isNull(discountedGross) || _.isUndefined(discountedGross))) { expectedGross = discountedGross; } else { expectedGross = element.get('gross'); } var greaterTax = null; _.each(coll, function (taxRate, taxIndex) { if (!taxRate.get('summaryLevel')) { taxId = taxRate.get('id'); summedTaxAmt = OB.DEC.add(summedTaxAmt, taxesline[taxId].amount); if (me.get('orderType') === 1) { if (greaterTax === null || taxesline[greaterTax].amount > taxesline[taxId].amount) { greaterTax = taxId; } } else { if (greaterTax === null || taxesline[greaterTax].amount < taxesline[taxId].amount) { greaterTax = taxId; } } } }); var netandtax; if (!(_.isNull(discountedGross) || _.isUndefined(discountedGross))) { netandtax = OB.DEC.add(discountedNet, summedTaxAmt); } else { netandtax = OB.DEC.add(OB.DEC.mul(pricenet, element.get('qty')), summedTaxAmt); } if (expectedGross !== netandtax) { //An adjustment is needed taxesline[greaterTax].amount = OB.DEC.add(taxesline[greaterTax].amount, OB.DEC.sub(expectedGross, netandtax)); } element.set('taxLines', taxesline); // processed = yes queue[element.cid] = true; // checking queue status triggerNext = OB.UTIL.queueStatus(queue); _.each(coll, function (taxRate, taxIndex) { var taxId = taxRate.get('id'); delete taxes[taxId]; me.get('lines').each(function (line, taxIndex) { var taxLines = line.get('taxLines'); if (!taxLines || !taxLines[taxId]) { return; } if (!taxRate.get('summaryLevel')) { if (taxes[taxId]) { taxes[taxId].net = OB.DEC.add(taxes[taxId].net, taxLines[taxId].net); taxes[taxId].amount = OB.DEC.add(taxes[taxId].amount, taxLines[taxId].amount); } else { taxes[taxId] = {}; taxes[taxId].name = taxRate.get('name'); taxes[taxId].rate = taxRate.get('rate'); taxes[taxId].net = taxLines[taxId].net; taxes[taxId].amount = taxLines[taxId].amount; } } }); }); _.each(coll, function (taxRate, taxIndex) { var taxId = taxRate.get('id'); if (taxes[taxId]) { taxes[taxId].net = OB.DEC.toNumber(taxes[taxId].net); taxes[taxId].amount = OB.DEC.toNumber(taxes[taxId].amount); } }); // triggering next steps if (triggerNext) { me.set('taxes', taxes); me.set('net', totalnet); if (callback) { callback(); } } } else { me.deleteLine(element); OB.MobileApp.view.$.containerWindow.getRoot().doShowPopup({ popup: 'OB_UI_MessageDialog', args: { header: OB.I18N.getLabel('OBPOS_TaxNotFound_Header'), message: OB.I18N.getLabel('OBPOS_TaxNotFound_Message', [args.get('_identifier')]) } }); } }, function (tx, error) { // error me.deleteLine(element); OB.MobileApp.view.$.containerWindow.getRoot().doShowPopup({ popup: 'OB_UI_MessageDialog', args: { header: OB.I18N.getLabel('OBPOS_TaxNotFound_Header'), message: OB.I18N.getLabel('OBPOS_TaxCalculationError_Message') } }); }, product); // add line to queue of pending to be processed queue[element.cid] = false; }); }); } else { //In case the pricelist doesn't include taxes, the way to calculate taxes is different _.each(lines.models, function (element, index, list) { var product = element.get('product'); if (element.get('ignoreTaxes') === true || product.get('ignoreTaxes') === true) { var taxLine = {}; element.set('linerate', OB.DEC.toNumber(BigDecimal.prototype.ONE)); element.set('tax', OB.MobileApp.model.get('terminal').taxexempid); element.set('taxAmount', OB.DEC.Zero); element.set('net', element.get('net')); element.set('pricenet', element.get('net')); element.set('gross', element.get('net')); element.set('discountedGross', element.get('net')); element.set('discountedNet', new BigDecimal(String(element.get('net')))); element.set('taxAmount', OB.DEC.Zero); element.set('discountedNetPrice', new BigDecimal(String(element.get('net')))); taxLine[OB.MobileApp.model.get('terminal').taxexempid] = { amount: 0, rate: 0, net: element.get('net') }; element.set('taxLines', taxLine); } else { var sql = "select c_tax.c_tax_id, c_tax.name, c_tax.description, c_tax.taxindicator, c_tax.validfrom, c_tax.issummary, c_tax.rate, c_tax.parent_tax_id, (case when c_tax.c_country_id = '" + fromCountryOrg + "' then c_tax.c_country_id else tz.from_country_id end) as c_country_id, (case when c_tax.c_region_id = '" + fromRegionOrg + "' then c_tax.c_region_id else tz.from_region_id end) as c_region_id, (case when c_tax.to_country_id = bpl.countryId then c_tax.to_country_id else tz.to_country_id end) as to_country_id, (case when c_tax.to_region_id = bpl.regionId then c_tax.to_region_id else tz.to_region_id end) as to_region_id, c_tax.c_taxcategory_id, c_tax.isdefault, c_tax.istaxexempt, c_tax.sopotype, c_tax.cascade, c_tax.c_bp_taxcategory_id, c_tax.line, c_tax.iswithholdingtax, c_tax.isnotaxable, c_tax.deducpercent, c_tax.originalrate, c_tax.istaxundeductable, c_tax.istaxdeductable, c_tax.isnovat, c_tax.baseamount, c_tax.c_taxbase_id, c_tax.doctaxamount, c_tax.iscashvat, c_tax._identifier, c_tax._idx, (case when (c_tax.to_country_id = bpl.countryId or tz.to_country_id= bpl.countryId) then 0 else 1 end) as orderCountryTo, (case when (c_tax.to_region_id = bpl.regionId or tz.to_region_id = bpl.regionId) then 0 else 1 end) as orderRegionTo, (case when coalesce(c_tax.c_country_id, tz.from_country_id) is null then 1 else 0 end) as orderCountryFrom, (case when coalesce(c_tax.c_region_id, tz.from_region_id) is null then 1 else 0 end) as orderRegionFrom from c_tax left join c_tax_zone tz on tz.c_tax_id = c_tax.c_tax_id join c_bpartner_location bpl on bpl.c_bpartner_location_id = '" + me.get('bp').get('locId') + "' where c_tax.sopotype in ('B', 'S') "; if (bpIsExempt) { sql = sql + " and c_tax.istaxexempt = 'true'"; } else { sql = sql + " and c_tax.c_taxCategory_id = '" + product.get('taxCategory') + "'"; if (bpTaxCategory) { sql = sql + " and c_tax.c_bp_taxcategory_id = '" + bpTaxCategory + "'"; } else { sql = sql + " and c_tax.c_bp_taxcategory_id is null"; } } sql = sql + " and c_tax.validFrom <= date()"; sql = sql + " and (c_tax.to_country_id = bpl.countryId or tz.to_country_id = bpl.countryId or (c_tax.to_country_id is null and (not exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_country_id = bpl.countryId) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_country_id is null))))"; sql = sql + " and (c_tax.to_region_id = bpl.regionId or tz.to_region_id = bpl.regionId or (c_tax.to_region_id is null and (not exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_region_id = bpl.regionId) or exists (select 1 from c_tax_zone z where z.c_tax_id = c_tax.c_tax_id and z.to_region_id is null))))"; sql = sql + " order by orderRegionTo, orderRegionFrom, orderCountryTo, orderCountryFrom, c_tax.validFrom desc, c_tax.isdefault desc"; // the query is ordered by countryId desc and regionId desc // (so, the first record will be the tax with the same country or region that the customer, // or if toCountryId and toRegionId are nulls then will be ordered by validfromdate) OB.UTIL.HookManager.executeHooks('OBPOS_FindTaxRate', { context: me, line: element, sql: sql }, function (args) { OB.Dal.query(OB.Model.TaxRate, args.sql, [], function (coll, args) { // success var rate, taxAmt, net, pricenet, pricenetcascade, amount, taxId, roundingLoses; if (coll && coll.length > 0) { // First calculate the line rate. var linerate = BigDecimal.prototype.ONE; var linetaxid = coll.at(0).get('id'); var validFromDate = coll.at(0).get('validFromDate'); var fromCountryId = coll.at(0).get('country'); var fromRegionId = coll.at(0).get('region'); var toCountryId = coll.at(0).get('destinationCountry'); var toRegionId = coll.at(0).get('destinationRegion'); coll = _.filter(coll.models, function (taxRate) { var isOK = true; isOK = isOK && (taxRate.get('destinationCountry') === toCountryId); isOK = isOK && (taxRate.get('destinationRegion') === toRegionId); isOK = isOK && (taxRate.get('country') === fromCountryId); isOK = isOK && (taxRate.get('region') === fromRegionId); return isOK && ((taxRate.get('validFromDate') === validFromDate)); }); var discAmt = null; if (element.get('promotions') && element.get('promotions').length > 0) { discAmt = new BigDecimal(String(element.get('net'))); discAmt = element.get('promotions').reduce(function (memo, element) { return memo.subtract(new BigDecimal(String(element.actualAmt || element.amt || 0))); }, discAmt); } var linepricenet = element.get('price'); var discountedprice, calculatedDiscountedprice, orgDiscountedprice; if (!(_.isNull(discAmt) || _.isUndefined(discAmt))) { discountedprice = discAmt.divide(new BigDecimal(String(element.get('qty'))), 20, BigDecimal.prototype.ROUND_HALF_UP); discountedNet = OB.DEC.toNumber(discAmt); //sometimes with packs or discounts we are losing precision and this precision is reflected wrongly in the tax net //we save the number with total precision and bellow if there are differences they are corrected. calculatedDiscountedprice = true; orgDiscountedprice = discAmt.divide(new BigDecimal(String(element.get('qty'))), 20, BigDecimal.prototype.ROUND_HALF_UP); } else { discountedprice = new BigDecimal(String(element.get('price'))); discountedNet = OB.DEC.mul(discountedprice, element.get('qty')); } var linenet = OB.DEC.mul(linepricenet, element.get('qty')); var discountedGross = new BigDecimal(String(discountedNet)); var linegross = new BigDecimal(String(linenet)); // First calculate the line rate. _.each(coll, function (taxRate, taxIndex) { if (!taxRate.get('summaryLevel')) { rate = new BigDecimal(String(taxRate.get('rate'))); // 10 rate = rate.divide(new BigDecimal('100'), 20, BigDecimal.prototype.ROUND_HALF_UP); // 0.10 if (taxRate.get('cascade')) { linerate = linerate.multiply(rate.add(BigDecimal.prototype.ONE)); linegross = linegross.multiply(rate.add(BigDecimal.prototype.ONE)); discountedGross = discountedGross.add(new BigDecimal(OB.DEC.toNumber(discountedGross.multiply(rate)).toString())); } else { linerate = linerate.add(rate); linegross = linegross.add(new BigDecimal(String(linenet)).multiply(new BigDecimal(String(rate)))); discountedGross = discountedGross.add(new BigDecimal(OB.DEC.toNumber(new BigDecimal(String(discountedNet)).multiply(rate)).toString())); } } else { linetaxid = taxRate.get('id'); } }, this); var linepricegross = OB.DEC.div(linegross, element.get('qty')); element.set('linerate', OB.DEC.toNumber(linerate)); element.set('tax', linetaxid); element.set('taxAmount', OB.DEC.mul(OB.DEC.mul(discountedprice, element.get('qty')), linerate)); element.set('net', linenet); element.set('pricenet', linepricenet); element.set('gross', OB.DEC.toNumber(linegross)); element.set('fullgross', linegross); element.set('discountedGross', OB.DEC.toNumber(discountedGross)); element.set('discountedNet', discountedNet); element.set('taxAmount', OB.DEC.sub(element.get('discountedGross'), element.get('discountedNet'))); element.set('discountedNetPrice', discountedprice); totalnet = OB.DEC.add(totalnet, linenet); pricenet = new BigDecimal(String(discountedprice)) || (new BigDecimal(String(linepricenet))); // 2 decimals properly rounded. pricenetcascade = pricenet; // second calculate tax lines. taxesline = {}; _.each(coll, function (taxRate, taxIndex) { if (!taxRate.get('summaryLevel')) { taxId = taxRate.get('id'); rate = new BigDecimal(String(taxRate.get('rate'))); rate = rate.divide(new BigDecimal('100'), 20, BigDecimal.prototype.ROUND_HALF_UP); if (taxRate.get('cascade')) { pricenet = pricenetcascade; } net = OB.DEC.mul(pricenet, element.get('qty')); amount = OB.DEC.mul(net, rate); pricenetcascade = pricenet.multiply(rate.add(BigDecimal.prototype.ONE)); taxesline[taxId] = {}; taxesline[taxId].name = taxRate.get('name'); taxesline[taxId].rate = taxRate.get('rate'); taxesline[taxId].net = net; taxesline[taxId].amount = amount; if (taxes[taxId]) { taxes[taxId].net = OB.DEC.add(taxes[taxId].net, OB.DEC.mul(discountedprice, element.get('qty'))); if (calculatedDiscountedprice) { roundingLoses = orgDiscountedprice.subtract(discountedprice).multiply(new BigDecimal('2')); if (roundingLoses.compareTo(BigDecimal.prototype.ZERO) !== 0) { roundingLoses = OB.DEC.toNumber(roundingLoses); taxes[taxId].net = OB.DEC.add(taxes[taxId].net, roundingLoses); } } taxes[taxId].amount = OB.DEC.add(taxes[taxId].amount, amount); } else { taxes[taxId] = {}; taxes[taxId].name = taxRate.get('name'); taxes[taxId].rate = taxRate.get('rate'); taxes[taxId].net = net; if (calculatedDiscountedprice) { //If we lost precision because the price that we are showing is not the real one //we correct this small number in tax net. roundingLoses = orgDiscountedprice.subtract(discountedprice).multiply(new BigDecimal('2')); if (roundingLoses.compareTo(BigDecimal.prototype.ZERO) !== 0) { roundingLoses = OB.DEC.toNumber(roundingLoses); taxes[taxId].net = OB.DEC.add(taxes[taxId].net, roundingLoses); } } taxes[taxId].amount = amount; } } }, this); element.set('taxLines', taxesline); // processed = yes queue[element.cid] = true; // checking queue status triggerNext = OB.UTIL.queueStatus(queue); _.each(coll, function (taxRate, taxIndex) { var taxId = taxRate.get('id'); if (taxes[taxId]) { //taxes[taxId].net = taxes[taxId].net; taxes[taxId].amount = OB.DEC.toNumber(taxes[taxId].amount); } }); // triggering next steps if (triggerNext) { me.set('taxes', taxes); if (callback) { callback(); } } } else { me.deleteLine(element); OB.MobileApp.view.$.containerWindow.getRoot().doShowPopup({ popup: 'OB_UI_MessageDialog', args: { header: OB.I18N.getLabel('OBPOS_TaxNotFound_Header'), message: OB.I18N.getLabel('OBPOS_TaxNotFound_Message', [args.get('_identifier')]) } }); } }, function (tx, error) { // error me.deleteLine(element); OB.MobileApp.view.$.containerWindow.getRoot().doShowPopup({ popup: 'OB_UI_MessageDialog', args: { header: OB.I18N.getLabel('OBPOS_TaxNotFound_Header'), message: OB.I18N.getLabel('OBPOS_TaxCalculationError_Message') } }); }, product); // add line to queue of pending to be processed queue[element.cid] = false; }); } }); } }; }; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B,_*/ (function () { OB = window.OB || {}; OB.DATA = window.OB.DATA || {}; OB.DATA.CustomerSave = function (model) { this.context = model; this.customer = model.get('customer'); this.customer.on('customerSaved', function () { var me = this, customersList, customerId = this.customer.get('id'), isNew = false, bpToSave = new OB.Model.ChangedBusinessPartners(), bpLocToSave = new OB.Model.BPLocation(), customersListToChange; bpToSave.set('isbeingprocessed', 'N'); this.customer.set('createdBy', OB.POS.modelterminal.get('orgUserId')); bpToSave.set('createdBy', OB.POS.modelterminal.get('orgUserId')); if (customerId) { this.customer.set('posTerminal', OB.POS.modelterminal.get('terminal').id); bpToSave.set('json', JSON.stringify(this.customer.serializeToJSON())); bpToSave.set('c_bpartner_id', this.customer.get('id')); } else { isNew = true; } //save that the customer is being processed by server OB.Dal.save(this.customer, function () { //OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSavedSuccessfullyLocally',[me.customer.get('_identifier')])); // Saving Customer Address locally bpLocToSave.set('id', me.customer.get('locId')); bpLocToSave.set('bpartner', me.customer.get('id')); bpLocToSave.set('name', me.customer.get('locName')); bpLocToSave.set('postalCode', me.customer.get('postalCode')); bpLocToSave.set('cityName', me.customer.get('cityName')); if (isNew) { bpLocToSave.set('countryName', OB.POS.modelterminal.get('terminal').defaultbp_bpcountry_name); bpLocToSave.set('countryId', OB.POS.modelterminal.get('terminal').defaultbp_bpcountry); } else { bpLocToSave.set('countryName', me.customer.get('countryName')); bpLocToSave.set('countryId', me.customer.get('country')); } bpLocToSave.set('_identifier', me.customer.get('locName')); OB.Dal.save(bpLocToSave, function () {}, function () { OB.error(arguments); }, isNew); if (isNew) { me.customer.set('posTerminal', OB.POS.modelterminal.get('terminal').id); bpToSave.set('json', JSON.stringify(me.customer.serializeToJSON())); bpToSave.set('c_bpartner_id', me.customer.get('id')); } bpToSave.set('isbeingprocessed', 'Y'); OB.Dal.save(bpToSave, function () { bpToSave.set('json', me.customer.serializeToJSON()); var successCallback, errorCallback, List; successCallback = function () { OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSaved', [me.customer.get('_identifier')])); }; OB.MobileApp.model.runSyncProcess(successCallback); }, function () { //error saving BP changes with changes in changedbusinesspartners OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerChanges', [me.customer.get('_identifier')])); }); }, function () { //error saving BP with new values in c_bpartner OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerLocally', [me.customer.get('_identifier')])); }); }, this); }; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global B,_*/ (function () { OB = window.OB || {}; OB.DATA = window.OB.DATA || {}; OB.DATA.CustomerAddrSave = function (model) { this.context = model; this.customerAddr = model.get('customerAddr'); this.customerAddr.on('customerAddrSaved', function () { var me = this, customerAddrList, customerAddrId = this.customerAddr.get('id'), isNew = false, bpLocToSave = new OB.Model.ChangedBPlocation(), customerAddrListToChange; bpLocToSave.set('isbeingprocessed', 'N'); this.customerAddr.set('createdBy', OB.POS.modelterminal.get('orgUserId')); bpLocToSave.set('createdBy', OB.POS.modelterminal.get('orgUserId')); if (customerAddrId) { this.customerAddr.set('posTerminal', OB.POS.modelterminal.get('terminal').id); bpLocToSave.set('json', JSON.stringify(this.customerAddr.serializeToJSON())); bpLocToSave.set('c_bpartner_location_id', this.customerAddr.get('id')); } else { isNew = true; } //save that the customer address is being processed by server OB.Dal.save(this.customerAddr, function () { // Update Default Address function errorCallback(tx, error) { OB.error(tx); } function successCallbackBPs(dataBps) { if (dataBps.length === 0) { OB.Dal.get(OB.Model.BusinessPartner, me.customerAddr.get('bpartner'), function success(dataBps) { dataBps.set('locId', me.customerAddr.get('id')); dataBps.set('locName', me.customerAddr.get('name')); OB.Dal.save(dataBps, function () {}, function (tx) { OB.error(tx); }); }, function error(tx) { OB.error(tx); }); } } var criteria = {}; criteria._whereClause = "where c_bpartner_id = '" + me.customerAddr.get('bpartner') + "' and c_bpartnerlocation_id > '" + me.customerAddr.get('id') + "'"; criteria.params = []; OB.Dal.find(OB.Model.BusinessPartner, criteria, successCallbackBPs, errorCallback); if (isNew) { me.customerAddr.set('posTerminal', OB.POS.modelterminal.get('terminal').id); bpLocToSave.set('json', JSON.stringify(me.customerAddr.serializeToJSON())); bpLocToSave.set('c_bpartner_location_id', me.customerAddr.get('id')); } bpLocToSave.set('isbeingprocessed', 'Y'); OB.Dal.save(bpLocToSave, function () { bpLocToSave.set('json', me.customerAddr.serializeToJSON()); var successCallback, errorCallback, List; successCallback = function () { OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerAddrSaved', [me.customerAddr.get('_identifier')])); }; customerAddrListToChange = new OB.Collection.ChangedBPlocationList(); customerAddrListToChange.add(bpLocToSave); OB.MobileApp.model.runSyncProcess(successCallback); }, function () { //error saving BP changes with changes in changedbusinesspartners OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrChn', [me.customerAddr.get('_identifier')])); }); }, function () { //error saving BP Location with new values in c_bpartner_location OB.error(arguments); OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrLocally', [me.customerAddr.get('_identifier')])); }); }, this); }; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B */ (function () { OB = window.OB || {}; OB.DATA = window.OB.DATA || {}; OB.DATA.OrderDiscount = function (receipt) { receipt.on('discount', function (line, percentage) { if (line) { if (OB.DEC.compare(percentage) > 0 && OB.DEC.compare(OB.DEC.sub(percentage, OB.DEC.number(100))) <= 0) { receipt.setPrice(line, OB.DEC.toNumber(new BigDecimal(String(line.get('price'))).multiply(new BigDecimal(String(OB.DEC.sub(OB.DEC.number(100), percentage)))).divide(new BigDecimal("100"), OB.DEC.getScale(), OB.DEC.getRoundingMode()))); } else if (OB.DEC.compare(percentage) === 0) { receipt.setPrice(line, line.get('price')); } } }, this); }; }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.UI.ModalReceipts', kind: 'OB.UI.Modal', topPosition: '125px', published: { receiptsList: null }, i18nHeader: 'OBPOS_LblAssignReceipt', body: { kind: 'OB.UI.ListReceipts', name: 'listreceipts' }, receiptsListChanged: function (oldValue) { this.$.body.$.listreceipts.setReceiptsList(this.receiptsList); } }); enyo.kind({ name: 'OB.UI.ListReceipts', classes: 'row-fluid', published: { receiptsList: null }, events: { onChangeCurrentOrder: '' }, components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;' }, { components: [{ name: 'receiptslistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderLine: 'OB.UI.ListReceiptLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }], receiptsListChanged: function (oldValue) { this.$.receiptslistitemprinter.setCollection(this.receiptsList); this.receiptsList.on('click', function (model) { this.doChangeCurrentOrder({ newCurrentOrder: model }); }, this); } }); enyo.kind({ name: 'OB.UI.ListReceiptLine', kind: 'OB.UI.SelectButton', events: { onHideThisPopup: '' }, tap: function () { this.inherited(arguments); this.doHideThisPopup(); }, components: [{ name: 'line', style: 'line-height: 23px; width: 100%;', components: [{ components: [{ style: 'float: left; width: 15%', name: 'time' }, { style: 'float: left; width: 25%', name: 'orderNo' }, { style: 'float: left; width: 60%', name: 'bp' }, { style: 'clear: both;' }] }, { components: [{ style: 'float: left; width: 15%; font-weight: bold;' }, { style: 'float: left; width: 25%; font-weight: bold;' }, { style: 'float: right; text-align: right; width: 25%; font-weight: bold;', name: 'total' }, { style: 'clear: both;' }] }] }], create: function () { this.inherited(arguments); if (this.model.get('isPaid')) { this.$.time.setContent(OB.I18N.formatDate(this.model.get('orderDate'))); } else { this.$.time.setContent(OB.I18N.formatHour(this.model.get('orderDate'))); } this.$.orderNo.setContent(this.model.get('documentNo')); this.$.bp.setContent(this.model.get('bp').get('_identifier')); this.$.total.setContent(this.model.printTotal()); } }); /*delete confirmation modal*/ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalDeleteReceipt', bodyContent: { i18nContent: 'OBPOS_MsgConfirmDelete' // TODO: add this as part of the message + '\n' + OB.I18N.getLabel('OBPOS_cannotBeUndone') }, bodyButtons: { components: [{ kind: 'OB.UI.btnModalApplyDelete' }, { kind: 'OB.UI.btnModalCancelDelete' }] }, initComponents: function () { this.header = OB.I18N.getLabel('OBPOS_ConfirmDeletion'); this.inherited(arguments); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.btnModalApplyDelete', isDefaultAction: true, i18nContent: 'OBPOS_LblYesDelete', events: { onDeleteOrder: '' }, tap: function () { this.doHideThisPopup(); this.doDeleteOrder({ notSavedOrder: true }); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.btnModalCancelDelete', i18nContent: 'OBMOBC_LblCancel', tap: function () { this.doHideThisPopup(); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, _ */ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalMultiOrdersLayaway', executeOnShow: function () { this.$.bodyButtons.$.btnModalMultiSearchInput.setValue(''); }, bodyContent: { i18nContent: 'OBPOS_MultiOrdersLayaway' // TODO: add this as part of the message + '\n' + OB.I18N.getLabel('OBPOS_cannotBeUndone') }, bodyButtons: { components: [{ name: 'btnModalMultiSearchInput', kind: 'OB.UI.SearchInput' }, { kind: 'OB.UI.btnApplyMultiLayaway' }] }, initComponents: function () { this.header = OB.I18N.getLabel('OBPOS_MultiOrdersLayawayHeader'); this.inherited(arguments); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.btnApplyMultiLayaway', isDefaultAction: true, i18nContent: 'OBPOS_LblApplyButton', tap: function () { var amount = OB.DEC.Zero, tmp; if (this.owner.$.btnModalMultiSearchInput.getValue().indexOf('%') !== -1) { try { tmp = this.owner.$.btnModalMultiSearchInput.getValue().replace('%', ''); amount = OB.DEC.div(OB.DEC.mul(this.model.get('multiOrders').get('multiOrdersList').get(this.owner.owner.args.id).getPending(), tmp), 100); } catch (ex) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_notValidInput_header'), OB.I18N.getLabel('OBPOS_notValidQty')); return; } } else { try { amount = OB.I18N.parseNumber(this.owner.$.btnModalMultiSearchInput.getValue()); } catch (exc) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_notValidInput_header'), OB.I18N.getLabel('OBPOS_notValidQty')); return; } } if (_.isNaN(amount)) { this.model.get('multiOrders').get('multiOrdersList').get(this.owner.owner.args.id).setOrderType(null, 0); this.model.get('multiOrders').get('multiOrdersList').get(this.owner.owner.args.id).set('amountToLayaway', null); this.doHideThisPopup(); return; } this.model.get('multiOrders').get('multiOrdersList').get(this.owner.owner.args.id).set('amountToLayaway', amount); this.model.get('multiOrders').get('multiOrdersList').get(this.owner.owner.args.id).setOrderType(null, 2); this.doHideThisPopup(); }, init: function (model) { this.model = model; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.UI.RenderCategory', kind: 'OB.UI.listItemButton', components: [{ style: 'float: left; width: 25%', components: [{ kind: 'OB.UI.Thumbnail', name: 'thumbnail' }] }, { style: 'float: left; width: 75%;', components: [{ name: 'identifier', style: 'padding-left: 5px;' }, { style: 'clear:both;' }] }], initComponents: function () { this.inherited(arguments); this.addClass('btnselect-browse'); this.$.identifier.setContent(this.model.get('_identifier')); this.$.thumbnail.setImg(this.model.get('img')); } }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.UI.RenderProduct', kind: 'OB.UI.listItemButton', components: [{ style: 'float: left; width: 25%', components: [{ tag: 'div', classes: 'image-wrap', contentType: 'image/png', style: 'width: 49px; height: 49px', components: [{ tag: 'img', name: 'icon', style: 'margin: auto; height: 100%; width: 100%; background-size: contain; background-repeat:no-repeat; background-position:center;' }] }, { kind: 'OB.UI.Thumbnail', name: 'thumbnail' }] }, { style: 'float: left; width: 38%; ', components: [{ name: 'identifier' }, { style: 'color: #888888', name: 'bottonLine' }] }, { name: 'price', style: 'float: right; width: 27%; text-align: right; font-weight:bold;' }, { style: 'clear:both;' }, { name: 'generic', style: 'float: right; width: 20%; text-align: right; font-style: italic; color: grey; padding: 15px' }], initComponents: function () { this.inherited(arguments); this.$.identifier.setContent(this.setIdentifierContent()); if (this.model.get('showchdesc')) { this.$.bottonLine.setContent(this.model.get('characteristicDescription')); } this.$.price.setContent(OB.I18N.formatCurrency(this.model.get('standardPrice'))); if (OB.MobileApp.model.get('permissions')["OBPOS_retail.productImages"]) { this.$.icon.applyStyle('background-image', 'url(' + OB.UTIL.getImageURL(this.model.get('id')) + '), url(' + "../org.openbravo.mobile.core/assets/img/box.png" + ')'); this.$.thumbnail.hide(); } else { this.$.thumbnail.setImg(this.model.get('img')); this.$.icon.parent.hide(); } if (this.model.get('isGeneric')) { this.$.generic.setContent(OB.I18N.getLabel('OBMOBC_LblGeneric')); } }, setIdentifierContent: function () { return this.model.get('_identifier'); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.UI.RenderProductCh', style: 'width: 86%; padding: 0px', classes: 'btnlink-white-simple', events: { onShowPopup: '' }, tap: function () { if (!this.disabled) { this.doShowPopup({ popup: 'modalproductcharacteristic', args: { model: this.model } }); } }, initComponents: function () { this.inherited(arguments); if (this.model.get('_identifier').length < 13) { this.setContent(this.model.get('_identifier')); } else { this.setContent(this.model.get('_identifier').substring(0, 10) + '...'); } if (this.model.get('filtering')) { this.addClass('btnlink-yellow-bold'); } } }); enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.UI.RenderEmptyCh', style: 'width: 150px; border: 2px solid #cccccc;', classes: 'btnlink-white', events: { onClearAction: '' }, tap: function () { this.doClearAction(); }, initComponents: function () { this.inherited(arguments); this.setContent('Clear Filters'); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ // Order list enyo.kind({ name: 'OB.UI.Total', tag: 'span', attributes: { style: 'font-weight:bold;' }, renderTotal: function (total) { this.setContent(OB.I18N.formatCurrency(total)); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.UI.ModalPayment', kind: 'OB.UI.ModalAction', header: '', maxheight: '600px', bodyContent: {}, bodyButtons: {}, executeOnShow: function () { if (this.args.receipt.get('orderType') === 0 || this.args.receipt.get('orderType') === 2 || this.args.receipt.get('isLayaway')) { this.$.header.setContent(OB.I18N.getLabel('OBPOS_LblModalPayment', [OB.I18N.formatCurrency(this.args.amount)])); } else if (this.args.receipt.get('orderType') === 1 || this.args.receipt.get('orderType') === 3) { this.$.header.setContent(OB.I18N.getLabel('OBPOS_LblModalReturn', [OB.I18N.formatCurrency(this.args.amount)])); } else { this.$.header.setContent(''); } this.$.bodyContent.destroyComponents(); //default values to reset changes done by a payment method this.closeOnEscKey = this.dfCloseOnEscKey; this.autoDismiss = this.dfAutoDismiss; this.executeOnShown = null; this.executeBeforeHide = null; this.executeOnHide = null; this.$.bodyContent.createComponent({ mainPopup: this, kind: this.args.provider, paymentMethod: this.args.paymentMethod, paymentType: this.args.name, paymentAmount: this.args.amount, key: this.args.key, receipt: this.args.receipt, allowOpenDrawer: this.args.paymentMethod.allowopendrawer, isCash: this.args.paymentMethod.iscash, openDrawer: this.args.paymentMethod.openDrawer }).render(); }, initComponents: function () { this.inherited(arguments); this.dfAutoDismiss = this.autoDismiss; this.dfCloseOnEscKey = this.closeOnEscKey; } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo,_ */ enyo.kind({ kind: 'OB.UI.listItemButton', name: 'OB.UI.RenderOrderLine', classes: 'btnselect-orderline', handlers: { onChangeEditMode: 'changeEditMode', onCheckBoxBehaviorForTicketLine: 'checkBoxForTicketLines' }, events: { onLineChecked: '' }, components: [{ name: 'checkBoxColumn', kind: 'OB.UI.CheckboxButton', tag: 'div', tap: function () { }, style: 'float: left; width: 10%;' }, { name: 'product', attributes: { style: 'float: left; width: 40%;' } }, { name: 'quantity', attributes: { style: 'float: left; width: 20%; text-align: right;' } }, { name: 'price', attributes: { style: 'float: left; width: 20%; text-align: right;' } }, { name: 'gross', attributes: { style: 'float: left; width: 20%; text-align: right;' } }, { style: 'clear: both;' }], initComponents: function () { this.inherited(arguments); this.$.checkBoxColumn.hide(); this.$.product.setContent(this.model.get('product').get('_identifier')); this.$.quantity.setContent(this.model.printQty()); this.$.price.setContent(this.model.printPrice()); if (this.model.get('priceIncludesTax')) { this.$.gross.setContent(this.model.printGross()); } else { this.$.gross.setContent(this.model.printNet()); } if (this.model.get('product').get('characteristicDescription')) { this.createComponent({ style: 'display: block;', components: [{ content: OB.UTIL.getCharacteristicValues(this.model.get('product').get('characteristicDescription')), attributes: { style: 'float: left; width: 60%; color:grey' } }, { style: 'clear: both;' }] }); } if (this.model.get('promotions')) { enyo.forEach(this.model.get('promotions'), function (d) { if (d.hidden) { // continue return; } this.createComponent({ style: 'display: block;', components: [{ content: '-- ' + d.name, attributes: { style: 'float: left; width: 80%;' } }, { content: OB.I18N.formatCurrency(-d.amt), attributes: { style: 'float: right; width: 20%; text-align: right;' } }, { style: 'clear: both;' }] }); }, this); } OB.UTIL.HookManager.executeHooks('OBPOS_RenderOrderLine', { orderline: this }, function (args) { //All should be done in module side }); }, changeEditMode: function (inSender, inEvent) { this.addRemoveClass('btnselect-orderline-edit', inEvent.edit); this.bubble('onShowColumn', { colNum: 1 }); }, checkBoxForTicketLines: function (inSender, inEvent) { if (inEvent.status) { this.$.gross.hasNode().style.width = '18%'; this.$.quantity.hasNode().style.width = '16%'; this.$.price.hasNode().style.width = '18%'; this.$.product.hasNode().style.width = '38%'; this.$.checkBoxColumn.show(); this.changeEditMode(this, inEvent.status); } else { this.$.gross.hasNode().style.width = '20%'; this.$.quantity.hasNode().style.width = '20%'; this.$.price.hasNode().style.width = '20%'; this.$.product.hasNode().style.width = '40%'; this.$.checkBoxColumn.hide(); this.changeEditMode(this, false); } } }); enyo.kind({ name: 'OB.UI.RenderOrderLineEmpty', style: 'border-bottom: 1px solid #cccccc; padding: 20px; text-align: center; font-weight: bold; font-size: 30px; color: #cccccc', initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBPOS_ReceiptNew')); } }); enyo.kind({ name: 'OB.UI.RenderTaxLineEmpty', style: 'border-bottom: 1px solid #cccccc; padding: 20px; text-align: center; font-weight: bold; font-size: 30px; color: #cccccc', initComponents: function () { this.inherited(arguments); } }); enyo.kind({ kind: 'OB.UI.listItemButton', name: 'OB.UI.RenderTaxLine', classes: 'btnselect-orderline', tap: function () { }, components: [{ name: 'tax', attributes: { style: 'float: left; width: 60%;' } }, { name: 'base', attributes: { style: 'float: left; width: 20%; text-align: right;' } }, { name: 'totaltax', attributes: { style: 'float: left; width: 20%; text-align: right;' } }, { style: 'clear: both;' }], selected: function () { }, initComponents: function () { this.inherited(arguments); this.$.tax.setContent(this.model.get('name')); this.$.base.setContent(OB.I18N.formatCurrency(this.model.get('net'))); this.$.totaltax.setContent(OB.I18N.formatCurrency(this.model.get('amount'))); } }); enyo.kind({ kind: 'OB.UI.SelectButton', name: 'OB.UI.RenderPaymentLine', classes: 'btnselect-orderline', style: 'border-bottom: 0px', tap: function () { }, components: [{ name: 'name', attributes: { style: 'float: left; width: 40%; padding: 5px 0px 0px 0px;' } }, { name: 'date', attributes: { style: 'float: left; width: 20%; padding: 5px 0px 0px 0px; text-align: right;' } }, { name: 'foreignAmount', attributes: { style: 'float: left; width: 20%; padding: 5px 0px 0px 0px; text-align: right;' } }, { name: 'amount', attributes: { style: 'float: left; width: 20%; padding: 5px 0px 0px 0px; text-align: right;' } }, { style: 'clear: both;' }], selected: function () { }, initComponents: function () { var paymentDate; this.inherited(arguments); this.$.name.setContent(OB.POS.modelterminal.getPaymentName(this.model.get('kind')) || this.model.get('name')); if (OB.UTIL.isNullOrUndefined(this.model.get('paymentDate'))) { paymentDate = new Date(); } else { // Convert to UTC to properly manage browser timezone paymentDate = this.model.get('paymentDate'); paymentDate = new Date(paymentDate.getTime() + (60000 * paymentDate.getTimezoneOffset())); } this.$.date.setContent(OB.I18N.formatDate(paymentDate)); if (this.model.get('rate') && this.model.get('rate') !== '1') { this.$.foreignAmount.setContent(this.model.printForeignAmount()); } else { this.$.foreignAmount.setContent(''); } this.$.amount.setContent(this.model.printAmount()); } }); enyo.kind({ name: 'OB.UI.RenderPaymentLineEmpty', style: 'border-bottom: 1px solid #cccccc; padding: 20px; text-align: center; font-weight: bold; font-size: 30px; color: #cccccc', initComponents: function () { this.inherited(arguments); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo,_ */ enyo.kind({ name: 'OB.UI.RemoveMultiOrders', kind: 'OB.UI.SmallButton', classes: 'btnlink-darkgray btnlink-payment-clear btn-icon-small btn-icon-clearPayment', events: { onRemoveMultiOrders: '' }, tap: function () { var me = this; if ((_.isUndefined(this.deleting) || this.deleting === false)) { this.deleting = true; this.removeClass('btn-icon-clearPayment'); this.addClass('btn-icon-loading'); this.doRemoveMultiOrders({ order: this.owner.model }); } } }); enyo.kind({ kind: 'OB.UI.SelectButton', name: 'OB.UI.RenderMultiOrdersLineValues', classes: 'btnselect-orderline', handlers: { onChangeEditMode: 'changeEditMode' }, events: { onShowPopup: '' }, components: [{ name: 'line', style: 'line-height: 23px; width: 100%;', components: [{ style: 'display: inline;', name: 'multiTopLine', initComponents: function () { this.setContent(this.owner.owner.model.get('documentNo') + ' - ' + this.owner.owner.model.get('bp').get('_identifier')); } }, { style: 'font-weight: bold; color: lightblue; float: right; text-align:right; ', name: 'isLayaway', initComponents: function () { if (!_.isUndefined(this.owner.owner.model.get('amountToLayaway')) && !_.isNull(this.owner.owner.model.get('amountToLayaway'))) { this.setContent(OB.I18N.getLabel('OBPOS_ToBeLaidaway')); } } }, { style: 'color: #888888; display: inline-block;', name: 'multiBottonLine', initComponents: function () { this.setContent(this.owner.owner.model.printTotal() + ' - Remaining to pay: ' + this.owner.owner.model.printPending() + ' - (' + OB.I18N.formatDate(new Date(this.owner.owner.model.get('orderDate'))) + ') '); } }, { style: 'font-weight: bold; float: right; text-align:right; display: inline-block;', name: 'total', initComponents: function () { this.setContent((!_.isUndefined(this.owner.owner.model.get('amountToLayaway')) && !_.isNull(this.owner.owner.model.get('amountToLayaway'))) ? OB.I18N.formatCurrency(this.owner.owner.model.get('amountToLayaway')) : this.owner.owner.model.printPending()); } }, { style: 'clear: both;' }] }], tap: function () { if (OB.POS.modelterminal.hasPermission('OBPOS_receipt.layawayReceipt')) { this.doShowPopup({ popup: 'modalmultiorderslayaway', args: this.owner.model }); } }, changeEditMode: function (inSender, inEvent) { this.addRemoveClass('btnselect-orderline-edit', inEvent.edit); this.bubble('onShowColumn', { colNum: 1 }); } }); enyo.kind({ name: 'OB.UI.RenderMultiOrdersLine', style: 'border-bottom: 1px solid #cccccc; width: 100%', components: [{ style: 'display: inline; width: 8%', kind: 'OB.UI.RemoveMultiOrders' }, { style: 'display: inline; width: 88%; border: none; margin: 1px; padding-right: 6px;', kind: 'OB.UI.RenderMultiOrdersLineValues' }] }); enyo.kind({ name: 'OB.UI.RenderMultiOrdersLineEmpty', style: 'border-bottom: 1px solid #cccccc; padding: 20px; text-align: center; font-weight: bold; font-size: 30px; color: #cccccc', initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBPOS_ReceiptNew')); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _ */ enyo.kind({ name: 'OB.UI.OrderHeader', classes: 'row-fluid span12', published: { order: null }, style: 'border-bottom: 1px solid #cccccc;', components: [{ kind: 'OB.UI.OrderDetails', name: 'orderdetails' }, { components: [{ kind: 'OB.UI.BusinessPartner', name: 'bpbutton' }, { kind: 'OB.UI.BPLocation', name: 'bplocbutton' }] }], orderChanged: function (oldValue) { this.$.bpbutton.setOrder(this.order); this.$.bplocbutton.setOrder(this.order); this.$.orderdetails.setOrder(this.order); } }); enyo.kind({ name: 'OB.UI.TotalMultiReceiptLine', style: 'position: relative; padding: 10px;', components: [{ name: 'lblTotal', style: 'float: left; width: 40%;' }, { name: 'totalqty', style: 'float: left; width: 20%; text-align:right; font-weight:bold;' }, { name: 'totalgross', style: 'float: left; width: 40%; text-align:right; font-weight:bold;' }, { style: 'clear: both;' }], renderTotal: function (newTotal) { this.$.totalgross.setContent(OB.I18N.formatCurrency(newTotal)); }, renderQty: function (newQty) { this.$.totalqty.setContent(newQty); }, initComponents: function () { this.inherited(arguments); this.$.lblTotal.setContent(OB.I18N.getLabel('OBPOS_LblTotal')); } }); enyo.kind({ name: 'OB.UI.TotalReceiptLine', handlers: { onCheckBoxBehaviorForTicketLine: 'checkBoxForTicketLines' }, style: 'position: relative; padding: 10px;', components: [{ name: 'lblTotal', style: 'float: left; width: 40%;' }, { name: 'totalqty', style: 'float: left; width: 20%; text-align:right; font-weight:bold;' }, { name: 'totalgross', style: 'float: left; width: 40%; text-align:right; font-weight:bold;' }, { style: 'clear: both;' }], renderTotal: function (newTotal) { this.$.totalgross.setContent(OB.I18N.formatCurrency(newTotal)); }, renderQty: function (newQty) { this.$.totalqty.setContent(newQty); }, checkBoxForTicketLines: function (inSender, inEvent) { if (inEvent.status) { this.$.lblTotal.hasNode().style.width = '48%'; this.$.totalqty.hasNode().style.width = '16%'; this.$.totalgross.hasNode().style.width = '36%'; } else { this.$.lblTotal.hasNode().style.width = '40%'; this.$.totalqty.hasNode().style.width = '20%'; this.$.totalgross.hasNode().style.width = '40%'; } }, initComponents: function () { this.inherited(arguments); this.$.lblTotal.setContent(OB.I18N.getLabel('OBPOS_LblTotal')); } }); enyo.kind({ name: 'OB.UI.TotalTaxLine', style: 'position: relative; padding: 10px;', components: [{ name: 'lblTotalTax', style: 'float: left; width: 40%;' }, { name: 'totalbase', style: 'float: left; width: 20%; text-align:right; font-weight:bold;' }, { name: 'totaltax', style: 'float: left; width: 60%; text-align:right; font-weight:bold;' }, { style: 'clear: both;' }], renderTax: function (newTax) { this.$.totaltax.setContent(OB.I18N.formatCurrency(newTax)); }, renderBase: function (newBase) { //this.$.totalbase.setContent(newBase); }, initComponents: function () { this.inherited(arguments); this.$.lblTotalTax.setContent(OB.I18N.getLabel('OBPOS_LblTotalTax')); } }); enyo.kind({ name: 'OB.UI.TaxBreakdown', style: 'position: relative; padding: 10px;', components: [{ name: 'lblTotalTaxBreakdown', style: 'float: left; width: 40%;' }, { style: 'clear: both;' }], initComponents: function () { this.inherited(arguments); this.$.lblTotalTaxBreakdown.setContent(OB.I18N.getLabel('OBPOS_LblTaxBreakdown')); } }); enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.UI.BtnReceiptToInvoice', events: { onCancelReceiptToInvoice: '' }, style: 'width: 50px;', classes: 'btnlink-white btnlink-payment-clear btn-icon-small btn-icon-check', tap: function () { this.doCancelReceiptToInvoice(); } }); enyo.kind({ name: 'btninvoice', showing: false, style: 'float: left; width: 50%;', components: [{ kind: 'OB.UI.BtnReceiptToInvoice' }, { tag: 'span', content: ' ' }, { tag: 'span', name: 'lblInvoiceReceipt', style: 'font-weight:bold; ' }], initComponents: function () { this.inherited(arguments); this.$.lblInvoiceReceipt.setContent(OB.I18N.getLabel('OBPOS_LblInvoiceReceipt')); } }); enyo.kind({ name: 'OB.UI.OrderView', published: { order: null }, handlers: { onCheckBoxBehaviorForTicketLine: 'checkBoxBehavior', onAllTicketLinesChecked: 'allTicketLinesChecked' }, components: [{ kind: 'OB.UI.ScrollableTable', name: 'listOrderLines', columns: ['product', 'quantity', 'price', 'gross'], scrollAreaMaxHeight: '250px', renderLine: 'OB.UI.RenderOrderLine', renderEmpty: 'OB.UI.RenderOrderLineEmpty', //defined on redenderorderline.js listStyle: 'edit', isSelectableLine: function (model) { if (!OB.UTIL.isNullOrUndefined(model) && !OB.UTIL.isNullOrUndefined(model.attributes) && !OB.UTIL.isNullOrUndefined(model.attributes.originalOrderLineId)) { return false; } return true; } }, { tag: 'ul', classes: 'unstyled', components: [{ tag: 'li', components: [{ kind: 'OB.UI.TotalTaxLine', name: 'totalTaxLine' }, { kind: 'OB.UI.TotalReceiptLine', name: 'totalReceiptLine' }] }, { tag: 'li', components: [{ style: 'padding: 10px; border-top: 1px solid #cccccc; height: 40px;', components: [{ kind: 'btninvoice', name: 'divbtninvoice', showing: false }, { name: 'divText', style: 'float: right; text-align: right; font-weight:bold; font-size: 30px;', showing: false, content: '' }, { style: 'clear: both;' }] }] }, { tag: 'li', components: [{ style: 'padding: 10px; border-top: 1px solid #cccccc; height: 40px;', components: [{ kind: 'OB.UI.TaxBreakdown', name: 'taxBreakdown' }] }] }, { kind: 'OB.UI.ScrollableTable', name: 'listTaxLines', scrollAreaMaxHeight: '250px', renderLine: 'OB.UI.RenderTaxLine', renderEmpty: 'OB.UI.RenderTaxLineEmpty', //defined on redenderorderline.js listStyle: 'nonselectablelist', columns: ['tax', 'base', 'totaltax'] }, { tag: 'li', components: [{ name: 'paymentBreakdown', style: 'padding: 10px; height: 40px;', showing: false, components: [{ style: 'position: relative; padding: 10px;', components: [{ name: 'lblTotalPayment', style: 'float: left; width: 40%;' }, { style: 'clear: both;' }] }] }] }, { kind: 'OB.UI.ScrollableTable', style: 'border-bottom: 1px solid #cccccc;', name: 'listPaymentLines', showing: false, scrollAreaMaxHeight: '250px', renderLine: 'OB.UI.RenderPaymentLine', renderEmpty: 'OB.UI.RenderPaymentLineEmpty', //defined on redenderorderline.js listStyle: 'nonselectablelist' }] }], initComponents: function () { this.inherited(arguments); this.$.lblTotalPayment.setContent(OB.I18N.getLabel('OBPOS_LblPaymentBreakdown')); }, checkBoxBehavior: function (inSender, inEvent) { if (inEvent.status) { this.$.listOrderLines.setListStyle('checkboxlist'); } else { this.$.listOrderLines.setListStyle('edit'); } }, allTicketLinesChecked: function (inSender, inEvent) { if (inEvent.status) { this.order.get('lines').trigger('checkAll'); } else { this.order.get('lines').trigger('unCheckAll'); } }, setTaxes: function () { var taxList = new Backbone.Collection(); var taxes = this.order.get('taxes'); var empty = true, prop; for (prop in taxes) { if (taxes.hasOwnProperty(prop)) { taxList.add(new OB.Model.TaxLine(taxes[prop])); empty = false; } } if (empty) { this.$.taxBreakdown.hide(); } else { this.$.taxBreakdown.show(); } taxList.models = _.sortBy(taxList.models, function (taxLine) { return taxLine.get('name'); }); this.$.listTaxLines.setCollection(taxList); }, orderChanged: function (oldValue) { this.$.totalReceiptLine.renderTotal(this.order.getTotal()); this.$.totalReceiptLine.renderQty(this.order.getQty()); this.$.totalTaxLine.renderTax(OB.DEC.sub(this.order.getTotal(), this.order.getNet())); this.$.totalTaxLine.renderBase(''); this.$.listOrderLines.setCollection(this.order.get('lines')); this.$.listPaymentLines.setCollection(this.order.get('payments')); this.setTaxes(); this.order.on('change:gross change:net change:taxes', function (model) { if (model.get('orderType') !== 3) { this.$.totalReceiptLine.renderTotal(model.getTotal()); this.$.totalTaxLine.renderTax(OB.DEC.sub(model.getTotal(), model.getNet())); this.setTaxes(); } }, this); this.order.on('change:priceIncludesTax ', function (model) { if (this.order.get('priceIncludesTax')) { this.$.totalTaxLine.hide(); } else { this.$.totalTaxLine.show(); } }, this); this.order.on('change:qty', function (model) { this.$.totalReceiptLine.renderQty(model.getQty()); }, this); this.order.on('change:orderType', function (model) { if (model.get('orderType') === 1) { this.$.divText.addStyles('width: 50%; color: #f8941d;'); this.$.divText.setContent(OB.I18N.getLabel('OBPOS_ToBeReturned')); this.$.divText.show(); } else if (model.get('orderType') === 2) { this.$.divText.addStyles('width: 50%; color: lightblue;'); this.$.divText.setContent(OB.I18N.getLabel('OBPOS_ToBeLaidaway')); this.$.divText.show(); //We have to ensure that there is not another handler showing this div } else if (model.get('orderType') === 3) { this.$.divText.addStyles('width: 50%; color: lightblue;'); this.$.divText.setContent(OB.I18N.getLabel('OBPOS_VoidLayaway')); this.$.divText.show(); //We have to ensure that there is not another handler showing this div } else if (model.get('isLayaway')) { this.$.divText.addStyles('width: 50%; color: lightblue;'); this.$.divText.setContent(OB.I18N.getLabel('OBPOS_LblLayaway')); this.$.divText.show(); //We have to ensure that there is not another handler showing this div } else if (this.$.divText.content === OB.I18N.getLabel('OBPOS_ToBeReturned') || this.$.divText.content === OB.I18N.getLabel('OBPOS_ToBeLaidaway') || this.$.divText.content === OB.I18N.getLabel('OBPOS_VoidLayaway')) { this.$.divText.hide(); } }, this); this.order.on('change:generateInvoice', function (model) { if (model.get('generateInvoice')) { this.$.divbtninvoice.show(); } else { this.$.divbtninvoice.hide(); } }, this); this.order.on('change:isQuotation', function (model) { if (model.get('isQuotation')) { this.$.divText.addStyles('width: 100%; color: #f8941d;'); this.$.listOrderLines.children[4].children[0].setContent(OB.I18N.getLabel('OBPOS_QuotationNew')); if (model.get('hasbeenpaid') === 'Y') { this.$.divText.setContent(OB.I18N.getLabel('OBPOS_QuotationUnderEvaluation')); } else { this.$.divText.setContent(OB.I18N.getLabel('OBPOS_QuotationDraft')); } this.$.divText.show(); } else { this.$.listOrderLines.children[4].children[0].setContent(OB.I18N.getLabel('OBPOS_ReceiptNew')); // We have to ensure that there is not another handler showing this div if (this.$.divText.content === OB.I18N.getLabel('OBPOS_QuotationUnderEvaluation') || this.$.divText.content === OB.I18N.getLabel('OBPOS_QuotationDraft')) { this.$.divText.hide(); } } }, this); this.order.on('change:hasbeenpaid', function (model) { if (model.get('isQuotation') && model.get('hasbeenpaid') === 'Y' && this.$.divText.content && (this.$.divText.content === OB.I18N.getLabel('OBPOS_QuotationNew') || this.$.divText.content === OB.I18N.getLabel('OBPOS_QuotationDraft'))) { this.$.divText.setContent(OB.I18N.getLabel('OBPOS_QuotationUnderEvaluation')); } else if (model.get('isQuotation') && model.get('hasbeenpaid') === 'N' && !model.get('isLayaway')) { this.$.divText.setContent(OB.I18N.getLabel('OBPOS_QuotationDraft')); } }, this); this.order.on('change:isPaid change:paidOnCredit change:isQuotation', function (model) { if (model.get('isPaid') === true && !model.get('isQuotation')) { this.$.divText.addStyles('width: 50%; color: #f8941d;'); if (model.get('paidOnCredit')) { this.$.divText.setContent(OB.I18N.getLabel('OBPOS_paidOnCredit')); } else if (model.get('documentType') === OB.POS.modelterminal.get('terminal').terminalType.documentTypeForReturns) { this.$.divText.setContent(OB.I18N.getLabel('OBPOS_paidReturn')); } else { this.$.divText.setContent(OB.I18N.getLabel('OBPOS_paid')); } this.$.divText.show(); this.$.listPaymentLines.show(); this.$.paymentBreakdown.show(); //We have to ensure that there is not another handler showing this div } else if (this.$.divText.content === OB.I18N.getLabel('OBPOS_paid') || this.$.divText.content === OB.I18N.getLabel('OBPOS_paidReturn') || this.$.divText.content === OB.I18N.getLabel('OBPOS_paidOnCredit')) { this.$.divText.hide(); this.$.listPaymentLines.hide(); this.$.paymentBreakdown.hide(); } }, this); this.order.on('change:isLayaway', function (model) { if (model.get('isLayaway') === true) { this.$.divText.addStyles('width: 50%; color: lightblue;'); this.$.divText.setContent(OB.I18N.getLabel('OBPOS_LblLayaway')); this.$.divText.show(); this.$.listPaymentLines.show(); this.$.paymentBreakdown.show(); //We have to ensure that there is not another handler showing this div } else if (this.$.divText.content === OB.I18N.getLabel('OBPOS_LblLayaway')) { this.$.divText.hide(); this.$.listPaymentLines.hide(); this.$.paymentBreakdown.hide(); } }, this); } }); enyo.kind({ name: 'OB.UI.MultiOrderView', published: { order: null }, events: { onChangeTotal: '' }, components: [{ kind: 'OB.UI.ScrollableTable', name: 'listMultiOrderLines', scrollAreaMaxHeight: '450px', renderLine: 'OB.UI.RenderMultiOrdersLine', renderEmpty: 'OB.UI.RenderMultiOrdersLineEmpty', //defined on redenderorderline.js listStyle: 'edit' }, { tag: 'ul', classes: 'unstyled', components: [{ tag: 'li', components: [{ kind: 'OB.UI.TotalMultiReceiptLine', name: 'totalMultiReceiptLine' }] }, { tag: 'li', components: [{ style: 'padding: 10px; border-top: 1px solid #cccccc; height: 40px;', components: [{ kind: 'btninvoice', name: 'multiOrder_btninvoice', showing: false }, { style: 'clear: both;' }] }] }] }], listMultiOrders: null, init: function (model) { this.model = model; var me = this; this.total = 0; this.listMultiOrders = new Backbone.Collection(); this.$.listMultiOrderLines.setCollection(this.listMultiOrders); this.model.get('multiOrders').on('change:additionalInfo', function (changedModel) { if (changedModel.get('additionalInfo') === 'I') { this.$.multiOrder_btninvoice.show(); return; } this.$.multiOrder_btninvoice.hide(); }, this); this.model.get('multiOrders').get('multiOrdersList').on('reset add remove change', function () { me.total = _.reduce(me.model.get('multiOrders').get('multiOrdersList').models, function (memo, order) { return memo + ((!_.isUndefined(order.get('amountToLayaway')) && !_.isNull(order.get('amountToLayaway'))) ? order.get('amountToLayaway') : order.getPending()); }, 0); this.model.get('multiOrders').set('total', this.total); this.model.get('multiOrders').on('change:total', function (model) { this.doChangeTotal({ newTotal: model.get('total') }); }, this); this.$.totalMultiReceiptLine.renderTotal(this.total); me.listMultiOrders.reset(me.model.get('multiOrders').get('multiOrdersList').models); if (this.model.get('leftColumnViewManager').isMultiOrder()) { this.doChangeTotal({ newTotal: this.total }); } this.$.totalMultiReceiptLine.renderQty(me.model.get('multiOrders').get('multiOrdersList').length); }, this); }, initComponents: function () { this.inherited(arguments); } }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.UI.OrderDetails', published: { order: null }, attributes: { style: 'padding: 13px 50px 15px 10px; font-weight: bold; color: #6CB33F;' }, initComponents: function () {}, renderData: function (docNo) { var content, me = this; if (this.order.get('orderDate') instanceof Date) { content = OB.I18N.formatHour(this.order.get('orderDate')) + ' - ' + docNo; } else { content = this.order.get('orderDate') + ' - ' + docNo; } OB.UTIL.HookManager.executeHooks('OBPOS_OrderDetailContentHook', { content: content, docNo: docNo, order: me.order }, function (args) { me.setContent(args.content); }); }, orderChanged: function (oldValue) { this.renderData(this.order.get('documentNo')); this.order.on('change:documentNo', function (model) { this.renderData(model.get('documentNo')); }, this); } }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, OB */ enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.UI.BusinessPartner', classes: 'btnlink btnlink-small btnlink-gray', style: 'float: left; text-overflow:ellipsis; white-space: nowrap; overflow: hidden;', published: { order: null }, events: { onShowPopup: '' }, handlers: { onBPSelectionDisabled: 'buttonDisabled' }, buttonDisabled: function (inSender, inEvent) { this.setDisabled(inEvent.status); }, tap: function () { if (!this.disabled) { this.doShowPopup({ popup: 'modalcustomer' }); } }, initComponents: function () {}, renderCustomer: function (newCustomer) { this.setContent(newCustomer); }, orderChanged: function (oldValue) { if (this.order.get('bp')) { this.renderCustomer(this.order.get('bp').get('_identifier')); } else { this.renderCustomer(''); } this.order.on('change:bp', function (model) { if (model.get('bp')) { this.renderCustomer(model.get('bp').get('_identifier')); } else { this.renderCustomer(''); } }, this); } }); /*Modal*/ /*header of scrollable table*/ enyo.kind({ kind: 'OB.UI.Button', name: 'OB.UI.NewCustomerWindowButton', events: { onChangeSubWindow: '', onHideThisPopup: '' }, disabled: false, style: 'width: 170px; margin: 0px 5px 8px 19px;', classes: 'btnlink-yellow btnlink btnlink-small', i18nLabel: 'OBPOS_LblNewCustomer', handlers: { onSetModel: 'setModel', onNewBPDisabled: 'doDisableNewBP' }, setModel: function (inSender, inEvent) { this.model = inEvent.model; }, doDisableNewBP: function (inSender, inEvent) { this.putDisabled(inEvent.status); }, tap: function (model) { if (this.disabled) { return true; } this.doHideThisPopup(); this.doChangeSubWindow({ newWindow: { name: 'customerCreateAndEdit', params: { navigateOnClose: 'mainSubWindow' } } }); }, putDisabled: function (status) { if (status === false) { this.disabled = false; this.setDisabled(false); this.removeClass('disabled'); return; } else { this.disabled = true; this.setDisabled(); this.addClass('disabled'); } } }); enyo.kind({ kind: 'OB.UI.Button', name: 'OB.UI.AdvancedSearchCustomerWindowButton', style: 'margin: 0px 0px 8px 5px;', classes: 'btnlink-yellow btnlink btnlink-small', i18nLabel: 'OBPOS_LblAdvancedSearch', disabled: false, handlers: { onSetModel: 'setModel', onNewBPDisabled: 'doDisableNewBP' }, setModel: function (inSender, inEvent) { this.model = inEvent.model; }, doDisableNewBP: function (inSender, inEvent) { this.putDisabled(inEvent.status); }, events: { onHideThisPopup: '' }, tap: function () { if (this.disabled) { return true; } this.doHideThisPopup(); this.model.get('subWindowManager').set('currentWindow', { name: 'customerAdvancedSearch', params: { caller: 'mainSubWindow' } }); }, putDisabled: function (status) { if (status === false) { this.disabled = false; this.setDisabled(false); this.removeClass('disabled'); return; } else { this.disabled = true; this.setDisabled(); this.addClass('disabled'); } }, initComponents: function () { this.inherited(arguments); this.putDisabled(!OB.MobileApp.model.hasPermission('OBPOS_receipt.customers')); } }); enyo.kind({ name: 'OB.UI.ModalBpScrollableHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onSearchAction: '', onClearAction: '' }, handlers: { onSearchActionByKey: 'searchAction', onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'filterText', style: 'width: 100%' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }] }, { style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell;', components: [{ kind: 'OB.UI.NewCustomerWindowButton', name: 'newAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.AdvancedSearchCustomerWindowButton' }] }] }] }], clearAction: function () { this.$.filterText.setValue(''); this.doClearAction(); }, searchAction: function () { this.doSearchAction({ bpName: this.$.filterText.getValue() }); return true; } }); /*items of collection*/ enyo.kind({ name: 'OB.UI.ListBpsLine', kind: 'OB.UI.SelectButton', components: [{ name: 'line', style: 'line-height: 23px;', components: [{ name: 'identifier' }, { style: 'color: #888888', name: 'address' }, { style: 'clear: both;' }] }], events: { onHideThisPopup: '' }, tap: function () { this.inherited(arguments); this.doHideThisPopup(); }, create: function () { this.inherited(arguments); this.$.identifier.setContent(this.model.get('_identifier')); this.$.address.setContent(this.model.get('locName')); } }); /*scrollable table (body of modal)*/ enyo.kind({ name: 'OB.UI.ListBps', classes: 'row-fluid', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, events: { onChangeBusinessPartner: '' }, components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;', classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'stBPAssignToReceipt', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderHeader: 'OB.UI.ModalBpScrollableHeader', renderLine: 'OB.UI.ListBpsLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }], clearAction: function (inSender, inEvent) { this.bpsList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, filter = inEvent.bpName; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackBPs(dataBps) { if (dataBps && dataBps.length > 0) { me.bpsList.reset(dataBps.models); } else { me.bpsList.reset(); } } var criteria = {}; if (filter && filter !== '') { criteria._filter = { operator: OB.Dal.CONTAINS, value: filter }; } OB.Dal.find(OB.Model.BusinessPartner, criteria, successCallbackBPs, errorCallback); return true; }, bpsList: null, init: function (model) { this.bpsList = new Backbone.Collection(); this.$.stBPAssignToReceipt.setCollection(this.bpsList); this.bpsList.on('click', function (model) { this.doChangeBusinessPartner({ businessPartner: model }); }, this); } }); /*Modal definiton*/ enyo.kind({ name: 'OB.UI.ModalBusinessPartners', topPosition: '125px', kind: 'OB.UI.Modal', executeOnShow: function () { this.$.body.$.listBps.$.stBPAssignToReceipt.$.theader.$.modalBpScrollableHeader.$.newAction.putDisabled(!OB.MobileApp.model.hasPermission('OBPOS_retail.editCustomers')); return true; }, executeOnHide: function () { this.$.body.$.listBps.$.stBPAssignToReceipt.$.theader.$.modalBpScrollableHeader.clearAction(); }, i18nHeader: 'OBPOS_LblAssignCustomer', body: { kind: 'OB.UI.ListBps' }, init: function (model) { this.model = model; this.waterfall('onSetModel', { model: this.model }); } }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global enyo, Backbone */ enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.UI.BPLocation', classes: 'btnlink btnlink-small btnlink-gray', style: 'float: right; text-overflow:ellipsis; white-space: nowrap; overflow: hidden;', published: { order: null }, events: { onShowPopup: '' }, handlers: { onBPLocSelectionDisabled: 'buttonDisabled' }, buttonDisabled: function (inSender, inEvent) { this.setDisabled(inEvent.status); }, tap: function () { if (!this.disabled) { this.doShowPopup({ popup: 'modalcustomeraddress' }); } }, initComponents: function () {}, renderBPLocation: function (newLocation) { this.setContent(newLocation); }, orderChanged: function (oldValue) { if (this.order.get('bp')) { this.renderBPLocation(this.order.get('bp').get('locName')); } else { this.renderBPLocation(''); } this.order.on('change:bp', function (model) { if (model.get('bp')) { this.renderBPLocation(model.get('bp').get('locName')); } else { this.renderBPLocation(''); } }, this); } }); enyo.kind({ kind: 'OB.UI.Button', name: 'OB.UI.NewCustomerAddressWindowButton', events: { onChangeSubWindow: '', onHideThisPopup: '' }, disabled: false, style: 'width: 170px; margin: 0px 5px 8px 19px;', classes: 'btnlink-yellow btnlink btnlink-small', i18nLabel: 'OBPOS_LblNewCustomerAddress', handlers: { onSetModel: 'setModel', onNewBPLocDisabled: 'doDisableNewBPLoc' }, setModel: function (inSender, inEvent) { this.model = inEvent.model; }, doDisableNewBPLoc: function (inSender, inEvent) { this.putDisabled(inEvent.status); }, tap: function (model) { if (this.disabled) { return true; } this.doHideThisPopup(); var me = this; function errorCallback(tx, error) { OB.error(tx); OB.error(error); } function successCallbackBPs(dataBps) { me.doChangeSubWindow({ newWindow: { name: 'customerAddrCreateAndEdit', params: { navigateOnClose: 'mainSubWindow', businessPartner: dataBps } } }); } OB.Dal.get(OB.Model.BusinessPartner, this.model.get('order').get('bp').get('id'), successCallbackBPs, errorCallback); }, putDisabled: function (status) { if (status === false) { this.disabled = false; this.setDisabled(false); this.removeClass('disabled'); return; } else { this.disabled = true; this.setDisabled(); this.addClass('disabled'); } } }); enyo.kind({ kind: 'OB.UI.Button', name: 'OB.UI.SearchCustomerAddressWindowButton', style: 'width: 170px; margin: 0px 0px 8px 5px;', classes: 'btnlink-yellow btnlink btnlink-small', i18nLabel: 'OBPOS_LblEditAddress', disabled: false, handlers: { onSetModel: 'setModel', onNewBPLocDisabled: 'doDisableNewBPLoc' }, doDisableNewBPLoc: function (inSender, inEvent) { this.putDisabled(inEvent.status); }, setModel: function (inSender, inEvent) { this.model = inEvent.model; }, events: { onHideThisPopup: '' }, tap: function () { if (this.disabled) { return true; } this.doHideThisPopup(); this.model.get('subWindowManager').set('currentWindow', { name: 'customerAddressSearch', params: { caller: 'mainSubWindow', bPartner: this.model.get('order').get('bp').get('id') } }); }, putDisabled: function (status) { if (status === false) { this.disabled = false; this.setDisabled(false); this.removeClass('disabled'); return; } else { this.disabled = true; this.setDisabled(); this.addClass('disabled'); } }, initComponents: function () { this.inherited(arguments); this.putDisabled(!OB.MobileApp.model.hasPermission('OBPOS_receipt.customers')); } }); enyo.kind({ name: 'OB.UI.ModalBpLocScrollableHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onSearchAction: '', onClearAction: '' }, handlers: { onSearchActionByKey: 'searchAction', onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'filterText', style: 'width: 100%' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }] }, { style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell;', components: [{ kind: 'OB.UI.NewCustomerAddressWindowButton', name: 'newAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SearchCustomerAddressWindowButton' }] }] }] }], clearAction: function () { this.$.filterText.setValue(''); this.doSearchAction({ locName: this.$.filterText.getValue() }); return true; }, searchAction: function () { this.doSearchAction({ locName: this.$.filterText.getValue() }); return true; } }); /*items of collection*/ enyo.kind({ name: 'OB.UI.ListBpsLocLine', kind: 'OB.UI.SelectButton', components: [{ name: 'line', style: 'line-height: 30px;', components: [{ name: 'identifier' }, { style: 'clear: both;' }] }], events: { onHideThisPopup: '' }, tap: function () { this.inherited(arguments); this.doHideThisPopup(); }, create: function () { this.inherited(arguments); this.$.identifier.setContent(this.model.get('name')); } }); /*scrollable table (body of modal)*/ enyo.kind({ name: 'OB.UI.ListBpsLoc', classes: 'row-fluid', published: { bPartnerId: null }, handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, events: { onChangeBusinessPartner: '' }, components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;', classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'bpsloclistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderHeader: 'OB.UI.ModalBpLocScrollableHeader', renderLine: 'OB.UI.ListBpsLocLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }], clearAction: function (inSender, inEvent) { this.bpsList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, criteria = {}, filter = inEvent.locName; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackBPsLoc(dataBps) { if (dataBps && dataBps.length > 0) { me.bpsList.reset(dataBps.models); } else { me.bpsList.reset(); } } criteria.name = { operator: OB.Dal.CONTAINS, value: filter }; criteria.bpartner = this.bPartnerId; OB.Dal.find(OB.Model.BPLocation, criteria, successCallbackBPsLoc, errorCallback); return true; }, bpsList: null, init: function (model) { this.bpsList = new Backbone.Collection(); this.$.bpsloclistitemprinter.setCollection(this.bpsList); this.bpsList.on('click', function (model) { var me = this; function errorCallback(tx, error) { OB.error(tx); OB.error(error); } function successCallbackBPs(dataBps) { dataBps.set('locId', model.get('id')); dataBps.set('locName', model.get('name')); me.doChangeBusinessPartner({ businessPartner: dataBps }); } OB.Dal.get(OB.Model.BusinessPartner, this.bPartnerId, successCallbackBPs, errorCallback); }, this); } }); /*Modal definiton*/ enyo.kind({ name: 'OB.UI.ModalBPLocation', topPosition: '125px', kind: 'OB.UI.Modal', executeOnShow: function () { this.$.body.$.listBpsLoc.setBPartnerId(this.model.get('order').get('bp').get('id')); this.$.body.$.listBpsLoc.$.bpsloclistitemprinter.$.theader.$.modalBpLocScrollableHeader.searchAction(); this.$.body.$.listBpsLoc.$.bpsloclistitemprinter.$.theader.$.modalBpLocScrollableHeader.$.newAction.putDisabled(!OB.MobileApp.model.hasPermission('OBPOS_retail.editCustomers')); return true; }, executeOnHide: function () { this.$.body.$.listBpsLoc.$.bpsloclistitemprinter.$.theader.$.modalBpLocScrollableHeader.clearAction(); }, i18nHeader: 'OBPOS_LblAssignCustomerAddress', body: { kind: 'OB.UI.ListBpsLoc' }, init: function (model) { this.model = model; this.waterfall('onSetModel', { model: this.model }); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _ */ enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.UI.SalesRepresentative', classes: 'btnlink btnlink-small btnlink-gray', style: 'float:left; margin:7px; height:27px; padding: 4px 15px 7px 15px;', published: { order: null }, events: { onShowPopup: '' }, tap: function () { if (!this.disabled) { this.doShowPopup({ popup: 'modalsalesrepresentative' }); } }, init: function (model) { if (!OB.POS.modelterminal.hasPermission(this.permission)) { this.parent.parent.parent.hide(); } else { if (!OB.POS.modelterminal.hasPermission(this.permissionOption)) { this.parent.parent.parent.hide(); } } this.setOrder(model.get('order')); }, renderSalesRepresentative: function (newSalesRepresentative) { this.setContent(newSalesRepresentative); }, orderChanged: function (oldValue) { if (this.order.get('salesRepresentative')) { this.renderSalesRepresentative(this.order.get('salesRepresentative')); } else { this.renderSalesRepresentative(''); } this.order.on('change:salesRepresentative$_identifier change:salesRepresentative', function (model) { if (!_.isUndefined(model.get('salesRepresentative$_identifier')) && !_.isNull(model.get('salesRepresentative$_identifier'))) { this.renderSalesRepresentative(model.get('salesRepresentative$_identifier')); } else { this.renderSalesRepresentative(''); } }, this); } }); /*Modal*/ enyo.kind({ name: 'OB.UI.ModalSrScrollableHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onSearchAction: '', onClearAction: '' }, handlers: { onSearchActionByKey: 'searchAction', onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'filterText', style: 'width: 100%' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }] }], clearAction: function () { this.$.filterText.setValue(''); this.doClearAction(); }, searchAction: function () { this.doSearchAction({ srName: this.$.filterText.getValue() }); return true; } }); /*items of collection*/ enyo.kind({ name: 'OB.UI.ListSrsLine', kind: 'OB.UI.SelectButton', components: [{ name: 'line', style: 'line-height: 23px;', components: [{ name: 'name' }, { style: 'clear: both;' }] }], events: { onHideThisPopup: '' }, tap: function () { this.inherited(arguments); this.doHideThisPopup(); }, create: function () { this.inherited(arguments); this.$.name.setContent(this.model.get('name')); } }); /*scrollable table (body of modal)*/ enyo.kind({ name: 'OB.UI.ListSrs', classes: 'row-fluid', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, events: { onChangeSalesRepresentative: '' }, components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;', classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'srslistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderHeader: 'OB.UI.ModalSrScrollableHeader', renderLine: 'OB.UI.ListSrsLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }], clearAction: function (inSender, inEvent) { this.srsList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, filter = inEvent.srName; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackBPs(dataSrs) { if (dataSrs && dataSrs.length > 0) { me.srsList.reset(dataSrs.models); } else { me.srsList.reset(); } } var criteria = {}; if (filter && filter !== '') { criteria._identifier = { operator: OB.Dal.CONTAINS, value: filter }; } OB.Dal.find(OB.Model.SalesRepresentative, criteria, successCallbackBPs, errorCallback); return true; }, srsList: null, init: function (model) { this.srsList = new Backbone.Collection(); this.$.srslistitemprinter.setCollection(this.srsList); this.srsList.on('click', function (model) { this.doChangeSalesRepresentative({ salesRepresentative: model }); }, this); } }); /*Modal definiton*/ enyo.kind({ name: 'OB.UI.ModalSalesRepresentative', topPosition: '125px', kind: 'OB.UI.Modal', executeOnHide: function () { this.$.body.$.listSrs.$.srslistitemprinter.$.theader.$.modalSrScrollableHeader.clearAction(); }, i18nHeader: 'OBPOS_LblAssignSalesRepresentative', body: { kind: 'OB.UI.ListSrs' }, init: function (model) { this.model = model; this.waterfall('onSetModel', { model: this.model }); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.UI.ReceiptsCounter', style: 'position: absolute; top:0px; right: 0px;', showing: false, published: { orderList: null }, components: [{ kind: 'OB.UI.ReceiptsCounterButton', name: 'receiptsCounterButton' }], events: { onSetReceiptsList: '' }, renderNrItems: function (nrItems) { if (nrItems > 1) { this.$.receiptsCounterButton.$.counter.setContent(nrItems - 1); this.show(); } else { this.$.receiptsCounterButton.$.counter.setContent(''); this.hide(); } }, orderListChanged: function (oldValue) { var me = this; this.doSetReceiptsList({ orderList: this.orderList }); this.renderNrItems(this.orderList.length); this.orderList.on('add remove reset', function () { me.renderNrItems(me.orderList.length); }, this); }, initComponents: function () { this.inherited(arguments); } }); enyo.kind({ name: 'OB.UI.ReceiptsCounterButton', kind: 'OB.UI.Button', classes: 'btnlink btnlink-gray', style: 'position: relative; overflow: hidden; margin:0px; padding:0px; height:50px; width: 50px;', events: { onShowPopup: '' }, handlers: { onOrderSelectionDisabled: 'orderDisabled' }, orderDisabled: function (inSender, inEvent) { this.setDisabled(inEvent.status); this.addRemoveClass('disabled', inEvent.status); }, tap: function () { if (!this.disabled) { this.doShowPopup({ popup: 'modalreceipts' }); } }, components: [{ style: 'position: absolute; top: -35px; right:-35px; background: #404040; height:70px; width: 70px; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -ms-transform: rotate(45deg); -transform: rotate(45deg);' }, { name: 'counter', style: 'position: absolute; top: 0px; right:0px; padding-top: 5px; padding-right: 10px; font-weight: bold; color: white;' }] }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ enyo.kind({ name: 'OB.UI.MenuReturn', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.return', events: { onShowDivText: '' }, i18nLabel: 'OBPOS_LblReturn', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure this.doShowDivText({ permission: this.permission, orderType: 1 }); if (OB.MobileApp.model.get('lastPaneShown') === 'payment') { this.model.get('order').trigger('scan'); } }, displayLogic: function () { var negativeLines = _.filter(this.model.get('order').get('lines').models, function (line) { return line.get('qty') < 0; }).length; if (!this.model.get('order').get('isQuotation')) { this.show(); } else { this.hide(); return; } if (negativeLines > 0) { this.hide(); return; } if (this.model.get('order').get('isEditable') === false) { this.setShowing(false); return; } this.adjustVisibilityBasedOnPermissions(); }, init: function (model) { this.model = model; var receipt = model.get('order'), me = this; receipt.on('change:isEditable change:isQuotation change:gross', function (changedModel) { this.displayLogic(); }, this); this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { if (changedModel.isOrder()) { this.displayLogic(); return; } if (changedModel.isMultiOrder()) { this.setShowing(false); return; } }, this); } }); enyo.kind({ name: 'OB.UI.MenuVoidLayaway', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.voidLayaway', events: { onShowDivText: '', onTabChange: '' }, i18nLabel: 'OBPOS_VoidLayaway', tap: function () { var voidAllowed = true, notValid = {}; if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure // check if this order has been voided previously if (this.model.get('order').get('orderType') === 3) { return; } enyo.forEach(this.model.get('order').get('payments').models, function (curPayment) { if (_.isUndefined(curPayment.get('isPrePayment')) || _.isNull(curPayment.get('isPrePayment'))) { voidAllowed = false; notValid = curPayment; return; } }, this); if (voidAllowed) { this.doShowDivText({ permission: this.permission, orderType: 3 }); this.doTabChange({ tabPanel: 'payment', keyboard: 'toolbarpayment', edit: false }); } else { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_lblPaymentNotProcessedHeader'), OB.I18N.getLabel('OBPOS_lblPaymentNotProcessedMessage', [notValid.get('name'), notValid.get('origAmount'), OB.MobileApp.model.paymentnames[notValid.get('kind')].isocode])); } }, displayLogic: function () { if (this.model.get('order').get('isLayaway')) { this.show(); this.adjustVisibilityBasedOnPermissions(); } else { this.hide(); } }, init: function (model) { this.model = model; var receipt = model.get('order'), me = this; this.setShowing(false); receipt.on('change:isLayaway', function (model) { this.displayLogic(); }, this); this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { if (changedModel.isOrder()) { this.displayLogic(); return; } if (changedModel.isMultiOrder()) { this.setShowing(false); return; } }, this); } }); enyo.kind({ name: 'OB.UI.MenuLayaway', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.layawayReceipt', events: { onShowDivText: '' }, i18nLabel: 'OBPOS_LblLayawayReceipt', tap: function () { var negativeLines; if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure negativeLines = _.find(this.model.get('order').get('lines').models, function (line) { return line.get('qty') < 0; }); if (negativeLines) { OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_layawaysOrdersWithReturnsNotAllowed')); return true; } this.doShowDivText({ permission: this.permission, orderType: 2 }); }, updateVisibility: function (isVisible) { if (!OB.POS.modelterminal.hasPermission(this.permission)) { this.hide(); return; } if (!isVisible) { this.hide(); return; } this.show(); }, init: function (model) { this.model = model; var receipt = model.get('order'), me = this; receipt.on('change:isQuotation', function (model) { if (!model.get('isQuotation')) { me.updateVisibility(true); } else { me.updateVisibility(false); } }, this); receipt.on('change:isEditable', function (newValue) { if (newValue) { if (newValue.get('isEditable') === false) { me.updateVisibility(false); return; } } me.updateVisibility(true); }, this); this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { if (changedModel.isOrder()) { if (model.get('order').get('isEditable') && !this.model.get('order').get('isQuotation')) { me.updateVisibility(true); } else { me.updateVisibility(false); } return; } if (changedModel.isMultiOrder()) { me.updateVisibility(false); } }, this); } }); enyo.kind({ name: 'OB.UI.MenuProperties', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.properties', events: { onShowReceiptProperties: '' }, i18nLabel: 'OBPOS_LblProperties', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure this.doShowReceiptProperties(); }, init: function (model) { this.model = model; this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { if (changedModel.isOrder()) { if (model.get('order').get('isEditable')) { this.setDisabled(false); this.adjustVisibilityBasedOnPermissions(); } else { this.setDisabled(true); } return; } if (changedModel.isMultiOrder()) { this.setDisabled(true); } }, this); this.model.get('order').on('change:isEditable', function (newValue) { if (newValue) { if (newValue.get('isEditable') === false) { this.setShowing(false); return; } } this.setShowing(true); }, this); } }); enyo.kind({ name: 'OB.UI.MenuInvoice', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.invoice', events: { onReceiptToInvoice: '', onCancelReceiptToInvoice: '' }, i18nLabel: 'OBPOS_LblInvoice', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure this.taxIdValidation(this.model.get('order')); }, taxIdValidation: function (model) { if (!OB.POS.modelterminal.hasPermission('OBPOS_receipt.invoice')) { this.doCancelReceiptToInvoice(); } else if (OB.POS.modelterminal.hasPermission('OBPOS_retail.restricttaxidinvoice') && !model.get('bp').get('taxID')) { OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_BP_No_Taxid')); this.doCancelReceiptToInvoice(); } else { this.doReceiptToInvoice(); } }, init: function (model) { this.model = model; var receipt = model.get('order'), me = this; receipt.on('change:isQuotation change:isLayaway', function (model) { if (!model.get('isQuotation') || model.get('isLayaway')) { me.show(); } else { me.hide(); } }, this); receipt.on('change:bp', function (model) { if (model.get('generateInvoice')) { me.taxIdValidation(model); } }, this); receipt.on('change:isEditable', function (newValue) { if (newValue) { if (newValue.get('isEditable') === false && !newValue.get('isLayaway')) { this.setShowing(false); return; } } this.setShowing(true); }, this); } }); enyo.kind({ name: 'OB.UI.MenuOpenDrawer', kind: 'OB.UI.MenuAction', permission: 'OBPOS_retail.opendrawerfrommenu', i18nLabel: 'OBPOS_LblOpenDrawer', init: function (model) { this.model = model; }, tap: function () { var me = this; if (this.disabled) { return true; } OB.UTIL.Approval.requestApproval( me.model, 'OBPOS_approval.opendrawer.menu', function (approved, supervisor, approvalType) { if (approved) { OB.POS.hwserver.openDrawer({ openFirst: true }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); } }); this.inherited(arguments); } }); enyo.kind({ name: 'OB.UI.MenuCustomers', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.customers', events: { onChangeSubWindow: '' }, i18nLabel: 'OBPOS_LblCustomers', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure this.doChangeSubWindow({ newWindow: { name: 'customerAdvancedSearch', params: { navigateOnClose: 'mainSubWindow' } } }); }, init: function (model) { this.model = model; model.get('leftColumnViewManager').on('order', function () { this.setDisabled(false); this.adjustVisibilityBasedOnPermissions(); }, this); model.get('leftColumnViewManager').on('multiorder', function () { this.setDisabled(true); }, this); } }); enyo.kind({ name: 'OB.UI.MenuPrint', kind: 'OB.UI.MenuAction', permission: 'OBPOS_print.receipt', events: { onPrintReceipt: '' }, i18nLabel: 'OBPOS_LblPrintReceipt', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doPrintReceipt(); } }, init: function (model) { var receipt = model.get('order'), me = this; receipt.on('change:isQuotation', function (model) { if (!model.get('isQuotation')) { me.show(); } else { me.hide(); } }, this); } }); enyo.kind({ name: 'OB.UI.MenuQuotation', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.quotation', events: { onCreateQuotation: '' }, i18nLabel: 'OBPOS_CreateQuotation', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (OB.POS.modelterminal.get('terminal').terminalType.documentTypeForQuotations) { if (OB.POS.modelterminal.hasPermission(this.permission)) { if (this.model.get('leftColumnViewManager').isMultiOrder()) { if (this.model.get('multiorders')) { this.model.get('multiorders').resetValues(); } this.model.get('leftColumnViewManager').setOrderMode(); } this.doCreateQuotation(); } } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_QuotationNoDocType')); } }, updateVisibility: function (model) { if (!model.get('isQuotation')) { this.show(); this.adjustVisibilityBasedOnPermissions(); } else { this.hide(); } }, init: function (model) { var receipt = model.get('order'), me = this; this.model = model; receipt.on('change:isQuotation', function (model) { this.updateVisibility(model); }, this); } }); enyo.kind({ name: 'OB.UI.MenuDiscounts', kind: 'OB.UI.MenuAction', permission: 'OBPOS_retail.advDiscounts', events: { onDiscountsMode: '' }, //TODO i18nLabel: 'OBPOS_LblReceiptDiscounts', tap: function () { if (!this.disabled) { this.inherited(arguments); // Manual dropdown menu closure this.doDiscountsMode({ tabPanel: 'edit', keyboard: 'toolbardiscounts', edit: false, options: { discounts: true } }); } }, updateVisibility: function () { var me = this; if (this.model.get('leftColumnViewManager').isMultiOrder()) { me.setDisabled(true); return; } me.setDisabled(OB.UTIL.isDisableDiscount(this.receipt)); me.adjustVisibilityBasedOnPermissions(); }, init: function (model) { var me = this; this.model = model; this.receipt = model.get('order'); //set disabled until ticket has lines me.setDisabled(true); if (!OB.POS.modelterminal.hasPermission(this.permission)) { //no permissions, never will be enabled return; } model.get('leftColumnViewManager').on('order', function () { this.updateVisibility(); }, this); model.get('leftColumnViewManager').on('multiorder', function () { me.setDisabled(true); }, this); this.receipt.get('lines').on('all', function () { this.updateVisibility(); }, this); } }); enyo.kind({ name: 'OB.UI.MenuCreateOrderFromQuotation', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.createorderfromquotation', events: { onShowPopup: '' }, i18nLabel: 'OBPOS_CreateOrderFromQuotation', tap: function () { if (this.disabled) { return true; } if (OB.POS.modelterminal.hasPermission(this.permission)) { this.inherited(arguments); // Manual dropdown menu closure this.doShowPopup({ popup: 'modalCreateOrderFromQuotation' }); } }, updateVisibility: function (model) { if (OB.POS.modelterminal.hasPermission(this.permission) && model.get('isQuotation') && model.get('hasbeenpaid') === 'Y') { this.show(); } else { this.hide(); } }, init: function (model) { var receipt = model.get('order'), me = this; me.hide(); model.get('leftColumnViewManager').on('order', function () { this.updateVisibility(receipt); this.adjustVisibilityBasedOnPermissions(); }, this); model.get('leftColumnViewManager').on('multiorder', function () { me.hide(); }, this); receipt.on('change:isQuotation', function (model) { this.updateVisibility(model); }, this); receipt.on('change:hasbeenpaid', function (model) { this.updateVisibility(model); }, this); } }); enyo.kind({ name: 'OB.UI.MenuRejectQuotation', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.rejectquotation', events: { onRejectQuotation: '' }, i18nLabel: 'OBPOS_RejectQuotation', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doRejectQuotation(); } }, updateVisibility: function (model) { if (model.get('isQuotation') && model.get('hasbeenpaid') === 'Y') { this.hide(); } else { this.hide(); } }, init: function (model) { var receipt = model.get('order'), me = this; me.hide(); receipt.on('change:isQuotation', function (model) { this.updateVisibility(model); }, this); receipt.on('change:hasbeenpaid', function (model) { this.updateVisibility(model); }, this); } }); enyo.kind({ name: 'OB.UI.MenuReactivateQuotation', kind: 'OB.UI.MenuAction', permission: 'OBPOS_receipt.reactivatequotation', events: { onShowReactivateQuotation: '' }, i18nLabel: 'OBPOS_ReactivateQuotation', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doShowReactivateQuotation(); } }, updateVisibility: function (model) { if (OB.POS.modelterminal.hasPermission(this.permission) && model.get('isQuotation') && model.get('hasbeenpaid') === 'Y') { this.show(); } else { this.hide(); } }, init: function (model) { var receipt = model.get('order'), me = this; me.hide(); model.get('leftColumnViewManager').on('order', function () { this.updateVisibility(receipt); this.adjustVisibilityBasedOnPermissions(); }, this); model.get('leftColumnViewManager').on('multiorder', function () { me.hide(); }, this); receipt.on('change:isQuotation', function (model) { this.updateVisibility(model); }, this); receipt.on('change:hasbeenpaid', function (model) { this.updateVisibility(model); }, this); } }); enyo.kind({ name: 'OB.UI.MenuPaidReceipts', kind: 'OB.UI.MenuAction', permission: 'OBPOS_retail.paidReceipts', events: { onPaidReceipts: '' }, i18nLabel: 'OBPOS_LblPaidReceipts', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (!OB.POS.modelterminal.get('connectedToERP')) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowRequiresOnline')); return; } if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doPaidReceipts({ isQuotation: false }); } } }); enyo.kind({ name: 'OB.UI.MenuQuotations', kind: 'OB.UI.MenuAction', permission: 'OBPOS_retail.quotations', events: { onQuotations: '' }, i18nLabel: 'OBPOS_Quotations', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (!OB.POS.modelterminal.get('connectedToERP')) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowRequiresOnline')); return; } if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doQuotations(); } } }); enyo.kind({ name: 'OB.UI.MenuLayaways', kind: 'OB.UI.MenuAction', permission: 'OBPOS_retail.layaways', events: { onLayaways: '' }, i18nLabel: 'OBPOS_LblLayaways', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (!OB.POS.modelterminal.get('connectedToERP')) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowRequiresOnline')); return; } if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doLayaways(); } } }); enyo.kind({ name: 'OB.UI.MenuMultiOrders', kind: 'OB.UI.MenuAction', permission: 'OBPOS_retail.multiorders', events: { onMultiOrders: '' }, i18nLabel: 'OBPOS_LblPayOpenTickets', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (!OB.POS.modelterminal.get('connectedToERP')) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowRequiresOnline')); return; } if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doMultiOrders(); } } }); enyo.kind({ name: 'OB.UI.MenuBackOffice', kind: 'OB.UI.MenuAction', permission: 'OBPOS_retail.backoffice', url: '../..', events: { onBackOffice: '' }, i18nLabel: 'OBPOS_LblOpenbravoWorkspace', tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doBackOffice({ url: this.url }); } } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, _ */ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalSelectTerminal', closeOnEscKey: false, autoDismiss: false, executeOnShow: function () { this.$.bodyButtons.$.terminalKeyIdentifier.attributes.placeholder = OB.I18N.getLabel('OBPOS_TerminalKeyIdentifier'); this.$.bodyButtons.$.username.attributes.placeholder = OB.I18N.getLabel('OBMOBC_LoginUserInput'); this.$.bodyButtons.$.password.attributes.placeholder = OB.I18N.getLabel('OBMOBC_LoginPasswordInput'); }, bodyContent: { i18nContent: 'OBPOS_SelectTerminalMsg' }, bodyButtons: { components: [{ kind: 'enyo.Input', type: 'text', name: 'terminalKeyIdentifier', classes: 'input-login', style: 'display: block; margin-left: auto; margin-right: auto;', onkeydown: 'inputKeydownHandler' }, { kind: 'enyo.Input', type: 'text', name: 'username', classes: 'input-login', style: 'display: block; margin-left: auto; margin-right: auto;', onkeydown: 'inputKeydownHandler' }, { kind: 'enyo.Input', type: 'password', name: 'password', classes: 'input-login', style: 'display: block; margin-left: auto; margin-right: auto;', onkeydown: 'inputKeydownHandler' }, { kind: 'OB.UI.btnApplyTerminal' }] }, initComponents: function () { this.header = OB.I18N.getLabel('OBPOS_SelectTerminalHeader'); this.inherited(arguments); this.$.headerCloseButton.hide(); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.btnApplyTerminal', isDefaultAction: true, i18nContent: 'OBPOS_LblApplyButton', tap: function () { var terminalData = { terminalKeyIdentifier: this.owner.$.terminalKeyIdentifier.getValue(), username: this.owner.$.username.getValue(), password: this.owner.$.password.getValue() }; this.doHideThisPopup(); this.owner.owner.context.linkTerminal(JSON.stringify(terminalData), this.owner.owner.callback); } }); /* ************************************************************************************ * Copyright (C) 2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, _ */ enyo.kind({ name: 'OB.UI.PopupDrawerOpened', kind: 'OB.UI.Popup', classes: 'modal-dialog', bodyContentClass: 'modal-dialog-header-text', showing: false, closeOnEscKey: false, autoDismiss: false, keydownHandler: '', i18nHeader: 'OBPOS_closeDrawerContinue', components: [{ classes: 'modal-dialog-header', name: 'table', components: [{ name: 'header', classes: 'modal-dialog-header-text' }] }, { classes: 'modal-dialog-body', name: 'bodyParent', components: [{ name: 'bodyContent' }] }], bodyContent: { kind: 'enyo.Control', name: 'label' }, initComponents: function () { this.inherited(arguments); this.setStyle('min-height: 180px;'); if (this.i18nHeader) { this.$.header.setContent(OB.I18N.getLabel(this.i18nHeader)); } else { this.$.header.setContent(this.header); } this.$.bodyContent.setClasses(this.bodyContentClass); if (this.bodyContent && this.bodyContent.i18nContent) { this.$.bodyContent.setContent(OB.I18N.getLabel(this.bodyContent.i18nContent)); } else { this.$.bodyContent.createComponent(this.bodyContent); } } }); OB.UTIL.HookManager.registerHook('OBPOS_LoadPOSWindow', function (args, callbacks) { if (OB.MobileApp.model.get('permissions').OBPOS_closeDrawerBeforeContinue) { OB.POS.hwserver.isDrawerClosed({ openFirst: false }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); } OB.UTIL.HookManager.callbackExecutor(args, callbacks); }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, Backbone, $, _, moment, enyo */ /*header of scrollable table*/ enyo.kind({ name: 'OB.UI.ModalPRScrollableHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onSearchAction: '', onClearAction: '' }, handlers: { onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'filterText', style: 'width: 100%' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }, { style: 'display: table;', components: [{ style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStartDate')); }, style: 'width: 200px; margin: 0px 0px 2px 5px;' }] }, { style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblEndDate')); }, style: 'width 200px; margin: 0px 0px 2px 65px;' }] }] }, { style: 'display: table;', components: [{ style: 'display: table-cell;', components: [{ kind: 'enyo.Input', name: 'startDate', size: '10', type: 'text', style: 'width: 100px; margin: 0px 0px 8px 5px;', onchange: 'searchAction' }] }, { style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getDateFormatLabel()); }, style: 'width: 100px; color:gray; margin: 0px 0px 8px 5px;' }] }, { kind: 'enyo.Input', name: 'endDate', size: '10', type: 'text', style: 'width: 100px; margin: 0px 0px 8px 50px;', onchange: 'searchAction' }, { style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getDateFormatLabel()); }, style: 'width: 100px; color:gray; margin: 0px 0px 8px 5px;' }] }] }] }], showValidationErrors: function (stDate, endDate) { var me = this; if (stDate === false) { this.$.startDate.addClass('error'); setTimeout(function () { me.$.startDate.removeClass('error'); }, 5000); } if (endDate === false) { this.$.endDate.addClass('error'); setTimeout(function () { me.$.endDate.removeClass('error'); }, 5000); } }, clearAction: function () { this.$.filterText.setValue(''); this.$.startDate.setValue(''); this.$.endDate.setValue(''); this.doClearAction(); }, getDateFilters: function () { var startDate, endDate, startDateValidated = true, endDateValidated = true, formattedStartDate = '', formattedEndDate = ''; startDate = this.$.startDate.getValue(); endDate = this.$.endDate.getValue(); if (startDate !== '') { startDateValidated = OB.Utilities.Date.OBToJS(startDate, OB.Format.date); if (startDateValidated) { formattedStartDate = OB.Utilities.Date.JSToOB(startDateValidated, 'yyyy-MM-dd'); } } if (endDate !== '') { endDateValidated = OB.Utilities.Date.OBToJS(endDate, OB.Format.date); if (endDateValidated) { formattedEndDate = OB.Utilities.Date.JSToOB(endDateValidated, 'yyyy-MM-dd'); } } if (startDate !== '' && startDateValidated && endDate !== '' && endDateValidated) { if (moment(endDateValidated).diff(moment(startDateValidated)) < 0) { endDateValidated = null; startDateValidated = null; } } if (startDateValidated === null || endDateValidated === null) { this.showValidationErrors(startDateValidated !== null, endDateValidated !== null); return false; } else { this.$.startDate.removeClass('error'); this.$.endDate.removeClass('error'); } this.filters = _.extend(this.filters, { startDate: formattedStartDate, endDate: formattedEndDate }); return true; }, searchAction: function () { var params = this.parent.parent.parent.parent.parent.parent.parent.parent.params; this.filters = { documentType: params.isQuotation ? ([OB.POS.modelterminal.get('terminal').terminalType.documentTypeForQuotations]) : ([OB.POS.modelterminal.get('terminal').terminalType.documentType, OB.POS.modelterminal.get('terminal').terminalType.documentTypeForReturns]), docstatus: params.isQuotation ? 'UE' : null, isQuotation: params.isQuotation ? true : false, isLayaway: params.isLayaway ? true : false, isReturn: params.isReturn ? true : false, filterText: this.$.filterText.getValue(), pos: OB.POS.modelterminal.get('terminal').id, client: OB.POS.modelterminal.get('terminal').client, organization: OB.POS.modelterminal.get('terminal').organization }; if (!this.getDateFilters()) { return true; } this.doSearchAction({ filters: this.filters }); return true; } }); /*items of collection*/ enyo.kind({ name: 'OB.UI.ListPRsLine', kind: 'OB.UI.SelectButton', allowHtml: true, events: { onHideThisPopup: '' }, tap: function () { this.inherited(arguments); this.doHideThisPopup(); }, components: [{ name: 'line', style: 'line-height: 23px;', components: [{ name: 'topLine' }, { style: 'color: #888888', name: 'bottonLine' }, { style: 'clear: both;' }] }], create: function () { var returnLabel = ''; this.inherited(arguments); if (this.model.get('documentTypeId') === OB.POS.modelterminal.get('terminal').terminalType.documentTypeForReturns) { this.model.set('totalamount', OB.DEC.mul(this.model.get('totalamount'), -1)); returnLabel = ' (' + OB.I18N.getLabel('OBPOS_ToReturn') + ')'; } this.$.topLine.setContent(this.model.get('documentNo') + ' - ' + this.model.get('businessPartner') + returnLabel); this.$.bottonLine.setContent(this.model.get('totalamount') + ' (' + this.model.get('orderDate').substring(0, 10) + ') '); this.render(); } }); /*scrollable table (body of modal)*/ enyo.kind({ name: 'OB.UI.ListPRs', classes: 'row-fluid', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, events: { onChangePaidReceipt: '', onShowPopup: '', onAddProduct: '', onHideThisPopup: '' }, components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;', classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'prslistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderHeader: 'OB.UI.ModalPRScrollableHeader', renderLine: 'OB.UI.ListPRsLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }], clearAction: function (inSender, inEvent) { this.prsList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, process = new OB.DS.Process('org.openbravo.retail.posterminal.PaidReceiptsHeader'); me.filters = inEvent.filters; this.clearAction(); process.exec({ filters: me.filters, _limit: OB.Model.Order.prototype.dataLimit, _dateFormat: OB.Format.date }, function (data) { if (data) { _.each(data, function (iter) { me.model.get('orderList').newDynamicOrder(iter, function (order) { if (me.filters.isReturn) { order.set('forReturn', true); } me.prsList.add(order); }); }); me.$.prslistitemprinter.getScrollArea().scrollToTop(); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgErrorDropDep')); } }); return true; }, prsList: null, init: function (model) { var me = this, process = new OB.DS.Process('org.openbravo.retail.posterminal.PaidReceipts'); this.model = model; this.prsList = new Backbone.Collection(); this.$.prslistitemprinter.setCollection(this.prsList); this.prsList.on('click', function (model) { OB.UTIL.showLoading(true); process.exec({ orderid: model.get('id'), forReturn: model.get('forReturn') }, function (data) { OB.UTIL.showLoading(false); if (data) { if (me.model.get('leftColumnViewManager').isMultiOrder()) { if (me.model.get('multiorders')) { me.model.get('multiorders').resetValues(); } me.model.get('leftColumnViewManager').setOrderMode(); } OB.UTIL.HookManager.executeHooks('OBRETUR_ReturnFromOrig', { order: data[0], context: me, params: me.parent.parent.params }, function (args) { if (!args.cancelOperation) { me.model.get('orderList').newPaidReceipt(data[0], function (order) { me.doChangePaidReceipt({ newPaidReceipt: order }); }); } }); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgErrorDropDep')); } }); return true; }, this); } }); /*Modal definiton*/ enyo.kind({ name: 'OB.UI.ModalPaidReceipts', kind: 'OB.UI.Modal', topPosition: '125px', i18nHeader: 'OBPOS_LblPaidReceipts', published: { params: null }, changedParams: function (value) { }, body: { kind: 'OB.UI.ListPRs' }, handlers: { onChangePaidReceipt: 'changePaidReceipt' }, changePaidReceipt: function (inSender, inEvent) { this.model.get('orderList').addPaidReceipt(inEvent.newPaidReceipt); return true; }, executeOnShow: function () { this.$.body.$.listPRs.$.prslistitemprinter.$.theader.$.modalPRScrollableHeader.clearAction(); if (this.params.isQuotation) { this.$.header.setContent(OB.I18N.getLabel('OBPOS_Quotations')); } else if (this.params.isLayaway) { this.$.header.setContent(OB.I18N.getLabel('OBPOS_LblLayaways')); } else { this.$.header.setContent(OB.I18N.getLabel('OBPOS_LblPaidReceipts')); } }, init: function (model) { this.model = model; } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, moment */ /*header of scrollable table*/ enyo.kind({ name: 'OB.UI.ModalMultiOrdersHeader', kind: 'OB.UI.ModalPRScrollableHeader', events: { onSearchAction: '', onClearAction: '' }, handlers: { onSearchActionByKey: 'searchAction', onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'filterText', style: 'width: 100%', isFirstFocus: true }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }, { style: 'display: table;', components: [{ style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStartDate')); }, style: 'width: 200px; margin: 0px 0px 2px 5px;' }] }, { style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblEndDate')); }, style: 'width 200px; margin: 0px 0px 2px 65px;' }] }] }, { style: 'display: table;', components: [{ style: 'display: table-cell;', components: [{ kind: 'enyo.Input', name: 'startDate', size: '10', type: 'text', style: 'width: 100px; margin: 0px 0px 8px 5px;', onchange: 'searchAction' }] }, { style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getDateFormatLabel()); }, style: 'width: 100px; color:gray; margin: 0px 0px 8px 5px;' }] }, { kind: 'enyo.Input', name: 'endDate', size: '10', type: 'text', style: 'width: 100px; margin: 0px 0px 8px 50px;', onchange: 'searchAction' }, { style: 'display: table-cell;', components: [{ tag: 'h4', initComponents: function () { this.setContent(OB.I18N.getDateFormatLabel()); }, style: 'width: 100px; color:gray; margin: 0px 0px 8px 5px;' }] }] }] }], searchAction: function () { this.filters = { documentType: [OB.POS.modelterminal.get('terminal').terminalType.documentType, OB.POS.modelterminal.get('terminal').terminalType.documentTypeForReturns], docstatus: null, isQuotation: false, isLayaway: true, filterText: this.$.filterText.getValue(), startDate: this.$.startDate.getValue(), endDate: this.$.endDate.getValue(), pos: OB.POS.modelterminal.get('terminal').id, client: OB.POS.modelterminal.get('terminal').client, organization: OB.POS.modelterminal.get('terminal').organization }; if (!this.getDateFilters()) { return true; } this.doSearchAction({ filters: this.filters }); return true; } }); /*items of collection*/ enyo.kind({ name: 'OB.UI.ListMultiOrdersLine', kind: 'OB.UI.CheckboxButton', classes: 'modal-dialog-btn-check', style: 'border-bottom: 1px solid #cccccc;text-align: left; padding-left: 70px; height: 58px;', events: { onHideThisPopup: '' }, tap: function () { this.inherited(arguments); this.model.set('checked', !this.model.get('checked')); }, components: [{ name: 'line', style: 'line-height: 23px; display: inline', components: [{ style: 'display: inline', name: 'topLine' }, { style: 'font-weight: bold; color: lightblue; float: right; text-align:right; ', name: 'isLayaway' }, { style: 'color: #888888', name: 'bottonLine' }, { style: 'clear: both;' }] }], create: function () { var returnLabel = ''; this.inherited(arguments); if (this.model.get('documentTypeId') === OB.POS.modelterminal.get('terminal').terminalType.documentTypeForReturns) { this.model.set('totalamount', OB.DEC.mul(this.model.get('totalamount'), -1)); returnLabel = ' (' + OB.I18N.getLabel('OBPOS_ToReturn') + ')'; } this.$.topLine.setContent(this.model.get('documentNo') + ' - ' + (this.model.get('bp') ? this.model.get('bp').get('_identifier') : this.model.get('businessPartner')) + returnLabel); this.$.bottonLine.setContent(((this.model.get('totalamount') || this.model.get('totalamount') === 0) ? this.model.get('totalamount') : this.model.getPending()) + ' (' + OB.I18N.formatDate(new Date(this.model.get('orderDate'))) + ') '); if (this.model.get('checked')) { this.addClass('active'); } else { this.removeClass('active'); } if (this.model.get('isLayaway')) { this.$.isLayaway.setContent(OB.I18N.getLabel('OBPOS_LblLayaway')); } this.render(); } }); /*scrollable table (body of modal)*/ enyo.kind({ name: 'OB.UI.ListMultiOrders', classes: 'row-fluid', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, components: [{ classes: 'span12', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'multiorderslistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '300px', renderHeader: 'OB.UI.ModalMultiOrdersHeader', renderLine: 'OB.UI.ListMultiOrdersLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }], cleanFilter: false, clearAction: function (inSender, inEvent) { this.multiOrdersList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, toMatch = 0, re, actualDate, i, processHeader = new OB.DS.Process('org.openbravo.retail.posterminal.PaidReceiptsHeader'), negativeLines; me.filters = inEvent.filters; this.clearAction(); processHeader.exec({ filters: me.filters, _limit: OB.Model.Order.prototype.dataLimit }, function (data) { if (data) { _.each(me.model.get('orderList').models, function (iter) { if (iter.get('lines') && iter.get('lines').length > 0) { re = new RegExp(me.filters.filterText, 'gi'); negativeLines = _.find(iter.get('lines').models, function (line) { return line.get('qty') < 0; }); toMatch = iter.get('documentNo').match(re) + iter.get('bp').get('_identifier').match(re); if ((me.filters.filterText === "" || toMatch !== 0) && (iter.get('orderType') === 0 || iter.get('orderType') === 2) && !iter.get('isPaid') && !iter.get('isQuotation') && !negativeLines) { actualDate = new Date().setHours(0, 0, 0, 0); if (me.filters.endDate === "" || new Date(me.filters.endDate) >= actualDate) { for (i = 0; i < me.filters.documentType.length; i++) { if (me.filters.documentType[i] === iter.get('documentType')) { if (!_.isNull(iter.id) && !_.isUndefined(iter.id)) { if (me.cleanFilter) { iter.unset("checked"); } me.multiOrdersList.add(iter); break; } } } } } } }); if (me.cleanFilter) { me.cleanFilter = false; } _.each(data, function (iter) { me.multiOrdersList.add(iter); }); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgErrorDropDep')); } }); return true; }, multiOrdersList: null, init: function (model) { this.model = model; this.multiOrdersList = new Backbone.Collection(); this.$.multiorderslistitemprinter.setCollection(this.multiOrdersList); } }); enyo.kind({ name: 'OB.UI.ModalMultiOrdersTopHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onHideThisPopup: '', onSelectMultiOrders: '', onTabChange: '', onRightToolDisabled: '' }, components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; float:left', components: [{ name: 'doneMultiOrdersButton', kind: 'OB.UI.SmallButton', ontap: 'doneAction' }] }, { style: 'display: table-cell; vertical-align: middle; width: 100%;', components: [{ name: 'title', style: 'text-align: center;' }] }, { style: 'display: table-cell; float:right', components: [{ classes: 'btnlink-gray', name: 'cancelMultiOrdersButton', kind: 'OB.UI.SmallButton', ontap: 'cancelAction' }] }] }], initComponents: function () { this.inherited(arguments); this.$.doneMultiOrdersButton.setContent(OB.I18N.getLabel('OBMOBC_LblDone')); this.$.cancelMultiOrdersButton.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); }, doneAction: function () { var selectedMultiOrders = [], me = this, process = new OB.DS.Process('org.openbravo.retail.posterminal.PaidReceipts'), checkedMultiOrders = _.compact(this.parent.parent.parent.$.body.$.listMultiOrders.multiOrdersList.map(function (e) { if (e.get('checked')) { return e; } })); if (checkedMultiOrders.length === 0) { return true; } _.each(checkedMultiOrders, function (iter) { if (_.indexOf(me.owner.owner.model.get('orderList').models, iter) !== -1) { iter.save(); selectedMultiOrders.push(iter); } else { process.exec({ orderid: iter.id }, function (data) { var taxes; OB.UTIL.showLoading(false); if (data) { me.owner.owner.model.get('orderList').newPaidReceipt(data[0], function (order) { order.set('loadedFromServer', true); order.set('checked', iter.get('checked')); taxes = OB.DATA.OrderTaxes(order); order.save(); selectedMultiOrders.push(order); if (selectedMultiOrders.length === checkedMultiOrders.length) { me.doSelectMultiOrders({ value: selectedMultiOrders }); } }); } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgErrorDropDep')); } }); } if (selectedMultiOrders.length === checkedMultiOrders.length) { me.doSelectMultiOrders({ value: selectedMultiOrders }); } }); this.doTabChange({ tabPanel: 'payment', keyboard: 'toolbarpayment', edit: false }); this.doHideThisPopup(); }, cancelAction: function () { this.doHideThisPopup(); } }); /*Modal definiton*/ enyo.kind({ name: 'OB.UI.ModalMultiOrders', topPosition: '125px', kind: 'OB.UI.Modal', executeOnHide: function () { this.$.body.$.listMultiOrders.$.multiorderslistitemprinter.$.theader.$.modalMultiOrdersHeader.clearAction(); }, executeOnShow: function () { var i, j; this.$.header.$.modalMultiOrdersTopHeader.$.title.setContent(OB.I18N.getLabel('OBPOS_LblMultiOrders')); this.$.body.$.listMultiOrders.cleanFilter = true; }, i18nHeader: '', body: { kind: 'OB.UI.ListMultiOrders' }, initComponents: function () { this.inherited(arguments); this.$.closebutton.hide(); this.$.header.createComponent({ kind: 'OB.UI.ModalMultiOrdersTopHeader' }); }, init: function (model) { this.model = model; this.waterfall('onSetModel', { model: this.model }); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, Backbone, $, _, enyo */ enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSPointOfSale.UI.Modals.btnModalCreateOrderCancel', i18nContent: 'OBMOBC_LblCancel', tap: function () { this.doHideThisPopup(); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSPointOfSale.UI.Modals.btnModalCreateOrderAccept', i18nContent: 'OBPOS_CreateOrderFromQuotation', events: { onCreateOrderFromQuotation: '' }, tap: function () { var checked = !this.parent.children[1].children[0].checked; this.parent.parent.parent.parent.theQuotation.createOrderFromQuotation(checked); this.doHideThisPopup(); } }); enyo.kind({ name: 'OB.UI.updateprices', kind: 'OB.UI.CheckboxButton', classes: 'modal-dialog-btn-check', checked: false, init: function () { this.checked = !OB.MobileApp.model.get('permissions')['OBPOS_quotation.defaultNotFirm']; this.addRemoveClass('active', this.checked); this.setDisabled(!OB.MobileApp.model.hasPermission('OBPOS_quotation.editableFirmCheck')); } }); enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalCreateOrderFromQuotation', myId: 'modalCreateOrderFromQuotation', bodyContent: {}, bodyButtons: { components: [{ style: 'height: 40px; width: 120px; float:left;' }, { style: 'height: 40px; width: 50px; background-color: rgb(226, 226, 226); float:left', components: [{ kind: 'OB.UI.updateprices', myId: 'updatePricesCheck' }] }, { style: 'text-align: left; padding: 11px; float: left; width: 248px; background: #dddddd;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_QuotationUpdatePrices')); } }, { style: 'clear: both;' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.btnModalCreateOrderAccept' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.btnModalCreateOrderCancel' }] }, init: function (model) { this.model = model; var receipt = this.model.get('order'); receipt.on('orderCreatedFromQuotation', function () { this.model.get('orderList').add(this.theQuotation); }, this); this.theQuotation = receipt; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, Backbone, $, _, enyo */ enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSPointOfSale.UI.Modals.btnModalReactivateQuotationCancel', i18nContent: 'OBMOBC_LblCancel', tap: function () { this.doHideThisPopup(); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSPointOfSale.UI.Modals.btnModalReactivateQuotationAccept', i18nContent: 'OBMOBC_LblOk', events: { onReactivateQuotation: '' }, tap: function () { this.doReactivateQuotation(); this.doHideThisPopup(); } }); enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalReactivateQuotation', myId: 'modalReactivateQuotation', bodyContent: {}, i18nHeader: 'OBPOS_ReactivateQuotation', bodyButtons: { components: [{ initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_ReactivateQuotationMessage')); } }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.btnModalReactivateQuotationAccept' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.btnModalReactivateQuotationCancel' }] } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, Backbone, $, _, enyo */ enyo.kind({ kind: 'OB.UI.Button', name: 'OB.OBPOSPointOfSale.UI.Modals.btnModaContextChangedAccept', classes: 'btnlink btnlink-gray modal-dialog-button', i18nContent: 'OBMOBC_LblOk', events: { onHideThisPopup: '' }, tap: function () { OB.POS.modelterminal.logout(); } }); enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.ModalContextChanged', bodyContent: {}, closeOnEscKey: false, autoDismiss: false, i18nHeader: 'OBPOS_ContextChanged', bodyButtons: { components: [{ initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_ContextChangedMessage')); } }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.btnModaContextChangedAccept' }] } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _ */ /*items of collection*/ enyo.kind({ name: 'OB.UI.ListValuesLineCheck', kind: 'OB.UI.CheckboxButton', classes: 'modal-dialog-btn-check', style: 'width: 86%; text-align: left; padding-left: 70px;', events: { onAddToSelected: '' }, tap: function () { this.inherited(arguments); var me = this; if (!this.parent.model.get('childrenSelected')) { this.removeClass('half-active'); } this.doAddToSelected({ value: me.parent.model, checked: !this.parent.model.get('checked'), selected: !this.parent.model.get('selected') }); }, create: function () { this.inherited(arguments); this.setContent(this.parent.model.get('name')); if (this.parent.model.get('selected')) { this.addClass('active'); } else { this.removeClass('active'); if (this.parent.model.get('childrenSelected')) { this.addClass('half-active'); } } } }); enyo.kind({ name: 'OB.UI.ListValuesLineChildren', kind: 'OB.UI.Button', classes: 'btn-icon-inspectTree', style: 'width: 14%; margin: 0px; ', showing: false, childrenArray: [], events: { onSetCollection: '' }, create: function () { this.inherited(arguments); var me = this; OB.Dal.query(OB.Model.ProductChValue, "select distinct(id), name, characteristic_id from m_ch_value where parent = '" + this.parent.model.get('id') + "' order by UPPER(name) asc", [], function (dataValues, me) { if (dataValues && dataValues.length > 0) { me.childrenArray = dataValues.models; me.show(); } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); }, tap: function () { this.doSetCollection({ value: this.childrenArray, parentValue: this.parent.model.get('id') }); } }); enyo.kind({ name: 'OB.UI.ListValuesLine', style: 'border-bottom: 1px solid #cccccc', components: [{ kind: 'OB.UI.ListValuesLineCheck' }, { kind: 'OB.UI.ListValuesLineChildren' }] }); /*scrollable table (body of modal)*/ enyo.kind({ name: 'OB.UI.ListValues', classes: 'row-fluid', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction', onSetCollection: 'setCollection' }, components: [{ classes: 'span12', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'valueslistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderLine: 'OB.UI.ListValuesLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }], clearAction: function (inSender, inEvent) { this.valuesList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, i, j, whereClause = '', params = []; params.push(this.parent.parent.characteristic.get('characteristic_id')); OB.Dal.query(OB.Model.ProductChValue, "select distinct(id), name, characteristic_id, parent from m_ch_value where parent = '" + this.parentValue + "' and characteristic_id = ?" + whereClause + ' order by UPPER(name) asc', params, function (dataValues, me) { if (dataValues && dataValues.length > 0) { for (i = 0; i < dataValues.length; i++) { for (j = 0; j < me.parent.parent.model.get('filter').length; j++) { if (dataValues.models[i].get('id') === me.parent.parent.model.get('filter')[j].id) { dataValues.models[i].set('checked', true); dataValues.models[i].set('selected', me.parent.parent.model.get('filter')[j].selected); break; } else { dataValues.models[i].set('checked', false); } dataValues.models[i].set('childrenSelected', null); me.hasSelectedChildrenTree([dataValues.models[i]], dataValues.models[i]); } } me.parent.parent.$.body.$.listValues.valuesList.reset(dataValues.models); } else { me.parent.parent.$.body.$.listValues.valuesList.reset(); } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); return true; }, parentValue: 0, setCollection: function (inSender, inEvent) { var i, j, k; if (inEvent.parentValue !== 0) { this.parent.parent.$.header.$.modalProductChTopHeader.$.backChButton.addStyles('visibility: visible'); } this.parentValue = inEvent.parentValue; for (i = 0; i < inEvent.value.length; i++) { for (j = 0; j < this.parent.parent.model.get('filter').length; j++) { if (inEvent.value[i].get('id') === this.parent.parent.model.get('filter')[j].id) { inEvent.value[i].set('checked', this.parent.parent.model.get('filter')[j].selected); inEvent.value[i].set('selected', this.parent.parent.model.get('filter')[j].selected); } } for (k = 0; k < this.parent.parent.selected.length; k++) { if (inEvent.value[i].get('id') === this.parent.parent.selected[k].id) { inEvent.value[i].set('checked', this.parent.parent.selected[k].get('checked')); inEvent.value[i].set('selected', this.parent.parent.selected[k].get('selected')); } } inEvent.value[i].set('childrenSelected', null); this.hasSelectedChildrenTree([inEvent.value[i]], inEvent.value[i]); } this.valuesList.reset(inEvent.value); }, hasSelectedChildrenTree: function (selected, rootObject) { var aux; for (aux = 0; aux < selected.length; aux++) { this.hasSelectedChildren(selected, aux, rootObject, this); } }, hasSelectedChildren: function (selected, aux, rootObject, me) { var j, k; me.exist = null; me.selected = selected; me.aux = aux; me.rootObject = rootObject; OB.Dal.query(OB.Model.ProductChValue, "select distinct(id), name, characteristic_id, parent " + "from m_ch_value where parent = '" + selected[aux].get('id') + "' order by UPPER(name) asc", [], function (dataValues, me) { for (j = 0; j < me.parent.parent.model.get('filter').length; j++) { if (selected[aux].id === me.parent.parent.model.get('filter')[j].id && selected[aux].id !== rootObject.id && me.parent.parent.model.get('filter')[j].selected) { me.exist = true; break; } } for (k = 0; k < me.parent.parent.selected.length; k++) { if (selected[aux].id === me.parent.parent.selected[k].id && selected[aux].id !== rootObject.id) { me.exist = me.parent.parent.selected[k].get('selected'); break; } } if (_.isNull(rootObject.get('childrenSelected')) || !rootObject.get('childrenSelected')) { rootObject.set('childrenSelected', me.exist); } me.exist = null; if (dataValues && dataValues.length > 0) { me.hasSelectedChildrenTree(dataValues.models, rootObject); } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); }, valuesList: null, init: function (model) { this.valuesList = new Backbone.Collection(); this.$.valueslistitemprinter.setCollection(this.valuesList); } }); enyo.kind({ name: 'OB.UI.ModalProductChTopHeader', kind: 'OB.UI.ScrollableTableHeader', style: '', events: { onHideThisPopup: '', onSelectCharacteristicValue: '', onGetPrevCollection: '' }, components: [{ style: 'display: table; width: 100%;', components: [{ style: 'display: table-cell; ', components: [{ classes: 'btnlink-gray', name: 'backChButton', kind: 'OB.UI.SmallButton', ontap: 'backAction' }] }, { style: 'display: table-cell; width: 55%;', components: [{ name: 'title', style: 'text-align: center; vertical-align: middle;' }] }, { style: 'display: table-cell; ', components: [{ name: 'doneChButton', kind: 'OB.UI.SmallButton', ontap: 'doneAction' }] }, { style: 'display: table-cell;', components: [{ classes: 'btnlink-gray', name: 'cancelChButton', kind: 'OB.UI.SmallButton', ontap: 'cancelAction' }] }] }], initComponents: function () { this.inherited(arguments); this.$.backChButton.setContent(OB.I18N.getLabel('OBMOBC_LblBack')); this.$.backChButton.addStyles('visibility: hidden'); this.$.doneChButton.setContent(OB.I18N.getLabel('OBMOBC_LblDone')); this.$.cancelChButton.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); this.selectedToSend = []; }, backAction: function () { this.doGetPrevCollection(); }, doneAction: function () { var me = this; this.countingValues = this.countingValues + me.parent.parent.parent.selected.length; if (me.parent.parent.parent.selected.length > 0) { this.inspectTree(me.parent.parent.parent.selected); OB.UTIL.showLoading(true); } else { this.doHideThisPopup(); } }, cancelAction: function () { this.parent.parent.parent.selected = []; this.parent.parent.parent.countedValues = 0; this.doHideThisPopup(); }, checkFinished: function () { var me = this; if (this.parent.parent.parent.countedValues === this.countingValues) { this.doSelectCharacteristicValue({ value: me.selectedToSend }); this.parent.parent.parent.selected = []; this.selectedToSend = []; this.parent.parent.parent.countedValues = 0; this.countingValues = 0; OB.UTIL.showLoading(false); this.doHideThisPopup(); } }, countingValues: 0, inspectTree: function (selected, checkedParent) { var aux; for (aux = 0; aux < selected.length; aux++) { this.getChildren(selected, aux, checkedParent, this); } }, getChildren: function (selected, aux, checkedParent, me) { OB.Dal.query(OB.Model.ProductChValue, "select distinct(id), name, characteristic_id, parent " + "from m_ch_value where parent = '" + selected[aux].get('id') + "' order by UPPER(name) asc", [], function (dataValues, me) { var index; if (dataValues && dataValues.length > 0) { if (!_.isUndefined(checkedParent)) { selected[aux].set('checked', checkedParent); } index = me.selectedToSend.map(function (e) { return e.id; }).indexOf(selected[aux].id); if (index === -1) { me.selectedToSend.push(selected[aux]); } else if (!_.isNull(selected[aux].get('selected')) && !_.isUndefined(selected[aux].get('selected'))) { me.selectedToSend[index] = selected[aux]; } if (!_.isUndefined(checkedParent)) { me.inspectTree(dataValues.models, checkedParent); } else { me.inspectTree(dataValues.models, selected[aux].get('checked')); } } else { if (!_.isUndefined(checkedParent)) { selected[aux].set('checked', checkedParent); } index = me.selectedToSend.map(function (e) { return e.id; }).indexOf(selected[aux].id); if (index === -1) { me.selectedToSend.push(selected[aux]); } else if (!_.isNull(selected[aux].get('selected')) && !_.isUndefined(selected[aux].get('selected'))) { me.selectedToSend[index] = selected[aux]; } me.countingValues++; me.checkFinished(); } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); } }); /*Modal definiton*/ enyo.kind({ name: 'OB.UI.ModalProductCharacteristic', topPosition: '170px', kind: 'OB.UI.Modal', published: { characteristic: null, selected: [] }, events: { onAddToSelected: '' }, handlers: { onAddToSelected: 'addToSelected', onGetPrevCollection: 'getPrevCollection' }, executeOnShow: function () { var i, j; this.$.body.$.listValues.parentValue = 0; this.$.header.parent.addStyles('padding: 0px; border-bottom: 1px solid #cccccc'); this.$.header.$.modalProductChTopHeader.$.backChButton.addStyles('visibility: hidden'); this.characteristic = this.args.model; this.$.header.$.modalProductChTopHeader.$.title.setContent(this.args.model.get('_identifier')); this.waterfall('onSearchAction'); }, i18nHeader: '', body: { kind: 'OB.UI.ListValues' }, initComponents: function () { this.inherited(arguments); this.$.closebutton.hide(); this.$.header.createComponent({ kind: 'OB.UI.ModalProductChTopHeader', style: 'border-bottom: 0px' }); }, addToSelected: function (inSender, inEvent) { var index = this.selected.map(function (e) { return e.get('id'); }).indexOf(inEvent.value.get('id')); if (!inEvent.checked) { inEvent.value.set('childrenSelected', false); this.inspectDeselectTree([inEvent.value], inEvent.value); } if (index !== -1) { inEvent.value.set('checked', inEvent.checked); inEvent.value.set('selected', inEvent.selected); this.selected[index].set('checked', inEvent.checked); this.selected[index].set('selected', inEvent.selected); } else { inEvent.value.set('checked', inEvent.checked); inEvent.value.set('selected', inEvent.selected); this.selected.push(inEvent.value); this.inspectCountTree([inEvent.value]); this.countedValues++; } }, getPrevCollection: function (inSender, inEvent) { var me = this, i, j, k; OB.Dal.query(OB.Model.ProductChValue, "select distinct(id) , name , characteristic_id, parent as parent from m_ch_value " + "where parent = (select parent from m_ch_value where id = '" + this.$.body.$.listValues.parentValue + "') and " + "characteristic_id = (select characteristic_id from m_ch_value where id = '" + this.$.body.$.listValues.parentValue + "') order by UPPER(name) asc", [], function (dataValues, me) { if (dataValues && dataValues.length > 0) { for (i = 0; i < dataValues.length; i++) { for (j = 0; j < me.model.get('filter').length; j++) { if (dataValues.models[i].get('id') === me.model.get('filter')[j].id) { dataValues.models[i].set('checked', me.model.get('filter')[j].checked); dataValues.models[i].set('selected', me.model.get('filter')[j].selected); } } for (k = 0; k < me.selected.length; k++) { if (dataValues.models[i].get('id') === me.selected[k].id) { dataValues.models[i].set('checked', me.selected[k].get('checked')); dataValues.models[i].set('selected', me.selected[k].get('selected')); } } dataValues.models[i].set('childrenSelected', null); me.$.body.$.listValues.hasSelectedChildrenTree([dataValues.models[i]], dataValues.models[i]); } me.$.body.$.listValues.valuesList.reset(dataValues.models); //We take the first to know the parent me.$.body.$.listValues.parentValue = dataValues.models[0].get('parent'); if (me.$.body.$.listValues.parentValue === '0') { //root me.$.header.$.modalProductChTopHeader.$.backChButton.addStyles('visibility: hidden'); } } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); }, countedValues: 0, inspectCountTree: function (selected) { var aux; for (aux = 0; aux < selected.length; aux++) { this.countChildren(selected, aux, this); } }, countChildren: function (selected, aux, me) { OB.Dal.query(OB.Model.ProductChValue, "select distinct(id), name, characteristic_id, parent " + "from m_ch_value where parent = '" + selected[aux].get('id') + "' order by UPPER(name) asc", [], function (dataValues, me) { if (dataValues && dataValues.length > 0) { me.inspectCountTree(dataValues.models); } else { me.countedValues++; } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); }, inspectDeselectTree: function (selected, rootObject) { var aux; for (aux = 0; aux < selected.length; aux++) { this.deselectChildren(selected, aux, rootObject, this); } }, deselectChildren: function (selected, aux, rootObject, me) { OB.Dal.query(OB.Model.ProductChValue, "select distinct(id), name, characteristic_id, parent " + "from m_ch_value where parent = '" + selected[aux].get('id') + "' order by UPPER(name) asc", [], function (dataValues, me) { var index = me.selected.map(function (e) { return e.id; }).indexOf(selected[aux].id); if (!rootObject.get('selected') && rootObject.get('id') !== selected[aux].get('id')) { selected[aux].set('selected', rootObject.get('selected')); if (index === -1) { me.doAddToSelected({ value: selected[aux], checked: selected[aux].get('checked'), selected: selected[aux].get('selected') }); } else { me.selected[index] = selected[aux]; } } if (dataValues && dataValues.length > 0) { me.inspectDeselectTree(dataValues.models, rootObject); } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); }, init: function (model) { this.model = model; this.waterfall('onSetModel', { model: this.model }); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _ */ /*items of collection*/ enyo.kind({ name: 'OB.UI.ListBrandsLine', kind: 'OB.UI.CheckboxButton', classes: 'modal-dialog-btn-check', style: 'border-bottom: 1px solid #cccccc;text-align: left; padding-left: 70px;', events: { onHideThisPopup: '' }, tap: function () { this.inherited(arguments); this.model.set('checked', !this.model.get('checked')); }, create: function () { this.inherited(arguments); this.setContent(this.model.get('name')); if (this.model.get('checked')) { this.addClass('active'); } else { this.removeClass('active'); } } }); /*scrollable table (body of modal)*/ enyo.kind({ name: 'OB.UI.ListBrands', classes: 'row-fluid', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, components: [{ classes: 'span12', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'brandslistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderLine: 'OB.UI.ListBrandsLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }], clearAction: function (inSender, inEvent) { this.brandsList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, i, j; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackBrands(dataBrands) { if (dataBrands && dataBrands.length > 0) { for (i = 0; i < dataBrands.length; i++) { for (j = 0; j < me.parent.parent.model.get('brandFilter').length; j++) { if (dataBrands.models[i].get('id') === me.parent.parent.model.get('brandFilter')[j].id) { dataBrands.models[i].set('checked', true); } } } me.brandsList.reset(dataBrands.models); } else { me.brandsList.reset(); } } OB.Dal.find(OB.Model.Brand, null, successCallbackBrands, errorCallback); return true; }, brandsList: null, init: function (model) { this.brandsList = new Backbone.Collection(); this.$.brandslistitemprinter.setCollection(this.brandsList); } }); enyo.kind({ name: 'OB.UI.ModalProductBrandTopHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onHideThisPopup: '', onSelectBrand: '', onSearchAction: '' }, components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ name: 'title', style: 'text-align: center; vertical-align: middle' }] }, { style: 'display: table-cell;', components: [{ name: 'doneBrandButton', kind: 'OB.UI.SmallButton', ontap: 'doneAction' }] }, { style: 'display: table-cell;', components: [{ classes: 'btnlink-gray', name: 'cancelBrandButton', kind: 'OB.UI.SmallButton', ontap: 'cancelAction' }] }] }], initComponents: function () { this.inherited(arguments); this.$.doneBrandButton.setContent(OB.I18N.getLabel('OBMOBC_LblDone')); this.$.cancelBrandButton.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); }, doneAction: function () { var selectedBrands = _.compact(this.parent.parent.parent.$.body.$.listBrands.brandsList.map(function (e) { return e; })); this.doSelectBrand({ value: selectedBrands }); this.doHideThisPopup(); }, cancelAction: function () { this.doHideThisPopup(); } }); /*Modal definiton*/ enyo.kind({ name: 'OB.UI.ModalProductBrand', topPosition: '170px', kind: 'OB.UI.Modal', published: { characteristic: null }, executeOnShow: function () { var i, j; this.$.header.parent.addStyles('padding: 0px; border-bottom: 1px solid #cccccc'); this.$.header.$.modalProductBrandTopHeader.$.title.setContent(OB.I18N.getLabel('OBMOBC_LblBrand')); this.waterfall('onSearchAction'); }, i18nHeader: '', body: { kind: 'OB.UI.ListBrands' }, initComponents: function () { this.inherited(arguments); this.$.closebutton.hide(); this.$.header.createComponent({ kind: 'OB.UI.ModalProductBrandTopHeader', style: 'border-bottom: 0px' }); }, init: function (model) { this.model = model; this.waterfall('onSetModel', { model: this.model }); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var ProductCategory = OB.Data.ExtensibleModel.extend({ modelName: 'ProductCategory', tableName: 'm_product_category', entityName: 'ProductCategory', source: 'org.openbravo.retail.posterminal.master.Category', dataLimit: 300, includeTerminalDate: true, createBestSellerCategory: function () { this.set('id', 'OBPOS_bestsellercategory'); this.set('searchKey', 'bestseller'); this.set('name', OB.I18N.getLabel('OBPOS_bestSellerCategory')); this.set('img', 'iconBestSellers'); this.set('_identifier', this.get('name')); } }); ProductCategory.addProperties([{ name: 'id', column: 'm_product_category_id', primaryKey: true, type: 'TEXT' }, { name: 'searchKey', column: 'value', type: 'TEXT' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: 'img', column: 'ad_image_id', type: 'TEXT' }, { name: '_identifier', column: '_identifier', type: 'TEXT' }]); OB.Data.Registry.registerModel(ProductCategory); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var Product = OB.Data.ExtensibleModel.extend({ modelName: 'Product', tableName: 'm_product', entityName: 'Product', source: 'org.openbravo.retail.posterminal.master.Product', dataLimit: 300, includeTerminalDate: true, initialize: function () { this.set('originalStandardPrice', this.get('standardPrice')); } }); Product.addProperties([{ name: 'id', column: 'm_product_id', primaryKey: true, type: 'TEXT' }, { name: 'searchkey', column: 'searchkey', filter: true, type: 'TEXT' }, { name: 'uPCEAN', column: 'upc', filter: true, type: 'TEXT' }, { name: 'uOM', column: 'c_uom_id', type: 'TEXT' }, { name: 'uOMsymbol', column: 'c_uom_symbol', type: 'TEXT' }, { name: 'productCategory', column: 'm_product_category_id', type: 'TEXT' }, { name: 'taxCategory', column: 'c_taxcategory_id', type: 'TEXT' }, { name: 'img', column: 'img', type: 'TEXT' }, { name: 'description', column: 'description', type: 'TEXT' }, { name: 'obposScale', column: 'em_obpos_scale', type: 'TEXT' }, { name: 'groupProduct', column: 'em_obpos_groupedproduct', type: 'TEXT' }, { name: 'stocked', column: 'stocked', type: 'TEXT' }, { name: 'showstock', column: 'em_obpos_showstock', type: 'TEXT' }, { name: 'isGeneric', column: 'isGeneric', type: 'TEXT' }, { name: 'generic_product_id', column: 'generic_product_id', type: 'TEXT' }, { name: 'brand', column: 'brand', type: 'TEXT' }, { name: 'characteristicDescription', column: 'characteristicDescription', type: 'TEXT' }, { name: 'showchdesc', column: 'showchdesc', type: 'TEXT' }, { name: 'bestseller', column: 'bestseller', type: 'TEXT' }, { name: 'ispack', column: 'ispack', type: 'TEXT' }, { name: 'listPrice', column: 'listPrice', type: 'NUMERIC' }, { name: 'standardPrice', column: 'standardPrice', type: 'NUMERIC' }, { name: 'priceLimit', column: 'priceLimit', type: 'NUMERIC' }, { name: 'cost', column: 'cost', type: 'NUMERIC' }, { name: 'algorithm', column: 'algorithm', type: 'TEXT' }, { name: '_identifier', column: '_identifier', filter: true, type: 'TEXT' }]); Product.addIndex([{ name: 'obpos_in_prodCat', columns: [{ name: 'm_product_category_id', sort: 'desc' }] }, { name: 'obpos_in_bestseller', columns: [{ name: 'bestseller', sort: 'asc' }] }, { name: 'obpos_in_upc', columns: [{ name: 'upc', sort: 'asc' }] }]); OB.Data.Registry.registerModel(Product); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _, OB */ (function () { var BusinessPartner = OB.Data.ExtensibleModel.extend({ modelName: 'BusinessPartner', tableName: 'c_bpartner', entityName: 'BusinessPartner', source: 'org.openbravo.retail.posterminal.master.BusinessPartner', dataLimit: 300, saveCustomer: function (silent) { var nameLength, newSk; if (!this.get("name")) { OB.UTIL.showWarning('Name is required for BPartner'); return false; } if (!this.get("locId")) { this.set('locId', OB.UTIL.get_UUID()); } if (!this.get("contactId")) { this.set('contactId', OB.UTIL.get_UUID()); } if (!this.get('searchKey')) { nameLength = this.get('name').toString().length; newSk = this.get('name'); if (nameLength > 30) { newSk = this.get('name').substring(0, 30); } this.set('searchKey', newSk); } this.set('_identifier', this.get('name')); this.trigger('customerSaved'); //datacustomersave will catch this event and save this locally with changed = 'Y' //Then it will try to send to the backend return true; }, loadById: function (CusId, userCallback) { //search data in local DB and load it to this var me = this, criteria = { id: CusId }; OB.Dal.find(OB.Model.BusinessPartner, criteria, function (customerCol) { //OB.Dal.find success var successCallback, errorCallback; if (!customerCol || customerCol.length === 0) { me.clearModelWith(null); userCallback(me); } else { me.clearModelWith(customerCol.at(0)); userCallback(me); } }); }, loadByModel: function (cusToLoad) { //copy data from model to this }, newCustomer: function () { //set values of new attrs in bp model //this values will be copied to the created one //in the next instruction this.trigger('beforeChangeCustomerForNewOne', this); this.clearModelWith(null); }, clearModelWith: function (cusToLoad) { var me = this, undf; if (cusToLoad === null) { this.set('id', null); this.set('searchKey', null); this.set('name', null); this.set('description', null); this.set('taxID', null); this.set('taxCategory', null); this.set('paymentMethod', OB.POS.modelterminal.get('terminal').defaultbp_paymentmethod); this.set('businessPartnerCategory', OB.POS.modelterminal.get('terminal').defaultbp_bpcategory); this.set('businessPartnerCategory_name', OB.POS.modelterminal.get('terminal').defaultbp_bpcategory_name); this.set('paymentTerms', OB.POS.modelterminal.get('terminal').defaultbp_paymentterm); this.set('invoiceTerms', OB.POS.modelterminal.get('terminal').defaultbp_invoiceterm); this.set('priceList', OB.POS.modelterminal.get('pricelist').id); this.set('country', OB.POS.modelterminal.get('terminal').defaultbp_bpcountry); this.set('countryName', OB.POS.modelterminal.get('terminal').defaultbp_bpcountry_name); this.set('client', OB.POS.modelterminal.get('terminal').client); this.set('organization', OB.POS.modelterminal.get('terminal').defaultbp_bporg); this.set('locId', null); this.set('locName', null); this.set('creditLimit', OB.DEC.Zero); this.set('creditUsed', OB.DEC.Zero); this.set('_identifier', null); this.set('postalCode', null); this.set('contactId', null); this.set('cityName', null); this.set('phone', null); this.set('email', null); this.set('taxExempt', null); } else { _.each(_.keys(cusToLoad.attributes), function (key) { if (cusToLoad.get(key) !== undf) { if (cusToLoad.get(key) === null) { me.set(key, null); } else if (cusToLoad.get(key).at) { //collection me.get(key).reset(); cusToLoad.get(key).forEach(function (elem) { me.get(key).add(elem); }); } else { //property me.set(key, cusToLoad.get(key)); } } }); } }, loadByJSON: function (obj) { var me = this, undf; _.each(_.keys(me.attributes), function (key) { if (obj[key] !== undf) { if (obj[key] === null) { me.set(key, null); } else { me.set(key, obj[key]); } } }); }, serializeToJSON: function () { return JSON.parse(JSON.stringify(this.toJSON())); } }); BusinessPartner.addProperties([{ name: 'id', column: 'c_bpartner_id', primaryKey: true, type: 'TEXT' }, { name: 'organization', column: 'ad_org_id', type: 'TEXT' }, { name: 'searchKey', column: 'value', type: 'TEXT' }, { name: '_identifier', column: '_identifier', filter: true, type: 'NUMERIC' }, { name: 'name', column: 'name', type: 'TEXT' }, { name: 'description', column: 'description', type: 'TEXT' }, { name: 'taxID', column: 'taxID', filter: true, type: 'TEXT' }, { name: 'taxCategory', column: 'so_bp_taxcategory_id', type: 'TEXT' }, { name: 'paymentMethod', column: 'FIN_Paymentmethod_ID', type: 'TEXT' }, { name: 'paymentTerms', column: 'c_paymentterm_id', type: 'TEXT' }, { name: 'priceList ', column: 'm_pricelist_id', type: 'TEXT ' }, { name: 'invoiceTerms', column: 'invoicerule', type: 'TEXT' }, { name: 'locId', column: 'c_bpartnerlocation_id', type: 'TEXT' }, { name: 'locName', column: 'c_bpartnerlocation_name', type: 'TEXT' }, { name: 'postalCode', column: 'postalCode', type: 'TEXT' }, { name: 'cityName', column: 'cityName', type: 'TEXT' }, { name: 'countryName', column: 'countryName', type: 'TEXT' }, { name: 'contactId', column: 'ad_user_id', type: 'TEXT' }, { name: 'phone', column: 'phone', filter: true, type: 'TEXT' }, { name: 'email', column: 'email', filter: true, type: 'TEXT' }, { name: 'businessPartnerCategory', column: 'c_bp_group_id', type: 'TEXT' }, { name: 'businessPartnerCategory_name', column: 'c_bp_group_name', type: 'TEXT' }, { name: 'creditLimit', column: 'creditLimit', type: 'NUMERIC' }, { name: 'creditUsed', column: 'creditUsed', type: 'NUMERIC' }, { name: 'taxExempt', column: 'taxExempt', type: 'TEXT' }]); BusinessPartner.addIndex([{ name: 'bp_filter_idx', columns: [{ name: '_filter', sort: 'desc' }] }, { name: 'bp_name_idx', columns: [{ name: 'name', sort: 'desc' }] }]); OB.Data.Registry.registerModel(BusinessPartner); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var DocumentSequence = Backbone.Model.extend({ modelName: 'DocumentSequence', tableName: 'c_document_sequence', entityName: '', source: '', local: true, properties: ['id', 'posSearchKey', 'documentSequence', 'quotationDocumentSequence'], propertyMap: { 'id': 'c_document_sequence_id', 'posSearchKey': 'pos_search_key', 'documentSequence': 'document_sequence', 'quotationDocumentSequence': 'quotation_document_sequence' }, defaults: { documentSequence: 0, quotationDocumentSequence: 0 }, createStatement: 'CREATE TABLE IF NOT EXISTS c_document_sequence (c_document_sequence_id TEXT PRIMARY KEY, pos_search_key TEXT, document_sequence NUMBER, quotation_document_sequence NUMBER)', dropStatement: 'DROP TABLE IF EXISTS c_document_sequence', insertStatement: 'INSERT INTO c_document_sequence(c_document_sequence_id, pos_search_key, document_sequence, quotation_document_sequence) VALUES (?,?,?,?)' }); OB.Data.Registry.registerModel(DocumentSequence); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, _, Backbone */ (function () { var taxRate = OB.Data.ExtensibleModel.extend({ modelName: 'TaxRate', generatedStructure: true, entityName: 'FinancialMgmtTaxRate', source: 'org.openbravo.retail.posterminal.master.TaxRate' }); OB.Data.Registry.registerModel(taxRate); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, _, Backbone */ (function () { var taxZone = OB.Data.ExtensibleModel.extend({ modelName: 'TaxZone', tableName: 'c_tax_zone', entityName: 'FinancialMgmtTaxZone', source: 'org.openbravo.retail.posterminal.master.TaxZone' }); taxZone.addProperties([{ name: 'id', column: 'c_tax_zone_id', primaryKey: true, type: 'TEXT' }, { name: 'tax', column: 'c_tax_id', filter: true, type: 'TEXT' }, { name: 'fromCountry', column: 'from_country_id', filter: true, type: 'TEXT' }, { name: 'fromRegion', column: 'from_region_id', type: 'TEXT' }, { name: 'destinationCountry', column: 'to_country_id', type: 'TEXT' }, { name: 'destinationRegion', column: 'to_region_id', type: 'TEXT' }]); taxZone.addIndex([{ name: 'obpos_in_taxZone', columns: [{ name: 'c_tax_id', sort: 'asc' }] }]); OB.Data.Registry.registerModel(taxZone); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, $, _, Backbone */ (function () { var promotions = Backbone.Model.extend({ modelName: 'Discount', generatedStructure: true, entityName: 'PricingAdjustment', source: 'org.openbravo.retail.posterminal.master.Discount' }); var promotionsBP = Backbone.Model.extend({ modelName: 'DiscountFilterBusinessPartner', generatedStructure: true, entityName: 'PricingAdjustmentBusinessPartner', source: 'org.openbravo.retail.posterminal.master.DiscountFilterBusinessPartner' }); var promotionsBPCategory = Backbone.Model.extend({ modelName: 'DiscountFilterBusinessPartnerGroup', generatedStructure: true, entityName: 'PricingAdjustmentBusinessPartnerGroup', source: 'org.openbravo.retail.posterminal.master.DiscountFilterBusinessPartnerGroup' }); var promotionsProduct = Backbone.Model.extend({ modelName: 'DiscountFilterProduct', generatedStructure: true, entityName: 'PricingAdjustmentProduct', source: 'org.openbravo.retail.posterminal.master.DiscountFilterProduct' }); var promotionsProductCategory = Backbone.Model.extend({ modelName: 'DiscountFilterProductCategory', generatedStructure: true, entityName: 'PricingAdjustmentProductCategory', source: 'org.openbravo.retail.posterminal.master.DiscountFilterProductCategory' }); var promotionsRole = Backbone.Model.extend({ modelName: 'DiscountFilterRole', generatedStructure: true, entityName: 'OBDISC_Offer_Role', source: 'org.openbravo.retail.posterminal.master.DiscountFilterRole' }); OB.Data.Registry.registerModel(promotions); OB.Data.Registry.registerModel(promotionsBP); OB.Data.Registry.registerModel(promotionsBPCategory); OB.Data.Registry.registerModel(promotionsProduct); OB.Data.Registry.registerModel(promotionsProductCategory); OB.Data.Registry.registerModel(promotionsRole); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone*/ /** * Local model to keep the supervisor and which type of approval can do each of them */ OB.Data.Registry.registerModel(Backbone.Model.extend({ modelName: 'Supervisor', tableName: 'supervisor', entityName: 'Supervisor', properties: ['id', 'name', 'password', 'permissions', 'created', '_identifier', '_idx'], propertyMap: { 'id': 'supervisor_id', 'name': 'name', 'password': 'password', 'permissions': 'permissions', 'created': 'created', '_identifier': '_identifier', '_idx': '_idx' }, createStatement: 'CREATE TABLE IF NOT EXISTS supervisor (supervisor_id TEXT PRIMARY KEY , name TEXT , password TEXT , permissions TEXT, created TEXT, _identifier TEXT , _idx NUMERIC)', dropStatement: 'DROP TABLE IF EXISTS supervisor', insertStatement: 'INSERT INTO supervisor(supervisor_id, name, password, permissions, created, _identifier, _idx) VALUES (?, ?, ?, ?, ?, ?, ?)', updateStatement: '', local: true })); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global $, _ */ (function () { var PrintReceipt = function (model) { var terminal = OB.POS.modelterminal.get('terminal'); function dumyFunction() {} function extendHWResource(resource, template) { if (terminal[template + "IsPdf"] === 'true') { resource.ispdf = true; resource.printer = terminal[template + "Printer"]; var i = 0, subreports = []; while (terminal.hasOwnProperty(template + "Subrep" + i)) { subreports[i] = new OB.DS.HWResource(terminal[template + "Subrep" + i]); subreports[i].getData(dumyFunction); i++; } resource.subreports = subreports; resource.getData(function () {}); } } this.receipt = model.get('order'); this.multiOrders = model.get('multiOrders'); this.multiOrders.on('print', function (order, args) { this.print(order, args); }, this); this.receipt.on('print', function (order, args) { this.print(null, args); }, this); this.receipt.on('displayTotal', this.displayTotal, this); this.multiOrders.on('displayTotal', function () { this.displayTotalMultiorders(); }, this); this.templatereceipt = new OB.DS.HWResource(terminal.printTicketTemplate || OB.OBPOSPointOfSale.Print.ReceiptTemplate); extendHWResource(this.templatereceipt, "printTicketTemplate"); this.templateclosedreceipt = new OB.DS.HWResource(terminal.printClosedReceiptTemplate || OB.OBPOSPointOfSale.Print.ReceiptClosedTemplate); extendHWResource(this.templateclosedreceipt, "printClosedReceiptTemplate"); this.templateinvoice = new OB.DS.HWResource(terminal.printInvoiceTemplate || OB.OBPOSPointOfSale.Print.ReceiptTemplateInvoice); extendHWResource(this.templateinvoice, "printInvoiceTemplate"); this.templatereturn = new OB.DS.HWResource(terminal.printReturnTemplate || OB.OBPOSPointOfSale.Print.ReceiptTemplateReturn); extendHWResource(this.templatereturn, "printReturnTemplate"); this.templatereturninvoice = new OB.DS.HWResource(terminal.printReturnInvoiceTemplate || OB.OBPOSPointOfSale.Print.ReceiptTemplateReturnInvoice); extendHWResource(this.templatereturninvoice, "printReturnInvoiceTemplate"); this.templatelayaway = new OB.DS.HWResource(terminal.printLayawayTemplate || OB.OBPOSPointOfSale.Print.ReceiptTemplateLayaway); extendHWResource(this.templatelayaway, "printLayawayTemplate"); this.templatecashup = new OB.DS.HWResource(terminal.printCashUpTemplate || OB.OBPOSPointOfSale.Print.CashUpTemplate); extendHWResource(this.templatecashup, "printCashUpTemplate"); this.templategoodbye = new OB.DS.HWResource(terminal.printGoodByeTemplate || OB.OBPOSPointOfSale.Print.GoodByeTemplate); extendHWResource(this.templategoodbye, "printGoodByeTemplate"); this.templatewelcome = new OB.DS.HWResource(terminal.printWelcomeTemplate || OB.OBPOSPointOfSale.Print.WelcomeTemplate); extendHWResource(this.templatewelcome, "printWelcomeTemplate"); }; PrintReceipt.prototype.print = function (order, printargs) { printargs = printargs || {}; // Clone the receipt var receipt = new OB.Model.Order(), me = this, template; OB.UTIL.HookManager.executeHooks('OBPRINT_PrePrint', { forcePrint: printargs.forcePrint, offline: printargs.offline, order: order ? order : me.receipt, template: template, callback: printargs.callback }, function (args) { function printPDF(receipt, args) { OB.POS.hwserver._printPDF({ param: receipt.serializeToJSON(), mainReport: args.template, subReports: args.template.subreports }, function (result) { var myreceipt = receipt; if (result && result.exception) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_MsgHardwareServerNotAvailable'), OB.I18N.getLabel('OBPOS_MsgPrintAgain'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), action: function () { me.print(receipt, printargs); if (args.callback) { args.callback(); } return true; } }, { label: OB.I18N.getLabel('OBMOBC_LblCancel') }], { onHideFunction: function (dialog) { if (printargs.offline && OB.POS.modelterminal.get('terminal').printoffline) { OB.Dal.save(new OB.Model.OfflinePrinter({ data: result.data, sendfunction: '_sendPDF' })); } } }); } else { // Success. Try to print the pending receipts. OB.Model.OfflinePrinter.printPendingJobs(); if (args.callback) { args.callback(); } } }); } if (args.cancelOperation && args.cancelOperation === true) { if (args.callback) { args.callback(); } return true; } if (!_.isUndefined(args.order) && !_.isNull(args.order)) { receipt.clearWith(args.order); } else { receipt.clearWith(me.receipt); } if (args.forcedtemplate) { args.template = args.forcedtemplate; } else if (receipt.get('generateInvoice') && receipt.get('orderType') !== 2 && receipt.get('orderType') !== 3 && !receipt.get('isLayaway')) { if (receipt.get('orderType') === 1) { args.template = me.templatereturninvoice; } else { args.template = me.templateinvoice; } } else { if (receipt.get('isPaid')) { if (receipt.get('orderType') === 1) { args.template = me.templatereturn; } else { args.template = me.templateclosedreceipt; } } else { if (receipt.get('orderType') === 1) { args.template = me.templatereturn; } else if (receipt.get('orderType') === 2 || receipt.get('isLayaway') || receipt.get('orderType') === 3) { args.template = me.templatelayaway; } else { args.template = me.templatereceipt; } } } if (args.template.ispdf) { args.template.dateFormat = OB.Format.date; printPDF(receipt, args); if (receipt.get('orderType') === 1 && !OB.POS.modelterminal.hasPermission('OBPOS_print.once')) { printPDF(receipt, args); } } else { OB.POS.hwserver.print(args.template, { order: receipt }, function (result) { var myreceipt = receipt; if (result && result.exception) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_MsgHardwareServerNotAvailable'), OB.I18N.getLabel('OBPOS_MsgPrintAgain'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { me.print(receipt, printargs); return true; } }, { label: OB.I18N.getLabel('OBMOBC_LblCancel'), action: function () { if (args.callback) { args.callback(); } return true; } }], { onHideFunction: function (dialog) { if (printargs.offline && OB.POS.modelterminal.get('terminal').printoffline) { OB.Dal.save(new OB.Model.OfflinePrinter({ data: result.data, sendfunction: '_send' })); } if (args.callback) { args.callback(); } } }); } else { // Success. Try to print the pending receipts. OB.Model.OfflinePrinter.printPendingJobs(); if (args.callback) { args.callback(); } } }); if (!OB.POS.hwserver.url) { if (args.callback) { args.callback(); } } //Print again when it is a return and the preference is 'Y' or when one of the payments method has the print twice checked if ((receipt.get('orderType') === 1 && !OB.POS.modelterminal.hasPermission('OBPOS_print.once')) || _.filter(receipt.get('payments').models, function (iter) { if (iter.get('printtwice')) { return iter; } }).length > 0) { OB.POS.hwserver.print(args.template, { order: receipt }, function (result) { var myreceipt = receipt; if (result && result.exception) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_MsgHardwareServerNotAvailable'), OB.I18N.getLabel('OBPOS_MsgPrintAgain'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), action: function () { me.print(receipt, printargs); return true; } }, { label: OB.I18N.getLabel('OBMOBC_LblCancel') }], { onHideFunction: function (dialog) { if (printargs.offline && OB.POS.modelterminal.get('terminal').printoffline) { OB.Dal.save(new OB.Model.OfflinePrinter({ data: result.data, sendfunction: '_send' })); } } }); } else { // Success. Try to print the pending receipts. OB.Model.OfflinePrinter.printPendingJobs(); } }); } } }); }; PrintReceipt.prototype.displayTotal = function () { // Clone the receipt var receipt = new OB.Model.Order(); receipt.clearWith(this.receipt); this.template = new OB.DS.HWResource(OB.OBPOSPointOfSale.Print.DisplayTotal); OB.POS.hwserver.print(this.template, { order: receipt }); }; PrintReceipt.prototype.displayTotalMultiorders = function () { // Clone the receipt var multiOrders; multiOrders = this.multiOrders; this.template = new OB.DS.HWResource(OB.OBPOSPointOfSale.Print.DisplayTotal); OB.POS.hwserver.print(this.template, { order: multiOrders }); }; var PrintReceiptLine = function (receipt) { this.receipt = receipt; this.line = null; this.receipt.get('lines').on('selected', function (line) { if (this.receipt.get("isPaid") === true) { return; } if (this.line) { this.line.off('change', this.print); } this.line = line; if (this.line) { this.line.on('change', this.print, this); } this.print(); }, this); this.templateline = new OB.DS.HWResource(OB.OBPOSPointOfSale.Print.ReceiptLineTemplate); }; PrintReceiptLine.prototype.print = function () { if (this.line) { OB.POS.hwserver.print(this.templateline, { line: this.line }); } }; // Public object definition OB.OBPOSPointOfSale = OB.OBPOSPointOfSale || {}; OB.OBPOSPointOfSale.Print = OB.OBPOSPointOfSale.Print || {}; OB.OBPOSPointOfSale.Print.Receipt = PrintReceipt; OB.OBPOSPointOfSale.Print.ReceiptTemplate = '../org.openbravo.retail.posterminal/res/printreceipt.xml'; OB.OBPOSPointOfSale.Print.ReceiptClosedTemplate = '../org.openbravo.retail.posterminal/res/printclosedreceipt.xml'; OB.OBPOSPointOfSale.Print.ReceiptTemplateInvoice = '../org.openbravo.retail.posterminal/res/printinvoice.xml'; OB.OBPOSPointOfSale.Print.ReceiptTemplateReturn = '../org.openbravo.retail.posterminal/res/printreturn.xml'; OB.OBPOSPointOfSale.Print.ReceiptTemplateReturnInvoice = '../org.openbravo.retail.posterminal/res/printreturninvoice.xml'; OB.OBPOSPointOfSale.Print.ReceiptLine = PrintReceiptLine; OB.OBPOSPointOfSale.Print.ReceiptLineTemplate = '../org.openbravo.retail.posterminal/res/printline.xml'; OB.OBPOSPointOfSale.Print.ReceiptTemplateLayaway = '../org.openbravo.retail.posterminal/res/printlayaway.xml'; OB.OBPOSPointOfSale.Print.DisplayTotal = '../org.openbravo.retail.posterminal/res/displaytotal.xml'; OB.OBPOSPointOfSale.Print.CashUpTemplate = '../org.openbravo.retail.posterminal/res/printcashup.xml'; OB.OBPOSPointOfSale.Print.GoodByeTemplate = '../org.openbravo.retail.posterminal/res/goodbye.xml'; OB.OBPOSPointOfSale.Print.WelcomeTemplate = '../org.openbravo.retail.posterminal/res/welcome.xml'; }()); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global $ Backbone enyo _ localStorage */ OB.OBPOSPointOfSale = OB.OBPOSPointOfSale || {}; OB.OBPOSPointOfSale.Model = OB.OBPOSPointOfSale.Model || {}; OB.OBPOSPointOfSale.UI = OB.OBPOSPointOfSale.UI || {}; //Window model OB.OBPOSPointOfSale.Model.PointOfSale = OB.Model.TerminalWindowModel.extend({ models: [{ generatedModel: true, modelName: 'TaxRate' }, { generatedModel: true, modelName: 'TaxZone' }, OB.Model.Product, OB.Model.ProductCategory, OB.Model.BusinessPartner, OB.Model.BPCategory, OB.Model.BPLocation, OB.Model.Order, OB.Model.DocumentSequence, OB.Model.ChangedBusinessPartners, OB.Model.ChangedBPlocation, { generatedModel: true, modelName: 'Discount' }, { generatedModel: true, modelName: 'DiscountFilterBusinessPartner' }, { generatedModel: true, modelName: 'DiscountFilterBusinessPartnerGroup' }, { generatedModel: true, modelName: 'DiscountFilterProduct' }, { generatedModel: true, modelName: 'DiscountFilterProductCategory' }, { generatedModel: true, modelName: 'DiscountFilterRole' }, OB.Model.CurrencyPanel, OB.Model.SalesRepresentative, OB.Model.ProductCharacteristic, OB.Model.Brand, OB.Model.ProductChValue, OB.Model.ReturnReason, OB.Model.CashUp, OB.Model.OfflinePrinter, OB.Model.PaymentMethodCashUp, OB.Model.TaxCashUp], loadUnpaidOrders: function () { // Shows a modal window with the orders pending to be paid var orderlist = this.get('orderList'), model = this, criteria = { 'hasbeenpaid': 'N', 'session': OB.POS.modelterminal.get('session') }; OB.Dal.find(OB.Model.Order, criteria, function (ordersNotPaid) { //OB.Dal.find success var currentOrder = {}, loadOrderStr; OB.UTIL.HookManager.executeHooks('OBPOS_PreLoadUnpaidOrdersHook', { ordersNotPaid: ordersNotPaid, model: model }, function (args) { if (!args.ordersNotPaid || args.ordersNotPaid.length === 0) { // If there are no pending orders, // add an initial empty order orderlist.addFirstOrder(); } else { // The order object is stored in the json property of the row fetched from the database orderlist.reset(args.ordersNotPaid.models); // At this point it is sure that there exists at least one order // Function to continue of there is some error currentOrder = args.ordersNotPaid.models[0]; orderlist.load(currentOrder); loadOrderStr = OB.I18N.getLabel('OBPOS_Order') + currentOrder.get('documentNo') + OB.I18N.getLabel('OBPOS_Loaded'); OB.UTIL.showAlert.display(loadOrderStr, OB.I18N.getLabel('OBPOS_Info')); } }); }, function () { //OB.Dal.find error // If there is an error fetching the pending orders, // add an initial empty order orderlist.addFirstOrder(); }); }, loadCheckedMultiorders: function () { // Shows a modal window with the orders pending to be paid var checkedMultiOrders, multiOrderList = this.get('multiOrders').get('multiOrdersList'), criteria = { 'hasbeenpaid': 'N', 'session': OB.POS.modelterminal.get('session') }; OB.Dal.find(OB.Model.Order, criteria, function (possibleMultiOrder) { //OB.Dal.find success if (possibleMultiOrder && possibleMultiOrder.length > 0) { checkedMultiOrders = _.compact(possibleMultiOrder.map(function (e) { if (e.get('checked')) { return e; } })); //The order object is stored in the json property of the row fetched from the database multiOrderList.reset(checkedMultiOrders); } }, function () { // If there is an error fetching the checked orders of multiorders, //OB.Dal.find error }); }, isValidMultiOrderState: function () { if (this.get('leftColumnViewManager') && this.get('multiOrders')) { return this.get('leftColumnViewManager').isMultiOrder() && this.get('multiOrders').hasDataInList(); } return false; }, getPending: function () { if (this.get('leftColumnViewManager').isOrder()) { return this.get('order').getPending(); } else { return this.get('multiOrders').getPending(); } }, getChange: function () { if (this.get('leftColumnViewManager').isOrder()) { return this.get('order').getChange(); } else { return this.get('multiOrders').getChange(); } }, getTotal: function () { if (this.get('leftColumnViewManager').isOrder()) { return this.get('order').getTotal(); } else { return this.get('multiOrders').getTotal(); } }, getPayment: function () { if (this.get('leftColumnViewManager').isOrder()) { return this.get('order').getPayment(); } else { return this.get('multiOrders').getPayment(); } }, addPayment: function (payment) { var modelToIncludePayment; if (this.get('leftColumnViewManager').isOrder()) { modelToIncludePayment = this.get('order'); } else { modelToIncludePayment = this.get('multiOrders'); } modelToIncludePayment.addPayment(payment); }, init: function () { var receipt = new OB.Model.Order(), auxReceipt = new OB.Model.Order(), i, j, k, amtAux, amountToPay, ordersLength, multiOrders = new OB.Model.MultiOrders(), me = this, iter, isNew = false, discounts, ordersave, customersave, customeraddrsave, taxes, orderList, hwManager, ViewManager, LeftColumnViewManager, LeftColumnCurrentView, SyncReadyToSendFunction, auxReceiptList = []; function success() { return true; } function error() { OB.UTIL.showError('Error removing'); } this.set('filter', []); this.set('brandFilter', []); function searchCurrentBP() { var errorCallback = function (tx, error) { OB.UTIL.showError("OBDAL error while getting BP info: " + error); }; function successCallbackBPs(dataBps) { var partnerAddressId = OB.MobileApp.model.get('terminal').partnerAddress, successCallbackBPLoc; if (dataBps) { if (partnerAddressId && dataBps.get('locId') !== partnerAddressId) { // Set default location successCallbackBPLoc = function (bpLoc) { dataBps.set('locId', bpLoc.get('id')); dataBps.set('locName', bpLoc.get('name')); OB.POS.modelterminal.set('businessPartner', dataBps); me.loadUnpaidOrders(); }; OB.Dal.get(OB.Model.BPLocation, partnerAddressId, successCallbackBPLoc, errorCallback); } else { OB.POS.modelterminal.set('businessPartner', dataBps); me.loadUnpaidOrders(); } } } OB.Dal.get(OB.Model.BusinessPartner, OB.POS.modelterminal.get('businesspartner'), successCallbackBPs, errorCallback); } //Because in terminal we've the BP id and we want to have the BP model. //In this moment we can ensure data is already loaded in the local database searchCurrentBP(); ViewManager = Backbone.Model.extend({ defaults: { currentWindow: { name: 'mainSubWindow', params: [] } }, initialize: function () {} }); LeftColumnViewManager = Backbone.Model.extend({ defaults: { currentView: {} }, initialize: function () { this.on('change:currentView', function (changedModel) { localStorage.setItem('leftColumnCurrentView', JSON.stringify(changedModel.get('currentView'))); this.trigger(changedModel.get('currentView').name); }, this); }, setOrderMode: function (parameters) { this.set('currentView', { name: 'order', params: parameters }); localStorage.setItem('leftColumnCurrentView', JSON.stringify(this.get('currentView'))); }, isOrder: function () { if (this.get('currentView').name === 'order') { return true; } return false; }, setMultiOrderMode: function (parameters) { this.set('currentView', { name: 'multiorder', params: parameters }); }, isMultiOrder: function () { if (this.get('currentView').name === 'multiorder') { return true; } return false; } }); this.set('order', receipt); orderList = new OB.Collection.OrderList(receipt); this.set('orderList', orderList); this.set('customer', new OB.Model.BusinessPartner()); this.set('customerAddr', new OB.Model.BPLocation()); this.set('multiOrders', multiOrders); this.get('multiOrders').on('paymentAccepted', function () { OB.UTIL.showLoading(true); ordersLength = this.get('multiOrders').get('multiOrdersList').length; function readyToSendFunction() { //this function is executed when all orders are ready to be sent me.get('leftColumnViewManager').setOrderMode(); if (me.get('orderList').length > _.filter(me.get('multiOrders').get('multiOrdersList').models, function (order) { return !order.get('isLayaway'); }).length) { me.get('orderList').addNewOrder(); } } function prepareToSendCallback(order) { auxReceipt = new OB.Model.Order(); auxReceipt.clearWith(order); if (order.get('orderType') !== 2 && order.get('orderType') !== 3) { var negativeLines = _.filter(order.get('lines').models, function (line) { return line.get('qty') < 0; }).length; if (negativeLines === order.get('lines').models.length) { order.setOrderType('OBPOS_receipt.return', OB.DEC.One, { applyPromotions: false, saveOrder: false }); } else { order.setOrderType('', OB.DEC.Zero, { applyPromotions: false, saveOrder: false }); } } me.get('multiOrders').trigger('closed', order); me.get('multiOrders').trigger('print', order, { offline: true }); // to guaranty execution order SyncReadyToSendFunction(); auxReceiptList.push(auxReceipt); if (auxReceiptList.length === me.get('multiOrders').get('multiOrdersList').length) { OB.UTIL.cashUpReport(auxReceiptList); } } //this var is a function (copy of the above one) which is called by every items, but it is just executed once (when ALL items has called to it) SyncReadyToSendFunction = _.after(this.get('multiOrders').get('multiOrdersList').length, readyToSendFunction); for (j = 0; j < ordersLength; j++) { //Create the negative payment for change iter = this.get('multiOrders').get('multiOrdersList').at(j); amountToPay = !_.isUndefined(iter.get('amountToLayaway')) && !_.isNull(iter.get('amountToLayaway')) ? iter.get('amountToLayaway') : OB.DEC.sub(iter.get('gross'), iter.get('payment')); while (((_.isUndefined(iter.get('amountToLayaway')) || iter.get('amountToLayaway') > 0) && iter.get('gross') > iter.get('payment')) || (iter.get('amountToLayaway') > 0)) { for (i = 0; i < this.get('multiOrders').get('payments').length; i++) { var payment = this.get('multiOrders').get('payments').at(i), paymentMethod = OB.MobileApp.model.paymentnames[payment.get('kind')]; //FIXME:Change is always given back in store currency if (this.get('multiOrders').get('change') > 0 && paymentMethod.paymentMethod.iscash) { payment.set('origAmount', OB.DEC.sub(payment.get('origAmount'), this.get('multiOrders').get('change'))); this.get('multiOrders').set('change', OB.DEC.Zero); } if (payment.get('origAmount') <= amountToPay) { var bigDecAmount = new BigDecimal(String(OB.DEC.mul(payment.get('origAmount'), paymentMethod.mulrate))); iter.addPayment(new OB.Model.PaymentLine({ 'kind': payment.get('kind'), 'name': payment.get('name'), 'amount': OB.DEC.toNumber(bigDecAmount), 'rate': paymentMethod.rate, 'mulrate': paymentMethod.mulrate, 'isocode': paymentMethod.isocode, 'allowOpenDrawer': payment.get('allowopendrawer'), 'isCash': payment.get('iscash'), 'openDrawer': payment.get('openDrawer'), 'printtwice': payment.get('printtwice') })); if (!_.isUndefined(iter.get('amountToLayaway')) && !_.isNull(iter.get('amountToLayaway'))) { iter.set('amountToLayaway', OB.DEC.sub(iter.get('amountToLayaway'), payment.get('origAmount'))); } this.get('multiOrders').get('payments').remove(this.get('multiOrders').get('payments').at(i)); amountToPay = !_.isUndefined(iter.get('amountToLayaway')) && !_.isNull(iter.get('amountToLayaway')) ? iter.get('amountToLayaway') : OB.DEC.sub(iter.get('gross'), iter.get('payment')); } else { var bigDecAmountAux; if (j === this.get('multiOrders').get('multiOrdersList').length - 1 && !paymentMethod.paymentMethod.iscash) { bigDecAmountAux = new BigDecimal(String(payment.get('origAmount'))); amtAux = OB.DEC.toNumber(bigDecAmountAux); this.get('multiOrders').get('payments').at(i).set('origAmount', OB.DEC.sub(this.get('multiOrders').get('payments').at(i).get('origAmount'), payment.get('origAmount'))); } else { bigDecAmountAux = new BigDecimal(String(OB.DEC.mul(amountToPay, paymentMethod.mulrate))); amtAux = OB.DEC.toNumber(bigDecAmountAux); this.get('multiOrders').get('payments').at(i).set('origAmount', OB.DEC.sub(this.get('multiOrders').get('payments').at(i).get('origAmount'), amountToPay)); } iter.addPayment(new OB.Model.PaymentLine({ 'kind': payment.get('kind'), 'name': payment.get('name'), 'amount': amtAux, 'rate': paymentMethod.rate, 'mulrate': paymentMethod.mulrate, 'isocode': paymentMethod.isocode, 'allowOpenDrawer': payment.get('allowopendrawer'), 'isCash': payment.get('iscash'), 'openDrawer': payment.get('openDrawer'), 'printtwice': payment.get('printtwice') })); if (!_.isUndefined(iter.get('amountToLayaway')) && !_.isNull(iter.get('amountToLayaway'))) { iter.set('amountToLayaway', OB.DEC.sub(iter.get('amountToLayaway'), amtAux)); } amountToPay = !_.isUndefined(iter.get('amountToLayaway')) && !_.isNull(iter.get('amountToLayaway')) ? iter.get('amountToLayaway') : OB.DEC.sub(iter.get('gross'), iter.get('payment')); break; } } } iter.prepareToSend(prepareToSendCallback); } }, this); customersave = new OB.DATA.CustomerSave(this); customeraddrsave = new OB.DATA.CustomerAddrSave(this); this.set('leftColumnViewManager', new LeftColumnViewManager()); this.set('subWindowManager', new ViewManager()); discounts = new OB.DATA.OrderDiscount(receipt); ordersave = new OB.DATA.OrderSave(this); taxes = new OB.DATA.OrderTaxes(receipt); OB.POS.modelterminal.saveDocumentSequenceInDB(); OB.MobileApp.model.runSyncProcess(function () { me.loadCheckedMultiorders(); }, function () { me.loadCheckedMultiorders(); }); receipt.on('paymentAccepted', function () { receipt.prepareToSend(function () { //Create the negative payment for change var oldChange = receipt.get('change'); var clonedCollection = new Backbone.Collection(); if (receipt.get('orderType') !== 2 && receipt.get('orderType') !== 3) { var negativeLines = _.filter(receipt.get('lines').models, function (line) { return line.get('qty') < 0; }).length; if (negativeLines === receipt.get('lines').models.length) { receipt.setOrderType('OBPOS_receipt.return', OB.DEC.One, { applyPromotions: false, saveOrder: false }); } else { receipt.setOrderType('', OB.DEC.Zero, { applyPromotions: false, saveOrder: false }); } } if (!_.isUndefined(receipt.selectedPayment) && receipt.getChange() > 0) { var payment = OB.MobileApp.model.paymentnames[receipt.selectedPayment]; receipt.get('payments').each(function (model) { clonedCollection.add(new Backbone.Model(model.toJSON())); }); if (!payment.paymentMethod.iscash) { payment = OB.MobileApp.model.paymentnames[OB.POS.modelterminal.get('paymentcash')]; } if (receipt.get('payment') >= receipt.get('gross')) { receipt.addPayment(new OB.Model.PaymentLine({ 'kind': payment.payment.searchKey, 'name': payment.payment.commercialName, 'amount': OB.DEC.sub(0, OB.DEC.mul(receipt.getChange(), payment.mulrate)), 'rate': payment.rate, 'mulrate': payment.mulrate, 'isocode': payment.isocode, 'allowOpenDrawer': payment.paymentMethod.allowopendrawer, 'isCash': payment.paymentMethod.iscash, 'openDrawer': payment.paymentMethod.openDrawer, 'printtwice': payment.paymentMethod.printtwice })); } receipt.set('change', oldChange); receipt.trigger('closed', { callback: function () { receipt.get('payments').reset(); clonedCollection.each(function (model) { receipt.get('payments').add(new Backbone.Model(model.toJSON()), { silent: true }); }); receipt.trigger('print', null, { offline: true, callback: function () { orderList.deleteCurrent(true); } }); } }); } else { receipt.trigger('closed', { callback: function () { receipt.trigger('print', null, { offline: true, callback: function () { orderList.deleteCurrent(true); } }); } }); } }); }, this); receipt.on('paymentDone', function (openDrawer) { if (receipt.overpaymentExists()) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_OverpaymentWarningTitle'), OB.I18N.getLabel('OBPOS_OverpaymentWarningBody'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { if (openDrawer) { OB.POS.hwserver.openDrawer({ openFirst: false, receipt: receipt }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); } receipt.trigger('paymentAccepted'); } }, { label: OB.I18N.getLabel('OBMOBC_LblCancel') }]); } else if ((OB.DEC.abs(receipt.getPayment()) !== OB.DEC.abs(receipt.getGross())) && (!receipt.isLayaway() && !receipt.get('paidOnCredit'))) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_PaymentAmountDistinctThanReceiptAmountTitle'), OB.I18N.getLabel('OBPOS_PaymentAmountDistinctThanReceiptAmountBody'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { receipt.trigger('paymentAccepted'); } }, { label: OB.I18N.getLabel('OBMOBC_LblCancel') }]); } else { if (openDrawer) { OB.POS.hwserver.openDrawer({ openFirst: true, receipt: receipt }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); } receipt.trigger('paymentAccepted'); } }, this); this.get('multiOrders').on('paymentDone', function (openDrawer) { var me = this, paymentstatus = this.get('multiOrders'); if (OB.DEC.compare(OB.DEC.sub(paymentstatus.get('payment'), paymentstatus.get('total'))) > 0) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_OverpaymentWarningTitle'), OB.I18N.getLabel('OBPOS_OverpaymentWarningBody'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { if (openDrawer) { OB.POS.hwserver.openDrawer({ openFirst: false, receipt: me.get('multiOrders') }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); } me.get('multiOrders').trigger('paymentAccepted'); } }, { label: OB.I18N.getLabel('OBMOBC_LblCancel') }]); } else { if (openDrawer) { OB.POS.hwserver.openDrawer({ openFirst: true, receipt: me.get('multiOrders') }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); } this.get('multiOrders').trigger('paymentAccepted'); } }, this); this.printReceipt = new OB.OBPOSPointOfSale.Print.Receipt(this); this.printLine = new OB.OBPOSPointOfSale.Print.ReceiptLine(receipt); // Listening events that cause a discount recalculation receipt.get('lines').on('add change:qty change:price', function (line) { if (!receipt.get('isEditable')) { return; } //When we do not want to launch promotions process (Not apply or remove discounts) if (receipt.get('skipApplyPromotions') || line.get('skipApplyPromotions')) { return; } OB.Model.Discounts.applyPromotions(receipt, line); }, this); receipt.get('lines').on('remove', function () { if (!receipt.get('isEditable')) { return; } OB.Model.Discounts.applyPromotions(receipt); }); receipt.on('change:bp', function (line) { if (!receipt.get('isEditable') || receipt.get('lines').length === 0) { return; } OB.Model.Discounts.applyPromotions(receipt); }, this); receipt.on('voidLayaway', function () { var process = new OB.DS.Process('org.openbravo.retail.posterminal.ProcessVoidLayaway'), auxReceipt = new OB.Model.Order(); auxReceipt.clearWith(receipt); process.exec({ order: receipt }, function (data, message) { if (data && data.exception) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgErrorVoidLayaway')); } else { auxReceipt.calculateTaxes = receipt.calculateTaxes; auxReceipt.calculateTaxes(function () { auxReceipt.adjustPrices(); OB.UTIL.cashUpReport(auxReceipt); }); OB.Dal.remove(receipt, null, function (tx, err) { OB.UTIL.showError(err); }); receipt.trigger('print'); if (receipt.get('layawayGross')) { receipt.set('layawayGross', null); } orderList.deleteCurrent(); receipt.trigger('change:gross', receipt); OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgSuccessVoidLayaway')); } }, function () { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowRequiresOnline')); }); }, this); }, /** * This method is invoked before paying a ticket, it is intended to do global * modifications in the ticket with OBPOS_PrePaymentHook hook, after this hook * execution checkPaymentApproval is invoked * OBPOS_PrePaymentApproval can be used to ensure certain order within the * same hook */ completePayment: function () { var me = this; OB.UTIL.HookManager.executeHooks('OBPOS_PrePaymentHook', { context: this }, function () { OB.UTIL.HookManager.executeHooks('OBPOS_PrePaymentApproval', { context: me }, function () { me.checkPaymentApproval(); }); }); }, /** * Hooks for OBPOS_CheckPaymentApproval can modify args.approved to check if * payment is approved. In case value is true the process will continue, if not * it is aborted */ checkPaymentApproval: function () { var me = this; OB.UTIL.HookManager.executeHooks('OBPOS_CheckPaymentApproval', { approvals: [], context: this }, function (args) { var negativeLines = _.filter(me.get('order').get('lines').models, function (line) { return line.get('qty') < 0; }).length; if (negativeLines > 0 && !OB.POS.modelterminal.get('permissions')['OBPOS_approval.returns']) { args.approvals.push('OBPOS_approval.returns'); } if (args.approvals.length > 0) { OB.UTIL.Approval.requestApproval( me, args.approvals, function (approved, supervisor, approvalType) { if (approved) { me.trigger('approvalChecked', { approved: args.approved }); } }); } else { me.trigger('approvalChecked', { approved: true }); } }); }, /** * Approval final stage. Where approvalChecked event is triggered, with approved * property set to true or false regarding if approval was finally granted. In * case of granted approval, the approval is added to the order so it can be saved * in backend for audit purposes. */ approvedRequest: function (approved, supervisor, approvalType, callback) { var order = this.get('order'), newApprovals = [], approvals, approval, i, date; approvals = order.get('approvals') || []; if (!Array.isArray(approvalType)) { approvalType = [approvalType]; } _.each(approvals, function (appr) { var results; results = _.find(approvalType, function (apprType) { return apprType === appr.approvalType; }); if (_.isUndefined(results)) { newApprovals.push(appr); } }); if (approved) { date = new Date(); date = date.getTime(); for (i = 0; i < approvalType.length; i++) { approval = { approvalType: approvalType[i], userContact: supervisor.get('id'), created: (new Date()).getTime() }; newApprovals.push(approval); } order.set('approvals', newApprovals); } this.trigger('approvalChecked', { approved: approved }); if (enyo.isFunction(callback)) { callback(approved, supervisor, approvalType); } } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone _ */ (function () { OB = window.OB || {}; OB.OBPOSPointOfSale = OB.OBPOSPointOfSale || {}; OB.OBPOSPointOfSale.UsedModels = OB.OBPOSPointOfSale.UsedModels || {}; OB.OBPOSPointOfSale.UsedModels.LocalStock = Backbone.Model.extend({ defaults: { product: OB.Model.Product, qty: 0, warehouses: OB.OBPOSPointOfSale.UsedModels.WarehouseStockDetailList }, initialize: function (serverData) { var warehouses; if (serverData.product) { this.set('product', serverData.product); } this.set('qty', serverData.qty); warehouses = new OB.OBPOSPointOfSale.UsedModels.WarehouseStockDetailList(serverData.warehouses); this.set('warehouses', warehouses); }, getWarehouseById: function (warId) { return _.find(this.get('warehouses').models, function (whmodel) { if (whmodel.get('warehouseid') === warId) { return warId; } }); } }); OB.OBPOSPointOfSale.UsedModels.WarehouseStockDetail = Backbone.Model.extend({ defaults: { warehouseid: null, warehousename: null, warehouseqty: 0, bins: OB.OBPOSPointOfSale.UsedModels.BinStockDetailList }, initialize: function (warehouse) { var bins; bins = new OB.OBPOSPointOfSale.UsedModels.BinStockDetailList(warehouse.bins); this.set('warehouseid', warehouse.warehouseid); this.set('warehousename', warehouse.warehousename); this.set('warehouseqty', warehouse.warehouseqty); this.set('bins', bins); } }); OB.OBPOSPointOfSale.UsedModels.BinStockDetail = Backbone.Model.extend({ defaults: { binid: null, binname: null, binqty: 0 }, initialize: function (bin) { this.set('binid', bin.binid); this.set('binname', bin.binname); this.set('binqty', bin.binqty); } }); OB.OBPOSPointOfSale.UsedModels.WarehouseStockDetailList = Backbone.Collection.extend({ model: OB.OBPOSPointOfSale.UsedModels.WarehouseStockDetail }); OB.OBPOSPointOfSale.UsedModels.BinStockDetailList = Backbone.Collection.extend({ model: OB.OBPOSPointOfSale.UsedModels.BinStockDetail }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { OB = window.OB || {}; OB.OBPOSPointOfSale = OB.OBPOSPointOfSale || {}; OB.OBPOSPointOfSale.UsedModels = OB.OBPOSPointOfSale.UsedModels || {}; OB.OBPOSPointOfSale.UsedModels.OtherStoresWarehousesStock = Backbone.Model.extend({ defaults: { product: OB.Model.Product, qty: 0, organizations: OB.OBPOSPointOfSale.UsedModels.OrganizationStockList }, initialize: function (serverData) { var organizations; if (serverData.product) { this.set('product', serverData.product); } this.set('qty', serverData.qty); organizations = new OB.OBPOSPointOfSale.UsedModels.OrganizationStockList(serverData.organizations); this.set('organizations', organizations); } }); OB.OBPOSPointOfSale.UsedModels.OrganizationStock = Backbone.Model.extend({ defaults: { organizationid: null, organizationname: null, organizationqty: 0, warehouses: OB.OBPOSPointOfSale.UsedModels.OrganizationWarehousesList }, initialize: function (organization) { var warehouses; warehouses = new OB.OBPOSPointOfSale.UsedModels.OrganizationWarehousesList(organization.warehouses); this.set('organizationid', organization.organizationid); this.set('organizationname', organization.organizationname); this.set('organizationqty', organization.organizationqty); this.set('warehouses', warehouses); } }); OB.OBPOSPointOfSale.UsedModels.OrganizationWarehouses = Backbone.Model.extend({ defaults: { warehouseid: null, warehousename: null, warehouseqty: 0 }, initialize: function (warehouse) { this.set('warehouseid', warehouse.warehouseid); this.set('warehousename', warehouse.warehousename); this.set('warehouseqty', warehouse.warehouseqty); } }); OB.OBPOSPointOfSale.UsedModels.OrganizationStockList = Backbone.Collection.extend({ model: OB.OBPOSPointOfSale.UsedModels.OrganizationStock }); OB.OBPOSPointOfSale.UsedModels.OrganizationWarehousesList = Backbone.Collection.extend({ model: OB.OBPOSPointOfSale.UsedModels.OrganizationWarehouses }); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, Backbone, enyo, $, confirm, _, localStorage */ // Point of sale main window view enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.PointOfSale', kind: 'OB.UI.WindowView', windowmodel: OB.OBPOSPointOfSale.Model.PointOfSale, tag: 'section', handlers: { onAddProduct: 'addProductToOrder', onViewProductDetails: 'viewProductDetails', onCloseProductDetailsView: 'showOrder', onCancelReceiptToInvoice: 'cancelReceiptToInvoice', onReceiptToInvoice: 'receiptToInvoice', onCreateQuotation: 'createQuotation', onCreateOrderFromQuotation: 'createOrderFromQuotation', onShowCreateOrderPopup: 'showCreateOrderPopup', onReactivateQuotation: 'reactivateQuotation', onShowReactivateQuotation: 'showReactivateQuotation', onRejectQuotation: 'rejectQuotation', onQuotations: 'quotations', onShowDivText: 'showDivText', onAddNewOrder: 'addNewOrder', onDeleteOrder: 'deleteCurrentOrder', onTabChange: 'tabChange', onDeleteLine: 'deleteLine', onEditLine: 'editLine', onReturnLine: 'returnLine', onExactPayment: 'exactPayment', onRemovePayment: 'removePayment', onChangeCurrentOrder: 'changeCurrentOrder', onChangeBusinessPartner: 'changeBusinessPartner', onPrintReceipt: 'printReceipt', onBackOffice: 'backOffice', onPaidReceipts: 'paidReceipts', onChangeSubWindow: 'changeSubWindow', onShowLeftSubWindow: 'showLeftSubWindow', onCloseLeftSubWindow: 'showOrder', onSetProperty: 'setProperty', onSetLineProperty: 'setLineProperty', onSetReceiptsList: 'setReceiptsList', onShowReceiptProperties: 'showModalReceiptProperties', onDiscountsMode: 'discountsMode', onDiscountsModeFinished: 'discountsModeFinished', onDisableLeftToolbar: 'leftToolbarDisabled', onDisableBPSelection: 'BPSelectionDisabled', onDisableNewBP: 'newBPDisabled', onDisableNewBPLoc: 'newBPLocDisabled', onDisableOrderSelection: 'orderSelectionDisabled', onDisableKeyboard: 'keyboardDisabled', onDiscountsModeKeyboard: 'keyboardOnDiscountsMode', onCheckAllTicketLines: 'allTicketLinesChecked', onSetDiscountQty: 'discountQtyChanged', onLineChecked: 'checkedLine', onStatusChanged: 'statusChanged', onLayaways: 'layaways', onChangeSalesRepresentative: 'changeSalesRepresentative', onMultiOrders: 'multiOrders', onSelectMultiOrders: 'selectMultiOrders', onRemoveMultiOrders: 'removeMultiOrders', onRightToolDisabled: 'rightToolbarDisabled', onSelectCharacteristicValue: 'selectCharacteristicValue', onSelectBrand: 'selectBrand', onShowLeftHeader: 'doShowLeftHeader', onWarehouseSelected: 'warehouseSelected', onClearUserInput: 'clearUserInput' }, events: { onShowPopup: '', onButtonStatusChanged: '' }, components: [{ name: 'otherSubWindowsContainer', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.ModalConfigurationRequiredForCreateCustomers', name: 'modalConfigurationRequiredForCreateNewCustomers' }, { kind: 'OB.OBPOSPointOfSale.UI.customers.cas', name: 'customerAdvancedSearch' }, { kind: 'OB.OBPOSPointOfSale.UI.customers.newcustomer', name: 'customerCreateAndEdit' }, { kind: 'OB.OBPOSPointOfSale.UI.customers.editcustomer', name: 'customerView' }, { kind: 'OB.OBPOSPointOfSale.UI.customeraddr.cas', name: 'customerAddressSearch' }, { kind: 'OB.OBPOSPointOfSale.UI.customeraddr.newcustomeraddr', name: 'customerAddrCreateAndEdit' }, { kind: 'OB.OBPOSPointOfSale.UI.customeraddr.editcustomeraddr', name: 'customerAddressView' }, { kind: 'OB.UI.ModalDeleteReceipt', name: 'modalConfirmReceiptDelete' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalProductCannotBeGroup', name: 'modalProductCannotBeGroup' }, { kind: 'OB.UI.Modalnoteditableorder', name: 'modalNotEditableOrder' }, { kind: 'OB.UI.ModalNotEditableLine', name: 'modalNotEditableLine' }, { kind: 'OB.UI.ModalBusinessPartners', name: "modalcustomer" }, { kind: 'OB.UI.ModalBPLocation', name: "modalcustomeraddress" }, { kind: 'OB.UI.ModalReceipts', name: 'modalreceipts' }, { kind: 'OB.UI.ModalPaidReceipts', name: 'modalPaidReceipts' }, { kind: 'OB.UI.ModalMultiOrders', name: 'modalMultiOrders' }, { kind: 'OB.UI.ModalCreateOrderFromQuotation', name: 'modalCreateOrderFromQuotation' }, { kind: 'OB.UI.ModalReactivateQuotation', name: 'modalReactivateQuotation' }, { kind: 'OB.UI.ModalReceiptPropertiesImpl', name: 'receiptPropertiesDialog' }, { kind: 'OB.UI.ModalReceiptLinesPropertiesImpl', name: "receiptLinesPropertiesDialog" }, { kind: 'OB.UI.ModalPayment', name: "modalpayment" }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalConfigurationRequiredForCrossStore', name: 'modalConfigurationRequiredForCrossStore' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore', name: 'modalLocalStock' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStoreClickable', name: 'modalLocalStockClickable' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInOtherStores', name: 'modalStockInOtherStores' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.modalEnoughCredit', name: 'modalEnoughCredit' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.modalNotEnoughCredit', name: 'modalNotEnoughCredit' }, { kind: 'OB.UI.ValidateAction', name: 'modalValidateAction' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.modalDiscountNeedQty', name: 'modalDiscountNeedQty' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.modalNotValidValueForDiscount', name: 'modalNotValidValueForDiscount' }, { kind: 'OB.UI.ModalSalesRepresentative', name: "modalsalesrepresentative" }, { kind: 'OB.UI.ModalMultiOrdersLayaway', name: "modalmultiorderslayaway" }, { kind: 'OB.UI.ModalProductCharacteristic', name: "modalproductcharacteristic" }, { kind: 'OB.UI.ModalProductBrand', name: "modalproductbrand" }] }, { name: 'mainSubWindow', isMainSubWindow: true, components: [{ kind: 'OB.UI.MultiColumn', name: 'multiColumn', handlers: { onChangeTotal: 'processChangeTotal' }, leftToolbar: { kind: 'OB.OBPOSPointOfSale.UI.LeftToolbarImpl', name: 'leftToolbar', showMenu: true, showWindowsMenu: true }, leftPanel: { name: 'leftPanel', style: 'max-height: 622px;', components: [{ classes: 'span12', kind: 'OB.OBPOSPointOfSale.UI.LeftHeader', style: 'height: 35px;', name: 'divHeader' }, { classes: 'span12', kind: 'OB.OBPOSPointOfSale.UI.ReceiptView', name: 'receiptview', init: function (model) { this.model = model; this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { this.setShowing(changedModel.isOrder()); }, this); // this.model.get('multiOrders').on('change:isMultiOrders', function () { // this.setShowing(!this.model.get('multiOrders').get('isMultiOrders')); // }, this); } }, { classes: 'span12', kind: 'OB.OBPOSPointOfSale.UI.MultiReceiptView', name: 'multireceiptview', showing: false, init: function (model) { this.model = model; this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { this.setShowing(changedModel.isMultiOrder()); }, this); // this.model.get('multiOrders').on('change:isMultiOrders', function () { // this.setShowing(this.model.get('multiOrders').get('isMultiOrders')); // }, this); } }, { name: 'leftSubWindowsContainer', components: [{ classes: 'span12', kind: 'OB.OBPOSPointOfSale.UI.ProductDetailsView', name: 'productdetailsview' }] }] }, rightToolbar: { kind: 'OB.OBPOSPointOfSale.UI.RightToolbarImpl', name: 'rightToolbar' }, rightPanel: { name: 'keyboardTabsPanel', components: [{ classes: 'span12', components: [{ kind: 'OB.OBPOSPointOfSale.UI.RightToolbarPane', name: 'toolbarpane' }, { kind: 'OB.OBPOSPointOfSale.UI.KeyboardOrder', name: 'keyboard' }] }] }, processChangeTotal: function (inSender, inEvent) { this.waterfall('onChangedTotal', { newTotal: inEvent.newTotal }); } }] }], classModel: new Backbone.Model(), printReceipt: function () { if (OB.POS.modelterminal.hasPermission('OBPOS_print.receipt')) { if (this.model.get('leftColumnViewManager').isOrder()) { var receipt = this.model.get('order'); if (receipt.get("isPaid")) { OB.UTIL.HookManager.executeHooks('OBPOS_PrePrintPaidReceipt', { context: this, receipt: this.model.get('order') }, function (args) { if (args && args.cancelOperation && args.cancelOperation === true) { return; } receipt.trigger('print', null, { force: true }); }); return; } receipt.calculateTaxes(function () { receipt.trigger('print', null, { force: true }); }); return; } if (this.model.get('leftColumnViewManager').isMultiOrder()) { _.each(this.model.get('multiOrders').get('multiOrdersList').models, function (order) { this.model.get('multiOrders').trigger('print', order, { force: true }); }, this); } } }, paidReceipts: function (inSender, inEvent) { this.$.modalPaidReceipts.setParams(inEvent); this.$.modalPaidReceipts.waterfall('onClearAction'); this.doShowPopup({ popup: 'modalPaidReceipts' }); return true; }, quotations: function (inSender, inEvent) { this.$.modalPaidReceipts.setParams({ isQuotation: true }); this.$.modalPaidReceipts.waterfall('onClearAction'); this.doShowPopup({ popup: 'modalPaidReceipts' }); }, backOffice: function (inSender, inEvent) { if (inEvent.url) { window.open(inEvent.url, '_blank'); } }, addNewOrder: function (inSender, inEvent) { this.$.receiptPropertiesDialog.resetProperties(); this.model.get('orderList').addNewOrder(); return true; }, deleteCurrentOrder: function (inSender, inEvent) { function removeOrder(context) { if (context.model.get('order').get('id')) { context.model.get('orderList').saveCurrent(); OB.Dal.remove(context.model.get('orderList').current, null, null); } context.model.get('orderList').deleteCurrent(); } if (inEvent && inEvent.notSavedOrder === true) { OB.UTIL.HookManager.executeHooks('OBPOS_PreDeleteCurrentOrder', { context: this, receipt: this.model.get('order') }, function (args) { if (args && args.cancelOperation && args.cancelOperation === true) { return; } removeOrder(args.context); }); } else { removeOrder(this); } return true; }, addProductToOrder: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } if (inEvent.ignoreStockTab) { this.showOrder(inSender, inEvent); } else { if (inEvent.product.get('showstock') && !inEvent.product.get('ispack') && OB.POS.modelterminal.get('connectedToERP')) { inEvent.leftSubWindow = OB.OBPOSPointOfSale.UICustomization.stockLeftSubWindow; this.showLeftSubWindow(inSender, inEvent); if (enyo.Panels.isScreenNarrow()) { this.$.multiColumn.switchColumn(); } return true; } else { this.showOrder(inSender, inEvent); } } OB.UTIL.HookManager.executeHooks('OBPOS_PreAddProductToOrder', { context: this, receipt: this.model.get('order'), productToAdd: inEvent.product, qtyToAdd: inEvent.qty, options: inEvent.options, attrs: inEvent.attrs }, function (args) { if (args.cancelOperation && args.cancelOperation === true) { return true; } args.context.model.get('order').addProduct(args.productToAdd, args.qtyToAdd, args.options, args.attrs); args.context.model.get('orderList').saveCurrent(); }); return true; }, showOrder: function (inSender, inEvent) { var allHidden = true; enyo.forEach(this.$.multiColumn.$.leftPanel.$.leftSubWindowsContainer.getControls(), function (component) { if (component.showing === true) { if (component.mainBeforeSetHidden) { if (!component.mainBeforeSetHidden(inEvent)) { allHidden = false; return false; } else { component.setShowing(false); } } } }, this); if (allHidden) { this.$.multiColumn.$.leftPanel.$.receiptview.setShowing(true); } }, showLeftSubWindow: function (inSender, inEvent) { if (this.$.multiColumn.$.leftPanel.$[inEvent.leftSubWindow]) { if (this.$.multiColumn.$.leftPanel.$[inEvent.leftSubWindow].mainBeforeSetShowing) { var allHidden = true; enyo.forEach(this.$.multiColumn.$.leftPanel.getControls(), function (component) { if (component.showing === true) { if (component.mainBeforeSetHidden) { if (!component.mainBeforeSetHidden(inEvent)) { allHidden = false; return false; } } } }, this); if (this.$.multiColumn.$.leftPanel.$[inEvent.leftSubWindow].mainBeforeSetShowing(inEvent) && allHidden) { this.$.multiColumn.$.leftPanel.$.receiptview.setShowing(false); this.$.multiColumn.$.leftPanel.$[inEvent.leftSubWindow].setShowing(true); } } } }, viewProductDetails: function (inSender, inEvent) { this.$.multiColumn.$.leftPanel.$.receiptview.applyStyle('display', 'none'); this.$.productdetailsview.updateProduct(inEvent.product); this.$.productdetailsview.applyStyle('display', 'inline'); return true; }, changeBusinessPartner: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } this.model.get('order').setBPandBPLoc(inEvent.businessPartner, false, true); this.model.get('orderList').saveCurrent(); return true; }, receiptToInvoice: function () { if (this.model.get('leftColumnViewManager').isOrder()) { if (this.model.get('order').get('isEditable') === false && !this.model.get('order').get('isLayaway')) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } this.model.get('order').setOrderInvoice(); this.model.get('orderList').saveCurrent(); return true; } if (this.model.get('leftColumnViewManager').isMultiOrder()) { this.model.get('multiOrders').toInvoice(true); } }, createQuotation: function () { this.model.get('orderList').addNewQuotation(); return true; }, createOrderFromQuotation: function () { this.model.get('order').createOrderFromQuotation(); this.model.get('orderList').saveCurrent(); return true; }, showReactivateQuotation: function () { this.doShowPopup({ popup: 'modalReactivateQuotation' }); }, reactivateQuotation: function () { this.model.get('order').reactivateQuotation(); this.model.get('orderList').saveCurrent(); return true; }, rejectQuotation: function () { this.model.get('order').rejectQuotation(); this.model.get('orderList').saveCurrent(); return true; }, showDivText: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false && !this.model.get('order').get('isLayaway')) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } //Void Layaway must block keyboard actions if (inEvent.orderType === 3) { this.$.multiColumn.$.rightPanel.$.keyboard.setStatus(''); } this.model.get('order').setOrderType(inEvent.permission, inEvent.orderType); this.model.get('orderList').saveCurrent(); return true; }, cancelReceiptToInvoice: function (inSender, inEvent) { if (this.model.get('leftColumnViewManager').isOrder()) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } this.model.get('order').resetOrderInvoice(); this.model.get('orderList').saveCurrent(); return true; } if (this.model.get('leftColumnViewManager').isMultiOrder()) { if (this.model.get('leftColumnViewManager').isMultiOrder()) { this.model.get('multiOrders').toInvoice(false); } } }, checkedLine: function (inSender, inEvent) { if (inEvent.originator.kind === 'OB.UI.RenderOrderLine') { this.waterfall('onCheckedTicketLine', inEvent); return true; } }, discountQtyChanged: function (inSender, inEvent) { this.waterfall('onDiscountQtyChanged', inEvent); }, keyboardOnDiscountsMode: function (inSender, inEvent) { this.waterfall('onKeyboardOnDiscountsMode', inEvent); }, keyboardDisabled: function (inSender, inEvent) { this.waterfall('onKeyboardDisabled', inEvent); }, allTicketLinesChecked: function (inSender, inEvent) { this.waterfall('onAllTicketLinesChecked', inEvent); }, leftToolbarDisabled: function (inSender, inEvent) { this.waterfall('onLeftToolbarDisabled', inEvent); }, rightToolbarDisabled: function (inSender, inEvent) { this.waterfall('onRightToolbarDisabled', inEvent); }, BPSelectionDisabled: function (inSender, inEvent) { this.waterfall('onBPSelectionDisabled', inEvent); }, newBPDisabled: function (inSender, inEvent) { this.waterfall('onNewBPDisabled', inEvent); }, newBPLocDisabled: function (inSender, inEvent) { this.waterfall('onNewBPLocDisabled', inEvent); }, orderSelectionDisabled: function (inSender, inEvent) { this.waterfall('onOrderSelectionDisabled', inEvent); }, discountsMode: function (inSender, inEvent) { this.leftToolbarDisabled(inSender, { status: true }); this.rightToolbarDisabled(inSender, { status: true }); this.BPSelectionDisabled(inSender, { status: true }); this.orderSelectionDisabled(inSender, { status: true }); this.keyboardOnDiscountsMode(inSender, { status: true }); this.waterfall('onCheckBoxBehaviorForTicketLine', { status: true }); this.tabChange(inSender, inEvent); }, tabChange: function (inSender, inEvent) { this.waterfall('onTabButtonTap', { tabPanel: inEvent.tabPanel, options: inEvent.options }); this.waterfall('onChangeEditMode', { edit: inEvent.edit }); if (inEvent.keyboard) { this.$.multiColumn.$.rightPanel.$.keyboard.showToolbar(inEvent.keyboard); } else { this.$.multiColumn.$.rightPanel.$.keyboard.hide(); } if (!_.isUndefined(inEvent.status)) { this.$.multiColumn.$.rightPanel.$.keyboard.setStatus(inEvent.status); } }, discountsModeFinished: function (inSender, inEvent) { this.leftToolbarDisabled(inSender, { status: false }); this.keyboardOnDiscountsMode(inSender, { status: false }); this.rightToolbarDisabled(inSender, { status: false }); this.keyboardDisabled(inSender, { status: false }); this.BPSelectionDisabled(inSender, { status: false }); this.orderSelectionDisabled(inSender, { status: false }); this.waterfall('onCheckBoxBehaviorForTicketLine', { status: false }); this.allTicketLinesChecked(inSender, { status: false }); this.tabChange(inSender, inEvent); }, deleteLine: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } var line = inEvent.line, receipt = this.model.get('order'); if (line && receipt) { receipt.deleteLine(line); receipt.trigger('scan'); } }, editLine: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } this.doShowPopup({ popup: 'receiptLinesPropertiesDialog', args: inEvent ? inEvent.args : null }); }, returnLine: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } this.model.get('order').returnLine(inEvent.line); }, exactPayment: function (inSender, inEvent) { this.$.multiColumn.$.rightPanel.$.keyboard.execStatelessCommand('cashexact'); }, changeCurrentOrder: function (inSender, inEvent) { this.model.get('orderList').load(inEvent.newCurrentOrder); return true; }, removePayment: function (inSender, inEvent) { var me = this; if (inEvent.payment.get('paymentData')) { if (!confirm(OB.I18N.getLabel('OBPOS_MsgConfirmRemovePayment'))) { if (inEvent.removeCallback) { inEvent.removeCallback(); } //canceled, not remove return; } else { //To remove this payment we've to connect with server //a callback is defined to receive the confirmation var callback = function (hasError, error) { if (inEvent.removeCallback) { inEvent.removeCallback(); } if (hasError) { OB.UTIL.showError(error); } else { // if (!me.model.get('multiOrders').get('isMultiOrders')) { // me.model.get('order').removePayment(inEvent.payment); // } else { // me.model.get('multiOrders').removePayment(inEvent.payment); // } if (me.model.get('leftColumnViewManager').isOrder()) { me.model.get('order').removePayment(inEvent.payment); me.model.get('order').trigger('displayTotal'); return; } if (me.model.get('leftColumnViewManager').isMultiOrder()) { me.model.get('multiOrders').removePayment(inEvent.payment); me.model.get('multiOrders').trigger('displayTotal'); return; } } }; //async call with defined callback inEvent.payment.get('paymentData').voidTransaction(callback); return; } } else { // if (!me.model.get('multiOrders').get('isMultiOrders')) { // me.model.get('order').removePayment(inEvent.payment); // } else { // me.model.get('multiOrders').removePayment(inEvent.payment); // } if (me.model.get('leftColumnViewManager').isOrder()) { me.model.get('order').removePayment(inEvent.payment); me.model.get('order').trigger('displayTotal'); return; } if (me.model.get('leftColumnViewManager').isMultiOrder()) { me.model.get('multiOrders').removePayment(inEvent.payment); me.model.get('multiOrders').trigger('displayTotal'); return; } } }, changeSubWindow: function (inSender, inEvent) { this.model.get('subWindowManager').set('currentWindow', inEvent.newWindow); }, setReceiptsList: function (inSender, inEvent) { this.$.modalreceipts.setReceiptsList(inEvent.orderList); }, showModalReceiptProperties: function (inSender, inEvent) { this.doShowPopup({ popup: 'receiptPropertiesDialog' }); return true; }, setProperty: function (inSender, inEvent) { var i; if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } if (inEvent.extraProperties) { for (i = 0; i < inEvent.extraProperties.length; i++) { this.model.get('order').setProperty(inEvent.extraProperties[i], inEvent.value); } } this.model.get('order').setProperty(inEvent.property, inEvent.value); this.model.get('orderList').saveCurrent(); return true; }, setLineProperty: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } var line = inEvent.line, receipt = this.model.get('order'); if (line && receipt) { receipt.setLineProperty(line, inEvent.property, inEvent.value); } this.model.get('orderList').saveCurrent(); return true; }, statusChanged: function (inSender, inEvent) { // sending the event to the components bellow this one this.waterfall('onButtonStatusChanged', { value: inEvent }); }, layaways: function (inSender, inEvent) { this.$.modalPaidReceipts.setParams({ isLayaway: true }); this.$.modalPaidReceipts.waterfall('onClearAction'); this.doShowPopup({ popup: 'modalPaidReceipts' }); }, changeSalesRepresentative: function (inSender, inEvent) { if (this.model.get('order').get('isEditable') === false) { this.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } this.model.get('order').set('salesRepresentative', inEvent.salesRepresentative.get('id')); this.model.get('order').set('salesRepresentative$_identifier', inEvent.salesRepresentative.get('_identifier')); this.model.get('orderList').saveCurrent(); return true; }, selectCharacteristicValue: function (inSender, inEvent) { this.waterfall('onUpdateFilter', { value: inEvent }); }, multiOrders: function (inSender, inEvent) { this.doShowPopup({ popup: 'modalMultiOrders' }); return true; }, selectBrand: function (inSender, inEvent) { this.waterfall('onUpdateBrandFilter', { value: inEvent }); }, warehouseSelected: function (inSender, inEvent) { this.waterfall('onModifyWarehouse', inEvent); }, selectMultiOrders: function (inSender, inEvent) { var me = this; me.model.get('multiOrders').get('multiOrdersList').reset(); _.each(inEvent.value, function (iter) { //iter.set('isMultiOrder', true); me.model.get('orderList').addMultiReceipt(iter); me.model.get('multiOrders').get('multiOrdersList').add(iter); }); this.model.get('leftColumnViewManager').setMultiOrderMode(); //this.model.get('multiOrders').set('isMultiOrders', true); return true; }, removeMultiOrders: function (inSender, inEvent) { var me = this; me.model.get('multiOrders').get('multiOrdersList').remove(inEvent.order); if (inEvent && inEvent.order && inEvent.order.get('loadedFromServer')) { me.model.get('orderList').current = inEvent.order; me.model.get('orderList').deleteCurrent(); me.model.get('orderList').deleteCurrentFromDatabase(inEvent.order); } return true; }, doShowLeftHeader: function (inSender, inEvent) { this.waterfall('onLeftHeaderShow', inEvent); }, clearUserInput: function (inSender, inEvent) { this.waterfall('onClearEditBox', inEvent); }, init: function () { var receipt, receiptList, LeftColumnCurrentView; this.inherited(arguments); receipt = this.model.get('order'); receiptList = this.model.get('orderList'); OB.MobileApp.view.scanningFocus(true); // Try to print the pending receipts. OB.Model.OfflinePrinter.printPendingJobs(); this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { if (changedModel.isMultiOrder()) { this.rightToolbarDisabled({}, { status: true, exceptionPanel: 'payment' }); this.tabChange({}, { tabPanel: 'payment', keyboard: 'toolbarpayment' }); return; } if (changedModel.isOrder()) { this.rightToolbarDisabled({}, { status: false }); this.tabChange({}, { tabPanel: 'scan', keyboard: 'toolbarscan' }); return; } }, this); LeftColumnCurrentView = enyo.json.parse(localStorage.getItem('leftColumnCurrentView')); if (LeftColumnCurrentView === null) { LeftColumnCurrentView = { name: 'order', params: [] }; } this.model.get('leftColumnViewManager').set('currentView', LeftColumnCurrentView); this.model.get('subWindowManager').on('change:currentWindow', function (changedModel) { function restorePreviousState(swManager, changedModel) { swManager.set('currentWindow', changedModel.previousAttributes().currentWindow, { silent: true }); } var showNewSubWindow = false, currentWindowClosed = true; if (this.$[changedModel.get('currentWindow').name]) { if (!changedModel.get('currentWindow').params) { changedModel.get('currentWindow').params = {}; } changedModel.get('currentWindow').params.caller = changedModel.previousAttributes().currentWindow.name; if (this.$[changedModel.previousAttributes().currentWindow.name].mainBeforeClose) { currentWindowClosed = this.$[changedModel.previousAttributes().currentWindow.name].mainBeforeClose(changedModel.get('currentWindow').name); } if (currentWindowClosed) { if (this.$[changedModel.get('currentWindow').name].mainBeforeSetShowing) { showNewSubWindow = this.$[changedModel.get('currentWindow').name].mainBeforeSetShowing(changedModel.get('currentWindow').params); if (showNewSubWindow) { this.$[changedModel.previousAttributes().currentWindow.name].setShowing(false); this.$[changedModel.get('currentWindow').name].setShowing(true); if (this.$[changedModel.get('currentWindow').name].mainAfterShow) { this.$[changedModel.get('currentWindow').name].mainAfterShow(); } } else { restorePreviousState(this.model.get('subWindowManager'), changedModel); } } else { if (this.$[changedModel.get('currentWindow').name].isMainSubWindow) { this.$[changedModel.previousAttributes().currentWindow.name].setShowing(false); this.$[changedModel.get('currentWindow').name].setShowing(true); OB.MobileApp.view.scanningFocus(true); } else { //developers helps //OB.info("Error! A subwindow must inherits from OB.UI.subwindow -> restore previous state"); restorePreviousState(this.model.get('subWindowManager'), changedModel); } } } else { restorePreviousState(this.model.get('subWindowManager'), changedModel); } } else { //developers helps //OB.info("The subwindow to navigate doesn't exists -> restore previous state"); restorePreviousState(this.model.get('subWindowManager'), changedModel); } }, this); // show properties when needed... receipt.get('lines').on('created', function (line) { this.classModel.trigger('createdLine', this, line); }, this); receipt.get('lines').on('removed', function (line) { this.classModel.trigger('removedLine', this, line); }, this); this.$.multiColumn.$.leftPanel.$.receiptview.setOrder(receipt); this.$.multiColumn.$.leftPanel.$.receiptview.setOrderList(receiptList); this.$.multiColumn.$.rightPanel.$.toolbarpane.setModel(this.model); this.$.multiColumn.$.rightPanel.$.keyboard.setReceipt(receipt); this.$.multiColumn.$.rightToolbar.$.rightToolbar.setReceipt(receipt); }, initComponents: function () { this.inherited(arguments); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.LeftHeader', showing: false, published: { text: null }, handlers: { onLeftHeaderShow: 'doShowHeader' }, doShowHeader: function (inSender, inEvent) { this.setText(inEvent.text); if (inEvent.style) { this.$.innerDiv.addStyles(inEvent.style); } this.show(); }, components: [{ name: 'innerDiv', style: 'text-align: center; font-size: 30px; padding: 5px; padding-top: 0px;', components: [{ name: 'headerText', attributes: { style: 'background-color: #ffffff; height: 30px; font-weight:bold; padding-top: 15px;' }, content: '' }] }], textChanged: function () { this.$.headerText.setContent(this.text); } }); OB.OBPOSPointOfSale.UICustomization = OB.OBPOSPointOfSale.UICustomization || {}; OB.OBPOSPointOfSale.UICustomization.stockLeftSubWindow = 'productdetailsview'; OB.POS.registerWindow({ windowClass: OB.OBPOSPointOfSale.UI.PointOfSale, route: 'retail.pointofsale', menuPosition: null, permission: 'OBPOS_retail.pointofsale', // Not to display it in the menu menuLabel: 'POS' }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, Backbone, enyo */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ReceiptView', classes: 'span6', published: { order: null, orderList: null }, components: [{ style: 'margin: 5px', components: [{ style: 'position: relative;background-color: #ffffff; color: black;overflow-y: auto; max-height:622px', components: [{ kind: 'OB.UI.ReceiptsCounter', name: 'receiptcounter' }, { style: 'padding: 5px;', components: [{ kind: 'OB.UI.OrderHeader', name: 'receiptheader' }, { classes: 'row-fluid', style: 'max-height: 536px;', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.OrderView', name: 'orderview' }] }] }] }] }] }], orderChanged: function (oldValue) { this.$.receiptheader.setOrder(this.order); this.$.orderview.setOrder(this.order); }, orderListChanged: function (oldValue) { this.$.receiptcounter.setOrderList(this.orderList); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, Backbone, enyo */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.MultiReceiptView', classes: 'span6', published: { order: null, orderList: null }, components: [{ style: 'margin: 5px', components: [{ style: 'position: relative;background-color: #ffffff; color: black;', components: [{ style: 'padding: 5px;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'padding: 5px 0px 10px 0px; border-bottom: 1px solid #cccccc;', components: [{ style: 'clear:both;' }] }] }] }, { classes: 'row-fluid', style: 'max-height: 536px;', components: [{ classes: 'span12', components: [{ kind: 'OB.UI.MultiOrderView', name: 'multiorderview' }] }] }] }] }] }] }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, $, Backbone, enyo */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonStockThisStore', kind: 'OB.UI.SmallButton', events: { onOpenLocalStockModal: '', onOpenLocalStockClickableModal: '' }, classes: 'btnlink-green', style: 'min-width: 200px; margin: 2px 5px 2px 5px;', tap: function () { if ((this.leftSubWindow && this.leftSubWindow.line) || !OB.MobileApp.model.get('permissions').OBPOS_warehouseselectionforline || !this.model.get('order').get('isEditable')) { this.doOpenLocalStockModal(); } else { this.doOpenLocalStockClickableModal(); } }, init: function (model) { this.model = model; } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonStockOtherStore', kind: 'OB.UI.SmallButton', events: { onOpenOtherStoresStockModal: '' }, classes: 'btnlink-green', style: 'min-width: 200px; margin: 2px 5px 2px 5px;', tap: function () { this.doOpenOtherStoresStockModal(); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonAddToTicket', kind: 'OB.UI.RegularButton', classes: 'btnlink-green', style: 'min-width: 70px; margin: 2px 5px 2px 5px;', i18nLabel: 'OBPOS_addToTicket', events: { onAddProduct: '' }, tap: function () { if (this.leftSubWindow.product) { var line = null; if (this.leftSubWindow && this.leftSubWindow.line) { line = this.leftSubWindow.line; } this.doAddProduct({ attrs: { warehouse: { id: this.leftSubWindow.warehouse.warehouseid, warehousename: this.leftSubWindow.warehouse.warehousename, warehouseqty: this.leftSubWindow.warehouse.warehouseqty } }, options: { line: line }, product: this.leftSubWindow.product, ignoreStockTab: true }); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonClose', style: 'float: right; cursor: pointer; font-size: 150%; font-weight: bold; color: #CCCCCC; width: 40px; height: 40px; margin: -10px; text-align: right; padding: 8px;', content: '×', tap: function () { this.leftSubWindow.doCloseLeftSubWindow(); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_header', style: 'font-size: 22px; height: 25px; padding: 15px 15px 5px 15px;', components: [{ name: 'productName', style: 'float: left;' }, { kind: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonClose' }] }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_body', handlers: { onOpenLocalStockModal: 'openLocalStockModal', onOpenLocalStockClickableModal: 'openLocalStockClickableModal', onOpenOtherStoresStockModal: 'openOtherStoresStockModal' }, events: { onShowPopup: '' }, openLocalStockModal: function () { if (this.leftSubWindow.localStockModel) { this.doShowPopup({ popup: 'modalLocalStock', args: { stockInfo: this.leftSubWindow.localStockModel } }); } return true; }, openLocalStockClickableModal: function () { if (this.leftSubWindow.localStockModel) { this.doShowPopup({ popup: 'modalLocalStockClickable', args: { stockInfo: this.leftSubWindow.localStockModel } }); } return true; }, openOtherStoresStockModal: function () { if (this.leftSubWindow.otherStoresStockModel) { this.doShowPopup({ popup: 'modalStockInOtherStores', args: { stockInfo: this.leftSubWindow.otherStoresStockModel } }); } return true; }, components: [{ style: 'height: 160px; padding: 20px;', components: [{ name: 'productImage', baseStyle: 'background:#ffffff url(data:image/png;base64,xxImgBinaryDataxx) center center no-repeat;background-size:contain;margin: auto; height: 100%; width: 100%; background-size: contain;', style: 'background-color:#ffffff; background-repeat: no-repeat; background-position: center center; background-size: contain; margin: auto; height: 100%; width: 100%;' }] }, { style: 'margin: 5px 15px;', components: [{ name: 'warehouseToGet', allowHtml: true, style: 'line-height: 20px; font-size: 20px; padding: 10px; color: black;' }] }, { style: 'height: 80px; padding: 10px;', components: [{ style: 'float: left; width: 50%;', components: [{ style: 'padding: 0px 0px 15px 0px;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonStockThisStore', name: 'stockHere' }] }, { kind: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonStockOtherStore', name: 'stockOthers' }] }, { style: 'float: right;', components: [{ name: 'productPrice', allowHtml: true, style: 'margin: 5px 0px 12px 0px; text-align: center; font-size: 18px; font-weight: 600;' }, { components: [{ kind: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_ButtonAddToTicket' }] }] }] }, { kind: 'Scroller', maxHeight: '191px', style: 'padding: 15px;', components: [{ name: 'descriptionArea' }] }] }); enyo.kind({ kind: 'OB.UI.LeftSubWindow', name: 'OB.OBPOSPointOfSale.UI.ProductDetailsView', events: { onShowPopup: '' }, handlers: { onModifyWarehouse: 'changeWarehouseInfo' }, changeWarehouseInfo: function (inSender, inEvent) { this.bodyComponent.$.warehouseToGet.setContent(OB.I18N.getLabel('OBPOS_warehouseSelected', [inEvent.warehousename, inEvent.warehouseqty])); this.warehouse = inEvent; }, loadDefaultWarehouseData: function (defaultWarehouse) { if (defaultWarehouse) { this.bodyComponent.$.warehouseToGet.setContent(OB.I18N.getLabel('OBPOS_warehouseSelected', [defaultWarehouse.get('warehousename'), defaultWarehouse.get('warehouseqty')])); } else { this.bodyComponent.$.warehouseToGet.setContent(OB.I18N.getLabel('OBPOS_warehouseSelected', [OB.POS.modelterminal.get('warehouses')[0].warehousename, '0'])); } }, getStoreStock: function () { var serverCallStoreDetailedStock = new OB.DS.Process('org.openbravo.retail.posterminal.stock.StoreDetailedStock'), me = this; this.bodyComponent.$.stockHere.setContent(OB.I18N.getLabel('OBPOS_loadingStock')); serverCallStoreDetailedStock.exec({ organization: OB.POS.modelterminal.get('terminal').organization, product: this.product.get('id') }, function (data) { if (data && data.exception) { me.bodyComponent.$.stockHere.setContent(OB.I18N.getLabel('OBPOS_stockCannotBeRetrieved')); me.bodyComponent.$.stockHere.addClass("error"); } else if (data.product === me.product.get('id') && me.showing) { if (data.qty || data.qty === 0) { data.product = me.product; me.localStockModel = new OB.OBPOSPointOfSale.UsedModels.LocalStock(data); if (me.localStockModel.get('warehouses').at(0)) { if (me.warehouse.warehouseid) { me.loadDefaultWarehouseData(me.localStockModel.getWarehouseById(me.warehouse.warehouseid)); } else { me.loadDefaultWarehouseData(me.localStockModel.getWarehouseById(me.warehouse.id)); } } me.bodyComponent.$.stockHere.removeClass("error"); me.bodyComponent.$.stockHere.setContent(OB.I18N.getLabel('OBPOS_storeStock') + data.qty); } } }); }, getOtherStock: function () { var serverCallStoreDetailedStock = new OB.DS.Process('org.openbravo.retail.posterminal.stock.OtherStoresDetailedStock'), me = this; this.bodyComponent.$.stockOthers.setContent(OB.I18N.getLabel('OBPOS_loadingStock')); serverCallStoreDetailedStock.exec({ organization: OB.POS.modelterminal.get('terminal').organization, product: this.product.get('id') }, function (data) { if (data && data.exception) { me.bodyComponent.$.stockOthers.setContent(OB.I18N.getLabel('OBPOS_stockCannotBeRetrieved')); me.bodyComponent.$.stockOthers.addClass("error"); } else if (data.product === me.product.get('id') && me.showing) { if (data.qty || data.qty === 0) { data.product = me.product; me.otherStoresStockModel = new OB.OBPOSPointOfSale.UsedModels.OtherStoresWarehousesStock(data); me.bodyComponent.$.stockOthers.removeClass("error"); me.bodyComponent.$.stockOthers.setContent(OB.I18N.getLabel('OBPOS_otherStoresStock') + data.qty); } } }); }, beforeSetShowing: function (params) { if (!params.product || OB.POS.modelterminal.get('warehouses').length === 0) { this.doShowPopup({ popup: 'modalConfigurationRequiredForCrossStore' }); return false; } this.line = params.line || null; this.product = params.product; this.localStockModel = null; this.otherStoresStockModel = null; if (params.warehouse) { this.warehouse = params.warehouse; } else { this.warehouse = OB.POS.modelterminal.get('warehouses')[0]; } this.headerComponent.$.productName.setContent(params.product.get('_identifier') + ' (' + params.product.get('uOMsymbol') + ')'); if (OB.MobileApp.model.get('permissions')["OBPOS_retail.productImages"]) { this.bodyComponent.$.productImage.applyStyle('background-image', 'url(' + OB.UTIL.getImageURL(params.product.get('id')) + '), url(' + "../org.openbravo.mobile.core/assets/img/box.png" + ')'); } else { this.bodyComponent.$.productImage.applyStyle('background-image', 'url(data:image/png;base64,' + params.product.get('img') + ')'); } this.bodyComponent.$.warehouseToGet.setContent(OB.I18N.getLabel('OBPOS_loadingFromWarehouse', [this.warehouse.warehousename])); this.bodyComponent.$.productPrice.setContent(OB.I18N.getLabel('OBPOS_priceInfo') + '' + OB.I18N.formatCurrency(params.product.get('standardPrice')) + ''); this.bodyComponent.$.descriptionArea.setContent(params.product.get('description')); this.getOtherStock(); this.getStoreStock(); return true; }, header: { kind: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_header', name: 'header' }, body: { kind: 'OB.OBPOSPointOfSale.UI.ProductDetailsView_body', name: 'body' } }); /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, _ */ /*left toolbar*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.LeftToolbarButton', tag: 'li', classes: 'span4', components: [{ name: 'theButton', attributes: { style: 'margin: 0px 5px 0px 5px;' } }], initComponents: function () { this.inherited(arguments); this.$.theButton.createComponent(this.button); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.LeftToolbar', classes: 'span3', components: [{ tag: 'ul', classes: 'unstyled nav-pos row-fluid', name: 'toolbar' }], initComponents: function () { this.inherited(arguments); enyo.forEach(this.buttons, function (btn) { this.$.toolbar.createComponent({ kind: 'OB.OBPOSPointOfSale.UI.LeftToolbarButton', button: btn }); }, this); } }); enyo.kind({ name: 'OB.UI.ButtonNew', kind: 'OB.UI.ToolbarButton', icon: 'btn-icon btn-icon-new', events: { onAddNewOrder: '' }, handlers: { onLeftToolbarDisabled: 'disabledButton' }, disabledButton: function (inSender, inEvent) { this.isEnabled = !inEvent.status; this.setDisabled(inEvent.status); }, init: function (model) { this.model = model; }, tap: function () { var i; if (this.model.get('leftColumnViewManager').isMultiOrder()) { for (i = 0; this.model.get('multiOrders').get('multiOrdersList').length > i; i++) { if (!this.model.get('multiOrders').get('multiOrdersList').at(i).get('isLayaway')) { //if it is not true, means that iti is a new order (not a loaded layaway) this.model.get('multiOrders').get('multiOrdersList').at(i).unset('amountToLayaway'); this.model.get('multiOrders').get('multiOrdersList').at(i).set('orderType', 0); continue; } this.model.get('orderList').current = this.model.get('multiOrders').get('multiOrdersList').at(i); this.model.get('orderList').deleteCurrent(); if (!_.isNull(this.model.get('multiOrders').get('multiOrdersList').at(i).id)) { this.model.get('orderList').deleteCurrentFromDatabase(this.model.get('multiOrders').get('multiOrdersList').at(i)); } } this.model.get('multiOrders').resetValues(); this.model.get('leftColumnViewManager').setOrderMode(); } else { if (OB.POS.modelterminal.get('permissions')['OBPOS_print.suspended'] && this.model.get('order').get('lines').length !== 0) { this.model.get('order').trigger('print'); } } this.doAddNewOrder(); return true; } }); enyo.kind({ name: 'OB.UI.ButtonDelete', kind: 'OB.UI.ToolbarButton', icon: 'btn-icon btn-icon-delete', events: { onShowPopup: '', onDeleteOrder: '' }, handlers: { onLeftToolbarDisabled: 'disabledButton' }, disabledButton: function (inSender, inEvent) { this.isEnabled = !inEvent.status; this.setDisabled(inEvent.status); }, tap: function () { var i, me = this; if (me.model.get('leftColumnViewManager').isMultiOrder()) { for (i = 0; me.model.get('multiOrders').get('multiOrdersList').length > i; i++) { if (!me.model.get('multiOrders').get('multiOrdersList').at(i).get('isLayaway')) { //if it is not true, means that iti is a new order (not a loaded layaway) me.model.get('multiOrders').get('multiOrdersList').at(i).unset('amountToLayaway'); me.model.get('multiOrders').get('multiOrdersList').at(i).set('orderType', 0); continue; } me.model.get('orderList').current = me.model.get('multiOrders').get('multiOrdersList').at(i); me.model.get('orderList').deleteCurrent(); if (!_.isNull(me.model.get('multiOrders').get('multiOrdersList').at(i).id)) { me.model.get('orderList').deleteCurrentFromDatabase(me.model.get('multiOrders').get('multiOrdersList').at(i)); } } me.model.get('multiOrders').resetValues(); me.model.get('leftColumnViewManager').setOrderMode(); return true; } // deletion without warning is allowed if the ticket has been processed if (me.hasClass('paidticket')) { me.doDeleteOrder(); } else { OB.UTIL.Approval.requestApproval( this.model, 'OBPOS_approval.removereceipts', function (approved, supervisor, approvalType) { if (approved) { me.doShowPopup({ popup: 'modalConfirmReceiptDelete' }); } }); } }, init: function (model) { this.model = model; this.model.get('leftColumnViewManager').on('multiorder', function () { this.addClass('paidticket'); return true; }, this); this.model.get('leftColumnViewManager').on('order', function () { this.removeClass('paidticket'); if (this.model.get('order').get('isPaid') || this.model.get('order').get('isLayaway') || (this.model.get('order').get('isQuotation') && this.model.get('order').get('hasbeenpaid') === 'Y')) { this.addClass('paidticket'); } this.bubble('onChangeTotal', { newTotal: this.model.get('order').getTotal() }); }, this); // this.model.get('multiOrders').on('change:isMultiOrders', function (model) { // if (model.get('isMultiOrders')) { // this.addClass('paidticket'); // } else { // this.removeClass('paidticket'); // } // return true; // }, this); this.model.get('order').on('change:isPaid change:isQuotation change:isLayaway change:hasbeenpaid', function (changedModel) { if (changedModel.get('isPaid') || changedModel.get('isLayaway') || (changedModel.get('isQuotation') && changedModel.get('hasbeenpaid') === 'Y')) { this.addClass('paidticket'); return; } this.removeClass('paidticket'); }, this); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ButtonTabPayment', kind: 'OB.UI.ToolbarButtonTab', tabPanel: 'payment', handlers: { onChangedTotal: 'renderTotal', onRightToolbarDisabled: 'disabledButton', synchronizing: 'disableButton', synchronized: 'enableButton' }, disabledButton: function (inSender, inEvent) { if (inEvent.exceptionPanel === this.tabPanel) { return true; } this.isEnabled = !inEvent.status; this.setDisabled(inEvent.status); }, disableButton: function () { this.setDisabled(true); }, enableButton: function () { this.setDisabled(false); }, events: { onTabChange: '', onClearUserInput: '' }, showPaymentTab: function () { var receipt = this.model.get('order'), me = this; if (receipt.get('isQuotation')) { if (receipt.get('hasbeenpaid') !== 'Y') { receipt.prepareToSend(function () { receipt.trigger('closed', { callback: function () { receipt.trigger('scan'); } }); }); } else { receipt.prepareToSend(function () { receipt.trigger('scan'); OB.UTIL.showError(OB.I18N.getLabel('OBPOS_QuotationClosed')); }); } return; } if ((this.model.get('order').get('isEditable') === false && !this.model.get('order').get('isLayaway')) || this.model.get('order').get('orderType') === 3) { return true; } OB.MobileApp.view.scanningFocus(false); if (this.model.get('leftColumnViewManager').isMultiOrder()) { this.model.get('multiOrders').trigger('displayTotal'); } else { receipt.trigger('displayTotal'); } me.doTabChange({ tabPanel: me.tabPanel, keyboard: 'toolbarpayment', edit: false }); me.bubble('onShowColumn', { colNum: 1 }); }, tap: function () { if (this.disabled === false) { this.model.on('approvalChecked', function (event) { this.model.off('approvalChecked'); if (event.approved) { this.showPaymentTab(); } }, this); this.model.completePayment(); this.doClearUserInput(); } }, attributes: { style: 'text-align: center; font-size: 30px;' }, components: [{ style: 'font-weight: bold; margin: 0px 5px 0px 0px;', kind: 'OB.UI.Total', name: 'totalPrinter' }], getLabel: function () { return this.$.totalPrinter.getContent(); }, initComponents: function () { this.inherited(arguments); this.removeClass('btnlink-gray'); }, renderTotal: function (inSender, inEvent) { this.$.totalPrinter.renderTotal(inEvent.newTotal); }, init: function (model) { this.model = model; this.model.get('order').on('change:isEditable change:isLayaway', function (newValue) { if (newValue) { if (newValue.get('isEditable') === false && !newValue.get('isLayaway')) { this.tabPanel = null; this.setDisabled(true); return; } } this.tabPanel = 'payment'; this.setDisabled(false); }, this); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.LeftToolbarImpl', kind: 'OB.UI.MultiColumn.Toolbar', menuEntries: [], buttons: [{ kind: 'OB.UI.ButtonNew', span: 3 }, { kind: 'OB.UI.ButtonDelete', span: 3 }, { kind: 'OB.OBPOSPointOfSale.UI.ButtonTabPayment', name: 'btnTotalToPay', span: 6 }], initComponents: function () { // set up the POS menu //Menu entries is used for modularity. cannot be initialized //this.menuEntries = []; this.menuEntries.push({ kind: 'OB.UI.MenuReturn' }); this.menuEntries.push({ kind: 'OB.UI.MenuVoidLayaway' }); this.menuEntries.push({ kind: 'OB.UI.MenuProperties' }); this.menuEntries.push({ kind: 'OB.UI.MenuInvoice' }); this.menuEntries.push({ kind: 'OB.UI.MenuPrint' }); this.menuEntries.push({ kind: 'OB.UI.MenuLayaway' }); this.menuEntries.push({ kind: 'OB.UI.MenuCustomers' }); this.menuEntries.push({ kind: 'OB.UI.MenuPaidReceipts' }); this.menuEntries.push({ kind: 'OB.UI.MenuQuotations' }); this.menuEntries.push({ kind: 'OB.UI.MenuOpenDrawer' }); // TODO: what is this for?!! // this.menuEntries = this.menuEntries.concat(this.externalEntries); this.menuEntries.push({ kind: 'OB.UI.MenuSeparator', name: 'sep1' }); this.menuEntries.push({ kind: 'OB.UI.MenuDiscounts' }); this.menuEntries.push({ kind: 'OB.UI.MenuSeparator', name: 'sep2' }); this.menuEntries.push({ kind: 'OB.UI.MenuReactivateQuotation' }); this.menuEntries.push({ kind: 'OB.UI.MenuRejectQuotation' }); this.menuEntries.push({ kind: 'OB.UI.MenuCreateOrderFromQuotation' }); this.menuEntries.push({ kind: 'OB.UI.MenuQuotation' }); this.menuEntries.push({ kind: 'OB.UI.MenuLayaways' }); this.menuEntries.push({ kind: 'OB.UI.MenuMultiOrders' }); this.menuEntries.push({ kind: 'OB.UI.MenuSeparator', name: 'sep3' }); this.menuEntries.push({ kind: 'OB.UI.MenuBackOffice' }); //remove duplicates this.menuEntries = _.uniq(this.menuEntries, false, function (p) { return p.kind + p.name; }); this.inherited(arguments); } }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, _*/ // Toolbar container // ---------------------------------------------------------------------------- //enyo.kind({ // name: 'OB.OBPOSPointOfSale.UI.RightToolbar', // handlers: { // onTabButtonTap: 'tabButtonTapHandler' // }, // components: [{ // tag: 'ul', // classes: 'unstyled nav-pos row-fluid', // name: 'toolbar' // }], // tabButtonTapHandler: function (inSender, inEvent) { // if (inEvent.tabPanel) { // this.setTabButtonActive(inEvent.tabPanel); // } // }, // setTabButtonActive: function (tabName) { // var buttonContainerArray = this.$.toolbar.getComponents(), // i; // // for (i = 0; i < buttonContainerArray.length; i++) { // buttonContainerArray[i].removeClass('active'); // if (buttonContainerArray[i].getComponents()[0].getComponents()[0].name === tabName) { // buttonContainerArray[i].addClass('active'); // } // } // }, // manualTap: function (tabName, options) { // var tab; // // function getButtonByName(name, me) { // var componentArray = me.$.toolbar.getComponents(), // i; // for (i = 0; i < componentArray.length; i++) { // if (componentArray[i].$.theButton.getComponents()[0].name === name) { // return componentArray[i].$.theButton.getComponents()[0]; // } // } // return null; // } // // tab = getButtonByName(tabName, this); // if (tab) { // tab.tap(options); // } // }, // initComponents: function () { // this.inherited(arguments); // enyo.forEach(this.buttons, function (btn) { // this.$.toolbar.createComponent({ // kind: 'OB.OBPOSPointOfSale.UI.RightToolbarButton', // button: btn // }); // }, this); // } //}); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.RightToolbarImpl', published: { receipt: null }, handlers: { onTabButtonTap: 'tabButtonTapHandler' }, tabButtonTapHandler: function (inSender, inEvent) { if (inEvent.tabPanel) { this.setTabButtonActive(inEvent.tabPanel); } }, setTabButtonActive: function (tabName) { var buttonContainerArray = this.$.toolbar.getComponents(), i; for (i = 0; i < buttonContainerArray.length; i++) { buttonContainerArray[i].removeClass('active'); if (buttonContainerArray[i].getComponents()[0].getComponents()[0].tabToOpen === tabName) { buttonContainerArray[i].addClass('active'); } } }, manualTap: function (tabName, options) { var tab; function getButtonByName(name, me) { var componentArray = me.$.toolbar.getComponents(), i; for (i = 0; i < componentArray.length; i++) { if (componentArray[i].$.theButton.getComponents()[0].tabToOpen === name) { return componentArray[i].$.theButton.getComponents()[0]; } } return null; } tab = getButtonByName(tabName, this); if (tab) { tab.tap(options); } }, kind: 'OB.UI.MultiColumn.Toolbar', buttons: [{ kind: 'OB.OBPOSPointOfSale.UI.ButtonTabScan', name: 'toolbarBtnScan', tabToOpen: 'scan' }, { kind: 'OB.OBPOSPointOfSale.UI.ButtonTabBrowse', name: 'toolbarBtnCatalog', tabToOpen: 'catalog' }, { kind: 'OB.OBPOSPointOfSale.UI.ButtonTabSearchCharacteristic', name: 'toolbarBtnSearchCharacteristic', tabToOpen: 'searchCharacteristic' }, { kind: 'OB.OBPOSPointOfSale.UI.ButtonTabEditLine', name: 'toolbarBtnEdit', tabToOpen: 'edit' }], receiptChanged: function () { var totalPrinterComponent; this.receipt.on('clear', function () { this.waterfall('onChangeTotal', { newTotal: this.receipt.getTotal() }); if (this.receipt.get('isEditable') === false) { this.manualTap('edit'); } else { if (OB.POS.modelterminal.get('terminal').defaultwebpostab) { if (OB.POS.modelterminal.get('terminal').defaultwebpostab !== '') { this.manualTap(OB.POS.modelterminal.get('terminal').defaultwebpostab); } else { this.manualTap('scan'); } } else { this.manualTap('scan'); } } }, this); this.receipt.on('scan', function (params) { this.manualTap('scan', params); }, this); this.receipt.get('lines').on('click', function () { this.manualTap('edit'); }, this); //some button will draw the total if (this.receipt.get('orderType') !== 3) { //Do not change voiding layaway this.bubble('onChangeTotal', { newTotal: this.receipt.getTotal() }); } this.receipt.on('change:gross', function (model) { if (this.receipt.get('orderType') !== 3) { //Do not change voiding layaway this.bubble('onChangeTotal', { newTotal: this.receipt.getTotal() }); } }, this); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.RightToolbarButton', tag: 'li', components: [{ name: 'theButton', attributes: { style: 'margin: 0px 5px 0px 5px;' } }], initComponents: function () { this.inherited(arguments); if (this.button.containerCssClass) { this.setClassAttribute(this.button.containerCssClass); } this.$.theButton.createComponent(this.button); } }); // Toolbar buttons // ---------------------------------------------------------------------------- enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ButtonTabScan', kind: 'OB.UI.ToolbarButtonTab', tabPanel: 'scan', i18nLabel: 'OBMOBC_LblScan', events: { onTabChange: '', onRightToolbarDisabled: '' }, handlers: { onRightToolbarDisabled: 'disabledButton' }, init: function (model) { this.model = model; // var me = this; // this.model.get('multiOrders').on('change:isMultiOrders', function (model) { // if (!model.get('isMultiOrders')) { // this.doTabChange({ // tabPanel: this.tabPanel, // keyboard: 'toolbarscan', // edit: false, // status: '' // }); // } // me.doRightToolbarDisabled({ // status: model.get('isMultiOrders') // }); // }, this); }, disabledButton: function (inSender, inEvent) { this.isEnabled = !inEvent.status; this.setDisabled(inEvent.status); }, tap: function (options) { if (!this.disabled) { this.doTabChange({ tabPanel: this.tabPanel, keyboard: 'toolbarscan', edit: false, options: options, status: '' }); } OB.MobileApp.view.scanningFocus(true); return true; } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ButtonTabBrowse', kind: 'OB.UI.ToolbarButtonTab', events: { onTabChange: '', onRightToolbarDisabled: '' }, handlers: { onRightToolbarDisabled: 'disabledButton' }, init: function (model) { this.model = model; // var me = this; // this.model.get('multiOrders').on('change:isMultiOrders', function (model) { // me.doRightToolbarDisabled({ // status: model.get('isMultiOrders') // }); // }, this); }, disabledButton: function (inSender, inEvent) { this.isEnabled = !inEvent.status; this.setDisabled(inEvent.status); }, tabPanel: 'catalog', i18nLabel: 'OBMOBC_LblBrowse', tap: function () { OB.MobileApp.view.scanningFocus(false); if (!this.disabled) { this.doTabChange({ tabPanel: this.tabPanel, keyboard: false, edit: false }); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ButtonTabSearchCharacteristic', kind: 'OB.UI.ToolbarButtonTab', tabPanel: 'searchCharacteristic', i18nLabel: 'OBPOS_LblSearch', events: { onTabChange: '', onRightToolbarDisabled: '' }, handlers: { onRightToolbarDisabled: 'disabledButton' }, init: function (model) { this.model = model; // var me = this; // this.model.get('multiOrders').on('change:isMultiOrders', function (model) { // me.doRightToolbarDisabled({ // status: model.get('isMultiOrders') // }); // }, this); }, disabledButton: function (inSender, inEvent) { this.isEnabled = !inEvent.status; this.setDisabled(inEvent.status); }, tap: function () { OB.MobileApp.view.scanningFocus(false); if (this.disabled === false) { this.doTabChange({ tabPanel: this.tabPanel, keyboard: false, edit: false }); } }, initComponents: function () { this.inherited(arguments); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ButtonTabEditLine', published: { ticketLines: null }, kind: 'OB.UI.ToolbarButtonTab', tabPanel: 'edit', i18nLabel: 'OBPOS_LblEdit', events: { onTabChange: '', onRightToolbarDisabled: '' }, handlers: { onRightToolbarDisabled: 'disabledButton' }, init: function (model) { this.model = model; // var me = this; // this.model.get('multiOrders').on('change:isMultiOrders', function (model) { // me.doRightToolbarDisabled({ // status: model.get('isMultiOrders') // }); // }, this); }, disabledButton: function (inSender, inEvent) { this.setDisabled(inEvent.status); }, tap: function () { OB.MobileApp.view.scanningFocus(false); if (!this.disabled) { this.doTabChange({ tabPanel: this.tabPanel, keyboard: 'toolbarscan', edit: true }); } } }); // Toolbar panes //---------------------------------------------------------------------------- enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.RightToolbarPane', published: { model: null }, classes: 'postab-content', handlers: { onTabButtonTap: 'tabButtonTapHandler' }, components: [{ kind: 'OB.OBPOSPointOfSale.UI.TabScan', name: 'scan' }, { kind: 'OB.OBPOSPointOfSale.UI.TabBrowse', name: 'catalog' }, { kind: 'OB.OBPOSPointOfSale.UI.TabSearchCharacteristic', name: 'searchCharacteristic', style: 'margin: 5px' }, { kind: 'OB.OBPOSPointOfSale.UI.TabPayment', name: 'payment' }, { kind: 'OB.OBPOSPointOfSale.UI.TabEditLine', name: 'edit' }], tabButtonTapHandler: function (inSender, inEvent) { if (inEvent.tabPanel) { this.showPane(inEvent.tabPanel, inEvent.options); } }, showPane: function (tabName, options) { var paneArray = this.getComponents(), i; for (i = 0; i < paneArray.length; i++) { paneArray[i].removeClass('active'); if (paneArray[i].name === tabName) { OB.MobileApp.model.set('lastPaneShown', tabName); if (paneArray[i].executeOnShow) { paneArray[i].executeOnShow(options); } paneArray[i].addClass('active'); } } }, modelChanged: function () { var receipt = this.model.get('order'); this.$.scan.setReceipt(receipt); this.$.searchCharacteristic.setReceipt(receipt); this.$.payment.setReceipt(receipt); this.$.edit.setReceipt(receipt); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.TabSearchCharacteristic', kind: 'OB.UI.TabPane', published: { receipt: null }, components: [{ kind: 'OB.UI.SearchProductCharacteristic', name: 'searchCharacteristicTabContent' }], receiptChanged: function () { this.$.searchCharacteristicTabContent.setReceipt(this.receipt); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.TabBrowse', kind: 'OB.UI.TabPane', components: [{ kind: 'OB.UI.ProductBrowser', name: 'catalogTabContent' }] }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.TabScan', kind: 'OB.UI.TabPane', published: { receipt: null }, components: [{ kind: 'OB.OBPOSPointOfSale.UI.Scan', name: 'scanTabContent' }], receiptChanged: function () { this.$.scanTabContent.setReceipt(this.receipt); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.TabEditLine', kind: 'OB.UI.TabPane', published: { receipt: null }, components: [{ kind: 'OB.OBPOSPointOfSale.UI.EditLine', name: 'editTabContent' }], receiptChanged: function () { this.$.editTabContent.setReceipt(this.receipt); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.TabPayment', kind: 'OB.UI.TabPane', published: { receipt: null }, components: [{ kind: 'OB.OBPOSPointOfSale.UI.Payment', name: 'paymentTabContent' }], receiptChanged: function () { this.$.paymentTabContent.setReceipt(this.receipt); }, executeOnShow: function (options) { var me = this; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Scan', published: { receipt: null }, components: [{ style: 'position:relative; background-color: #7da7d9; background-size: cover; color: white; height: 200px; margin: 5px; padding: 5px', components: [{ kind: 'OB.UI.Clock', classes: 'pos-clock' }, { components: [{ name: 'msgwelcome', showing: false, style: 'padding: 10px;', components: [{ style: 'float:right;', name: 'msgwelcomeLbl' }] }, { name: 'msgaction', showing: false, components: [{ name: 'txtaction', style: 'padding: 10px; float: left; width: 320px; line-height: 23px;' }, { style: 'float: right;', components: [{ name: 'undobutton', kind: 'OB.UI.SmallButton', i18nContent: 'OBMOBC_LblUndo', classes: 'btnlink-white btnlink-fontblue', tap: function () { if (this.undoclick) { this.undoclick(); } } }] }] }] }] }], receiptChanged: function () { this.receipt.on('clear change:undo', function () { this.manageUndo(); }, this); this.manageUndo(); }, manageUndo: function () { var undoaction = this.receipt.get('undo'); if (undoaction) { this.$.msgwelcome.hide(); this.$.msgaction.show(); this.$.txtaction.setContent(undoaction.text); this.$.undobutton.undoclick = undoaction.undo; } else { this.$.msgaction.hide(); this.$.msgwelcome.show(); delete this.$.undobutton.undoclick; } }, initComponents: function () { this.inherited(arguments); this.$.msgwelcomeLbl.setContent(OB.I18N.getLabel('OBPOS_WelcomeMessage')); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.LineProperty', components: [{ classes: 'row-fluid', style: 'clear: both;', components: [{ classes: 'span4', name: 'propertyLabel' }, { classes: 'span8', components: [{ tag: 'span', name: 'propertyValue' }] }] }], render: function (model) { if (model) { this.$.propertyValue.setContent(model.get(this.propertyToPrint)); } else { this.$.propertyValue.setContent(''); } }, initComponents: function () { this.inherited(arguments); this.$.propertyLabel.setContent(OB.I18N.getLabel(this.I18NLabel)); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.LinePropertyDiv', components: [{ classes: 'row-fluid', style: 'clear: both;', components: [{ classes: 'span4', name: 'propertyLabel' }, { classes: 'span8', components: [{ tag: 'div', name: 'propertyValue' }] }] }], render: function (model) { if (model) { this.$.propertyValue.setContent(model.get(this.propertyToPrint)); } else { this.$.propertyValue.setContent(''); } }, initComponents: function () { this.inherited(arguments); this.$.propertyLabel.setContent(OB.I18N.getLabel(this.I18NLabel)); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.EditLine', propertiesToShow: [{ kind: 'OB.OBPOSPointOfSale.UI.LineProperty', position: 10, name: 'descLine', I18NLabel: 'OBPOS_LineDescription', render: function (line) { if (line) { this.$.propertyValue.setContent(line.get('product').get('_identifier')); } else { this.$.propertyValue.setContent(''); } } }, { kind: 'OB.OBPOSPointOfSale.UI.LineProperty', position: 20, name: 'qtyLine', I18NLabel: 'OBPOS_LineQuantity', render: function (line) { if (line) { this.$.propertyValue.setContent(line.printQty()); } else { this.$.propertyValue.setContent(''); } } }, { kind: 'OB.OBPOSPointOfSale.UI.LineProperty', position: 30, name: 'priceLine', I18NLabel: 'OBPOS_LinePrice', render: function (line) { if (line) { this.$.propertyValue.setContent(line.printPrice()); } else { this.$.propertyValue.setContent(''); } } }, { kind: 'OB.OBPOSPointOfSale.UI.LineProperty', position: 40, name: 'discountedAmountLine', I18NLabel: 'OBPOS_LineDiscount', render: function (line) { if (line) { this.$.propertyValue.setContent(line.printDiscount()); } else { this.$.propertyValue.setContent(''); } } }, { kind: 'OB.OBPOSPointOfSale.UI.LineProperty', position: 50, name: 'grossLine', I18NLabel: 'OBPOS_LineTotal', render: function (line) { if (line) { if (line.get('priceIncludesTax')) { this.$.propertyValue.setContent(line.printGross()); } else { this.$.propertyValue.setContent(line.printNet()); } } else { this.$.propertyValue.setContent(''); } } }, { kind: 'OB.OBPOSPointOfSale.UI.LineProperty', position: 60, name: 'warehouseLine', I18NLabel: 'OBPOS_LineWarehouse', render: function (line) { if (line && line.get('warehouse')) { this.$.propertyValue.setContent(line.get('warehouse').warehousename); } else { this.$.propertyValue.setContent(OB.POS.modelterminal.get('warehouses')[0].warehousename); } } }], published: { receipt: null }, events: { onDeleteLine: '', onEditLine: '', onReturnLine: '' }, handlers: { onCheckBoxBehaviorForTicketLine: 'checkBoxBehavior' }, checkBoxBehavior: function (inSender, inEvent) { if (inEvent.status) { this.line = null; //WARN! When off is done the components which are listening to this event //are removed. Because of it, the callback for the selected event are saved //and then recovered. this.selectedCallbacks = this.receipt.get('lines')._callbacks.selected; this.receipt.get('lines').off('selected'); this.render(); } else { //WARN! recover the callbacks for the selected events this.receipt.get('lines')._callbacks.selected = this.selectedCallbacks; if (this.receipt.get('lines').length > 0) { var line = this.receipt.get('lines').at(0); line.trigger('selected', line); } } }, executeOnShow: function (args) { if (args && args.discounts) { this.$.defaultEdit.hide(); this.$.discountsEdit.show(); return; } this.$.defaultEdit.show(); this.$.discountsEdit.hide(); }, components: [{ kind: 'OB.OBPOSPointOfSale.UI.Discounts', showing: false, name: 'discountsEdit' }, { name: 'defaultEdit', style: 'background-color: #ffffff; color: black; height: 200px; margin: 5px; padding: 5px', components: [{ name: 'msgedit', classes: 'row-fluid', showing: false, components: [{ classes: 'span12', components: [{ kind: 'OB.UI.SmallButton', i18nContent: 'OBPOS_ButtonDelete', classes: 'btnlink-orange', tap: function () { var me = this; OB.UTIL.Approval.requestApproval( me.model, 'OBPOS_approval.deleteLine', function (approved, supervisor, approvalType) { if (approved) { me.owner.doDeleteLine({ line: me.owner.line }); } }); }, init: function (model) { this.model = model; this.model.get('order').on('change:isPaid change:isLayaway', function (newValue) { if (newValue) { if (newValue.get('isPaid') === true || newValue.get('isLayaway') === true) { this.setShowing(false); return; } } this.setShowing(true); }, this); } }, { kind: 'OB.UI.SmallButton', i18nContent: 'OBPOS_LblDescription', classes: 'btnlink-orange', tap: function () { this.owner.doEditLine({ line: this.owner.line }); }, init: function (model) { this.model = model; this.model.get('order').on('change:isPaid change:isLayaway', function (newValue) { if (newValue) { if (newValue.get('isPaid') === true || newValue.get('isLayaway') === true) { this.setShowing(false); return; } } this.setShowing(true); }, this); } }, { kind: 'OB.UI.SmallButton', name: 'returnLine', i18nContent: 'OBPOS_LblReturnLine', permission: 'OBPOS_ReturnLine', classes: 'btnlink-orange', showing: false, tap: function () { this.owner.doReturnLine({ line: this.owner.line }); }, init: function (model) { this.model = model; if (OB.POS.modelterminal.get('permissions')[this.permission]) { this.setShowing(true); } this.model.get('order').on('change:isPaid change:isLayaway change:isQuotation', function (newValue) { if (newValue) { if (newValue.get('isPaid') === true || newValue.get('isLayaway') === true || newValue.get('isQuotation') === true) { this.setShowing(false); return; } } if (OB.POS.modelterminal.get('permissions')[this.permission]) { this.setShowing(true); } }, this); } }, { kind: 'OB.UI.SmallButton', name: 'removeDiscountButton', i18nContent: 'OBPOS_LblRemoveDiscount', showing: false, classes: 'btnlink-orange', tap: function () { if (this.owner && this.owner.line && this.owner.line.get('promotions')) { this.owner.line.unset('promotions'); OB.Model.Discounts.applyPromotions(this.model.get('order')); this.model.get('order').calculateGross(); this.hide(); } }, init: function (model) { this.model = model; } }, { kind: 'OB.OBPOSPointOfSale.UI.EditLine.OpenStockButton', name: 'checkStockButton', showing: false }] }, { kind: 'OB.UI.List', name: 'returnreason', classes: 'combo', style: 'width: 100%; margin-bottom: 0px; height: 30px ', events: { onSetReason: '' }, handlers: { onchange: 'changeReason' }, changeReason: function (inSender, inEvent) { if (this.children[this.getSelected()].getValue() === '') { this.owner.line.unset('returnReason'); } else { this.owner.line.set('returnReason', this.children[this.getSelected()].getValue()); } }, renderHeader: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(''); this.setContent(OB.I18N.getLabel('OBPOS_ReturnReasons')); } }), renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get('id')); this.setContent(this.model.get('_identifier')); } }), renderEmpty: 'enyo.Control' }, { classes: 'span12', components: [{ classes: 'span7', kind: 'Scroller', name: 'linePropertiesContainer', maxHeight: '134px', thumb: true, horizontal: 'hidden', style: 'padding: 8px 0px 4px 25px; line-height: 120%;' }, { classes: 'span4', sytle: 'text-align: right', components: [{ style: 'padding: 2px 10px 10px 10px;', components: [{ tag: 'div', classes: 'image-wrap image-editline', contentType: 'image/png', style: 'width: 128px; height: 128px', components: [{ tag: 'img', name: 'icon', style: 'margin: auto; height: 100%; width: 100%; background-size: contain; background-repeat:no-repeat; background-position:center;' }] }, { name: 'editlineimage', kind: 'OB.UI.Thumbnail', classes: 'image-wrap image-editline', width: '105px', height: '105px' }] }] }] }, { name: 'msgaction', style: 'padding: 10px;', components: [{ name: 'txtaction', style: 'float:left;' }] }] }] }], selectedListener: function (line) { this.$.returnreason.setSelected(0); if (this.line) { this.line.off('change', this.render); } this.line = line; if (this.line) { this.line.on('change', this.render, this); } if (this.line && (this.line.get('product').get('showstock') || this.line.get('product').get('_showstock')) && !this.line.get('product').get('ispack') && OB.POS.modelterminal.get('connectedToERP')) { this.$.checkStockButton.show(); } else { this.$.checkStockButton.hide(); } if (this.line && this.line.get('promotions')) { if (this.line.get('promotions').length > 0) { var filtered; filtered = _.filter(this.line.get('promotions'), function (prom) { //discrectionary discounts ids return prom.discountType === '20E4EC27397344309A2185097392D964' || prom.discountType === 'D1D193305A6443B09B299259493B272A' || prom.discountType === '8338556C0FBF45249512DB343FEFD280' || prom.discountType === '7B49D8CC4E084A75B7CB4D85A6A3A578'; }, this); if (filtered.length === this.line.get('promotions').length) { //lines with just discrectionary discounts can be removed. this.$.removeDiscountButton.show(); } } } else { this.$.removeDiscountButton.hide(); } if ((!_.isUndefined(line) && !_.isUndefined(line.get('originalOrderLineId'))) || this.model.get('order').get('orderType') === 1) { this.$.returnLine.hide(); } else if (OB.POS.modelterminal.get('permissions')[this.$.returnLine.permission] && !(this.model.get('order').get('isPaid') === true || this.model.get('order').get('isLayaway') === true || this.model.get('order').get('isQuotation') === true)) { this.$.returnLine.show(); } this.render(); }, receiptChanged: function () { this.inherited(arguments); this.line = null; this.receipt.get('lines').on('selected', this.selectedListener, this); }, render: function () { var me = this, selectedReason; this.inherited(arguments); if (this.line) { this.$.msgaction.hide(); this.$.msgedit.show(); if (OB.MobileApp.model.get('permissions')["OBPOS_retail.productImages"]) { this.$.icon.applyStyle('background-image', 'url(' + OB.UTIL.getImageURL(this.line.get('product').get('id')) + '), url(' + "../org.openbravo.mobile.core/assets/img/box.png" + ')'); this.$.editlineimage.hide(); } else { this.$.editlineimage.setImg(this.line.get('product').get('img')); this.$.icon.parent.hide(); } if (this.line.get('qty') < OB.DEC.Zero) { if (!_.isUndefined(this.line.get('returnReason'))) { selectedReason = _.filter(this.$.returnreason.children, function (reason) { return reason.getValue() === me.line.get('returnReason'); })[0]; this.$.returnreason.setSelected(selectedReason.getNodeProperty('index')); } this.$.returnreason.show(); } else { this.$.returnreason.hide(); } } else { this.$.txtaction.setContent(OB.I18N.getLabel('OBPOS_NoLineSelected')); this.$.msgedit.hide(); this.$.msgaction.show(); if (OB.MobileApp.model.get('permissions')["OBPOS_retail.productImages"]) { this.$.icon.applyStyle('background-image', ''); } else { if (OB.MobileApp.model.get('permissions')["OBPOS_retail.productImages"]) { this.$.icon.applyStyle('background-image', ''); } else { this.$.editlineimage.setImg(null); } } } enyo.forEach(this.$.linePropertiesContainer.getComponents(), function (compToRender) { if (compToRender.kindName.indexOf("enyo.") !== 0) { compToRender.render(this.line); } }, this); }, initComponents: function () { var sortedPropertiesByPosition; this.inherited(arguments); sortedPropertiesByPosition = _.sortBy(this.propertiesToShow, function (comp) { return (comp.position ? comp.position : (comp.position === 0 ? 0 : 999)); }); enyo.forEach(sortedPropertiesByPosition, function (compToCreate) { this.$.linePropertiesContainer.createComponent(compToCreate); }, this); }, init: function (model) { this.model = model; this.reasons = new OB.Collection.ReturnReasonList(); this.$.returnreason.setCollection(this.reasons); function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackReasons(dataReasons, me) { if (dataReasons && dataReasons.length > 0) { me.reasons.reset(dataReasons.models); } else { me.reasons.reset(); } } OB.Dal.find(OB.Model.ReturnReason, null, successCallbackReasons, errorCallback, this); } }); enyo.kind({ kind: 'OB.UI.SmallButton', name: 'OB.OBPOSPointOfSale.UI.EditLine.OpenStockButton', events: { onShowLeftSubWindow: '' }, content: '', classes: 'btnlink-orange', tap: function () { var line = this.owner.line; var product = this.owner.line.get('product'); var params = {}; //show always or just when the product has been set to show stock screen? if ((product.get('showstock') || product.get('_showstock')) && !product.get('ispack') && OB.POS.modelterminal.get('connectedToERP')) { params.leftSubWindow = OB.OBPOSPointOfSale.UICustomization.stockLeftSubWindow; params.product = product; params.line = line; params.warehouse = this.owner.line.get('warehouse'); this.doShowLeftSubWindow(params); } }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBPOS_checkStock')); } }); /* ************************************************************************************ * Copyright (C) 2013-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo,_ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Payment', published: { receipt: null }, handlers: { onButtonStatusChanged: 'buttonStatusChanged' }, getSelectedPayment: function () { if (this.receipt && this.receipt.selectedPayment) { return this.receipt.selectedPayment; } return null; }, buttonStatusChanged: function (inSender, inEvent) { var payment, amt, change, pending, isMultiOrders, paymentstatus; payment = inEvent.value.payment || OB.MobileApp.model.paymentnames[OB.POS.modelterminal.get('paymentcash')]; if (_.isUndefined(payment)) { return true; } isMultiOrders = this.model.isValidMultiOrderState(); change = this.model.getChange(); pending = this.model.getPending(); if (!isMultiOrders) { this.receipt.selectedPayment = payment.payment.searchKey; paymentstatus = this.receipt.getPaymentStatus(); } else { this.model.get('multiOrders').set('selectedPayment', payment.payment.searchKey); paymentstatus = this.model.get('multiOrders').getPaymentStatus(); } if (!_.isNull(change) && change) { this.$.change.setContent(OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(change, payment.mulrate), payment.symbol, payment.currencySymbolAtTheRight)); OB.MobileApp.model.set('changeReceipt', OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(change, payment.mulrate), payment.symbol, payment.currencySymbolAtTheRight)); } else if (!_.isNull(pending) && pending) { this.$.totalpending.setContent(OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(pending, payment.mulrate), payment.symbol, payment.currencySymbolAtTheRight)); } this.checkEnoughCashAvailable(paymentstatus, payment); }, components: [{ style: 'background-color: #363636; color: white; height: 200px; margin: 5px; padding: 5px; position: relative;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12' }] }, { classes: 'row-fluid', components: [{ classes: 'span9', components: [{ style: 'padding: 10px 0px 0px 10px; height: 28px;', components: [{ tag: 'span', name: 'totalpending', style: 'font-size: 24px; font-weight: bold;' }, { tag: 'span', name: 'totalpendinglbl' }, { tag: 'span', name: 'change', style: 'font-size: 24px; font-weight: bold;' }, { tag: 'span', name: 'changelbl' }, { tag: 'span', name: 'overpayment', style: 'font-size: 24px; font-weight: bold;' }, { tag: 'span', name: 'overpaymentlbl' }, { tag: 'span', name: 'exactlbl' }, { tag: 'span', name: 'donezerolbl' }, { name: 'creditsalesaction', kind: 'OB.OBPOSPointOfSale.UI.CreditButton' }, { name: 'layawayaction', kind: 'OB.OBPOSPointOfSale.UI.LayawayButton', showing: false }] }, { style: 'overflow:auto; width: 100%;', components: [{ style: 'padding: 5px', components: [{ style: 'margin: 2px 0px 0px 0px; border-bottom: 1px solid #cccccc;' }, { kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '150px', name: 'payments', renderEmpty: enyo.kind({ style: 'height: 36px' }), renderLine: 'OB.OBPOSPointOfSale.UI.RenderPaymentLine' }, { kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '150px', name: 'multiPayments', showing: false, renderEmpty: enyo.kind({ style: 'height: 36px' }), renderLine: 'OB.OBPOSPointOfSale.UI.RenderPaymentLine' }, { style: 'position: absolute; bottom: 0px; height: 20px; color: #ff0000;', name: 'noenoughchangelbl', showing: false }] }] }] }, { classes: 'span3', components: [{ style: 'float: right;', name: 'doneaction', components: [{ kind: 'OB.OBPOSPointOfSale.UI.DoneButton' }] }, { style: 'float: right;', name: 'exactaction', components: [{ kind: 'OB.OBPOSPointOfSale.UI.ExactButton' }] }] }] }] }], receiptChanged: function () { var me = this; this.$.payments.setCollection(this.receipt.get('payments')); this.$.multiPayments.setCollection(this.model.get('multiOrders').get('payments')); this.receipt.on('change:payment change:change calculategross change:bp change:gross', function () { this.updatePending(); }, this); this.model.get('leftColumnViewManager').on('change:currentView', function () { if (!this.model.get('leftColumnViewManager').isMultiOrder()) { this.updatePending(); } else { this.updatePendingMultiOrders(); } }, this); this.updatePending(); if (this.model.get('leftColumnViewManager').isMultiOrder()) { this.updatePendingMultiOrders(); } this.receipt.on('change:orderType change:isLayaway change:payment', function (model) { if (this.model.get('leftColumnViewManager').isMultiOrder()) { this.$.creditsalesaction.hide(); this.$.layawayaction.hide(); return; } var payment = OB.MobileApp.model.paymentnames[OB.MobileApp.model.get('paymentcash')]; if ((model.get('orderType') === 2 || (model.get('isLayaway'))) && model.get('orderType') !== 3 && !model.getPaymentStatus().done) { this.$.creditsalesaction.hide(); this.$.layawayaction.setContent(OB.I18N.getLabel('OBPOS_LblLayaway')); this.$.layawayaction.show(); } else if (model.get('orderType') === 3) { this.$.creditsalesaction.hide(); this.$.layawayaction.hide(); } else { this.$.layawayaction.hide(); } }, this); }, updatePending: function () { if (this.model.get('leftColumnViewManager').isMultiOrder()) { return true; } var paymentstatus = this.receipt.getPaymentStatus(); var symbol = '', rate = OB.DEC.One, symbolAtRight = true, isCashType = true; if (_.isEmpty(OB.MobileApp.model.paymentnames)) { symbol = OB.MobileApp.model.get('terminal').symbol; symbolAtRight = OB.MobileApp.model.get('terminal').currencySymbolAtTheRight; } if (!_.isUndefined(this.receipt) && !_.isUndefined(OB.MobileApp.model.paymentnames[this.receipt.selectedPayment])) { symbol = OB.MobileApp.model.paymentnames[this.receipt.selectedPayment].symbol; rate = OB.MobileApp.model.paymentnames[this.receipt.selectedPayment].mulrate; symbolAtRight = OB.MobileApp.model.paymentnames[this.receipt.selectedPayment].currencySymbolAtTheRight; isCashType = OB.MobileApp.model.paymentnames[this.receipt.selectedPayment].paymentMethod.iscash; } this.checkEnoughCashAvailable(paymentstatus, OB.MobileApp.model.paymentnames[this.receipt.selectedPayment || OB.POS.modelterminal.get('paymentcash')]); if (paymentstatus.change) { this.$.change.setContent(OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(this.receipt.getChange(), rate), symbol, symbolAtRight)); OB.MobileApp.model.set('changeReceipt', OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(this.receipt.getChange(), rate), symbol, symbolAtRight)); this.$.change.show(); this.$.changelbl.show(); } else { this.$.change.hide(); this.$.changelbl.hide(); } if (paymentstatus.overpayment) { this.$.overpayment.setContent(paymentstatus.overpayment); this.$.overpayment.show(); this.$.overpaymentlbl.show(); } else { this.$.overpayment.hide(); this.$.overpaymentlbl.hide(); } if (paymentstatus.done) { this.$.totalpending.hide(); this.$.totalpendinglbl.hide(); if (!_.isEmpty(OB.MobileApp.model.paymentnames)) { this.$.doneaction.show(); } this.$.creditsalesaction.hide(); this.$.layawayaction.hide(); } else { this.$.totalpending.setContent(OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(this.receipt.getPending(), rate), symbol, symbolAtRight)); this.$.totalpending.show(); // if (this.receipt.get('orderType') === 1 || this.receipt.get('orderType') === 3) { if (paymentstatus.isNegative || this.receipt.get('orderType') === 3) { this.$.totalpendinglbl.setContent(OB.I18N.getLabel('OBPOS_ReturnRemaining')); } else { this.$.totalpendinglbl.setContent(OB.I18N.getLabel('OBPOS_PaymentsRemaining')); } this.$.totalpendinglbl.show(); this.$.doneaction.hide(); if (this.$.doneButton.drawerpreference) { this.$.doneButton.setContent(OB.I18N.getLabel('OBPOS_LblOpen')); this.$.doneButton.drawerOpened = false; } if (OB.POS.modelterminal.get('terminal').allowpayoncredit && this.receipt.get('bp')) { if ((this.receipt.get('bp').get('creditLimit') > 0 || this.receipt.get('bp').get('creditUsed') < 0 || this.receipt.getGross() < 0) && !this.$.layawayaction.showing) { this.$.creditsalesaction.show(); } else { this.$.creditsalesaction.hide(); } } } if (paymentstatus.done || this.receipt.getGross() === 0) { this.$.exactaction.hide(); this.$.creditsalesaction.hide(); this.$.layawayaction.hide(); } else { if (!_.isEmpty(OB.MobileApp.model.paymentnames)) { this.$.exactaction.show(); } if (this.receipt.get('orderType') === 2 || (this.receipt.get('isLayaway') && this.receipt.get('orderType') !== 3)) { this.$.layawayaction.show(); if (!this.receipt.get('isLayaway')) { this.$.exactaction.hide(); } } else if (this.receipt.get('orderType') === 3) { this.$.layawayaction.hide(); } if (OB.POS.modelterminal.get('terminal').allowpayoncredit && this.receipt.get('bp')) { if ((this.receipt.get('bp').get('creditLimit') > 0 || this.receipt.get('bp').get('creditUsed') < 0 || this.receipt.getGross() < 0) && !this.$.layawayaction.showing) { this.$.creditsalesaction.show(); } else { this.$.creditsalesaction.hide(); } } } if (paymentstatus.done && !paymentstatus.change && !paymentstatus.overpayment) { if (this.receipt.getGross() === 0) { this.$.exactlbl.hide(); this.$.donezerolbl.show(); } else { this.$.donezerolbl.hide(); // if (this.receipt.get('orderType') === 1 || this.receipt.get('orderType') === 3) { if (paymentstatus.isNegative || this.receipt.get('orderType') === 3) { this.$.exactlbl.setContent(OB.I18N.getLabel('OBPOS_ReturnExact')); } else { this.$.exactlbl.setContent(OB.I18N.getLabel('OBPOS_PaymentsExact')); } this.$.exactlbl.show(); } } else { this.$.exactlbl.hide(); this.$.donezerolbl.hide(); } }, updatePendingMultiOrders: function () { var paymentstatus = this.model.get('multiOrders'); var symbol = '', symbolAtRight = true, rate = OB.DEC.One, isCashType = true, selectedPayment; this.$.layawayaction.hide(); if (_.isEmpty(OB.MobileApp.model.paymentnames)) { symbol = OB.MobileApp.model.get('terminal').symbol; symbolAtRight = OB.MobileApp.model.get('terminal').currencySymbolAtTheRight; } if (paymentstatus.get('selectedPayment')) { selectedPayment = OB.MobileApp.model.paymentnames[paymentstatus.get('selectedPayment')]; } else { selectedPayment = OB.MobileApp.model.paymentnames[OB.POS.modelterminal.get('paymentcash')]; } if (!_.isUndefined(selectedPayment)) { symbol = selectedPayment.symbol; rate = selectedPayment.mulrate; symbolAtRight = selectedPayment.currencySymbolAtTheRight; isCashType = selectedPayment.paymentMethod.iscash; } this.checkEnoughCashAvailable(paymentstatus.getPaymentStatus(), selectedPayment); if (paymentstatus.get('change')) { this.$.change.setContent(OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(paymentstatus.get('change'), rate), symbol, symbolAtRight)); OB.MobileApp.model.set('changeReceipt', OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(paymentstatus.get('change'), rate), symbol, symbolAtRight)); this.$.change.show(); this.$.changelbl.show(); } else { this.$.change.hide(); this.$.changelbl.hide(); } //overpayment if (OB.DEC.compare(OB.DEC.sub(paymentstatus.get('payment'), paymentstatus.get('total'))) > 0) { this.$.overpayment.setContent(OB.I18N.formatCurrency(OB.DEC.sub(paymentstatus.get('payment'), paymentstatus.get('total')))); this.$.overpayment.show(); this.$.overpaymentlbl.show(); } else { this.$.overpayment.hide(); this.$.overpaymentlbl.hide(); } if (paymentstatus.get('multiOrdersList').length > 0 && OB.DEC.compare(paymentstatus.get('total')) >= 0 && OB.DEC.compare(OB.DEC.sub(paymentstatus.get('payment'), paymentstatus.get('total'))) >= 0) { this.$.totalpending.hide(); this.$.totalpendinglbl.hide(); if (!_.isEmpty(OB.MobileApp.model.paymentnames)) { this.$.doneaction.show(); } this.$.creditsalesaction.hide(); // this.$.layawayaction.hide(); } else { this.$.totalpending.setContent(OB.I18N.formatCurrency(OB.I18N.formatCurrencyWithSymbol(OB.DEC.mul(OB.DEC.sub(paymentstatus.get('total'), paymentstatus.get('payment')), rate), symbol, symbolAtRight))); this.$.totalpending.show(); this.$.totalpendinglbl.show(); this.$.doneaction.hide(); if (this.$.doneButton.drawerpreference) { this.$.doneButton.setContent(OB.I18N.getLabel('OBPOS_LblOpen')); this.$.doneButton.drawerOpened = false; } } this.$.creditsalesaction.hide(); this.$.layawayaction.hide(); if (paymentstatus.get('multiOrdersList').length > 0 && OB.DEC.compare(paymentstatus.get('total')) >= 0 && (OB.DEC.compare(OB.DEC.sub(paymentstatus.get('payment'), paymentstatus.get('total'))) >= 0 || paymentstatus.get('total') === 0)) { this.$.exactaction.hide(); } else { if (!_.isEmpty(OB.MobileApp.model.paymentnames)) { this.$.exactaction.show(); } } if (paymentstatus.get('multiOrdersList').length > 0 && OB.DEC.compare(paymentstatus.get('total')) >= 0 && OB.DEC.compare(OB.DEC.sub(paymentstatus.get('payment'), paymentstatus.get('total'))) >= 0 && !paymentstatus.get('change') && OB.DEC.compare(OB.DEC.sub(paymentstatus.get('payment'), paymentstatus.get('total'))) <= 0) { if (paymentstatus.get('total') === 0) { this.$.exactlbl.hide(); this.$.donezerolbl.show(); } else { this.$.donezerolbl.hide(); this.$.exactlbl.setContent(OB.I18N.getLabel('OBPOS_PaymentsExact')); this.$.exactlbl.show(); } } else { this.$.exactlbl.hide(); this.$.donezerolbl.hide(); } }, checkEnoughCashAvailable: function (paymentstatus, selectedPayment) { var currentCash = OB.DEC.Zero, requiredCash, hasEnoughCash; if (selectedPayment && selectedPayment.paymentMethod.iscash) { currentCash = selectedPayment.currentCash || OB.DEC.Zero; } if (OB.UTIL.isNullOrUndefined(selectedPayment) || !selectedPayment.paymentMethod.iscash) { requiredCash = OB.DEC.Zero; } else if (paymentstatus.isNegative) { requiredCash = paymentstatus.pendingAmt; paymentstatus.payments.each(function (payment) { if (payment.get('kind') === selectedPayment.payment.searchKey) { requiredCash = OB.DEC.add(requiredCash, payment.get('amount')); } }); } else { requiredCash = paymentstatus.changeAmt; } hasEnoughCash = OB.DEC.compare(OB.DEC.sub(currentCash, requiredCash)) >= 0; if (hasEnoughCash) { this.$.noenoughchangelbl.hide(); this.$.payments.scrollAreaMaxHeight = '150px'; this.$.doneButton.setDisabled(false); } else { this.$.noenoughchangelbl.show(); this.$.payments.scrollAreaMaxHeight = '130px'; this.$.doneButton.setDisabled(true); } }, initComponents: function () { this.inherited(arguments); this.$.totalpendinglbl.setContent(OB.I18N.getLabel('OBPOS_PaymentsRemaining')); this.$.changelbl.setContent(OB.I18N.getLabel('OBPOS_PaymentsChange')); this.$.overpaymentlbl.setContent(OB.I18N.getLabel('OBPOS_PaymentsOverpayment')); this.$.exactlbl.setContent(OB.I18N.getLabel('OBPOS_PaymentsExact')); this.$.donezerolbl.setContent(OB.I18N.getLabel('OBPOS_MsgPaymentAmountZero')); this.$.noenoughchangelbl.setContent(OB.I18N.getLabel('OBPOS_NoEnoughCash')); }, init: function (model) { var me = this; this.model = model; if (_.isEmpty(OB.MobileApp.model.paymentnames)) { this.$.doneaction.show(); this.$.exactaction.hide(); } this.model.get('multiOrders').get('multiOrdersList').on('all', function (event) { if (this.model.isValidMultiOrderState()) { this.updatePendingMultiOrders(); } }, this); this.model.get('multiOrders').on('change:payment change:total change:change', function () { this.updatePendingMultiOrders(); }, this); this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { if (changedModel.isOrder()) { this.$.multiPayments.hide(); this.$.payments.show(); return; } if (changedModel.isMultiOrder()) { this.$.multiPayments.show(); this.$.payments.hide(); return; } }, this); // this.model.get('multiOrders').on('change:isMultiOrders', function () { // if (!this.model.get('multiOrders').get('isMultiOrders')) { // this.$.multiPayments.hide(); // this.$.payments.show(); // } else { // this.$.payments.hide(); // this.$.multiPayments.show(); // } // }, this); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.DoneButton', kind: 'OB.UI.RegularButton', drawerOpened: true, init: function (model) { this.model = model; this.setContent(OB.I18N.getLabel('OBPOS_LblDone')); this.model.get('order').on('change:openDrawer', function () { this.drawerpreference = this.model.get('order').get('openDrawer'); var me = this; if (this.drawerpreference) { this.drawerOpened = false; this.setContent(OB.I18N.getLabel('OBPOS_LblOpen')); } else { this.drawerOpened = true; this.setContent(OB.I18N.getLabel('OBPOS_LblDone')); } }, this); this.model.get('multiOrders').on('change:openDrawer', function () { this.drawerpreference = this.model.get('multiOrders').get('openDrawer'); if (this.drawerpreference) { this.drawerOpened = false; this.setContent(OB.I18N.getLabel('OBPOS_LblOpen')); } else { this.drawerOpened = true; this.setContent(OB.I18N.getLabel('OBPOS_LblDone')); } }, this); }, tap: function () { var myModel = this.owner.model, me = this, payments; this.allowOpenDrawer = false; if (myModel.get('leftColumnViewManager').isOrder()) { payments = this.owner.receipt.get('payments'); } else { payments = this.owner.model.get('multiOrders').get('payments'); } payments.each(function (payment) { if (payment.get('allowOpenDrawer') || payment.get('isCash')) { me.allowOpenDrawer = true; } }); //if (this.owner.model.get('multiOrders').get('multiOrdersList').length === 0 && !this.owner.model.get('multiOrders').get('isMultiOrders')) { if (myModel.get('leftColumnViewManager').isOrder()) { if (this.drawerpreference && this.allowOpenDrawer) { if (this.drawerOpened) { if (this.owner.receipt.get('orderType') === 3) { this.owner.receipt.trigger('voidLayaway'); } else { this.setDisabled(true); this.owner.model.get('order').trigger('paymentDone', false); } this.drawerOpened = false; this.setContent(OB.I18N.getLabel('OBPOS_LblOpen')); } else { OB.POS.hwserver.openDrawer({ openFirst: true, receipt: me.owner.receipt }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); this.drawerOpened = true; this.setContent(OB.I18N.getLabel('OBPOS_LblDone')); } } else { //Void Layaway if (this.owner.receipt.get('orderType') === 3) { this.owner.receipt.trigger('voidLayaway'); } else { this.setDisabled(true); this.owner.receipt.trigger('paymentDone', this.allowOpenDrawer); } } } else { if (this.drawerpreference && this.allowOpenDrawer) { if (this.drawerOpened) { this.owner.model.get('multiOrders').trigger('paymentDone', false); this.owner.model.get('multiOrders').set('openDrawer', false); this.drawerOpened = false; this.setContent(OB.I18N.getLabel('OBPOS_LblOpen')); } else { OB.POS.hwserver.openDrawer({ openFirst: true, receipt: me.owner.model.get('multiOrders') }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); this.drawerOpened = true; this.setContent(OB.I18N.getLabel('OBPOS_LblDone')); } } else { this.owner.model.get('multiOrders').trigger('paymentDone', this.allowOpenDrawer); this.owner.model.get('multiOrders').set('openDrawer', false); } } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ExactButton', events: { onExactPayment: '' }, kind: 'OB.UI.RegularButton', classes: 'btn-icon-adaptative btn-icon-check btnlink-green', style: 'width: 73px; height: 43.37px;', tap: function () { this.doExactPayment(); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.RenderPaymentLine', classes: 'btnselect', components: [{ style: 'color:white;', components: [{ name: 'name', style: 'float: left; width: 20%; padding: 5px 0px 0px 0px;' }, { name: 'info', style: 'float: left; width: 15%; padding: 5px 0px 0px 0px;' }, { name: 'foreignAmount', style: 'float: left; width: 20%; padding: 5px 0px 0px 0px; text-align: right;' }, { name: 'amount', style: 'float: left; width: 25%; padding: 5px 0px 0px 0px; text-align: right;' }, { style: 'float: left; width: 20%; text-align: right;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.RemovePayment' }] }, { style: 'clear: both;' }] }], initComponents: function () { this.inherited(arguments); this.$.name.setContent(OB.POS.modelterminal.getPaymentName(this.model.get('kind')) || this.model.get('name')); this.$.amount.setContent(this.model.printAmount()); if (this.model.get('rate') && this.model.get('rate') !== '1') { this.$.foreignAmount.setContent(this.model.printForeignAmount()); } else { this.$.foreignAmount.setContent(''); } if (this.model.get('description')) { this.$.info.setContent(this.model.get('description')); } else { if (this.model.get('paymentData')) { this.$.info.setContent(this.model.get('paymentData').Name); } else { this.$.info.setContent(''); } } if (this.model.get('isPrePayment')) { this.hide(); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.RemovePayment', events: { onRemovePayment: '' }, kind: 'OB.UI.SmallButton', classes: 'btnlink-darkgray btnlink-payment-clear btn-icon-small btn-icon-clearPayment', tap: function () { var me = this; if ((_.isUndefined(this.deleting) || this.deleting === false)) { this.deleting = true; this.removeClass('btn-icon-clearPayment'); this.addClass('btn-icon-loading'); this.doRemovePayment({ payment: this.owner.model, removeCallback: function () { me.deleting = false; me.removeClass('btn-icon-loading'); me.addClass('btn-icon-clearPayment'); } }); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.CreditButton', kind: 'OB.UI.SmallButton', i18nLabel: 'OBPOS_LblCreditSales', classes: 'btn-icon-small btnlink-green', style: 'width: 120px; float: right; margin: -5px 5px 0px 0px; height: 1.8em', permission: 'OBPOS_receipt.creditsales', events: { onShowPopup: '' }, init: function (model) { this.model = model; }, disabled: false, putDisabled: function (status) { if (status === false) { this.setDisabled(false); this.removeClass('disabled'); this.disabled = false; } else { this.setDisabled(true); this.addClass('disabled'); this.disabled = true; } }, initComponents: function () { this.inherited(arguments); this.putDisabled(!OB.MobileApp.model.hasPermission(this.permission)); }, tap: function () { if (this.disabled) { return true; } var process = new OB.DS.Process('org.openbravo.retail.posterminal.CheckBusinessPartnerCredit'); var me = this; var paymentstatus = this.model.get('order').getPaymentStatus(); if (!paymentstatus.isReturn) { //this.setContent(OB.I18N.getLabel('OBPOS_LblLoading')); process.exec({ businessPartnerId: this.model.get('order').get('bp').get('id'), totalPending: this.model.get('order').getPending() }, function (data) { if (data) { if (data.enoughCredit) { me.doShowPopup({ popup: 'modalEnoughCredit', args: { order: me.model.get('order') } }); //this.setContent(OB.I18N.getLabel('OBPOS_LblCreditSales')); } else { var bpName = data.bpName; var actualCredit = data.actualCredit; me.doShowPopup({ popup: 'modalNotEnoughCredit', args: { bpName: bpName, actualCredit: actualCredit } }); //this.setContent(OB.I18N.getLabel('OBPOS_LblCreditSales')); //OB.UI.UTILS.domIdEnyoReference['modalNotEnoughCredit'].$.bodyContent.children[0].setContent(); } } else { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgErrorCreditSales')); } }, function () { me.doShowPopup({ popup: 'modalEnoughCredit', args: { order: me.model.get('order'), message: 'OBPOS_Unabletocheckcredit' } }); }); // } else if (this.model.get('order').get('orderType') === 1) { } else if (paymentstatus.isReturn) { var actualCredit; var creditLimit = this.model.get('order').get('bp').get('creditLimit'); var creditUsed = this.model.get('order').get('bp').get('creditUsed'); var totalPending = this.model.get('order').getPending(); this.doShowPopup({ popup: 'modalEnoughCredit', args: { order: this.model.get('order') } }); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.LayawayButton', kind: 'OB.UI.SmallButton', content: '', classes: 'btn-icon-small btnlink-green', style: 'width: 120px; float: right; margin: -5px 5px 0px 0px; height: 1.8em', permission: 'OBPOS_receipt.layaway', init: function (model) { this.model = model; this.setContent(OB.I18N.getLabel('OBPOS_LblLayaway')); }, tap: function () { var receipt = this.owner.receipt, negativeLines, me = this, myModel = this.owner.model, payments; this.allowOpenDrawer = false; if (myModel.get('leftColumnViewManager').isOrder()) { payments = this.owner.receipt.get('payments'); } else { payments = this.owner.model.get('multiOrders').get('payments'); } payments.each(function (payment) { if (payment.get('allowOpenDrawer') || payment.get('isCash')) { me.allowOpenDrawer = true; } }); if (receipt) { negativeLines = _.find(receipt.get('lines').models, function (line) { return line.get('qty') < 0; }); if (negativeLines) { OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_layawaysOrdersWithReturnsNotAllowed')); return true; } if (receipt.get('generateInvoice')) { OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_noInvoiceIfLayaway')); receipt.set('generateInvoice', false); } } receipt.trigger('paymentDone', me.allowOpenDrawer); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Discounts', handlers: { onApplyDiscounts: 'applyDiscounts', onDiscountsClose: 'closingDiscounts', onDiscountQtyChanged: 'discountQtyChanged', onCheckedTicketLine: 'ticketLineChecked' }, events: { onDiscountsModeFinished: '', onDisableKeyboard: '', onDiscountsModeKeyboard: '', onShowPopup: '', onCheckAllTicketLines: '' }, checkedLines: [], style: 'position:relative; background-color: orange; background-size: cover; color: white; height: 200px; margin: 5px; padding: 5px', components: [{ kind: 'Scroller', maxHeight: '130px', thumb: true, horizontal: 'hidden', components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 35%; height: 40px; float: left; text-align: left', components: [{ style: 'padding: 5px 8px 0px 3px;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LineDiscount')); } }] }, { style: 'border: 1px solid #F0F0F0; float: left; width: 63%;', components: [{ kind: 'OB.UI.List', name: 'discountsList', tag: 'select', onchange: 'discountChanged', classes: 'discount-dialog-profile-combo', renderEmpty: enyo.Control, renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.setValue(this.model.get('id')); this.originalText = this.model.get('_identifier'); // TODO: this shouldn't be hardcoded but defined in each promotion if (this.model.get('discountType') === 'D1D193305A6443B09B299259493B272A' || this.model.get('discountType') === '20E4EC27397344309A2185097392D964') { //variable this.requiresQty = true; if (this.model.get('discountType') === '20E4EC27397344309A2185097392D964') { //variable porcentaje this.units = '%'; if (!_.isUndefined(this.model.get('obdiscPercentage')) && !_.isNull(this.model.get('obdiscPercentage'))) { this.amt = this.model.get('obdiscPercentage'); } } else if (this.model.get('discountType') === 'D1D193305A6443B09B299259493B272A') { //variable qty this.units = OB.POS.modelterminal.get('terminal').currency$_identifier; if (this.model.get('obdiscAmt')) { this.amt = this.model.get('obdiscAmt'); } } } else { //fixed this.requiresQty = false; if (this.model.get('discountType') === '8338556C0FBF45249512DB343FEFD280') { //fixed percentage this.units = '%'; if (!_.isUndefined(this.model.get('obdiscPercentage')) && !_.isNull(this.model.get('obdiscPercentage'))) { this.amt = this.model.get('obdiscPercentage'); } } else if (this.model.get('discountType') === '7B49D8CC4E084A75B7CB4D85A6A3A578') { //fixed amount this.units = OB.POS.modelterminal.get('terminal').currency$_identifier; if (!_.isUndefined(this.model.get('obdiscAmt')) && !_.isNull(this.model.get('obdiscAmt'))) { this.amt = this.model.get('obdiscAmt'); } } } if (this.amt) { this.setContent(this.originalText + ' - ' + this.amt + ' ' + this.units); } else { this.setContent(this.originalText); } } }) }] }] }, { style: 'clear: both' }, { components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 35%; height: 40px; float: left; text-align: left', components: [{ style: 'padding: 5px 8px 0px 3px;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_overridePromotions')); } }] }, { style: 'border: 1px solid #F0F0F0; float: left; width: 63%;', components: [{ classes: 'modal-dialog-profile-checkbox', components: [{ kind: 'OB.OBPOSPointOfSale.UI.Discounts.btnCheckOverride', name: 'checkOverride', classes: 'modal-dialog-btn-check' }] }] }] }, { style: 'clear: both' }, { components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 35%; height: 40px; float: left; text-align: left', components: [{ style: 'padding: 5px 8px 0px 3px;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_applyToAllLines')); } }] }, { style: 'border: 1px solid #F0F0F0; float: left; width: 63%;', components: [{ classes: 'modal-dialog-profile-checkbox', components: [{ kind: 'OB.OBPOSPointOfSale.UI.Discounts.btnCheckAll', name: 'checkSelectAll', classes: 'modal-dialog-btn-check' }] }] }] }, { style: 'clear: both' }] }, { style: 'padding: 10px;', components: [{ style: 'text-align: center;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.Discounts.btnDiscountsApply', name: 'btnApply' }, { kind: 'OB.OBPOSPointOfSale.UI.Discounts.btnDiscountsCancel' }] }] }], show: function () { var me = this; OB.MobileApp.view.scanningFocus(false); me.discounts.reset(); //uncheck lines this.doCheckAllTicketLines({ status: false }); //load discounts OB.Dal.find(OB.Model.Discount, { _whereClause: "where m_offer_type_id in (" + OB.Model.Discounts.getManualPromotions() + ") " // filter discretionary discounts by current role + " AND ((EM_OBDISC_ROLE_SELECTION = 'Y'" // + " AND NOT EXISTS" // + " (SELECT 1" // + " FROM OBDISC_OFFER_ROLE" // + " WHERE M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND AD_ROLE_ID = '" + OB.MobileApp.model.get('context').role.id + "'" // + " ))" // + " OR (EM_OBDISC_ROLE_SELECTION = 'N'" // + " AND EXISTS" // + " (SELECT 1" // + " FROM OBDISC_OFFER_ROLE" // + " WHERE M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND AD_ROLE_ID = '" + OB.MobileApp.model.get('context').role.id + "'" // + " )))" // }, function (promos) { me.discounts.reset(promos.models); //set the keyboard for selected discount me.discountChanged({}, { originator: me.$.discountsList }); }, function () { //show an error in combo var tr; me.discounts.reset(); tr = me.$.discountsList.createComponent({ kind: 'enyo.Option', text: OB.I18N.getLabel('OBPOS_errorGettingDiscounts'), value: 'error', initComponents: function () { this.setValue(this.value); this.setContent(this.text); } }); tr.render(); }); this.inherited(arguments); }, disableKeyboard: function () { this.doDiscountsModeKeyboard({ status: true, writable: false }); }, enableKeyboard: function () { this.doDiscountsModeKeyboard({ status: true, writable: true }); }, _searchSelectedComponent: function (selectedId) { return _.find(this.$.discountsList.getComponents(), function (comp) { if (comp.getValue() === selectedId) { return true; } }, this); }, discountQtyChanged: function (inSender, inEvent) { if (!OB.DEC.isNumber(inEvent.qty)) { this.doShowPopup({ popup: 'modalNotValidValueForDiscount' }); return; } var comp = this._searchSelectedComponent(this.$.discountsList.getValue()); if (comp.units === '%' && OB.DEC.toBigDecimal(inEvent.qty) > 100) { this.doShowPopup({ popup: 'modalNotValidValueForDiscount' }); return; } comp.setContent(comp.originalText + ' - ' + inEvent.qty + ' ' + comp.units); comp.amt = inEvent.qty; }, initComponents: function () { var discountsModel = Backbone.Collection.extend({ model: OB.Model.Discounts }); this.inherited(arguments); this.discounts = new discountsModel(); this.$.discountsList.setCollection(this.discounts); }, ticketLineChecked: function (inSender, inEvent) { if (inEvent.allChecked) { this.$.checkSelectAll.check(); } else { this.$.checkSelectAll.unCheck(); } this.checkedLines = inEvent.checkedLines; if (this.checkedLines.length > 0) { this.$.btnApply.setDisabled(false); } else { this.$.btnApply.setDisabled(true); } }, discountChanged: function (inSender, inEvent) { var selectedDiscount = inEvent.originator.collection.find(function (discount) { if (discount.get('id') === inEvent.originator.getValue()) { return true; } }, this); if (selectedDiscount.get('discountType') === "8338556C0FBF45249512DB343FEFD280" || selectedDiscount.get('discountType') === "7B49D8CC4E084A75B7CB4D85A6A3A578") { this.disableKeyboard(); } else { //enable keyboard this.enableKeyboard(); } }, closingDiscounts: function (inSender, inEvent) { OB.MobileApp.view.scanningFocus(true); this.$.checkSelectAll.unCheck(); this.doDiscountsModeFinished({ tabPanel: 'scan', keyboard: 'toolbarscan', edit: false, options: { discounts: false } }); }, applyDiscounts: function (inSender, inEvent) { var promotionToAplly = {}, comp = this._searchSelectedComponent(this.$.discountsList.getValue()), orderLinesCollection = new OB.Collection.OrderLineList(); promotionToAplly.rule = comp.model; promotionToAplly.definition = {}; promotionToAplly.definition.userAmt = comp.amt; promotionToAplly.definition.applyNext = !this.$.checkOverride.checked; promotionToAplly.definition.lastApplied = true; if (comp.requiresQty && !comp.amt) { //Show a modal pop up with the error this.doShowPopup({ popup: 'modalDiscountNeedQty' }); return true; } _.each(this.checkedLines, function (line) { orderLinesCollection.add(line); }); OB.Model.Discounts.addManualPromotion(this.order, orderLinesCollection, promotionToAplly); this.closingDiscounts(); }, init: function (model) { this.order = model.get('order'); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSPointOfSale.UI.Discounts.btnDiscountsApply', style: 'color: orange; font-weight: bold;', i18nLabel: 'OBMOBC_LblApply', events: { onApplyDiscounts: '' }, tap: function () { this.doApplyDiscounts(); }, initComponents: function () { this.inherited(arguments); this.setDisabled(true); } }); enyo.kind({ kind: 'OB.UI.CheckboxButton', name: 'OB.OBPOSPointOfSale.UI.Discounts.btnCheckAll', events: { onCheckAllTicketLines: '' }, checked: false, tap: function () { this.inherited(arguments); this.doCheckAllTicketLines({ status: this.checked }); } }); enyo.kind({ kind: 'OB.UI.CheckboxButton', name: 'OB.OBPOSPointOfSale.UI.Discounts.btnCheckOverride', checked: false }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Discounts.btnDiscountsCancel', kind: 'OB.UI.ModalDialogButton', style: 'color: orange; font-weight: bold;', events: { onDiscountsClose: '' }, i18nContent: 'OBMOBC_LblCancel', tap: function () { this.doDiscountsClose(); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ OB.OBPOSPointOfSale.UI.ToolbarScan = { name: 'toolbarscan', buttons: [{ command: 'code', i18nLabel: 'OBMOBC_KbCode', classButtonActive: 'btnactive-blue', idSufix: 'upcean' }], shown: function () { var keyboard = this.owner.owner; keyboard.showKeypad('basic'); keyboard.showSidepad('sideenabled'); keyboard.defaultcommand = 'code'; keyboard.disableCommandKey(this, { disabled: true, commands: ['%'] }); } }; OB.OBPOSPointOfSale.UI.ToolbarDiscounts = { name: 'toolbardiscounts', buttons: [], shown: function () { var keyboard = this.owner.owner; keyboard.showKeypad('basic'); keyboard.showSidepad('sideenabled'); keyboard.defaultcommand = 'line:dto'; keyboard.disableCommandKey(this, { disabled: true, commands: ['%'] }); } }; enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ToolbarPayment', sideButtons: [], published: { receipt: null }, toolbarName: 'toolbarpayment', events: { onShowPopup: '' }, handlers: { onShowAllButtons: 'showAllButtons', onCloseAllPopups: 'closeAllPopups' }, components: [{ kind: 'OB.OBPOSPointOfSale.UI.PaymentMethods', name: 'OBPOS_UI_PaymentMethods' }], init: function (model) { this.model = model; }, pay: function (amount, key, name, paymentMethod, rate, mulrate, isocode, options) { if (options && options.percentaje) { var pending = this.model.getPending(); if (mulrate && mulrate !== '1') { pending = OB.DEC.mul(pending, mulrate); } amount = OB.DEC.div(OB.DEC.mul(pending, amount), 100); } if (OB.DEC.compare(amount) > 0) { var provider, receiptToPay, me = this; if (this.model.get('leftColumnViewManager').isOrder()) { receiptToPay = this.receipt; if (this.receipt.get('orderType') === 0 || this.receipt.get('orderType') === 2 || this.receipt.get('isLayaway')) { provider = paymentMethod.paymentProvider; } else if (this.receipt.get('orderType') === 1 || this.receipt.get('orderType') === 3) { provider = paymentMethod.refundProvider; } else { provider = null; } } //multiorders doesn't allow to return if (this.model.get('leftColumnViewManager').isMultiOrder()) { provider = paymentMethod.paymentProvider; receiptToPay = this.model.get('multiOrders'); } if (provider) { this.doShowPopup({ popup: 'modalpayment', args: { 'receipt': receiptToPay, 'provider': provider, 'key': key, 'name': name, 'paymentMethod': paymentMethod, 'amount': amount, 'rate': rate, 'mulrate': mulrate, 'isocode': isocode } }); } else { this.model.addPayment(new OB.Model.PaymentLine({ 'kind': key, 'name': name, 'amount': amount, 'rate': rate, 'mulrate': mulrate, 'isocode': isocode, 'allowOpenDrawer': paymentMethod.allowopendrawer, 'isCash': paymentMethod.iscash, 'openDrawer': paymentMethod.openDrawer, 'printtwice': paymentMethod.printtwice })); } } }, getButtonComponent: function (sidebutton) { if (sidebutton.i18nLabel) { sidebutton.label = OB.I18N.getLabel(sidebutton.i18nLabel); } return { kind: 'OB.UI.BtnSide', btn: { command: sidebutton.command, label: sidebutton.label, permission: sidebutton.permission, definition: { permission: sidebutton.permission, stateless: sidebutton.stateless, action: sidebutton.action } } }; }, initComponents: function () { //TODO: modal payments var i, max, payments, paymentsdialog, paymentsbuttons, countbuttons, btncomponent, Btn, inst, cont, exactdefault, cashdefault, allpayments = {}, me = this, dialogbuttons = {}; this.inherited(arguments); payments = OB.POS.modelterminal.get('payments'); paymentsdialog = payments.length + this.sideButtons.length > 5; paymentsbuttons = paymentsdialog ? 4 : 5; countbuttons = 0; enyo.forEach(payments, function (payment) { if (payment.paymentMethod.id === OB.POS.modelterminal.get('terminal').terminalType.paymentMethod) { exactdefault = payment; } if (payment.payment.searchKey === OB.POS.modelterminal.get('paymentcash')) { cashdefault = payment; } allpayments[payment.payment.searchKey] = payment; btncomponent = this.getButtonComponent({ command: payment.payment.searchKey, label: payment.payment._identifier, permission: payment.payment.searchKey, stateless: false, action: function (keyboard, txt) { var options = {}; if (_.last(txt) === '%') { options.percentaje = true; } var amount = OB.DEC.number(OB.I18N.parseNumber(txt)); if (_.isNaN(amount)) { OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_NotValidNumber', [txt])); return; } me.pay(amount, payment.payment.searchKey, payment.payment._identifier, payment.paymentMethod, payment.rate, payment.mulrate, payment.isocode, options); } }); if (countbuttons++ < paymentsbuttons) { this.createComponent(btncomponent); } else { OB.OBPOSPointOfSale.UI.PaymentMethods.prototype.sideButtons.push(btncomponent); dialogbuttons[payment.payment.searchKey] = payment.payment._identifier; } }, this); // Fallback assign of the payment for the exact command. exactdefault = exactdefault || cashdefault || payments[0]; enyo.forEach(this.sideButtons, function (sidebutton) { btncomponent = this.getButtonComponent(sidebutton); if (countbuttons++ < paymentsbuttons) { this.createComponent(btncomponent); } else { OB.OBPOSPointOfSale.UI.PaymentMethods.prototype.sideButtons.push(btncomponent); dialogbuttons[sidebutton.command] = sidebutton.label; } }, this); while (countbuttons++ < paymentsbuttons) { this.createComponent({ kind: 'OB.UI.BtnSide', btn: {} }); } if (paymentsdialog) { this.createComponent({ name: 'btnMore', toolbar: this, dialogbuttons: dialogbuttons, kind: 'OB.OBPOSPointOfSale.UI.ButtonMore' }); } this.createComponent({ kind: 'OB.OBPOSPointOfSale.UI.ButtonSwitch', keyboard: this.keyboard }); this.owner.owner.addCommand('cashexact', { action: function (keyboard, txt) { if (keyboard.status && !allpayments[keyboard.status]) { // Is not a payment, so continue with the default path... keyboard.execCommand(keyboard.status, null); } else { // It is a payment... var exactpayment = allpayments[keyboard.status] || exactdefault, amount = me.model.getPending(); if (exactpayment.rate && exactpayment.rate !== '1') { amount = OB.DEC.div(me.model.getPending(), exactpayment.rate); } if (amount > 0 && exactpayment && OB.POS.modelterminal.hasPermission(exactpayment.payment.searchKey)) { me.pay(amount, exactpayment.payment.searchKey, exactpayment.payment._identifier, exactpayment.paymentMethod, exactpayment.rate, exactpayment.mulrate, exactpayment.isocode); } } } }); }, showAllButtons: function () { this.$.OBPOS_UI_PaymentMethods.show(); }, closeAllPopups: function () { this.$.OBPOS_UI_PaymentMethods.hide(); }, shown: function () { var me = this, i, max, p, keyboard = this.owner.owner; keyboard.showKeypad('Coins-' + OB.POS.modelterminal.get('currency').id); // shows the Coins/Notes panel for the terminal currency keyboard.showSidepad('sidedisabled'); keyboard.disableCommandKey(this, { commands: ['%'], disabled: false }); for (i = 0, max = OB.POS.modelterminal.get('payments').length; i < max; i++) { p = OB.POS.modelterminal.get('payments')[i]; if (p.paymentMethod.id === OB.POS.modelterminal.get('terminal').terminalType.paymentMethod) { keyboard.defaultcommand = OB.POS.modelterminal.get('payments')[i].payment.searchKey; keyboard.setStatus(OB.POS.modelterminal.get('payments')[i].payment.searchKey); break; } } if (keyboard && OB.POS.modelterminal.get('paymentcash') && keyboard.status === '') { keyboard.defaultcommand = OB.POS.modelterminal.get('paymentcash'); keyboard.setStatus(OB.POS.modelterminal.get('paymentcash')); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.PaymentMethods', kind: 'OB.UI.Modal', topPosition: '125px', i18nHeader: 'OBPOS_MorePaymentsHeader', sideButtons: [], body: { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;', classes: 'row-fluid', components: [{ name: 'buttonslist', classes: 'span12' }] }] }] }, executeOnShow: function () { // build only the first time... if (this.$.body.$.buttonslist.children.length === 0) { enyo.forEach(this.sideButtons, function (sidebutton) { sidebutton.btn.definition.includedInPopUp = true; this.$.body.$.buttonslist.createComponent(sidebutton, { owner: this.args.toolbar }); }, this); } return true; }, init: function (model) { this.model = model; } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ButtonMore', style: 'display:table; width:100%;', events: { onShowAllButtons: '' }, handlers: { onButtonStatusChanged: 'buttonStatusChanged' }, components: [{ style: 'margin: 5px;', components: [{ kind: 'OB.UI.Button', classes: 'btnkeyboard', name: 'btn', label: '' }] }], initComponents: function () { this.inherited(arguments); this.$.btn.setContent(OB.I18N.getLabel('OBPOS_MorePayments')); this.activegreen = false; }, tap: function () { // this.toolbar.keyboard // this.dialogbuttons if (this.activegreen) { this.toolbar.keyboard.setStatus(''); } else { this.doShowAllButtons(); } }, buttonStatusChanged: function (inSender, inEvent) { var status = inEvent.value.status; if (this.activegreen) { this.$.btn.setContent(OB.I18N.getLabel('OBPOS_MorePayments')); this.$.btn.removeClass('btnactive-green'); this.activegreen = false; } if (this.dialogbuttons[status]) { this.$.btn.setContent(this.dialogbuttons[status]); this.$.btn.addClass('btnactive-green'); this.activegreen = true; } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.ButtonSwitch', style: 'display:table; width:100%;', components: [{ style: 'margin: 5px;', components: [{ kind: 'OB.UI.Button', classes: 'btnkeyboard', name: 'btn' }] }], setLabel: function (lbl) { this.$.btn.setContent(lbl); }, tap: function () { this.keyboard.showNextKeypad(); }, create: function () { this.inherited(arguments); this.keyboard.state.on('change:keypadNextLabel', function () { this.setLabel(this.keyboard.state.get('keypadNextLabel')); }, this); this.setLabel(this.keyboard.state.get('keypadNextLabel')); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $, _, Backbone */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.KeyboardOrder', kind: 'OB.UI.Keyboard', keypads: [], published: { receipt: null }, events: { onShowPopup: '', onAddProduct: '', onSetDiscountQty: '', onDiscountsMode: '' }, discountsMode: false, handlers: { onKeyboardOnDiscountsMode: 'keyboardOnDiscountsMode' }, keyboardOnDiscountsMode: function (inSender, inEvent) { if (inEvent.status) { this.showSidepad('ticketDiscountsToolbar'); } else { this.showSidepad('sideenabled'); } if (!inEvent.status) { //exit from discounts this.discountsMode = false; if (this.prevdefaultcommand) { this.defaultcommand = this.prevdefaultcommand; } if (this.buttons['ticket:discount']) { this.buttons['ticket:discount'].removeClass('btnactive'); } this.keyboardDisabled(inSender, { status: false }); } else { this.discountsMode = true; this.prevdefaultcommand = this.defaultcommand; this.defaultcommand = 'ticket:discount'; if (inEvent.writable) { //enable keyboard this.keyboardDisabled(inSender, { status: false }); //button as active if (this.buttons['ticket:discount']) { this.buttons['ticket:discount'].addClass('btnactive'); } } else { if (this.buttons['ticket:discount']) { this.buttons['ticket:discount'].removeClass('btnactive'); } this.keyboardDisabled(inSender, { status: true }); return true; } } }, sideBarEnabled: true, receiptChanged: function () { this.$.toolbarcontainer.$.toolbarPayment.setReceipt(this.receipt); this.line = null; this.receipt.get('lines').on('selected', function (line) { this.line = line; this.clearInput(); }, this); }, initComponents: function () { var me = this; var actionAddProduct = function (keyboard, value) { if (keyboard.receipt.get('isEditable') === false) { me.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } if (keyboard.line && keyboard.line.get('product').get('isEditableQty') === false) { me.doShowPopup({ popup: 'modalNotEditableLine' }); return true; } if (keyboard.line) { if ((_.isNaN(value) || value > 0) && keyboard.line.get('product').get('groupProduct') === false) { me.doShowPopup({ popup: 'modalProductCannotBeGroup' }); return true; } me.doAddProduct({ product: keyboard.line.get('product'), qty: value, options: { line: keyboard.line } }); keyboard.receipt.trigger('scan'); } }; var actionRemoveProduct = function (keyboard, value) { if (keyboard.receipt.get('isEditable') === false) { me.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } if (keyboard.line && keyboard.line.get('product').get('isEditableQty') === false) { me.doShowPopup({ popup: 'modalNotEditableLine' }); return true; } if (keyboard.line) { keyboard.receipt.removeUnit(keyboard.line, value); keyboard.receipt.trigger('scan'); } }; // action bindable to a command that completely deletes a product from the order list var actionDeleteLine = function (keyboard) { if (keyboard.receipt.get('isEditable') === false) { me.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } if (keyboard.line && keyboard.line.get('product').get('isEditableQty') === false) { me.doShowPopup({ popup: 'modalNotEditableLine' }); return true; } if (keyboard.line) { keyboard.receipt.deleteLine(keyboard.line); keyboard.receipt.trigger('scan'); } }; this.addCommand('line:qty', { action: function (keyboard, txt) { var value = OB.I18N.parseNumber(txt), toadd; if (!keyboard.line) { return true; } if (value || value === 0) { toadd = value - keyboard.line.get('qty'); if (toadd === 0) { // If nothing to add then return return; } if (value === 0) { // If final quantity will be 0 then request approval OB.UTIL.Approval.requestApproval(me.model, 'OBPOS_approval.deleteLine', function (approved, supervisor, approvalType) { if (approved) { actionAddProduct(keyboard, toadd); } }); } else { actionAddProduct(keyboard, toadd); } } } }); this.addCommand('line:price', { permission: 'OBPOS_order.changePrice', action: function (keyboard, txt) { if (keyboard.receipt.get('isEditable') === false) { me.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } if (!keyboard.line) { return true; } if (keyboard.line.get('product').get('isEditablePrice') === false) { me.doShowPopup({ popup: 'modalNotEditableLine' }); return true; } if (keyboard.line) { OB.UTIL.Approval.requestApproval( me.model, 'OBPOS_approval.setPrice', function (approved, supervisor, approvalType) { if (approved) { keyboard.receipt.setPrice(keyboard.line, OB.I18N.parseNumber(txt)); keyboard.receipt.trigger('scan'); } }); } } }); this.addCommand('line:dto', { permission: 'OBPOS_order.discount', action: function (keyboard, txt) { if (keyboard.receipt.get('isEditable') === false) { me.doShowPopup({ popup: 'modalNotEditableOrder' }); return true; } if (OB.MobileApp.model.get('permissions')["OBPOS_retail.discountkeyboard"] === true || keyboard.line.getQty() < 0) { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_LineCanNotBeSelected')); return true; } if (keyboard.line) { keyboard.receipt.trigger('discount', keyboard.line, OB.I18N.parseNumber(txt)); } } }); this.addCommand('screen:dto', { stateless: true, permission: 'OBPOS_order.discount', action: function (keyboard, txt) { me.doDiscountsMode({ tabPanel: 'edit', keyboard: 'toolbardiscounts', edit: false, options: { discounts: true } }); } }); //To be used in the discounts side bar this.addCommand('ticket:discount', { permission: 'OBPOS_retail.advDiscounts', action: function (keyboard, txt) { if (keyboard.discountsMode) { me.doSetDiscountQty({ qty: OB.I18N.parseNumber(txt) }); return true; } } }); this.addCommand('code', new OB.UI.BarcodeActionHandler()); this.addCommand('+', { stateless: true, action: function (keyboard, txt) { var qty = 1; if ((!_.isNull(txt) || !_.isUndefined(txt)) && !_.isNaN(OB.I18N.parseNumber(txt))) { qty = OB.I18N.parseNumber(txt); } actionAddProduct(keyboard, qty); } }); this.addCommand('-', { stateless: true, action: function (keyboard, txt) { var qty = 1, value; if ((!_.isNull(txt) || !_.isUndefined(txt)) && !_.isNaN(OB.I18N.parseNumber(txt))) { qty = OB.I18N.parseNumber(txt); } if (!_.isUndefined(keyboard.line)) { value = keyboard.line.get('qty') - qty; } if (value === 0) { // If final quantity will be 0 then request approval OB.UTIL.Approval.requestApproval(me.model, 'OBPOS_approval.deleteLine', function (approved, supervisor, approvalType) { if (approved) { actionAddProduct(keyboard, -qty); } }); } else { actionAddProduct(keyboard, -qty); } } }); // add a command that will handle the DELETE keyboard key this.addCommand('line:delete', { stateless: true, action: function (keyboard) { OB.UTIL.Approval.requestApproval(me.model, 'OBPOS_approval.deleteLine', function (approved, supervisor, approvalType) { if (approved) { actionDeleteLine(keyboard); } }); } }); // calling super after setting keyboard properties this.inherited(arguments); this.addToolbarComponent('OB.OBPOSPointOfSale.UI.ToolbarPayment'); this.addToolbar(OB.OBPOSPointOfSale.UI.ToolbarScan); this.addToolbar(OB.OBPOSPointOfSale.UI.ToolbarDiscounts); }, init: function (model) { this.model = model; // Add the keypads for each payment method this.initCurrencyKeypads(); _.each(this.keypads, function (keypadname) { this.addKeypad(keypadname); }, this); }, initCurrencyKeypads: function () { var me = this; var currenciesManaged = {}; _.each(OB.POS.modelterminal.get('payments'), function (payment) { // Is cash method if is checked as iscash or is the legacy hardcoded cash method for euros. if ((payment.paymentMethod.iscash && payment.paymentMethod.showkeypad) && !currenciesManaged[payment.paymentMethod.currency]) { // register that is already built currenciesManaged[payment.paymentMethod.currency] = true; // Build the panel OB.Dal.find(OB.Model.CurrencyPanel, { 'currency': payment.paymentMethod.currency, _orderByClause: 'line' }, function (datacurrency) { if (datacurrency.length > 0) { me.buildCoinsAndNotesPanel(payment, payment.symbol, datacurrency); } else if (payment.payment.searchKey === 'OBPOS_payment.cash' && payment.paymentMethod.currency === '102') { // Add the legacy keypad if is the legacy hardcoded cash method for euros. me.addKeypad('OB.UI.KeypadCoinsLegacy'); } }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }); } }, this); }, buildCoinsAndNotesButton: function (paymentkey, coin) { if (coin) { return { kind: 'OB.UI.PaymentButton', paymenttype: paymentkey, amount: coin.get('amount'), background: coin.get('backcolor') || '#f3bc9e', bordercolor: coin.get('bordercolor') || coin.get('backcolor') || '#f3bc9e' }; } else { return { kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '', command: 'dummy' }; } }, buildCoinsAndNotesPanel: function (payment, symbol, datacurrency) { enyo.kind({ name: 'OB.UI.Keypad' + payment.payment.searchKey, label: _.template('<%= symbol %>,<%= symbol %>,<%= symbol %>,...', { symbol: symbol }), padName: 'Coins-' + payment.paymentMethod.currency, padPayment: payment.payment.searchKey, components: [{ classes: 'row-fluid', components: [{ classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '/', command: '/' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '*', command: '*' }] }, { classes: 'span4', components: [{ kind: 'OB.UI.ButtonKey', classButton: 'btnkeyboard-num', label: '%', command: '%' }] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(9))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(10))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(11))] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(6))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(7))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(8))] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(3))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(4))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(5))] }] }, { classes: 'row-fluid', components: [{ classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(0))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(1))] }, { classes: 'span4', components: [this.buildCoinsAndNotesButton(payment.payment.searchKey, datacurrency.at(2))] }] }] }); this.addKeypad('OB.UI.Keypad' + payment.payment.searchKey); } }); enyo.kind({ // Overwrite this component to customize the BarcodeActionHandler name: 'OB.UI.BarcodeActionHandler', kind: 'OB.UI.AbstractBarcodeActionHandler', addWhereFilter: function (txt) { return "where product.upc = '" + txt + "'"; }, findProductByBarcode: function (txt, callback) { var criteria; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackProducts(dataProducts) { if (dataProducts && dataProducts.length > 0) { OB.debug('productfound'); callback(new Backbone.Model(dataProducts.at(0))); } else { // 'UPC/EAN code not found' OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_KbUPCEANCodeNotFound', [txt])); } } OB.debug('BarcodeActionHandler - id: ' + txt); OB.Dal.query(OB.Model.Product, 'select * from m_product as product ' + this.addWhereFilter(txt), null, successCallbackProducts, errorCallback, this); }, addProductToReceipt: function (keyboard, product) { keyboard.doAddProduct({ product: product }); keyboard.receipt.trigger('scan'); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _, $, console */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.ModalConfigurationRequiredForCreateCustomers', kind: 'OB.UI.ModalInfo', i18nHeader: 'OBPOS_configurationRequired', bodyContent: { i18nContent: 'OBPOS_configurationNeededToCreateCustomers' } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.cancelEdit', kind: 'OB.UI.Button', style: 'width: 100px; margin: 0px 0px 8px 5px;', classes: 'btnlink-gray btnlink btnlink-small', i18nContent: 'OBMOBC_LblCancel' }); enyo.kind({ name: 'OB.UI.CustomerPropertyLine', components: [{ name: 'labelLine', style: 'font-size: 15px; color: black; text-align: right; border: 1px solid #FFFFFF; background-color: #E2E2E2; width: 20%; height: 28px; padding: 12px 5px 1px 0; float: left;' }, { style: 'border: 1px solid #FFFFFF; float: left; width: 75%;', name: 'newAttribute' }, { style: 'clear: both' }], initComponents: function () { this.inherited(arguments); this.$.newAttribute.createComponent(this.newAttribute); this.$.labelLine.content = this.newAttribute.i18nLabel ? OB.I18N.getLabel(this.newAttribute.i18nLabel) : this.newAttribute.label; } }); enyo.kind({ name: 'OB.UI.CustomerTextProperty', kind: 'enyo.Input', type: 'text', classes: 'input', style: 'width: 100%; height: 30px; margin:0;', handlers: { onLoadValue: 'loadValue', onSaveChange: 'saveChange' }, events: { onSaveProperty: '' }, loadValue: function (inSender, inEvent) { if (inEvent.customer !== undefined) { if (inEvent.customer.get(this.modelProperty) !== undefined) { this.setValue(inEvent.customer.get(this.modelProperty)); } } else { this.setValue(''); } }, saveChange: function (inSender, inEvent) { inEvent.customer.set(this.modelProperty, this.getValue()); }, initComponents: function () { if (this.readOnly) { this.setAttribute('readonly', 'readonly'); } if (this.maxlength) { this.setAttribute('maxlength', this.maxlength); } } }); enyo.kind({ name: 'OB.UI.CustomerComboProperty', handlers: { onLoadValue: 'loadValue', onSaveChange: 'saveChange' }, events: { onSaveProperty: '' }, components: [{ kind: 'OB.UI.List', name: 'customerCombo', classes: 'combo', style: 'width: 101%; margin:0;', renderLine: enyo.kind({ kind: 'enyo.Option', initComponents: function () { this.inherited(arguments); this.setValue(this.model.get(this.parent.parent.retrievedPropertyForValue)); this.setContent(this.model.get(this.parent.parent.retrievedPropertyForText)); } }), renderEmpty: 'enyo.Control' }], loadValue: function (inSender, inEvent) { this.$.customerCombo.setCollection(this.collection); this.fetchDataFunction(inEvent); }, dataReadyFunction: function (data, inEvent) { var index = 0, result = null; if (data) { this.collection.reset(data.models); } else { this.collection.reset(null); return; } result = _.find(this.collection.models, function (categ) { if (inEvent.customer) { //Edit: select actual value if (categ.get(this.retrievedPropertyForValue) === inEvent.customer.get(this.modelProperty)) { return true; } } else { //New: select default value if (categ.get(this.retrievedPropertyForValue) === this.defaultValue()) { return true; } } index += 1; }, this); if (result) { this.$.customerCombo.setSelected(index); } else { this.$.customerCombo.setSelected(0); } }, saveChange: function (inSender, inEvent) { var selected = this.collection.at(this.$.customerCombo.getSelected()); inEvent.customer.set(this.modelProperty, selected.get(this.retrievedPropertyForValue)); if (this.modelPropertyText) { inEvent.customer.set(this.modelPropertyText, selected.get(this.retrievedPropertyForText)); } }, initComponents: function () { if (this.collectionName && OB && OB.Collection && OB.Collection[this.collectionName]) { this.collection = new OB.Collection[this.collectionName](); } else { OB.info('OB.UI.CustomerComboProperty: Collection is required'); } this.inherited(arguments); if (this.readOnly) { this.setAttribute('readonly', 'readonly'); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.edit_createcustomers', handlers: { onSetCustomer: 'setCustomer', onSaveCustomer: 'preSaveCustomer' }, events: {}, components: [{ name: 'bodyheader' }, { name: 'customerAttributes' }], setCustomer: function (inSender, inEvent) { this.customer = inEvent.customer; this.waterfall('onLoadValue', { customer: this.customer }); }, preSaveCustomer: function (inSender, inEvent) { var me = this, inSenderOriginal = inSender, inEventOriginal = inEvent; OB.UTIL.HookManager.executeHooks('OBPOS_PreCustomerSave', { inSender: inSenderOriginal, inEvent: inEventOriginal, passValidation: true, error: '', meObject: me }, function (args) { if (args.passValidation) { args.meObject.saveCustomer(args.inSender, args.inEvent); } else { OB.UTIL.showError(args.error); } }); }, saveCustomer: function (inSender, inEvent) { var me = this, sw = me.subWindow; function getCustomerValues(params) { me.waterfall('onSaveChange', { customer: params.customer }); } function goToViewWindow(sw, params) { if (sw.caller === 'mainSubWindow') { sw.doChangeSubWindow({ newWindow: { name: 'customerView', params: { navigateOnClose: 'mainSubWindow', businessPartner: params.customer } } }); } else { sw.doChangeSubWindow({ newWindow: { name: 'customerView', params: { navigateOnClose: 'customerAdvancedSearch', businessPartner: params.customer } } }); } } if (this.customer === undefined) { this.model.get('customer').newCustomer(); this.waterfall('onSaveChange', { customer: this.model.get('customer') }); var success = this.model.get('customer').saveCustomer(); if (success) { goToViewWindow(sw, { customer: this.model.get('customer') }); } } else { this.model.get('customer').loadById(this.customer.get('id'), function (customer) { getCustomerValues({ customer: customer }); var success = customer.saveCustomer(); if (success) { goToViewWindow(sw, { customer: customer }); } }); } }, initComponents: function () { this.inherited(arguments); this.$.bodyheader.createComponent({ kind: this.windowHeader }); this.attributeContainer = this.$.customerAttributes; enyo.forEach(this.newAttributes, function (natt) { var resultDisplay = true, undf; if (natt.displayLogic !== undf && natt.displayLogic !== null) { if (enyo.isFunction(natt.displayLogic)) { resultDisplay = natt.displayLogic(this); } else { resultDisplay = natt.displayLogic; } } if (resultDisplay) { this.$.customerAttributes.createComponent({ kind: 'OB.UI.CustomerPropertyLine', name: 'line_' + natt.name, newAttribute: natt }); } }, this); }, init: function (model) { this.model = model; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, Backbone, $, _, enyo */ //Modal pop up enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.cas', kind: 'OB.UI.Subwindow', events: { onSearchAction: '' }, beforeSetShowing: function (params) { if (this.caller === 'mainSubWindow') { this.waterfall('onSearchAction', { cleanResults: true }); } else { this.waterfall('onSearchAction', { executeLastCriteria: true }); } this.$.subWindowBody.$.casbody.$.listcustomers.$.leftbar.$.newAction.putDisabled(!OB.MobileApp.model.hasPermission('OBPOS_retail.editCustomers')); return true; }, beforeClose: function (dest) { if (dest === 'mainSubWindow') { this.waterfall('onSearchAction', { cleanResults: true }); } return true; }, defaultNavigateOnClose: 'mainSubWindow', header: { kind: 'OB.OBPOSPointOfSale.UI.customers.casheader' }, body: { kind: 'OB.OBPOSPointOfSale.UI.customers.casbody', name: 'casbody' } }); //Header of the body of cas (customer advanced search) enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.ModalCustomerScrollableHeader', kind: 'OB.UI.ScrollableTableHeader', style: 'border-bottom: 10px solid #ff0000;', events: { onSearchAction: '', onClearAction: '' }, handlers: { onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px; 10px; 0px; 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'filterText', style: 'width: 100%', isFirstFocus: true }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }] }], clearAction: function () { this.$.filterText.setValue(''); this.doClearAction(); }, searchAction: function () { this.doSearchAction({ bpName: this.$.filterText.getValue(), operator: OB.Dal.CONTAINS }); return true; } }); /*items of collection Customer*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.ListCustomersLine', kind: 'OB.UI.SelectButton', classes: 'btnselect-customer', components: [{ name: 'line', style: 'line-height: 23px;', components: [{ style: 'float: left; font-weight: bold;', name: 'identifier' }, { style: 'float: left;', name: 'address' }, { style: 'clear: both;' }] }], create: function () { this.inherited(arguments); this.$.identifier.setContent(this.model.get('_identifier') + ' / '); this.$.address.setContent(this.model.get('locName')); } }); /*Search Customer Button*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', kind: 'OB.UI.Button', events: { onSearchAction: '' }, classes: 'btnlink-left-toolbar', searchAction: function (params) { this.doSearchAction({ bpName: params.initial, operator: params.operator }); }, initComponents: function () { this.inherited(arguments); this.setContent(this.i18nLabel ? OB.I18N.getLabel(this.i18nLabel) : this.label); } }); /*New Customer Button*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.NewCustomerButton', kind: 'OB.UI.Button', events: { onChangeSubWindow: '' }, disabled: false, classes: 'btnlink-left-toolbar', tap: function () { if (this.disabled) { return true; } var sw = this.subWindow; this.doChangeSubWindow({ newWindow: { name: 'customerCreateAndEdit', params: { navigateOnClose: 'customerView' } } }); }, putDisabled: function (status) { if (status === false) { this.disabled = false; this.setDisabled(false); this.removeClass('disabled'); return; } else { this.disabled = true; this.setDisabled(); this.addClass('disabled'); } }, initComponents: function () { this.inherited(arguments); this.setContent(this.i18nLabel ? OB.I18N.getLabel(this.i18nLabel) : this.label); } }); /* Buttons Left bar*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.CustomerLeftBar', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.NewCustomerButton', i18nLabel: 'OBPOS_LblNew', name: 'newAction' }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblAC', tap: function () { this.searchAction({ initial: 'A,B,C', operator: OB.Dal.STARTSWITH }); } }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblDF', tap: function () { this.searchAction({ initial: 'D,E,F', operator: OB.Dal.STARTSWITH }); } }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblGI', tap: function () { this.searchAction({ initial: 'G,H,I', operator: OB.Dal.STARTSWITH }); } }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblJL', tap: function () { this.searchAction({ initial: 'J,K,L', operator: OB.Dal.STARTSWITH }); } }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblMO', tap: function () { this.searchAction({ initial: 'M,N,O', operator: OB.Dal.STARTSWITH }); } }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblPR', tap: function () { this.searchAction({ initial: 'P,Q,R', operator: OB.Dal.STARTSWITH }); } }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblSV', tap: function () { this.searchAction({ initial: 'S,T,U,V', operator: OB.Dal.STARTSWITH }); } }, { kind: 'OB.OBPOSPointOfSale.UI.customers.SearchCustomerButton', i18nLabel: 'OBPOS_LblWZ', tap: function () { this.searchAction({ initial: 'W,X,Y,Z', operator: OB.Dal.STARTSWITH }); } }] }); /*scrollable table (body of customer)*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.ListCustomers', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, events: { onChangeBusinessPartner: '', onChangeSubWindow: '' }, components: [{ style: 'text-align: center; padding-top: 10px; float: left; width: 19%;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.CustomerLeftBar', name: 'leftbar' }] }, { style: 'float: left; width: 80%;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'stBPAdvSearch', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '301px', renderHeader: 'OB.OBPOSPointOfSale.UI.customers.ModalCustomerScrollableHeader', renderLine: 'OB.OBPOSPointOfSale.UI.customers.ListCustomersLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }, { style: 'clear: both' }], clearAction: function (inSender, inEvent) { this.bpsList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, filter, splitFilter, splitFilterLength, _operator, i, criteria = {}, lastCriteria = []; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackBPs(dataBps, args) { if (args === 0) { me.bpsList.reset(); } if (dataBps && dataBps.length > 0) { me.bpsList.add(dataBps.models); } } function reset(me) { me.bpsList.reset(); me.lastCriteria = null; return true; } if (inEvent.executeLastCriteria) { if (this.lastCriteria) { for (i = 0; i < this.lastCriteria.length; i++) { OB.Dal.find(OB.Model.BusinessPartner, this.lastCriteria[i], successCallbackBPs, errorCallback, i); lastCriteria.push(this.lastCriteria[i]); } this.lastCriteria = lastCriteria; return true; } else { return reset(this); } } if (inEvent.cleanResults) { return reset(this); } filter = inEvent.bpName; splitFilter = filter.split(","); splitFilterLength = splitFilter.length; _operator = inEvent.operator; if (filter && filter !== '') { for (i = 0; i < splitFilter.length; i++) { criteria._filter = { operator: _operator, value: splitFilter[i] }; OB.Dal.find(OB.Model.BusinessPartner, criteria, successCallbackBPs, errorCallback, i); lastCriteria.push(enyo.clone(criteria)); } this.lastCriteria = lastCriteria; } else { OB.Dal.find(OB.Model.BusinessPartner, criteria, successCallbackBPs, errorCallback, 0); } return true; }, bpsList: null, init: function () { this.bpsList = new Backbone.Collection(); this.$.stBPAdvSearch.setCollection(this.bpsList); this.bpsList.on('click', function (model) { var sw = this.subWindow; this.doChangeSubWindow({ newWindow: { name: 'customerView', params: { navigateOnClose: sw.getName(), businessPartner: model } } }); }, this); } }); //header enyo.kind({ kind: 'OB.UI.SubwindowHeader', name: 'OB.OBPOSPointOfSale.UI.customers.casheader', onTapCloseButton: function () { var subWindow = this.subWindow; subWindow.doChangeSubWindow({ newWindow: { name: 'mainSubWindow' } }); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBPOS_TitleCustomerAdvancedSearch')); } }); /*instance*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.casbody', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.ListCustomers', name: 'listcustomers' }] }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _, $ */ enyo.kind({ kind: 'OB.UI.Subwindow', name: 'OB.OBPOSPointOfSale.UI.customers.newcustomer', events: { onShowPopup: '' }, beforeSetShowing: function (params) { if (OB.POS.modelterminal.get('terminal').defaultbp_paymentmethod !== null && OB.POS.modelterminal.get('terminal').defaultbp_bpcategory !== null && OB.POS.modelterminal.get('terminal').defaultbp_paymentterm !== null && OB.POS.modelterminal.get('terminal').defaultbp_invoiceterm !== null && OB.POS.modelterminal.get('terminal').defaultbp_bpcountry !== null && OB.POS.modelterminal.get('terminal').defaultbp_bporg !== null) { this.waterfall('onSetCustomer', { customer: params.businessPartner }); //show return true; } else { this.doShowPopup({ popup: 'modalConfigurationRequiredForCreateNewCustomers' }); //not show return false; } }, defaultNavigateOnClose: 'customerView', header: { kind: 'OB.UI.SubwindowHeader', name: 'OB.OBPOSPointOfSale.UI.customers.newcustomerheader', handlers: { onSetCustomer: 'setCustomer' }, i18nHeaderMessage: 'OBPOS_TitleEditNewCustomer', setCustomer: function (inSender, inEvent) { this.customer = inEvent.customer; }, onTapCloseButton: function () { var subWindow = this.subWindow; if (subWindow.caller === 'mainSubWindow') { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller } }); } else { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller, params: { navigateOnClose: 'customerAdvancedSearch', businessPartner: (this.headerContainer && this.headerContainer.customer) ? this.headerContainer.customer : (this.customer ? this.customer : null) } } }); } } }, body: { kind: 'OB.OBPOSPointOfSale.UI.customers.edit_createcustomers_impl' } }); //button of header of the body enyo.kind({ kind: 'OB.UI.Button', name: 'OB.OBPOSPointOfSale.UI.customers.newcustomersave', style: 'width: 100px; margin: 0px 5px 8px 19px;', classes: 'btnlink btnlink-small', i18nLabel: 'OBPOS_LblSave', events: { onSaveCustomer: '' }, tap: function () { this.doSaveCustomer(); } }); //Header of body enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.subwindowNewCustomer_bodyheader', components: [{ components: [{ style: 'display: table; margin: 0 auto;', components: [{ style: 'display: table-cell;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.newcustomersave' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.cancelEdit', handlers: { onSetCustomer: 'setCustomer' }, setCustomer: function (inSender, inEvent) { this.customer = inEvent.customer; }, tap: function () { var subWindow = this.subWindow; if (subWindow.caller === 'mainSubWindow') { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller } }); } else { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller, params: { navigateOnClose: 'customerAdvancedSearch', businessPartner: this.customer } } }); } } }] }] }] }] }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.edit_createcustomers_impl', kind: 'OB.OBPOSPointOfSale.UI.customers.edit_createcustomers', style: 'padding: 9px 15px;', windowHeader: 'OB.OBPOSPointOfSale.UI.customers.subwindowNewCustomer_bodyheader', newAttributes: [{ kind: 'OB.UI.CustomerTextProperty', name: 'customerName', modelProperty: 'name', isFirstFocus: true, i18nLabel: 'OBPOS_LblName', maxlength: 60 }, { kind: 'OB.UI.CustomerComboProperty', name: 'customerCategory', modelProperty: 'businessPartnerCategory', //Required: property where the selected value will be get and where the value will be saved modelPropertyText: 'businessPartnerCategory_name', //optional: When saving, the property which will store the selected text collectionName: 'BPCategoryList', defaultValue: function () { return OB.MobileApp.model.get('terminal').defaultbp_bpcategory; }, //Default value for new lines retrievedPropertyForValue: 'id', //property of the retrieved model to get the value of the combo item retrievedPropertyForText: '_identifier', //property of the retrieved model to get the text of the combo item //function to retrieve the data fetchDataFunction: function (args) { var me = this, criteria; criteria = { _orderByClause: '_identifier asc' }; OB.Dal.find(OB.Model.BPCategory, criteria, function (data, args) { //This function must be called when the data is ready me.dataReadyFunction(data, args); }, function (error) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_ErrorGettingBPCategories')); //This function must be called when the data is ready me.dataReadyFunction(null, args); }, args); }, i18nLabel: 'OBPOS_BPCategory', displayLogic: function () { return OB.MobileApp.model.get('terminal').bp_showcategoryselector; } }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerTaxId', modelProperty: 'taxID', i18nLabel: 'OBPOS_LblTaxId', displayLogic: function () { return OB.MobileApp.model.get('terminal').bp_showtaxid; }, maxlength: 20 }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerLocName', modelProperty: 'locName', i18nLabel: 'OBPOS_LblAddress', maxlength: 60 }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerPostalCode', modelProperty: 'postalCode', i18nLabel: 'OBPOS_LblPostalCode', maxlength: 10 }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerCity', modelProperty: 'cityName', i18nLabel: 'OBPOS_LblCity', maxlength: 60 }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerPhone', modelProperty: 'phone', i18nLabel: 'OBPOS_LblPhone', maxlength: 40 }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerEmail', modelProperty: 'email', i18nLabel: 'OBPOS_LblEmail', maxlength: 255 }] }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $*/ enyo.kind({ kind: 'OB.UI.Subwindow', name: 'OB.OBPOSPointOfSale.UI.customers.editcustomer', events: { onShowPopup: '' }, beforeSetShowing: function (params) { this.waterfall('onSetCustomer', { customer: params.businessPartner }); return true; }, defaultNavigateOnClose: 'customerAdvancedSearch', header: { kind: 'OB.UI.SubwindowHeader', i18nHeaderMessage: 'OBPOS_TitleViewCustomer', onTapCloseButton: function () { var subWindow = this.subWindow; subWindow.doChangeSubWindow({ newWindow: { name: subWindow.navigateOnClose, params: { navigateOnClose: 'mainSubWindow' } } }); } }, body: { kind: 'OB.OBPOSPointOfSale.UI.customers.editcustomers_impl' } }); /**/ enyo.kind({ kind: 'OB.UI.Button', name: 'OB.OBPOSPointOfSale.UI.customers.assigncustomertoticket', style: 'margin: 0px 0px 8px 5px;', classes: 'btnlink btnlink-small', handlers: { onSetCustomer: 'setCustomer' }, events: { onChangeBusinessPartner: '' }, setCustomer: function (inSender, inEvent) { this.customer = inEvent.customer; }, tap: function () { var sw = this.subWindow; sw.doChangeSubWindow({ newWindow: { name: 'mainSubWindow' } }); this.doChangeBusinessPartner({ businessPartner: this.customer }); }, init: function (model) { this.model = model; }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBPOS_LblAssignToTicket')); } }); /**/ enyo.kind({ kind: 'OB.UI.Button', name: 'OB.OBPOSPointOfSale.UI.customers.editnewaddress', style: 'margin: 0px 0px 8px 5px;', classes: 'btnlink btnlink-small', handlers: { onSetCustomer: 'setCustomer' }, events: { onHideThisPopup: '' }, setCustomer: function (inSender, inEvent) { this.customer = inEvent.customer; }, tap: function () { if (this.disabled) { return true; } this.doHideThisPopup(); this.model.get('subWindowManager').set('currentWindow', { name: 'customerAddressSearch', params: { caller: 'mainSubWindow', bPartner: this.customer.get('id') } }); }, init: function (model) { this.model = model; }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBPOS_TitleEditNewAddress')); } }); /*header of window body*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customers.EditCustomerWindowHeader', events: { onSearchAction: '' }, components: [{ components: [{ style: 'display: table; margin: 0 auto;', components: [{ components: [{ kind: 'OB.UI.Button', handlers: { onSetCustomer: 'setCustomer' }, style: 'width: 100px; margin: 0px 5px 8px 19px;', classes: 'btnlink-orange btnlink btnlink-small', setCustomer: function (inSender, inEvent) { this.customer = inEvent.customer; if (!OB.UTIL.isWritableOrganization(this.customer.get('organization')) || !OB.MobileApp.model.hasPermission('OBPOS_retail.editCustomers')) { this.disabled = true; this.setAttribute("disabled", "disabled"); } else { this.disabled = false; this.setAttribute("disabled", null); } }, tap: function () { if (this.disabled === false) { var sw = this.subWindow; this.model.get('subWindowManager').set('currentWindow', { name: 'customerCreateAndEdit', params: { businessPartner: this.customer, navigateOnClose: sw.getName() } }); } }, init: function (model) { this.model = model; }, initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblEdit')); } }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.assigncustomertoticket' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customers.editnewaddress' }] }] }] }], searchAction: function () { this.doSearchAction({ bpName: this.$.filterText.getValue() }); } }); enyo.kind({ kind: 'OB.OBPOSPointOfSale.UI.customers.edit_createcustomers', name: 'OB.OBPOSPointOfSale.UI.customers.editcustomers_impl', style: 'padding: 9px 15px;', windowHeader: 'OB.OBPOSPointOfSale.UI.customers.EditCustomerWindowHeader', newAttributes: [{ kind: 'OB.UI.CustomerTextProperty', name: 'customerName', modelProperty: 'name', i18nLabel: 'OBPOS_LblName', readOnly: true }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerBpCat', modelProperty: 'businessPartnerCategory_name', i18nLabel: 'OBPOS_BPCategory', readOnly: true //displayLogic: OB.POS.modelterminal.get('terminal').bp_showcategoryselector }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerTaxId', modelProperty: 'taxID', i18nLabel: 'OBPOS_LblTaxId', readOnly: true // displayLogic: OB.POS.modelterminal.get('terminal').bp_showtaxid }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerLocName', modelProperty: 'locName', i18nLabel: 'OBPOS_LblAddress', readOnly: true }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerPostalCode', modelProperty: 'postalCode', i18nLabel: 'OBPOS_LblPostalCode', readOnly: true }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerCity', modelProperty: 'cityName', i18nLabel: 'OBPOS_LblCity', readOnly: true }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerPhone', modelProperty: 'phone', i18nLabel: 'OBPOS_LblPhone', readOnly: true }, { kind: 'OB.UI.CustomerTextProperty', name: 'customerEmail', modelProperty: 'email', i18nLabel: 'OBPOS_LblEmail', readOnly: true }] }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global enyo, _, $ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.ModalConfigurationRequiredForCreateCustomers', kind: 'OB.UI.ModalInfo', i18nHeader: 'OBPOS_configurationRequired', bodyContent: { i18nContent: 'OBPOS_configurationNeededToCreateCustomers' } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.cancelEdit', kind: 'OB.UI.Button', style: 'width: 100px; margin: 0px 0px 8px 5px;', classes: 'btnlink-gray btnlink btnlink-small', i18nContent: 'OBMOBC_LblCancel' }); enyo.kind({ name: 'OB.UI.CustomerPropertyLine', components: [{ name: 'labelLine', style: 'font-size: 15px; color: black; text-align: right; border: 1px solid #FFFFFF; background-color: #E2E2E2; width: 20%; height: 28px; padding: 12px 5px 1px 0; float: left;' }, { style: 'border: 1px solid #FFFFFF; float: left; width: 75%;', name: 'newAttribute' }, { style: 'clear: both' }], initComponents: function () { this.inherited(arguments); this.$.newAttribute.createComponent(this.newAttribute); this.$.labelLine.content = this.newAttribute.i18nLabel ? OB.I18N.getLabel(this.newAttribute.i18nLabel) : this.newAttribute.label; } }); enyo.kind({ name: 'OB.UI.CustomerAddrTextProperty', kind: 'enyo.Input', type: 'text', classes: 'input', style: 'width: 100%; height: 30px; margin:0;', handlers: { onLoadValue: 'loadValue', onSaveChange: 'saveChange' }, events: { onSaveProperty: '' }, loadValue: function (inSender, inEvent) { if (inEvent.customerAddr !== undefined) { if (inEvent.customerAddr.get(this.modelProperty) !== undefined) { this.setValue(inEvent.customerAddr.get(this.modelProperty)); } } else { this.setValue(''); if (this.modelProperty === 'countryName') { this.setValue(OB.POS.modelterminal.get('terminal').defaultbp_bpcountry_name); } } if (this.modelProperty === 'customerName' && inEvent.customer !== undefined && inEvent.customer.get('name') !== undefined) { this.setValue(inEvent.customer.get('name')); } }, saveChange: function (inSender, inEvent) { inEvent.customerAddr.set(this.modelProperty, this.getValue()); }, initComponents: function () { if (this.readOnly) { this.setAttribute('readonly', 'readonly'); } if (this.maxlength) { this.setAttribute('maxlength', this.maxlength); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.edit_createcustomers', handlers: { onSetCustomerAddr: 'setCustomerAddr', onSaveCustomerAddr: 'saveCustomerAddr' }, events: { onChangeBusinessPartner: '' }, components: [{ name: 'bodyheader' }, { name: 'customerAddrAttributes' }], setCustomerAddr: function (inSender, inEvent) { this.customer = inEvent.customer; this.customerAddr = inEvent.customerAddr; this.waterfall('onLoadValue', { customer: this.customer, customerAddr: this.customerAddr }); }, saveCustomerAddr: function (inSender, inEvent) { var me = this, sw = me.subWindow; function getCustomerAddrValues(params) { me.waterfall('onSaveChange', { customer: params.customer, customerAddr: params.customerAddr }); } function goToViewWindow(sw, params) { if (sw.caller === 'mainSubWindow') { sw.doChangeSubWindow({ newWindow: { name: 'customerAddressView', params: { navigateOnClose: 'mainSubWindow', businessPartner: params.customer, bPLocation: params.customerAddr } } }); } else { sw.doChangeSubWindow({ newWindow: { name: 'customerAddressView', params: { navigateOnClose: 'customerAddressSearch', businessPartner: params.customer, bPLocation: params.customerAddr } } }); } } if (this.customerAddr === undefined) { this.model.get('customerAddr').newCustomerAddr(); this.model.get('customerAddr').set('bpartner', this.customer.get('id')); this.waterfall('onSaveChange', { customerAddr: this.model.get('customerAddr') }); if (this.model.get('customerAddr').saveCustomerAddr()) { goToViewWindow(sw, { customer: this.customer, customerAddr: this.model.get('customerAddr') }); } } else { this.model.get('customerAddr').loadById(this.customerAddr.get('id'), function (customerAddr) { getCustomerAddrValues({ customerAddr: customerAddr }); if (customerAddr.saveCustomerAddr()) { goToViewWindow(sw, { customer: me.customer, customerAddr: customerAddr }); if (customerAddr.get('id') === me.customer.get("locId")) { me.customer.set('locId', customerAddr.get('id')); me.customer.set('locName', customerAddr.get('name')); OB.Dal.save(me.customer, function success(tx) { me.doChangeBusinessPartner({ businessPartner: me.customer }); }, function error(tx) { OB.error(tx); }); } } }); } }, initComponents: function () { this.inherited(arguments); this.$.bodyheader.createComponent({ kind: this.windowHeader }); this.attributeContainer = this.$.customerAddrAttributes; enyo.forEach(this.newAttributes, function (natt) { var resultDisplay = true, undf; if (natt.displayLogic !== undf && natt.displayLogic !== null) { if (enyo.isFunction(natt.displayLogic)) { resultDisplay = natt.displayLogic(this); } else { resultDisplay = natt.displayLogic; } } if (resultDisplay) { this.$.customerAddrAttributes.createComponent({ kind: 'OB.UI.CustomerPropertyLine', name: 'line_' + natt.name, newAttribute: natt }); } }, this); }, init: function (model) { this.model = model; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global enyo, _, $ */ enyo.kind({ kind: 'OB.UI.Subwindow', name: 'OB.OBPOSPointOfSale.UI.customeraddr.newcustomeraddr', events: { onShowPopup: '' }, beforeSetShowing: function (params) { if (OB.POS.modelterminal.get('terminal').defaultbp_paymentmethod !== null && OB.POS.modelterminal.get('terminal').defaultbp_bpcategory !== null && OB.POS.modelterminal.get('terminal').defaultbp_paymentterm !== null && OB.POS.modelterminal.get('terminal').defaultbp_invoiceterm !== null && OB.POS.modelterminal.get('terminal').defaultbp_bpcountry !== null && OB.POS.modelterminal.get('terminal').defaultbp_bporg !== null) { this.waterfall('onSetCustomerAddr', { customer: params.businessPartner, customerAddr: params.bPLocation }); //show return true; } else { this.doShowPopup({ popup: 'modalConfigurationRequiredForCreateNewCustomers' }); //not show return false; } }, defaultNavigateOnClose: 'customerAddressView', header: { kind: 'OB.UI.SubwindowHeader', name: 'OB.OBPOSPointOfSale.UI.customeraddr.newcustomerheader', handlers: { onSetCustomerAddr: 'setCustomerAddr' }, i18nHeaderMessage: 'OBPOS_TitleEditNewCustomerAddress', setCustomerAddr: function (inSender, inEvent) { this.customer = inEvent.customer; this.customerAddr = inEvent.customerAddr; }, onTapCloseButton: function () { var subWindow = this.subWindow; var customer, customerAddr; if (this.headerContainer) { customer = this.headerContainer.customer; customerAddr = this.headerContainer.customerAddr; } else { customer = this.customer; customerAddr = this.customerAddr; } if (subWindow.caller === 'mainSubWindow') { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller } }); } else { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller, params: { navigateOnClose: 'customerAddressSearch', businessPartner: customer, bPLocation: customerAddr } } }); } } }, body: { kind: 'OB.OBPOSPointOfSale.UI.customeraddr.edit_createcustomers_impl' } }); //button of header of the body enyo.kind({ kind: 'OB.UI.Button', name: 'OB.OBPOSPointOfSale.UI.customeraddr.newcustomeraddrsave', style: 'width: 100px; margin: 0px 5px 8px 19px;', classes: 'btnlink btnlink-small', i18nLabel: 'OBPOS_LblSave', events: { onSaveCustomerAddr: '' }, tap: function () { this.doSaveCustomerAddr(); } }); //Header of body enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.subwindowNewCustomer_bodyheader', components: [{ components: [{ style: 'display: table; margin: 0 auto;', components: [{ style: 'display: table-cell;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customeraddr.newcustomeraddrsave' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customeraddr.cancelEdit', handlers: { onSetCustomerAddr: 'setCustomerAddr' }, setCustomerAddr: function (inSender, inEvent) { this.customer = inEvent.customer; this.customerAddr = inEvent.customerAddr; }, tap: function () { var subWindow = this.subWindow; if (subWindow.caller === 'mainSubWindow') { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller } }); } else { subWindow.doChangeSubWindow({ newWindow: { name: subWindow.caller, params: { navigateOnClose: 'customerAddressSearch', businessPartner: this.customer, bPLocation: this.customerAddr } } }); } } }] }] }] }] }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.edit_createcustomers_impl', kind: 'OB.OBPOSPointOfSale.UI.customeraddr.edit_createcustomers', style: 'padding: 9px 15px;', windowHeader: 'OB.OBPOSPointOfSale.UI.customeraddr.subwindowNewCustomer_bodyheader', newAttributes: [{ kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrCustomerName', modelProperty: 'customerName', i18nLabel: 'OBPOS_LblCustomer', readOnly: true }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrName', modelProperty: 'name', i18nLabel: 'OBPOS_LblAddress', maxlength: 60 }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrPostalCode', modelProperty: 'postalCode', i18nLabel: 'OBPOS_LblPostalCode', maxlength: 10 }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrCity', modelProperty: 'cityName', i18nLabel: 'OBPOS_LblCity', maxlength: 60 }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrCountry', modelProperty: 'countryName', i18nLabel: 'OBPOS_LblCountry', readOnly: true }] }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global B, Backbone, $, _, enyo */ //Header of the body of cas (customer address search) enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.ModalCustomerAddrScrollableHeader', kind: 'OB.UI.ScrollableTableHeader', style: 'border-bottom: 10px solid #ff0000;', events: { onSearchAction: '', onClearAction: '' }, handlers: { onFiltered: 'searchAction' }, components: [{ style: 'padding: 10px; 10px; 0px; 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInputAutoFilter', name: 'filterText', style: 'width: 100%', isFirstFocus: true }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }] }], clearAction: function () { this.$.filterText.setValue(''); this.doClearAction(); }, searchAction: function () { this.doSearchAction({ locName: this.$.filterText.getValue(), operator: OB.Dal.CONTAINS }); return true; } }); /*items of collection Customer*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.ListCustomerAddrLine', kind: 'OB.UI.SelectButton', classes: 'btnselect-customer', components: [{ name: 'line', style: 'line-height: 23px;', components: [{ style: 'float: left; font-weight: bold;', name: 'identifier' }, { style: 'clear: both;' }] }], create: function () { this.inherited(arguments); if (_.isString(this.model.get('name')) && this.model.get('name').length > 0) { this.$.identifier.setContent(this.model.get('name') + ' - ' + this.model.get('countryName')); } else { this.$.identifier.setContent(OB.I18N.getLabel('OBPOS_EmptyLocation') + ' - ' + this.model.get('countryName')); } } }); /*Search Customer Button*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.SearchCustomerButton', kind: 'OB.UI.Button', events: { onSearchAction: '' }, classes: 'btnlink-left-toolbar', searchAction: function (params) { this.doSearchAction({ locName: params.initial, operator: params.operator }); }, initComponents: function () { this.inherited(arguments); this.setContent(this.i18nLabel ? OB.I18N.getLabel(this.i18nLabel) : this.label); } }); /* Buttons Left bar*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.CustomerAddrLeftBar', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customeraddr.NewCustomerAddrButton', i18nLabel: 'OBPOS_LblNew' }] }); /*New Customer Button*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.NewCustomerAddrButton', kind: 'OB.UI.Button', events: { onChangeSubWindow: '' }, published: { businessPartner: null }, disabled: false, classes: 'btnlink-left-toolbar', tap: function () { if (this.disabled) { return true; } var sw = this.subWindow; this.doChangeSubWindow({ newWindow: { name: 'customerAddrCreateAndEdit', params: { navigateOnClose: 'customerAddrCreateAndEdit', businessPartner: this.businessPartner } } }); }, putDisabled: function (status) { if (status === false) { this.disabled = false; this.setDisabled(false); this.removeClass('disabled'); return; } else { this.disabled = true; this.setDisabled(); this.addClass('disabled'); } }, initComponents: function () { this.inherited(arguments); this.putDisabled(!OB.MobileApp.model.hasPermission('OBPOS_retail.editCustomers')); this.setContent(this.i18nLabel ? OB.I18N.getLabel(this.i18nLabel) : this.label); } }); /*scrollable table (body of customer)*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.ListCustomerAddress', handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction' }, published: { bPartnerId: null, bPartnerModel: null }, events: { onChangeBusinessPartner: '', onChangeSubWindow: '' }, components: [{ style: 'text-align: center; padding-top: 10px; float: left; width: 19%;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customeraddr.CustomerAddrLeftBar' }] }, { style: 'float: left; width: 80%;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'bpsloclistitemprinter', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '301px', renderHeader: 'OB.OBPOSPointOfSale.UI.customeraddr.ModalCustomerAddrScrollableHeader', renderLine: 'OB.OBPOSPointOfSale.UI.customeraddr.ListCustomerAddrLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }, { style: 'clear: both' }], clearAction: function (inSender, inEvent) { this.bpsLocList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this, filter = inEvent.locName, criteria = {}; function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); } function successCallbackBPsLoc(dataBps, args) { me.bpsLocList.reset(); if (dataBps && dataBps.length > 0) { me.bpsLocList.add(dataBps.models); } } if (filter && _.isString(filter) && filter.length > 0) { criteria.name = { operator: OB.Dal.CONTAINS, value: filter }; } criteria.bpartner = this.bPartnerId; OB.Dal.find(OB.Model.BPLocation, criteria, successCallbackBPsLoc, errorCallback); return true; }, bpsLocList: null, init: function () { this.bpsLocList = new Backbone.Collection(); this.$.bpsloclistitemprinter.setCollection(this.bpsLocList); this.bpsLocList.on('click', function (model) { var sw = this.subWindow; this.doChangeSubWindow({ newWindow: { name: 'customerAddressView', params: { navigateOnClose: sw.getName(), businessPartner: this.bPartnerModel, bPLocation: model } } }); }, this); } }); /*body*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.casbody', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customeraddr.ListCustomerAddress', style: 'padding: 15px; padding-top: 0px;' }] }); //Modal pop up enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.cas', kind: 'OB.UI.Subwindow', events: { onSearchAction: '' }, beforeSetShowing: function (params) { if (params.bPartner) { var listCustAddr = this.$.subWindowBody.$.casbody.$.listCustomerAddress; listCustAddr.setBPartnerId(params.bPartner); OB.Dal.get(OB.Model.BusinessPartner, params.bPartner, function successCallbackBPs(dataBps) { listCustAddr.setBPartnerModel(dataBps); listCustAddr.$.customerAddrLeftBar.$.newCustomerAddrButton.setBusinessPartner(dataBps); }, function errorCallback(tx, error) {}); } if (this.caller === 'mainSubWindow') { this.waterfall('onSearchAction', { cleanResults: true }); } this.$.subWindowBody.$.casbody.$.listCustomerAddress.$.bpsloclistitemprinter.$.theader.$.modalCustomerAddrScrollableHeader.searchAction(); return true; }, beforeClose: function (dest) { if (dest === 'mainSubWindow') { this.waterfall('onSearchAction', { cleanResults: true }); } return true; }, defaultNavigateOnClose: 'mainSubWindow', header: { kind: 'OB.UI.SubwindowHeader', i18nHeaderMessage: 'OBPOS_TitleCustomerAddressSearch', onTapCloseButton: function () { var subWindow = this.subWindow; subWindow.doChangeSubWindow({ newWindow: { name: 'mainSubWindow' } }); } }, body: { kind: 'OB.OBPOSPointOfSale.UI.customeraddr.casbody' } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. * * Contributed by Qualian Technologies Pvt. Ltd. ************************************************************************************ */ /*global enyo, $*/ enyo.kind({ kind: 'OB.UI.Subwindow', name: 'OB.OBPOSPointOfSale.UI.customeraddr.editcustomeraddr', events: { onShowPopup: '' }, beforeSetShowing: function (params) { this.waterfall('onSetCustomerAddr', { customer: params.businessPartner, customerAddr: params.bPLocation }); return true; }, defaultNavigateOnClose: 'customerAddressSearch', header: { kind: 'OB.UI.SubwindowHeader', i18nHeaderMessage: 'OBPOS_TitleViewCustomerAddress', onTapCloseButton: function () { var subWindow = this.subWindow; subWindow.doChangeSubWindow({ newWindow: { name: subWindow.navigateOnClose, params: { navigateOnClose: 'mainSubWindow' } } }); } }, body: { kind: 'OB.OBPOSPointOfSale.UI.customeraddr.editcustomers_impl' } }); /**/ enyo.kind({ kind: 'OB.UI.Button', name: 'OB.OBPOSPointOfSale.UI.customeraddr.assigncustomeraddrtoticket', style: 'margin: 0px 0px 8px 5px;', classes: 'btnlink btnlink-small', handlers: { onSetCustomerAddr: 'setCustomerAddr' }, events: { onChangeBusinessPartner: '' }, setCustomerAddr: function (inSender, inEvent) { this.customer = inEvent.customer; this.customerAddr = inEvent.customerAddr; }, tap: function () { var me = this; me.customer.set('locId', me.customerAddr.get('id')); me.customer.set('locName', me.customerAddr.get('name')); me.doChangeBusinessPartner({ businessPartner: me.customer }); var sw = me.subWindow; sw.doChangeSubWindow({ newWindow: { name: 'mainSubWindow' } }); }, init: function (model) { this.model = model; }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBPOS_LblAssignAddress')); } }); /*header of window body*/ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.customeraddr.EditCustomerWindowHeader', events: { onSearchAction: '' }, components: [{ components: [{ style: 'display: table; margin: 0 auto;', components: [{ components: [{ kind: 'OB.UI.Button', handlers: { onSetCustomerAddr: 'setCustomerAddr' }, style: 'width: 100px; margin: 0px 5px 8px 19px;', classes: 'btnlink-orange btnlink btnlink-small', setCustomerAddr: function (inSender, inEvent) { this.customer = inEvent.customer; this.customerAddr = inEvent.customerAddr; if (!OB.UTIL.isWritableOrganization(this.customer.get('organization')) || !OB.MobileApp.model.hasPermission('OBPOS_retail.editCustomers')) { this.disabled = true; this.setAttribute("disabled", "disabled"); } else { this.disabled = false; this.setAttribute("disabled", null); } }, tap: function () { if (this.disabled === false) { var sw = this.subWindow; this.model.get('subWindowManager').set('currentWindow', { name: 'customerAddrCreateAndEdit', params: { businessPartner: this.customer, bPLocation: this.customerAddr, navigateOnClose: sw.getName() } }); } }, init: function (model) { this.model = model; }, initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblEdit')); } }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.OBPOSPointOfSale.UI.customeraddr.assigncustomeraddrtoticket' }] }] }] }], searchAction: function () { this.doSearchAction({ bpName: this.$.filterText.getValue() }); } }); enyo.kind({ kind: 'OB.OBPOSPointOfSale.UI.customeraddr.edit_createcustomers', name: 'OB.OBPOSPointOfSale.UI.customeraddr.editcustomers_impl', style: 'padding: 9px 15px;', windowHeader: 'OB.OBPOSPointOfSale.UI.customeraddr.EditCustomerWindowHeader', newAttributes: [{ kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrCustomerName', modelProperty: 'customerName', i18nLabel: 'OBPOS_LblCustomer', readOnly: true }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrName', modelProperty: 'name', i18nLabel: 'OBPOS_LblAddress', readOnly: true }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrPostalCode', modelProperty: 'postalCode', i18nLabel: 'OBPOS_LblPostalCode', readOnly: true }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrCity', modelProperty: 'cityName', i18nLabel: 'OBPOS_LblCity', readOnly: true }, { kind: 'OB.UI.CustomerAddrTextProperty', name: 'customerAddrCountry', modelProperty: 'countryName', i18nLabel: 'OBPOS_LblCountry', readOnly: true }] }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore', myId: 'ModalStockInStore', published: { stockInfo: null }, kind: 'OB.UI.Modal', header: '', body: { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.ListStockInStore', name: 'stockDetailList' }, executeOnHide: function () { this.stockInfo = null; }, executeOnShow: function () { this.setStockInfo(this.args.stockInfo); }, stockInfoChanged: function (oldValue) { if (this.stockInfo) { this.$.header.setContent(this.stockInfo.get('product').get('_identifier') + ' (' + this.stockInfo.get('product').get('uOMsymbol') + ')'); this.$.body.$.stockDetailList.setStockValuesPerWarehouse(this.stockInfo.get('warehouses')); } else { this.$.body.$.stockDetailList.setStockValuesPerWarehouse(null); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.ListStockInStore', classes: 'row-fluid', published: { stockValuesPerWarehouse: null }, components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;' }, { components: [{ name: 'scrollListStockDetails', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderLine: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.StockInStoreLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }], stockValuesPerWarehouseChanged: function (oldValue) { if (this.stockValuesPerWarehouse) { this.$.scrollListStockDetails.setCollection(this.stockValuesPerWarehouse); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.StockInStoreLine', classes: 'btnselect', components: [{ name: 'line', style: 'line-height: 23px;', components: [{ style: 'float: left; width: 60%; font-size: 20px;', name: 'warehouse' }, { style: 'float: left; width: 25%; font-weight: bold; font-size: 20px;', name: 'quantity' }, { style: 'clear: both' }] }, { components: [{ style: 'padding: 5px; padding-left: 10px;', name: 'detail', allowHtml: true }] }], create: function () { var str = ""; this.inherited(arguments); this.$.warehouse.setContent(this.model.get('warehousename')); this.$.quantity.setContent(this.model.get('warehouseqty')); this.model.get('bins').each(function (model) { str += '' + model.get('binqty') + ' - ' + model.get('binname') + '
'; }); this.$.detail.setContent(str); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStoreClickable', myId: 'ModalStockInStoreClickable', kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore', body: { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.ListStockInStoreClickable', name: 'stockDetailListClickable' }, stockInfoChanged: function (oldValue) { if (this.stockInfo) { this.$.header.setContent(this.stockInfo.get('product').get('_identifier') + ' (' + this.stockInfo.get('product').get('uOMsymbol') + ')'); this.$.body.$.stockDetailListClickable.setStockValuesPerWarehouse(this.stockInfo.get('warehouses')); } else { this.$.body.$.stockDetailListClickable.setStockValuesPerWarehouse(null); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.ListStockInStoreClickable', kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.ListStockInStore', components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;' }, { components: [{ name: 'scrollListStockDetailsClickable', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderLine: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.StockInStoreLineClickable', renderEmpty: 'OB.UI.RenderEmpty' }] }] }], stockValuesPerWarehouseChanged: function (oldValue) { if (this.stockValuesPerWarehouse) { this.$.scrollListStockDetailsClickable.setCollection(this.stockValuesPerWarehouse); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.StockInStoreLineClickable', kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInStore.Components.StockInStoreLine', classes: 'stockinstorelines', events: { onHideThisPopup: '', onWarehouseSelected: '' }, tap: function () { this.doHideThisPopup(); this.doWarehouseSelected({ warehouseid: this.model.get('warehouseid'), warehousename: this.model.get('warehousename'), warehouseqty: this.model.get('warehouseqty') }); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInOtherStores', myId: 'ModalStockInOtherStores', published: { stockInfo: null }, kind: 'OB.UI.Modal', header: '', body: { kind: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInOtherStores.Components.ListStockInOtherStores', name: 'stockDetailList' }, executeOnHide: function () { this.stockInfo = null; }, executeOnShow: function () { this.setStockInfo(this.args.stockInfo); }, stockInfoChanged: function (oldValue) { if (this.stockInfo) { this.$.header.setContent(this.stockInfo.get('product').get('_identifier') + ' (' + this.stockInfo.get('product').get('uOMsymbol') + ')'); this.$.body.$.stockDetailList.setStockValuesOtherStores(this.stockInfo.get('organizations')); } else { this.$.body.$.stockDetailList.setStockValuesOtherStores(null); } } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInOtherStores.Components.ListStockInOtherStores', classes: 'row-fluid', published: { stockValuesOtherStores: null }, components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;' }, { components: [{ name: 'scrollListStockDetails', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderLine: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInOtherStores.Components.StockInOtherStoresLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }], stockValuesOtherStoresChanged: function (oldValue) { this.$.scrollListStockDetails.setCollection(this.stockValuesOtherStores); } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalStockInOtherStores.Components.StockInOtherStoresLine', classes: 'btnselect', components: [{ name: 'line', style: 'line-height: 23px;', components: [{ style: 'float: left; width: 60%; font-size: 20px;', name: 'organization' }, { style: 'float: left; width: 25%; font-weight: bold; font-size: 20px;', name: 'quantity' }, { style: 'clear: both' }] }, { components: [{ style: 'padding: 5px; padding-left: 10px;', name: 'detail', allowHtml: true }] }], create: function () { var str = ""; this.inherited(arguments); this.$.organization.setContent(this.model.get('organizationname')); this.$.quantity.setContent(this.model.get('organizationqty')); this.model.get('warehouses').each(function (model) { str += '' + model.get('warehouseqty') + ' - ' + model.get('warehousename') + '
'; }); this.$.detail.setContent(str); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, Backbone, $, _, enyo */ enyo.kind({ kind: 'OB.UI.ModalInfo', name: 'OB.OBPOSPointOfSale.UI.Modals.ModalProductCannotBeGroup', i18nHeader: 'OBPOS_productCannotBeGroupHeader', bodyContent: { i18nContent: 'OBPOS_productCannotBeGroupMessage' } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.ModalConfigurationRequiredForCrossStore', kind: 'OB.UI.ModalInfo', i18nHeader: 'OBPOS_configurationRequired', bodyContent: { i18nContent: 'OBPOS_configurationNeededToCrossStore' }, myId: 'modalConfigurationRequiredForCrossStore' }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.OBPOSPointOfSale.UI.Modals.modalEnoughCredit', bodyContent: { name: 'popupmessage', content: '' }, bodyButtons: { components: [{ kind: 'OB.OBPOSPointOfSale.UI.Modals.modalEnoughCredit.Components.apply_button' }, { kind: 'OB.OBPOSPointOfSale.UI.Modals.modalEnoughCredit.Components.cancel_button' }] }, executeOnShow: function () { var pendingQty = this.args.order.getPending(); var bpName = this.args.order.get('bp').get('_identifier'); var selectedPaymentMethod = this.args.order.selectedPayment; var currSymbol; var rate = 1, i; var paymentList = OB.POS.modelterminal.get('payments'); for (i = 0; i < paymentList.length; i++) { if (paymentList[i].payment.searchKey === selectedPaymentMethod) { rate = paymentList[i].mulrate; currSymbol = paymentList[i].symbol; } } this.setHeader(OB.I18N.getLabel('OBPOS_enoughCreditHeader')); if (this.args.message) { this.$.bodyContent.$.popupmessage.setContent(OB.I18N.getLabel(this.args.message)); } else if (this.args.order.get('orderType') === 1) { this.$.bodyContent.$.popupmessage.setContent(OB.I18N.getLabel('OBPOS_enoughCreditReturnBody', [OB.I18N.formatCurrency(pendingQty * rate) + " " + currSymbol, bpName])); } else { this.$.bodyContent.$.popupmessage.setContent(OB.I18N.getLabel('OBPOS_enoughCreditBody', [OB.I18N.formatCurrency(pendingQty * rate) + " " + currSymbol, bpName])); } } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSPointOfSale.UI.Modals.modalEnoughCredit.Components.apply_button', i18nContent: 'OBPOS_LblUseCredit', isDefaultAction: true, init: function (model) { this.model = model; }, tap: function () { function error(tx) { OB.UTIL.showError("OBDAL error: " + tx); } this.doHideThisPopup(); this.model.get('order').set('paidOnCredit', true); this.model.get('order').trigger('paymentDone'); this.allowOpenDrawer = false; var payments = this.model.get('order').get('payments'); var me = this; payments.each(function (payment) { if (payment.get('allowOpenDrawer') || payment.get('isCash')) { me.allowOpenDrawer = true; } }); if (this.allowOpenDrawer) { OB.POS.hwserver.openDrawer({ openFirst: false, receipt: this.model.get('order') }, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerSales); } var bp = this.model.get('order').get('bp'); var bpCreditUsed = this.model.get('order').get('bp').get('creditUsed'); var totalPending = this.model.get('order').getPending(); if (this.parent.parent.parent.parent.args.order.get('gross') < 0) { bp.set('creditUsed', bpCreditUsed - totalPending); } else { bp.set('creditUsed', bpCreditUsed + totalPending); } OB.Dal.save(bp, null, error); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSPointOfSale.UI.Modals.modalEnoughCredit.Components.cancel_button', i18nContent: 'OBMOBC_LblCancel', tap: function () { this.doHideThisPopup(); } }); enyo.kind({ kind: 'OB.UI.ModalInfo', name: 'OB.OBPOSPointOfSale.UI.Modals.modalNotEnoughCredit', style: 'background-color: #EBA001;', i18nHeader: 'OBPOS_notEnoughCreditHeader', isDefaultAction: true, executeOnShow: function () { if (this.args) { this.$.bodyContent.$.popupmessage.setContent(OB.I18N.getLabel('OBPOS_notEnoughCreditBody', [this.args.bpName, this.args.actualCredit])); } }, bodyContent: { name: 'popupmessage', content: '' } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.modalDiscountNeedQty', kind: 'OB.UI.ModalInfo', i18nHeader: 'OBPOS_discountNeedsQty_header', bodyContent: { i18nContent: 'OBPOS_discountNeedsQty_body' } }); enyo.kind({ name: 'OB.OBPOSPointOfSale.UI.Modals.modalNotValidValueForDiscount', kind: 'OB.UI.ModalInfo', i18nHeader: 'OBPOS_modalNotValidValueForDiscount_header', bodyContent: { i18nContent: 'OBPOS_modalNotValidValueForDiscount_body' } }); /* ************************************************************************************ * Copyright (C) 2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, _ */ (function () { enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.UI.MessageDialog', header: '', bodyContent: { name: 'bodymessage', content: '' }, bodyButtons: { components: [{ kind: 'OB.UI.MessageDialogOK' }] }, executeOnShow: function () { this.$.header.setContent(this.args.header); this.$.bodyContent.$.bodymessage.setContent(this.args.message); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.MessageDialogOK', i18nContent: 'OBMOBC_LblOk', isDefaultAction: true, tap: function () { this.doHideThisPopup(); } }); OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', { kind: 'OB.UI.MessageDialog', name: 'OB_UI_MessageDialog' }); // object.doShowPopup({ // OB.MobileApp.view.$.containerWindow.getRoot().doShowPopup({ // popup: 'OB_UI_MessageDialog', // args: { // header: header, // message: message // } // }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global $ */ (function () { var PrintCashMgmt = function () { this.templatecashmgmt = new OB.DS.HWResource(OB.OBPOSCashMgmt.Print.CashMgmtTemplate); }; PrintCashMgmt.prototype.print = function (depsdropstosave) { OB.POS.hwserver.print(this.templatecashmgmt, { cashmgmt: depsdropstosave }); }; // Public object definition OB.OBPOSCashMgmt = OB.OBPOSCashMgmt || {}; OB.OBPOSCashMgmt.Print = OB.OBPOSCashMgmt.Print || {}; OB.OBPOSCashMgmt.Print.CashMgmt = PrintCashMgmt; OB.OBPOSCashMgmt.Print.CashMgmtTemplate = 'res/printcashmgmt.xml'; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, Backbone, _, TestRegistry */ OB.OBPOSCashMgmt = OB.OBPOSCashMgmt || {}; OB.OBPOSCashMgmt.Model = OB.OBPOSCashMgmt.Model || {}; OB.OBPOSCashMgmt.UI = OB.OBPOSCashMgmt.UI || {}; // Window model OB.OBPOSCashMgmt.Model.CashManagement = OB.Model.WindowModel.extend({ models: [OB.Model.CashManagement], init: function () { var payments = new Backbone.Collection(), me = this, paymentMth, criteria, runSyncProcessCM, error, addedCashMgmt, selectedPayment; this.set('payments', new Backbone.Collection()); this.set('cashMgmtDropEvents', new Backbone.Collection(OB.POS.modelterminal.get('cashMgmtDropEvents'))); this.set('cashMgmtDepositEvents', new Backbone.Collection(OB.POS.modelterminal.get('cashMgmtDepositEvents'))); OB.Dal.find(OB.Model.CashUp, { 'isbeingprocessed': 'N' }, function (cashUp) { OB.Dal.find(OB.Model.PaymentMethodCashUp, { 'cashup_id': cashUp.at(0).get('id'), _orderByClause: 'searchKey desc' }, function (pays) { payments = pays; payments.each(function (pay) { criteria = { 'paymentMethodId': pay.get('paymentmethod_id'), 'cashup_id': cashUp.at(0).get('id') }; paymentMth = OB.POS.modelterminal.get('payments').filter(function (payment) { return payment.payment.id === pay.get('paymentmethod_id'); })[0].paymentMethod; if (paymentMth.allowdeposits || paymentMth.allowdrops) { OB.Dal.find(OB.Model.CashManagement, criteria, function (cashmgmt, pay) { if (cashmgmt.length > 0) { pay.set('listdepositsdrops', cashmgmt.models); } me.get('payments').add(pay); }, null, pay); } }); }); }, null, this); this.depsdropstosave = new Backbone.Collection(); this.depsdropstosave.on('paymentDone', function (model, p) { error = false; payments.each(function (pay) { if (p.id === pay.get('paymentmethod_id')) { error = (p.type === 'drop' && OB.DEC.sub(pay.get('total'), OB.DEC.mul(p.amount, p.rate)) < 0); } }); if (error) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgMoreThanAvailable')); return; } OB.Dal.find(OB.Model.CashUp, { 'isbeingprocessed': 'N' }, function (cashUp) { addedCashMgmt = new OB.Model.CashManagement({ id: OB.Dal.get_uuid(), description: p.identifier + ' - ' + model.get('name'), amount: p.amount, origAmount: OB.DEC.mul(p.amount, p.rate), type: p.type, reasonId: model.get('id'), paymentMethodId: p.id, user: OB.POS.modelterminal.get('context').user._identifier, userId: OB.POS.modelterminal.get('context').user.id, time: new Date().toString().substring(16, 21), isocode: p.isocode, glItem: p.glItem, cashup_id: cashUp.at(0).get('id'), isbeingprocessed: 'N' }); me.depsdropstosave.add(addedCashMgmt); selectedPayment = payments.filter(function (payment) { return payment.get('paymentmethod_id') === p.id; })[0]; if (selectedPayment.get('listdepositsdrops')) { selectedPayment.get('listdepositsdrops').push(addedCashMgmt); selectedPayment.trigger('change'); } else { selectedPayment.set('listdepositsdrops', [addedCashMgmt]); } }, null, this); }, this); this.depsdropstosave.on('makeDeposits', function () { // Done button has been clicked me = this; TestRegistry.CashMgmt = TestRegistry.CashMgmt || {}; TestRegistry.CashMgmt.isCashDepositPrinted = false; OB.UTIL.showLoading(true); if (this.depsdropstosave.length === 0) { // Nothing to do go to main window OB.POS.navigate('retail.pointofsale'); return true; } this.printCashMgmt = new OB.OBPOSCashMgmt.Print.CashMgmt(); TestRegistry.CashMgmt.isCashDepositPrinted = true; function runSync() { if (OB.MobileApp.model.get('connectedToERP')) { OB.MobileApp.model.runSyncProcess(function () { OB.UTIL.showLoading(false); me.set("finished", true); if (OB.POS.modelterminal.hasPermission('OBPOS_print.cashmanagement')) { me.printCashMgmt.print(me.depsdropstosave.toJSON()); } }); } else { OB.UTIL.showLoading(false); me.set("finished", true); if (OB.POS.modelterminal.hasPermission('OBPOS_print.cashmanagement')) { me.printCashMgmt.print(me.depsdropstosave.toJSON()); } } } runSyncProcessCM = _.after(this.depsdropstosave.models.length, runSync); // Sending drops/deposits to backend _.each(this.depsdropstosave.models, function (depdrop, index) { OB.Dal.save(depdrop, function () { OB.UTIL.calculateCurrentCash(); runSyncProcessCM(); }, function (error) { OB.UTIL.showLoading(false); me.set("finishedWrongly", true); return; }, true); }, this); }, this); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, $, _, enyo */ // Numeric keyboard with buttons for each payment method accepting drops/deposits enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.CashMgmtKeyboard', kind: 'OB.UI.Keyboard', events: { onShowPopup: '' }, getPayment: function (id, key, iscash, allowopendrawer, name, identifier, type, rate, isocode, glItem) { var me = this; return { permission: key, action: function (keyboard, txt) { txt = OB.I18N.parseNumber(txt); keyboard.owner.owner.owner.currentPayment = { id: id, amount: txt, identifier: identifier, destinationKey: key, type: type, rate: rate, isocode: isocode, iscash: iscash, allowopendrawer: allowopendrawer, glItem: glItem }; if (type === 'drop') { me.doShowPopup({ popup: 'modaldropevents' }); } else { me.doShowPopup({ popup: 'modaldepositevents' }); } } }; }, init: function () { var buttons = []; this.inherited(arguments); buttons.push({ command: 'opendrawer', i18nLabel: 'OBPOS_OpenDrawer', stateless: true, definition: { stateless: true, action: function (keyboard, amt) { OB.POS.hwserver.openCheckDrawer(false, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerCount); } } }); _.bind(this.getPayment, this); _.each(OB.POS.modelterminal.get('payments'), function (paymentMethod) { var payment = paymentMethod.payment; if (paymentMethod.paymentMethod.allowdeposits) { buttons.push({ idSufix: 'Deposit.' + paymentMethod.isocode, command: payment.searchKey + '_' + OB.I18N.getLabel('OBPOS_LblDeposit'), definition: this.getPayment(payment.id, payment.searchKey, paymentMethod.paymentMethod.iscash, paymentMethod.paymentMethod.allowopendrawer, payment._identifier, payment._identifier, 'deposit', paymentMethod.rate, paymentMethod.isocode, paymentMethod.paymentMethod.gLItemForDeposits), label: payment._identifier + ' ' + OB.I18N.getLabel('OBPOS_LblDeposit') }); } if (paymentMethod.paymentMethod.allowdrops) { buttons.push({ idSufix: 'Withdrawal.' + paymentMethod.isocode, command: payment.searchKey + '_' + OB.I18N.getLabel('OBPOS_LblWithdrawal'), definition: this.getPayment(payment.id, payment.searchKey, paymentMethod.paymentMethod.iscash, paymentMethod.paymentMethod.allowopendrawer, payment._identifier, payment._identifier, 'drop', paymentMethod.rate, paymentMethod.isocode, paymentMethod.paymentMethod.gLItemForDrops), label: payment._identifier + ' ' + OB.I18N.getLabel('OBPOS_LblWithdrawal') }); } }, this); this.addToolbar({ name: 'cashMgmtToolbar', buttons: buttons }); this.showToolbar('cashMgmtToolbar'); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, Backbone, enyo */ //Renders a modal popup with a list of reasons for drops/deposits enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.ModalDepositEvents', kind: 'OB.UI.Modal', topPosition: '125px', body: { kind: 'OB.OBPOSCashMgmt.UI.ListEvents' } }); //Popup with the destinations for deposits/drops enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.ListEvents', classes: 'row-fluid', components: [{ classes: 'span12', components: [{ components: [{ //tableview name: 'eventList', kind: 'OB.UI.Table', style: 'overflow: auto; max-height: 600px', renderLine: 'OB.OBPOSCashMgmt.UI.ListEventLine', renderEmpty: 'OB.UI.RenderEmpty' }] }] }], init: function (model) { this.model = model; this.$.eventList.setCollection(this.model.get(this.owner.owner.type)); } }); //Renders each of the deposit/drops destinations enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.ListEventLine', kind: 'OB.UI.SelectButton', style: 'height: 60px; background-color: #dddddd; border: 1px solid #ffffff;', events: { onHideThisPopup: '' }, components: [{ name: 'line', style: 'padding: 1px 0px 1px 5px;' }], tap: function () { this.inherited(arguments); this.doHideThisPopup(); }, create: function () { this.inherited(arguments); this.$.line.setContent(this.model.get('name')); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, Backbone, enyo */ // Top-right panel with clock and buttons enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.CashMgmtInfo', components: [{ style: 'position: relative; background: #363636; color: white; height: 200px; margin: 5px; padding: 5px', components: [{ //clock here kind: 'OB.UI.Clock', classes: 'pos-clock' }, { // process info style: 'padding: 10px; float: left; width: 320px; line-height: 23px;', name: 'infoLbl' }] }], initComponents: function () { this.inherited(arguments); this.$.infoLbl.setContent(OB.I18N.getLabel('OBPOS_LblDepositsWithdrawalsMsg')); } }); enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.DoneButton', kind: 'OB.UI.RegularButton', classes: 'btnlink-white btnlink-fontgray', style: 'min-width: 115px;', i18nContent: 'OBPOS_LblDone', tap: function () { this.owner.owner.model.depsdropstosave.trigger('makeDeposits'); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, _, enyo */ // Renders lines of deposits/drops enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.RenderDepositLine', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ name: 'description', style: 'padding: 6px 20px 6px 10px; float: left; width:30%' }, { name: 'user', style: 'text-align:right; padding: 6px 20px 6px 10px; float: left; width: 12%' }, { name: 'time', style: 'text-align:right; padding: 6px 20px 6px 10px; float: left; width: 8%' }, { name: 'foreignAmt', style: 'text-align:right; padding: 6px 0px 6px 10px; float: left; width: 15% ', content: '' }, { name: 'amt', style: 'text-align:right; padding: 6px 20px 6px 10px; float: right; width: 20%' }] }] }], create: function () { var amnt, foreignAmt, lbl; this.inherited(arguments); if (this.model.get('type') === 'drop') { lbl = OB.I18N.getLabel('OBPOS_LblWithdrawal') + ': '; if (this.model.get('origAmount') !== this.model.get('amount')) { foreignAmt = OB.I18N.formatCurrency(OB.DEC.add(0, this.model.get('amount'))); amnt = OB.I18N.formatCurrency(this.model.get('origAmount')); } else { amnt = OB.I18N.formatCurrency(OB.DEC.add(0, this.model.get('amount'))); } } else { lbl = OB.I18N.getLabel('OBPOS_LblDeposit') + ': '; if (this.model.get('origAmount') !== this.model.get('amount')) { foreignAmt = OB.I18N.formatCurrency(OB.DEC.add(0, this.model.get('amount'))); amnt = OB.I18N.formatCurrency(this.model.get('origAmount')); } else { amnt = OB.I18N.formatCurrency(OB.DEC.add(0, this.model.get('amount'))); } } this.$.description.setContent(lbl + this.model.get('description')); this.$.user.setContent(this.model.get('user')); this.$.time.setContent(this.model.get('time')); if (foreignAmt && ((this.model.get('rate') && this.model.get('rate') !== '1') || amnt !== foreignAmt)) { this.$.foreignAmt.setContent('(' + foreignAmt + ' ' + this.model.get('isocode') + ')'); } this.$.amt.setContent(amnt); } }); enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.RenderForeignTotal', tag: 'span', published: { foreignTotal: null, textForeignTotal: '' }, create: function () { this.inherited(arguments); this.owner.model.on('change:total', function (model) { this.setForeignTotal(model.get('total')); }, this); }, foreignTotalChanged: function (oldValue) { this.setContent(this.textForeignTotal); if (OB.DEC.compare(this.foreignTotal) < 0) { this.applyStyle('color', 'red'); } else { this.applyStyle('color', 'black'); } } }); enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.RenderTotal', tag: 'span', published: { total: null }, create: function () { this.inherited(arguments); this.owner.model.on('change:total', function (model) { this.setTotal(model.get('total')); }, this); }, totalChanged: function (oldValue) { this.setContent(OB.I18N.formatCurrency(this.total)); if (OB.DEC.compare(this.total) < 0) { this.applyStyle('color', 'red'); } else { this.applyStyle('color', 'black'); } } }); //Renders each of the payment types with their summary and a list of deposits/drops (OB.OBPOSCashMgmt.UI.RenderDepositLine) enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.RenderDepositsDrops', components: [ // separator { classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ style: 'padding: 10px 20px 10px 10px; float: left;' }, { style: 'clear: both;' }] }] }, // Total per payment type { classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ name: 'startingCashPayName', style: 'padding: 6px 20px 6px 10px; float: left; width: 61%' }, { name: 'startingCashForeignAmnt', style: 'text-align:right; padding: 6px 0px 6px 10px; float: left; width: 15%', content: '' }, { name: 'startingCashAmnt', style: 'text-align:right; padding: 6px 20px 6px 10px; float: right;' }] }] }, // Tendered per payment type { classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ name: 'tenderedLbl', style: 'padding: 6px 20px 6px 10px; float: left; width: 61%' }, { name: 'tenderedForeignAmnt', style: 'text-align:right; padding: 6px 0px 6px 10px; float: left; width: 15%', content: '' }, { name: 'tenderedAmnt', style: 'text-align:right; padding: 6px 20px 6px 10px; float: right;' }] }] }, // Drops/deposits { name: 'theList', listStyle: 'list', kind: 'OB.UI.Table', renderLine: 'OB.OBPOSCashMgmt.UI.RenderDepositLine', renderEmpty: 'enyo.Control' }, // Available per payment type { classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ name: 'availableLbl', style: 'padding: 10px 20px 10px 10px; float: left; width: 61%; font-weight:bold;' }, { style: 'text-align:right; padding: 6px 0px 6px 10px; float: left; width: 15%; font-weight:bold;', components: [{ name: 'foreignTotal', kind: 'OB.OBPOSCashMgmt.UI.RenderForeignTotal', style: 'float:right;' }] }, { style: 'padding: 10px 20px 10px 0px; float: right;', components: [{ name: 'total', kind: 'OB.OBPOSCashMgmt.UI.RenderTotal', style: 'float:right; font-weight: bold;' }] }] }] }], create: function () { var transactionsArray = this.model.get('listdepositsdrops'), transactionsCollection = new Backbone.Collection(transactionsArray), total; var fromCurrencyId = OB.MobileApp.model.paymentnames[this.model.attributes.searchKey].paymentMethod.currency; this.inherited(arguments); total = OB.DEC.add(0, this.model.get('startingCash')); total = OB.DEC.add(total, this.model.get('totalSales')); total = OB.DEC.sub(total, this.model.get('totalReturns')); var totalDeposits = _.reduce(transactionsArray, function (accum, trx) { if (trx.get('type') === 'deposit') { return OB.DEC.add(accum, trx.get('origAmount')); } else { return OB.DEC.sub(accum, trx.get('origAmount')); } }, 0); total = OB.DEC.add(total, totalDeposits); this.$.availableLbl.setContent(OB.I18N.getLabel('OBPOS_LblNewAvailableIn') + ' ' + this.model.get('name')); if (OB.UTIL.currency.isDefaultCurrencyId(fromCurrencyId)) { this.model.set('total', total, { silent: true // prevents triggering change event }); this.$.total.setTotal(total); } else { var foreignTotal = OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, total); this.model.set('total', foreignTotal, { silent: true // prevents triggering change event }); this.$.total.setTotal(foreignTotal); if (foreignTotal > 0) { this.$.foreignTotal.setTextForeignTotal('(' + OB.I18N.formatCurrency(total) + ' ' + this.model.get('isocode') + ')'); this.$.foreignTotal.setForeignTotal(total); } } this.$.theList.setCollection(transactionsCollection); this.$.startingCashPayName.setContent(OB.I18N.getLabel('OBPOS_LblStarting') + ' ' + this.model.get('name')); var startingCash = OB.DEC.add(0, this.model.get('startingCash')); this.$.startingCashAmnt.setContent(OB.I18N.formatCurrency(OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, startingCash))); if ((OB.UTIL.currency.isDefaultCurrencyId(fromCurrencyId) === false) && (startingCash > 0)) { this.$.startingCashForeignAmnt.setContent('(' + OB.I18N.formatCurrency(startingCash) + ' ' + this.model.get('isocode') + ')'); } this.$.tenderedLbl.setContent(OB.I18N.getLabel('OBPOS_LblTotalTendered') + ' ' + this.model.get('name')); var totalSalesReturns = OB.DEC.add(0, OB.DEC.sub(this.model.get('totalSales'), this.model.get('totalReturns'))); if ((OB.UTIL.currency.isDefaultCurrencyId(fromCurrencyId) === false) && (totalSalesReturns > 0)) { this.$.tenderedForeignAmnt.setContent('(' + OB.I18N.formatCurrency(totalSalesReturns) + ' ' + this.model.get('isocode') + ')'); } this.$.tenderedAmnt.setContent(OB.I18N.formatCurrency(OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, totalSalesReturns))); } }); //Renders the summary of deposits/drops and contains a list (OB.OBPOSCashMgmt.UI.RenderDepositsDrops) //with detailed information for each payment type enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.ListDepositsDrops', components: [{ style: 'overflow:auto; height: 500px; margin: 5px', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ style: 'padding: 6px; border-bottom: 1px solid #cccccc;text-align:center; font-weight:bold;', name: 'titleLbl' }, { name: 'userName', style: 'padding: 6px; border-bottom: 1px solid #cccccc; text-align:center;' }, { name: 'time', style: 'padding: 6px; border-bottom: 1px solid #cccccc; text-align:center;' }, { name: 'store', style: 'padding: 6px; border-bottom: 1px solid #cccccc; text-align:center;' }, { name: 'terminal', style: 'padding: 6px; border-bottom: 1px solid #cccccc; text-align:center;' }, { name: 'depositDropsList', kind: 'OB.UI.Table', renderLine: 'OB.OBPOSCashMgmt.UI.RenderDepositsDrops', renderEmpty: 'enyo.Control', listStyle: 'list' }] }] }] }] }], create: function () { var now = new Date(); this.inherited(arguments); this.$.userName.setContent(OB.I18N.getLabel('OBPOS_LblUser') + ': ' + OB.POS.modelterminal.get('context').user._identifier); this.$.time.setContent(OB.I18N.getLabel('OBPOS_LblTime') + ': ' + OB.I18N.formatDate(now) + ' ' + OB.I18N.formatHour(now, true)); this.$.store.setContent(OB.I18N.getLabel('OBPOS_LblStore') + ': ' + OB.POS.modelterminal.get('terminal').organization$_identifier); this.$.terminal.setContent(OB.I18N.getLabel('OBPOS_LblTerminal') + ': ' + OB.POS.modelterminal.get('terminal')._identifier); }, init: function (model) { // this.owner is the window (OB.UI.WindowView) // this.parent is the DOM object on top of the list (usually a DIV) this.model = model; this.$.depositDropsList.setCollection(this.model.get('payments')); this.$.titleLbl.setContent(OB.I18N.getLabel('OBPOS_LblCashManagement')); } }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, $, SynchronizationHelper */ enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.LeftToolbarImpl', kind: 'OB.UI.MultiColumn.Toolbar', synchId: null, buttons: [{ kind: 'OB.UI.ToolbarButton', name: 'btnCancel', disabled: false, i18nLabel: 'OBMOBC_LblCancel', stepCount: 0, span: 6, tap: function () { OB.POS.hwserver.checkDrawer(function () { OB.POS.navigate('retail.pointofsale'); }); } }, { kind: 'OB.UI.ToolbarButton', name: 'btnDone', disabled: true, i18nLabel: 'OBPOS_LblDone', stepCount: 0, span: 6, handlers: { synchronizing: 'disableButton', synchronized: 'enableButton' }, disableButton: function () { this.setDisabled(true); }, enableButton: function () { this.setDisabled(false); }, init: function (model) { this.model = model; }, tap: function () { OB.POS.hwserver.checkDrawer(function () { this.model.depsdropstosave.trigger('makeDeposits'); }, this); } }] }); enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.RightToolbarImpl', kind: 'OB.UI.MultiColumn.Toolbar', buttons: [{ kind: 'OB.UI.ToolbarButton', name: 'btnCashMgmt', span: 12, disabled: true, i18nLabel: 'OBPOS_LblCashManagement' }] }); // Cash Management main window view enyo.kind({ name: 'OB.OBPOSCashMgmt.UI.CashManagement', kind: 'OB.UI.WindowView', windowmodel: OB.OBPOSCashMgmt.Model.CashManagement, tag: 'section', events: { onShowPopup: '' }, components: [{ kind: 'OB.UI.MultiColumn', name: 'cashupMultiColumn', leftToolbar: { kind: 'OB.OBPOSCashMgmt.UI.LeftToolbarImpl', name: 'leftToolbar', showMenu: false, showWindowsMenu: false }, rightToolbar: { kind: 'OB.OBPOSCashMgmt.UI.RightToolbarImpl', name: 'rightToolbar', showMenu: false, showWindowsMenu: false }, leftPanel: { name: 'cashmgmtLeftPanel', components: [{ classes: 'row', components: [ // 1st column: list of deposits/drops done or in process { classes: 'span12', components: [{ kind: 'OB.OBPOSCashMgmt.UI.ListDepositsDrops' }] }] }] }, rightPanel: { name: 'cashmgmtRightPanel', components: [ //2nd column { classes: 'span12', components: [{ kind: 'OB.OBPOSCashMgmt.UI.CashMgmtInfo' }, { kind: 'OB.OBPOSCashMgmt.UI.CashMgmtKeyboard' }] }] } }, //hidden stuff { components: [{ kind: 'OB.OBPOSCashMgmt.UI.ModalDepositEvents', i18nHeader: 'OBPOS_SelectDepositDestinations', name: 'modaldepositevents', type: 'cashMgmtDepositEvents' }, { kind: 'OB.OBPOSCashMgmt.UI.ModalDepositEvents', i18nHeader: 'OBPOS_SelectDropDestinations', name: 'modaldropevents', type: 'cashMgmtDropEvents' }] }], init: function () { this.synchId = SynchronizationHelper.busyUntilFinishes("cashmanagement"); this.inherited(arguments); // cashMgmtDepositEvents or cashMgmtDropEvents Collection is shown by OB.UI.Table, when selecting an option 'click' event // is triggered, propagating this UI event to model here this.model.get('cashMgmtDepositEvents').on('click', function (model) { this.model.depsdropstosave.trigger('paymentDone', model, this.currentPayment); delete this.currentPayment; }, this); this.model.get('cashMgmtDropEvents').on('click', function (model) { this.model.depsdropstosave.trigger('paymentDone', model, this.currentPayment); delete this.currentPayment; }, this); //finished this.model.on('change:finished', function () { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_LblDone'), OB.I18N.getLabel('OBPOS_FinishCashMgmtDialog'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.POS.navigate('retail.pointofsale'); } }]); }, this); //finishedWrongly this.model.on('change:finishedWrongly', function () { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_CashMgmtWronglyHeader'), OB.I18N.getLabel('OBPOS_CashMgmtWrongly'), [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.POS.navigate('retail.pointofsale'); } }]); }, this); }, rendered: function () { SynchronizationHelper.finished(this.synchId, "cashmanagement"); } }); OB.POS.registerWindow({ windowClass: OB.OBPOSCashMgmt.UI.CashManagement, route: 'retail.cashmanagement', menuPosition: 10, menuI18NLabel: 'OBPOS_LblCashManagement', permission: 'OBPOS_retail.cashmanagement', approvalType: 'OBPOS_approval.cashmgmt' }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.OBPOSCashMgmt.UI.modalFinished', i18nHeader: 'OBPOS_LblDone', bodyContent: { i18nContent: 'OBPOS_FinishCashMgmtDialog' }, bodyButtons: { components: [{ //OK button kind: 'OB.OBPOSCashMgmt.UI.modalFinished_OkButton' }] }, executeOnHide: function () { OB.POS.navigate('retail.pointofsale'); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSCashMgmt.UI.modalFinished_OkButton', i18nContent: 'OBMOBC_LblOk', tap: function () { this.doHideThisPopup(); } }); enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.OBPOSCashMgmt.UI.modalFinishedWrongly', i18nHeader: 'OBPOS_CashMgmtWronglyHeader', bodyContent: { i18nContent: 'OBPOS_CashMgmtWrongly' }, bodyButtons: { components: [{ //OK button kind: 'OB.OBPOSCashMgmt.UI.modalFinishedWrongly_OkButton' }] }, executeOnHide: function () { OB.POS.navigate('retail.pointofsale'); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSCashMgmt.UI.modalFinishedWrongly_OkButton', i18nContent: 'OBMOBC_LblOk', tap: function () { this.doHideThisPopup(); } }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, Backbone, _, $ */ enyo.kind({ name: 'OB.CashUp.StepPendingOrders', kind: enyo.Object, getStepComponent: function (leftpanel$) { return leftpanel$.listPendingReceipts; }, getToolbarName: function () { return 'toolbarempty'; }, nextButtonI18NLabel: function () { return 'OBPOS_LblNextStep'; }, allowNext: function () { return this.model.get('orderlist').length === 0 && !this.model.get('pendingOrdersToProcess'); }, getSubstepsLength: function (model) { return 1; }, isSubstepAvailable: function (model, substep) { return true; } }); enyo.kind({ name: 'OB.CashUp.CashPayments', kind: enyo.Object, getStepComponent: function (leftpanel$) { return leftpanel$.cashPayments; }, getToolbarName: function () { return 'toolbarcashpayments'; }, nextButtonI18NLabel: function () { return 'OBPOS_LblNextStep'; }, allowNext: function () { return true; }, getSubstepsLength: function (model) { return model.get('paymentList').length; }, isSubstepAvailable: function (model, substep) { var payment = model.get('paymentList').at(substep); var paymentMethod = payment.get('paymentMethod'); return paymentMethod.iscash && paymentMethod.countcash; } }); enyo.kind({ name: 'OB.CashUp.PaymentMethods', kind: enyo.Object, getStepComponent: function (leftpanel$) { return leftpanel$.listPaymentMethods; }, getToolbarName: function () { return 'toolbarcountcash'; }, nextButtonI18NLabel: function () { return 'OBPOS_LblNextStep'; }, allowNext: function () { return _.reduce(this.model.get('paymentList').models, function (allCounted, model) { return allCounted && model.get('counted') !== null && model.get('counted') !== undefined; }, true); }, getSubstepsLength: function (model) { return 1; }, isSubstepAvailable: function (model, substep) { return true; } }); enyo.kind({ name: 'OB.CashUp.CashToKeep', kind: enyo.Object, getStepComponent: function (leftpanel$) { return leftpanel$.cashToKeep; }, getToolbarName: function () { if (this.model.get('paymentList').at(this.model.get('substep')).get('paymentMethod').allowvariableamount) { return 'toolbarother'; } else { return 'toolbarempty'; } }, nextButtonI18NLabel: function () { return 'OBPOS_LblNextStep'; }, allowNext: function () { var qtyToKeep = this.model.get('paymentList').at(this.model.get('substep')).get('qtyToKeep'); var foreignCounted = this.model.get('paymentList').at(this.model.get('substep')).get('foreignCounted'); return _.isNumber(qtyToKeep) && foreignCounted >= qtyToKeep; }, getSubstepsLength: function (model) { return model.get('paymentList').length; }, isSubstepAvailable: function (model, substep) { var payment = model.get('paymentList').at(substep); var paymentMethod = payment.get('paymentMethod'); var options = 0; if (paymentMethod.automatemovementtoother) { // Option 1 if (paymentMethod.allowmoveeverything) { payment.set('qtyToKeep', 0); options++; } // Option 2 if (paymentMethod.allowdontmove) { payment.set('qtyToKeep', payment.get('foreignCounted')); options++; } // Option 3 if (paymentMethod.keepfixedamount) { if (_.isNumber(payment.get('foreignCounted')) && payment.get('foreignCounted') < paymentMethod.amount) { payment.set('qtyToKeep', payment.get('foreignCounted')); } else { payment.set('qtyToKeep', paymentMethod.amount); } options++; } // if there is there is more than one option or allowvariableamount exists. then show the substep return (options > 1 || paymentMethod.allowvariableamount); } else { return false; } } }); enyo.kind({ name: 'OB.CashUp.PostPrintAndClose', kind: enyo.Object, getStepComponent: function (leftpanel$) { return leftpanel$.postPrintClose; }, getToolbarName: function () { return 'toolbarempty'; }, nextButtonI18NLabel: function () { return 'OBPOS_LblPostPrintClose'; }, allowNext: function () { this.model.get('cashUpReport').at(0).set('time', new Date()); return true; }, getSubstepsLength: function (model) { return 1; }, isSubstepAvailable: function (model, substep) { return true; } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global $ */ (function () { var PrintCashUp = function () { this.templatecashup = new OB.DS.HWResource(OB.OBPOSPointOfSale.Print.CashUpTemplate); }; PrintCashUp.prototype.print = function (report, sumary) { OB.POS.hwserver.print(this.templatecashup, { cashup: { report: report, summary: sumary } }); }; // Public object definition OB.OBPOSCashUp = OB.OBPOSCashUp || {}; OB.OBPOSCashUp.Print = OB.OBPOSCashUp.Print || {}; OB.OBPOSCashUp.Print.CashUp = PrintCashUp; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, Backbone, _, $, SynchronizationHelper */ OB.OBPOSCashUp = OB.OBPOSCashUp || {}; OB.OBPOSCashUp.Model = OB.OBPOSCashUp.Model || {}; OB.OBPOSCashUp.UI = OB.OBPOSCashUp.UI || {}; //Window model OB.OBPOSCashUp.Model.CashUp = OB.Model.TerminalWindowModel.extend({ models: [OB.Model.Order], defaults: { step: OB.DEC.Zero, allowedStep: OB.DEC.Zero, totalExpected: OB.DEC.Zero, totalCounted: OB.DEC.Zero, totalDifference: OB.DEC.Zero, pendingOrdersToProcess: false, otherInput: OB.DEC.Zero }, cashupstepsdefinition: ['OB.CashUp.StepPendingOrders', 'OB.CashUp.CashPayments', 'OB.CashUp.PaymentMethods', 'OB.CashUp.CashToKeep', 'OB.CashUp.PostPrintAndClose'], init: function () { //Check for orders wich are being processed in this moment. //cancel -> back to point of sale //Ok -> Continue closing without these orders var synchId = SynchronizationHelper.busyUntilFinishes('cashup.init'); var undf, me = this, newstep, expected = 0, totalStartings = 0, startings = [], cashUpReport, tempList = new Backbone.Collection(); //steps this.set('step', 1); this.set('substep', 0); // Create steps instances this.cashupsteps = []; _.each(this.cashupstepsdefinition, function (s) { newstep = enyo.createFromKind(s); newstep.model = this; this.cashupsteps.push(newstep); }, this); this.set('orderlist', new OB.Collection.OrderList()); this.set('paymentList', new Backbone.Collection()); OB.Dal.find(OB.Model.CashUp, { 'isbeingprocessed': 'N' }, function (cashUp) { OB.Dal.find(OB.Model.PaymentMethodCashUp, { 'cashup_id': cashUp.at(0).get('id'), '_orderByClause': 'name asc' }, function (payMthds) { //OB.Dal.find success _.each(OB.POS.modelterminal.get('payments'), function (payment, index) { expected = 0; var auxPay = payMthds.filter(function (payMthd) { return payMthd.get('paymentmethod_id') === payment.payment.id; })[0]; if (!auxPay) { //We cannot find this payment in local database, it must be a new payment method, we skip it. return; } auxPay.set('_id', payment.payment.searchKey); auxPay.set('isocode', payment.isocode); auxPay.set('paymentMethod', payment.paymentMethod); auxPay.set('id', payment.payment.id); OB.Dal.find(OB.Model.CashManagement, { 'cashup_id': cashUp.at(0).get('id'), 'paymentMethodId': payment.payment.id }, function (cashMgmts, args) { var cStartingCash = auxPay.get('startingCash'); var cTotalReturns = auxPay.get('totalReturns'); var cTotalSales = auxPay.get('totalSales'); var cTotalDeposits = _.reduce(cashMgmts.models, function (accum, trx) { if (trx.get('type') === 'deposit') { return OB.DEC.add(accum, trx.get('origAmount')); } else { return OB.DEC.sub(accum, trx.get('origAmount')); } }, 0); expected = OB.DEC.add(OB.DEC.add(cStartingCash, OB.DEC.sub(cTotalSales, cTotalReturns)), cTotalDeposits); var fromCurrencyId = auxPay.get('paymentMethod').currency; auxPay.set('expected', OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, expected)); auxPay.set('foreignExpected', expected); tempList.add(auxPay); if (args.index === OB.POS.modelterminal.get('payments').length - 1) { me.get('paymentList').reset(tempList.models); me.set('totalExpected', _.reduce(me.get('paymentList').models, function (total, model) { return OB.DEC.add(total, model.get('expected')); }, 0)); me.set('totalDifference', OB.DEC.sub(me.get('totalDifference'), me.get('totalExpected'))); me.setIgnoreStep3(); } }, null, { me: me, index: index }); }, this); SynchronizationHelper.finished(synchId, 'init'); }); }, this); this.convertExpected(); this.setIgnoreStep3(); this.set('cashUpReport', new Backbone.Collection()); OB.Dal.find(OB.Model.CashUp, { 'isbeingprocessed': 'N' }, function (cashUp) { cashUpReport = cashUp.at(0); OB.Dal.find(OB.Model.CashManagement, { 'cashup_id': cashUpReport.get('id'), 'type': 'deposit' }, function (cashMgmts) { cashUpReport.set('deposits', cashMgmts.models); cashUpReport.set('totalDeposits', _.reduce(cashMgmts.models, function (accum, trx) { return OB.DEC.add(accum, trx.get('origAmount')); }, 0)); }, this); OB.Dal.find(OB.Model.CashManagement, { 'cashup_id': cashUpReport.get('id'), 'type': 'drop' }, function (cashMgmts) { cashUpReport.set('drops', cashMgmts.models); cashUpReport.set('totalDrops', _.reduce(cashMgmts.models, function (accum, trx) { return OB.DEC.add(accum, trx.get('origAmount')); }, 0)); }, this); OB.Dal.find(OB.Model.TaxCashUp, { 'cashup_id': cashUpReport.get('id'), 'orderType': { operator: '!=', value: '1' }, '_orderByClause': 'name asc' }, function (taxcashups) { cashUpReport.set('salesTaxes', taxcashups.models); }, this); OB.Dal.find(OB.Model.TaxCashUp, { 'cashup_id': cashUpReport.get('id'), 'orderType': '1', '_orderByClause': 'name asc' }, function (taxcashups) { cashUpReport.set('returnsTaxes', taxcashups.models); }, this); OB.Dal.find(OB.Model.PaymentMethodCashUp, { 'cashup_id': cashUpReport.get('id'), '_orderByClause': 'name asc' }, function (payMthds) { //OB.Dal.find success cashUpReport.set('totalStartings', _.reduce(payMthds.models, function (accum, trx) { var fromCurrencyId = OB.MobileApp.model.paymentnames[trx.get('searchKey')].paymentMethod.currency; var cStartingCash = OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, trx.get('startingCash')); return OB.DEC.add(accum, cStartingCash); }, 0)); _.each(payMthds.models, function (p, index) { var auxPay = OB.POS.modelterminal.get('payments').filter(function (pay) { return pay.payment.id === p.get('paymentmethod_id'); })[0]; if (!auxPay) { //We cannot find this payment in local database, it must be a new payment method, we skip it. return; } var fromCurrencyId = auxPay.paymentMethod.currency; cashUpReport.get('deposits').push(new Backbone.Model({ origAmount: OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, p.get('totalSales')), amount: OB.DEC.add(0, p.get('totalSales')), description: p.get('name'), isocode: auxPay.isocode, rate: p.get('rate') })); var ccAmount1 = OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, p.get('totalSales')); cashUpReport.set('totalDeposits', OB.DEC.add(cashUpReport.get('totalDeposits'), ccAmount1)); cashUpReport.get('drops').push(new Backbone.Model({ origAmount: OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, p.get('totalReturns')), amount: OB.DEC.add(0, p.get('totalReturns')), description: p.get('name'), isocode: auxPay.isocode, rate: p.get('rate') })); var ccAmount2 = OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, p.get('totalReturns')); cashUpReport.set('totalDrops', OB.DEC.add(cashUpReport.get('totalDrops'), ccAmount2)); startings.push(new Backbone.Model({ origAmount: OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, p.get('startingCash')), amount: OB.DEC.add(0, p.get('startingCash')), description: 'Starting ' + p.get('name'), isocode: auxPay.isocode, rate: p.get('rate'), paymentId: p.get('paymentmethod_id') })); }, this); cashUpReport.set('startings', startings); //FIXME: We are not sure if other finds are done. OB.UTIL.HookManager.executeHooks('OBPOS_EditCashupReport', { cashUpReport: cashUpReport }, function (args) { me.get('cashUpReport').add(args.cashUpReport); }); }, this); }, this); this.get('paymentList').on('change:counted', function (mod) { mod.set('difference', OB.DEC.sub(mod.get('counted'), mod.get('expected'))); if (mod.get('foreignCounted') !== null && mod.get('foreignCounted') !== undf && mod.get('foreignExpected') !== null && mod.get('foreignExpected') !== undf) { mod.set('foreignDifference', OB.DEC.sub(mod.get('foreignCounted'), mod.get('foreignExpected'))); } this.set('totalCounted', _.reduce(this.get('paymentList').models, function (total, model) { return model.get('counted') ? OB.DEC.add(total, model.get('counted')) : total; }, 0), 0); if (mod.get('counted') === OB.DEC.Zero) { this.trigger('change:totalCounted'); } }, this); OB.Dal.find(OB.Model.Order, { hasbeenpaid: 'N' }, function (pendingOrderList, me) { var emptyOrders; // Detect empty orders and remove them from here emptyOrders = _.filter(pendingOrderList.models, function (pendingorder) { if (pendingorder && pendingorder.get('lines') && pendingorder.get('lines').length === 0) { return true; } }); _.each(emptyOrders, function (orderToRemove) { pendingOrderList.remove(orderToRemove); }); // Recalculate total properly for all pendingorders. pendingOrderList.each(function (pendingorder) { OB.DATA.OrderTaxes(pendingorder); pendingorder.calculateGross(); }); me.get('orderlist').reset(pendingOrderList.models); }, function (tx, error) { OB.UTIL.showError("OBDAL error: " + error); }, this); this.printCashUp = new OB.OBPOSCashUp.Print.CashUp(); }, //Previous next allowNext: function () { return this.cashupsteps[this.get('step') - 1].allowNext(); }, allowPrevious: function () { return this.get('step') > 1; }, setIgnoreStep3: function () { var result = null; _.each(this.get('paymentList').models, function (model) { if (model.get('paymentMethod').automatemovementtoother === false) { model.set('qtyToKeep', 0); if (result !== false) { result = true; } } else { //fix -> break result = false; return false; } }, this); this.set('ignoreStep3', result); }, showStep: function (leftpanel$) { var currentstep = this.get('step') - 1; var i; var stepcomponent; for (i = 0; i < this.cashupsteps.length; i++) { stepcomponent = this.cashupsteps[i].getStepComponent(leftpanel$); stepcomponent.setShowing(i === currentstep); if (i === currentstep) { stepcomponent.displayStep(this); } } }, getStepToolbar: function () { var currentstep = this.get('step') - 1; return this.cashupsteps[currentstep].getToolbarName(); }, nextButtonI18NLabel: function () { var currentstep = this.get('step') - 1; return this.cashupsteps[currentstep].nextButtonI18NLabel(); }, isFinishedWizard: function (step) { return step > this.cashupsteps.length; }, getSubstepsLength: function (step) { return this.cashupsteps[step - 1].getSubstepsLength(this); }, isSubstepAvailable: function (step, substep) { return this.cashupsteps[step - 1].isSubstepAvailable(this, substep); }, verifyStep: function (leftpanel$, callback) { var currentstep = this.get('step') - 1; var stepcomponent = this.cashupsteps[currentstep].getStepComponent(leftpanel$); if (stepcomponent.verifyStep) { return stepcomponent.verifyStep(this, callback); } else { callback(); } }, isPaymentMethodListVisible: function () { return this.get('step') === 2; }, // Step 2: logic, expected vs counted countAll: function () { this.get('paymentList').each(function (model) { model.set('foreignCounted', OB.DEC.add(0, model.get('foreignExpected'))); model.set('counted', OB.DEC.add(0, model.get('expected'))); }); }, //step 3 validateCashKeep: function (qty) { var unfd, result = { result: false, message: '' }; if (qty !== unfd && qty !== null && $.isNumeric(qty)) { if (this.get('paymentList').at(this.get('substep')).get('foreignCounted') >= qty) { result.result = true; result.message = ''; } else { result.result = false; result.message = OB.I18N.getLabel('OBPOS_MsgMoreThanCounted'); } } else { result.result = false; result.message = 'Not valid number to keep'; } if (!result.result) { this.get('paymentList').at(this.get('substep')).set('qtyToKeep', null); } return result; }, //Step 4 getCountCashSummary: function () { var synchId = SynchronizationHelper.busyUntilFinishes('getCountCashSummary'); var countCashSummary, counter, enumConcepts, enumSecondConcepts, enumSummarys, i, undf, model, value = OB.DEC.Zero, second = OB.DEC.Zero; countCashSummary = { expectedSummary: [], countedSummary: [], differenceSummary: [], qtyToKeepSummary: [], qtyToDepoSummary: [], totalCounted: this.get('totalCounted'), totalExpected: this.get('totalExpected'), totalDifference: this.get('totalDifference'), totalQtyToKeep: _.reduce(this.get('paymentList').models, function (total, model) { if (model.get('qtyToKeep')) { var cQtyToKeep = OB.UTIL.currency.toDefaultCurrency(model.get('paymentMethod').currency, model.get('qtyToKeep')); return OB.DEC.add(total, cQtyToKeep); } else { return total; } }, 0), totalQtyToDepo: _.reduce(this.get('paymentList').models, function (total, model) { if (model.get('qtyToKeep') !== null && model.get('qtyToKeep') !== undf && model.get('foreignCounted') !== null && model.get('foreignCounted') !== undf) { var qtyToDepo = OB.DEC.sub(model.get('foreignCounted'), model.get('qtyToKeep')); var cQtyToDepo = OB.UTIL.currency.toDefaultCurrency(model.get('paymentMethod').currency, qtyToDepo); return OB.DEC.add(total, cQtyToDepo); } else { return total; } }, 0) }; //First we fix the qty to keep for non-automated payment methods _.each(this.get('paymentList').models, function (model) { if (OB.UTIL.isNullOrUndefined(model.get('qtyToKeep'))) { model.set('qtyToKeep', model.get('counted')); } }); enumSummarys = ['expectedSummary', 'countedSummary', 'differenceSummary', 'qtyToKeepSummary', 'qtyToDepoSummary']; enumConcepts = ['expected', 'counted', 'difference', 'qtyToKeep', 'foreignCounted']; enumSecondConcepts = ['foreignExpected', 'foreignCounted', 'foreignDifference', 'qtyToKeep', 'qtyToKeep']; var sortedPays = _.sortBy(this.get('paymentList').models, function (p) { return p.get('name'); }); for (counter = 0; counter < 5; counter++) { for (i = 0; i < sortedPays.length; i++) { model = sortedPays[i]; if (!model.get(enumConcepts[counter])) { countCashSummary[enumSummarys[counter]].push(new Backbone.Model({ name: model.get('name'), value: 0, second: 0, isocode: '' })); } else { var fromCurrencyId = model.get('paymentMethod').currency; switch (enumSummarys[counter]) { case 'qtyToKeepSummary': if (model.get(enumSecondConcepts[counter]) !== null && model.get(enumSecondConcepts[counter]) !== undf) { value = OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, model.get(enumConcepts[counter])); second = model.get(enumSecondConcepts[counter]); } break; case 'qtyToDepoSummary': if (model.get(enumSecondConcepts[counter]) !== null && model.get(enumSecondConcepts[counter]) !== undf && model.get('rate') !== '1') { second = OB.DEC.sub(model.get(enumConcepts[counter]), model.get(enumSecondConcepts[counter])); } else { second = OB.DEC.Zero; } if (model.get(enumSecondConcepts[counter]) !== null && model.get(enumSecondConcepts[counter]) !== undf) { var baseAmount = OB.DEC.sub(model.get(enumConcepts[counter]), model.get(enumSecondConcepts[counter])); value = OB.UTIL.currency.toDefaultCurrency(fromCurrencyId, baseAmount); } else { value = OB.DEC.Zero; } break; default: value = model.get(enumConcepts[counter]); second = model.get(enumSecondConcepts[counter]); } countCashSummary[enumSummarys[counter]].push(new Backbone.Model({ name: model.get('name'), value: value, second: second, isocode: model.get('isocode') })); } } } SynchronizationHelper.finished(synchId, 'getCountCashSummary'); return countCashSummary; }, additionalProperties: [], propertyFunctions: [], processAndFinishCashUp: function () { var synchId = SynchronizationHelper.busyUntilFinishes('processAndFinishCashUp'); var objToSend = { posTerminal: OB.POS.modelterminal.get('terminal').id, id: OB.UTIL.get_UUID(), cashCloseInfo: [], cashUpDate: this.get('cashUpReport').at(0).get('time') }, server = new OB.DS.Process('org.openbravo.retail.posterminal.ProcessCashClose'), me = this, i; OB.UTIL.showLoading(true); OB.Dal.find(OB.Model.CashUp, { 'isbeingprocessed': 'N' }, function (cashUp) { objToSend = new Backbone.Model({ posTerminal: OB.POS.modelterminal.get('terminal').id, id: cashUp.at(0).get('id'), cashCloseInfo: [], cashUpDate: me.get('cashUpReport').at(0).get('time') }); for (i = 0; i < me.additionalProperties.length; i++) { objToSend.set(me.additionalProperties[i], me.propertyFunctions[i](OB.POS.modelterminal.get('terminal').id, cashUp.at(0))); } _.each(me.get('paymentList').models, function (curModel) { var cashCloseInfo = { expected: 0, difference: 0, paymentTypeId: 0, paymentMethod: {} }; cashCloseInfo.paymentTypeId = curModel.get('id'); cashCloseInfo.difference = curModel.get('difference'); cashCloseInfo.foreignDifference = curModel.get('foreignDifference'); cashCloseInfo.expected = curModel.get('expected'); cashCloseInfo.foreignExpected = curModel.get('foreignExpected'); curModel.get('paymentMethod').amountToKeep = curModel.get('qtyToKeep'); cashCloseInfo.paymentMethod = curModel.get('paymentMethod'); objToSend.get('cashCloseInfo').push(cashCloseInfo); }, this); objToSend.set('cashMgmtIds', []); OB.Dal.find(OB.Model.CashManagement, { 'cashup_id': cashUp.at(0).get('id') }, function (cashMgmts) { SynchronizationHelper.finished(synchId, 'processAndFinishCashUp'); _.each(cashMgmts.models, function (cashMgmt) { objToSend.get('cashMgmtIds').push(cashMgmt.get('id')); }); cashUp.at(0).set('userId', OB.POS.modelterminal.get('context').user.id); objToSend.set('userId', OB.POS.modelterminal.get('context').user.id); cashUp.at(0).set('objToSend', JSON.stringify(objToSend.toJSON())); cashUp.at(0).set('isbeingprocessed', 'Y'); OB.Dal.save(cashUp.at(0), null, null); if (OB.MobileApp.model.get('connectedToERP')) { if (OB.POS.modelterminal.hasPermission('OBPOS_print.cashup')) { me.printCashUp.print(me.get('cashUpReport').at(0), me.getCountCashSummary()); } OB.MobileApp.model.runSyncProcess(function () { OB.UTIL.calculateCurrentCash(); OB.UTIL.showLoading(false); me.set("finished", true); }); } else { OB.Dal.save(cashUp.at(0), function () { if (OB.POS.modelterminal.hasPermission('OBPOS_print.cashup')) { me.printCashUp.print(me.get('cashUpReport').at(0), me.getCountCashSummary()); } OB.UTIL.initCashUp(function () { OB.UTIL.calculateCurrentCash(); OB.UTIL.showLoading(false); me.set("finished", true); }); }, null); } }, null, null); }, null, this); }, convertExpected: function () { _.each(this.get('paymentList').models, function (model) { model.set('foreignExpected', model.get('expected')); var cExpected = OB.UTIL.currency.toDefaultCurrency(model.get('paymentMethod').currency, model.get('expected')); model.set('expected', cExpected); }, this); } }); /* ************************************************************************************ * Copyright (C) 2012-2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, _, $*/ enyo.kind({ name: 'OB.OBPOSCashUp.UI.Button', kind: 'OB.UI.ToolbarButton', disabled: true, events: { onChangeStep: '' }, init: function (model) { this.model = model; }, tap: function () { return OB.POS.hwserver.checkDrawer(function () { if (this.disabled) { return true; } this.doChangeStep(); }, this); }, initialize: function () { if (this.i18nLabel) { this.setContent(OB.I18N.getLabel(this.i18nLabel)); } } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.CancelButton', kind: 'OB.UI.ToolbarButton', i18nLabel: 'OBMOBC_LblCancel', disabled: true, events: { onCancelCashup: '' }, tap: function () { OB.POS.hwserver.checkDrawer(function () { this.doCancelCashup(); }, this); } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.RightToolbarImpl', kind: 'OB.UI.MultiColumn.Toolbar', buttons: [{ kind: 'OB.OBPOSCashUp.UI.Button', name: 'btnCashUp', span: 12, i18nLabel: 'OBPOS_LblCloseCash' }] }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.LeftToolbarImpl', kind: 'OB.UI.MultiColumn.Toolbar', published: { model: null }, buttons: [{ kind: 'OB.OBPOSCashUp.UI.Button', name: 'btnPrevious', i18nLabel: 'OBPOS_LblPrevStep', stepCount: -1, span: 4, handlers: { onDisablePreviousButton: 'disablePreviousButton' }, disablePreviousButton: function (inSender, inEvent) { this.setDisabled(inEvent.disable); if (this.hasClass('btn-over')) { this.removeClass('btn-over'); } } }, { kind: 'OB.OBPOSCashUp.UI.CancelButton', name: 'btnCancel', disabled: false, span: 4 }, { kind: 'OB.OBPOSCashUp.UI.Button', name: 'btnNext', i18nLabel: 'OBPOS_LblNextStep', stepCount: 1, span: 4, handlers: { onDisableNextButton: 'disableNextButton', onEnableNextButton: 'enableNextButton', synchronizing: 'disableButton', synchronized: 'enableButton' }, disableButton: function () { this.setDisabled(true); }, enableButton: function () { this.setDisabled(false); }, enableNextButton: function () { this.setDisabled(false); if (this.hasClass('btn-over')) { this.removeClass('btn-over'); } }, disableNextButton: function (inSender, inEvent) { this.setDisabled(inEvent.disable); if (this.hasClass('btn-over')) { this.removeClass('btn-over'); } } }] }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.CashUp', kind: 'OB.UI.WindowView', statics: { TitleExtensions: [], getTitleExtensions: function () { return _.reduce(this.TitleExtensions, function (memo, item) { return memo + ' ' + item(); }, ''); } }, windowmodel: OB.OBPOSCashUp.Model.CashUp, handlers: { onButtonOk: 'buttonOk', onTapRadio: 'tapRadio', onChangeStep: 'changeStep', onCancelCashup: 'cancelCashup', onCountAllOK: 'countAllOK', onLineEditCount: 'lineEditCount', onPaymentMethodKept: 'paymentMethodKept', onResetQtyToKeep: 'resetQtyToKeep', onHoldActiveCmd: 'holdActiveCmd' }, published: { model: null }, events: { onShowPopup: '', onChangeOption: '', onDisablePreviousButton: '', onDisableNextButton: '', onEnableNextButton: '' }, components: [{ kind: 'OB.UI.MultiColumn', name: 'cashupMultiColumn', leftToolbar: { kind: 'OB.OBPOSCashUp.UI.LeftToolbarImpl', name: 'leftToolbar', showMenu: false, showWindowsMenu: false }, rightToolbar: { kind: 'OB.OBPOSCashUp.UI.RightToolbarImpl', name: 'rightToolbar', showMenu: false, showWindowsMenu: false }, leftPanel: { name: 'cashupLeftPanel', components: [{ classes: 'span12', kind: 'OB.OBPOSCashUp.UI.ListPendingReceipts', name: 'listPendingReceipts' }, { classes: 'span12', kind: 'OB.OBPOSCashUp.UI.CashPayments', name: 'cashPayments', showing: false }, { classes: 'span12', kind: 'OB.OBPOSCashUp.UI.ListPaymentMethods', name: 'listPaymentMethods', showing: false }, { classes: 'span12', kind: 'OB.OBPOSCashUp.UI.CashToKeep', name: 'cashToKeep', showing: false }, { classes: 'span12', kind: 'OB.OBPOSCashUp.UI.PostPrintClose', name: 'postPrintClose', showing: false }] }, rightPanel: { classes: 'span12', name: 'cashupRightPanel', components: [{ kind: 'OB.OBPOSCashUp.UI.CashUpInfo', name: 'cashUpInfo' }, { kind: 'OB.OBPOSCashUp.UI.CashUpKeyboard', name: 'cashUpKeyboard' }] } }, { kind: 'OB.UI.ModalCancel', name: 'modalCancel' }, { kind: 'OB.OBPOSCashUp.UI.modalPendingToProcess', name: 'modalPendingToProcess' }], finalAction: function () { OB.POS.navigate('retail.pointofsale'); }, init: function () { var me = this; this.inherited(arguments); this.$.cashupMultiColumn.$.rightPanel.$.cashUpInfo.setModel(this.model); this.$.cashupMultiColumn.$.leftToolbar.$.leftToolbar.setModel(this.model); //step 0 this.model.on('change:pendingOrdersToProcess', function (model) { this.doShowPopup({ popup: 'modalprocessreceipts' }); }, this); // Pending Orders - Step 1 this.$.cashupMultiColumn.$.leftPanel.$.listPendingReceipts.setCollection(this.model.get('orderlist')); this.model.get('orderlist').on('all', function () { this.refreshButtons(); }, this); // Cash count - Step 2 this.$.cashupMultiColumn.$.leftPanel.$.listPaymentMethods.setCollection(this.model.get('paymentList')); this.$.cashupMultiColumn.$.leftPanel.$.listPaymentMethods.$.total.printAmount(this.model.get('totalExpected')); this.$.cashupMultiColumn.$.leftPanel.$.listPaymentMethods.$.difference.printAmount(OB.DEC.sub(0, this.model.get('totalExpected'))); this.model.on('change:totalExpected', function () { this.$.cashupMultiColumn.$.leftPanel.$.listPaymentMethods.$.total.printAmount(this.model.get('totalExpected')); }, this); this.model.on('change:totalCounted', function () { this.$.cashupMultiColumn.$.leftPanel.$.listPaymentMethods.$.difference.printAmount(OB.DEC.sub(this.model.get('totalCounted'), this.model.get('totalExpected'))); this.model.set("totalDifference", OB.DEC.sub(this.model.get('totalCounted'), this.model.get('totalExpected'))); this.waterfall('onAnyCounted'); this.refreshButtons(); }, this); // Cash to keep - Step 3. this.model.on('change:stepOfStep3', function (model) { this.$.cashupMultiColumn.$.leftPanel.$.cashToKeep.disableSelection(); this.$.cashupMultiColumn.$.leftPanel.$.cashToKeep.setPaymentToKeep(this.model.get('paymentList').at(this.model.get('stepOfStep3'))); this.refresh(); }, this); //FIXME:It is triggered only once, but it is not the best way to do it this.model.get('paymentList').on('reset', function () { this.model.get('paymentList').at(this.model.get('substep')).on('change:foreignCounted', function () { this.$.cashupMultiColumn.$.leftPanel.$.cashToKeep.$.formkeep.renderBody(this.model.get('paymentList').at(this.model.get('substep'))); }, this); }, this); // Cash Up Report - Step 4 //this data doesn't changes this.model.get('cashUpReport').on('reset', function (model) { this.$.cashupMultiColumn.$.leftPanel.$.postPrintClose.setModel(this.model.get('cashUpReport').at(0)); }); //This data changed when money is counted //difference is calculated after counted this.$.cashupMultiColumn.$.leftPanel.$.postPrintClose.setSummary(this.model.getCountCashSummary()); this.model.on('change:totalDifference', function (model) { this.$.cashupMultiColumn.$.leftPanel.$.postPrintClose.setSummary(this.model.getCountCashSummary()); }, this); //finished this.model.on('change:finished', function () { // this.model.messages ???? var content; var i; var messages = this.model.get('messages'); var next = this.model.get('next'), me = this; // Build the content of the dialog. if (messages && messages.length) { content = [{ content: OB.I18N.getLabel('OBPOS_FinishCloseDialog') }, { allowHtml: true, content: ' ' }]; for (i = 0; i < messages.length; i++) { content.push({ content: OB.UTIL.decodeXMLComponent(messages[i]) }); } } else { content = OB.I18N.getLabel('OBPOS_FinishCloseDialog'); } OB.UTIL.HookManager.executeHooks('OBPOS_AfterCashUpSent', {}, function () { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_LblGoodjob'), content, [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { me.finalAction(); return true; } }], { autoDismiss: false }); }); }, this); //finishedWrongly this.model.on('change:finishedWrongly', function (model) { var message = ""; if (model.get('errorMessage')) { message = OB.I18N.getLabel(model.get('errorMessage'), [model.get('errorDetail')]); } else { message = OB.I18N.getLabel('OBPOS_CashUpWrongly'); } var errorNoNavigateToInitialScreen = model.get('errorNoNavigateToInitialScreen'); if (errorNoNavigateToInitialScreen && errorNoNavigateToInitialScreen === 'true') { model.set('cashUpSent', false); model.set("finishedWrongly", false); OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_CashUpWronglyHeader'), message, [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { me.waterfall('onEnableNextButton'); return true; } }]); } else { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_CashUpWronglyHeader'), message, [{ label: OB.I18N.getLabel('OBMOBC_LblOk'), isConfirmButton: true, action: function () { OB.POS.navigate('retail.pointofsale'); return true; } }]); } }, this); this.refreshButtons(); }, refreshButtons: function () { // Disable/Enable buttons this.waterfall('onDisablePreviousButton', { disable: !this.model.allowPrevious() }); this.waterfall('onDisableNextButton', { disable: !this.model.allowNext() }); // Show step keyboard this.$.cashupMultiColumn.$.rightPanel.$.cashUpKeyboard.showToolbar(this.model.getStepToolbar()); }, refresh: function () { // Show step panel this.model.showStep(this.$.cashupMultiColumn.$.leftPanel.$); // Refresh buttons this.refreshButtons(); // Show button label. var nextButtonI18NLabel = this.model.nextButtonI18NLabel(); this.$.cashupMultiColumn.$.leftToolbar.$.leftToolbar.$.toolbar.getComponents()[2].$.theButton.$.btnNext.setContent(OB.I18N.getLabel(nextButtonI18NLabel)); }, changeStep: function (inSender, inEvent) { var direction = inEvent.originator.stepCount; var me = this; if (direction > 0) { // Check with the step if can go next. this.model.verifyStep(this.$.cashupMultiColumn.$.leftPanel.$, function () { me.moveStep(direction); }); } else { this.moveStep(direction); } }, cancelCashup: function (inSender, inEvent) { OB.POS.navigate('retail.pointofsale'); }, moveStep: function (direction) { // direction can be -1 or +1 // allways moving substep by substep var nextstep = this.model.get('step'); var nextsubstep = this.model.get('substep') + direction; if (nextstep <= 0) { // error. go to the begining this.model.set('step', 1); this.model.set('substep', -1); this.moveStep(1); } else if (this.model.isFinishedWizard(nextstep)) { //send cash up to the server if it has not been sent yet if (this.model.get('cashUpSent')) { return true; } this.$.cashupMultiColumn.$.leftToolbar.$.leftToolbar.$.toolbar.getComponents()[2].$.theButton.$.btnNext.setDisabled(true); this.model.set('cashUpSent', true); this.model.processAndFinishCashUp(); } else if (nextsubstep < 0) { // jump to previous step this.model.set('step', nextstep - 1); this.model.set('substep', this.model.getSubstepsLength(nextstep - 1)); this.moveStep(-1); } else if (nextsubstep >= this.model.getSubstepsLength(nextstep)) { // jump to next step this.model.set('step', nextstep + 1); this.model.set('substep', -1); this.moveStep(1); } else if (this.model.isSubstepAvailable(nextstep, nextsubstep)) { // go to step this.model.set('step', nextstep); this.model.set('substep', nextsubstep); this.refresh(); } else { // move again this.model.set('step', nextstep); this.model.set('substep', nextsubstep); this.moveStep(direction); } }, countAllOK: function (inSender, inEvent) { this.model.countAll(); this.refreshButtons(); }, lineEditCount: function (inSender, inEvent) { this.waterfall('onShowColumn', { colNum: 1 }); this.$.cashupMultiColumn.$.rightPanel.$.cashUpKeyboard.setStatus(inEvent.originator.model.get('_id')); }, paymentMethodKept: function (inSender, inEvent) { var validationResult = this.model.validateCashKeep(inEvent.qtyToKeep); if (validationResult.result) { this.model.get('paymentList').at(this.model.get('substep')).set('qtyToKeep', inEvent.qtyToKeep); } else { OB.UTIL.showWarning(validationResult.message); } this.refreshButtons(); this.$.cashupMultiColumn.$.rightPanel.$.cashUpKeyboard.setStatus(inEvent.name); }, resetQtyToKeep: function (inSender, inEvent) { this.model.get('paymentList').at(this.model.get('substep')).set('qtyToKeep', null); this.refreshButtons(); }, holdActiveCmd: function (inSender, inEvent) { this.waterfall('onChangeOption', { cmd: inEvent.cmd }); } }); OB.POS.registerWindow({ windowClass: OB.OBPOSCashUp.UI.CashUp, route: 'retail.cashup', online: false, menuPosition: 20, menuI18NLabel: 'OBPOS_LblCloseCash', permission: 'OBPOS_retail.cashup', approvalType: 'OBPOS_approval.cashup' }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, _ */ enyo.kind({ name: 'OB.OBPOSCashUp.UI.CashUpKeyboard', published: { payments: null }, kind: 'OB.UI.Keyboard', sideBarEnabled: true, init: function (model) { this.model = model; var me = this; this.inherited(arguments); this.showSidepad('sidecashup'); this.addCommand('+', { stateless: true, action: function (keyboard, txt) { var t = keyboard.$.editbox.getContent(); keyboard.$.editbox.setContent(t + '+'); } }); this.addCommand('-', { stateless: true, action: function (keyboard, txt) { var t = keyboard.$.editbox.getContent(); keyboard.$.editbox.setContent(t + '-'); } }); this.addToolbar({ name: 'toolbarempty', buttons: [] }); this.addToolbar({ name: 'toolbarother', buttons: [{ command: 'allowvariableamount', definition: { holdActive: true, action: function (keyboard, amt) { me.model.set('otherInput', OB.I18N.parseNumber(amt)); } }, label: OB.I18N.getLabel('OBPOS_LblOther') }] }); // CashPayments step. this.addToolbar({ name: 'toolbarcashpayments', buttons: [{ command: 'cashpayments', i18nLabel: 'OBPOS_SetQuantity', definition: { action: function (keyboard, amt) { keyboard.model.trigger('action:addUnitToCollection', { coin: keyboard.selectedCoin, amount: parseInt(amt, 10) }); } } }, { command: 'resetallcoins', i18nLabel: 'OBPOS_ResetAllCoins', stateless: true, definition: { stateless: true, action: function (keyboard, amt) { keyboard.model.trigger('action:resetAllCoins'); } } }, { command: 'opendrawer', i18nLabel: 'OBPOS_OpenDrawer', stateless: true, definition: { stateless: true, action: function (keyboard, amt) { OB.UTIL.Approval.requestApproval( me.model, 'OBPOS_approval.opendrawer.cashup', function (approved, supervisor, approvalType) { if (approved) { OB.POS.hwserver.openCheckDrawer(false, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerCount); } }); } } }] }); this.addCommand('coin', { action: function (keyboard, txt) { keyboard.model.trigger('action:SelectCoin', { keyboard: keyboard, txt: txt }); } }); this.model.on('action:SetStatusCoin', function () { this.setStatus('coin'); }, this); this.model.on('action:ResetStatusCoin', function () { this.setStatus(''); }, this); this.showToolbar('toolbarempty'); this.model.get('paymentList').on('reset', function () { var buttons = []; this.model.get('paymentList').each(function (payment) { if (!payment.get('paymentMethod').iscash || !payment.get('paymentMethod').countcash) { buttons.push({ command: payment.get('_id'), definition: { action: function (keyboard, amt) { var convAmt = OB.I18N.parseNumber(amt); payment.set('foreignCounted', OB.DEC.add(0, convAmt)); payment.set('counted', OB.DEC.mul(convAmt, payment.get('rate'))); } }, label: payment.get('name') }); } }, this); if (this.model.get('paymentList').length !== 0) { this.addToolbar({ name: 'toolbarcountcash', buttons: buttons }); } }, this); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global OB, enyo, */ enyo.kind({ name: 'OB.OBPOSCashUp.UI.CashUpInfo', published: { model: null }, components: [{ style: 'position: relative; background: #363636; color: white; height: 200px; margin: 5px; padding: 5px', components: [{ //clock here kind: 'OB.UI.Clock', classes: 'pos-clock' }, { // process info style: 'padding: 5px', initialize: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblCashUpProcess')); } }, { style: 'padding: 3px', initialize: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStep1')); } }, { style: 'padding: 3px', initialize: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStep2')); } }, { style: 'padding: 3px', initialize: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStep3')); } }, { style: 'padding: 3px', initialize: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStep4')); } }] }] }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.OBPOSCashUp.UI.ButtonVoid', kind: 'OB.UI.SmallButton', classes: 'btnlink-gray', style: 'min-width: 70px; margin: 2px 5px 2px 5px;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_Delete')); } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.RenderPendingReceiptLine', events: { onVoidOrder: '' }, components: [{ classes: 'display: table-row; height: 42px;', components: [{ name: 'orderDate', style: 'display: table-cell; vertical-align: middle; padding: 2px 5px 2px 5px; border-bottom: 1px solid #cccccc; width: 10%;' }, { name: 'documentNo', style: 'display: table-cell; vertical-align: middle; padding: 2px 5px 2px 5px; border-bottom: 1px solid #cccccc; width: 20%;' }, { name: 'bp', style: 'display: table-cell; vertical-align: middle; padding: 2px 5px 2px 5px; border-bottom: 1px solid #cccccc; width: 39%;' }, { style: 'display: table-cell; vertical-align: middle; padding: 2px 5px 2px 5px; border-bottom: 1px solid #cccccc; width: 15%; text-align:right;', components: [{ //FIXME: should be part of a

tag: 'strong', components: [{ name: 'printGross' }] }] }, { style: 'display: table-cell; vertical-align: middle; padding: 2px 5px 2px 5px; border-bottom: 1px solid #cccccc; width: 15%;', components: [{ name: 'buttonVoid', kind: 'OB.OBPOSCashUp.UI.ButtonVoid', ontap: 'voidOrder' }] }, { style: 'clear: both;' }] }], create: function () { this.inherited(arguments); this.$.orderDate.setContent(OB.I18N.formatHour(this.model.get('orderDate'))); this.$.documentNo.setContent(this.model.get('documentNo')); this.$.bp.setContent(this.model.get('bp').get('_identifier')); this.$.printGross.setContent(this.model.printGross()); }, voidOrder: function (inSender, inEvent) { this.doVoidOrder(); } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.ListPendingReceipts', published: { collection: null }, handlers: { onVoidOrder: 'voidOrder' }, components: [{ classes: 'tab-pane', components: [{ style: 'overflow:auto; height: 500px; margin: 5px', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'padding: 10px; border-bottom: 1px solid #cccccc; text-align:center;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStep1of4') + OB.OBPOSCashUp.UI.CashUp.getTitleExtensions()); } }] }] }, { name: 'rowDeleteAll', classes: 'row-fluid', components: [{ style: 'span12; padding: 2px 5px 2px 5px; border-bottom: 1px solid #cccccc;', components: [{ name: 'btnDeleteAll', kind: 'OB.UI.SmallButton', classes: 'btnlink-gray', style: 'float: right; min-width: 70px; margin: 2px 5px 2px 5px;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_DeleteAll')); }, ontap: 'voidAllOrders' }, { style: 'clear: both;' }] }] }, { classes: 'row-fluid', components: [{ style: 'span12', components: [{ classes: 'row-fluid', components: [{ name: 'pendingReceiptList', kind: 'OB.UI.Table', renderLine: 'OB.OBPOSCashUp.UI.RenderPendingReceiptLine', renderEmpty: 'OB.UI.RenderEmpty', listStyle: 'list' }] }] }] }] }] }] }], init: function (model) { this.model = model; }, collectionChanged: function (oldCol) { this.$.pendingReceiptList.setCollection(this.collection); if (oldCol) { oldCol.off('remove add reset', this.receiptsChanged); } this.collection.on('remove add reset', this.receiptsChanged, this); }, receiptsChanged: function () { if (this.collection.length === 0) { this.$.rowDeleteAll.hide(); } else { this.$.rowDeleteAll.show(); } }, voidOrder: function (inSender, inEvent) { var me = this, model = inEvent.originator.model; OB.UTIL.Approval.requestApproval( this.model, 'OBPOS_approval.cashupremovereceipts', function (approved, supervisor, approvalType) { if (approved) { // approved so remove the entry OB.Dal.remove(model, function () { me.collection.remove(model); }, OB.UTIL.showError); } }); }, voidAllOrders: function (inSender, inEvent) { var me = this; function removeOneModel(collection, model) { OB.Dal.remove(model, function () { collection.remove(model); }, OB.UTIL.showError); } OB.UTIL.Approval.requestApproval( this.model, 'OBPOS_approval.cashupremovereceipts', function (approved, supervisor, approvalType) { if (approved) { var models = me.collection.toArray(); var i; for (i = 0; i < models.length; i++) { removeOneModel(me.collection, models[i]); } } }); }, displayStep: function (model) { // this function is invoked when displayed. } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone, enyo, _ */ enyo.kind({ name: 'OB.OBPOSCashUp.UI.RenderCashPaymentsLine', statics: { getLegacyCoins: function () { return new Backbone.Collection([{ amount: 0.01, backcolor: '#f3bc9e' }, { amount: 0.02, backcolor: '#f3bc9e' }, { amount: 0.05, backcolor: '#f3bc9e' }, { amount: 0.10, backcolor: '#f9e487' }, { amount: 0.20, backcolor: '#f9e487' }, { amount: 0.50, backcolor: '#f9e487' }, { amount: 1, backcolor: '#e4e0e3', bordercolor: '#f9e487' }, { amount: 2, backcolor: '#f9e487', bordercolor: '#e4e0e3' }, { amount: 5, backcolor: '#bccdc5' }, { amount: 10, backcolor: '#e9b7c3' }, { amount: 20, backcolor: '#bac3de' }, { amount: 50, backcolor: '#f9bb92' }]); } }, events: { onLineEditCash: '', onAddUnit: '', onSubUnit: '' }, components: [{ components: [{ classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ name: 'coin', kind: 'OB.UI.MediumButton', classes: 'btnlink-gray btnlink-cashup-edit', ontap: 'addUnit' }, { style: 'display:inline-block; width: 10%' }, { name: 'qtyminus', kind: 'OB.UI.SmallButton', style: 'width: 40px;', classes: 'btnlink-gray btnlink-cashup-edit', content: '-', ontap: 'subUnit' }, { name: 'numberOfCoins', kind: 'OB.UI.MediumButton', classes: 'btnlink-gray btnlink-cashup-edit', style: 'background-color: white; border: 1px solid lightgray; border-radius: 3px;', ontap: 'lineEdit' }, { name: 'qtyplus', kind: 'OB.UI.SmallButton', style: 'width: 40px;', classes: 'btnlink-gray btnlink-cashup-edit', content: '+', ontap: 'addUnit' }, { style: 'display:inline-block; width: 10%' }, { name: 'total', style: 'display:inline-block;padding: 10px 0px 10px 0px; width: 15%; text-align: center;' }] }] }] }], create: function () { this.inherited(arguments); this.$.coin.setContent(OB.I18N.formatCurrency(this.model.get('coinValue'))); var style = 'float: left; width: 15%; text-align: center;'; if (this.model.get('bordercolor')) { style += ' border:10px solid ' + this.model.get('bordercolor') + ';'; } style += ' background-color:' + this.model.get('backcolor') + ';'; this.$.coin.addStyles(style); this.$.numberOfCoins.setContent(this.model.get('numberOfCoins')); this.$.total.setContent(OB.I18N.formatCurrency(OB.DEC.add(0, this.model.get('totalAmount')))); }, render: function () { var udfn, counted, foreignCounted; this.inherited(arguments); counted = this.model.get('numberOfCoins'); if (counted !== null && counted !== udfn) { this.$.numberOfCoins.setContent(counted); this.$.total.setContent(OB.I18N.formatCurrency(OB.DEC.add(0, this.model.get('totalAmount')))); } }, lineEdit: function () { this.doLineEditCash(); }, addUnit: function () { this.doAddUnit(); }, subUnit: function () { this.doSubUnit(); } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.RenderTotal', tag: 'span', style: 'font-weight: bold;', printAmount: function (value) { this.setContent(OB.I18N.formatCurrency(value)); this.applyStyle('color', OB.DEC.compare(value) < 0 ? 'red' : 'black'); } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.CashPayments', handlers: { onAddUnit: 'addUnit', onSubUnit: 'subUnit', onLineEditCash: 'lineEditCash' }, components: [{ classes: 'tab-pane', components: [{ style: 'margin: 5px', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'padding: 10px; border-bottom: 1px solid #cccccc; text-align:center;', name: 'title' }] }] }, { style: 'background-color: #ffffff; color: black;', components: [{ components: [{ classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ style: 'padding: 10px 20px 10px 10px; float: left; width: 30%', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_CoinType')); } }, { style: 'padding: 10px 20px 10px 0px; float: left; width: 30%', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_NumberOfItems')); } }, { style: 'padding: 10px 0px 10px 0px; float: left; width: 25%', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_AmountOfCash')); } }] }] }, { style: 'overflow:auto; height: 454px;', components: [{ name: 'paymentsList', kind: 'OB.UI.Table', renderLine: 'OB.OBPOSCashUp.UI.RenderCashPaymentsLine', renderEmpty: 'OB.UI.RenderEmpty', listStyle: 'list' }, { name: 'renderLoading', style: 'border-bottom: 1px solid #cccccc; padding: 20px; text-align: center; font-weight: bold; font-size: 30px; color: #cccccc', showing: false, initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblLoading')); } }] }, { classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc; border-top: 1px solid #cccccc; height: 70px;', components: [{ style: 'float:left; display: table-row;', components: [{ name: 'totalLbl', style: 'padding: 10px 20px 10px 10px; display: table-cell;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_ReceiptTotal')); } }, { style: 'padding: 10px 20px 10px 0px; display: table-cell;', components: [{ name: 'total', kind: 'OB.OBPOSCashUp.UI.RenderTotal' }] }] }, { style: 'float:left; display: table-row;', components: [{ name: 'countedLbl', style: 'padding: 10px 20px 10px 10px; display: table-cell;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_Counted')); } }, { style: 'padding: 10px 5px 10px 0px; display: table-cell;', components: [{ name: 'counted', kind: 'OB.OBPOSCashUp.UI.RenderTotal' }] }] }, { style: 'float:left; display: table-row;', components: [{ name: 'differenceLbl', style: 'padding: 10px 20px 10px 10px; display: table-cell;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_Remaining')); } }, { style: 'padding: 10px 5px 10px 0px; display: table-cell;', components: [{ name: 'difference', kind: 'OB.OBPOSCashUp.UI.RenderTotal' }] }] }] }] }] }] }] }] }] }], init: function (model) { this.inherited(arguments); this.model = model; this.model.on('action:resetAllCoins', function (args) { this.resetAllCoins(); }, this); this.model.on('action:SelectCoin', function (args) { this.selectCoin(args); }, this); }, printTotals: function () { this.$.counted.printAmount(this.payment.get('foreignCounted')); this.$.difference.printAmount(this.payment.get('foreignDifference')); }, lineEditCash: function (inSender, inEvent) { this.setCoinsStatus(inEvent.originator); }, setCoinsStatus: function (originator) { // reset previous status if (this.originator && this.originator.$.numberOfCoins) { this.originator.$.numberOfCoins.applyStyle('background-color', 'white'); } // set new status if (originator && originator !== this.originator) { this.originator = originator; this.originator.$.numberOfCoins.applyStyle('background-color', '#6CB33F'); this.model.trigger('action:SetStatusCoin'); } else { this.originator = null; this.model.trigger('action:ResetStatusCoin'); } }, selectCoin: function (args) { // args -> {keyboard: keyboard, txt: txt}); if (this.originator) { // This function also resets the status this.addUnitToCollection(this.originator.model.get('coinValue'), parseInt(args.txt, 10)); } }, addUnit: function (inSender, inEvent) { this.addUnitToCollection(inEvent.originator.model.get('coinValue'), 'add'); }, subUnit: function (inSender, inEvent) { this.addUnitToCollection(inEvent.originator.model.get('coinValue'), 'sub'); }, addUnitToCollection: function (coinValue, amount) { var collection = this.$.paymentsList.collection; var lAmount, resetAmt, newAmount; if (amount === 'add') { lAmount = 1; resetAmt = false; } else if (amount === 'sub') { lAmount = -1; resetAmt = false; } else { lAmount = amount; resetAmt = true; } var totalCounted = 0; collection.each(function (coin) { if (coin.get('coinValue') === coinValue) { if (resetAmt) { newAmount = lAmount; } else { newAmount = coin.get('numberOfCoins') + lAmount; } if (newAmount >= 0) { coin.set('numberOfCoins', newAmount); } } coin.set('totalAmount', OB.DEC.mul(coin.get('numberOfCoins'), coin.get('coinValue'))); totalCounted += coin.get('totalAmount'); }); this.payment.set('foreignCounted', totalCounted); var cTotalCounted = OB.UTIL.currency.toDefaultCurrency(this.payment.attributes.paymentMethod.currency, totalCounted); this.payment.set('counted', cTotalCounted); this.payment.set('foreignDifference', OB.DEC.sub(totalCounted, this.payment.get('foreignExpected'))); this.printTotals(); this.setCoinsStatus(null); }, resetAllCoins: function () { var collection = this.$.paymentsList.collection; collection.each(function (coin) { coin.set('numberOfCoins', 0); coin.set('totalAmount', 0); }); this.payment.set('foreignCounted', 0); this.payment.set('counted', 0); this.payment.set('foreignDifference', OB.DEC.sub(0, this.payment.get('foreignExpected'))); this.printTotals(); this.setCoinsStatus(null); }, initPaymentToCount: function (payment) { this.payment = payment; this.$.title.setContent(OB.I18N.getLabel('OBPOS_CashPaymentsTitle', [payment.get('name')]) + OB.OBPOSCashUp.UI.CashUp.getTitleExtensions()); this.$.total.printAmount(this.payment.get('foreignExpected')); if (!this.payment.get('coinsCollection')) { this.$.paymentsList.hide(); this.$.renderLoading.show(); // First empty collection before loading. this.$.paymentsList.setCollection(new Backbone.Collection()); this.payment.set('foreignCounted', 0); this.payment.set('counted', 0); this.payment.set('foreignDifference', OB.DEC.sub(0, this.payment.get('foreignExpected'))); this.printTotals(); this.setCoinsStatus(null); // Call to draw currencies. var currencyId = payment.get('paymentMethod').currency; var me = this; OB.Dal.find(OB.Model.CurrencyPanel, { currency: currencyId, _orderByClause: 'line' }, function (coins) { var coinCol = new Backbone.Collection(); if (coins.length === 0 && payment.get('paymentMethod').currency === '102') { coins = OB.OBPOSCashUp.UI.RenderCashPaymentsLine.getLegacyCoins(); } coins.each(function (coin) { var coinModel = new Backbone.Model(); coinModel.set('numberOfCoins', 0); coinModel.set('totalAmount', 0); coinModel.set('coinValue', coin.get('amount')); coinModel.set('backcolor', coin.get('backcolor')); coinModel.set('bordercolor', coin.get('bordercolor')); coinCol.add(coinModel); }); me.payment.set('coinsCollection', coinCol); me.$.paymentsList.setCollection(coinCol); me.payment.set('foreignCounted', 0); me.payment.set('counted', 0); me.payment.set('foreignDifference', OB.DEC.sub(0, me.payment.get('foreignExpected'))); me.printTotals(); me.setCoinsStatus(null); me.$.renderLoading.hide(); me.$.paymentsList.show(); }); } else { this.$.paymentsList.setCollection(this.payment.get('coinsCollection')); this.printTotals(); this.setCoinsStatus(null); } }, displayStep: function (model) { var payment = model.get('paymentList').at(model.get('substep')); // this function is invoked when displayed. this.initPaymentToCount(payment); // Open drawer if allow open drawer. Already a cash method. if (payment.get('paymentMethod').allowopendrawer) { OB.POS.hwserver.openDrawer(false, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerCount); } } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ enyo.kind({ name: 'OB.OBPOSCashUp.UI.RenderPaymentsLine', events: { onLineEditCount: '' }, components: [{ components: [{ classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ style: 'float:left; display: table; width: 50%', components: [{ name: 'name', style: 'padding: 10px 20px 10px 10px; display: table-cell; width: 40%;' }, { name: 'foreignExpected', style: 'padding: 10px 10px 10px 0px; text-align:right; display: table-cell; width: 35%;' }, { name: 'expected', style: 'padding: 10px 10px 10px 0px; text-align:right; display: table-cell; width: 35%;' }] }, { style: 'float:left; display: table; width: 50%;', components: [{ style: 'display: table-cell; width: 15%;', components: [{ name: 'buttonEdit', kind: 'OB.UI.SmallButton', classes: 'btnlink-orange btnlink-cashup-edit btn-icon-small btn-icon-edit', ontap: 'lineEdit' }] }, { style: 'display: table-cell; width: 15%;', components: [{ name: 'buttonOk', kind: 'OB.UI.SmallButton', classes: 'btnlink-green btnlink-cashup-ok btn-icon-small btn-icon-check', ontap: 'lineOK' }] }, { name: 'foreignCounted', style: 'display: table-cell; padding: 10px 10px 10px 0px; text-align:right; width: 35%;', content: '' }, { name: 'counted', style: 'display: table-cell; padding: 10px 10px 10px 0px; text-align:right; width: 35%;', showing: false }] }] }] }] }], create: function () { this.inherited(arguments); this.$.name.setContent(this.model.get('name')); if (this.model.get('rate') && this.model.get('rate') !== 1) { this.$.foreignExpected.setContent('(' + OB.I18N.formatCurrency(this.model.get('foreignExpected')) + ' ' + this.model.get('isocode') + ')'); this.$.foreignExpected.show(); } this.$.expected.setContent(OB.I18N.formatCurrency(OB.DEC.add(0, this.model.get('expected')))); }, render: function () { var udfn, counted, foreignCounted; this.inherited(arguments); counted = this.model.get('counted'); if (counted !== null && counted !== udfn) { this.$.counted.setContent(OB.I18N.formatCurrency(OB.DEC.add(0, counted))); this.$.counted.show(); if (this.model.get('rate') && this.model.get('rate') !== 1) { this.$.foreignCounted.setContent('(' + OB.I18N.formatCurrency(this.model.get('foreignCounted')) + ' ' + this.model.get('isocode') + ')'); } this.$.buttonOk.hide(); } this.$.buttonEdit.setDisabled(this.model.get('paymentMethod').iscash && this.model.get('paymentMethod').countcash); }, lineEdit: function () { this.doLineEditCount(); }, lineOK: function (inSender, inEvent) { this.model.set('counted', this.model.get('expected')); this.model.set('foreignCounted', this.model.get('foreignExpected')); } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.ListPaymentMethods', handlers: { onAnyCounted: 'anyCounted' }, events: { onCountAllOK: '' }, components: [{ classes: 'tab-pane', components: [{ style: 'overflow:auto; height: 500px; margin: 5px', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'padding: 10px; border-bottom: 1px solid #cccccc; text-align:center;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStep2of4') + OB.OBPOSCashUp.UI.CashUp.getTitleExtensions()); } }] }] }, { style: 'background-color: #ffffff; color: black;', components: [{ components: [{ classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ style: 'float: left; display:table; width: 50%; ', components: [{ style: 'padding: 10px 10px 10px 10px; display: table-cell; width: 60%;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblPaymentMethod')); } }, { style: 'padding: 10px 10px 10px 0px; display: table-cell; width: 40%; text-align:right;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblExpected')); } }] }, { style: 'float: left; display:table; width: 50%; ', components: [{ style: 'padding: 10px 10px 10px 0px; display: table-cell; width: 100%; text-align: right;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblCounted')); } }] }] }] }, { name: 'paymentsList', kind: 'OB.UI.Table', renderLine: 'OB.OBPOSCashUp.UI.RenderPaymentsLine', renderEmpty: 'OB.UI.RenderEmpty', listStyle: 'list' }, { components: [{ classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ style: 'float: left; display:table; width: 50%; ', components: [{ style: 'display:table-cell; width: 100%;', content: ' ', allowHtml: true }] }, { style: 'float: left; display:table; width: 50%; ', components: [{ style: 'display:table-cell; width: 50px; padding: 10px 10px 10px 0px;' }, { style: 'display:table-cell; width: 15%;', components: [{ name: 'buttonAllOk', kind: 'OB.UI.SmallButton', classes: 'btnlink-green btnlink-cashup-ok btn-icon-small btn-icon-check', ontap: 'doCountAllOK' }] }, { // This element has been intentionally created empty. }] }] }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', style: 'border-bottom: 1px solid #cccccc;', components: [{ style: 'float: left; display:table; width: 50%; ', components: [{ name: 'totalLbl', style: 'padding: 10px 10px 10px 10px; display: table-cell; width: 60%;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_ReceiptTotal')); } }, { style: 'padding: 10px 10px 10px 0px; display: table-cell; width: 40%; text-align:right;', components: [{ name: 'total', kind: 'OB.OBPOSCashUp.UI.RenderTotal' }] }] }, { components: [{ style: 'float: left; display:table; width: 50%; ', components: [{ style: 'padding: 10px 10px 10px 0px; display: table-cell; width: 100%; text-align: right;', name: 'difference', kind: 'OB.OBPOSCashUp.UI.RenderTotal' }] }] }] }] }] }] }] }] }] }], setCollection: function (col) { this.$.paymentsList.setCollection(col); }, anyCounted: function () { this.$.buttonAllOk.applyStyle('visibility', 'hidden'); //hiding in this way to keep the space }, displayStep: function (model) { // this function is invoked when displayed. var opendrawer = model.get('paymentList').any(function (payment) { var paymentmethod = payment.get('paymentMethod'); return paymentmethod.iscash && !paymentmethod.countcash && paymentmethod.allowopendrawer; }); if (opendrawer) { OB.POS.hwserver.openDrawer(false, OB.MobileApp.model.get('permissions').OBPOS_timeAllowedDrawerCount); } }, verifyStep: function (model, callback) { // this function is invoked when going next, invokes callback to continue // do not invoke callback to cancel going next. var firstdiff = model.get('paymentList').find(function (payment) { return payment.get('difference') !== 0; }); if (firstdiff) { // there is at leat 1 payment with differences OB.UTIL.Approval.requestApproval( model, 'OBPOS_approval.cashupdifferences', function (approved, supervisor, approvalType) { if (approved) { callback(); } }); } else { callback(); } } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.OBPOSCashUp.UI.CashToKeepRadioButton', kind: 'OB.UI.RadioButton', style: 'padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 40px; margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px;', components: [{ name: 'lbl', style: 'padding: 5px 0px 0px 0px;' }], events: { onPaymentMethodKept: '' }, tap: function () { this.inherited(arguments); this.doPaymentMethodKept({ qtyToKeep: this.qtyToKeep, name: this.name }); }, render: function (content) { this.$.lbl.setContent(content); }, setQtyToKeep: function (qty) { this.qtyToKeep = qty; }, initComponents: function () { this.inherited(arguments); if (this.i18nLabel) { this.$.lbl.setContent(OB.I18N.getLabel(this.i18nLabel)); return; } if (this.label) { this.$.lbl.setContent(this.label); } } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.KeepDetails', style: 'background-color: #ffffff; color: black;', events: { onResetQtyToKeep: '' }, init: function (model) { this.model = model; var me = this; this.model.on('change:otherInput', function () { me.$.variableInput.setContent(me.model.get('otherInput')); me.$.allowvariableamount.setQtyToKeep(me.model.get('otherInput')); me.$.allowvariableamount.tap(); }, this); }, components: [{ kind: "Group", name: 'RadioGroup', classes: 'btn-group', components: [{ name: 'keepfixedamount', showing: false, kind: 'OB.OBPOSCashUp.UI.CashToKeepRadioButton' }, { style: 'clear: both;' }, { name: 'allowmoveeverything', kind: 'OB.OBPOSCashUp.UI.CashToKeepRadioButton', qtyToKeep: 0, i18nLabel: 'OBPOS_LblNothing', showing: false }, { style: 'clear: both;' }, { name: 'allowdontmove', kind: 'OB.OBPOSCashUp.UI.CashToKeepRadioButton', showing: false }, { style: 'clear: both;' }, { name: 'allowvariableamount', binded: false, kind: 'OB.OBPOSCashUp.UI.CashToKeepRadioButton', showing: false, qtyToKeep: 0, style: 'padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 40px; margin-top: 10px; margin-right: 10px; margin-bottom: 10px; margin-left: 10px;', components: [{ style: 'display: table-row;', components: [{ style: 'vertical-align: middle; display: table-cell; ', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblOther')); } }, { name: 'variableInput', style: 'width: 90px; vertical-align: middle; margin-top: 0px; margin-right: 0px; margin-bottom: 1px; margin-left: 10px; display: inline-block; ', content: OB.DEC.Zero }] }] }] }] }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.CashToKeep', published: { paymentToKeep: null }, components: [{ classes: 'tab-pane', components: [{ style: 'overflow:auto; height: 500px; margin: 5px', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'cashtokeepheader', style: 'padding: 10px; border-bottom: 1px solid #cccccc; text-align:center;', renderHeader: function (value) { this.setContent(OB.I18N.getLabel('OBPOS_LblStep3of4', [value]) + OB.OBPOSCashUp.UI.CashUp.getTitleExtensions()); } }] }] }, { kind: 'OB.OBPOSCashUp.UI.KeepDetails', name: 'formkeep', handlers: { onChangeOption: 'changeOption' }, changeOption: function (inSender, inEvent) { this.$.allowvariableamount.tap(); }, disableControls: function () { //remove selected RButtons //reset UI and model. this.$.keepfixedamount.disableRadio(); this.$.allowmoveeverything.disableRadio(); this.$.allowdontmove.disableRadio(); this.$.allowvariableamount.disableRadio(); this.$.variableInput.setContent(''); this.doResetQtyToKeep({ qtyToKeep: null }); }, renderFixedAmount: function (modelToDraw) { var udfn, cnted; if (modelToDraw.get('foreignCounted')) { cnted = modelToDraw.get('foreignCounted'); } else { cnted = modelToDraw.get('counted'); } this.$.keepfixedamount.setShowing(modelToDraw.get('paymentMethod').keepfixedamount); if (modelToDraw.get('paymentMethod').keepfixedamount) { if (modelToDraw.get('foreignCounted') !== null && modelToDraw.get('foreignCounted') !== udfn) { if (cnted < modelToDraw.get('paymentMethod').amount) { this.$.keepfixedamount.render(OB.I18N.formatCurrency(cnted)); this.$.keepfixedamount.setQtyToKeep(cnted); } else { this.$.keepfixedamount.render(OB.I18N.formatCurrency(modelToDraw.get('paymentMethod').amount)); this.$.keepfixedamount.setQtyToKeep(modelToDraw.get('paymentMethod').amount); } } else { this.$.keepfixedamount.render(OB.I18N.formatCurrency(modelToDraw.get('paymentMethod').amount)); this.$.keepfixedamount.setQtyToKeep(modelToDraw.get('paymentMethod').amount); } } else { this.$.keepfixedamount.render(''); } }, renderBody: function (modelToDraw) { var paymentMethod = modelToDraw.get('paymentMethod'); if (!paymentMethod.automatemovementtoother) { return true; } this.disableControls(); //draw this.renderFixedAmount(modelToDraw); this.$.allowmoveeverything.setShowing(paymentMethod.allowmoveeverything); this.$.allowdontmove.setShowing(paymentMethod.allowdontmove); if (paymentMethod.allowdontmove) { this.$.allowdontmove.setQtyToKeep(modelToDraw.get('foreignCounted')); this.$.allowdontmove.render(OB.I18N.getLabel('OBPOS_LblTotalAmount') + ' ' + OB.I18N.formatCurrency(modelToDraw.get('foreignCounted'))); } else { this.$.allowdontmove.render(''); } this.$.allowvariableamount.setShowing(paymentMethod.allowvariableamount); } }] }] }] }], paymentToKeepChanged: function (model) { this.$.cashtokeepheader.renderHeader(this.paymentToKeep.get('name')); this.$.formkeep.renderBody(this.paymentToKeep); //If fixed quantity to keep is more than counted quantity, //counted quantity should be propossed to keep. if (this.paymentToKeep.get('paymentMethod').keepfixedamount) { this.paymentToKeep.on('change:counted', function (mod) { this.$.formkeep.renderFixedAmount(this.paymentToKeep); }, this); } }, displayStep: function (model) { // this function is invoked when displayed. this.$.formkeep.disableControls(); this.setPaymentToKeep(model.get('paymentList').at(model.get('substep'))); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo */ //Renders the summary of deposits/drops and contains a list (OB.OBPOSCasgMgmt.UI.RenderDepositsDrops) //with detailed information for each payment typ enyo.kind({ name: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'width: 10%; float: left;', components: [{ allowHtml: true, tag: 'span', content: ' ' }] }, { style: 'padding: 5px 0px 0px 5px; float: left; width: 60%; font-weight:bold;', components: [{ style: 'clear:both;' }] }] }, {}] }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.ppc_totalsLine', classes: 'row-fluid', label: '', value: '', components: [{ classes: 'span12', components: [{ style: 'width: 10%; float: left;', components: [{ allowHtml: true, tag: 'span', content: ' ' }] }, { name: 'totalLbl', style: 'padding: 5px 0px 0px 5px; border-bottom: 1px solid #cccccc; border-top: 1px solid #cccccc; border-right: 1px solid #cccccc; float: left; width: 55%; font-weight:bold;' }, { name: 'totalQty', style: 'padding: 5px 0px 0px 5px; border-bottom: 1px solid #cccccc; border-top: 1px solid #cccccc; float: left; width: 20%; text-align:right; font-weight:bold;' }, { style: 'width: 10%; float: left;', components: [{ allowHtml: true, tag: 'span', content: ' ' }] }] }, {}], setValue: function (value) { this.value = value; this.render(); }, render: function () { if (this.i18nLabel) { this.$.totalLbl.setContent(OB.I18N.getLabel(this.i18nLabel)); } else { this.$.totalLbl.setContent(this.label); } this.$.totalQty.setContent(OB.I18N.formatCurrency(OB.DEC.add(0, this.value))); }, initComponents: function () { this.inherited(arguments); if ((this.label || this.i18nLabel) && this.value) { if (this.i18nLabel) { this.$.totalLbl.setContent(OB.I18N.getLabel(this.i18nLabel)); } else { this.$.totalLbl.setContent(this.label); } this.$.totalQty.setContent(this.value); } } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.ppc_itemLine', label: '', value: '', classes: 'row-fluid', convertedValues: ['expected', 'counted', 'difference', 'qtyToKeep', 'qtyToDepo'], valuestoConvert: ['deposits', 'drops', 'startings'], components: [{ classes: 'span12', components: [{ style: 'width: 10%; float: left;', components: [{ allowHtml: true, tag: 'span', content: ' ' }] }, { name: 'itemLbl', style: 'padding: 5px 0px 0px 5px; border-top: 1px solid #cccccc; float: left; width: 35%' }, { name: 'foreignItemQty', style: 'padding: 5px 0px 0px 0px; border-top: 1px solid #cccccc; float: left; width: 20%; text-align:right;' }, { name: 'itemQty', style: 'padding: 5px 0px 0px 5px; border-top: 1px solid #cccccc; border-left: 1px solid #cccccc; float: left; width: 20%; text-align:right;' }, { style: 'width: 10%; float: left;', components: [{ allowHtml: true, tag: 'span', content: ' ' }] }] }, {}], setValue: function (value) { this.value = value; this.render(); }, render: function () { if (this.i18nLabel) { this.$.itemLbl.setContent(OB.I18N.getLabel(this.i18nLabel)); } else { this.$.itemLbl.setContent(this.label); } this.$.itemQty.setContent(OB.I18N.formatCurrency(OB.DEC.add(0, this.value))); if (this.convertedValue && this.convertedValue !== this.value && this.convertedValues.indexOf(this.type) !== -1) { this.$.foreignItemQty.setContent('(' + OB.I18N.formatCurrency(this.convertedValue) + ' ' + this.isocode + ')'); } else if (this.valueToConvert && this.value !== this.valueToConvert && this.valuestoConvert.indexOf(this.type) !== -1) { if (this.value) { this.$.foreignItemQty.setContent('(' + OB.I18N.formatCurrency(this.value) + ' ' + this.isocode + ')'); } this.$.itemQty.setContent(OB.I18N.formatCurrency(this.valueToConvert)); } else { this.$.foreignItemQty.setContent(''); } }, create: function () { this.inherited(arguments); if (this.model) { this.label = this.model.get(this.lblProperty); this.value = this.model.get(this.qtyProperty); this.type = this.owner.typeProperty; this.valueToConvert = this.model.get('origAmount'); this.convertedValue = this.model.get('second'); this.rate = this.model.get('rate'); this.isocode = this.model.get('isocode'); // DEVELOPER: This two rules must be followed if you want this kind to keep data meaningfulness // Each type is related to either convertedValues or valuestoConvert if (this.convertedValue && this.convertedValues.indexOf(this.type) === -1) { OB.warn("DEVELOPER: the type '" + this.type + "' is being incorrectly implemented."); } if (this.valueToConvert && this.valuestoConvert.indexOf(this.type) === -1){ OB.warn("DEVELOPER: the type '" + this.type + "' is being incorrectly implemented."); } } } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.ppc_collectionLines', kind: 'OB.UI.iterateArray', renderLine: 'OB.OBPOSCashUp.UI.ppc_itemLine', renderEmpty: 'OB.UI.RenderEmpty' }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.ppc_table', setValue: function (name, value) { this.$[name].setValue(value); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_salesTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_itemLine', name: 'netsales', i18nLabel: 'OBPOS_LblNetSales' }, { kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'salestaxes', lblProperty: 'name', qtyProperty: 'amount' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totalsales', i18nLabel: 'OBPOS_LblGrossSales' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.salestaxes.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_returnsTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_itemLine', name: 'netreturns', i18nLabel: 'OBPOS_LblNetReturns' }, { kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'retunrnstaxes', lblProperty: 'name', qtyProperty: 'amount' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totalreturns', i18nLabel: 'OBPOS_LblGrossReturns' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.retunrnstaxes.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_totalTransactionsTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totaltransactionsline', i18nLabel: 'OBPOS_LblTotalRetailTrans' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }] }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_cashDropsTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'drops', lblProperty: 'description', qtyProperty: 'amount', typeProperty: 'drops' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totaldrops', i18nLabel: 'OBPOS_LblTotalWithdrawals' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.drops.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_cashDepositsTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'deposits', lblProperty: 'description', qtyProperty: 'amount', typeProperty: 'deposits' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totaldeposits', i18nLabel: 'OBPOS_LblTotalDeposits' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.deposits.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_startingsTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'startings', lblProperty: 'description', qtyProperty: 'amount', typeProperty: 'startings' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totalstartings', i18nLabel: 'OBPOS_LblTotalStarting' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.startings.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_cashExpectedTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'expectedPerPayment', lblProperty: 'name', qtyProperty: 'value', typeProperty: 'expected' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totalexpected', i18nLabel: 'OBPOS_LblTotalExpected' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.expectedPerPayment.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_cashDifferenceTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'differencePerPayment', lblProperty: 'name', qtyProperty: 'value', typeProperty: 'difference' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totaldifference', i18nLabel: 'OBPOS_LblTotalDifference' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.differencePerPayment.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_cashCountedTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'countedPerPayment', lblProperty: 'name', qtyProperty: 'value', typeProperty: 'counted' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totalcounted', i18nLabel: 'OBPOS_LblTotalCounted' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.countedPerPayment.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_cashQtyToKeepTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'qtyToKeepPerPayment', lblProperty: 'name', qtyProperty: 'value', typeProperty: 'qtyToKeep' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totalqtyToKeep', i18nLabel: 'OBPOS_LblTotalQtyToKeep' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.qtyToKeepPerPayment.setCollection(col); } }); enyo.kind({ kind: 'OB.OBPOSCashUp.UI.ppc_table', name: 'OB.OBPOSCashUp.UI.ppc_cashQtyToDepoTable', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_collectionLines', name: 'qtyToDepoPerPayment', lblProperty: 'name', qtyProperty: 'value', typeProperty: 'qtyToDepo' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalsLine', name: 'totalqtyToDepo', i18nLabel: 'OBPOS_LblTotalQtyToDepo' }, { kind: 'OB.OBPOSCashUp.UI.ppc_lineSeparator', name: 'separator' }], setCollection: function (col) { this.$.qtyToDepoPerPayment.setCollection(col); } }); enyo.kind({ name: 'OB.OBPOSCashUp.UI.PostPrintClose', published: { model: null, summary: null }, classes: 'tab-pane', components: [{ style: 'overflow:auto; height: 612px; margin: 5px', components: [{ style: 'background-color: #ffffff; color: black; padding: 5px;', components: [{ classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'padding: 10px; border-bottom: 1px solid #cccccc; text-align:center;', initComponents: function () { this.setContent(OB.I18N.getLabel('OBPOS_LblStep4of4') + OB.OBPOSCashUp.UI.CashUp.getTitleExtensions()); } }] }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'padding: 10px; text-align:center;', components: [{ tag: 'img', style: 'padding: 20px;', initComponents: function () { if (OB.MobileApp.model.get('terminal').organizationImage) { this.setAttribute('src', 'data:'+OB.MobileApp.model.get('terminal').organizationImageMime+';base64,'+OB.MobileApp.model.get('terminal').organizationImage); } } }, { name: 'store', style: 'padding: 5px; text-align:center;' }, { name: 'terminal', style: 'padding: 5px; text-align:center;' }, { name: 'user', style: 'padding: 5px; text-align:center;' }, { name: 'time', style: 'padding: 5px; text-align:center;' }, { style: 'padding: 0px 0px 10px 0px;' }] }] }] }, //FIXME: Iterate taxes { classes: 'row-fluid', components: [{ tag: 'ul', classes: 'unstyled', style: 'display:block', components: [{ tag: 'li', classes: 'selected', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_salesTable', name: 'sales' }, { kind: 'OB.OBPOSCashUp.UI.ppc_returnsTable', name: 'returns' }, { kind: 'OB.OBPOSCashUp.UI.ppc_totalTransactionsTable', name: 'totaltransactions' }] }] }, { style: 'border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); padding-top: 15px; padding-right: 15px; padding-bottom: 15px; padding-left: 15px; font-weight: bold; color: rgb(204, 204, 204); display: none;' }, { style: 'display:none;' }] }, { classes: 'row-fluid', components: [{ kind: 'OB.OBPOSCashUp.UI.ppc_startingsTable', name: 'startingsTable' }, { kind: 'OB.OBPOSCashUp.UI.ppc_cashDropsTable', name: 'dropsTable' }, { kind: 'OB.OBPOSCashUp.UI.ppc_cashDepositsTable', name: 'depositsTable' }, { kind: 'OB.OBPOSCashUp.UI.ppc_cashExpectedTable', name: 'expectedTable' }, { kind: 'OB.OBPOSCashUp.UI.ppc_cashCountedTable', name: 'countedTable' }, { kind: 'OB.OBPOSCashUp.UI.ppc_cashDifferenceTable', name: 'differenceTable' }, { kind: 'OB.OBPOSCashUp.UI.ppc_cashQtyToKeepTable', name: 'qtyToKeepTable' }, { kind: 'OB.OBPOSCashUp.UI.ppc_cashQtyToDepoTable', name: 'qtyToDepoTable' }] }, { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'width: 10%; float: left', components: [{ tag: 'span', allowHtml: true, content: ' ' }] }, { style: 'padding: 5px 0px 0px 5px; float: left; width: 60%; font-weight:bold;' }, { style: 'clear:both;' }] }] }] }] }], create: function () { this.inherited(arguments); this.$.store.setContent(OB.I18N.getLabel('OBPOS_LblStore') + ': ' + OB.POS.modelterminal.get('terminal').organization$_identifier); this.$.terminal.setContent(OB.I18N.getLabel('OBPOS_LblTerminal') + ': ' + OB.POS.modelterminal.get('terminal')._identifier); this.$.user.setContent(OB.I18N.getLabel('OBPOS_LblUser') + ': ' + OB.POS.modelterminal.get('context').user._identifier); this.$.time.setContent(OB.I18N.getLabel('OBPOS_LblTime') + ': ' + OB.I18N.formatDate(new Date()) + ' - ' + OB.I18N.formatHour(new Date())); }, init: function (model) { this.model = model; this.model.get('cashUpReport').on('add', function (cashUpReport) { this.$.sales.setValue('netsales', cashUpReport.get('netSales')); this.$.sales.setCollection(cashUpReport.get('salesTaxes')); this.$.sales.setValue('totalsales', cashUpReport.get('grossSales')); this.$.returns.setValue('netreturns', cashUpReport.get('netReturns')); this.$.returns.setCollection(cashUpReport.get('returnsTaxes')); this.$.returns.setValue('totalreturns', cashUpReport.get('grossReturns')); this.$.totaltransactions.setValue('totaltransactionsline', cashUpReport.get('totalRetailTransactions')); this.$.startingsTable.setCollection(cashUpReport.get('startings')); this.$.startingsTable.setValue('totalstartings', cashUpReport.get('totalStartings')); this.$.dropsTable.setCollection(cashUpReport.get('drops')); this.$.dropsTable.setValue('totaldrops', cashUpReport.get('totalDrops')); this.$.depositsTable.setCollection(cashUpReport.get('deposits')); this.$.depositsTable.setValue('totaldeposits', cashUpReport.get('totalDeposits')); }, this); this.model.on('change:time', function () { this.$.time.setContent(OB.I18N.getLabel('OBPOS_LblTime') + ': ' + OB.I18N.formatDate(this.model.get('time')) + ' - ' + OB.I18N.formatHour(this.model.get('time'))); }, this); }, summaryChanged: function () { this.$.expectedTable.setCollection(this.summary.expectedSummary); this.$.expectedTable.setValue('totalexpected', this.summary.totalExpected); this.$.countedTable.setCollection(this.summary.countedSummary); this.$.countedTable.setValue('totalcounted', this.summary.totalCounted); this.$.differenceTable.setCollection(this.summary.differenceSummary); this.$.differenceTable.setValue('totaldifference', this.summary.totalDifference); this.$.qtyToKeepTable.setCollection(this.summary.qtyToKeepSummary); this.$.qtyToKeepTable.setValue('totalqtyToKeep', this.summary.totalQtyToKeep); this.$.qtyToDepoTable.setCollection(this.summary.qtyToDepoSummary); this.$.qtyToDepoTable.setValue('totalqtyToDepo', this.summary.totalQtyToDepo); }, modelChanged: function () { this.$.sales.setValue('netsales', this.model.get('netSales')); this.$.sales.setCollection(this.model.get('salesTaxes')); this.$.sales.setValue('totalsales', this.model.get('grossSales')); this.$.returns.setValue('netreturns', this.model.get('netReturns')); this.$.returns.setCollection(this.model.get('returnsTaxes')); this.$.returns.setValue('totalreturns', this.model.get('grossReturns')); this.$.totaltransactions.setValue('totaltransactionsline', this.model.get('totalRetailTransactions')); this.$.startingsTable.setCollection(this.model.get('startings')); this.$.startingsTable.setValue('totalstartings', this.model.get('totalStartings')); this.$.dropsTable.setCollection(this.model.get('drops')); this.$.dropsTable.setValue('totaldrops', this.model.get('totalDrops')); this.$.depositsTable.setCollection(this.model.get('deposits')); this.$.depositsTable.setValue('totaldeposits', this.model.get('totalDeposits')); this.model.on('change:time', function () { this.$.time.setContent(OB.I18N.getLabel('OBPOS_LblTime') + ': ' + OB.I18N.formatDate(this.model.get('time')) + ' - ' + OB.I18N.formatHour(this.model.get('time'))); }, this); }, displayStep: function (model) { // this function is invoked when displayed. this.setSummary(model.getCountCashSummary()); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ kind: 'OB.UI.ModalAction', name: 'OB.OBPOSCashUp.UI.modalPendingToProcess', i18nHeader: 'OBPOS_LblReceiptsToProcess', bodyContent: { i18nContent: 'OBPOS_MsgReceiptsProcess' }, bodyButtons: { components: [{ //OK button kind: 'OB.OBPOSCashUp.UI.modalPendingToProcess_OkButton' }, { //Cancel button kind: 'OB.OBPOSCashUp.UI.modalPendingToProcess_CancelButton' }] } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSCashUp.UI.modalPendingToProcess_OkButton', i18nContent: 'OBMOBC_LblOk', isDefaultAction: true, tap: function () { this.doHideThisPopup(); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.OBPOSCashUp.UI.modalPendingToProcess_CancelButton', i18nContent: 'OBMOBC_LblCancel', tap: function () { this.doHideThisPopup(); OB.POS.navigate('retail.pointofsale'); } }); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global B, _ , Backbone, localStorage */ (function () { OB = window.OB || {}; OB.Model = window.OB.Model || {}; OB.Collection = window.OB.Collection || {}; OB.Model.PaymentMethod = Backbone.Model.extend({ defaults: { id: null, name: null, expected: OB.DEC.Zero, counted: OB.DEC.Zero } }); //DayCash.PaymentMethodCol Model. OB.Collection.PaymentMethodList = Backbone.Collection.extend({ model: OB.Model.PaymentMethod, serializeToJSON: function () { var jsonpayment = this.toJSON(); // remove not needed members delete jsonpayment.undo; _.forEach(jsonpayment, function (item) { item.difference = item.counted - item.expected; item.paymentTypeId = item.id; delete item.id; delete item.name; delete item.counted; delete item._id; }); return jsonpayment; } }); OB.Model.DayCash = Backbone.Model.extend({ defaults: { totalExpected: OB.DEC.Zero, totalCounted: OB.DEC.Zero, totalDifference: OB.DEC.Zero, step: 0, allowedStep: 0 }, initialize: function () { this.set('paymentmethods', new OB.Model.PaymentMethodList()); } }); }()); /* ************************************************************************* * The contents of this file are subject to the Openbravo Public License * Version 1.1 (the "License"), being the Mozilla Public License * Version 1.1 with a permitted attribution clause; you may not use this * file except in compliance with the License. You may obtain a copy of * the License at http://www.openbravo.com/legal/license.html * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU * All portions are Copyright (C) 2011-2014 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************ */ OB = window.OB || {}; OB.Utilities = window.OB.Utilities || {}; // = Openbravo Number Utilities = // Defines utility methods related to handling numbers on the client, for // example formatting. OB.Utilities.Number = {}; // ** {{{ OB.Utilities.Number.roundJSNumber }}} ** // // Function that rounds a JS number to a given decimal number // // Parameters: // * {{{num}}}: the JS number // * {{{dec}}}: the JS number of decimals // Return: // * The rounded JS number OB.Utilities.Number.roundJSNumber = function (num, dec) { var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec); return result; }; // ** {{{ OB.Utilities.Number.OBMaskedToOBPlain }}} ** // // Function that returns a plain OB number just with the decimal Separator // // Parameters: // * {{{number}}}: the formatted OB number // * {{{decSeparator}}}: the decimal separator of the OB number // * {{{groupSeparator}}}: the group separator of the OB number // Return: // * The plain OB number OB.Utilities.Number.OBMaskedToOBPlain = function (number, decSeparator, groupSeparator) { number = number.toString(); var plainNumber = number, decimalNotation = (number.indexOf('E') === -1 && number.indexOf('e') === -1); // Remove group separators if (groupSeparator) { var groupRegExp = new RegExp('\\' + groupSeparator, 'g'); plainNumber = plainNumber.replace(groupRegExp, ''); } //Check if the number is not on decimal notation if (!decimalNotation) { plainNumber = OB.Utilities.Number.ScientificToDecimal(number, decSeparator); } // Catch sign var numberSign = ''; if (plainNumber.substring(0, 1) === '+') { numberSign = ''; plainNumber = plainNumber.substring(1, number.length); } else if (plainNumber.substring(0, 1) === '-') { numberSign = '-'; plainNumber = plainNumber.substring(1, number.length); } // Remove ending decimal '0' if (plainNumber.indexOf(decSeparator) !== -1) { while (plainNumber.substring(plainNumber.length - 1, plainNumber.length) === '0') { plainNumber = plainNumber.substring(0, plainNumber.length - 1); } } // Remove starting integer '0' while (plainNumber.substring(0, 1) === '0' && plainNumber.substring(1, 2) !== decSeparator && plainNumber.length > 1) { plainNumber = plainNumber.substring(1, plainNumber.length); } // Remove decimal separator if is the last character if (plainNumber.substring(plainNumber.length - 1, plainNumber.length) === decSeparator) { plainNumber = plainNumber.substring(0, plainNumber.length - 1); } // Re-set sign if (plainNumber !== '0') { plainNumber = numberSign + plainNumber; } // Return plain number return plainNumber; }; // ** {{{ OB.Utilities.Number.OBPlainToOBMasked }}} ** // // Function that transform a OB plain number into a OB formatted one (by // applying a mask). // // Parameters: // * {{{number}}}: The OB plain number // * {{{maskNumeric}}}: The numeric mask of the OB number // * {{{decSeparator}}}: The decimal separator of the OB number // * {{{groupSeparator}}}: The group separator of the OB number // * {{{groupInterval}}}: The group interval of the OB number // Return: // * The OB formatted number. OB.Utilities.Number.OBPlainToOBMasked = function (number, maskNumeric, decSeparator, groupSeparator, groupInterval) { if (number === '' || number === null || number === undefined) { return number; } if (groupInterval === null || groupInterval === undefined) { groupInterval = OB.Format.defaultGroupingSize; } // Management of the mask if (maskNumeric.indexOf('+') === 0 || maskNumeric.indexOf('-') === 0) { maskNumeric = maskNumeric.substring(1, maskNumeric.length); } if (groupSeparator && maskNumeric.indexOf(groupSeparator) !== -1 && maskNumeric.indexOf(decSeparator) !== -1 && maskNumeric.indexOf(groupSeparator) > maskNumeric.indexOf(decSeparator)) { var fixRegExp = new RegExp('\\' + groupSeparator, 'g'); maskNumeric = maskNumeric.replace(fixRegExp, ''); } var maskLength = maskNumeric.length; var decMaskPosition = maskNumeric.indexOf(decSeparator); if (decMaskPosition === -1) { decMaskPosition = maskLength; } var intMask = maskNumeric.substring(0, decMaskPosition); var decMask = maskNumeric.substring(decMaskPosition + 1, maskLength); if ((groupSeparator && decMask.indexOf(groupSeparator) !== -1) || decMask.indexOf(decSeparator) !== -1) { if (groupSeparator) { var fixRegExp_1 = new RegExp('\\' + groupSeparator, 'g'); decMask = decMask.replace(fixRegExp_1, ''); } var fixRegExp_2 = new RegExp('\\' + decSeparator, 'g'); decMask = decMask.replace(fixRegExp_2, ''); } // Management of the number number = number.toString(); number = OB.Utilities.Number.OBMaskedToOBPlain(number, decSeparator, groupSeparator); var numberSign = ''; if (number.substring(0, 1) === '+') { numberSign = ''; number = number.substring(1, number.length); } else if (number.substring(0, 1) === '-') { numberSign = '-'; number = number.substring(1, number.length); } // //Splitting the number var formattedNumber = ''; var numberLength = number.length; var decPosition = number.indexOf(decSeparator); if (decPosition === -1) { decPosition = numberLength; } var intNumber = number.substring(0, decPosition); var decNumber = number.substring(decPosition + 1, numberLength); // //Management of the decimal part if (decNumber.length > decMask.length) { decNumber = '0.' + decNumber; decNumber = OB.Utilities.Number.roundJSNumber(decNumber, decMask.length); decNumber = decNumber.toString(); // Check if the number is on Scientific notation if (decNumber.indexOf('e') !== -1 || decNumber.indexOf('E') !== -1) { decNumber = OB.Utilities.Number.ScientificToDecimal(decNumber, decSeparator); } if (decNumber.substring(0, 1) === '1') { intNumber = parseFloat(intNumber); intNumber = intNumber + 1; intNumber = intNumber.toString(); } decNumber = decNumber.substring(2, decNumber.length); } if (decNumber.length < decMask.length) { var decNumber_temp = '', decMaskLength = decMask.length, i; for (i = 0; i < decMaskLength; i++) { if (decMask.substring(i, i + 1) === '#') { if (decNumber.substring(i, i + 1) !== '') { decNumber_temp = decNumber_temp + decNumber.substring(i, i + 1); } } else if (decMask.substring(i, i + 1) === '0') { if (decNumber.substring(i, i + 1) !== '') { decNumber_temp = decNumber_temp + decNumber.substring(i, i + 1); } else { decNumber_temp = decNumber_temp + '0'; } } } decNumber = decNumber_temp; } // Management of the integer part var isGroup = false; if (groupSeparator) { if (intMask.indexOf(groupSeparator) !== -1) { isGroup = true; } var groupRegExp = new RegExp('\\' + groupSeparator, 'g'); intMask = intMask.replace(groupRegExp, ''); } var intNumber_temp; if (intNumber.length < intMask.length) { intNumber_temp = ''; var diff = intMask.length - intNumber.length, j; for (j = intMask.length; j > 0; j--) { if (intMask.substring(j - 1, j) === '#') { if (intNumber.substring(j - 1 - diff, j - diff) !== '') { intNumber_temp = intNumber.substring(j - 1 - diff, j - diff) + intNumber_temp; } } else if (intMask.substring(j - 1, j) === '0') { if (intNumber.substring(j - 1 - diff, j - diff) !== '') { intNumber_temp = intNumber.substring(j - 1 - diff, j - diff) + intNumber_temp; } else { intNumber_temp = '0' + intNumber_temp; } } } intNumber = intNumber_temp; } if (isGroup === true) { intNumber_temp = ''; var groupCounter = 0, k; for (k = intNumber.length; k > 0; k--) { intNumber_temp = intNumber.substring(k - 1, k) + intNumber_temp; groupCounter++; if (groupCounter.toString() === groupInterval.toString() && k !== 1) { groupCounter = 0; intNumber_temp = groupSeparator + intNumber_temp; } } intNumber = intNumber_temp; } // Building the final number if (intNumber === '' && decNumber !== '') { intNumber = '0'; } formattedNumber = numberSign + intNumber; if (decNumber !== '') { formattedNumber += decSeparator + decNumber; } return formattedNumber; }; // ** {{{ OB.Utilities.Number.OBMaskedToJS }}} ** // // Function that returns a JS number just with the decimal separator which // always is '.'. It is used for math operations // // Parameters: // * {{{number}}}: The OB formatted (or plain) number // * {{{decSeparator}}}: The decimal separator of the OB number // * {{{groupSeparator}}}: The group separator of the OB number // Return: // * The JS number. OB.Utilities.Number.OBMaskedToJS = function (numberStr, decSeparator, groupSeparator) { if (!numberStr || numberStr.trim() === '') { return null; } var calcNumber = OB.Utilities.Number.OBMaskedToOBPlain(numberStr, decSeparator, groupSeparator); calcNumber = calcNumber.replace(decSeparator, '.'); var numberResult = parseFloat(calcNumber); if (isNaN(numberResult)) { return numberStr; } return numberResult; }; // ** {{{ OB.Utilities.Number.JSToOBMasked }}} ** // // Function that returns a OB formatted number given as input a JS number just // with the decimal separator which always is '.' // // Parameters: // * {{{number}}}: The JS number // * {{{maskNumeric}}}: The numeric mask of the OB number // * {{{decSeparator}}}: The decimal separator of the OB number // * {{{groupSeparator}}}: The group separator of the OB number // * {{{groupInterval}}}: The group interval of the OB number // Return: // * The OB formatted number. OB.Utilities.Number.JSToOBMasked = function (number, maskNumeric, decSeparator, groupSeparator, groupInterval) { var isANumber = Object.prototype.toString.call(number) === '[object Number]'; if (!isANumber) { return number; } var formattedNumber = number; formattedNumber = formattedNumber.toString(); formattedNumber = formattedNumber.replace('.', decSeparator); formattedNumber = OB.Utilities.Number.OBPlainToOBMasked(formattedNumber, maskNumeric, decSeparator, groupSeparator, groupInterval); return formattedNumber; }; OB.Utilities.Number.IsValidValueString = function (type, numberStr) { var maskNumeric = type.maskNumeric; // note 0 is also okay to return true if (!numberStr) { return true; } var bolNegative = true; if (maskNumeric.indexOf('+') === 0) { bolNegative = false; maskNumeric = maskNumeric.substring(1, maskNumeric.length); } var bolDecimal = true; if (maskNumeric.indexOf(type.decSeparator) === -1) { bolDecimal = false; } var checkPattern = ''; checkPattern += '^'; if (bolNegative) { checkPattern += '([+]|[-])?'; } checkPattern += '(\\d+)?((\\' + type.groupSeparator + '\\d{' + OB.Format.defaultGroupingSize + '})?)+'; if (bolDecimal) { checkPattern += '(\\' + type.decSeparator + '\\d+)?'; } checkPattern += '$'; var checkRegExp = new RegExp(checkPattern); if (numberStr.match(checkRegExp) && numberStr.substring(0, 1) !== type.groupSeparator) { return true; } return false; }; OB.Utilities.Number.Grouping = { getGroupingModes: function () { return this.groupingModes; }, groupingModes: { byDecimal10: OB.I18N.getLabel('OBUIAPP_GroupByDecimal10'), by1: OB.I18N.getLabel('OBUIAPP_GroupBy1'), by10: OB.I18N.getLabel('OBUIAPP_GroupBy10'), by100: OB.I18N.getLabel('OBUIAPP_GroupBy100'), by1000: OB.I18N.getLabel('OBUIAPP_GroupBy1000'), by10000: OB.I18N.getLabel('OBUIAPP_GroupBy10000'), by100000: OB.I18N.getLabel('OBUIAPP_GroupBy100000') }, defaultGroupingMode: 'by10', //default grouping mode groupingMode: 'by10', getGroupingMultiplier: function (groupingMode) { switch (groupingMode) { case 'byDecimal10': return 0.1; case 'by1': return 1; case 'by10': return 10; case 'by100': return 100; case 'by1000': return 1000; case 'by10000': return 10000; case 'by100000': return 100000; } // default return 10; }, getGroupValue: function (value, record, field, fieldName, grid) { var returnValue, groupingMode = (field.groupingMode || OB.Utilities.Number.Grouping.defaultGroupingMode), multiplier = this.getGroupingMultiplier(groupingMode); if (!isc.isA.Number(value) || !groupingMode) { return value; } returnValue = value / multiplier; // round down returnValue = Math.round(returnValue - 0.49); returnValue = returnValue * multiplier; return returnValue; }, getGroupTitle: function (value, record, field, fieldName, grid) { var groupValue = this.getGroupValue(value, record, field, fieldName, grid), groupingMode = (field.groupingMode || OB.Utilities.Number.Grouping.defaultGroupingMode), multiplier = this.getGroupingMultiplier(groupingMode); return groupValue + ' - ' + (groupValue + multiplier); } }; //** {{{ OB.Utilities.Number.ScientificToDecimal }}} ** // // Convert a number from Scientific notation to decimal notation // // Parameters: // * {{{number}}}: the number on scientific notation // * {{{decSeparator}}}: the decimal separator of the OB number // Return: // * The OB number on decimal notation OB.Utilities.Number.ScientificToDecimal = function (number, decSeparator) { number = number.toString(); var coeficient, exponent, numberOfZeros, zeros = '', i, split, index; // Look for 'e' or 'E' if (number.indexOf('e') !== -1) { index = number.indexOf('e'); } else if (number.indexOf('E') !== -1) { index = number.indexOf('E'); } else { // Number is not expressed in scientific notation return number; } // Set the number before and after e coeficient = number.substring(0, index); exponent = number.substring(index + 1, number.length); //Remove the decimal separator if (coeficient.indexOf(decSeparator) !== -1) { split = coeficient.split(decSeparator); coeficient = split[0] + split[1]; } if (exponent.indexOf('-') !== -1) { // Case the number is smaller than 1 numberOfZeros = exponent.substring(1, exponent.length); //Create the string of zeros for (i = 1; i < numberOfZeros; i++) { zeros = zeros + '0'; } //Create the final number number = '0.' + zeros + coeficient; } else if (exponent.indexOf('+') !== -1) { // Case the number is bigger than 1 numberOfZeros = exponent.substring(1, exponent.length); if (split) { numberOfZeros = numberOfZeros - split[1].length; } //Create the string of zeros for (i = 0; i < numberOfZeros; i++) { zeros = zeros + '0'; } //Create the final number number = coeficient + zeros; } return number; }; /* ************************************************************************* * The contents of this file are subject to the Openbravo Public License * Version 1.1 (the "License"), being the Mozilla Public License * Version 1.1 with a permitted attribution clause; you may not use this * file except in compliance with the License. You may obtain a copy of * the License at http://www.openbravo.com/legal/license.html * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * The Original Code is Openbravo ERP. * The Initial Developer of the Original Code is Openbravo SLU * All portions are Copyright (C) 2009-2014 Openbravo SLU * All Rights Reserved. * Contributor(s): ______________________________________. ************************************************************************ */ OB = window.OB || {}; OB.Utilities = window.OB.Utilities || {}; // = Openbravo Date Utilities = // Defines utility methods related to handling date, incl. formatting. OB.Utilities.Date = {}; // ** {{{ OB.Utilities.Date.centuryReference }}} ** // For a two-digit year display format, it establishes where is the frontier // between the 20th and the 21st century // The range is taken between 1900+centuryReference and 2100-centuryReference-1 OB.Utilities.Date.centuryReference = 50; // Notice that change this value // implies that also the QUnit test // case should be changed // ** {{{ OB.Utilities.Date.normalizeDisplayFormat }}} ** // Repairs the displayFormat definition (passed in as a parameter) to a value // expected by the rest of the system. For example mm is replaced by MM, // dd is replacecd by DD, YYYY to %Y. // // Parameters: // * {{{displayFormat}}}: the string displayFormat definition to repair. OB.Utilities.Date.normalizeDisplayFormat = function (displayFormat) { var newFormat = ''; displayFormat = displayFormat.replace('mm', 'MM').replace('dd', 'DD').replace('yyyy', 'YYYY').replace('yy', 'YY'); displayFormat = displayFormat.replace('%D', '%d').replace('%M', '%m'); if (displayFormat !== null && displayFormat !== '') { newFormat = displayFormat; newFormat = newFormat.replace('YYYY', '%Y'); newFormat = newFormat.replace('YY', '%y'); newFormat = newFormat.replace('MM', '%m'); newFormat = newFormat.replace('DD', '%d'); newFormat = newFormat.substring(0, 8); } displayFormat = displayFormat.replace('hh', 'HH').replace('HH24', 'HH').replace('mi', 'MI').replace('ss', 'SS'); displayFormat = displayFormat.replace('%H', 'HH').replace('HH:%m', 'HH:MI').replace('HH.%m', 'HH.MI').replace('%S', 'SS'); displayFormat = displayFormat.replace('HH:mm', 'HH:MI').replace('HH.mm', 'HH.MI'); displayFormat = displayFormat.replace('HH:MM', 'HH:MI').replace('HH.MM', 'HH.MI'); if (displayFormat.indexOf(' HH:MI:SS') !== -1) { newFormat += ' %H:%M:%S'; } else if (displayFormat.indexOf(' HH:MI') !== -1) { newFormat += ' %H:%M'; } else if (displayFormat.indexOf(' HH.MI.SS') !== -1) { newFormat += ' %H.%M.%S'; } else if (displayFormat.indexOf(' HH.MI') !== -1) { newFormat += ' %H.%M'; } if (displayFormat.indexOf(' a') !== -1) { newFormat += ' A'; } return newFormat; }; //** {{{ OB.Utilities.getTimeFormat }}} ** // // Returns an object with the timeformatter, a boolean if 24 hours // time clock are being used and the timeformat itself OB.Utilities.getTimeFormatDefinition = function () { var timeFormat, is24h = true; if (OB.Format.dateTime.indexOf(' ') === -1) { return 'to24HourTime'; } timeFormat = OB.Format.dateTime.substring(OB.Format.dateTime.indexOf(' ') + 1); if (timeFormat && timeFormat.toUpperCase().lastIndexOf(' A') !== -1 && timeFormat.toUpperCase().lastIndexOf(' A') === timeFormat.length - 2) { is24h = false; } if (timeFormat.toLowerCase().contains('ss')) { return { timeFormat: timeFormat, is24h: is24h, timeFormatter: is24h ? 'to24HourTime' : 'toTime' }; } return { timeFormat: timeFormat, is24h: is24h, timeFormatter: is24h ? 'toShort24HourTime' : 'toShortTime' }; }; // ** {{{ OB.Utilities.Date.OBToJS }}} ** // // Converts a String to a Date object. // // Parameters: // * {{{OBDate}}}: the date string to convert // * {{{dateFormat}}}: the dateFormat pattern to use // Return: // * a Date object or null if conversion was not possible. OB.Utilities.Date.OBToJS = function (OBDate, dateFormat) { if (!OBDate) { return null; } // if already a date then return true var isADate = Object.prototype.toString.call(OBDate) === '[object Date]', PMIndicator = ' PM', AMIndicator = ' AM', is24h = true, isPM = false; if (isADate) { return OBDate; } if (window.isc && isc.Time && isc.Time.PMIndicator) { PMIndicator = isc.Time.PMIndicator; } if (window.isc && isc.Time && isc.Time.AMIndicator) { AMIndicator = isc.Time.AMIndicator; } dateFormat = OB.Utilities.Date.normalizeDisplayFormat(dateFormat); dateFormat = dateFormat.replace(' A', ''); var dateSeparator = dateFormat.substring(2, 3); var timeSeparator = dateFormat.substring(11, 12); var isFullYear = (dateFormat.indexOf('%Y') !== -1); if (OBDate.indexOf(PMIndicator) !== 1 || OBDate.indexOf(AMIndicator) !== 1) { is24h = false; } if (!is24h && OBDate.indexOf(PMIndicator) !== -1) { isPM = true; } OBDate = OBDate.replace(AMIndicator, '').replace(PMIndicator, ''); if ((isFullYear ? OBDate.length - 2 : OBDate.length) !== dateFormat.length) { return null; } if (isFullYear) { dateFormat = dateFormat.replace('%Y', '%YYY'); } if (dateFormat.indexOf('-') !== -1 && OBDate.indexOf('-') === -1) { return null; } else if (dateFormat.indexOf('/') !== -1 && OBDate.indexOf('/') === -1) { return null; } else if (dateFormat.indexOf(':') !== -1 && OBDate.indexOf(':') === -1) { return null; } else if (dateFormat.indexOf('.') !== -1 && OBDate.indexOf('.') === -1) { return null; } var year = dateFormat.indexOf('%y') !== -1 ? OBDate.substring(dateFormat.indexOf('%y'), dateFormat.indexOf('%y') + 2) : 0; var fullYear = dateFormat.indexOf('%Y') !== -1 ? OBDate.substring(dateFormat.indexOf('%Y'), dateFormat.indexOf('%Y') + 4) : 0; var month = dateFormat.indexOf('%m') !== -1 ? OBDate.substring(dateFormat.indexOf('%m'), dateFormat.indexOf('%m') + 2) : 0; var day = dateFormat.indexOf('%d') !== -1 ? OBDate.substring(dateFormat.indexOf('%d'), dateFormat.indexOf('%d') + 2) : 0; var hours = dateFormat.indexOf('%H') !== -1 ? OBDate.substring(dateFormat.indexOf('%H'), dateFormat.indexOf('%H') + 2) : 0; var minutes = dateFormat.indexOf('%M') !== -1 ? OBDate.substring(dateFormat.indexOf('%M'), dateFormat.indexOf('%M') + 2) : 0; var seconds = dateFormat.indexOf('%S') !== -1 ? OBDate.substring(dateFormat.indexOf('%S'), dateFormat.indexOf('%S') + 2) : 0; // Check that really all date parts (if they are present) are numbers var digitRegExp = ['^\\d+$', 'gm']; if ((year && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(year))) || (fullYear && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(fullYear))) || (month && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(month))) || (day && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(day))) || (hours && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(hours))) || (minutes && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(minutes))) || (seconds && !(new RegExp(digitRegExp[0], digitRegExp[1]).test(seconds)))) { return null; } month = parseInt(month, 10); day = parseInt(day, 10); hours = parseInt(hours, 10); minutes = parseInt(minutes, 10); seconds = parseInt(seconds, 10); if (!is24h) { if (!isPM && hours === 12) { hours = 0; } if (isPM && hours !== 12) { hours = hours + 12; } } if (day < 1 || day > 31 || month < 1 || month > 12 || year > 99 || fullYear > 9999) { return null; } if (hours > 23 || minutes > 59 || seconds > 59) { return null; } // alert('year: ' + year + '\n' + 'fullYear: ' + fullYear + '\n' + 'month: ' + // month + '\n' + 'day: ' + day + '\n' + 'hours: ' + hours + '\n' + 'minutes: // ' + minutes + '\n' + 'seconds: ' + seconds); // var JSDate = isc.Date.create(); /**It doesn't work in IE**/ var JSDate = new Date(); var centuryReference = OB.Utilities.Date.centuryReference; if (!isFullYear) { if (parseInt(year, 10) < centuryReference) { fullYear = '20' + year; } else { fullYear = '19' + year; } } fullYear = parseInt(fullYear, 10); JSDate.setFullYear(fullYear, month - 1, day); // https://issues.openbravo.com/view.php?id=22505 if (day !== JSDate.getDate()) { return null; } JSDate.setHours(hours); JSDate.setMinutes(minutes); JSDate.setSeconds(seconds); JSDate.setMilliseconds(0); if (JSDate.toString() === 'Invalid Date' || JSDate.toString() === 'NaN') { return null; } else { return JSDate; } }; // ** {{{ OB.Utilities.Date.JSToOB }}} ** // // Converts a Date to a String // // Parameters: // * {{{JSDate}}}: the javascript Date object // * {{{dateFormat}}}: the dateFormat pattern to use // Return: // * a String or null if the JSDate is not a date. OB.Utilities.Date.JSToOB = function (JSDate, dateFormat) { dateFormat = OB.Utilities.Date.normalizeDisplayFormat(dateFormat); var isADate = Object.prototype.toString.call(JSDate) === '[object Date]', PMIndicator = ' PM', AMIndicator = ' AM', is24h = true, isPM = false; if (!isADate) { return null; } if (window.isc && isc.Time && isc.Time.PMIndicator) { PMIndicator = isc.Time.PMIndicator; } if (window.isc && isc.Time && isc.Time.AMIndicator) { AMIndicator = isc.Time.AMIndicator; } if (dateFormat.toUpperCase().lastIndexOf(' A') !== -1 && dateFormat.toUpperCase().lastIndexOf(' A') === dateFormat.length - 2) { is24h = false; } var year = JSDate.getYear().toString(); var fullYear = JSDate.getFullYear().toString(); var month = (JSDate.getMonth() + 1).toString(); var day = JSDate.getDate().toString(); var hours = JSDate.getHours().toString(); var minutes = JSDate.getMinutes().toString(); var seconds = JSDate.getSeconds().toString(); var centuryReference = OB.Utilities.Date.centuryReference; if (dateFormat.indexOf('%y') !== -1) { if (parseInt(fullYear, 10) >= 1900 + centuryReference && parseInt(fullYear, 10) < 2100 - centuryReference) { if (parseInt(year, 10) >= 100) { year = parseInt(year, 10) - 100; year = year.toString(); } } else { return null; } } if (!is24h) { hours = parseInt(hours, 10); if (hours >= 12) { isPM = true; } if (hours > 12) { hours = hours - 12; } if (hours === 0) { hours = 12; } hours = hours.toString(); } while (year.length < 2) { year = '0' + year; } while (fullYear.length < 4) { fullYear = '0' + fullYear; } while (month.length < 2) { month = '0' + month; } while (day.length < 2) { day = '0' + day; } while (hours.length < 2) { hours = '0' + hours; } while (minutes.length < 2) { minutes = '0' + minutes; } while (seconds.length < 2) { seconds = '0' + seconds; } var OBDate = dateFormat; OBDate = OBDate.replace('%y', year); OBDate = OBDate.replace('%Y', fullYear); OBDate = OBDate.replace('%m', month); OBDate = OBDate.replace('%d', day); OBDate = OBDate.replace('%H', hours); OBDate = OBDate.replace('%M', minutes); OBDate = OBDate.replace('%S', seconds); if (!is24h) { if (isPM) { OBDate = OBDate.replace(' A', PMIndicator); } else { OBDate = OBDate.replace(' A', AMIndicator); } } return OBDate; }; //** {{{ OB.Utilities.Date.getTimeFields }}} ** // // Returns an array with the names of the time fields. // // Parameters: // * {{{allFields}}}: complete list of fields // Return: // * an array with the names of the time fields contained in allFields. OB.Utilities.Date.getTimeFields = function (allFields) { var i, field, timeFields = [], length = allFields.length; for (i = 0; i < length; i++) { field = allFields[i]; if (field.type === '_id_24') { timeFields.push(field); } } return timeFields; }; //** {{{ OB.Utilities.Date.convertUTCTimeToLocalTime }}} ** // // Converts the value of time fields from UTC to local time // // Parameters: // * {{{newData}}}: records to be converted // * {{{allFields}}}: array with the fields of the records // Return: // * Nothing. newData, after converting its time fields from UTC timezone the the client side timezone OB.Utilities.Date.convertUTCTimeToLocalTime = function (newData, allFields) { var textField, fieldToDate, i, j, UTCOffsetInMiliseconds = OB.Utilities.Date.getUTCOffsetInMiliseconds(), timeFields = OB.Utilities.Date.getTimeFields(allFields), timeFieldsLength = timeFields.length, convertedData = isc.clone(newData), convertedDataLength = convertedData.length; for (i = 0; i < timeFieldsLength; i++) { for (j = 0; j < convertedDataLength; j++) { textField = convertedData[j][timeFields[i].name]; if (!textField) { continue; } if (isc.isA.String(textField)) { fieldToDate = isc.Time.parseInput(textField); } else if (isc.isA.Date(textField)) { fieldToDate = textField; } fieldToDate.setTime(fieldToDate.getTime() + UTCOffsetInMiliseconds); convertedData[j][timeFields[i].name] = fieldToDate.getHours() + ':' + fieldToDate.getMinutes() + ':' + fieldToDate.getSeconds(); } } return convertedData; }; //** {{{ OB.Utilities.Date.addTimezoneOffset }}} ** // // Adds to a date its timezone offset // // Parameters: // * {{{date}}}: date in which it be added its timezone offset OB.Utilities.Date.addTimezoneOffset = function (date) { var newDate; if (Object.prototype.toString.call(date) !== '[object Date]') { return date; } newDate = new Date(date.getTime() + (date.getTimezoneOffset() * 60000)); return newDate; }; //** {{{ OB.Utilities.Date.substractTimezoneOffset }}} ** // // Substracts to a date its timezone offset // // Parameters: // * {{{date}}}: date in which it be substracted its timezone offset OB.Utilities.Date.substractTimezoneOffset = function (date) { var newDate; if (Object.prototype.toString.call(date) !== '[object Date]') { return date; } newDate = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)); return newDate; }; //** {{{ OB.Utilities.Date.getUTCOffsetInMiliseconds }}} ** // // Return the offset with UTC measured in miliseconds OB.Utilities.Date.getUTCOffsetInMiliseconds = function () { var UTCHourOffset = isc.Time.getUTCHoursDisplayOffset(new Date()), UTCMinuteOffset = isc.Time.getUTCMinutesDisplayOffset(new Date()); return (UTCHourOffset * 60 * 60 * 1000) + (UTCMinuteOffset * 60 * 1000); }; //** {{{ OB.Utilities.Date.roundToNextQuarter }}} ** // // Round any date to the next quarter OB.Utilities.Date.roundToNextQuarter = function (date) { var newDate = new Date(date), minutes = newDate.getMinutes(), timeBreak = 15; if (newDate.getMilliseconds() === 0 && newDate.getSeconds() === 0 && minutes % timeBreak === 0) { return newDate; } var roundedMinutes = (parseInt((minutes + timeBreak) / timeBreak, 10) * timeBreak) % 60; newDate.setMilliseconds(0); newDate.setSeconds(0); newDate.setMinutes(roundedMinutes); if (roundedMinutes === 0) { newDate.setHours(newDate.getHours() + 1); } return newDate; }; //** {{{ OB.Utilities.Date.roundToNextHalfHour }}} ** // // Round any date to the next half hour OB.Utilities.Date.roundToNextHalfHour = function (date) { var newDate = new Date(date), minutes = newDate.getMinutes(), timeBreak = 30; if (newDate.getMilliseconds() === 0 && newDate.getSeconds() === 0 && minutes % timeBreak === 0) { return newDate; } var roundedMinutes = (parseInt((minutes + timeBreak) / timeBreak, 10) * timeBreak) % 60; newDate.setMilliseconds(0); newDate.setSeconds(0); newDate.setMinutes(roundedMinutes); if (roundedMinutes === 0) { newDate.setHours(newDate.getHours() + 1); } return newDate; }; /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, $ */ enyo.kind({ name: 'OB.UI.MockPayment', components: [{ components: [{ classes: 'row-fluid', components: [{ style: 'float:left; padding-left:30px', name: 'lblType' }, { name: 'paymenttype', style: 'float:right; font-weight: bold; padding-right:30px' }] }, { style: 'clear: both' }, { classes: 'row-fluid', components: [{ style: 'float:left; padding-left:30px', name: 'lblAmount' }, { name: 'paymentamount', style: 'float:right; font-weight: bold; padding-right:30px' }] }] }, { style: 'clear: both' }, { kind: 'OB.UI.MockPayment_OkButton' }], initComponents: function () { this.inherited(arguments); this.$.lblType.setContent(OB.I18N.getLabel('OBPOS_LblModalType')); this.$.lblAmount.setContent(OB.I18N.getLabel('OBPOS_LblModalAmount')); this.$.paymenttype.setContent(this.paymentType); this.$.paymentamount.setContent(OB.I18N.formatCurrency(this.paymentAmount)); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.MockPayment_OkButton', style: 'float: right;', i18nContent: 'OBMOBC_LblOk', isDefaultAction: true, tap: function () { this.owner.receipt.addPayment(new OB.Model.PaymentLine({ 'kind': this.owner.key, 'name': this.owner.paymentType, 'amount': this.owner.paymentAmount, 'allowOpenDrawer': this.owner.allowOpenDrawer, 'isCash': this.owner.isCash, 'openDrawer': this.owner.openDrawer, 'printtwice': this.owner.printtwice })); this.doHideThisPopup(); } }); /* ************************************************************************************ * Copyright (C) 2012-2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone,$,_ */ (function () { // Because of problems with module dependencies, it is possible this object to already // be defined with some rules. var alreadyDefinedRules = (OB && OB.Model && OB.Model.Discounts && OB.Model.Discounts.discountRules) || {}, onLoadActions = (OB && OB.Model && OB.Model.Discounts && OB.Model.Discounts.onLoadActions) || [], i; OB.Model.Discounts = { discountRules: alreadyDefinedRules, executor: new OB.Model.DiscountsExecutor(), preventApplyPromotions: false, applyPromotionsTimeout: {}, applyPromotions: function (receipt, line) { // if the discount algorithm already started, stop pending computations... this.executor.removeGroup('discounts'); // ... and start over this.applyPromotionsLat(receipt, line); }, applyPromotionsLat: function (receipt, line) { var me = this; if (receipt.get('skipApplyPromotions') || this.preventApplyPromotions) { return; } if (OB.POS.modelterminal.hasPermission('OBPOS_discount.newFlow', true)) { var auxReceipt = new OB.Model.Order(), auxLine, hasPromotions, oldLines, oldLines2, actualLines, auxReceipt2, isFirstExecution = true; auxReceipt.clearWith(receipt); auxReceipt.groupLinesByProduct(); me.auxReceiptInExecution = auxReceipt; auxReceipt.on('discountsApplied', function () { // to avoid several calls to applyPromotions, only will be applied the changes to original receipt for the last call done to applyPromotion // so if the auxReceipt is distinct of the last auxReceipt created (last call) then nothing is done if (me.auxReceiptInExecution !== auxReceipt) { return; } var continueApplyPromotions = true; // replace the promotions with applyNext that they were applied previously auxReceipt.removePromotionsCascadeApplied(); // check if the order lines have changed in the last execution of applyPromotions // if they didn't changed, then stop if (!OB.UTIL.isNullOrUndefined(oldLines) && oldLines.size() > 0) { isFirstExecution = false; oldLines2 = new Backbone.Collection(); oldLines.forEach(function (ol) { oldLines2.push(ol); }); oldLines2.forEach(function (ol) { for (i = 0; i < auxReceipt.get('lines').size(); i++) { if (auxReceipt.isSimilarLine(ol, auxReceipt.get('lines').at(i))) { oldLines.remove(ol); break; } } }); if (oldLines.length === 0) { continueApplyPromotions = false; } } else if (!OB.UTIL.isNullOrUndefined(oldLines) && oldLines.size() === 0 && !isFirstExecution) { continueApplyPromotions = false; } if (continueApplyPromotions) { receipt.fillPromotionsWith(auxReceipt, isFirstExecution); if (auxReceipt.hasPromotions()) { auxReceipt.removeQtyOffer(); if (auxReceipt.get('lines').length > 0) { oldLines = new Backbone.Collection(); auxReceipt.get('lines').forEach(function (l) { oldLines.push(l.clone()); }); me.applyPromotionsImp(auxReceipt, undefined, true); } else { receipt.trigger('applyPromotionsFinished'); } } else { receipt.trigger('applyPromotionsFinished'); } } else { receipt.trigger('applyPromotionsFinished'); } }); if (line) { auxLine = _.filter(auxReceipt.get('lines').models, function (l) { if (l !== line && l.get('product').id === line.get('product').id && l.get('price') === line.get('price') && l.get('qty') === line.get('qty')) { return l; } }); } // if preventApplyPromotions then the promotions will not be deleted, because they will not be recalculated if (!this.preventApplyPromotions) { var manualPromotions; _.each(auxReceipt.get('lines').models, function (line) { manualPromotions = _.filter(line.get('promotions'), function (p) { return p.manual === true; }) || []; line.set('promotions', []); line.set('promotionCandidates', []); _.forEach(manualPromotions, function (promo) { var promotion = { rule: new Backbone.Model(promo), definition: { userAmt: promo.userAmt, applyNext: promo.applyNext, lastApplied: promo.lastApplied }, alreadyCalculated: true // to prevent loops }; OB.Model.Discounts.addManualPromotion(auxReceipt, [line], promotion); }); }); _.each(receipt.get('lines').models, function (line) { line.set('promotions', []); line.set('promotionCandidates', []); }); } this.applyPromotionsImp(auxReceipt, null, true); } else { this.applyPromotionsImp(receipt, line, false); } }, applyPromotionsImp: function (receipt, line, skipSave) { var lines; if (this.preventApplyPromotions) { return; } if (receipt && (!receipt.get('isEditable') || (!OB.UTIL.isNullOrUndefined(receipt.get('isNewReceipt')) && receipt.get('isNewReceipt')))) { return; } if (line) { this.executor.addEvent(new Backbone.Model({ id: line.cid, groupId: 'discounts', receipt: receipt, line: line, skipSave: skipSave }), true); } else { lines = receipt.get('lines'); if (lines.length === 0) { // Removing last line, recalculate total receipt.calculateGross(); } else { lines.forEach(function (l) { // with new flow discounts -> skipSave =true // in other case -> false this.applyPromotionsImp(receipt, l, OB.POS.modelterminal.hasPermission('OBPOS_discount.newFlow', true)); }, this); } } }, addManualPromotion: function (receipt, lines, promotion) { var rule = OB.Model.Discounts.discountRules[promotion.rule.get ? promotion.rule.get('discountType') : promotion.rule.discountType]; if (!rule || !rule.addManual) { OB.warn('No manual implemetation for rule ' + promotion.discountType); return; } lines.forEach(function (line) { if (line.get('promotions')) { line.get('promotions').forEach(function (promotion) { promotion.lastApplied = undefined; }); } rule.addManual(receipt, line, promotion); }); if (!promotion.alreadyCalculated) { // Recalculate all promotions again OB.Model.Discounts.applyPromotions(receipt); } }, /** * Gets the list of manual promotions. If asArray param is true, it is returned * as an array, other case, as a comma separated string to be used in sql statements */ getManualPromotions: function (asList) { var p, promos = [], promosSql = ''; for (p in this.discountRules) { if (this.discountRules.hasOwnProperty(p)) { if (this.discountRules[p].addManual) { promos.push(p); } } } if (asList) { return promos; } else { // generate sql for (p = 0; p < promos.length; p++) { if (promosSql !== '') { promosSql += ', '; } promosSql += "'" + promos[p] + "'"; } return promosSql; } }, registerRule: function (name, rule) { this.discountRules[name] = rule; }, standardFilter: "WHERE date('now') BETWEEN DATEFROM AND COALESCE(date(DATETO), date('9999-12-31'))" // + " AND((BPARTNER_SELECTION = 'Y'" // + " AND NOT EXISTS" // + " (SELECT 1" // + " FROM M_OFFER_BPARTNER" // + " WHERE M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND C_BPARTNER_ID = ?" // + " ))" // + " OR(BPARTNER_SELECTION = 'N'" // + " AND EXISTS" // + " (SELECT 1" // + " FROM M_OFFER_BPARTNER" // + " WHERE M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND C_BPARTNER_ID = ?" // + " )))" // + " AND((BP_GROUP_SELECTION = 'Y'" // + " AND NOT EXISTS" // + " (SELECT 1" // + " FROM C_BPARTNER B," // + " M_OFFER_BP_GROUP OB" // + " WHERE OB.M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND B.C_BPARTNER_ID = ?" // + " AND OB.C_BP_GROUP_ID = B.C_BP_GROUP_ID" // + " ))" // + " OR(BP_GROUP_SELECTION = 'N'" // + " AND EXISTS" // + " (SELECT 1" // + " FROM C_BPARTNER B," // + " M_OFFER_BP_GROUP OB" // + " WHERE OB.M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND B.C_BPARTNER_ID = ?" // + " AND OB.C_BP_GROUP_ID = B.C_BP_GROUP_ID" // + " )))" // + " AND((PRODUCT_SELECTION = 'Y'" // + " AND NOT EXISTS" // + " (SELECT 1" // + " FROM M_OFFER_PRODUCT" // + " WHERE M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND M_PRODUCT_ID = ?" // + " ))" // + " OR(PRODUCT_SELECTION = 'N'" // + " AND EXISTS" // + " (SELECT 1" // + " FROM M_OFFER_PRODUCT" // + " WHERE M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND M_PRODUCT_ID = ?" // + " )))" // + " AND((PROD_CAT_SELECTION = 'Y'" // + " AND NOT EXISTS" // + " (SELECT 1" // + " FROM M_PRODUCT P," // + " M_OFFER_PROD_CAT OP" // + " WHERE OP.M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND P.M_PRODUCT_ID = ?" // + " AND OP.M_PRODUCT_CATEGORY_ID = P.M_PRODUCT_CATEGORY_ID" // + " ))" // + " OR(PROD_CAT_SELECTION = 'N'" // + " AND EXISTS" // + " (SELECT 1" // + " FROM M_PRODUCT P," // + " M_OFFER_PROD_CAT OP" // + " WHERE OP.M_OFFER_ID = M_OFFER.M_OFFER_ID" // + " AND P.M_PRODUCT_ID = ?" // + " AND OP.M_PRODUCT_CATEGORY_ID = P.M_PRODUCT_CATEGORY_ID" // + " ))) " // }; // Price Adjustment OB.Model.Discounts.registerRule('5D4BAF6BB86D4D2C9ED3D5A6FC051579', { async: false, implementation: function (discountRule, receipt, line) { var linePrice, discountedLinePrice, qty = line.get('qty'), minQty = discountRule.get('minQuantity'), maxQty = discountRule.get('maxQuantity'); if ((minQty && qty < minQty) || (maxQty && qty > maxQty)) { return; } linePrice = line.get('discountedLinePrice') || line.get('price'); if (discountRule.get('fixedPrice') || discountRule.get('fixedPrice') === 0) { discountedLinePrice = discountRule.get('fixedPrice'); } else { discountedLinePrice = (linePrice - discountRule.get('discountAmount')) * (1 - discountRule.get('discount') / 100); } discountRule.set('qtyOffer', qty); receipt.addPromotion(line, discountRule, { amt: (linePrice - OB.DEC.toNumber(new BigDecimal(String(discountedLinePrice)))) * qty }); line.set('discountedLinePrice', discountedLinePrice); } }); // Because of dependency models cannot be directly registered in promotions module if (OB && OB.Model && OB.Model.Discounts && OB.Model.Discounts.extraModels) { for (i = 0; i < OB.Model.Discounts.extraModels.length; i++) { OB.Data.Registry.registerModel(OB.Model.Discounts.extraModels[i]); } } for (i = 0; i < onLoadActions.length; i++) { if (onLoadActions[i].execute) { onLoadActions[i].execute(); } } }()); /* ************************************************************************************ * Copyright (C) 2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $, _ */ OB.UTIL.HookManager.registerHook('OBMOBC_PreWindowOpen', function (args, callbacks) { var context = args.context, windows = args.windows, errorFunc = function () { OB.error(arguments); }, window; window = _.filter(windows, function (wind) { return wind.route === context.route; }); OB.UTIL.Approval.requestApproval( context.model, window[0].approvalType, function (approved, supervisor, approvalType) { if (approved) { args.cancellation = false; } else { args.cancellation = true; } OB.UTIL.HookManager.callbackExecutor(args, callbacks); }); }); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function () { enyo.kind({ name: 'OBRETUR.UI.MenuReturn', kind: 'OB.UI.MenuAction', permission: 'OBRETUR_Return', i18nLabel: 'OBRETUR_LblReturn', events: { onPaidReceipts: '' }, tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure if (!OB.POS.modelterminal.get('connectedToERP')) { OB.UTIL.showError(OB.I18N.getLabel('OBPOS_OfflineWindowRequiresOnline')); return; } if (OB.POS.modelterminal.hasPermission(this.permission)) { this.doPaidReceipts({ isQuotation: false, isReturn: true }); } } }); // Register the menu... OB.OBPOSPointOfSale.UI.LeftToolbarImpl.prototype.menuEntries.push({ kind: 'OBRETUR.UI.MenuReturn' }); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $, _ */ (function () { enyo.kind({ name: 'OB.UI.CheckboxButtonAll', kind: 'OB.UI.CheckboxButton', classes: 'modal-dialog-btn-check span1', style: 'width: 8%', events: { onCheckedAll: '' }, handlers: { onAllSelected: 'allSelected' }, allSelected: function (inSender, inEvent) { if (inEvent.allSelected) { this.check(); } else { this.unCheck(); } return true; }, tap: function () { this.inherited(arguments); this.doCheckedAll({ checked: this.checked }); } }); enyo.kind({ name: 'OB.UI.CheckboxButtonReturn', kind: 'OB.UI.CheckboxButton', classes: 'modal-dialog-btn-check span1', style: 'width: 8%', handlers: { onCheckAll: 'checkAll' }, events: { onLineSelected: '' }, isGiftCard: false, checkAll: function (inSender, inEvent) { if (this.isGiftCard) { return; } if (inEvent.checked) { this.check(); } else { this.unCheck(); } this.parent.$.quantity.setDisabled(!inEvent.checked); this.parent.$.qtyplus.setDisabled(!inEvent.checked); this.parent.$.qtyminus.setDisabled(!inEvent.checked); }, tap: function () { if (this.isGiftCard) { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_LineCanNotBeSelected')); return; } this.inherited(arguments); this.parent.$.quantity.setDisabled(!this.checked); this.parent.$.qtyplus.setDisabled(!this.checked); this.parent.$.qtyminus.setDisabled(!this.checked); if (this.checked) { this.parent.$.quantity.focus(); } this.doLineSelected({ selected: this.checked }); } }); enyo.kind({ name: 'OB.UI.EditOrderLine', style: 'border-bottom: 1px solid #cccccc; text-align: center; color: black; padding-top: 9px;', handlers: { onApplyChange: 'applyChange' }, events: { onCorrectQty: '' }, isGiftCard: false, applyChange: function (inSender, inEvent) { var me = this; var index = inEvent.lines.indexOf(this.newAttribute); var line, promotionsfactor; if (index !== -1) { if (this.$.checkboxButtonReturn.checked) { var initialQty = inEvent.lines[index].quantity; inEvent.lines[index].quantity = this.$.quantity.getValue(); // update promotions amount to the quantity returned enyo.forEach(this.newAttribute.promotions, function (p) { if (!OB.UTIL.isNullOrUndefined(p)) { p.amt = OB.DEC.mul(p.amt, (me.$.quantity.getValue() / initialQty)); p.actualAmt = OB.DEC.mul(p.actualAmt, (me.$.quantity.getValue() / initialQty)); } }); } else { inEvent.lines.splice(index, 1); } } }, components: [{ kind: 'OB.UI.CheckboxButtonReturn', name: 'checkboxButtonReturn' }, { name: 'product', classes: 'span4', style: 'line-height: 40px; font-size: 17px;' }, { name: 'maxQuantity', classes: 'span2', style: 'line-height: 40px; font-size: 17px; width: 70px;' }, { name: 'qtyminus', kind: 'OB.UI.SmallButton', style: 'width: 40px', classes: 'btnlink-gray btnlink-cashup-edit span1', content: '-', ontap: 'subUnit' }, { kind: 'enyo.Input', type: 'text', classes: 'input span1', style: 'margin-right: 2px; text-align: center;', name: 'quantity', isFirstFocus: true, selectOnFocus: true, autoKeyModifier: 'num-lock', onchange: 'validate' }, { name: 'qtyplus', kind: 'OB.UI.SmallButton', style: 'width: 40px', classes: 'btnlink-gray btnlink-cashup-edit span1', content: '+', ontap: 'addUnit' }, { name: 'price', classes: 'span2', style: 'line-height: 40px; font-size: 17px;' }, { style: 'clear: both;' }], addUnit: function (inSender, inEvent) { var units = parseInt(this.$.quantity.getValue(), 10); if (!isNaN(units) && units < this.$.quantity.getAttribute('max')) { this.$.quantity.setValue(units + 1); this.validate(); } }, subUnit: function (inSender, inEvent) { var units = parseInt(this.$.quantity.getValue(), 10); if (!isNaN(units) && units > this.$.quantity.getAttribute('min')) { this.$.quantity.setValue(units - 1); this.validate(); } }, validate: function () { var value, maxValue; value = this.$.quantity.getValue(); try { value = parseFloat(this.$.quantity.getValue()); } catch (e) { this.addStyles('background-color: red'); this.doCorrectQty({ correctQty: false }); return true; } maxValue = OB.DEC.toNumber(OB.DEC.toBigDecimal(this.$.quantity.getAttribute('max'))); if (!_.isNumber(value) || _.isNaN(value)) { this.addStyles('background-color: red'); this.doCorrectQty({ correctQty: false }); return true; } value = OB.DEC.toNumber(OB.DEC.toBigDecimal(value)); this.$.quantity.setValue(value); if (value > maxValue || value <= 0) { this.addStyles('background-color: red'); this.doCorrectQty({ correctQty: false }); } else { this.addStyles('background-color: white'); this.doCorrectQty({ correctQty: true }); return true; } }, markAsGiftCard: function () { this.isGiftCard = true; this.$.checkboxButtonReturn.isGiftCard = this.isGiftCard; }, tap: function () { if (this.isGiftCard === true) { OB.UTIL.showWarning(OB.I18N.getLabel('OBMOBC_LineCanNotBeSelected')); } }, initComponents: function () { this.inherited(arguments); this.$.product.setContent(this.newAttribute.name); this.$.maxQuantity.setContent(this.newAttribute.quantity); this.$.quantity.setDisabled(true); this.$.qtyplus.setDisabled(true); this.$.qtyminus.setDisabled(true); this.$.quantity.setValue(this.newAttribute.quantity); this.$.quantity.setAttribute('max', this.newAttribute.quantity); this.$.quantity.setAttribute('min', OB.DEC.One); this.$.price.setContent(this.newAttribute.priceIncludesTax ? this.newAttribute.unitPrice : this.newAttribute.baseNetUnitPrice); if (this.newAttribute.promotions.length > 0) { this.$.quantity.addStyles('margin-bottom:0px'); enyo.forEach(this.newAttribute.promotions, function (d) { if (d.hidden) { // continue return; } this.createComponent({ style: 'display: block; color:gray; font-size:13px; line-height: 20px;', components: [{ content: '-- ' + d.name, attributes: { style: 'float: left; width: 60%;' } }, { content: OB.I18N.formatCurrency(-d.amt), attributes: { style: 'float: left; width: 31%; text-align: right;' } }, { style: 'clear: both;' }] }); }, this); } // shipment info if (!OB.UTIL.isNullOrUndefined(this.newAttribute.shiplineNo)) { this.createComponent({ style: 'display: block; color:gray; font-size:13px; line-height: 20px;', components: [{ content: this.newAttribute.shipment + ' - ' + this.newAttribute.shiplineNo, attributes: { style: 'float: left; width: 60%;' } }, { style: 'clear: both;' }] }); } } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ReturnReceiptDialogApply', events: { onApplyChanges: '', onCallbackExecutor: '', onCheckQty: '' }, tap: function () { if (this.doCheckQty()) { return true; } if (this.doApplyChanges()) { this.doCallbackExecutor(); this.doHideThisPopup(); } }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); } }); enyo.kind({ kind: 'OB.UI.ModalDialogButton', name: 'OB.UI.ReturnReceiptDialogCancel', tap: function () { this.doHideThisPopup(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblCancel')); } }); enyo.kind({ name: 'OB.UI.ModalReturnReceipt', kind: 'OB.UI.ModalAction', correctQty: true, handlers: { onApplyChanges: 'applyChanges', onCallbackExecutor: 'callbackExecutor', onCheckedAll: 'checkedAll', onCheckQty: 'checkQty', onCorrectQty: 'changeCorrectQty', onLineSelected: 'lineSelected' }, lineShouldBeIncludedFunctions: [], bodyContent: { kind: 'Scroller', maxHeight: '225px', style: 'background-color: #ffffff;', thumb: true, horizontal: 'hidden', components: [{ name: 'attributes' }] }, bodyButtons: { components: [{ kind: 'OB.UI.ReturnReceiptDialogApply' }, { kind: 'OB.UI.ReturnReceiptDialogCancel' }] }, applyChanges: function (inSender, inEvent) { this.waterfall('onApplyChange', { lines: this.args.args.order.receiptLines }); return true; }, callbackExecutor: function (inSender, inEvent) { var me = this; var nameLocation = ""; OB.Dal.get(OB.Model.BPLocation, me.args.args.order.bpLocId, function (bpLoc) { me.nameLocation = bpLoc.get('name'); }); OB.Dal.get(OB.Model.BusinessPartner, this.args.args.order.bp, function (bp) { me.args.args.context.model.get('order').set('bp', bp); _.each(me.args.args.order.receiptLines, function (line) { _.each(line.promotions, function (promotion) { promotion.amt = -promotion.amt; promotion.actualAmt = -promotion.actualAmt; }); OB.Dal.get(OB.Model.Product, line.id, function (prod) { prod.set('ignorePromotions', true); prod.set('standardPrice', line.priceIncludesTax ? line.unitPrice : line.baseNetUnitPrice); me.args.args.context.model.get('order').createLine(prod, -line.quantity, null, { 'originalOrderLineId': line.lineId, 'originalDocumentNo': me.args.args.order.documentNo, 'skipApplyPromotions': true, 'promotions': line.promotions, 'shipmentlineId': line.shipmentlineId }); me.args.args.cancelOperation = true; bp.set('locId', me.args.args.order.bpLocId); bp.set('locName', me.nameLocation); me.args.args.context.model.get('order').calculateGross(); me.args.args.context.model.get('order').save(); me.args.args.context.model.get('orderList').saveCurrent(); OB.UTIL.HookManager.callbackExecutor(me.args.args, me.args.callbacks); }); }); }); }, checkedAll: function (inSender, inEvent) { if (inEvent.checked) { this.selectedLines = this.numberOfLines; this.allSelected = true; } else { this.selectedLines = 0; this.allSelected = false; } this.waterfall('onCheckAll', { checked: inEvent.checked }); return true; }, checkQty: function (inSender, inEvent) { if (!this.correctQty) { return true; } }, changeCorrectQty: function (inSender, inEvent) { this.correctQty = inEvent.correctQty; }, lineSelected: function (inSender, inEvent) { if (inEvent.selected) { this.selectedLines += 1; } else { this.selectedLines -= 1; } if (this.selectedLines === this.numberOfLines) { this.allSelected = true; this.waterfall('onAllSelected', { allSelected: this.allSelected }); return true; } else { if (this.allSelected) { this.allSelected = false; this.waterfall('onAllSelected', { allSelected: this.allSelected }); } } }, splitShipmentLines: function (lines) { var newlines = []; enyo.forEach(lines, function (line) { if (line.shipmentlines && line.shipmentlines.length > 1) { enyo.forEach(line.shipmentlines, function (sline) { var attr, splitline = {}; for (attr in line) { if (line.hasOwnProperty(attr) && !OB.UTIL.isNullOrUndefined(line[attr]) && typeof line[attr] !== 'object') { splitline[attr] = line[attr]; } } splitline.compname = line.lineId + sline.shipLineId; splitline.quantity = sline.qty; splitline.shiplineNo = sline.shipmentlineNo; splitline.shipment = sline.shipment; splitline.shipmentlineId = sline.shipLineId; // delete confusing properties delete splitline.linegrossamount; delete splitline.warehouse; delete splitline.warehousename; // split promotions splitline.promotions = []; if (line.promotions.length > 0) { enyo.forEach(line.promotions, function (p) { if (!OB.UTIL.isNullOrUndefined(p)) { var attr, splitpromo = {}; for (attr in p) { if (p.hasOwnProperty(attr) && !OB.UTIL.isNullOrUndefined(p[attr]) && typeof p[attr] !== 'object') { splitpromo[attr] = p[attr]; } } splitpromo.amt = OB.DEC.mul(p.amt, (splitline.quantity / line.quantity)); splitpromo.actualAmt = OB.DEC.mul(p.actualAmt, (splitline.quantity / line.quantity)); splitline.promotions.push(splitpromo); } }); } newlines.push(splitline); }, this); } else { line.compname = line.lineId; if (line.shipmentlines.length === 1) { line.shipmentlineId = line.shipmentlines[0].shipLineId; } // delete confusing properties delete line.linegrossamount; delete line.warehouse; delete line.warehousename; newlines.push(line); } }, this); return newlines; }, executeOnShow: function () { var me = this, newArray = []; this.$.bodyContent.$.attributes.destroyComponents(); this.$.header.destroyComponents(); this.$.header.createComponent({ name: 'CheckAllHeaderDocNum', style: 'text-align: center; color: white;', components: [{ content: me.args.args.order.documentNo, name: 'documentNo', classes: 'span12', style: 'line-height: 40px; font-size: 24px;' }, { style: 'clear: both;' }] }); if (!this.$.header.$.checkboxButtonAll) { this.$.header.addStyles('padding-bottom: 0px; margin: 0px; height: 103px;'); this.$.header.createComponent({ name: 'CheckAllHeader', style: 'padding-top: 5px; border-bottom: 3px solid #cccccc; text-align: center; color: black; margin-top: 10px; padding-bottom: 8px; font-weight: bold; background-color: white', components: [{ kind: 'OB.UI.CheckboxButtonAll' }, { content: OB.I18N.getLabel('OBRETUR_LblProductName'), name: 'productNameLbl', classes: 'span4', style: 'line-height: 40px; font-size: 17px;' }, { name: 'maxQtyLbl', content: OB.I18N.getLabel('OBRETUR_LblMaxQty'), classes: 'span2', style: 'line-height: 40px; font-size: 17px; width: 70px;' }, { content: OB.I18N.getLabel('OBRETUR_LblQty'), name: 'qtyLbl', classes: 'span3', style: 'line-height: 40px; font-size: 17px;' }, { content: OB.I18N.getLabel('OBRETUR_LblPrice'), name: 'priceLbl', classes: 'span2', style: 'line-height: 40px; font-size: 17px;' }, { style: 'clear: both;' }] }); } else { this.$.header.$.checkboxButtonAll.unCheck(); } newArray = _.filter(this.args.args.order.receiptLines, function (line) { return line.quantity > 0; }); newArray = this.splitShipmentLines(newArray); this.args.args.order.receiptLines = newArray; this.numberOfLines = 0; this.selectedLines = 0; this.allSelected = false; enyo.forEach(this.args.args.order.receiptLines, function (line) { var isSelectableLine = true; _.each(this.lineShouldBeIncludedFunctions, function (f) { isSelectableLine = isSelectableLine && f.isSelectableLine(line); }); var lineEnyoObject = this.$.bodyContent.$.attributes.createComponent({ kind: 'OB.UI.EditOrderLine', name: 'line_' + line.compname, id: 'OB.UI.id.Returns.Line.' + line.compname, newAttribute: line }); if (!isSelectableLine) { lineEnyoObject.markAsGiftCard(); } this.numberOfLines += 1; }, this); this.$.bodyContent.$.attributes.render(); this.$.header.render(); }, initComponents: function () { this.inherited(arguments); this.attributeContainer = this.$.bodyContent.$.attributes; } }); OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', { kind: 'OB.UI.ModalReturnReceipt', name: 'modalReturnReceipt' }); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function () { OB.UTIL.HookManager.registerHook('OBRETUR_ReturnFromOrig', function (args, callbacks) { var order = args.order, params = args.params, context = args.context; if (params.isReturn) { context.doShowPopup({ popup: 'modalReturnReceipt', args: { args: args, callbacks: callbacks } }); } else { OB.UTIL.HookManager.callbackExecutor(args, callbacks); } return; }); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $, _ */ (function () { OB.UTIL.HookManager.registerHook('OBPOS_PreAddProductToOrder', function (args, callbacks) { var affectedLine = _.filter(args.receipt.get('lines').models, function (line) { return line.get('product') === args.productToAdd; }); if (affectedLine.length > 0 && !_.isUndefined(affectedLine[0].get('originalOrderLineId'))) { args.cancelOperation = true; OB.UTIL.showError(OB.I18N.getLabel('OBRETUR_CannotChangeQty')); } OB.UTIL.HookManager.callbackExecutor(args, callbacks); return; }); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function () { OB.UTIL.HookManager.registerHook('OBPOS_RenderOrderLine', function (args, callbacks) { var orderline = args.orderline; if (orderline.model.get('originalDocumentNo')) { orderline.createComponent({ style: 'display: block;', components: [{ content: '** ' + OB.I18N.getLabel('OBRETUR_LblLineFromOriginal') + orderline.model.get('originalDocumentNo') + ' **', attributes: { style: 'float: left; width: 80%;' } }, { content: '', attributes: { style: 'float: right; width: 20%; text-align: right;' } }, { style: 'clear: both;' }] }); } OB.UTIL.HookManager.callbackExecutor(args, callbacks); return; }); }()); /* ************************************************************************************ * Copyright (C) 2013 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $, _ */ (function () { OB.UTIL.HookManager.registerHook('OBPOS_GroupedProductPreCreateLine', function (args, callbacks) { if (OB.UTIL.isNullOrUndefined(args.line) && !OB.UTIL.isNullOrUndefined(args.allLines)) { args.line = args.allLines.find(function (l) { var affectedByPack = null; if (l.get('product').id === args.p.id && (l.get('qty') > 0 || OB.UTIL.isNullOrUndefined(l.get('originalOrderLineId')))) { affectedByPack = l.isAffectedByPack(); if (!affectedByPack) { return true; } else if ((args.options && args.options.packId === affectedByPack.ruleId) || !(args.options && args.options.packId)) { return true; } } }); } if (!OB.UTIL.isNullOrUndefined(args.line) && !OB.UTIL.isNullOrUndefined(args.line.get('originalOrderLineId'))) { args.cancelOperation = true; args.receipt.createLine(args.p, args.qty, args.options, args.attrs); args.receipt.save(); } OB.UTIL.HookManager.callbackExecutor(args, callbacks); return; }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global Backbone */ (function () { var GiftCard = OB.Data.ExtensibleModel.extend({ modelName: 'GiftCard', tableName: 'giftcard', entityName: 'GiftCard', source: 'org.openbravo.retail.giftcards.master.GiftCard', dataLimit: 300 }); GiftCard.addProperties([{ name: 'id', column: 'giftcard_id', primaryKey: true, type: 'TEXT' },{ name: '_identifier', column: '_identifier', primaryKey: false, type: 'TEXT' },{ name: 'giftCardType', column: 'giftCardType', primaryKey: false, type: 'TEXT' },{ name: 'allowPartialReturn', column: 'allowPartialReturn', primaryKey: false, type: 'TEXT' },{ name: 'amount', column: 'amount', primaryKey: false, type: 'NUMERIC' }]) var GiftCardList = Backbone.Collection.extend({ model: GiftCard }); window.OB = window.OB || {}; window.OB.Model = window.OB.Model || {}; window.OB.Collection = window.OB.Collection || {}; window.OB.Model.GiftCard = GiftCard; window.OB.Collection.GiftCardList = GiftCardList; // add the model to the window. OB.OBPOSPointOfSale.Model.PointOfSale.prototype.models.push(OB.Model.GiftCard); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, $, GCNV */ (function () { var findProductModel = function (id, callback) { OB.Dal.find(OB.Model.Product, { 'id': id }, function successCallbackProducts(dataProducts) { if (dataProducts && dataProducts.length > 0) { callback(dataProducts.at(0)); } else { callback(null); } }, function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); callback(null); }); }; var findGiftCardModel = function (id, callback) { OB.Dal.find(GCNV.Model.GiftCard, { 'id': id }, function successCallbackGiftCard(dataGiftCard) { if (dataGiftCard && dataGiftCard.length > 0) { callback(dataGiftCard.at(0)); } else { callback(null); } }, function errorCallback(tx, error) { OB.UTIL.showError("OBDAL error: " + error); callback(null); }); }; var service = function (source, dataparams, callback, callbackError) { var ajaxRequest = new enyo.Ajax({ url: '../../org.openbravo.retail.posterminal.service.jsonrest/' + source, cacheBust: false, method: 'POST', handleAs: 'json', contentType: 'application/json;charset=utf-8', data: JSON.stringify(dataparams), success: function (inSender, inResponse) { var response = inResponse.response; var status = response.status; if (status === 0) { callback(response.data); } else if (response.errors) { callbackError({ exception: { message: response.errors.id } }); } else { callbackError({ exception: { message: response.error.message } }); } }, fail: function (inSender, inResponse) { callbackError({ exception: { message: OB.I18N.getLabel('OBPOS_MsgApplicationServerNotAvailable'), status: inResponse } }); } }); ajaxRequest.go(ajaxRequest.data).response('success').error('fail'); }; var cancelGiftCard = function (keyboard, receipt, card, success, fail) { if (!receipt.get('isEditable')) { keyboard.doShowPopup({ popup: 'modalNotEditableOrder' }); if (fail) { fail(); } return; } OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.CancelGiftCard', { giftcard: card }, function (result) { OB.UI.GiftCardUtils.findProductModel(result[0].product.id, function (transactionproduct) { // Add properties to product. transactionproduct.set('giftCardTransaction', result[0].transaction.id); transactionproduct.set('isEditablePrice', false); transactionproduct.set('isEditableQty', false); transactionproduct.set('standardPrice', result[0].transaction.amount); transactionproduct.set('ignorePromotions', true); keyboard.doAddProduct({ product: transactionproduct, ignoreStockTab: true }); }); if (success) { success(); } }, function (error) { var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) } }); if (fail) { fail(); } }); }; var consumeGiftCardAmount = function (keyboard, receipt, card, amount, includingTaxes, success, fail) { if (!receipt.get('isEditable')) { keyboard.doShowPopup({ popup: 'modalNotEditableOrder' }); if (fail) { fail(); } return; } var isReturn = receipt.getOrderType() === 1; if (receipt.getPaymentStatus().isNegative && isReturn === false) { amount = -1 * amount; } OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.ConsumeGiftCardAmount', { giftcard: card, amount: amount, isReturn: isReturn }, function (result) { OB.UI.GiftCardUtils.findProductModel(result[0].product.id, function (transactionproduct) { // Add properties to product. transactionproduct.set('giftCardTransaction', result[0].transaction.id); transactionproduct.set('isEditablePrice', false); transactionproduct.set('isEditableQty', false); transactionproduct.set('standardPrice', -result[0].transaction.amount); transactionproduct.set('ignorePromotions', true); transactionproduct.set('currentamt', result[0].currentamt); keyboard.doAddProduct({ product: transactionproduct, ignoreStockTab: true }); }); if (success) { success(); } }, function (error) { var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) } }); if (fail) { fail(); } }); }; var consumeGiftCardLines = function (keyboard, receipt, card, success, fail, options) { if (!receipt.get('isEditable')) { keyboard.doShowPopup({ popup: 'modalNotEditableOrder' }); if (fail) { fail(); } return; } // Calculate the vouchers already used in the lines. var currentvouchers = {}; _.each(receipt.get('lines').models, function (line) { var giftvoucherproduct = line.get('product').get('giftVoucherProduct'); if (giftvoucherproduct) { var giftvoucherqty = line.get('product').get('giftVoucherQuantity'); var voucherinfo = currentvouchers[giftvoucherproduct]; if (!voucherinfo) { voucherinfo = { product: giftvoucherproduct, quantity: 0 }; currentvouchers[giftvoucherproduct] = voucherinfo; } voucherinfo.quantity += giftvoucherqty; } }, this); var lines = []; _.each(receipt.get('lines').models, function (line) { var product = line.get('product').get('id'); var quantity = line.get('qty'); var voucherinfo = currentvouchers[product]; if (voucherinfo) { quantity -= voucherinfo.quantity; } lines.push({ product: product, quantity: quantity, price: line.get('price') }); }, this); OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.ConsumeGiftCardLines', { giftcard: card, lines: lines, isReturn: receipt.get('documentType') === OB.MobileApp.model.get('terminal').terminalType.documentTypeForReturns }, function (result) { if (result.length === 0) { var params = { message: OB.I18N.getLabel('GCNV_ErrorGiftVoucherNotApplied') }; if (options && options.cardType) { if (options.cardType === 'V') { params.header = OB.I18N.getLabel('GCNV_LblDialogGiftVoucher'); } } keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: params }); } else { _.each(result, function (item) { OB.UI.GiftCardUtils.findProductModel(item.product.id, function (transactionproduct) { // Add properties to product. if (item.transaction.quantity < 0) { //is a return but we need to add line as usual item.transaction.quantity = item.transaction.quantity * -1; } transactionproduct.set('giftCardTransaction', item.transaction.id); transactionproduct.set('giftVoucherProduct', item.transaction.product); transactionproduct.set('giftVoucherQuantity', item.transaction.quantity); transactionproduct.set('isEditablePrice', false); transactionproduct.set('isEditableQty', false); transactionproduct.set('standardPrice', -item.price); transactionproduct.set('ignorePromotions', true); var index = 0; var receiptlines = receipt.get('lines'); while (index < receiptlines.length) { if (receiptlines.at(index++).get('product').get('id') === item.transaction.product) { break; } } keyboard.doAddProduct({ product: transactionproduct, qty: item.transaction.quantity, ignoreStockTab: true, options: { at: index } }); }); }, this); } if (success) { success(); } }, function (error) { var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); var params = { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) }; if (options && options.cardType) { if (options.cardType === 'V') { params.header = OB.I18N.getLabel('GCNV_LblDialogGiftVoucher'); params.message = OB.I18N.getLabel('GCNV_ErrorVoucherNotFound', [msgsplit.slice(1)]); } } keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: params }); if (fail) { fail(); } }); }; OB.UI.GiftCardUtils = { findProductModel: findProductModel, service: service, cancelGiftCard: cancelGiftCard, consumeGiftCardAmount: consumeGiftCardAmount, consumeGiftCardLines: consumeGiftCardLines }; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function () { var GiftCard = Backbone.Model.extend({ dataLimit: 300 }); var GiftCardList = Backbone.Collection.extend({ model: GiftCard }); window.GCNV = window.GCNV || {}; window.GCNV.Model = window.GCNV.Model || {}; window.GCNV.Collection = window.GCNV.Collection || {}; window.GCNV.Model.GiftCard = GiftCard; window.GCNV.Collection.GiftCardList = GiftCardList; }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function () { var isGiftCard = function (product, callback) { if (product.get('giftCardTransaction')) { // Is a giftcard product BUT as a discount payment callback(false); } else { OB.Dal.find(window.OB.Model.GiftCard, { 'id': product.get('id') }, function (result) { callback(result.length === 1, result.at(0)); }, function (tx, error) { callback(false); }); } }; var GiftCardID = { kind: 'OB.UI.renderTextProperty', name: 'giftcardid', modelProperty: 'giftcardid', i18nLabel: 'GCNV_LblGiftCardID', applyValue: function (orderline) { if (this.getValue()) { this.doSetLineProperty({ line: orderline, property: this.modelProperty, value: this.getValue() }); return true; } else { this.propertiesDialog.owner.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel('GCNV_LblGiftCardInvalid') } }); return false; } }, showProperty: function (orderline, callback) { // Show the property only for giftcards... isGiftCard(orderline.get('product'), callback); } }; // Register the new property OB.UI.ModalReceiptLinesPropertiesImpl.prototype.newAttributes.unshift(GiftCardID); // Register event to show dialog if a gift card... OB.OBPOSPointOfSale.UI.PointOfSale.prototype.classModel.on('createdLine', function (instwindow, line) { isGiftCard(line.get('product'), function (result, giftcardproduct) { if (result) { line.get('product').set('isEditablePrice', giftcardproduct.get('amount') === null || giftcardproduct.get('amount') === 0); line.get('product').set('isEditableQty', false); instwindow.editLine(null, { args: { autoDismiss: false, requiredFiedls: ['giftcardid'], requiredFieldNotPresentFunction: function (line, field) { line.collection.remove(line); } } }); } }); }, this); OB.UTIL.HookManager.registerHook('OBPOS_PreAddProductToOrder', function (args, callbacks) { var receipt = args.receipt; var product = args.productToAdd; if (receipt.get('orderType') === 1) { isGiftCard(product, function (result, giftcardproduct) { if (result) { // cancel args.context.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel('GCNV_MsgCannotAddGiftCardToReturn', [product.get('_identifier')]) } }); args.cancelOperation = true; } OB.UTIL.HookManager.callbackExecutor(args, callbacks); }); } else { OB.UTIL.HookManager.callbackExecutor(args, callbacks); } }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, $ */ (function () { enyo.kind({ name: 'GCNV.UI.ApplyDialogButton', kind: 'OB.UI.ModalDialogButton', isDefaultAction: true, events: { onHideThisPopup: '', onAcceptButton: '' }, disabled: false, putDisabled: function (state) { if (state === false) { this.setDisabled(false); this.removeClass('disabled'); this.setAttribute('disabled', null); this.disabled = false; } else { this.setDisabled(); this.addClass('disabled'); this.setAttribute('disabled', 'disabled'); this.disabled = true; } }, tap: function () { if (this.disabled) { return; } this.doAcceptButton(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); } }); enyo.kind({ name: 'GCNV.UI.DetailsDialogButton', kind: 'OB.UI.ModalDialogButton', style: 'color: white; background-color: orange;', isDefaultAction: true, events: { onHideThisPopup: '', onDetailsButton: '' }, tap: function () { this.doDetailsButton(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('GCNV_LblDetails')); } }); enyo.kind({ kind: 'OB.UI.ModalAction', name: 'GCNV.UI.apopup', closeOnAcceptButton: true, header: '', events: { onHideThisPopup: '' }, handlers: { onDetailsButton: 'detailsButton', onAcceptButton: 'acceptButton' }, bodyContent: { kind: 'Scroller', maxHeight: '225px', style: 'background-color: #ffffff;', thumb: true, horizontal: 'hidden', components: [{ name: 'attributes', components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', components: [{ name: 'labelLine', style: 'padding: 5px 8px 0px 0px; font-size: 15px;' }] }, { style: 'border: 1px solid #F0F0F0; float: left;', components: [{ name: 'newAttribute', classes: 'modal-dialog-receipt-properties-text', components: [{ name: 'cardentry', kind: 'enyo.Input', type: 'text', classes: 'input', style: 'width: 392px;' }] }] }, { style: 'clear: both' }] }] }] }, bodyButtons: { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'GCNV.UI.DetailsDialogButton', name: 'detailsbutton' }, { kind: 'GCNV.UI.ApplyDialogButton', name: 'okbutton' }, { kind: 'OB.UI.CancelDialogButton' }] }] }, statusLoading: function () { this.$.bodyButtons.$.detailsbutton.setAttribute('disabled', 'disabled'); this.$.bodyContent.$.cardentry.setAttribute('disabled', 'disabled'); this.$.bodyButtons.$.okbutton.setAttribute('disabled', 'disabled'); this.$.bodyButtons.$.okbutton.setContent(OB.I18N.getLabel('GCNV_LblLoading')); }, statusReady: function () { this.$.bodyButtons.$.detailsbutton.setAttribute('disabled', null); this.$.bodyContent.$.cardentry.setAttribute('disabled', null); this.$.bodyContent.$.cardentry.setValue(''); this.$.bodyButtons.$.okbutton.setAttribute('disabled', null); this.$.bodyButtons.$.okbutton.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); }, acceptAction: function () { // execute action defined in arguments... if (this.$.bodyContent.$.cardentry.getValue()) { this.args.action(this); } else { // Gift Card ID cannot be null this.args.keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel('GCNV_LblGiftCardInvalid') } }); } }, acceptButton: function (inSender, inEvent) { this.acceptAction(); }, detailsButton: function (inSender, inEvent) { // Show the details if (this.$.bodyContent.$.cardentry.getValue()) { this.$.bodyButtons.$.detailsbutton.setAttribute('disabled', 'disabled'); this.$.bodyButtons.$.detailsbutton.setContent(OB.I18N.getLabel('GCNV_LblLoading')); var me = this; OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.FindGiftCard', { giftcard: this.$.bodyContent.$.cardentry.getValue(), giftcardtype: this.args.giftcardtype }, function (result) { var giftcard = result[0]; me.args.keyboard.doShowPopup({ popup: 'GCNV_UI_Details', args: { giftcard: giftcard, view: me.args.keyboard, receipt: me.args.keyboard.receipt, amount: me.args.amount } }); me.$.bodyButtons.$.detailsbutton.setAttribute('disabled', null); me.$.bodyButtons.$.detailsbutton.setContent(OB.I18N.getLabel('GCNV_LblDetails')); me.doHideThisPopup(); }, function (error) { var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); me.args.keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) } }); me.$.bodyButtons.$.detailsbutton.setAttribute('disabled', null); me.$.bodyButtons.$.detailsbutton.setContent(OB.I18N.getLabel('GCNV_LblDetails')); }); } else { // Gift Card ID cannot be null this.args.keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel('GCNV_LblGiftCardInvalid') } }); } }, executeOnShow: function () { this.$.header.setContent(this.args.header); this.statusReady(); this.$.bodyButtons.$.detailsbutton.setAttribute('disabled', null); this.$.bodyButtons.$.detailsbutton.setContent(OB.I18N.getLabel('GCNV_LblDetails')); }, initComponents: function () { this.inherited(arguments); this.$.bodyContent.$.labelLine.setContent(OB.I18N.getLabel('GCNV_LblSelectCard')); } }); OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', { kind: 'GCNV.UI.apopup', name: 'GCNV_UI_apopup' }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, $ */ (function () { enyo.kind({ name: 'GCNV.UI.ReturnButton', kind: 'OB.UI.ModalDialogButton', isDefaultAction: true, events: { onHideThisPopup: '', onReturnButton: '' }, disabled: false, putDisabled: function (state) { if (state === false) { this.setDisabled(false); this.removeClass('disabled'); this.setAttribute('disabled', null); this.disabled = false; } else { this.setDisabled(); this.addClass('disabled'); this.setAttribute('disabled', 'disabled'); this.disabled = true; } }, tap: function () { if (this.disabled) { return; } this.doReturnButton(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('GCNV_LblReturn')); } }); enyo.kind({ kind: 'OB.UI.ScrollableTableHeader', name: 'GCNV.UI.SummaryHeader', style: 'padding: 10px; border-bottom: 1px solid #cccccc;', components: [{ style: 'line-height: 27px; font-size: 18px; font-weight: bold;', name: 'title', components: [{ style: 'float: left; text-align: left; width: 60%;', name: 'LblProduct' }, { style: 'float: left; text-align:right; width: 20%;', name: 'LblQuantity' }, { style: 'float: left; text-align:right; width: 20%;', name: 'LblCurrentQuantity' }, { style: 'clear:both;' }] }], initComponents: function () { this.inherited(arguments); this.$.LblProduct.setContent(OB.I18N.getLabel('GCNV_LblProduct')); this.$.LblQuantity.setContent(OB.I18N.getLabel('GCNV_LblQuantity')); this.$.LblCurrentQuantity.setContent(OB.I18N.getLabel('GCNV_LblCurrentQuantity')); } }); enyo.kind({ name: 'GCNV.UI.SummaryRender', // kind: 'OB.UI.SelectButton', components: [{ style: 'float: left; text-align: left; width: 60%;', name: 'product' }, { style: 'float: left; text-align:right; width: 20%;', name: 'quantity' }, { style: 'float: left; text-align:right; width: 20%;', name: 'currentquantity' }, { style: 'clear:both;' }], initComponents: function () { this.inherited(arguments); this.$.product.setContent(this.model.get('product$_identifier')); this.$.quantity.setContent(this.model.get('quantity').toString()); this.$.currentquantity.setContent(this.model.get('currentquantity').toString()); } }); enyo.kind({ kind: 'OB.UI.ModalAction', name: 'GCNV.UI.Details', closeOnAcceptButton: true, header: '', events: { onHideThisPopup: '', onShowDivText: '' }, handlers: { onAcceptButton: 'acceptButton', onReturnButton: 'returnButton' }, bodyContent: { style: 'background-color: #ffffff;', components: [{ components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'LblGiftCardID' }] }, { style: 'float: left;width: 392px;text-align: left; color: black;', name: 'searchkey' }, { style: 'clear: both' }] }] }, { components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'LblStatus' }] }, { style: 'float: left;width: 392px;text-align: left; color: black;', name: 'status' }, { style: 'clear: both' }] }] }, { components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'LblProduct' }] }, { style: 'float: left;width: 392px;text-align: left; color: black;', name: 'product' }, { style: 'clear: both' }] }] }, { components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'LblBusinessPartner' }] }, { style: 'float: left;width: 392px;text-align: left; color: black;', name: 'businesspartner' }, { style: 'clear: both' }] }] }, { name: 'amountcontainer', components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'LblAmount' }] }, { style: 'float: left;width: 392px;text-align: right; color: black;', name: 'amount' }, { style: 'clear: both' }] }] }, { name: 'currentamountcontainer', components: [{ components: [{ style: 'border: 1px solid #F0F0F0; background-color: #E2E2E2; color: black; width: 150px; height: 40px; float: left; text-align: right;', components: [{ style: 'padding: 5px 8px 0px 0px; font-size: 15px;', name: 'LblCurrentAmount' }] }, { style: 'float: left;width: 392px;text-align: right; color: black;', name: 'currentamount' }, { style: 'clear: both' }] }] }, { kind: 'OB.UI.ScrollableTable', maxHeight: '225px', thumb: true, horizontal: 'hidden', style: 'color:black;padding: 10px;', name: 'summary', scrollAreaMaxHeight: '250px', renderHeader: 'GCNV.UI.SummaryHeader', renderEmpty: 'OB.UI.RenderEmpty', renderLine: 'GCNV.UI.SummaryRender' }] }, bodyButtons: { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ kind: 'GCNV.UI.ReturnButton', name: 'returnbutton' }, { kind: 'GCNV.UI.ApplyDialogButton', name: 'okbutton' }, { kind: 'OB.UI.CancelDialogButton' }] }] }, returnButton: function (inSender, inEvent) { var me = this; if (this.args.receipt.get('orderType') === 0) { // must be a return order this.args.view.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel('GCNV_MsgReturnOrder'), cancelButton: true, callback: function () { me.doShowDivText({ permission: 'OBPOS_receipt.return', orderType: 1 }); me.returnExecute(); } } }); } else { this.returnExecute(); } }, returnExecute: function () { var giftcard = this.args.giftcard; var me = this; var consumeOK = function () { if (me.args.okcallback) { me.args.okcallback(); } me.$.bodyButtons.$.returnbutton.setAttribute('disabled', null); me.$.bodyButtons.$.returnbutton.setContent(OB.I18N.getLabel('GCNV_LblReturn')); me.doHideThisPopup(); }; var consumeFail = function () { me.$.bodyButtons.$.returnbutton.setAttribute('disabled', null); me.$.bodyButtons.$.returnbutton.setContent(OB.I18N.getLabel('GCNV_LblReturn')); }; me.$.bodyButtons.$.returnbutton.setAttribute('disabled', 'disabled'); me.$.bodyButtons.$.returnbutton.setContent(OB.I18N.getLabel('GCNV_LblLoading')); // OB.UI.GiftCardUtils.cancelGiftCard(this.args.view, this.args.receipt, giftcard.searchKey, consumeOK, consumeFail); }, acceptButton: function (inSender, inEvent) { var giftcard = this.args.giftcard; var me = this; var consumeOK = function () { if (me.args.okcallback) { me.args.okcallback(); } me.$.bodyButtons.$.okbutton.setAttribute('disabled', null); me.$.bodyButtons.$.okbutton.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); me.doHideThisPopup(); }; var consumeFail = function () { me.$.bodyButtons.$.okbutton.setAttribute('disabled', null); me.$.bodyButtons.$.okbutton.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); }; me.$.bodyButtons.$.okbutton.setAttribute('disabled', 'disabled'); me.$.bodyButtons.$.okbutton.setContent(OB.I18N.getLabel('GCNV_LblLoading')); if (giftcard.amount !== null) { // its a gift card OB.UI.GiftCardUtils.consumeGiftCardAmount(this.args.view, this.args.receipt, giftcard.searchKey, this.args.amount || this.args.receipt.getPending(), this.args.receipt.get('priceIncludesTax'), consumeOK, consumeFail, { cardType: 'G' }); } else { // its a gift voucher OB.UI.GiftCardUtils.consumeGiftCardLines(this.args.view, this.args.receipt, giftcard.searchKey, consumeOK, consumeFail, { cardType: 'V' }); } }, statusReady: function () { var receipt = this.model.get('order'); this.$.bodyButtons.$.okbutton.putDisabled((receipt.getPending() <= 0)); this.$.bodyButtons.$.okbutton.setContent(OB.I18N.getLabel('OBMOBC_LblApply')); this.$.bodyButtons.$.returnbutton.putDisabled(!receipt.get('isEditable') || (receipt.get('orderType') !== 1 && receipt.get('orderType') !== 0)); this.$.bodyButtons.$.returnbutton.setContent(OB.I18N.getLabel('GCNV_LblReturn')); }, statusLoading: function () { this.$.bodyButtons.$.okbutton.setAttribute('disabled', 'disabled'); this.$.bodyButtons.$.okbutton.setContent(OB.I18N.getLabel('GCNV_LblLoading')); this.$.bodyButtons.$.returnbutton.setAttribute('disabled', 'disabled'); this.$.bodyButtons.$.returnbutton.setContent(OB.I18N.getLabel('GCNV_LblLoading')); }, executeOnShow: function () { var giftcard = this.args.giftcard; this.statusReady(); this.$.bodyContent.$.searchkey.setContent(giftcard.searchKey); this.$.bodyContent.$.status.setContent(OB.I18N.getLabel('GCNV_LblStatus-' + giftcard.alertStatus)); this.$.bodyContent.$.product.setContent(giftcard.product$_identifier); this.$.bodyContent.$.businesspartner.setContent(giftcard.businessPartner$_identifier); if (giftcard.amount !== null) { // It's a gift card this.$.header.setContent(OB.I18N.getLabel('GCNV_LblDialogGiftCard')); this.$.bodyContent.$.summary.setShowing(false); this.$.bodyContent.$.amountcontainer.setShowing(true); this.$.bodyContent.$.currentamountcontainer.setShowing(true); this.$.bodyContent.$.amount.setContent(OB.I18N.formatCurrency(giftcard.amount)); this.$.bodyContent.$.currentamount.setContent(OB.I18N.formatCurrency(giftcard.currentamount)); } else { // It's a gift voucher this.$.header.setContent(OB.I18N.getLabel('GCNV_LblDialogGiftVoucher')); this.$.bodyContent.$.summary.setShowing(true); this.$.bodyContent.$.amountcontainer.setShowing(false); this.$.bodyContent.$.currentamountcontainer.setShowing(false); // summary ordered by product identifier. var summarylist = new Backbone.Collection(); summarylist.comparator = function (model) { return model.get('product$_identifier'); }; summarylist.add(giftcard.gCNVGiftCardSummaryList); this.$.bodyContent.$.summary.setCollection(summarylist); } }, initComponents: function () { this.inherited(arguments); this.$.bodyContent.$.LblGiftCardID.setContent(OB.I18N.getLabel('GCNV_LblGiftCardID')); this.$.bodyContent.$.LblStatus.setContent(OB.I18N.getLabel('GCNV_LblStatus')); this.$.bodyContent.$.LblProduct.setContent(OB.I18N.getLabel('GCNV_LblProduct')); this.$.bodyContent.$.LblBusinessPartner.setContent(OB.I18N.getLabel('GCNV_LblBusinessPartner')); this.$.bodyContent.$.LblAmount.setContent(OB.I18N.getLabel('GCNV_LblAmount')); this.$.bodyContent.$.LblCurrentAmount.setContent(OB.I18N.getLabel('GCNV_LblCurrentAmount')); }, init: function (model) { this.model = model; this.$.bodyButtons.$.okbutton.putDisabled(true); } }); OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', { kind: 'GCNV.UI.Details', name: 'GCNV_UI_Details' }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, $ */ (function () { OB.OBPOSPointOfSale.UI.ToolbarPayment.prototype.sideButtons.push({ command: 'PaymentGiftCard', i18nLabel: 'GCNV_BtnPayGiftCard', permission: 'GCNV_PaymentGiftCard', stateless: false, action: function (keyboard, txt) { if (OB.GCNV.usingStandardMode === false) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('GCNV_UnsupportedPaymentMethod'), OB.I18N.getLabel('GCNV_multiorders_gc_notallowed')); return; } var amount = OB.DEC.number(OB.I18N.parseNumber(txt || '')); amount = _.isNaN(amount) ? keyboard.receipt.getPending() : amount; if (amount > keyboard.receipt.getPending()) { keyboard.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel('GCNV_ErrorCannotConsumeAmount') } }); return; } keyboard.doShowPopup({ popup: 'GCNV_UI_apopup', args: { keyboard: keyboard, header: OB.I18N.getLabel('GCNV_HeaderGiftCard', [OB.I18N.formatCurrency(amount)]), giftcardtype: 'G', amount: amount, // Gift Card action: function (dialog) { // Pay with a gift card dialog.statusLoading(); OB.UI.GiftCardUtils.consumeGiftCardAmount(keyboard, keyboard.receipt, dialog.$.bodyContent.$.cardentry.getValue(), amount, keyboard.receipt.get('priceIncludesTax'), function () { // success dialog.doHideThisPopup(); }, function () { // fail dialog.statusReady(); }); } } }); } }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, $ */ (function () { OB.OBPOSPointOfSale.UI.ToolbarPayment.prototype.sideButtons.push({ command: 'PaymentGiftVoucher', i18nLabel: 'GCNV_BtnPayGiftVoucher', permission: 'GCNV_PaymentGiftCard', stateless: true, action: function (keyboard, txt) { if (OB.GCNV.usingStandardMode === false) { OB.UTIL.showConfirmation.display(OB.I18N.getLabel('GCNV_UnsupportedPaymentMethod'), OB.I18N.getLabel('GCNV_multiorders_gv_notallowed')); return; } keyboard.doShowPopup({ popup: 'GCNV_UI_apopup', args: { keyboard: keyboard, header: OB.I18N.getLabel('GCNV_LblDialogGiftVoucher'), giftcardtype: 'V', // Gift Voucher action: function (dialog) { // Pay with a gift voucher dialog.statusLoading(); OB.UI.GiftCardUtils.consumeGiftCardLines(keyboard, keyboard.receipt, dialog.$.bodyContent.$.cardentry.getValue(), function () { // success dialog.doHideThisPopup(); }, function () { // fail dialog.statusReady(); }, { cardType: 'V' }); } } }); } }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function () { // Register event to show dialog if a gift card... OB.OBPOSPointOfSale.UI.PointOfSale.prototype.classModel.on('removedLine', function (instwindow, line) { var transaction = line.get('product').get('giftCardTransaction'); if (transaction) { // cancel transaction OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.CancelGiftCardTransaction', { transaction: transaction }, function (result) { // OK }, function (error) { // FAIL var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); instwindow.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) } }); }); } }, this); OB.UTIL.HookManager.registerHook('OBPOS_PreDeleteCurrentOrder', function (args, callbacks) { var receipt = args.receipt; receipt.get('lines').each(function (line) { var transaction = line.get('product').get('giftCardTransaction'); if (transaction) { // cancel transaction OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.CancelGiftCardTransaction', { transaction: transaction }, function (result) { // OK }, function (error) { // FAIL var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); args.context.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) } }); }); } }); OB.UTIL.HookManager.callbackExecutor(args, callbacks); }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, _, $ */ (function () { enyo.kind({ kind: 'OB.UI.ModalAction', name: 'GCNV.UI.Message', closeOnAcceptButton: true, header: 'label', events: { onHideThisPopup: '' }, handlers: { onAcceptButton: 'acceptButton' }, bodyContent: { name: 'bodymessage', content: 'label' }, bodyButtons: { components: [{ kind: 'GCNV.UI.AcceptMessageButton' }, { kind: 'OB.UI.CancelDialogButton', name: 'cancelButton' }] }, executeOnShow: function () { this.$.header.setContent(this.args.header || OB.I18N.getLabel('GCNV_LblGiftCardHeader')); this.$.bodyContent.$.bodymessage.setContent(this.args.message); this.$.bodyButtons.$.cancelButton.setShowing(this.args.cancelButton); }, acceptButton: function (inSender, inEvent) { this.doHideThisPopup(); if (this.args.callback) { this.args.callback(); } } }); enyo.kind({ name: 'GCNV.UI.AcceptMessageButton', kind: 'OB.UI.ModalDialogButton', classes: 'btnlink btnlink-gray modal-dialog-button', isDefaultAction: true, events: { onHideThisPopup: '', onAcceptButton: '' }, tap: function () { this.doAcceptButton(); }, initComponents: function () { this.inherited(arguments); this.setContent(OB.I18N.getLabel('OBMOBC_LblOk')); } }); OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', { kind: 'GCNV.UI.Message', name: 'GCNV_UI_Message' }); // object.doShowPopup({ // popup: 'GCNV_UI_Message', // args: { // header: header, // message: message, // callback: callback, // cancelButton: true / false // } // }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, GCNV, $ */ (function () { enyo.kind({ name: 'GCNV.UI.SearchHeader', kind: 'OB.UI.ScrollableTableHeader', events: { onSearchAction: '', onClearAction: '' }, components: [{ style: 'padding: 10px;', components: [{ style: 'display: table;', components: [{ style: 'display: table-cell; width: 100%;', components: [{ kind: 'OB.UI.SearchInput', name: 'filterText', style: 'width: 100%', onchange: 'searchAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-gray btn-icon-small btn-icon-clear', style: 'width: 100px; margin: 0px 5px 8px 19px;', ontap: 'clearAction' }] }, { style: 'display: table-cell;', components: [{ kind: 'OB.UI.SmallButton', classes: 'btnlink-yellow btn-icon-small btn-icon-search', style: 'width: 100px; margin: 0px 0px 8px 5px;', ontap: 'searchAction' }] }] }] }], clearAction: function () { this.$.filterText.setValue(''); this.doClearAction(); }, searchAction: function () { this.doSearchAction({ filter: '%' + this.$.filterText.getValue() + '%' }); } }); enyo.kind({ name: 'GCNV.UI.RenderGiftCard', kind: 'OB.UI.SelectButton', components: [{ name: 'line', style: 'line-height: 23px;width: 100%;', components: [{ components: [{ style: 'float: left; text-align: left; width: 30%;', name: 'searchkey' }, { style: 'float: left; text-align:left; width: 70%;', name: 'businesspartner' }, { style: 'clear:both;' }] }, { style: 'color: #888888', name: 'product' }, { style: 'clear: both;' }] }], initComponents: function () { this.inherited(arguments); this.$.searchkey.setContent(this.model.get('searchKey')); this.$.businesspartner.setContent(this.model.get('businessPartner$_identifier')); this.$.product.setContent(this.model.get('product$_identifier')); } }); enyo.kind({ name: 'GCNV.UI.SearchDialog', kind: 'OB.UI.Modal', topPosition: '125px', events: { onHideThisPopup: '', onShowPopup: '', onAddProduct: '' }, handlers: { onSearchAction: 'searchAction', onClearAction: 'clearAction', onChangePaidReceipt: 'changePaidReceipt' }, changedParams: function (value) {}, body: { classes: 'row-fluid', components: [{ classes: 'span12', components: [{ style: 'border-bottom: 1px solid #cccccc;', classes: 'row-fluid', components: [{ classes: 'span12', components: [{ name: 'listgiftcards', kind: 'OB.UI.ScrollableTable', scrollAreaMaxHeight: '400px', renderHeader: 'GCNV.UI.SearchHeader', renderLine: 'GCNV.UI.RenderGiftCard', renderEmpty: 'OB.UI.RenderEmpty' }] }] }] }] }, clearAction: function (inSender, inEvent) { this.prsList.reset(); return true; }, searchAction: function (inSender, inEvent) { var me = this; OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.ListGiftCard', { filter: inEvent.filter, _limit: GCNV.Model.GiftCard.prototype.dataLimit + 1 }, function (result) { me.prsList.reset(result); }, function (error) { var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); me.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) } }); }); return true; }, changePaidReceipt: function (inSender, inEvent) { this.model.get('orderList').addPaidReceipt(inEvent.newPaidReceipt); return true; }, executeOnShow: function () { this.clearAction(); return true; }, showGiftCard: function (giftcardid) { var me = this; OB.UI.GiftCardUtils.service('org.openbravo.retail.giftcards.FindGiftCard', { giftcard: giftcardid }, function (result) { me.doHideThisPopup(); var giftcard = result[0]; me.doShowPopup({ popup: 'GCNV_UI_Details', args: { giftcard: giftcard, view: me, receipt: me.model.get('order') } }); }, function (error) { var msgsplit = (error.exception.message || 'GCNV_ErrorGenericMessage').split(':'); me.doShowPopup({ popup: 'GCNV_UI_Message', args: { message: OB.I18N.getLabel(msgsplit[0], msgsplit.slice(1)) } }); }); }, init: function (model) { this.model = model; this.prsList = new OB.Collection.GiftCardList(); this.$.body.$.listgiftcards.setCollection(this.prsList); this.prsList.on('click', function (model) { this.showGiftCard(model.get('searchKey')); }, this); }, initComponents: function () { this.header = OB.I18N.getLabel('GCNV_LblSearchGiftCards'); this.inherited(arguments); } }); // Register modal in the menu... OB.UI.WindowView.registerPopup('OB.OBPOSPointOfSale.UI.PointOfSale', { kind: 'GCNV.UI.SearchDialog', name: 'GCNV_UI_SearchDialog' }); }()); /* ************************************************************************************ * Copyright (C) 2012 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function () { enyo.kind({ name: 'GCNV.UI.MenuPaidReceipts', kind: 'OB.UI.MenuAction', permission: 'GCNV_PaymentGiftCard', i18nLabel: 'GCNV_LblGiftCards', events: { onShowPopup: '' }, tap: function () { if (this.disabled) { return true; } this.inherited(arguments); // Manual dropdown menu closure this.doShowPopup({ popup: 'GCNV_UI_SearchDialog' }); }, init: function (model) { this.model = model; OB.GCNV = OB.GCNV || {}; OB.GCNV.usingStandardMode = true; if (this.model.get('leftColumnViewManager')) { OB.GCNV.usingStandardMode = this.model.get('leftColumnViewManager').isOrder(); this.model.get('leftColumnViewManager').on('change:currentView', function (changedModel) { if (changedModel.isOrder()) { this.setDisabled(false); OB.GCNV.usingStandardMode = true; return; } if (changedModel.isMultiOrder()) { OB.GCNV.usingStandardMode = false; this.setDisabled(true); return; } }, this); } } }); // Register the menu... OB.OBPOSPointOfSale.UI.LeftToolbarImpl.prototype.menuEntries.push({ kind: 'GCNV.UI.MenuPaidReceipts' }); }()); /* ************************************************************************************ * Copyright (C) 2014 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. ************************************************************************************ */ /*global enyo, Backbone, $ */ (function() { /** * Adds a function into the lineShouldBeIncludedFunctions array of functions of OB.UI.ModalReturnReceipt * * @return {Boolean} true: the receipt line can be selectable, false: the receipt line cannot be selected */ OB.UI.ModalReturnReceipt.prototype.lineShouldBeIncludedFunctions.push({ isSelectableLine: function(receiptLine) { if (!OB.UTIL.isNullOrUndefined(receiptLine.giftCardType)) { return false; } return true; } }); }()); if (window.onerror && window.onerror.name === 'indexErrorHandler') { window.onerror = null; }if (typeof OBStartApplication !== 'undefined' && Object.prototype.toString.call(OBStartApplication) === '[object Function]') { OBStartApplication(); }