[IMP] base_iban: convert to owl

1) conversion to owl

2) very small improvement:
 - make the validation icon appears when starting edition

closes odoo/odoo#100435

Task-id: 2857743
Signed-off-by: William André (wan) <wan@odoo.com>
This commit is contained in:
Brice bib Bartoletti
2022-09-21 01:29:59 +02:00
parent 67c906f4d2
commit dfa2130905
7 changed files with 137 additions and 55 deletions
+2 -2
View File
@@ -18,8 +18,8 @@ with a single statement.
'demo': ['data/res_partner_bank_demo.xml'],
'assets': {
'web.assets_backend': [
'base_iban/static/src/js/iban_widget.js',
'base_iban/static/src/scss/iban_widget_view.scss',
'base_iban/static/src/components/**/*',
'base_iban/static/src/js/*.js',
],
'web.qunit_suite_tests': [
'base_iban/static/src/tests/**/*',
@@ -0,0 +1,30 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { CharField } from "@web/views/fields/char/char_field";
import { useDebounced } from "@web/core/utils/timing";
import { useService } from "@web/core/utils/hooks";
const { useState } = owl;
export const DELAY = 400;
export class IbanWidget extends CharField {
setup() {
super.setup();
this.state = useState({ isValidIBAN: null });
this.orm = useService("orm");
this.validateIbanDebounced = useDebounced(async (ev) => {
const iban = ev.target.value;
if (!iban) {
this.state.isValidIBAN = null;
} else if (!/[A-Za-z]{2}.{3,}/.test(iban)) {
this.state.isValidIBAN = false;
} else {
this.state.isValidIBAN = await this.orm.call("res.partner.bank", "check_iban", [[], iban]);
}
}, DELAY);
}
}
IbanWidget.template = "base_iban.iban";
registry.category("fields").add("iban", IbanWidget);
@@ -4,13 +4,12 @@
.o_iban {
display: inline-flex;
margin-left: -15px;
margin-top: 5px;
}
.o_iban_fail {
cursor: help;
}
.o_iban_input_with_validator {
padding-right: 20px!important;
input.o_input.o_iban_input_with_validator {
padding-right: 17px!important;
}
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-name="base_iban.iban" t-inherit="web.CharField" owl="1">
<xpath expr="//input" position="attributes">
<attribute name="class" add="o_iban_input_with_validator" separator=" "/>
<attribute name="t-on-input">validateIbanDebounced</attribute>
<attribute name="t-on-focus">validateIbanDebounced</attribute>
<attribute name="t-on-blur">(ev) => { this.state.isValidIBAN = null; }</attribute>
</xpath>
<xpath expr="//input" position="after">
<t t-if="this.state.isValidIBAN === true">
<i class="fa fa-check o_iban text-success"/>
</t>
<t t-elif="this.state.isValidIBAN === false">
<i class="fa fa-times o_iban text-danger o_iban_fail" title="Account isn't a valid IBAN"/>
</t>
</xpath>
</t>
</templates>
@@ -0,0 +1,5 @@
/** @odoo-module **/
import { addModelNamesToFetch } from '@bus/../tests/helpers/model_definitions_helpers';
addModelNamesToFetch(['res.partner.bank']);
@@ -1,65 +1,94 @@
odoo.define('base_iban.iban_widget_tests', function (require) {
"use strict";
/** @odoo-module **/
import { start, startServer } from '@mail/../tests/helpers/test_utils';
import { click, clickEdit, clickSave, editInput, getFixture } from "@web/../tests/helpers/utils";
import { DELAY } from "@base_iban/components/iban_widget/iban_widget";
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var createView = testUtils.createView;
QUnit.module('Fields', {}, function () {
QUnit.module("IbanWidget");
const [validIban, invalidIban] = ["BE12651194580992", "invalidIban!"];
QUnit.module('fields', {
beforeEach: function () {
this.data = {
partner: {
fields: {
acc_number: {string: "acc_number", type: "char"},
},
records: [{
id: 1,
acc_number: "",
}]
const openPreparedView = async (assert, validIbanList, startingAccNumber) => {
const target = getFixture();
const pyEnv = await startServer();
const partnerId = pyEnv['res.partner'].create([
{
name: "Awesome partner",
bank_ids: [
pyEnv['res.partner.bank'].create([{ acc_number: startingAccNumber }]),
],
},
]);
const views = {
'res.partner,false,form':
`<form>
<sheet>
<group>
<field name="name"/>
</group>
<field name="bank_ids">
<tree editable="bottom">
<field name="acc_number" widget="iban"/>
</tree>
</field>
</sheet>
</form>`,
};
// patch _.debounce to be fast and synchronous
this.underscoreDebounce = _.debounce;
_.debounce = _.identity;
},
afterEach: function () {
// unpatch _.debounce
_.debounce = this.underscoreDebounce;
}
}, function () {
QUnit.module('IbanWidget');
QUnit.test('Iban widgets are correctly rendered', async function (assert) {
assert.expect(6);
var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form><sheet><field name="acc_number" widget="iban"/></sheet></form>',
const { advanceTime, afterNextRender, openView } = await start({
serverData: { views },
hasTimeControl: true,
mockRPC: function (route, args) {
if (args.method === 'check_iban') {
console.log(args.args[1] === "BE00 0000 0000 0000 0000")
return Promise.resolve(args.args[1] === "BE00 0000 0000 0000 0000");
if (args.method === "check_iban") {
const iban = args.args[1].replace(/\s/g, '');
return Promise.resolve(iban === validIban);
}
return this._super.apply(this, arguments);
},
});
await openView({
res_id: partnerId,
res_model: 'res.partner',
views: [[false, 'form']],
});
return { target, advanceTime, afterNextRender };
};
await testUtils.fields.editAndTrigger(form.$('.o_field_widget'), "BE00", 'input');
assert.containsOnce(form, '.o_iban_fail', "Should be a False account, it's too short");
assert.containsOnce(form, '.fa-times', "Should have a cross pictogram");
QUnit.test('Iban Widget full flow', async assert => {
const { target, advanceTime, afterNextRender } = await openPreparedView(assert, [validIban], "");
await testUtils.fields.editAndTrigger(form.$('.o_field_widget'), "BE00 0000 0000 0000 0000", 'input');
assert.containsOnce(form, '.text-success', "Should have text-success");
assert.containsOnce(form, '.fa-check', "Should have a valid pictogram");
assert.containsNone(target, ".o_iban", "Shouldn't display any validation icon while not editing");
await clickEdit(target);
assert.containsNone(target, ".o_iban",
"Shouldn't display any validation icon while not editing a specific line");
await testUtils.fields.editAndTrigger(form.$('.o_field_widget'), "BE00 xxxx xxxx xxxx xxxx", 'input');
assert.containsOnce(form, '.o_iban_fail', "Should be False account");
assert.containsOnce(form, '.fa-times', "Should have a cross pictogram");
await click(target, "td.o_iban_cell");
assert.containsNone(target, ".o_iban", "Shouldn't display any validation icon while iban is empty");
form.destroy();
await editInput(target, ".o_iban_cell .o_input", invalidIban);
assert.containsNone(target, ".o_iban", "Shouldn't change its state of display before edition is finished");
await afterNextRender(() => advanceTime(DELAY));
assert.containsOnce(target, ".o_iban", "Should contain a validation icon 400ms after edition");
assert.containsOnce(target, "i.fa.fa-times.o_iban_fail", "The validation icon should be the failed one");
assert.containsNone(target, "i.fa.fa-check.o_iban", "The validation icon shouldn't be the successful one");
await clickSave(target);
assert.containsNone(target, ".o_iban", "Shouldn't display any validation while not editing");
await clickEdit(target);
assert.containsNone(target, ".o_iban",
"Shouldn't display any validation icon while not editing a specific line");
await click(target, "td.o_iban_cell");
await afterNextRender(() => advanceTime(DELAY));
assert.containsOnce(target, "i.fa.fa-times.o_iban_fail", "The validation icon should be present while clicking on an already filled IBAN");
await editInput(target, ".o_iban_cell .o_input", validIban);
assert.containsOnce(target, "i.fa.fa-times.o_iban_fail", "The validation icon shouldn't change during the edition");
await afterNextRender(() => advanceTime(DELAY));
assert.containsOnce(target, ".o_iban", "Should contain a validation icon 400ms after edition");
assert.containsOnce(target, "i.fa.fa-check.o_iban", "The validation icon should be the successful one");
assert.containsNone(target, "i.fa.fa-times.o_iban_fail", "The validation icon shouldn't be the failed one");
await clickSave(target);
assert.containsNone(target, ".o_iban", "Shouldn't display any validation while not editing");
});
});
});