diff --git a/odex30_base/odex30_web/i18n/ar_001.po b/odex30_base/odex30_web/i18n/ar_001.po
deleted file mode 100644
index 805626c..0000000
--- a/odex30_base/odex30_web/i18n/ar_001.po
+++ /dev/null
@@ -1,457 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * odex30_web
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 18.0+e\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-01 22:17+0000\n"
-"PO-Revision-Date: 2026-01-01 22:17+0000\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "%s days"
-msgstr "%s أيام"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0
-msgid "(Enterprise Edition)"
-msgstr "(النسخة الشركاتية)"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "1 month"
-msgstr "شهر واحد"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/views/list/list_renderer_desktop.xml:0
-msgid "Add Custom Field"
-msgstr "إضافة حقل مخصص"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/views/kanban/kanban_header_patch.js:0
-msgid "Automations"
-msgstr "الأتمتة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Build new apps from scratch"
-msgstr "بناء تطبيقات جديدة من الصفر"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Build new reports"
-msgstr "بناء تقارير جديدة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/share_url/burger_menu.xml:0
-msgid "Close menu"
-msgstr "إغلاق القائمة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid ""
-"Contact your sales representative to help you to unlink your previous "
-"database"
-msgstr ""
-"تواصل مع مندوب المبيعات لمساعدتك في فصل قاعدة البيانات السابقة"
-""
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Create automation rules"
-msgstr "إنشاء قواعد الأتمتة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Customize Reports"
-msgstr "تخصيص التقارير"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Customize any screen"
-msgstr "تخصيص أي شاشة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/color_scheme/color_scheme_menu_items.js:0
-msgid "Dark Mode"
-msgstr "الوضع الداكن"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0
-msgid "Database expiration:"
-msgstr "انتهاء صلاحية قاعدة البيانات:"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Define webhooks"
-msgstr "تعريف Webhooks"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Discard"
-msgstr "إلغاء"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Dismiss"
-msgstr "إغلاق"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Error reason:"
-msgstr "سبب الخطأ:"
-
-#. module: odex30_web
-#: model:ir.model,name:odex30_web.model_ir_http
-msgid "HTTP Routing"
-msgstr "مسار HTTP"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu_service.js:0
-msgid "Home"
-msgstr "الرئيسية"
-
-#. module: odex30_web
-#: model:ir.model.fields,field_description:odex30_web.field_res_users_settings__homemenu_config
-msgid "Home Menu Configuration"
-msgstr "إعدادات قائمة الرئيسية"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/navbar/navbar.js:0
-msgid "Home menu"
-msgstr "قائمة الرئيسية"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "I paid, please recheck!"
-msgstr "لقد دفعت، يرجى إعادة التحقق!"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Install Odoo Studio and its dependencies"
-msgstr "تثبيت Odoo Studio وتبعياته"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Learn More"
-msgstr "تعرف على المزيد"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Log in as an administrator to correct the issue."
-msgstr "سجل الدخول كمدير لإصلاح المشكلة."
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu.xml:0
-msgid "No result"
-msgstr "لا توجد نتائج"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0
-msgid "Odoo"
-msgstr "أودو"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/settings_form_view/res_config_edition.xml:0
-msgid "Odoo Enterprise Edition License V1.0"
-msgstr "رخصة Odoo Enterprise Edition V1.0"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/views/list/list_renderer_desktop.js:0
-msgid "Odoo Studio - Add new fields to any view"
-msgstr "Odoo Studio - إضافة حقول جديدة إلى أي عرض"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/views/kanban/kanban_header_patch.js:0
-msgid "Odoo Studio - Customize workflows in minutes"
-msgstr "Odoo Studio - تخصيص سير العمل في دقائق"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Odoo Support"
-msgstr "دعم أودو"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Paste code here"
-msgstr "الصق الكود هنا"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/navbar/navbar.js:0
-msgid "Previous view"
-msgstr "العرض السابق"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "Register"
-msgstr "تسجيل"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Register your subscription"
-msgstr "تسجيل اشتراكك"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Renew now"
-msgstr "تجديد الآن"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "Retry"
-msgstr "إعادة المحاولة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Send an email"
-msgstr "إرسال بريد إلكتروني"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Sending the instructions by email ..."
-msgstr "إرسال التعليمات بالبريد الإلكتروني..."
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/share_url/share_url.js:0
-msgid "Share"
-msgstr "مشاركة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/share_url/burger_menu.xml:0
-msgid "Share URL"
-msgstr "مشاركة الرابط"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid ""
-"Something went wrong while registering your database. You can try again or "
-"contact"
-msgstr ""
-"حدث خطأ أثناء تسجيل قاعدة البيانات. يمكنك المحاولة مرة أخرى أو التواصل"
-" مع"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Start using Odoo Studio"
-msgstr "ابدأ استخدام Odoo Studio"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Subscription Code:"
-msgstr "كود الاشتراك:"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu.xml:0
-msgid "TIP"
-msgstr "نصيحة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid ""
-"Thank you, your registration was successful! Your database is valid until"
-msgstr ""
-"شكراً، تم تسجيلك بنجاح! قاعدة بياناتك صالحة حتى"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js:0
-msgid ""
-"Thank you, your registration was successful! Your database is valid until "
-"%s."
-msgstr ""
-"شكراً، تم تسجيلك بنجاح! قاعدة بياناتك صالحة حتى %s."
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid ""
-"The instructions to unlink your subscription from the previous database(s) "
-"have been sent"
-msgstr ""
-"تم إرسال التعليمات لفصل اشتراكك من قواعد البيانات السابقة"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "This database has expired. "
-msgstr "انتهت صلاحية هذه قاعدة البيانات. "
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "This database will expire in %s. "
-msgstr "ستنتهي صلاحية قاعدة البيانات هذه في %s. "
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "This demo database will expire in %s. "
-msgstr "ستنتهي صلاحية قاعدة بيانات العرض التجريبي في %s. "
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Unable to send the instructions by email, please contact the"
-msgstr "تعذر إرسال التعليمات بالبريد الإلكتروني، يرجى التواصل مع"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Unleash the power of Odoo Studio:"
-msgstr "استخدم قوة Odoo Studio:"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Upgrade your subscription"
-msgstr "ترقية اشتراكك"
-
-#. module: odex30_web
-#: model:ir.model,name:odex30_web.model_res_users_settings
-msgid "User Settings"
-msgstr "إعدادات المستخدم"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "Want to tailor-make your Odoo?"
-msgstr "هل تريد تخصيص أودو حسب احتياجاتك؟"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid ""
-"You have more users or more apps installed than your subscription allows."
-msgstr ""
-"لديك مستخدمون أو تطبيقات مثبتة أكثر مما يسمح به اشتراكك."
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid ""
-"You will be able to register your database once you have installed your "
-"first app."
-msgstr ""
-"يمكنك تسجيل قاعدة البيانات بعد تثبيت أول تطبيق."
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Your subscription code"
-msgstr "كود اشتراكك"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid ""
-"Your subscription expired %s days ago. This database will be blocked soon. "
-msgstr ""
-"انتهى اشتراكك منذ %s أيام. سيتم حظر قاعدة البيانات قريباً. "
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.js:0
-msgid "Your subscription expires in %s days. "
-msgstr "ينتهي اشتراكك بعد %s أيام. "
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Your subscription is already linked to a database."
-msgstr "اشتراكك مرتبط بقاعدة بيانات بالفعل."
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "Your subscription was updated and is valid until"
-msgstr "تم تحديث اشتراكك وهو صالح حتى"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/promote_studio_dialog/promote_studio_dialog.xml:0
-msgid "and more!"
-msgstr "وأكثر!"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "buy a subscription"
-msgstr "شراء اشتراك"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "buy a subscription."
-msgstr "شراء اشتراك."
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "or"
-msgstr "أو"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/expiration_panel.xml:0
-msgid "to the subscription owner to confirm the change, enter a new code or"
-msgstr ""
-"لصاحب الاشتراك لتأكيد التغيير، أدخل كود جديد أو"
-
-#. module: odex30_web
-#. odoo-javascript
-#: code:addons/odex30_web/static/src/webclient/home_menu/home_menu.xml:0
-msgid "— open me anywhere with"
-msgstr ""
diff --git a/odex30_base/odex30_web/static/description/icon.png b/odex30_base/odex30_web/static/description/icon.png
new file mode 100644
index 0000000..d3b8d45
Binary files /dev/null and b/odex30_base/odex30_web/static/description/icon.png differ
diff --git a/odex30_base/odex30_web/static/img/background-dark.jpg b/odex30_base/odex30_web/static/img/background-dark.jpg
deleted file mode 100644
index ce69f95..0000000
Binary files a/odex30_base/odex30_web/static/img/background-dark.jpg and /dev/null differ
diff --git a/odex30_base/odex30_web/static/img/background-dark.png b/odex30_base/odex30_web/static/img/background-dark.png
new file mode 100644
index 0000000..ac94fc4
Binary files /dev/null and b/odex30_base/odex30_web/static/img/background-dark.png differ
diff --git a/odex30_base/odex30_web/static/img/background-light.png b/odex30_base/odex30_web/static/img/background-light.png
new file mode 100644
index 0000000..63ffa6c
Binary files /dev/null and b/odex30_base/odex30_web/static/img/background-light.png differ
diff --git a/odex30_base/odex30_web/static/img/background-light.svg b/odex30_base/odex30_web/static/img/background-light.svg
deleted file mode 100644
index aa437a1..0000000
--- a/odex30_base/odex30_web/static/img/background-light.svg
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/odex30_base/odex30_web/static/src/core/search/search_panel/search_panel.dark.scss b/odex30_base/odex30_web/static/src/core/search/search_panel/search_panel.dark.scss
deleted file mode 100644
index 5bf10d1..0000000
--- a/odex30_base/odex30_web/static/src/core/search/search_panel/search_panel.dark.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-// = Search Panel
-// ============================================================================
-// No CSS hacks, variables overrides only
-
-.o_search_panel_section {
- .o_popover > & .list-group {
- --#{$prefix}list-group-active-bg: #{$o-gray-400};
- }
-}
diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js b/odex30_base/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js
deleted file mode 100644
index e3c65c1..0000000
--- a/odex30_base/odex30_web/static/src/webclient/home_menu/enterprise_subscription_service.js
+++ /dev/null
@@ -1,195 +0,0 @@
-/** @odoo-module **/
-
-import { registry } from "@web/core/registry";
-import { session } from "@web/session";
-import { browser } from "@web/core/browser/browser";
-import { deserializeDateTime, serializeDate, formatDate } from "@web/core/l10n/dates";
-import { useService } from "@web/core/utils/hooks";
-import { _t } from "@web/core/l10n/translation";
-import { ExpirationPanel } from "./expiration_panel";
-import { cookie } from "@web/core/browser/cookie";
-import { rpc } from "@web/core/network/rpc";
-
-const { DateTime } = luxon;
-import { Component, xml, useState } from "@odoo/owl";
-
-function daysUntil(datetime) {
- const duration = datetime.diff(DateTime.utc(), "days");
- return Math.round(duration.values.days);
-}
-
-export class SubscriptionManager {
- constructor(env, { orm, notification }) {
- this.env = env;
- this.orm = orm;
- this.notification = notification;
- if (session.expiration_date) {
- this.expirationDate = deserializeDateTime(session.expiration_date);
- } else {
- // If no date found, assume 1 month and hope for the best
- this.expirationDate = DateTime.utc().plus({ days: 30 });
- }
- this.expirationReason = session.expiration_reason;
- // Hack: we need to know if there is at least one app installed (except from App and
- // Settings). We use mail to do that, as it is a dependency of almost every addon. To
- // determine whether mail is installed or not, we check for the presence of the key
- // "storeData" in session_info, as it is added in mail.
- this.hasInstalledApps = "storeData" in session;
- // "user" or "admin"
- this.warningType = session.warning;
- this.lastRequestStatus = null;
- this.isWarningHidden = cookie.get("oe_instance_hide_panel");
- }
-
- get formattedExpirationDate() {
- return formatDate(this.expirationDate, { format: "DDD" });
- }
-
- get daysLeft() {
- return daysUntil(this.expirationDate);
- }
-
- get unregistered() {
- return ["trial", "demo", false].includes(this.expirationReason);
- }
-
- hideWarning() {
- // Hide warning for 24 hours.
- cookie.set("oe_instance_hide_panel", true, 24 * 60 * 60);
- this.isWarningHidden = true;
- }
-
- async buy() {
- const limitDate = serializeDate(DateTime.utc().minus({ days: 15 }));
- const args = [
- [
- ["share", "=", false],
- ["login_date", ">=", limitDate],
- ],
- ];
- const nbUsers = await this.orm.call("res.users", "search_count", args);
- browser.location = `https://www.odoo.com/odoo-enterprise/upgrade?num_users=${nbUsers}`;
- }
-
- async submitCode(OdexCode) {
- const [oldDate, ] = await Promise.all([
- this.orm.call("ir.config_parameter", "get_param", ["database.expiration_date"]),
- this.orm.call("ir.config_parameter", "set_param", [
- "database.enterprise_code",
- OdexCode,
- ])
- ]);
-
- await this.orm.call("publisher_warranty.contract", "update_notification", [[]]);
-
- const [linkedSubscriptionUrl, linkedEmail, expirationDate] = await Promise.all([
- this.orm.call("ir.config_parameter", "get_param", [
- "database.already_linked_subscription_url",
- ]),
- this.orm.call("ir.config_parameter", "get_param", ["database.already_linked_email"]),
- this.orm.call("ir.config_parameter", "get_param", [
- "database.expiration_date",
- ])
- ]);
-
- if (linkedSubscriptionUrl) {
- this.lastRequestStatus = "link";
- this.linkedSubscriptionUrl = linkedSubscriptionUrl;
- this.mailDeliveryStatus = null;
- this.linkedEmail = linkedEmail;
- } else if (expirationDate !== oldDate) {
- this.lastRequestStatus = "success";
- this.expirationDate = deserializeDateTime(expirationDate);
- if (this.daysLeft > 30) {
- this.notification.add(
- _t(
- "Thank you, your registration was successful! Your database is valid until %s.",
- this.formattedExpirationDate
- ),
- { type: "success" }
- );
- }
- } else {
- this.lastRequestStatus = "error";
- }
- }
-
- async checkStatus() {
- await this.orm.call("publisher_warranty.contract", "update_notification", [[]]);
-
- const expirationDateStr = await this.orm.call("ir.config_parameter", "get_param", [
- "database.expiration_date",
- ]);
- this.lastRequestStatus = "update";
- this.expirationDate = deserializeDateTime(expirationDateStr);
- }
-
- async sendUnlinkEmail() {
- const sendUnlinkInstructionsUrl = await this.orm.call("ir.config_parameter", "get_param", [
- "database.already_linked_send_mail_url",
- ]);
- this.mailDeliveryStatus = "ongoing";
- const { result, reason } = await rpc(sendUnlinkInstructionsUrl);
- if (result) {
- this.mailDeliveryStatus = "success";
- } else {
- this.mailDeliveryStatus = "fail";
- this.mailDeliveryStatusError = reason;
- }
- }
-
- async renew() {
- const OdexCode = await this.orm.call("ir.config_parameter", "get_param", [
- "database.enterprise_code",
- ]);
-
- const url = "https://www.odoo.com/odoo-enterprise/renew";
- const contractQueryString = OdexCode ? `?contract=${OdexCode}` : "";
- browser.location = `${url}${contractQueryString}`;
- }
-
- async upsell() {
- const limitDate = serializeDate(DateTime.utc().minus({ days: 15 }));
- const [OdexCode, nbUsers] = await Promise.all([
- this.orm.call("ir.config_parameter", "get_param", ["database.enterprise_code"]),
- this.orm.call("res.users", "search_count", [
- [
- ["share", "=", false],
- ["login_date", ">=", limitDate],
- ],
- ]),
- ]);
- const url = "https://www.odoo.com/odoo-enterprise/upsell";
- const contractQueryString = OdexCode ? `&contract=${OdexCode}` : "";
- browser.location = `${url}?num_users=${nbUsers}${contractQueryString}`;
- }
-}
-
-class ExpiredSubscriptionBlockUI extends Component {
- static props = {};
- // TODO the "o_blockUI" div in there seems useless (it has 0 height and thus displays and does nothing)
- static template = xml`
-
-
-
-
-
- `;
- static components = { ExpirationPanel };
- setup() {
- this.subscription = useState(useService("enterprise_subscription"));
- }
-}
-
-export const enterpriseSubscriptionService = {
- name: "enterprise_subscription",
- dependencies: ["orm", "notification"],
- start(env, { orm, notification }) {
- registry
- .category("main_components")
- .add("expired_subscription_block_ui", { Component: ExpiredSubscriptionBlockUI });
- return new SubscriptionManager(env, { orm, notification });
- },
-};
-
-registry.category("services").add("enterprise_subscription", enterpriseSubscriptionService);
diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.js b/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.js
deleted file mode 100644
index 57d48a2..0000000
--- a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/** @odoo-module **/
-
-import { useService } from "@web/core/utils/hooks";
-import { Transition } from "@web/core/transition";
-import { _t } from "@web/core/l10n/translation";
-import { Component, useState, useRef } from "@odoo/owl";
-
-const { DateTime } = luxon;
-
-/**
- * Expiration panel
- *
- * Component representing the banner located on top of the home menu. Its purpose
- * is to display the expiration state of the current database and to help the
- * user to buy/renew its subscription.
- * @extends Component
- */
-export class ExpirationPanel extends Component {
- static template = "DatabaseExpirationPanel";
- static props = {};
- static components = { Transition };
-
- setup() {
- this.subscription = useState(useService("enterprise_subscription"));
-
- this.state = useState({
- displayRegisterForm: false,
- });
-
- this.inputRef = useRef("input");
- }
-
- get buttonText() {
- return this.subscription.lastRequestStatus === "error" ? _t("Retry") : _t("Register");
- }
-
- get alertType() {
- if (this.subscription.lastRequestStatus === "success") {
- return "success";
- }
- const { daysLeft } = this.subscription;
- if (daysLeft <= 6) {
- return "danger";
- } else if (daysLeft <= 16) {
- return "warning";
- }
- return "info";
- }
-
- get expirationMessage() {
- const { daysLeft } = this.subscription;
- if (daysLeft <= 0) {
- return _t("This database has expired. ");
- }
- const delay = daysLeft === 30 ? _t("1 month") : _t("%s days", daysLeft);
- if (this.subscription.expirationReason === "demo") {
- return _t("This demo database will expire in %s. ", delay);
- }
-
- const expirationDate = this.subscription.expirationDate;
- const today = DateTime.now();
- const diff = expirationDate.diff(today);
-
- if (this.subscription.expirationReason !== 'renewal') {
- return _t("This database will expire in %s. ", delay);
- } else {
- if (daysLeft > 15) {
- return _t(
- "Your subscription expires in %s days. ",
- daysLeft - 15
- );
- } else {
- return _t(
- "Your subscription expired %s days ago. This database will be blocked soon. ",
- (diff.as("days") | 0)
- );
- }
- }
- }
-
- showRegistrationForm() {
- this.state.displayRegisterForm = !this.state.displayRegisterForm;
- }
-
- async onCodeSubmit() {
- const OdexCode = this.inputRef.el.value;
- if (!OdexCode) {
- return;
- }
- await this.subscription.submitCode(OdexCode);
- if (this.subscription.lastRequestStatus === "success") {
- this.state.displayRegisterForm = false;
- } else {
- this.state.buttonText = _t("Retry");
- }
- }
-}
diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.scss b/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.scss
deleted file mode 100644
index 5d7511f..0000000
--- a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-.database_expiration_panel .oe_instance_register_form {
- max-height: 0;
- transition: max-height 0.4s;
-
- &.o-vertical-slide-enter-active {
- max-height: 10rem; // fixed value is required to properly trigger transition
- }
-}
diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.xml b/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.xml
deleted file mode 100644
index be99fd1..0000000
--- a/odex30_base/odex30_web/static/src/webclient/home_menu/expiration_panel.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
×
-
- You will be able to register your database once you have installed your first app.
-
-
-
-
- Register your subscription
- or
- buy a subscription .
-
-
-
-
- You have more users or more apps installed than your subscription allows.
-
-
-
- Log in as an administrator to correct the issue.
-
-
-
Thank you, your registration was successful! Your database is valid until .
-
Your subscription was updated and is valid until .
-
Something went wrong while registering your database. You can try again or contact Odoo Support .
-
- Your subscription is already linked to a database.
-
- Send an email to the subscription owner to confirm the change, enter a new code or buy a subscription.
- Sending the instructions by email ...
- The instructions to unlink your subscription from the previous database(s) have been sent
- Unable to send the instructions by email, please contact the Odoo Support
- Error reason:
-
-
- Contact your sales representative to help you to unlink your previous database
-
-
-
-
-
-
-
-
diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss
index 8c59efa..358d38b 100644
--- a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss
+++ b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.dark.scss
@@ -4,5 +4,5 @@
.o_home_menu_background {
--homeMenu-bg-color: #000511;
- --homeMenu-bg-image: url("/odex30_web/static/img/background-dark.jpg");
+ --homeMenu-bg-image: url("/odex30_web/static/img/background-dark.png");
}
diff --git a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss
index e00bcb9..65a3cdd 100644
--- a/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss
+++ b/odex30_base/odex30_web/static/src/webclient/home_menu/home_menu_background.scss
@@ -4,6 +4,6 @@
size: cover;
attachment: fixed;
color: var(--homeMenu-bg-color, #{$o-gray-200});
- image: var(--homeMenu-bg-image, url("/odex30_web/static/img/background-light.svg"));
+ image: var(--homeMenu-bg-image, url("/odex30_web/static/img/background-light.png"));
}
}
diff --git a/odex30_base/odex30_web/static/tests/helpers.js b/odex30_base/odex30_web/static/tests/helpers.js
deleted file mode 100644
index c743b5e..0000000
--- a/odex30_base/odex30_web/static/tests/helpers.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/** @odoo-module */
-
-import { createWebClient } from "@web/../tests/webclient/helpers";
-import { WebClientOdex } from "@odex30_web/webclient/webclient";
-
-export function createOdexWebClient(params) {
- params.WebClientClass = WebClientOdex;
- return createWebClient(params);
-}
diff --git a/odex30_base/odex30_web/static/tests/mobile/burger_menu.test.js b/odex30_base/odex30_web/static/tests/mobile/burger_menu.test.js
deleted file mode 100644
index e6afdb2..0000000
--- a/odex30_base/odex30_web/static/tests/mobile/burger_menu.test.js
+++ /dev/null
@@ -1,107 +0,0 @@
-import { beforeEach, describe, expect, test } from "@odoo/hoot";
-import { click, queryAll } from "@odoo/hoot-dom";
-import { animationFrame, runAllTimers } from "@odoo/hoot-mock";
-import { defineActions, defineMenus, mountWithCleanup } from "@web/../tests/web_test_helpers";
-
-import { Component, onMounted, xml } from "@odoo/owl";
-
-import { registry } from "@web/core/registry";
-import { WebClientOdex } from "@odex30_web/webclient/webclient";
-
-const actionRegistry = registry.category("actions");
-
-const queryAllRoot = (selector) => queryAll(selector, { root: document.body });
-
-class TestClientAction extends Component {
- static template = xml`
-
- ClientAction_
-
`;
- static props = ["*"];
- setup() {
- onMounted(() => this.env.config.setDisplayName(`Client action ${this.props.action.id}`));
- }
-}
-
-describe.current.tags("mobile");
-
-beforeEach(() => {
- defineMenus([
- {
- id: 1,
- name: "App1",
- appID: 1,
- actionID: 1001,
- xmlid: "menu_1",
- },
- ]);
-});
-
-test("Burger Menu on home menu", async () => {
- expect.assertions(5);
-
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
- expect(queryAllRoot(".o_burger_menu")).toHaveCount(0);
- expect(queryAllRoot(".o_home_menu")).toBeVisible();
-
- await click(queryAllRoot(".o_mobile_menu_toggle"));
- await runAllTimers();
- await animationFrame();
- expect(queryAllRoot(".o_burger_menu")).toHaveCount(1);
- expect(queryAllRoot(".o_user_menu_mobile")).toHaveCount(1);
- await click(queryAllRoot(".o_sidebar_close"));
- await animationFrame();
- expect(".o_burger_menu").toHaveCount(0);
-});
-
-test("Burger Menu on home menu over an App", async () => {
- expect.assertions(5);
-
- actionRegistry.add("__test__client__action__", TestClientAction);
-
- defineMenus([
- {
- id: 1,
- children: [
- {
- id: 99,
- name: "SubMenu",
- appID: 1,
- actionID: 1002,
- webIconData: undefined,
- webIcon: false,
- },
- ],
- },
- ]);
-
- defineActions([
- {
- id: 1001,
- tag: "__test__client__action__",
- target: "main",
- type: "ir.actions.client",
- params: { description: "Id 1" },
- },
- ]);
-
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- await click(queryAllRoot(".o_draggable:first-of-type .o_app"));
- await animationFrame();
- await click(queryAllRoot(".o_menu_toggle"));
- await animationFrame();
- await click(queryAllRoot(".o_sidebar_topbar a.btn-primary"));
- await animationFrame();
-
- expect(queryAllRoot(".o_burger_menu")).toHaveCount(0);
- expect(queryAllRoot(".o_home_menu")).toBeVisible();
-
- await click(queryAllRoot(".o_mobile_menu_toggle"));
- await animationFrame();
- expect(queryAllRoot(".o_burger_menu")).toHaveCount(1);
- expect(queryAllRoot(".o_burger_menu nav.o_burger_menu_content li")).toHaveCount(0);
- expect(queryAllRoot(".o_burger_menu_content")).not.toHaveClass("o_burger_menu_dark");
-});
diff --git a/odex30_base/odex30_web/static/tests/mobile/pivot_view.test.js b/odex30_base/odex30_web/static/tests/mobile/pivot_view.test.js
deleted file mode 100644
index 67b23d9..0000000
--- a/odex30_base/odex30_web/static/tests/mobile/pivot_view.test.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import { describe, expect, test } from "@odoo/hoot";
-import { click } from "@odoo/hoot-dom";
-import { animationFrame } from "@odoo/hoot-mock";
-import { defineModels, fields, models, mountView } from "@web/../tests/web_test_helpers";
-
-class Partner extends models.Model {
- foo = fields.Integer({ aggregator: "sum" });
-
- _records = [
- {
- id: 1,
- foo: 12,
- },
- {
- id: 2,
- foo: 1,
- },
- {
- id: 3,
- foo: 17,
- },
- {
- id: 4,
- foo: 2,
- },
- ];
-}
-
-defineModels([Partner]);
-
-describe.current.tags("mobile");
-
-test("simple pivot rendering", async () => {
- expect.assertions(2);
-
- await mountView({
- type: "pivot",
- resModel: "partner",
- arch: /* xml */ `
-
-
-
- `,
- });
-
- expect(".o_pivot_view").toHaveClass("o_view_controller");
- expect("td.o_pivot_cell_value:contains(32)").toHaveCount(1, {
- message: "should contain a pivot cell with the sum of all records",
- });
-});
-
-test("unselecting all measures should not crash pivot rendering", async () => {
- expect.assertions(1);
-
- await mountView({
- type: "pivot",
- resModel: "partner",
- arch: /* xml */ `
-
-
-
- `,
- });
-
- await click(".dropdown-toggle.btn.btn-primary:eq(1)");
- await animationFrame();
- await click(".dropdown-item.o_menu_item.selected:eq(0)");
- await animationFrame();
- expect("div.o_nocontent_help").toHaveCount(1, {
- message: "Instead of error action helper will appear",
- });
-});
diff --git a/odex30_base/odex30_web/static/tests/mobile/webclient_mobile.test.js b/odex30_base/odex30_web/static/tests/mobile/webclient_mobile.test.js
deleted file mode 100644
index 952d9c0..0000000
--- a/odex30_base/odex30_web/static/tests/mobile/webclient_mobile.test.js
+++ /dev/null
@@ -1,112 +0,0 @@
-import { describe, expect, test } from "@odoo/hoot";
-import { click, queryFirst } from "@odoo/hoot-dom";
-import { animationFrame, mockMatchMedia } from "@odoo/hoot-mock";
-import {
- defineActions,
- defineModels,
- fields,
- getService,
- models,
- mountWithCleanup,
-} from "@web/../tests/web_test_helpers";
-
-import { UserMenu } from "@web/webclient/user_menu/user_menu";
-import { WebClientOdex } from "@odex30_web/webclient/webclient";
-
-class Partner extends models.Model {
- name = fields.Char();
-
- _records = [
- { id: 1, name: "First record" },
- { id: 2, name: "Second record" },
- ];
- _views = {
- form: `
-
- `,
- kanban: `
-
-
-
-
-
-
-
- `,
- list: `
`,
- };
-}
-
-defineModels([Partner]);
-
-defineActions([
- {
- id: 1,
- xml_id: "action_1",
- name: "Partners Action 1",
- res_model: "partner",
- views: [[false, "kanban"]],
- },
- {
- id: 3,
- xml_id: "action_3",
- name: "Partners",
- res_model: "partner",
- views: [
- [false, "list"],
- [false, "kanban"],
- [false, "form"],
- ],
- },
-]);
-
-describe.current.tags("mobile");
-
-test("scroll position is kept", async () => {
- // This test relies on the fact that the scrollable element in mobile
- // is view's root node.
- const firstRecord = Partner._records[0];
- delete firstRecord.id;
- Partner._records = [...Array(80)].map((_, i) => ({
- ...firstRecord,
- name: `Record ${i + 1}`,
- }));
-
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- // partners in list/kanban
- await getService("action").doAction(3);
- expect(".o_kanban_view").toHaveCount(1);
-
- queryFirst(".o_kanban_view").scrollTo(0, 123);
- await click(".o_kanban_record:eq(20)");
- await animationFrame();
- expect(".o_form_view").toHaveCount(1);
- expect(".o_kanban_view").toHaveCount(0);
-
- await click(".o_breadcrumb .o_back_button");
- await animationFrame();
- expect(".o_form_view").toHaveCount(0);
- expect(".o_kanban_view").toHaveCount(1);
-});
-
-test("Share URL item is not present in the user menu when screen is small", async () => {
- mockMatchMedia({ ["display-mode"]: "standalone" });
-
- await mountWithCleanup(UserMenu);
-
- expect(".o_user_menu").toHaveCount(1);
- queryFirst(".o_user_menu").classList.remove("d-none");
-
- await click(".o_user_menu button");
- await animationFrame();
-
- expect(".o_user_menu .dropdown-item").toHaveCount(0, {
- message: "share button is not visible",
- });
-});
diff --git a/odex30_base/odex30_web/static/tests/tours/web_enterprise_tours.js b/odex30_base/odex30_web/static/tests/tours/web_enterprise_tours.js
deleted file mode 100644
index 35f1bc8..0000000
--- a/odex30_base/odex30_web/static/tests/tours/web_enterprise_tours.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/** @odoo-module */
-import { registry } from "@web/core/registry";
-
-registry.category("web_tour.tours").add("odex30_web.test_studio_list_upsell", {
- steps: () => [
- {
- trigger: ".o_list_view",
- },
- {
- trigger: ".o_optional_columns_dropdown > button",
- run: "click",
- },
- {
- trigger: " .o-dropdown--menu .dropdown-item-studio",
- },
- ],
-});
diff --git a/odex30_base/odex30_web/static/tests/views/list.test.js b/odex30_base/odex30_web/static/tests/views/list.test.js
deleted file mode 100644
index e282075..0000000
--- a/odex30_base/odex30_web/static/tests/views/list.test.js
+++ /dev/null
@@ -1,348 +0,0 @@
-import { beforeEach, describe, expect, test } from "@odoo/hoot";
-import { click, queryAll } from "@odoo/hoot-dom";
-import { animationFrame } from "@odoo/hoot-mock";
-import {
- contains,
- defineModels,
- fields,
- getDropdownMenu,
- getService,
- models,
- mountView,
- mountWithCleanup,
- onRpc,
- patchWithCleanup,
-} from "@web/../tests/web_test_helpers";
-
-import { browser } from "@web/core/browser/browser";
-import { user } from "@web/core/user";
-import { WebClientOdex } from "@odex30_web/webclient/webclient";
-
-class Foo extends models.Model {
- foo = fields.Char();
- bar = fields.Boolean();
-
- _records = [
- { id: 1, bar: true, foo: "yop" },
- { id: 2, bar: true, foo: "blip" },
- { id: 3, bar: true, foo: "gnap" },
- { id: 4, bar: false, foo: "blip" },
- ];
-}
-
-defineModels([Foo]);
-
-const getDefaultConfig = () => ({
- actionId: 1,
- actionType: "ir.actions.act_window",
-});
-
-describe.current.tags("desktop");
-
-beforeEach(() => {
- onRpc("has_group", () => true);
-});
-
-test("add custom field button with other optional columns - studio not installed", async () => {
- expect.assertions(8);
-
- onRpc("search_read", ({ model }) => {
- if (model === "ir.module.module") {
- expect.step("studio_module_id");
- return [{ id: 42 }];
- }
- });
- onRpc("button_immediate_install", ({ model, args }) => {
- if (model === "ir.module.module") {
- expect(args[0]).toEqual([42], {
- message: "Should be the id of studio module returned by the search read",
- });
- expect.step("studio_module_install");
- return true;
- }
- });
- await mountView({
- type: "list",
- resModel: "foo",
- arch: /* xml */ `
-
-
-
-
- `,
- config: getDefaultConfig(),
- });
-
- patchWithCleanup(browser.location, {
- reload: function () {
- expect.step("window_reload");
- },
- });
-
- expect(".o_data_row").toHaveCount(4);
- expect(".o_optional_columns_dropdown_toggle").toHaveCount(1);
-
- await click(".o_optional_columns_dropdown_toggle");
- await animationFrame();
- const dropdown = getDropdownMenu(".o_optional_columns_dropdown");
-
- expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(2);
- expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(1);
-
- await click(".dropdown-item-studio");
- await animationFrame();
- expect(".modal-studio").toHaveCount(1);
-
- await click(".modal .o_install_studio");
- await animationFrame();
- expect(browser.localStorage.getItem("openStudioOnReload")).toBe("main");
- expect.verifySteps(["studio_module_id", "studio_module_install", "window_reload"]);
-});
-
-test("add custom field button without other optional columns - studio not installed", async () => {
- expect.assertions(8);
-
- onRpc("search_read", ({ model }) => {
- if (model === "ir.module.module") {
- expect.step("studio_module_id");
- return [{ id: 42 }];
- }
- });
- onRpc("button_immediate_install", ({ model, args }) => {
- if (model === "ir.module.module") {
- expect(args[0]).toEqual([42], {
- message: "Should be the id of studio module returned by the search read",
- });
- expect.step("studio_module_install");
- return true;
- }
- });
- await mountView({
- type: "list",
- resModel: "foo",
- config: getDefaultConfig(),
- arch: /* xml */ `
-
-
-
-
- `,
- });
-
- patchWithCleanup(browser.location, {
- reload: function () {
- expect.step("window_reload");
- },
- });
-
- expect(".o_data_row").toHaveCount(4);
- expect(".o_optional_columns_dropdown_toggle").toHaveCount(1);
-
- await click(".o_optional_columns_dropdown_toggle");
- await animationFrame();
- const dropdown = getDropdownMenu(".o_optional_columns_dropdown");
-
- expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(1);
- expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(1);
-
- await click(".dropdown-item-studio");
- await animationFrame();
- expect(".modal-studio").toHaveCount(1);
-
- await click(".modal .o_install_studio");
- await animationFrame();
- expect(browser.localStorage.getItem("openStudioOnReload")).toBe("main");
- expect.verifySteps(["studio_module_id", "studio_module_install", "window_reload"]);
-});
-
-test("add custom field button not shown to non-system users (with opt. col.)", async () => {
- expect.assertions(3);
-
- patchWithCleanup(user, { isSystem: false });
-
- await mountView({
- type: "list",
- resModel: "foo",
- config: getDefaultConfig(),
- arch: /* xml */ `
-
-
-
-
- `,
- });
-
- expect(".o_optional_columns_dropdown_toggle").toHaveCount(1);
-
- await click(".o_optional_columns_dropdown_toggle");
- await animationFrame();
- const dropdown = getDropdownMenu(".o_optional_columns_dropdown");
- expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(1);
- expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(0);
-});
-
-test("add custom field button not shown to non-system users (wo opt. col.)", async () => {
- patchWithCleanup(user, { isSystem: false });
-
- await mountView({
- type: "list",
- resModel: "foo",
- config: getDefaultConfig(),
- arch: /* xml */ `
-
-
-
-
- `,
- });
-
- expect(".o_optional_columns_dropdown_toggle").toHaveCount(0);
-});
-
-test("add custom field button not shown with invalid action", async () => {
- expect.assertions(1);
-
- patchWithCleanup(user, { isSystem: false });
-
- await mountView({
- type: "list",
- resModel: "foo",
- config: { ...getDefaultConfig(), actionId: null },
- arch: /* xml */ `
-
-
-
-
- `,
- });
-
- expect(".o_optional_columns_dropdown_toggle").toHaveCount(0);
-});
-
-test("add custom field button not shown with bank statement line model", async () => {
- class AccountBankStatementLine extends models.Model {
- name = fields.Char();
- _views = {
- kanban: `
-
-
-
-
-
-
-
- `,
- list: `
`,
- };
- }
- defineModels([AccountBankStatementLine]);
-
- expect.assertions(3);
-
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- await getService("action").doAction({
- xml_id: "test",
- id: 1312,
- name: "test",
- res_id: 1,
- res_model: "account.bank.statement.line",
- type: "ir.actions.act_window",
- views: [[false, "kanban"], [false, "list"]],
- });
-
- expect("button.o_switch_view.o_list[data-tooltip='List']").toHaveCount(1);
- await contains("button.o_switch_view.o_list[data-tooltip='List']").click();
- expect(".o_list_renderer .o_list_controller button.dropdown-toggle").toHaveCount(1);
- await contains(".o_list_renderer .o_list_controller button.dropdown-toggle").click();
- expect(".dropdown-item-studio").toHaveCount(0);
-});
-
-test("x2many should not be editable", async () => {
- class Bar extends models.Model {}
- defineModels([Bar]);
- Foo._fields.o2m = fields.One2many({ relation: "bar" });
-
- await mountView({
- type: "form",
- resModel: "foo",
- arch: /* xml */ `
-
- `,
- });
- expect(".o_optional_columns_dropdown_toggle").toHaveCount(0);
- await click(".nav-link:eq(1)");
- await animationFrame();
- await click(".nav-link:eq(0)");
- await animationFrame();
- expect(".o_field_widget").toHaveCount(1);
- expect(".o_optional_columns_dropdown_toggle").toHaveCount(0);
-});
-
-test("upsell studio feature is not polluted by another view", async () => {
- class Partner extends models.Model {
- name = fields.Char();
-
- _views = {
- list: `
`,
- };
- }
-
- defineModels([Partner]);
-
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- await getService("action").doAction({
- xml_id: "editable",
- id: 999,
- type: "ir.actions.act_window",
- views: [[false, "list"]],
- res_model: "partner",
- });
-
- await click(".o_optional_columns_dropdown_toggle");
- await animationFrame();
- expect(".dropdown-item").toHaveCount(2);
- expect(".dropdown-item-studio").toHaveCount(1);
-
- await getService("action").doAction({
- id: 99,
- xml_id: "in_dialog",
- type: "ir.actions.act_window",
- views: [[false, "list"]],
- res_model: "partner",
- target: "new",
- });
-
- await click(".modal .o_optional_columns_dropdown_toggle");
- await animationFrame();
- let dropdown = getDropdownMenu(".modal .o_optional_columns_dropdown");
- expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(1);
- expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(0);
- await click(".modal-header .btn-close");
- await animationFrame();
- expect(".modal").toHaveCount(0);
-
- await click(".o_optional_columns_dropdown_toggle");
- await animationFrame();
- expect(".o-dropdown--menu").toHaveCount(0);
- await click(".o_optional_columns_dropdown_toggle");
- await animationFrame();
-
- dropdown = getDropdownMenu(".o_optional_columns_dropdown");
- expect(queryAll(".dropdown-item", { root: dropdown })).toHaveCount(2);
- expect(queryAll(".dropdown-item-studio", { root: dropdown })).toHaveCount(1);
-});
diff --git a/odex30_base/odex30_web/static/tests/webclient/action_manager_mobile.test.js b/odex30_base/odex30_web/static/tests/webclient/action_manager_mobile.test.js
deleted file mode 100644
index 16f7303..0000000
--- a/odex30_base/odex30_web/static/tests/webclient/action_manager_mobile.test.js
+++ /dev/null
@@ -1,164 +0,0 @@
-import { describe, expect, test } from "@odoo/hoot";
-import { click } from "@odoo/hoot-dom";
-import { animationFrame } from "@odoo/hoot-mock";
-import {
- defineActions,
- defineModels,
- getService,
- fields,
- models,
- mountWithCleanup,
- onRpc,
- stepAllNetworkCalls,
-} from "@web/../tests/web_test_helpers";
-
-import { redirect } from "@web/core/utils/urls";
-import { WebClientOdex } from "@odex30_web/webclient/webclient";
-
-class Partner extends models.Model {
- name = fields.Char();
-
- _records = [
- { id: 1, name: "First record" },
- { id: 2, name: "Second record" },
- ];
- _views = {
- form: `
-
- `,
- kanban: `
-
-
-
-
-
-
-
- `,
- list: `
`,
- };
-}
-
-defineModels([Partner]);
-
-defineActions([
- {
- id: 1,
- name: "Partners Action 1",
- res_model: "partner",
- views: [
- [false, "list"],
- [false, "kanban"],
- [false, "form"],
- ],
- },
- {
- id: 2,
- name: "Partners Action 2",
- res_model: "partner",
- views: [
- [false, "list"],
- [false, "form"],
- ],
- },
-]);
-
-describe.current.tags("mobile");
-
-test("uses a mobile-friendly view by default (if possible)", async () => {
- onRpc("has_group", () => true);
-
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
- // should default on a mobile-friendly view (kanban) for action 1
- await getService("action").doAction(1);
-
- expect(".o_list_view").toHaveCount(0);
- expect(".o_kanban_view").toHaveCount(1);
-
- // there is no mobile-friendly view for action 2, should use the first one (list)
- await getService("action").doAction(2);
-
- expect(".o_list_view").toHaveCount(1);
- expect(".o_kanban_view").toHaveCount(0);
-});
-
-test("lazy load mobile-friendly view", async () => {
- stepAllNetworkCalls();
-
- redirect("/odoo/action-1/new");
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- expect(".o_list_view").toHaveCount(0);
- expect(".o_kanban_view").toHaveCount(0);
- expect(".o_form_view").toHaveCount(1);
-
- // go back to lazy loaded view
- await click(".o_breadcrumb .o_back_button");
- await animationFrame();
- expect(".o_list_view").toHaveCount(0);
- expect(".o_form_view").toHaveCount(0);
- expect(".o_kanban_view").toHaveCount(1);
-
- expect.verifySteps([
- "/web/webclient/translations",
- "/web/webclient/load_menus",
- "/web/action/load",
- "get_views",
- "onchange", // default_get/onchange to open form view
- "web_search_read", // web search read when coming back to Kanban
- ]);
-});
-
-test("lazy load mobile-friendly view; legacy url", async () => {
- stepAllNetworkCalls();
-
- redirect("/web#action=1&view_type=form");
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- expect(".o_list_view").toHaveCount(0);
- expect(".o_kanban_view").toHaveCount(0);
- expect(".o_form_view").toHaveCount(1);
-
- // go back to lazy loaded view
- await click(".o_breadcrumb .o_back_button");
- await animationFrame();
- expect(".o_list_view").toHaveCount(0);
- expect(".o_form_view").toHaveCount(0);
- expect(".o_kanban_view").toHaveCount(1);
-
- expect.verifySteps([
- "/web/webclient/translations",
- "/web/webclient/load_menus",
- "/web/action/load",
- "get_views",
- "onchange", // default_get/onchange to open form view
- "web_search_read", // web search read when coming back to Kanban
- ]);
-});
-
-test("view switcher button should be displayed in dropdown on mobile screens", async () => {
- // This test will spawn a kanban view (mobile friendly).
- // so, the "legacy" code won't be tested here.
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- await getService("action").doAction(1);
-
- expect(".o_control_panel .o_cp_switch_buttons > button").toHaveCount(1);
- expect(".o_control_panel .o_cp_switch_buttons .o_switch_view.o_kanban").toHaveCount(0);
- expect(".o_control_panel .o_cp_switch_buttons button.o_switch_view").toHaveCount(0);
-
- expect(".o_control_panel .o_cp_switch_buttons > button > i").toHaveClass("oi-view-kanban");
- await click(".o_control_panel .o_cp_switch_buttons > button");
- await animationFrame();
-
- expect(".dropdown-item:has(.oi-view-kanban)").toHaveClass("selected");
- expect(".dropdown-item:has(.oi-view-list)").not.toHaveClass("selected");
-});
diff --git a/odex30_base/odex30_web/static/tests/webclient/clickbot.test.js b/odex30_base/odex30_web/static/tests/webclient/clickbot.test.js
deleted file mode 100644
index c95039e..0000000
--- a/odex30_base/odex30_web/static/tests/webclient/clickbot.test.js
+++ /dev/null
@@ -1,176 +0,0 @@
-import { beforeEach, describe, expect, test } from "@odoo/hoot";
-import { Deferred, mockDate } from "@odoo/hoot-mock";
-import {
- defineActions,
- defineMenus,
- defineModels,
- fields,
- models,
- mountWithCleanup,
- onRpc,
- patchWithCleanup,
-} from "@web/../tests/web_test_helpers";
-
-import { browser } from "@web/core/browser/browser";
-import { WebClient } from "@web/webclient/webclient";
-import { SUCCESS_SIGNAL } from "@web/webclient/clickbot/clickbot";
-
-class Foo extends models.Model {
- foo = fields.Char();
- bar = fields.Boolean();
- date = fields.Date();
-
- _records = [
- { id: 1, bar: true, foo: "yop", date: "2017-01-25" },
- { id: 2, bar: true, foo: "blip" },
- { id: 3, bar: true, foo: "gnap" },
- { id: 4, bar: false, foo: "blip" },
- ];
-
- _views = {
- search: /* xml */ `
-
-
-
-
- `,
- list: /* xml */ `
-
-
-
- `,
- kanban: /* xml */ `
-
-
-
-
-
- `,
- };
-}
-
-describe.current.tags("desktop");
-
-defineModels([Foo]);
-
-beforeEach(() => {
- defineActions([
- {
- id: 1001,
- name: "App1",
- res_model: "foo",
- views: [
- [false, "list"],
- [false, "kanban"],
- ],
- xml_id: "app1",
- },
- {
- id: 1002,
- name: "App2 Menu 1",
- res_model: "foo",
- views: [[false, "kanban"]],
- xml_id: "app2_menu1",
- },
- {
- id: 1022,
- name: "App2 Menu 2",
- res_model: "foo",
- views: [[false, "list"]],
- xml_id: "app2_menu2",
- },
- ]);
- defineMenus([
- { id: 1, name: "App1", appID: 1, actionID: 1001, xmlid: "app1" },
- {
- id: 2,
- children: [
- {
- id: 3,
- name: "menu 1",
- appID: 2,
- actionID: 1002,
- xmlid: "app2_menu1",
- },
- {
- id: 4,
- name: "menu 2",
- appID: 2,
- actionID: 1022,
- xmlid: "app2_menu2",
- },
- ],
- name: "App2",
- appID: 2,
- actionID: 1002,
- xmlid: "app2",
- },
- ]);
-});
-
-test("clickbot clickeverywhere test", async () => {
- onRpc("has_group", () => true);
- mockDate("2017-10-08T15:35:11.000");
- const clickEverywhereDef = new Deferred();
- patchWithCleanup(browser, {
- console: {
- log: (msg) => {
- expect.step(msg);
- if (msg === SUCCESS_SIGNAL) {
- clickEverywhereDef.resolve();
- }
- },
- error: (msg) => {
- expect.step(msg);
- clickEverywhereDef.resolve();
- },
- },
- });
- const webClient = await mountWithCleanup(WebClient);
- patchWithCleanup(odoo, {
- __WOWL_DEBUG__: { root: webClient },
- });
- window.clickEverywhere();
- await clickEverywhereDef;
- expect.verifySteps([
- "Clicking on: apps menu toggle button",
- "Testing app menu: app1",
- "Testing menu App1 app1",
- 'Clicking on: menu item "App1"',
- "Testing 2 filters",
- 'Clicking on: filter "Not Bar"',
- 'Clicking on: filter "Date"',
- 'Clicking on: filter option "October"',
- "Testing view switch: kanban",
- "Clicking on: kanban view switcher",
- "Testing 2 filters",
- 'Clicking on: filter "Not Bar"',
- 'Clicking on: filter "Date"',
- 'Clicking on: filter option "October"',
- "Clicking on: apps menu toggle button",
- "Testing app menu: app2",
- "Testing menu App2 app2",
- 'Clicking on: menu item "App2"',
- "Testing 2 filters",
- 'Clicking on: filter "Not Bar"',
- 'Clicking on: filter "Date"',
- 'Clicking on: filter option "October"',
- "Testing menu menu 1 app2_menu1",
- 'Clicking on: menu item "menu 1"',
- "Testing 2 filters",
- 'Clicking on: filter "Not Bar"',
- 'Clicking on: filter "Date"',
- 'Clicking on: filter option "October"',
- "Testing menu menu 2 app2_menu2",
- 'Clicking on: menu item "menu 2"',
- "Testing 2 filters",
- 'Clicking on: filter "Not Bar"',
- 'Clicking on: filter "Date"',
- 'Clicking on: filter option "October"',
- "Successfully tested 2 apps",
- "Successfully tested 2 menus",
- "Successfully tested 0 modals",
- "Successfully tested 10 filters",
- SUCCESS_SIGNAL,
- ]);
-});
diff --git a/odex30_base/odex30_web/static/tests/webclient/expiration_panel.test.js b/odex30_base/odex30_web/static/tests/webclient/expiration_panel.test.js
deleted file mode 100644
index 2a9bf4c..0000000
--- a/odex30_base/odex30_web/static/tests/webclient/expiration_panel.test.js
+++ /dev/null
@@ -1,615 +0,0 @@
-import { expect, test } from "@odoo/hoot";
-import { click, queryFirst, edit } from "@odoo/hoot-dom";
-import { animationFrame, mockDate, runAllTimers } from "@odoo/hoot-mock";
-import {
- getService,
- mockService,
- mountWithCleanup,
- onRpc,
- patchWithCleanup,
- serverState,
-} from "@web/../tests/web_test_helpers";
-
-import { session } from "@web/session";
-import { browser } from "@web/core/browser/browser";
-import { WebClientOdex } from "@odex30_web/webclient/webclient";
-
-test("Expiration Panel one app installed", async () => {
- mockDate("2019-10-10T12:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-11-09 12:00:00",
- expiration_reason: "",
- storeData: true,
- warning: "admin",
- });
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
- await getService("action").doAction("menu");
-
- expect(".oe_instance_register").toHaveText("This database will expire in 1 month.");
-
- expect(".database_expiration_panel").toHaveClass("alert-info");
-
- // Close the expiration panel
- await click(".oe_instance_hide_panel");
- await animationFrame();
-
- expect(".database_expiration_panel").toHaveCount(0);
-});
-
-test("Expiration Panel one app installed, buy subscription", async () => {
- expect.assertions(6);
-
- mockDate("2019-10-10T12:00:00");
- patchWithCleanup(session, {
- expiration_date: "2019-10-24 12:00:00",
- expiration_reason: "demo",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("res.users", "search_count", () => 7);
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
- await runAllTimers();
-
- expect(".oe_instance_register").toHaveText(
- "This demo database will expire in 14 days. Register your subscription or buy a subscription."
- );
-
- expect(".database_expiration_panel").toHaveClass("alert-warning", {
- message: "Color should be orange",
- });
-
- expect(".oe_instance_register_show").toHaveCount(1, {
- message: "Part 'Register your subscription'",
- });
- expect(".oe_instance_buy").toHaveCount(1, { message: "Part 'buy a subscription'" });
- expect(".oe_instance_register_form").toHaveCount(0, {
- message: "There should be no registration form",
- });
-
- // Click on 'buy subscription'
- await click(".oe_instance_buy");
- await animationFrame();
-
- expect(browser.location.href).toBe("https://www.odoo.com/odoo-enterprise/upgrade?num_users=7");
-});
-
-test("Expiration Panel one app installed, try several times to register subscription", async () => {
- expect.assertions(33);
-
- mockDate("2019-10-10T12:00:00");
-
- let callToGetParamCount = 0;
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-15 12:00:00",
- expiration_reason: "trial",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
-
- mockService("notification", {
- add: (message, options) => {
- expect.step(JSON.stringify({ message, options }));
- },
- });
- onRpc("get_param", ({ args }) => {
- expect.step("get_param");
- if (args[0] === "database.already_linked_subscription_url") {
- return false;
- }
- if (args[0] === "database.already_linked_email") {
- return "super_company_admin@gmail.com";
- }
- expect(args[0]).toBe("database.expiration_date");
- callToGetParamCount++;
- if (callToGetParamCount <= 3) {
- return "2019-10-15 12:00:00";
- } else {
- return "2019-11-15 12:00:00";
- }
- });
- onRpc("set_param", ({ args }) => {
- expect.step("set_param");
- expect(args[0]).toBe("database.enterprise_code");
- if (callToGetParamCount === 1) {
- expect(args[1]).toBe("ABCDEF");
- } else {
- expect(args[1]).toBe("ABC");
- }
- return true;
- });
- onRpc("update_notification", ({ args }) => {
- expect.step("update_notification");
- expect(args[0]).toBeInstanceOf(Array);
- expect(args[0]).toHaveLength(0);
- return true;
- });
- onRpc("res.users", "search_count", () => 7);
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- expect(".oe_instance_register").toHaveText(
- "This database will expire in 5 days. Register your subscription or buy a subscription."
- );
-
- expect(".database_expiration_panel").toHaveClass("alert-danger", {
- message: "Color should be red",
- });
-
- expect(".oe_instance_register_show").toHaveCount(1, {
- message: "Part 'Register your subscription'",
- });
- expect(".oe_instance_buy").toHaveCount(1, { message: "Part 'buy a subscription'" });
- expect(".oe_instance_register_form").toHaveCount(0, {
- message: "There should be no registration form",
- });
-
- // Click on 'buy subscription'
- await click(".oe_instance_register_show");
- await animationFrame();
-
- expect(".oe_instance_register_form").toHaveCount(1, {
- message: "there should be a registration form",
- });
- expect('.oe_instance_register_form input[placeholder="Paste code here"]').toHaveCount(1, {
- message: "with an input with place holder 'Paste code here'",
- });
- expect(".oe_instance_register_form button").toHaveCount(1, {
- message: "and a button 'Register'",
- });
- expect(".oe_instance_register_form button").toHaveText("Register");
-
- await click(".oe_instance_register_form button");
- await animationFrame();
-
- expect(".oe_instance_register_form").toHaveCount(1, {
- message: "there should be a registration form",
- });
- expect('.oe_instance_register_form input[placeholder="Paste code here"]').toHaveCount(1, {
- message: "with an input with place holder 'Paste code here'",
- });
- expect(".oe_instance_register_form button").toHaveCount(1, {
- message: "and a button 'Register'",
- });
-
- await click(".oe_instance_register_form input");
- await edit("ABCDEF");
- await animationFrame();
- await click(".oe_instance_register_form button");
- await animationFrame();
-
- expect(queryFirst(".oe_instance_register")).toHaveText(
- "Something went wrong while registering your database. You can try again or contact Odoo Support."
- );
- expect(".database_expiration_panel").toHaveClass("alert-danger", {
- message: "Color should be red",
- });
- expect("span.oe_instance_error").toHaveCount(1);
- expect(".oe_instance_register_form").toHaveCount(1, {
- message: "there should be a registration form",
- });
- expect('.oe_instance_register_form input[placeholder="Paste code here"]').toHaveCount(1, {
- message: "with an input with place holder 'Paste code here'",
- });
- expect(".oe_instance_register_form button").toHaveCount(1, {
- message: "and a button 'Register'",
- });
- expect(".oe_instance_register_form button").toHaveText("Retry");
-
- await click(".oe_instance_register_form input");
- await edit("ABC");
- await animationFrame();
- await click(".oe_instance_register_form button");
- await animationFrame();
-
- expect(".database_expiration_panel").toHaveCount(0, {
- message: "expiration panel should be gone",
- });
-
- expect.verifySteps([
- // second try to submit
- "get_param",
- "set_param",
- "update_notification",
- "get_param",
- "get_param",
- "get_param",
- // third try
- "get_param",
- "set_param",
- "update_notification",
- "get_param",
- "get_param",
- "get_param",
- `{"message":"Thank you, your registration was successful! Your database is valid until November 15, 2019.","options":{"type":"success"}}`,
- ]);
-});
-
-test("Expiration Panel one app installed, subscription already linked", async () => {
- expect.assertions(5);
-
- mockDate("2019-10-10T12:00:00");
-
- let getExpirationDateCount = 0;
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-15 12:00:00",
- expiration_reason: "trial",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("/already/linked/send/mail/url", () => ({
- result: false,
- reason: "By design",
- }));
- onRpc("get_param", ({ args }) => {
- expect.step("get_param");
- if (args[0] === "database.expiration_date") {
- getExpirationDateCount++;
- if (getExpirationDateCount === 1) {
- return "2019-10-15 12:00:00";
- } else {
- return "2019-11-17 12:00:00";
- }
- }
- if (args[0] === "database.already_linked_subscription_url") {
- return "www.super_company.com";
- }
- if (args[0] === "database.already_linked_send_mail_url") {
- return "/already/linked/send/mail/url";
- }
- if (args[0] === "database.already_linked_email") {
- return "super_company_admin@gmail.com";
- }
- });
- onRpc("set_param", () => {
- expect.step("set_param");
- return true;
- });
- onRpc("update_notification", () => {
- expect.step("update_notification");
- return true;
- });
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- expect(".oe_instance_register").toHaveText(
- "This database will expire in 5 days. Register your subscription or buy a subscription."
- );
- // Click on 'register your subscription'
- await click(".oe_instance_register_show");
- await animationFrame();
- await click(".oe_instance_register_form input");
- await edit("ABC");
- await click(".oe_instance_register_form button");
- await animationFrame();
-
- expect(".oe_instance_register.oe_database_already_linked").toHaveText(
- `Your subscription is already linked to a database.\nSend an email to the subscription owner to confirm the change, enter a new code or buy a subscription.`
- );
-
- await click("a.oe_contract_send_mail");
- await animationFrame();
- expect(".database_expiration_panel").toHaveClass("alert-danger", {
- message: "Color should be red",
- });
-
- expect(".oe_instance_register.oe_database_already_linked").toHaveText(
- `Your subscription is already linked to a database.\nSend an email to the subscription owner to confirm the change, enter a new code or buy a subscription.\n\nUnable to send the instructions by email, please contact the Odoo Support\nError reason: By design`
- );
-
- expect.verifySteps([
- "get_param",
- "set_param",
- "update_notification",
- "get_param",
- "get_param",
- "get_param",
- "get_param",
- ]);
-});
-
-test("One app installed, database expired", async () => {
- expect.assertions(8);
-
- mockDate("2019-10-10T12:00:00");
-
- let callToGetParamCount = 0;
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-08 12:00:00",
- expiration_reason: "trial",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("/already/linked/send/mail/url", () => ({
- result: false,
- reason: "By design",
- }));
- onRpc("get_param", ({ args }) => {
- if (args[0] === "database.already_linked_subscription_url") {
- return false;
- }
- callToGetParamCount++;
- if (callToGetParamCount === 1) {
- return "2019-10-09 12:00:00";
- } else {
- return "2019-11-09 12:00:00";
- }
- });
- onRpc("set_param", () => true);
- onRpc("update_notification", () => true);
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- expect(".oe_instance_register").toHaveText(
- "This database has expired. Register your subscription or buy a subscription."
- );
- expect(".o_blockUI").toHaveCount(1, { message: "UI should be blocked" });
-
- expect(".database_expiration_panel").toHaveClass("alert-danger", {
- message: "Color should be red",
- });
- expect(".oe_instance_register_show").toHaveCount(1, {
- message: "Part 'Register your subscription'",
- });
- expect(".oe_instance_buy").toHaveCount(1, { message: "Part 'buy a subscription'" });
-
- expect(".oe_instance_register_form").toHaveCount(0);
-
- // Click on 'Register your subscription'
- await click(".oe_instance_register_show");
- await animationFrame();
- await click(".oe_instance_register_form input");
- await edit("ABC");
- await click(".oe_instance_register_form button");
- await animationFrame();
-
- expect(".oe_instance_register").toHaveText(
- "Thank you, your registration was successful! Your database is valid until November 9, 2019."
- );
- expect(".o_blockUI").toHaveCount(0, { message: "UI should no longer be blocked" });
-});
-
-test("One app installed, renew", async () => {
- expect.assertions(7);
-
- mockDate("2019-10-10T12:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-20 12:00:00",
- expiration_reason: "renewal",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("get_param", ({ args }) => {
- expect.step("get_param");
- expect(args[0]).toBe("database.enterprise_code");
- return "ABC";
- });
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- expect(".oe_instance_register").toHaveText(
- "Your subscription expired 9 days ago. This database will be blocked soon.\n" +
- "Renew now\n" +
- "I paid, please recheck!"
- );
-
- expect(".database_expiration_panel").toHaveClass("alert-warning", {
- message: "Color should be orange",
- });
- expect(".oe_instance_renew").toHaveCount(1, { message: "Part 'Register your subscription'" });
- expect("a.check_enterprise_status").toHaveCount(1, {
- message: "there should be a button for status checking",
- });
-
- expect(".oe_instance_register_form").toHaveCount(0);
-
- // Click on 'Renew your subscription'
- await click(".oe_instance_renew");
- await animationFrame();
-
- expect.verifySteps(["get_param"]);
-});
-
-test("One app installed, check status and get success", async () => {
- expect.assertions(4);
-
- mockDate("2019-10-10T12:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-20 12:00:00",
- expiration_reason: "renewal",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("get_param", ({ args }) => {
- expect.step("get_param");
- expect(args[0]).toBe("database.expiration_date");
- return "2019-10-24 12:00:00";
- });
- onRpc("update_notification", () => {
- expect.step("update_notification");
- return true;
- });
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- // click on "I paid, please recheck!"
- expect("a.check_enterprise_status").toHaveText("I paid, please recheck!");
- await click("a.check_enterprise_status");
- await animationFrame();
-
- expect(".oe_instance_register.oe_subscription_updated").toHaveText(
- "Your subscription was updated and is valid until October 24, 2019."
- );
-
- expect.verifySteps(["update_notification", "get_param"]);
-});
-
-// Why would we want to reload the page when we check the status and it hasn't changed?
-test.skip("One app installed, check status and get page reload", async () => {
- expect.assertions(4);
-
- mockDate("2019-10-10T12:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-20 12:00:00",
- expiration_reason: "renewal",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("get_param", () => {
- expect.step("get_param");
- return "2019-10-20 12:00:00";
- });
- onRpc("update_notification", () => {
- expect.step("update_notification");
- return true;
- });
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- // click on "I paid, please recheck!"
- await click("a.check_enterprise_status");
- await animationFrame();
-
- expect.verifySteps(["update_notification", "get_param", "reloadPage"]);
-});
-
-test("One app installed, upgrade database", async () => {
- expect.assertions(4);
-
- mockDate("2019-10-10T12:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-20 12:00:00",
- expiration_reason: "upsell",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("get_param", ({ args }) => {
- expect.step("get_param");
- expect(args[0]).toBe("database.enterprise_code");
- return "ABC";
- });
- onRpc("search_count", () => {
- expect.step("search_count");
- return 13;
- });
- onRpc("update_notification", () => true);
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
- await runAllTimers();
-
- expect(".oe_instance_register").toHaveText(
- "This database will expire in 10 days. You have more users or more apps installed than your subscription allows.\n\n" +
- "Upgrade your subscription\n" +
- "I paid, please recheck!"
- );
-
- await click("a.oe_instance_upsell");
- await animationFrame();
-
- expect.verifySteps(["get_param", "search_count"]);
- expect(browser.location.href).toBe(
- "https://www.odoo.com/odoo-enterprise/upsell?num_users=13&contract=ABC"
- );
-});
-
-test("One app installed, message for non admin user", async () => {
- expect.assertions(2);
-
- mockDate("2019-10-10T12:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-11-08 12:00:00",
- expiration_reason: "",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "user",
- });
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- expect(".oe_instance_register").toHaveText(
- "This database will expire in 29 days. Log in as an administrator to correct the issue."
- );
-
- expect(".database_expiration_panel").toHaveClass("alert-info", {
- message: "Color should be grey",
- });
-});
-
-test("One app installed, navigation to renewal page", async () => {
- expect.assertions(8);
-
- mockDate("2019-11-10T00:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-20 12:00:00",
- expiration_reason: "renewal",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- onRpc("get_param", ({ args }) => {
- expect.step("get_param");
- expect(args[0]).toBe("database.enterprise_code");
- return "ABC";
- });
- onRpc("update_notification", () => {
- expect.step("update_notification");
- return true;
- });
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
- await runAllTimers();
-
- expect(".oe_instance_register").toHaveText(
- "This database has expired.\nRenew now\nI paid, please recheck!"
- );
-
- expect(".database_expiration_panel").toHaveClass("alert-danger");
- expect(".oe_instance_renew").toHaveCount(1, { message: "Part 'Register your subscription'" });
- expect("a.check_enterprise_status").toHaveCount(1, {
- message: "there should be a button for status checking",
- });
-
- expect(".oe_instance_register_form").toHaveCount(0);
-
- // Click on 'Renew your subscription'
- await click(".oe_instance_renew");
- await animationFrame();
-
- expect(browser.location.href).toBe("https://www.odoo.com/odoo-enterprise/renew?contract=ABC");
-
- expect.verifySteps(["get_param"]);
-});
-
-test("One app installed, different locale (arabic)", async () => {
- expect.assertions(1);
-
- mockDate("2019-25-09T12:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-10-20 12:00:00",
- expiration_reason: "renewal",
- storeData: true, // used by subscription service to know whether mail is installed
- warning: "admin",
- });
- serverState.lang = "ar-001";
- onRpc("get_param", () => "2019-11-09 12:00:00");
- onRpc("update_notification", () => true);
- await mountWithCleanup(WebClientOdex);
- await animationFrame();
-
- await click("a.check_enterprise_status");
- await animationFrame();
-
- expect(".oe_instance_register").toHaveText(
- "Your subscription was updated and is valid until ٩ نوفمبر ٢٠١٩."
- );
-});
diff --git a/odex30_base/odex30_web/static/tests/webclient/home_menu.test.js b/odex30_base/odex30_web/static/tests/webclient/home_menu.test.js
deleted file mode 100644
index 13020ed..0000000
--- a/odex30_base/odex30_web/static/tests/webclient/home_menu.test.js
+++ /dev/null
@@ -1,353 +0,0 @@
-import { describe, expect, test } from "@odoo/hoot";
-import { click, drag, keyDown, pointerDown, queryFirst } from "@odoo/hoot-dom";
-import { advanceTime, animationFrame, mockDate, mockTouch } from "@odoo/hoot-mock";
-import {
- getService,
- mountWithCleanup,
- onRpc,
- patchWithCleanup,
-} from "@web/../tests/web_test_helpers";
-
-import { reactive } from "@odoo/owl";
-import { session } from "@web/session";
-import { HomeMenu } from "@odex30_web/webclient/home_menu/home_menu";
-import { reorderApps } from "@web/webclient/menus/menu_helpers";
-
-async function walkOn(path) {
- for (const step of path) {
- await keyDown(`${step.shiftKey ? "shift+" : ""}${step.key}`);
- await animationFrame();
- expect(`.o_menuitem:eq(${step.index})`).toHaveClass("o_focused", {
- message: `step ${step.number}`,
- });
- }
-}
-
-const getDefaultHomeMenuProps = () => {
- const apps = [
- {
- actionID: 121,
- href: "/odoo/action-121",
- appID: 1,
- id: 1,
- label: "Discuss",
- parents: "",
- webIcon: false,
- xmlid: "app.1",
- },
- {
- actionID: 122,
- href: "/odoo/action-122",
- appID: 2,
- id: 2,
- label: "Calendar",
- parents: "",
- webIcon: false,
- xmlid: "app.2",
- },
- {
- actionID: 123,
- href: "/odoo/contacts",
- appID: 3,
- id: 3,
- label: "Contacts",
- parents: "",
- webIcon: false,
- xmlid: "app.3",
- },
- ];
- return { apps, reorderApps: (order) => reorderApps(apps, order) };
-};
-
-describe.current.tags("desktop");
-
-test("ESC Support", async () => {
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
- patchWithCleanup(getService("home_menu"), {
- async toggle(show) {
- expect.step(`toggle ${show}`);
- },
- });
- await keyDown("escape");
- expect.verifySteps(["toggle false"]);
-});
-
-test("Click on an app", async () => {
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
- patchWithCleanup(getService("menu"), {
- async selectMenu(menu) {
- expect.step(`selectMenu ${menu.id}`);
- },
- });
- await click(".o_menuitem:eq(0)");
- await animationFrame();
- expect.verifySteps(["selectMenu 1"]);
-});
-
-test("Display Expiration Panel (no module installed)", async () => {
- mockDate("2019-10-09T00:00:00");
-
- patchWithCleanup(session, {
- expiration_date: "2019-11-01 12:00:00",
- expiration_reason: "",
- isMailInstalled: false,
- warning: "admin",
- });
-
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
-
- expect(".database_expiration_panel").toHaveCount(1);
- expect(".database_expiration_panel .oe_instance_register").toHaveText(
- "You will be able to register your database once you have installed your first app.",
- { message: "There should be an expiration panel displayed" }
- );
-
- // Close the expiration panel
- await click(".database_expiration_panel .oe_instance_hide_panel");
- await animationFrame();
- expect(".database_expiration_panel").toHaveCount(0);
-});
-
-test("Navigation (only apps, only one line)", async () => {
- expect.assertions(8);
-
- const homeMenuProps = {
- apps: new Array(3).fill().map((x, i) => {
- return {
- actionID: 120 + i,
- href: "/odoo/act" + (120 + i),
- appID: i + 1,
- id: i + 1,
- label: `0${i}`,
- parents: "",
- webIcon: false,
- xmlid: `app.${i}`,
- };
- }),
- reorderApps: (order) => reorderApps(homeMenuProps.apps, order),
- };
- await mountWithCleanup(HomeMenu, {
- props: homeMenuProps,
- });
-
- const path = [
- { number: 0, key: "ArrowDown", index: 0 },
- { number: 1, key: "ArrowRight", index: 1 },
- { number: 2, key: "Tab", index: 2 },
- { number: 3, key: "ArrowRight", index: 0 },
- { number: 4, key: "Tab", shiftKey: true, index: 2 },
- { number: 5, key: "ArrowLeft", index: 1 },
- { number: 6, key: "ArrowDown", index: 1 },
- { number: 7, key: "ArrowUp", index: 1 },
- ];
-
- await walkOn(path);
-});
-
-test("Navigation (only apps, two lines, one incomplete)", async () => {
- expect.assertions(19);
-
- const homeMenuProps = {
- apps: new Array(8).fill().map((x, i) => {
- return {
- actionID: 121,
- href: "/odoo/action-121",
- appID: i + 1,
- id: i + 1,
- label: `0${i}`,
- parents: "",
- webIcon: false,
- xmlid: `app.${i}`,
- };
- }),
- reorderApps: (order) => reorderApps(homeMenuProps.apps, order),
- };
- await mountWithCleanup(HomeMenu, {
- props: homeMenuProps,
- });
-
- const path = [
- { number: 1, key: "ArrowRight", index: 0 },
- { number: 2, key: "ArrowUp", index: 6 },
- { number: 3, key: "ArrowUp", index: 0 },
- { number: 4, key: "ArrowDown", index: 6 },
- { number: 5, key: "ArrowDown", index: 0 },
- { number: 6, key: "ArrowRight", index: 1 },
- { number: 7, key: "ArrowRight", index: 2 },
- { number: 8, key: "ArrowUp", index: 7 },
- { number: 9, key: "ArrowUp", index: 1 },
- { number: 10, key: "ArrowRight", index: 2 },
- { number: 11, key: "ArrowDown", index: 7 },
- { number: 12, key: "ArrowDown", index: 1 },
- { number: 13, key: "ArrowUp", index: 7 },
- { number: 14, key: "ArrowRight", index: 6 },
- { number: 15, key: "ArrowLeft", index: 7 },
- { number: 16, key: "ArrowUp", index: 1 },
- { number: 17, key: "ArrowLeft", index: 0 },
- { number: 18, key: "ArrowLeft", index: 5 },
- { number: 19, key: "ArrowRight", index: 0 },
- ];
-
- await walkOn(path);
-});
-
-test("Navigation and open an app in the home menu", async () => {
- expect.assertions(6);
-
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
- patchWithCleanup(getService("menu"), {
- async selectMenu(menu) {
- expect.step(`selectMenu ${menu.id}`);
- },
- });
- // No app selected so nothing to open
- await keyDown("enter");
- expect.verifySteps([]);
-
- const path = [
- { number: 0, key: "ArrowDown", index: 0 },
- { number: 1, key: "ArrowRight", index: 1 },
- { number: 2, key: "Tab", index: 2 },
- { number: 3, key: "shift+Tab", index: 1 },
- ];
-
- await walkOn(path);
-
- // open first app (Calendar)
- await keyDown("enter");
-
- expect.verifySteps(["selectMenu 2"]);
-});
-
-test("Reorder apps in home menu using drag and drop", async () => {
- const homeMenuProps = {
- apps: reactive(
- new Array(8).fill().map((x, i) => {
- return {
- actionID: 121,
- href: "/odoo/action-121",
- appID: i + 1,
- id: i + 1,
- label: `0${i}`,
- parents: "",
- webIcon: false,
- xmlid: `app.${i}`,
- };
- })
- ),
- reorderApps: (order) => reorderApps(homeMenuProps.apps, order),
- };
- onRpc("set_res_users_settings", () => {
- expect.step(`set_res_users_settings`);
- return {
- id: 1,
- homemenu_config: '["app.1","app.2","app.3","app.0","app.4","app.5","app.6","app.7"]',
- };
- });
- await mountWithCleanup(HomeMenu, {
- props: homeMenuProps,
- });
-
- const { moveTo, drop } = await drag(".o_draggable:first-child");
- await advanceTime(250);
- expect(".o_draggable:first-child a").not.toHaveClass("o_dragged_app");
- await advanceTime(250);
- expect(".o_draggable:first-child a").toHaveClass("o_dragged_app");
- await moveTo(".o_draggable:first-child", {
- position: {
- x: 70,
- y: 35,
- },
- relative: true,
- });
- await drop(".o_draggable:not(.o_dragged):eq(3)");
- await animationFrame();
- expect.verifySteps(["set_res_users_settings"]);
- expect(".o_app:eq(0)").toHaveAttribute("data-menu-xmlid", "app.1", {
- message: "first displayed app has app.1 xmlid",
- });
- expect(".o_app:eq(3)").toHaveAttribute("data-menu-xmlid", "app.0", {
- message: "app 0 is now at 4th position",
- });
-});
-
-test("The HomeMenu input takes the focus when you press a key only if no other element is the activeElement", async () => {
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
- expect(".o_search_hidden").toBeFocused();
-
- const activeElement = document.createElement("div");
- getService("ui").activateElement(activeElement);
- // remove the focus from the input
- const otherInput = document.createElement("input");
- queryFirst(".o_home_menu").appendChild(otherInput);
- await pointerDown(otherInput);
- await pointerDown(document.body);
- expect(".o_search_hidden").not.toBeFocused();
-
- await keyDown("a");
- await animationFrame();
- expect(".o_search_hidden").not.toBeFocused();
-
- getService("ui").deactivateElement(activeElement);
- await keyDown("a");
- await animationFrame();
- expect(".o_search_hidden").toBeFocused();
-});
-
-test("The HomeMenu input does not take the focus if it is already on another input", async () => {
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
- expect(".o_search_hidden").toBeFocused();
-
- const otherInput = document.createElement("input");
- queryFirst(".o_home_menu").appendChild(otherInput);
- await pointerDown(otherInput);
- await keyDown("a");
- await animationFrame();
- expect(".o_search_hidden").not.toBeFocused();
-
- otherInput.remove();
- await keyDown("a");
- await animationFrame();
- expect(".o_search_hidden").toBeFocused();
-});
-
-test("The HomeMenu input does not take the focus if it is already on a textarea", async () => {
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
- expect(".o_search_hidden").toBeFocused();
-
- const textarea = document.createElement("textarea");
- queryFirst(".o_home_menu").appendChild(textarea);
- await pointerDown(textarea);
- await keyDown("a");
- await animationFrame();
- expect(".o_search_hidden").not.toBeFocused();
-
- textarea.remove();
- await keyDown("a");
- await animationFrame();
- expect(".o_search_hidden").toBeFocused();
-});
-
-test("home search input shouldn't be focused on touch devices", async () => {
- mockTouch(true);
- await mountWithCleanup(HomeMenu, {
- props: getDefaultHomeMenuProps(),
- });
- expect(".o_search_hidden").not.toBeFocused({
- message: "home menu search input shouldn't have the focus",
- });
-});
diff --git a/odex30_base/odex30_web/static/tests/webclient/webclient_enterprise.test.js b/odex30_base/odex30_web/static/tests/webclient/webclient_enterprise.test.js
deleted file mode 100644
index ef36fdf..0000000
--- a/odex30_base/odex30_web/static/tests/webclient/webclient_enterprise.test.js
+++ /dev/null
@@ -1,798 +0,0 @@
-import { beforeEach, describe, expect, test } from "@odoo/hoot";
-import { click, keyDown, queryAll, queryFirst } from "@odoo/hoot-dom";
-import { animationFrame, Deferred, mockMatchMedia } from "@odoo/hoot-mock";
-import { Component, onMounted, xml } from "@odoo/owl";
-import {
- clearRegistry,
- contains,
- defineActions,
- defineMenus,
- defineModels,
- fields,
- getMockEnv,
- getService,
- models,
- mountWithCleanup,
- onRpc,
- patchWithCleanup,
- serverState,
- stepAllNetworkCalls,
-} from "@web/../tests/web_test_helpers";
-import { browser } from "@web/core/browser/browser";
-import { router } from "@web/core/browser/router";
-import { registry } from "@web/core/registry";
-import { config as transitionConfig } from "@web/core/transition";
-import { user } from "@web/core/user";
-import { redirect } from "@web/core/utils/urls";
-import { UserMenu } from "@web/webclient/user_menu/user_menu";
-import { shareUrlMenuItem } from "@odex30_web/webclient/share_url/share_url";
-import { WebClientOdex } from "@odex30_web/webclient/webclient";
-
-const actionRegistry = registry.category("actions");
-
-/**
- * @param {{ env: import("@web/env").OdooEnv }} [options]
- */
-async function mountWebClientOdex(options) {
- await mountWithCleanup(WebClientOdex, options);
- // Wait for visual changes caused by a potential loadState
- await animationFrame();
- // wait for BlankComponent
- await animationFrame();
- // wait for the regular rendering
- await animationFrame();
-}
-
-async function goToHomeMenu() {
- await click(".o_menu_toggle");
- await animationFrame();
-
- if (getMockEnv().isSmall) {
- await click(queryFirst(".o_sidebar_topbar a.btn-primary", { root: document.body }));
- await animationFrame();
- }
-}
-
-defineActions([
- {
- id: 1,
- xml_id: "action_1",
- name: "Partners Action 1",
- res_model: "partner",
- views: [[false, "kanban"]],
- },
- {
- id: 2,
- xml_id: "action_2",
- type: "ir.actions.server",
- },
- {
- id: 3,
- xml_id: "action_3",
- name: "Partners",
- res_model: "partner",
- views: [
- [false, "list"],
- [false, "kanban"],
- [false, "form"],
- ],
- },
- {
- id: 4,
- xml_id: "action_4",
- name: "Partners Action 4",
- res_model: "partner",
- views: [
- [false, "kanban"],
- [false, "list"],
- [false, "form"],
- ],
- },
- {
- id: 5,
- xml_id: "action_5",
- name: "Create a Partner",
- res_model: "partner",
- target: "new",
- views: [[false, "form"]],
- },
- {
- id: 6,
- xml_id: "action_6",
- name: "Partner",
- res_id: 2,
- res_model: "partner",
- target: "inline",
- views: [[false, "form"]],
- },
- {
- id: 1001,
- tag: "__test__client__action__",
- target: "main",
- type: "ir.actions.client",
- params: { description: "Id 1" },
- },
- {
- id: 1002,
- tag: "__test__client__action__",
- target: "main",
- type: "ir.actions.client",
- params: { description: "Id 2" },
- },
-]);
-
-defineMenus([
- { id: 0 }, // prevents auto-loading the first action
- { id: 1, name: "App1", appID: 1, actionID: 1001, xmlid: "menu_1" },
- { id: 2, name: "App2", appID: 2, actionID: 1002, xmlid: "menu_2" },
-]);
-class Partner extends models.Model {
- name = fields.Char();
- foo = fields.Char();
- parent_id = fields.Many2one({ relation: "partner" });
- child_ids = fields.One2many({ relation: "partner", relation_field: "parent_id" });
-
- _records = [
- { id: 1, name: "First record", foo: "yop", parent_id: 3 },
- { id: 2, name: "Second record", foo: "blip", parent_id: 3 },
- { id: 3, name: "Third record", foo: "gnap", parent_id: 1 },
- { id: 4, name: "Fourth record", foo: "plop", parent_id: 1 },
- { id: 5, name: "Fifth record", foo: "zoup", parent_id: 1 },
- ];
- _views = {
- kanban: `
-
-
-
-
-
-
-
- `,
- list: `
`,
- form: `
-
- `,
- search: ` `,
- };
-}
-defineModels([Partner]);
-class TestClientAction extends Component {
- static template = xml`
-
- ClientAction_
-
- `;
- static props = ["*"];
-
- setup() {
- onMounted(() => {
- this.env.config.setDisplayName(`Client action ${this.props.action.id}`);
- });
- }
-}
-
-onRpc("has_group", () => true);
-
-beforeEach(() => {
- actionRegistry.add("__test__client__action__", TestClientAction);
- patchWithCleanup(transitionConfig, { disabled: true });
-});
-
-describe("basic flow with home menu", () => {
- stepAllNetworkCalls();
- onRpc("partner", "get_formview_action", () => ({
- type: "ir.actions.act_window",
- res_model: "partner",
- view_type: "form",
- view_mode: "form",
- views: [[false, "form"]],
- target: "current",
- res_id: 2,
- }));
- defineMenus(
- [
- {
- id: 1,
- name: "App1",
- appID: 1,
- actionID: 4,
- xmlid: "menu_1",
- },
- ],
- { mode: "replace" }
- );
- test("1 -- start up", async () => {
- await mountWebClientOdex();
- expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]);
- expect(document.body).toHaveClass("o_home_menu_background");
- expect(".o_home_menu").toHaveCount(1);
- expect(".o_menu_toggle").not.toBeVisible();
- expect(".o_app.o_menuitem").toHaveCount(1);
- });
-
- test("2 -- navbar updates on displaying an action", async () => {
- await mountWebClientOdex();
- expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]);
- await contains(".o_app.o_menuitem").click();
- await animationFrame();
- expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]);
- expect(document.body).not.toHaveClass("o_home_menu_background");
- expect(".o_home_menu").toHaveCount(0);
- expect(".o_kanban_view").toHaveCount(1);
- expect(".o_menu_toggle").toBeVisible();
- expect(".o_menu_toggle").not.toHaveClass("o_menu_toggle_back");
- });
-
- test("3 -- push another action in the breadcrumb", async () => {
- await mountWebClientOdex();
- expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]);
- await contains(".o_app.o_menuitem").click();
- await animationFrame();
- expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]);
- expect(".o_kanban_view").toHaveCount(1);
- await contains(".o_kanban_record").click();
- await animationFrame(); // there is another tick to update navbar and destroy HomeMenu
- expect.verifySteps(["web_read"]);
- expect(".o_menu_toggle").toBeVisible();
- expect(".o_form_view").toHaveCount(1);
- expect(".o_breadcrumb .active").toHaveText("First record");
- });
-
- test.tags("desktop");
- test("4 -- push a third action in the breadcrumb", async () => {
- Partner._views["form"] = `
-
- `;
- await mountWebClientOdex();
- expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]);
- await contains(".o_app.o_menuitem").click();
- await animationFrame();
- expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]);
- expect(".o_kanban_view").toHaveCount(1);
- await contains(".o_kanban_record").click();
- expect.verifySteps(["web_read"]);
- await contains('.o_field_widget[name="parent_id"] .o_external_button', {
- visible: false,
- }).click();
- expect.verifySteps(["get_formview_action", "get_views", "web_read"]);
- expect(".o_form_view").toHaveCount(1);
- expect(".o_breadcrumb .active").toHaveText("Second record");
- // The third one is the active one
- expect(".breadcrumb-item").toHaveCount(2);
- });
-
- test("5 -- switch to HomeMenu from an action with 2 breadcrumbs", async () => {
- Partner._views["form"] = `
-
- `;
- await mountWebClientOdex();
- expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]);
- await contains(".o_app.o_menuitem").click();
- await animationFrame();
- expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]);
- expect(".o_kanban_view").toHaveCount(1);
- await contains(".o_kanban_record").click();
- expect.verifySteps(["web_read"]);
- await contains('.o_field_widget[name="parent_id"] .o_external_button', {
- visible: false,
- }).click();
- expect.verifySteps(["get_formview_action", "get_views", "web_read"]);
- await goToHomeMenu();
- expect.verifySteps([]);
- expect(".o_menu_toggle").toHaveClass("o_menu_toggle_back");
- expect(".o_home_menu").toHaveCount(1);
- expect(".o_form_view").not.toHaveCount();
- });
-
- test.tags("desktop");
- test("6 -- back to underlying action with many breadcrumbs", async () => {
- Partner._views["form"] = `
-
- `;
- await mountWebClientOdex();
- expect.verifySteps(["/web/webclient/translations", "/web/webclient/load_menus"]);
- await contains(".o_app.o_menuitem").click();
- await animationFrame();
- expect.verifySteps(["/web/action/load", "get_views", "web_search_read"]);
- expect(".o_kanban_view").toHaveCount(1);
- await contains(".o_kanban_record").click();
- expect.verifySteps(["web_read"]);
- await contains('.o_field_widget[name="parent_id"] .o_external_button', {
- visible: false,
- }).click();
- expect.verifySteps(["get_formview_action", "get_views", "web_read"]);
- await contains(".o_menu_toggle").click();
-
- // can't click again too soon because of the mutex in home_menu
- // service (waiting for the url to be updated)
- await animationFrame();
-
- await contains(".o_menu_toggle").click();
-
- expect.verifySteps(["web_read"]);
- expect(".o_home_menu").toHaveCount(0);
- expect(".o_form_view").toHaveCount(1);
- expect(".o_menu_toggle").not.toHaveClass("o_menu_toggle_back");
- expect(".o_breadcrumb .active").toHaveText("Second record");
- // Third breadcrumb is the active one
- expect(".breadcrumb-item").toHaveCount(2);
- });
-});
-
-test("restore the newly created record in form view", async () => {
- defineActions(
- [
- {
- id: 6,
- xml_id: "action_6",
- name: "Partner",
- res_model: "partner",
- views: [[false, "form"]],
- },
- ],
- { mode: "replace" }
- );
- await mountWebClientOdex();
-
- await getService("action").doAction(6);
- expect(".o_form_view").toHaveCount(1);
- expect(".o_form_view .o_form_editable").toHaveCount(1);
- await contains(".o_field_widget[name=name] input").edit("red right hand");
- await contains(".o_form_button_save").click();
- expect(".o_breadcrumb .active").toHaveText("red right hand");
- await goToHomeMenu();
- expect(".o_form_view").not.toHaveCount();
-
- // can't click again too soon because of the mutex in home_menu
- // service (waiting for the url to be updated)
- await animationFrame();
-
- await contains(".o_menu_toggle").click();
- expect(".o_form_view").toHaveCount(1);
- expect(".o_form_view .o_form_saved").toHaveCount(1);
- expect(".o_breadcrumb .active").toHaveText("red right hand");
-});
-
-test.tags("desktop");
-test("fast clicking on restore (implementation detail)", async () => {
- expect.assertions(8);
-
- let doVeryFastClick = false;
-
- class DelayedClientAction extends Component {
- static template = xml`
- RESOLVE
-
`;
- static props = ["*"];
- setup() {
- onMounted(() => {
- if (doVeryFastClick) {
- doVeryFastClick = false;
- click(".o_menu_toggle"); // go to home menu
- }
- });
- }
- }
-
- registry.category("actions").add("DelayedClientAction", DelayedClientAction);
- await mountWebClientOdex();
- await getService("action").doAction("DelayedClientAction");
- await animationFrame();
- await contains(".o_menu_toggle").click(); // go to home menu
- expect(".o_home_menu").toBeVisible();
- expect(".delayed_client_action").not.toHaveCount();
-
- doVeryFastClick = true;
- await contains(".o_menu_toggle").click(); // back
- expect(".o_home_menu").toHaveCount(0);
- expect(".delayed_client_action").toHaveCount(1);
- await animationFrame(); // waiting for DelayedClientAction
- expect(".o_home_menu").toBeVisible();
- expect(".delayed_client_action").not.toHaveCount();
-
- await contains(".o_menu_toggle").click(); // back
- await animationFrame();
- expect(".o_home_menu").toHaveCount(0);
- expect(".delayed_client_action").toHaveCount(1);
-});
-
-test("clear unCommittedChanges when toggling home menu", async () => {
- expect.assertions(6);
- // Edit a form view, don't save, toggle home menu
- // the autosave feature of the Form view is activated
- // and relied upon by this test
-
- onRpc("web_save", ({ args, model }) => {
- expect(model).toBe("partner");
- expect(args[1]).toEqual({
- name: "red right hand",
- foo: false,
- });
- });
-
- await mountWebClientOdex();
- await getService("action").doAction(3, { viewType: "form" });
- expect(".o_form_view .o_form_editable").toHaveCount(1);
- await contains(".o_field_widget[name=name] input").edit("red right hand");
-
- await goToHomeMenu();
- expect(".o_form_view").toHaveCount(0);
- expect(".modal").toHaveCount(0);
- expect(".o_home_menu").toHaveCount(1);
-});
-
-test("can have HomeMenu and dialog action", async () => {
- await mountWebClientOdex();
- expect(".o_home_menu").toHaveCount(1);
- expect(".modal .o_form_view").toHaveCount(0);
- await getService("action").doAction(5);
- expect(".modal .o_form_view").toHaveCount(1);
- expect(".modal .o_form_view").toBeVisible();
- expect(".o_home_menu").toHaveCount(1);
-});
-
-test("supports attachments of apps deleted", async () => {
- // When doing a pg_restore without the filestore
- // LPE fixme: may not be necessary anymore since menus are not HomeMenu props anymore
- defineMenus([
- {
- id: 1,
- appID: 1,
- actionID: 1,
- xmlid: "",
- name: "Partners",
- webIconData: "",
- webIcon: "bloop,bloop",
- },
- ]);
- serverState.debug = "1";
- await mountWebClientOdex();
- expect(".o_home_menu").toHaveCount(1);
-});
-
-test.tags("desktop");
-test("debug manager resets to global items when home menu is displayed", async () => {
- const debugRegistry = registry.category("debug");
- debugRegistry.category("default").add("item_1", () => ({
- type: "item",
- description: "globalItem",
- callback: () => {},
- sequence: 10,
- }));
- onRpc("has_access", () => true);
- serverState.debug = "1";
- await mountWebClientOdex();
- await contains(".o_debug_manager .dropdown-toggle").click();
- expect(".dropdown-item:contains('globalItem')").toHaveCount(1);
- expect(".dropdown-item:contains('View: Kanban')").toHaveCount(0);
-
- await contains(".o_debug_manager .dropdown-toggle").click();
- await getService("action").doAction(1);
- await contains(".o_debug_manager .dropdown-toggle").click();
- expect(".dropdown-item:contains('globalItem')").toHaveCount(1);
- expect(".dropdown-item:contains('View: Kanban')").toHaveCount(1);
-
- await contains(".o_menu_toggle").click();
- await contains(".o_debug_manager .dropdown-toggle").click();
- expect(".dropdown-item:contains('globalItem')").toHaveCount(1);
- expect(".dropdown-item:contains('View: Kanban')").toHaveCount(0);
-
- await contains(".o_debug_manager .dropdown-toggle").click();
- await getService("action").doAction(3);
- await contains(".o_debug_manager .dropdown-toggle").click();
- expect(".dropdown-item:contains('globalItem')").toHaveCount(1);
- expect(".dropdown-item:contains('View: List')").toHaveCount(1);
- expect(".dropdown-item:contains('View: Kanban')").toHaveCount(0);
-});
-
-test("url state is well handled when going in and out of the HomeMenu", async () => {
- patchWithCleanup(browser.location, {
- origin: "http://example.com",
- });
- redirect("/odoo");
- await mountWebClientOdex();
- expect(router.current).toEqual({
- action: "menu",
- actionStack: [
- {
- action: "menu",
- displayName: "Home",
- },
- ],
- });
- expect(browser.history.length).toBe(1);
-
- await contains(".o_apps > .o_draggable:eq(1) > .o_app").click();
- await animationFrame();
- expect(router.current).toEqual({
- action: 1002,
- actionStack: [
- {
- action: 1002,
- displayName: "Client action 1002",
- },
- ],
- });
- expect(browser.history.length).toBe(2);
- expect(browser.location.href).toBe("http://example.com/odoo/action-1002");
-
- await goToHomeMenu();
- await animationFrame();
- expect(router.current).toEqual(
- {
- action: "menu",
- actionStack: [
- {
- action: 1002,
- displayName: "Client action 1002",
- },
- {
- action: "menu",
- displayName: "Home",
- },
- ],
- },
- {
- message:
- "the actionStack is required to be able to restore the menu toggle back button and the underlying breadcrumbs",
- }
- );
- expect(browser.history.length).toBe(3);
- expect(browser.location.href).toBe("http://example.com/odoo", {
- message:
- "despite the actionStack being in the router state, the url shouldn't have any path",
- });
-
- await contains(".o_apps > .o_draggable:eq(0) > .o_app").click();
- await animationFrame();
- expect(router.current).toEqual(
- {
- action: 1001,
- actionStack: [
- {
- action: 1001,
- displayName: "Client action 1001",
- },
- ],
- },
- { message: "clicking another app creates a new action stack (ie empties the breadcrumb)" }
- );
- expect(browser.history.length).toBe(4);
- expect(browser.location.href).toBe("http://example.com/odoo/action-1001");
-
- browser.history.back();
- await animationFrame();
- expect(router.current).toEqual(
- {
- action: "menu",
- actionStack: [
- {
- action: 1002,
- displayName: "Client action 1002",
- },
- {
- action: "menu",
- displayName: "Home",
- },
- ],
- globalState: {},
- },
- { message: "actionStack was restored" }
- );
- expect(browser.history.length).toBe(4, {
- message: "the previous history entry still exists (available with forward button)",
- });
- expect(browser.location.href).toBe("http://example.com/odoo");
-
- await contains(".o_menu_toggle").click();
- await animationFrame();
- expect(router.current).toEqual({
- action: 1002,
- actionStack: [
- {
- action: 1002,
- displayName: "Client action 1002",
- },
- ],
- });
- expect(browser.history.length).toBe(4);
- expect(browser.location.href).toBe("http://example.com/odoo/action-1002");
-});
-
-test.tags("desktop");
-test("underlying action's menu items are invisible when HomeMenu is displayed", async () => {
- defineMenus([
- {
- id: 1,
- children: [
- {
- id: 99,
- name: "SubMenu",
- appID: 1,
- actionID: 1002,
- xmlid: "",
- webIconData: undefined,
- webIcon: false,
- },
- ],
- },
- ]);
- await mountWebClientOdex();
- expect("nav .o_menu_sections").toHaveCount(0);
- expect("nav .o_menu_brand").toHaveCount(0);
- await contains(".o_app.o_menuitem:nth-child(1)").click();
- await animationFrame();
- expect("nav .o_menu_sections").toHaveCount(1);
- expect("nav .o_menu_brand").toHaveCount(1);
- expect(".o_menu_sections").toBeVisible();
- expect(".o_menu_brand").toBeVisible();
- await contains(".o_menu_toggle").click();
- expect("nav .o_menu_sections").toHaveCount(1);
- expect("nav .o_menu_brand").toHaveCount(1);
- expect(".o_menu_sections").not.toBeVisible();
- expect(".o_menu_brand").not.toBeVisible();
-});
-
-test("go back to home menu using browser back button", async () => {
- await mountWebClientOdex();
- expect(".o_home_menu").toHaveCount(1);
- expect(".o_main_navbar .o_menu_toggle").not.toBeVisible();
-
- await contains(".o_apps > .o_draggable:nth-child(2) > .o_app").click();
- expect(".test_client_action").toHaveCount(0);
- await animationFrame();
- expect(".test_client_action").toHaveCount(1);
- expect(".o_home_menu").toHaveCount(0);
-
- browser.history.back();
- await animationFrame();
- await animationFrame();
- expect(".test_client_action").toHaveCount(0);
- expect(".o_home_menu").toHaveCount(1);
- expect(".o_main_navbar .o_menu_toggle").not.toBeVisible();
-});
-
-test("initial action crashes", async () => {
- expect.errors(1);
- redirect("/odoo/action-__test__client__action__?menu_id=1");
- const ClientAction = registry.category("actions").get("__test__client__action__");
- class Override extends ClientAction {
- setup() {
- super.setup();
- expect.step("clientAction setup");
- throw new Error("my error");
- }
- }
- registry.category("actions").add("__test__client__action__", Override, { force: true });
-
- await mountWebClientOdex();
- expect.verifySteps(["clientAction setup"]);
- expect("nav .o_menu_toggle").toHaveCount(1);
- expect("nav .o_menu_toggle").toBeVisible();
- expect(".o_action_manager").toHaveInnerHTML("");
- expect(router.current).toEqual({
- action: "__test__client__action__",
- menu_id: 1,
- actionStack: [
- {
- action: "__test__client__action__",
- },
- ],
- });
- await animationFrame();
- expect.verifyErrors(["my error"]);
-});
-
-test("Apps are reordered at startup based on session's user settings", async () => {
- // Config is written with apps xmlids order (default is menu_1, menu_2)
- patchWithCleanup(user, {
- get settings() {
- return { id: 1, homemenu_config: '["menu_2","menu_1"]' };
- },
- });
- await mountWebClientOdex();
-
- const apps = queryAll(".o_app");
- expect(apps[0]).toHaveAttribute("data-menu-xmlid", "menu_2", {
- message: "first displayed app has menu_2 xmlid",
- });
- expect(apps[1]).toHaveAttribute("data-menu-xmlid", "menu_1", {
- message: "second displayed app has menu_1 xmlid",
- });
- expect(apps[0]).toHaveText("App2", { message: "first displayed app is App2" });
- expect(apps[1]).toHaveText("App1", { message: "second displayed app is App1" });
-});
-
-test.tags("desktop");
-test("Share URL item is present in the user menu when running as PWA", async () => {
- mockMatchMedia({ ["display-mode"]: "standalone" });
- clearRegistry(registry.category("user_menuitems"));
- // This service adds a "Dark Mode" item to the user menu items on start
- registry.category("services").remove("color_scheme");
- registry.category("user_menuitems").add("share_url", shareUrlMenuItem);
-
- await mountWithCleanup(UserMenu);
- await contains(".o_user_menu button").click();
-
- expect(".o-dropdown--menu .dropdown-item").toHaveCount(1);
- expect(".o-dropdown--menu .dropdown-item").toHaveText("Share");
-});
-
-test.tags("desktop");
-test("Share URL item is not present in the user menu when not running as PWA", async () => {
- mockMatchMedia({ ["display-mode"]: "browser" });
- clearRegistry(registry.category("user_menuitems"));
- // This service adds a "Dark Mode" item to the user menu items on start
- registry.category("services").remove("color_scheme");
- registry.category("user_menuitems").add("share_url", shareUrlMenuItem);
-
- await mountWithCleanup(UserMenu);
- await contains(".o_user_menu button").click();
-
- expect(".o-dropdown--menu .dropdown-item").not.toHaveCount();
-});
-
-test("Navigate to an application from the HomeMenu should generate only one pushState", async () => {
- patchWithCleanup(history, {
- pushState(state, title, url) {
- super.pushState(...arguments);
- const parsedUrl = new URL(url);
- expect.step(parsedUrl.pathname + parsedUrl.search);
- },
- });
- await mountWebClientOdex();
-
- await contains(".o_apps > .o_draggable:nth-child(2) > .o_app").click();
- await animationFrame();
- expect(".test_client_action").toHaveCount(1);
- expect(".test_client_action").toHaveText("ClientAction_Id 2");
-
- await goToHomeMenu();
- expect(".o_home_menu").toHaveCount(1);
-
- await contains(".o_apps > .o_draggable:nth-child(1) > .o_app").click();
- await animationFrame();
- expect(".test_client_action").toHaveCount(1);
- expect(".test_client_action").toHaveText("ClientAction_Id 1");
-
- await goToHomeMenu();
- await animationFrame();
- expect(".o_home_menu").toHaveCount(1);
- expect.verifySteps(["/odoo", "/odoo/action-1002", "/odoo", "/odoo/action-1001", "/odoo"]);
-});
-
-test.tags("desktop");
-test("Should not crash when opening an app via palette and immediately entering input in the palette search", async () => {
- await mountWebClientOdex();
-
- const def = new Deferred();
- onRpc("web_search_read", () => def);
- await keyDown("a");
- await animationFrame();
- await keyDown("Enter");
- await keyDown("a");
- await animationFrame();
- def.resolve();
- await animationFrame();
- expect(".test_client_action").toHaveCount(1);
- expect(".test_client_action").toHaveText("ClientAction_Id 1");
-});
diff --git a/odex30_base/odex30_web/tests/__init__.py b/odex30_base/odex30_web/tests/__init__.py
deleted file mode 100644
index 018fafd..0000000
--- a/odex30_base/odex30_web/tests/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-
-from . import test_odex
diff --git a/odex30_base/odex30_web/tests/test_odex.py b/odex30_base/odex30_web/tests/test_odex.py
deleted file mode 100644
index 9d6d88d..0000000
--- a/odex30_base/odex30_web/tests/test_odex.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import base64
-
-from odoo.tests.common import HttpCase, tagged
-
-
-class LoadMenusTests(HttpCase):
-
- def setUp(self):
- super().setUp()
- self.menu = self.env["ir.ui.menu"].create({
- "name": "test_menu",
- "parent_id": False,
- })
-
- def search(*args, **kwargs):
- return self.menu
-
- self.patch(type(self.env["ir.ui.menu"]), "search", search)
- self.authenticate("admin", "admin")
-
- def test_web_icon(self):
- self.menu.web_icon = False
- self.menu.web_icon_data = b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+BCQAHBQICJmhD1AAAAABJRU5ErkJggg=="
-
- menu_loaded = self.url_open("/web/webclient/load_menus/1234")
-
- expected = {
- str(self.menu.id): {
- "actionID": False,
- "actionModel": False,
- "actionPath": False,
- "appID": self.menu.id,
- "children": [],
- "id": self.menu.id,
- "name": "test_menu",
- "webIcon": False,
- "webIconData": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+BCQAHBQICJmhD1AAAAABJRU5ErkJggg==",
- "webIconDataMimetype": "image/png",
- "xmlid": ""
- },
- "root": {
- "actionID": False,
- "actionModel": False,
- "actionPath": False,
- "appID": False,
- "children": [
- self.menu.id
- ],
- "id": "root",
- "name": "root",
- "webIcon": None,
- "webIconData": None,
- "webIconDataMimetype": None,
- "xmlid": "",
- "backgroundImage": None,
- }
- }
-
- self.assertDictEqual(menu_loaded.json(), expected)
-
-
-@tagged("-at_install", "post_install")
-class TestWeb(HttpCase):
- def test_studio_list_upsell(self):
- invoice_action = self.env.ref("account.action_move_out_invoice_type", raise_if_not_found=False)
- if not invoice_action:
- return
- self.start_tour("/odoo/action-account.action_move_out_invoice_type", "odex30_web.test_studio_list_upsell", login="admin")
diff --git a/odex30_base/odex30_web/version.py b/odex30_base/odex30_web/version.py
deleted file mode 100644
index cf28214..0000000
--- a/odex30_base/odex30_web/version.py
+++ /dev/null
@@ -1,10 +0,0 @@
-
-import odoo
-
-odoo.release.version_info = odoo.release.version_info[:5] + ('e',)
-if '+e' not in odoo.release.version:
- odoo.release.version = '{0}+e{1}{2}'.format(*odoo.release.version.partition('-'))
-
-odoo.service.common.RPC_VERSION_1.update(
- server_version=odoo.release.version,
- server_version_info=odoo.release.version_info)