2018-01-16 11:34:37 +01:00
|
|
|
flectra.define('web.field_utils', function (require) {
|
2018-01-16 06:58:15 +01:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Field Utils
|
|
|
|
*
|
|
|
|
* This file contains two types of functions: formatting functions and parsing
|
|
|
|
* functions.
|
|
|
|
*
|
|
|
|
* Each field type has to display in string form at some point, but it should be
|
|
|
|
* stored in memory with the actual value. For example, a float value of 0.5 is
|
|
|
|
* represented as the string "0.5" but is kept in memory as a float. A date
|
|
|
|
* (or datetime) value is always stored as a Moment.js object, but displayed as
|
|
|
|
* a string. This file contains all sort of functions necessary to perform the
|
|
|
|
* conversions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
var core = require('web.core');
|
|
|
|
var dom = require('web.dom');
|
|
|
|
var session = require('web.session');
|
|
|
|
var time = require('web.time');
|
|
|
|
var utils = require('web.utils');
|
|
|
|
|
|
|
|
var _t = core._t;
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Formatting
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert binary to bin_size
|
|
|
|
*
|
|
|
|
* @param {string} value base64 representation of the binary (might be already a bin_size!)
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options (note: this parameter is ignored)
|
|
|
|
*
|
|
|
|
* @returns {string} bin_size (which is human-readable)
|
|
|
|
*/
|
|
|
|
function formatBinary(value, field, options) {
|
|
|
|
return utils.binaryToBinsize(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @todo Really? it returns a jQuery element... We should try to avoid this and
|
|
|
|
* let DOM utility functions handle this directly. And replace this with a
|
|
|
|
* function that returns a string so we can get rid of the forceString.
|
|
|
|
*
|
|
|
|
* @param {boolean} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.forceString=false] if true, returns a string
|
|
|
|
* representation of the boolean rather than a jQueryElement
|
|
|
|
* @returns {jQuery|string}
|
|
|
|
*/
|
|
|
|
function formatBoolean(value, field, options) {
|
|
|
|
if (options && options.forceString) {
|
|
|
|
return value ? _t('True') : _t('False');
|
|
|
|
}
|
|
|
|
return dom.renderCheckbox({
|
|
|
|
prop: {
|
|
|
|
checked: value,
|
|
|
|
disabled: true,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing a char. If the value is false, then we return
|
|
|
|
* an empty string.
|
|
|
|
*
|
|
|
|
* @param {string|false} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.escape=false] if true, escapes the formatted value
|
|
|
|
* @param {boolean} [options.isPassword=false] if true, returns '********'
|
|
|
|
* instead of the formatted value
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatChar(value, field, options) {
|
|
|
|
value = typeof value === 'string' ? value : '';
|
|
|
|
if (options && options.isPassword) {
|
|
|
|
return _.str.repeat('*', value ? value.length : 0);
|
|
|
|
}
|
|
|
|
if (options && options.escape) {
|
|
|
|
value = _.escape(value);
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing a date. If the value is false, then we return
|
|
|
|
* an empty string. Note that this is dependant on the localization settings
|
|
|
|
*
|
|
|
|
* @param {Moment|false} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.timezone=true] use the user timezone when formating the
|
|
|
|
* date
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatDate(value, field, options) {
|
|
|
|
if (value === false) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
if (field && field.type === 'datetime') {
|
|
|
|
if (!options || !('timezone' in options) || options.timezone) {
|
|
|
|
value = value.clone().add(session.getTZOffset(value), 'minutes');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var date_format = time.getLangDateFormat();
|
|
|
|
return value.format(date_format);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing a datetime. If the value is false, then we
|
|
|
|
* return an empty string. Note that this is dependant on the localization
|
|
|
|
* settings
|
|
|
|
*
|
|
|
|
* @params {Moment|false}
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.timezone=true] use the user timezone when formating the
|
|
|
|
* date
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatDateTime(value, field, options) {
|
|
|
|
if (value === false) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
if (!options || !('timezone' in options) || options.timezone) {
|
|
|
|
value = value.clone().add(session.getTZOffset(value), 'minutes');
|
|
|
|
}
|
|
|
|
return value.format(time.getLangDatetimeFormat());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing a float. The result takes into account the
|
|
|
|
* user settings (to display the correct decimal separator).
|
|
|
|
*
|
|
|
|
* @param {float|false} value the value that should be formatted
|
|
|
|
* @param {Object} [field] a description of the field (returned by fields_get
|
|
|
|
* for example). It may contain a description of the number of digits that
|
|
|
|
* should be used.
|
|
|
|
* @param {Object} [options] additional options to override the values in the
|
|
|
|
* python description of the field.
|
|
|
|
* @param {integer[]} [options.digits] the number of digits that should be used,
|
|
|
|
* instead of the default digits precision in the field.
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatFloat(value, field, options) {
|
|
|
|
if (value === false) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
var l10n = core._t.database.parameters;
|
|
|
|
var precision;
|
|
|
|
if (options && options.digits) {
|
|
|
|
precision = options.digits[1];
|
|
|
|
} else if (field && field.digits) {
|
|
|
|
precision = field.digits[1];
|
|
|
|
} else {
|
|
|
|
precision = 2;
|
|
|
|
}
|
|
|
|
var formatted = _.str.sprintf('%.' + precision + 'f', value || 0).split('.');
|
|
|
|
formatted[0] = utils.insert_thousand_seps(formatted[0]);
|
|
|
|
return formatted.join(l10n.decimal_point);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing a time value, from a float. The idea is that
|
|
|
|
* we sometimes want to display something like 1:45 instead of 1.75, or 0:15
|
|
|
|
* instead of 0.25.
|
|
|
|
*
|
|
|
|
* @param {float} value
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatFloatTime(value) {
|
|
|
|
var pattern = '%02d:%02d';
|
|
|
|
if (value < 0) {
|
|
|
|
value = Math.abs(value);
|
|
|
|
pattern = '-' + pattern;
|
|
|
|
}
|
|
|
|
var hour = Math.floor(value);
|
|
|
|
var min = Math.round((value % 1) * 60);
|
|
|
|
if (min === 60){
|
|
|
|
min = 0;
|
|
|
|
hour = hour + 1;
|
|
|
|
}
|
|
|
|
return _.str.sprintf(pattern, hour, min);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing an integer. If the value is false, then we
|
|
|
|
* return an empty string.
|
|
|
|
*
|
|
|
|
* @param {integer|false} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.isPassword=false] if true, returns '********'
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatInteger(value, field, options) {
|
|
|
|
if (options && options.isPassword) {
|
|
|
|
return _.str.repeat('*', String(value).length);
|
|
|
|
}
|
|
|
|
if (!value && value !== 0) {
|
|
|
|
// previously, it returned 'false'. I don't know why. But for the Pivot
|
|
|
|
// view, I want to display the concept of 'no value' with an empty
|
|
|
|
// string.
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return utils.insert_thousand_seps(_.str.sprintf('%d', value));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing an many2one. If the value is false, then we
|
|
|
|
* return an empty string. Note that it accepts two types of input parameters:
|
|
|
|
* an array, in that case we assume that the many2one value is of the form
|
|
|
|
* [id, nameget], and we return the nameget, or it can be an object, and in that
|
|
|
|
* case, we assume that it is a record from a BasicModel.
|
|
|
|
*
|
|
|
|
* @param {Array|Object|false} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.escape=false] if true, escapes the formatted value
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatMany2one(value, field, options) {
|
|
|
|
value = value && (_.isArray(value) ? value[1] : value.data.display_name) || '';
|
|
|
|
if (options && options.escape) {
|
|
|
|
value = _.escape(value);
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string indicating the number of records in the relation.
|
|
|
|
*
|
|
|
|
* @param {Object} value a valid element from a BasicModel, that represents a
|
|
|
|
* list of values
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatX2Many(value) {
|
|
|
|
if (value.data.length === 0) {
|
|
|
|
return _t('No records');
|
|
|
|
} else if (value.data.length === 1) {
|
|
|
|
return _t('1 record');
|
|
|
|
} else {
|
|
|
|
return value.data.length + _t(' records');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing a monetary value. The result takes into account
|
|
|
|
* the user settings (to display the correct decimal separator, currency, ...).
|
|
|
|
*
|
|
|
|
* @param {float|false} value the value that should be formatted
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (returned by fields_get for example). It
|
|
|
|
* may contain a description of the number of digits that should be used.
|
|
|
|
* @param {Object} [options]
|
|
|
|
* additional options to override the values in the python description of
|
|
|
|
* the field.
|
|
|
|
* @param {Object} [options.currency] the description of the currency to use
|
|
|
|
* @param {integer} [options.currency_id]
|
|
|
|
* the id of the 'res.currency' to use (ignored if options.currency)
|
|
|
|
* @param {string} [options.currency_field]
|
|
|
|
* the name of the field whose value is the currency id
|
|
|
|
* (ignore if options.currency or options.currency_id)
|
|
|
|
* Note: if not given it will default to the field currency_field value
|
|
|
|
* or to 'currency_id'.
|
|
|
|
* @param {Object} [options.data]
|
|
|
|
* a mapping of field name to field value, required with
|
|
|
|
* options.currency_field
|
|
|
|
* @param {integer[]} [options.digits]
|
|
|
|
* the number of digits that should be used, instead of the default
|
|
|
|
* digits precision in the field. Note: if the currency defines a
|
|
|
|
* precision, the currency's one is used.
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function formatMonetary(value, field, options) {
|
|
|
|
if (value === false) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
options = options || {};
|
|
|
|
|
|
|
|
var currency = options.currency;
|
|
|
|
if (!currency) {
|
|
|
|
var currency_id = options.currency_id;
|
|
|
|
if (!currency_id && options.data) {
|
|
|
|
var currency_field = options.currency_field || field.currency_field || 'currency_id';
|
|
|
|
currency_id = options.data[currency_field] && options.data[currency_field].res_id;
|
|
|
|
}
|
|
|
|
currency = session.get_currency(currency_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
var digits = (currency && currency.digits) || options.digits;
|
|
|
|
if (options.field_digits === true) {
|
|
|
|
digits = field.digits || digits;
|
|
|
|
}
|
|
|
|
var formatted_value = formatFloat(value, field, {
|
|
|
|
digits: digits,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!currency || options.noSymbol) {
|
|
|
|
return formatted_value;
|
|
|
|
}
|
|
|
|
if (currency.position === "after") {
|
|
|
|
return formatted_value += ' ' + currency.symbol;
|
|
|
|
} else {
|
|
|
|
return currency.symbol + ' ' + formatted_value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string representing the value of the selection.
|
|
|
|
*
|
|
|
|
* @param {string|false} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.escape=false] if true, escapes the formatted value
|
|
|
|
*/
|
|
|
|
function formatSelection(value, field, options) {
|
|
|
|
var val = _.find(field.selection, function (option) {
|
|
|
|
return option[0] === value;
|
|
|
|
});
|
|
|
|
if (!val) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
value = val[1];
|
|
|
|
if (options && options.escape) {
|
|
|
|
value = _.escape(value);
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Parse
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an Date object
|
|
|
|
* The method toJSON return the formated value to send value server side
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.isUTC] the formatted date is utc
|
|
|
|
* @param {boolean} [options.timezone=false] format the date after apply the timezone
|
|
|
|
* offset
|
|
|
|
* @returns {Moment|false} Moment date object
|
|
|
|
*/
|
|
|
|
function parseDate(value, field, options) {
|
|
|
|
if (!value) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
var datePattern = time.getLangDateFormat();
|
|
|
|
var datePatternWoZero = datePattern.replace('MM','M').replace('DD','D');
|
|
|
|
var date;
|
|
|
|
if (options && options.isUTC) {
|
|
|
|
date = moment.utc(value);
|
|
|
|
} else {
|
|
|
|
date = moment.utc(value, [datePattern, datePatternWoZero, moment.ISO_8601], true);
|
|
|
|
}
|
|
|
|
if (date.isValid()) {
|
|
|
|
if (date.year() === 0) {
|
|
|
|
date.year(moment.utc().year());
|
|
|
|
}
|
|
|
|
if (date.year() >= 1900) {
|
|
|
|
date.toJSON = function () {
|
|
|
|
return this.clone().locale('en').format('YYYY-MM-DD');
|
|
|
|
};
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new Error(_.str.sprintf(core._t("'%s' is not a correct date"), value));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an Date object
|
|
|
|
* The method toJSON return the formated value to send value server side
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (note: this parameter is ignored)
|
|
|
|
* @param {Object} [options] additional options
|
|
|
|
* @param {boolean} [options.isUTC] the formatted date is utc
|
|
|
|
* @param {boolean} [options.timezone=false] format the date after apply the timezone
|
|
|
|
* offset
|
|
|
|
* @returns {Moment|false} Moment date object
|
|
|
|
*/
|
|
|
|
function parseDateTime(value, field, options) {
|
|
|
|
if (!value) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
var datePattern = time.getLangDateFormat(),
|
|
|
|
timePattern = time.getLangTimeFormat();
|
|
|
|
var datePatternWoZero = datePattern.replace('MM','M').replace('DD','D'),
|
|
|
|
timePatternWoZero = timePattern.replace('HH','H').replace('mm','m').replace('ss','s');
|
|
|
|
var pattern1 = datePattern + ' ' + timePattern;
|
|
|
|
var pattern2 = datePatternWoZero + ' ' + timePatternWoZero;
|
|
|
|
var datetime;
|
|
|
|
if (options && options.isUTC) {
|
|
|
|
// phatomjs crash if we don't use this format
|
|
|
|
datetime = moment.utc(value.replace(' ', 'T') + 'Z');
|
|
|
|
} else {
|
|
|
|
datetime = moment.utc(value, [pattern1, pattern2, moment.ISO_8601], true);
|
|
|
|
if (options && options.timezone) {
|
|
|
|
datetime.add(-session.getTZOffset(datetime), 'minutes');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (datetime.isValid()) {
|
|
|
|
if (datetime.year() === 0) {
|
|
|
|
datetime.year(moment.utc().year());
|
|
|
|
}
|
|
|
|
if (datetime.year() >= 1900) {
|
|
|
|
datetime.toJSON = function () {
|
|
|
|
return this.clone().locale('en').format('YYYY-MM-DD HH:mm:ss');
|
|
|
|
};
|
|
|
|
return datetime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new Error(_.str.sprintf(core._t("'%s' is not a correct datetime"), value));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a String containing number in language formating
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* The string to be parsed with the setting of thousands and
|
|
|
|
* decimal separator
|
|
|
|
* @returns {float|NaN} the number value contained in the string representation
|
|
|
|
*/
|
|
|
|
function parseNumber(value) {
|
|
|
|
if (core._t.database.parameters.thousands_sep) {
|
|
|
|
var escapedSep = _.str.escapeRegExp(core._t.database.parameters.thousands_sep);
|
|
|
|
value = value.replace(new RegExp(escapedSep, 'g'), '');
|
|
|
|
}
|
|
|
|
if (core._t.database.parameters.decimal_point) {
|
|
|
|
value = value.replace(core._t.database.parameters.decimal_point, '.');
|
|
|
|
}
|
|
|
|
return Number(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a String containing float in language formating
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* The string to be parsed with the setting of thousands and
|
|
|
|
* decimal separator
|
|
|
|
* @returns {float}
|
|
|
|
* @throws {Error} if no float is found respecting the language configuration
|
|
|
|
*/
|
|
|
|
function parseFloat(value) {
|
|
|
|
var parsed = parseNumber(value);
|
|
|
|
if (isNaN(parsed)) {
|
|
|
|
throw new Error(_.str.sprintf(core._t("'%s' is not a correct float"), value));
|
|
|
|
}
|
|
|
|
return parsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a String containing currency symbol and returns amount
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* The string to be parsed
|
|
|
|
* We assume that a monetary is always a pair (symbol, amount) separated
|
|
|
|
* by a non breaking space. A simple float can also be accepted as value
|
|
|
|
* @param {Object} [field]
|
|
|
|
* a description of the field (returned by fields_get for example).
|
|
|
|
* @param {Object} [options] additional options.
|
|
|
|
* @param {Object} [options.currency] - the description of the currency to use
|
|
|
|
* @param {integer} [options.currency_id]
|
|
|
|
* the id of the 'res.currency' to use (ignored if options.currency)
|
|
|
|
* @param {string} [options.currency_field]
|
|
|
|
* the name of the field whose value is the currency id
|
|
|
|
* (ignore if options.currency or options.currency_id)
|
|
|
|
* Note: if not given it will default to the field currency_field value
|
|
|
|
* or to 'currency_id'.
|
|
|
|
* @param {Object} [options.data]
|
|
|
|
* a mapping of field name to field value, required with
|
|
|
|
* options.currency_field
|
|
|
|
*
|
|
|
|
* @returns {float} the float value contained in the string representation
|
|
|
|
* @throws {Error} if no float is found or if parameter does not respect monetary condition
|
|
|
|
*/
|
|
|
|
function parseMonetary(value, field, options) {
|
|
|
|
var values = value.split(' ');
|
|
|
|
if (values.length === 1) {
|
|
|
|
return parseFloat(value);
|
|
|
|
}
|
|
|
|
else if (values.length !== 2) {
|
|
|
|
throw new Error(_.str.sprintf(core._t("'%s' is not a correct monetary field"), value));
|
|
|
|
}
|
|
|
|
options = options || {};
|
|
|
|
var currency = options.currency;
|
|
|
|
if (!currency) {
|
|
|
|
var currency_id = options.currency_id;
|
|
|
|
if (!currency_id && options.data) {
|
|
|
|
var currency_field = options.currency_field || field.currency_field || 'currency_id';
|
|
|
|
currency_id = options.data[currency_field] && options.data[currency_field].res_id;
|
|
|
|
}
|
|
|
|
currency = session.get_currency(currency_id);
|
|
|
|
}
|
|
|
|
return parseFloat(values[0] === currency.symbol ? values[1] : values[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseFloatTime(value) {
|
|
|
|
var factor = 1;
|
|
|
|
if (value[0] === '-') {
|
|
|
|
value = value.slice(1);
|
|
|
|
factor = -1;
|
|
|
|
}
|
|
|
|
var float_time_pair = value.split(":");
|
|
|
|
if (float_time_pair.length !== 2)
|
|
|
|
return factor * parseFloat(value);
|
|
|
|
var hours = parseInteger(float_time_pair[0]);
|
|
|
|
var minutes = parseInteger(float_time_pair[1]);
|
|
|
|
return factor * (hours + (minutes / 60));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a String containing integer with language formating
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* The string to be parsed with the setting of thousands and
|
|
|
|
* decimal separator
|
|
|
|
* @returns {integer}
|
|
|
|
* @throws {Error} if no integer is found respecting the language configuration
|
|
|
|
*/
|
|
|
|
function parseInteger(value) {
|
|
|
|
var parsed = parseNumber(value);
|
|
|
|
// do not accept not numbers or float values
|
|
|
|
if (isNaN(parsed) || parsed % 1 || parsed < -2147483648 || parsed > 2147483647) {
|
|
|
|
throw new Error(_.str.sprintf(core._t("'%s' is not a correct integer"), value));
|
|
|
|
}
|
|
|
|
return parsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates an object with id and display_name.
|
|
|
|
*
|
|
|
|
* @param {Array|number|string|Object} value
|
|
|
|
* The given value can be :
|
|
|
|
* - an array with id as first element and display_name as second element
|
|
|
|
* - a number or a string representing the id (the display_name will be
|
|
|
|
* returned as undefined)
|
|
|
|
* - an object, simply returned untouched
|
|
|
|
* @returns {Object} (contains the id and display_name)
|
|
|
|
* Note: if the given value is not an array, a string or a
|
|
|
|
* number, the value is returned untouched.
|
|
|
|
*/
|
|
|
|
function parseMany2one(value) {
|
|
|
|
if (_.isArray(value)) {
|
|
|
|
return {
|
|
|
|
id: value[0],
|
|
|
|
display_name: value[1],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (_.isNumber(value) || _.isString(value)) {
|
|
|
|
return {
|
|
|
|
id: parseInt(value, 10),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
format: {
|
|
|
|
binary: formatBinary,
|
|
|
|
boolean: formatBoolean,
|
|
|
|
char: formatChar,
|
|
|
|
date: formatDate,
|
|
|
|
datetime: formatDateTime,
|
|
|
|
float: formatFloat,
|
|
|
|
float_time: formatFloatTime,
|
|
|
|
html: _.identity, // todo
|
|
|
|
integer: formatInteger,
|
|
|
|
many2many: formatX2Many,
|
|
|
|
many2one: formatMany2one,
|
|
|
|
monetary: formatMonetary,
|
|
|
|
one2many: formatX2Many,
|
|
|
|
reference: formatMany2one,
|
|
|
|
selection: formatSelection,
|
|
|
|
text: formatChar,
|
|
|
|
},
|
|
|
|
parse: {
|
|
|
|
binary: _.identity,
|
|
|
|
boolean: _.identity, // todo
|
|
|
|
char: _.identity, // todo
|
|
|
|
date: parseDate, // todo
|
|
|
|
datetime: parseDateTime, // todo
|
|
|
|
float: parseFloat,
|
|
|
|
float_time: parseFloatTime,
|
|
|
|
html: _.identity, // todo
|
|
|
|
integer: parseInteger,
|
|
|
|
many2many: _.identity, // todo
|
|
|
|
many2one: parseMany2one,
|
|
|
|
monetary: parseMonetary,
|
|
|
|
one2many: _.identity,
|
|
|
|
reference: parseMany2one,
|
|
|
|
selection: _.identity, // todo
|
|
|
|
text: _.identity, // todo
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|