Browse Source

Merge d06ef1fb4b into d736ee4460

pull/754/merge
Hoang Gia Minh 5 years ago
committed by GitHub
parent
commit
58cc1c0b14
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 82
      web_widget_float_formula/README.rst
  2. 0
      web_widget_float_formula/__init__.py
  3. 22
      web_widget_float_formula/__manifest__.py
  4. BIN
      web_widget_float_formula/static/description/icon.png
  5. 103
      web_widget_float_formula/static/src/js/web_widget_float_formula.js
  6. 102
      web_widget_float_formula/static/tests/js/test_web_widget_float_formula.js
  7. 5
      web_widget_float_formula/tests/__init__.py
  8. 16
      web_widget_float_formula/tests/test_js.py
  9. 21
      web_widget_float_formula/views/web_widget_float_formula.xml

82
web_widget_float_formula/README.rst

@ -0,0 +1,82 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
========================
Formulas in Float Fields
========================
This module allows the use of simple math formulas in integer/float fields
(e.g. "=45 + 4/3 - 5 * (2 + 1)").
* Only supports parentheses, decimal points, thousands separators, and the
operators "+", "-", "*", and "/"
* Will use the decimal point and thousands separator characters associated
with your language
* If the formula is valid, the result will be computed and displayed, and the
formula will be stored for editing
* If the formula is not valid, it's retained in the field as text
**Technical Details**
* Overloads web.form_widgets.FieldFloat (so it works for fields.integer &
fields.float)
* Uses the eval() JS function to evaluate the formula
* Does not do any rounding (this is handled elsewhere)
* Avoids code injection by applying strict regex to formula prior to eval()
(e.g. "=alert('security')" would not get evaluated)
Installation
============
To install this module, simply follow the standard install process.
Configuration
=============
No configuration is needed or possible.
Usage
=====
Install and enjoy. A short demo video can be found at
http://www.youtube.com/watch?v=jQGdD34WYrA.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/162/10.0
Known Issues / Roadmap
======================
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smash it by providing detailed and welcomed
feedback.
Credits
=======
Contributors
------------
* Sylvain Le Gal (https://twitter.com/legalsylvain)
* Oleg Bulkin <o.bulkin@gmail.com>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

0
web_widget_float_formula/__init__.py

22
web_widget_float_formula/__manifest__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Copyright GRAP
# Copyright 2016 LasLabs Inc.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Web Widget - Formulas in Float Fields',
'summary': 'Allow use of simple formulas in float fields',
'version': '11.0.1.0.0',
'category': 'Web',
'author': 'GRAP, LasLabs, Odoo Community Association (OCA)',
'website': 'http://www.grap.coop',
'license': 'AGPL-3',
'depends': [
'web',
],
'data': [
'views/web_widget_float_formula.xml',
],
'installable': True,
'application': False,
}

BIN
web_widget_float_formula/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 3.0 KiB

103
web_widget_float_formula/static/src/js/web_widget_float_formula.js

@ -0,0 +1,103 @@
/**
* Copyright GRAP
* Copyright 2016 LasLabs Inc.
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
**/
odoo.define('web_widget_float_formula', function(require) {
"use strict";
var core = require('web.core');
var basic_fields = require('web.basic_fields');
var FieldFloat = basic_fields.FieldFloat;
FieldFloat.include({
start: function() {
this._super();
this.on('blurred', this, this._compute_result);
this.on('focused', this, this._display_formula);
this.setUpFocus();
},
setUpFocus: function() {
var self = this;
this.$el.on({
focus: function() { self.trigger('focused'); },
blur: function() { self.trigger('blurred'); }
});
},
commitChanges: function() {
this._compute_result();
},
_formula_text: '',
_clean_formula_text: function() {
this._formula_text = '';
},
_process_formula: function(formula) {
try{
formula = formula.toString();
} catch (ex) {
return false;
}
var clean_formula = formula.toString().replace(/^\s+|\s+$/g, '');
if (clean_formula[0] == '=') {
clean_formula = clean_formula.substring(1);
var myreg = new RegExp('[0-9]|\\s|\\.|,|\\(|\\)|\\+|\\-|\\*|\\/', 'g');
if (clean_formula.replace(myreg, '') === '') {
return clean_formula;
}
}
return false;
},
_eval_formula: function(formula) {
// Import localization values used to eval formula
var translation_params = core._t.database.parameters;
var decimal_point = translation_params.decimal_point;
var thousands_sep = translation_params.thousands_sep;
var value;
formula = formula.replace(thousands_sep, '').replace(decimal_point, '.');
try {
value = eval(formula);
}
catch(e) {}
if (typeof value != 'undefined') {
return value;
}
return false;
},
_compute_result: function() {
this._clean_formula_text();
var input = this.$input.val();
var formula = this._process_formula(input);
if (formula !== false) {
var value = this._eval_formula(formula);
if (value !== false) {
this._formula_text = "=" + formula;
var decimal_point = core._t.database.parameters.decimal_point;
// _setValue
this._setValue(value.toString().replace(decimal_point, '.'))
this._render();
}
}
},
// Display the formula stored in the field to allow modification
_display_formula: function() {
if (this._formula_text !== '') {
this.$input.val(this._formula_text);
}
},
});
});

