From dfa2130905adea7f40e0fef00626ee8df9b2ccb5 Mon Sep 17 00:00:00 2001 From: Brice bib Bartoletti Date: Fri, 16 Sep 2022 08:16:56 +0000 Subject: [PATCH] [IMP] base_iban: convert to owl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- addons/base_iban/__manifest__.py | 4 +- .../src/components/iban_widget/iban_widget.js | 30 ++++ .../iban_widget/iban_widget.scss} | 5 +- .../components/iban_widget/iban_widget.xml | 19 +++ .../{iban_widget.js => legacy_iban_widget.js} | 0 .../tests/helpers/model_definitions_setup.js | 5 + .../static/src/tests/iban_widget_test.js | 129 +++++++++++------- 7 files changed, 137 insertions(+), 55 deletions(-) create mode 100644 addons/base_iban/static/src/components/iban_widget/iban_widget.js rename addons/base_iban/static/src/{scss/iban_widget_view.scss => components/iban_widget/iban_widget.scss} (64%) create mode 100644 addons/base_iban/static/src/components/iban_widget/iban_widget.xml rename addons/base_iban/static/src/js/{iban_widget.js => legacy_iban_widget.js} (100%) create mode 100644 addons/base_iban/static/src/tests/helpers/model_definitions_setup.js diff --git a/addons/base_iban/__manifest__.py b/addons/base_iban/__manifest__.py index 66af15cef9b..8ae9b42fbe2 100644 --- a/addons/base_iban/__manifest__.py +++ b/addons/base_iban/__manifest__.py @@ -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/**/*', diff --git a/addons/base_iban/static/src/components/iban_widget/iban_widget.js b/addons/base_iban/static/src/components/iban_widget/iban_widget.js new file mode 100644 index 00000000000..991c237f5ff --- /dev/null +++ b/addons/base_iban/static/src/components/iban_widget/iban_widget.js @@ -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); diff --git a/addons/base_iban/static/src/scss/iban_widget_view.scss b/addons/base_iban/static/src/components/iban_widget/iban_widget.scss similarity index 64% rename from addons/base_iban/static/src/scss/iban_widget_view.scss rename to addons/base_iban/static/src/components/iban_widget/iban_widget.scss index a226960e975..10ab6c8187c 100644 --- a/addons/base_iban/static/src/scss/iban_widget_view.scss +++ b/addons/base_iban/static/src/components/iban_widget/iban_widget.scss @@ -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; } } diff --git a/addons/base_iban/static/src/components/iban_widget/iban_widget.xml b/addons/base_iban/static/src/components/iban_widget/iban_widget.xml new file mode 100644 index 00000000000..c0b95eac41f --- /dev/null +++ b/addons/base_iban/static/src/components/iban_widget/iban_widget.xml @@ -0,0 +1,19 @@ + + + + + + validateIbanDebounced + validateIbanDebounced + (ev) => { this.state.isValidIBAN = null; } + + + + + + + + + + + diff --git a/addons/base_iban/static/src/js/iban_widget.js b/addons/base_iban/static/src/js/legacy_iban_widget.js similarity index 100% rename from addons/base_iban/static/src/js/iban_widget.js rename to addons/base_iban/static/src/js/legacy_iban_widget.js diff --git a/addons/base_iban/static/src/tests/helpers/model_definitions_setup.js b/addons/base_iban/static/src/tests/helpers/model_definitions_setup.js new file mode 100644 index 00000000000..81ca26b62ec --- /dev/null +++ b/addons/base_iban/static/src/tests/helpers/model_definitions_setup.js @@ -0,0 +1,5 @@ +/** @odoo-module **/ + +import { addModelNamesToFetch } from '@bus/../tests/helpers/model_definitions_helpers'; + +addModelNamesToFetch(['res.partner.bank']); diff --git a/addons/base_iban/static/src/tests/iban_widget_test.js b/addons/base_iban/static/src/tests/iban_widget_test.js index 3fe954d73f0..b3848d2d27f 100644 --- a/addons/base_iban/static/src/tests/iban_widget_test.js +++ b/addons/base_iban/static/src/tests/iban_widget_test.js @@ -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': + `
+ + + + + + + + + + +
`, }; - // 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: '
', + 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"); }); }); -});