From 1929e818788e0e2b8f6967a221f640025e1abc4a Mon Sep 17 00:00:00 2001 From: Alaguraj0361 Date: Mon, 12 Oct 2026 11:30:48 +0530 Subject: [PATCH] add dine360 dashboard and restaurant management modules with customized UI components --- addons/dine360_dashboard/controllers/main.py | 26 +- .../static/src/css/home_menu.css | 373 ++++++++++++++++-- .../static/src/js/dashboard_pages.js | 25 ++ addons/dine360_dashboard/views/apps_page.xml | 39 +- .../views/dashboard_components.xml | 19 +- .../dine360_dashboard/views/home_template.xml | 19 +- .../views/login_templates.xml | 2 +- .../dine360_dashboard/views/tables_page.xml | 3 - addons/dine360_recipe/views/recipe_views.xml | 4 +- .../models/restaurant_table.py | 6 + .../views/restaurant_table_views.xml | 2 + addons/dine360_restaurant/models/res_users.py | 8 +- .../views/pos_order_views.xml | 1 + .../views/restaurant_menus.xml | 3 +- .../models/saas_restaurant.py | 6 +- .../static/src/scss/theme.scss | 15 +- 16 files changed, 449 insertions(+), 102 deletions(-) diff --git a/addons/dine360_dashboard/controllers/main.py b/addons/dine360_dashboard/controllers/main.py index 22ee90f..6d596b1 100644 --- a/addons/dine360_dashboard/controllers/main.py +++ b/addons/dine360_dashboard/controllers/main.py @@ -477,8 +477,13 @@ class Dine360DashboardController(http.Controller): if kitchen_action and kitchen_action.res_id: return request.redirect(f'/web#action={kitchen_action.res_id}') - # 3. Fallback to POS register - return request.redirect('/pos/web') + # 3. Fallback to Dashboard + return request.redirect('/dashboard') + + @http.route(['/pos/web', '/pos/ui', '/pos/web/'], type='http', auth='user') + def redirect_pos_to_dashboard(self, **kwargs): + """Redirect direct POS cashier access to Dine360 restaurant dashboard.""" + return request.redirect('/dashboard') # ------------------------------------------------------------- # APIs: Interactive Operations & Form Handlers @@ -495,10 +500,7 @@ class Dine360DashboardController(http.Controller): if table_id and 'restaurant.table' in request.env: table = request.env['restaurant.table'].sudo().browse(table_id) if table.exists(): - if hasattr(table, 'is_occupied'): - table.write({'is_occupied': is_occupied}) - elif hasattr(table, 'state'): - table.write({'state': 'occupied' if is_occupied else 'available'}) + table.write({'is_occupied': bool(is_occupied)}) return request.make_response( json.dumps({'success': True, 'table_id': table_id, 'is_occupied': is_occupied}), @@ -653,10 +655,20 @@ class Dine360DashboardController(http.Controller): rec_id = False if 'restaurant.table' in request.env: + if not floor_id and 'restaurant.floor' in request.env: + first_floor = request.env['restaurant.floor'].sudo().search([], limit=1) + if first_floor: + floor_id = first_floor.id + + import uuid vals = { - 'name': name, + 'name': name or f"Table {request.env['restaurant.table'].sudo().search_count([]) + 1}", 'seats': seats, 'shape': shape, + 'is_occupied': False, + 'is_reservation_enabled': True, + 'reservation_slot_duration': '1.0', + 'identifier': str(uuid.uuid4())[:8], } if floor_id: vals['floor_id'] = floor_id diff --git a/addons/dine360_dashboard/static/src/css/home_menu.css b/addons/dine360_dashboard/static/src/css/home_menu.css index 40f9b12..7fba280 100644 --- a/addons/dine360_dashboard/static/src/css/home_menu.css +++ b/addons/dine360_dashboard/static/src/css/home_menu.css @@ -1,3 +1,29 @@ +@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap'); +@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'); + +/* Direct FontAwesome font-face declaration with reliable paths */ +@font-face { + font-family: 'FontAwesome'; + src: url('/web/static/src/libs/fontawesome/fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), + url('/web/static/src/libs/fontawesome/fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), + url('/web/static/src/libs/fontawesome/fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +/* Enforce FontAwesome font rendering across all dashboard components */ +.fa, .fas, .far, .fal, .fad, .fab, [class*=" fa-"], [class^="fa-"] { + font-family: 'FontAwesome' !important; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + /* Main background */ body.o_home_dashboard, #wrapwrap.o_home_dashboard, @@ -542,6 +568,73 @@ body.o_restaurant_body #wrap { overflow-x: hidden !important; } +/* Suppress website frontend header/footer & backend quick bar inside dashboard */ +html.o_dine_dashboard_root #oe_main_menu_navbar, +html.o_dine_dashboard_root .o_main_navbar, +html.o_dine_dashboard_root .o_frontend_to_backend_nav, +html.o_dine_dashboard_root header:not(.o_saas_topbar), +html.o_dine_dashboard_root #top, +html.o_dine_dashboard_root .o_header_standard, +html.o_dine_dashboard_root #wrapwrap > header, +html.o_dine_dashboard_root footer, +html.o_dine_dashboard_root #footer, +html.o_dine_dashboard_root #wrapwrap > footer, +body:has(.o_saas_layout) #oe_main_menu_navbar, +body:has(.o_saas_layout) .o_main_navbar, +body:has(.o_saas_layout) .o_frontend_to_backend_nav, +body:has(.o_saas_layout) header:not(.o_saas_topbar), +body:has(.o_saas_layout) #top, +body:has(.o_saas_layout) .o_header_standard, +body:has(.o_saas_layout) #wrapwrap > header, +body:has(.o_saas_layout) footer, +body:has(.o_saas_layout) #footer, +body:has(.o_saas_layout) #wrapwrap > footer, +body.o_restaurant_body #oe_main_menu_navbar, +body.o_restaurant_body .o_main_navbar, +body.o_restaurant_body .o_frontend_to_backend_nav, +body.o_restaurant_body header:not(.o_saas_topbar), +body.o_restaurant_body #top, +body.o_restaurant_body .o_header_standard, +body.o_restaurant_body #wrapwrap > header, +body.o_restaurant_body footer, +body.o_restaurant_body #footer, +body.o_restaurant_body #wrapwrap > footer, +body.o_saas_admin_body #oe_main_menu_navbar, +body.o_saas_admin_body .o_main_navbar, +body.o_saas_admin_body .o_frontend_to_backend_nav, +body.o_saas_admin_body header:not(.o_saas_topbar), +body.o_saas_admin_body #top, +body.o_saas_admin_body .o_header_standard, +body.o_saas_admin_body #wrapwrap > header, +body.o_saas_admin_body footer, +body.o_saas_admin_body #footer, +body.o_saas_admin_body #wrapwrap > footer { + display: none !important; +} + +/* Dine360 High-Visibility Title & Heading Typography Overrides */ +html.o_dine_dashboard_root h1, html.o_dine_dashboard_root h2, html.o_dine_dashboard_root h3, +html.o_dine_dashboard_root h4, html.o_dine_dashboard_root h5, html.o_dine_dashboard_root h6, +body:has(.o_saas_layout) h1, body:has(.o_saas_layout) h2, body:has(.o_saas_layout) h3, +body:has(.o_saas_layout) h4, body:has(.o_saas_layout) h5, body:has(.o_saas_layout) h6, +body.o_restaurant_body h1, body.o_restaurant_body h2, body.o_restaurant_body h3, +body.o_restaurant_body h4, body.o_restaurant_body h5, body.o_restaurant_body h6, +body.o_saas_admin_body h1, body.o_saas_admin_body h2, body.o_saas_admin_body h3, +body.o_saas_admin_body h4, body.o_saas_admin_body h5, body.o_saas_admin_body h6, +.o_saas_layout h1, .o_saas_layout h2, .o_saas_layout h3, +.o_saas_layout h4, .o_saas_layout h5, .o_saas_layout h6, +.o_heading_title, +.o_card_title, +.o_settings_title, +.o_modal_title, +.o_table_num, +.o_app_card_name, +.o_kpi_label { + font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important; + letter-spacing: -0.015em !important; + text-transform: none !important; +} + /* SaaS Admin Flex Layout */ .o_saas_layout { display: flex; @@ -550,20 +643,34 @@ body.o_restaurant_body #wrap { width: 100%; } -/* Sidebar */ +/* Sidebar - Fixed on Left so it never scrolls when right-side content scrolls */ .o_saas_sidebar { - width: 260px; - min-width: 260px; - background: #ffffff; - border-right: 1px solid #f1f5f9; - padding: 24px 20px; - display: flex; - flex-direction: column; - justify-content: space-between; - height: 100vh; - position: sticky; - top: 0; - z-index: 100; + width: 260px !important; + min-width: 260px !important; + max-width: 260px !important; + background: #ffffff !important; + border-right: 1px solid #e2e8f0 !important; + padding: 24px 20px !important; + display: flex !important; + flex-direction: column !important; + justify-content: space-between !important; + height: 100vh !important; + position: fixed !important; + top: 0 !important; + left: 0 !important; + bottom: 0 !important; + z-index: 1000 !important; + overflow-y: auto !important; + overflow-x: hidden !important; + box-sizing: border-box !important; +} + +.o_saas_sidebar::-webkit-scrollbar { + width: 4px; +} +.o_saas_sidebar::-webkit-scrollbar-thumb { + background: #e2e8f0; + border-radius: 4px; } .o_sidebar_brand { @@ -640,10 +747,13 @@ body.o_restaurant_body #wrap { } .o_nav_icon { - font-size: 15px; - width: 18px; - text-align: center; - color: inherit; + font-size: 16px !important; + width: 20px !important; + text-align: center !important; + color: inherit !important; + display: inline-block !important; + flex-shrink: 0 !important; + line-height: 1 !important; } /* Promo Card at bottom of sidebar */ @@ -700,12 +810,16 @@ body.o_restaurant_body #wrap { color: #dc2626 !important; } -/* Main Content Area */ +/* Main Content Area - Scroller with offset for fixed sidebar */ .o_saas_main { - flex: 1; - padding: 24px 32px 48px 32px; - width: calc(100% - 260px); - min-width: 0; + flex: 1 !important; + margin-left: 260px !important; + padding: 24px 32px 48px 32px !important; + width: calc(100% - 260px) !important; + max-width: calc(100% - 260px) !important; + min-width: 0 !important; + min-height: 100vh !important; + box-sizing: border-box !important; } /* Top Header Bar */ @@ -832,11 +946,14 @@ body.o_restaurant_body #wrap { } .o_heading_title { - font-size: 26px; - font-weight: 800; - color: #0f172a; - margin: 0 0 4px 0; - letter-spacing: -0.5px; + font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important; + font-size: 26px !important; + font-weight: 800 !important; + color: #0f172a !important; + margin: 0 0 4px 0 !important; + letter-spacing: -0.025em !important; + line-height: 1.25 !important; + text-transform: none !important; } .o_heading_subtitle { @@ -2064,6 +2181,63 @@ body.o_restaurant_body #wrap { color: #ffffff; } +/* Apps Marketplace Grid - Strictly 4 Cards Per Row on Desktop, 1 on Mobile */ +.o_apps_grid { + display: grid !important; + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + gap: 20px !important; + margin-bottom: 28px !important; + width: 100% !important; +} + +.o_app_col { + display: flex !important; + flex-direction: column !important; + min-width: 0 !important; + width: 100% !important; +} + +.o_app_col .o_settings_card { + height: 100% !important; + display: flex !important; + flex-direction: column !important; + justify-content: space-between !important; + padding: 22px 20px !important; + border-radius: 16px !important; + background: #ffffff !important; + border: 1px solid #e2e8f0 !important; + box-shadow: 0 4px 20px -2px rgba(15, 23, 42, 0.06) !important; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1) !important; +} + +.o_app_col .o_settings_card:hover { + transform: translateY(-4px) !important; + box-shadow: 0 16px 32px -4px rgba(15, 23, 42, 0.12) !important; + border-color: #cbd5e1 !important; +} + +.o_app_col .o_settings_title { + font-size: 15px !important; + font-weight: 700 !important; + line-height: 1.3 !important; + margin-bottom: 8px !important; +} + +.o_app_col .o_settings_desc { + font-size: 12px !important; + color: #64748b !important; + line-height: 1.45 !important; + margin-bottom: 16px !important; +} + +.o_app_col .o_settings_icon { + width: 40px !important; + height: 40px !important; + border-radius: 10px !important; + font-size: 16px !important; + flex-shrink: 0 !important; +} + /* Settings Category Grid */ .o_settings_grid { display: grid; @@ -2102,10 +2276,13 @@ body.o_restaurant_body #wrap { } .o_settings_title { - font-size: 16px; - font-weight: 700; - color: #0f172a; - margin: 0 0 2px 0; + font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important; + font-size: 16.5px !important; + font-weight: 700 !important; + color: #0f172a !important; + margin: 0 0 3px 0 !important; + letter-spacing: -0.015em !important; + text-transform: none !important; } .o_settings_desc { @@ -2267,4 +2444,138 @@ body.o_restaurant_body #wrap { overflow: hidden !important; } +/* ------------------------------------------------------------- + Icon Box Render Enforcements + ------------------------------------------------------------- */ +.o_kpi_icon_box i, +.o_substat_icon_box i, +.o_act_icon_box i, +.o_icon_btn i, +.o_settings_icon i { + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + font-size: inherit; + line-height: 1; +} + +.o_kpi_trend i, +.o_substat_pct i { + font-size: 11px; + margin-right: 2px; +} + +/* ------------------------------------------------------------- + Responsive Mobile & Tablet Viewport Adaptations + ------------------------------------------------------------- */ +@media (max-width: 1200px) { + .o_apps_grid { + grid-template-columns: repeat(2, minmax(0, 1fr)) !important; + gap: 18px !important; + } +} + +@media (max-width: 991px) { + .o_saas_layout { + flex-direction: column !important; + width: 100% !important; + overflow-x: hidden !important; + } + .o_saas_sidebar { + position: static !important; + width: 100% !important; + max-width: 100% !important; + min-width: 0 !important; + height: auto !important; + padding: 14px 16px !important; + border-right: none !important; + border-bottom: 1px solid #e2e8f0 !important; + box-sizing: border-box !important; + } + .o_sidebar_brand { + margin-bottom: 12px !important; + } + .o_sidebar_nav { + flex-direction: row !important; + overflow-x: auto !important; + flex-wrap: nowrap !important; + gap: 6px !important; + -webkit-overflow-scrolling: touch !important; + padding-bottom: 4px !important; + } + .o_nav_link { + white-space: nowrap !important; + padding: 6px 12px !important; + font-size: 13px !important; + flex-shrink: 0 !important; + } + .o_nav_link.active::before { + display: none !important; + } + .o_sidebar_promo { + display: none !important; + } + .o_saas_main { + margin-left: 0 !important; + width: 100% !important; + max-width: 100% !important; + padding: 16px 14px !important; + box-sizing: border-box !important; + } + .o_kpi_grid { + grid-template-columns: repeat(2, 1fr) !important; + } +} + +@media (max-width: 767px) { + .o_saas_topbar { + flex-direction: column-reverse !important; + align-items: stretch !important; + gap: 12px !important; + } + .o_search_container { + width: 100% !important; + } + .o_topbar_actions { + justify-content: flex-end !important; + width: 100% !important; + } + .o_page_header { + flex-direction: column !important; + align-items: flex-start !important; + gap: 12px !important; + } + .o_header_controls { + flex-wrap: wrap !important; + width: 100% !important; + } + .o_page_toolbar { + flex-direction: column !important; + align-items: stretch !important; + gap: 12px !important; + } + .o_toolbar_search { + width: 100% !important; + } + .o_filter_pills { + overflow-x: auto !important; + flex-wrap: nowrap !important; + padding-bottom: 6px !important; + -webkit-overflow-scrolling: touch !important; + } + .o_filter_pill { + white-space: nowrap !important; + flex-shrink: 0 !important; + } + .o_kpi_grid { + grid-template-columns: 1fr !important; + gap: 14px !important; + } + .o_apps_grid { + grid-template-columns: 1fr !important; + gap: 16px !important; + } +} + + \ No newline at end of file diff --git a/addons/dine360_dashboard/static/src/js/dashboard_pages.js b/addons/dine360_dashboard/static/src/js/dashboard_pages.js index c3038e4..99f787f 100644 --- a/addons/dine360_dashboard/static/src/js/dashboard_pages.js +++ b/addons/dine360_dashboard/static/src/js/dashboard_pages.js @@ -3,6 +3,31 @@ * Handles live search, status filter pills, modals, AJAX operations, and toast notifications. */ document.addEventListener('DOMContentLoaded', function () { + // ------------------------------------------------------------- + // Dashboard Layout Isolation + // ------------------------------------------------------------- + if (document.querySelector('.o_saas_layout')) { + document.documentElement.classList.add('o_dine_dashboard_root'); + document.body.classList.add('o_restaurant_body', 'o_dine_dashboard'); + + const straySelectors = [ + '#oe_main_menu_navbar', + '.o_main_navbar', + '.o_frontend_to_backend_nav', + '#wrapwrap > header', + 'header:not(.o_saas_topbar)', + '#wrapwrap > footer', + 'footer' + ]; + straySelectors.forEach(sel => { + document.querySelectorAll(sel).forEach(el => { + if (!el.closest('.o_saas_layout')) { + el.style.setProperty('display', 'none', 'important'); + } + }); + }); + } + // ------------------------------------------------------------- // Toast Notification Utility // ------------------------------------------------------------- diff --git a/addons/dine360_dashboard/views/apps_page.xml b/addons/dine360_dashboard/views/apps_page.xml index e80ca97..1d207e1 100644 --- a/addons/dine360_dashboard/views/apps_page.xml +++ b/addons/dine360_dashboard/views/apps_page.xml @@ -112,9 +112,10 @@ -
+ +
-
+
@@ -135,7 +136,7 @@ -
+
@@ -155,7 +156,7 @@
-
+
@@ -175,28 +176,8 @@
- -
-
-
-
-
- -
- Online -
-

Point of Sale (POS)

-

Ultra-fast touch screen cashier and waiter terminal, offline mode resilience, split billing, table transfers, and payment gateways.

-
-
- Terminal - Launch POS → -
-
-
- -
+
@@ -216,7 +197,7 @@
-
+
@@ -236,7 +217,7 @@
-
+
@@ -256,7 +237,7 @@
-
+
@@ -276,7 +257,7 @@
-
+
diff --git a/addons/dine360_dashboard/views/dashboard_components.xml b/addons/dine360_dashboard/views/dashboard_components.xml index 001cf4f..4d47ab2 100644 --- a/addons/dine360_dashboard/views/dashboard_components.xml +++ b/addons/dine360_dashboard/views/dashboard_components.xml @@ -54,10 +54,6 @@ Online Orders - - - Point of Sale - Tables @@ -152,8 +148,19 @@ - - +