102
web_widget_float_formula/static/tests/js/test_web_widget_float_formula.js

@ -0,0 +1,102 @@
/**
* Copyright 2016 LasLabs Inc.
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
**/
odoo.define('web_widget_float_formula', function(require) {
"use strict";
var core = require('web.core');
var testUtils = require('web.test_utils');
var FormView = require('web.FormView');
var createView = testUtils.createView;
var triggerKeypressEvent = testUtils.triggerKeypressEvent;
var assertClose = function(assert, actual, expected, message) {
var pass = Math.abs(actual - expected) < 0.00001;
assert.pushResult({
result: pass,
actual: actual,
expected: expected,
message: message
});
}
QUnit.module('web_widget_float_formula', {
beforeEach: function() {
this.data = {
foo: {
fields: {
bar: { string: "Bar", type: "float" }
},
records: [
{ id: 1, bar: 1.2 }
]
}
};
}
});
QUnit.test('Float fields in form view', function(assert) {
assert.expect(8);
var form = createView({
View: FormView,
model: 'foo',
data: this.data,
res_id: 1,
arch: '<form><field name="bar"/></form>',
viewOptions: {
mode: 'edit',
},
mockRPC: function (route, args) {
if (args.method === 'write') {
assert.step('save');
}
return this._super.apply(this, arguments);
},
});
assertClose(assert, form.$('input').val(), 1.2);
form.$('input').val('=(1 + 2) / 3').blur();
assertClose(assert, form.$('input').val(), 1,
'blur event should trigger compute event');
form.$('input').focus();
assert.strictEqual(form.$('input').val(), '=(1 + 2) / 3',
'focus event should display the forumla');
form.$('input').val('=(1 * 2x) /').blur();
assert.strictEqual(form.$('input').val(), '=(1 * 2x) /',
'invalid formula should not be calculated');
_.extend(core._t.database.parameters, {
grouping: [3, 0],
decimal_point: ',',
thousands_sep: '.'
});
form.$('input').val('=2.000*3,5').blur();
assert.strictEqual(form.$('input').val(), "7.000,00",
'eval should handle decimal point and thousands separator properly');
_.extend(core._t.database.parameters, {
grouping: [3, 0],
decimal_point: '.',
thousands_sep: ','
});
form.$('input').val('=3-2');
form.$buttons.find('.o_form_button_save').click();
assert.verifySteps(['save'], 'should have saved');
assertClose(assert, form.$('.o_field_widget').text(), 1,
'save should also trigger compute result')
form.destroy();
});
});

5
web_widget_float_formula/tests/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2016 LasLabs Inc.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_js

16
web_widget_float_formula/tests/test_js.py

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Copyright 2016 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
import odoo.tests
class FloatFormulaSuite(odoo.tests.HttpCase):
def test_js(self):
self.phantom_js(
"/web/tests?module=web_widget_float_formula",
"",
"",
login="admin"
)

21
web_widget_float_formula/views/web_widget_float_formula.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright GRAP
Copyright 2016 LasLabs Inc.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<template id="assets_backend" name="web_widget_float_formula Assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/web_widget_float_formula/static/src/js/web_widget_float_formula.js"/>
</xpath>
</template>
<template id="qunit_suite" name="web_widget_float_formula Test Assets" inherit_id="web.qunit_suite">
<xpath expr="//t[@t-set='head']" position="inside">
<script type="text/javascript" src="/web_widget_float_formula/static/tests/js/test_web_widget_float_formula.js"/>
</xpath>
</template>
</odoo>
Loading…
Cancel
Save