add dashboard, saas master, and reservation views, models, and static assets
This commit is contained in:
parent
e0192ad79e
commit
c3a9798a41
@ -394,6 +394,8 @@ class Dine360DashboardController(http.Controller):
|
|||||||
@http.route('/dashboard/reservations', type='http', auth='user', website=True)
|
@http.route('/dashboard/reservations', type='http', auth='user', website=True)
|
||||||
def dashboard_reservations(self, **kwargs):
|
def dashboard_reservations(self, **kwargs):
|
||||||
values = get_dashboard_context(active_page='reservations')
|
values = get_dashboard_context(active_page='reservations')
|
||||||
|
if values.get('is_saas_master'):
|
||||||
|
return request.redirect('/dashboard/restaurants')
|
||||||
return request.render('dine360_dashboard.reservations_page_template', values)
|
return request.render('dine360_dashboard.reservations_page_template', values)
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
@ -402,6 +404,8 @@ class Dine360DashboardController(http.Controller):
|
|||||||
@http.route('/dashboard/tables', type='http', auth='user', website=True)
|
@http.route('/dashboard/tables', type='http', auth='user', website=True)
|
||||||
def dashboard_tables(self, **kwargs):
|
def dashboard_tables(self, **kwargs):
|
||||||
values = get_dashboard_context(active_page='tables')
|
values = get_dashboard_context(active_page='tables')
|
||||||
|
if values.get('is_saas_master'):
|
||||||
|
return request.redirect('/dashboard/restaurants')
|
||||||
return request.render('dine360_dashboard.tables_page_template', values)
|
return request.render('dine360_dashboard.tables_page_template', values)
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
|
|||||||
@ -13,7 +13,15 @@ class IrUiMenu(models.Model):
|
|||||||
user = self.env.user
|
user = self.env.user
|
||||||
is_admin = user.has_group('base.group_system')
|
is_admin = user.has_group('base.group_system')
|
||||||
|
|
||||||
allowed_menus = ['Online Orders', 'Website', 'Table Reservations', 'Uber Integration', 'Apps', 'Settings']
|
db_name = self.env.cr.dbname or ''
|
||||||
|
is_saas_master = ('Dine360Restaurants' in db_name) or (
|
||||||
|
'saas.restaurant' in self.env and bool(self.env['saas.restaurant'].sudo().search_count([]))
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_saas_master:
|
||||||
|
allowed_menus = ['Dine360 SaaS', 'Apps', 'Settings']
|
||||||
|
else:
|
||||||
|
allowed_menus = ['Online Orders', 'Website', 'Table Reservations', 'Uber Integration', 'Apps', 'Settings']
|
||||||
|
|
||||||
if 'root' in menus and 'children' in menus['root']:
|
if 'root' in menus and 'children' in menus['root']:
|
||||||
new_children = []
|
new_children = []
|
||||||
@ -23,12 +31,17 @@ class IrUiMenu(models.Model):
|
|||||||
continue
|
continue
|
||||||
name = child_menu.get('name')
|
name = child_menu.get('name')
|
||||||
|
|
||||||
# Allow matching menus (with fallback for Table Reservation naming variations)
|
if is_saas_master:
|
||||||
if name in allowed_menus or name == 'Table Reservation':
|
if name in allowed_menus:
|
||||||
# Hide Apps and Settings for non-admins
|
if name in ['Apps', 'Settings'] and not is_admin:
|
||||||
if name in ['Apps', 'Settings'] and not is_admin:
|
continue
|
||||||
continue
|
new_children.append(child_id)
|
||||||
new_children.append(child_id)
|
else:
|
||||||
|
# Allow matching menus for tenant restaurant databases
|
||||||
|
if name in allowed_menus or name == 'Table Reservation':
|
||||||
|
if name in ['Apps', 'Settings'] and not is_admin:
|
||||||
|
continue
|
||||||
|
new_children.append(child_id)
|
||||||
menus['root']['children'] = new_children
|
menus['root']['children'] = new_children
|
||||||
|
|
||||||
return menus
|
return menus
|
||||||
|
|||||||
@ -1390,6 +1390,12 @@ body.o_restaurant_body #wrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Onboarded Restaurant Card Row - Highlighted Signature Card */
|
/* Onboarded Restaurant Card Row - Highlighted Signature Card */
|
||||||
|
.o_restaurants_list {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.o_res_row_card {
|
.o_res_row_card {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border: 1.5px solid #e2e8f0;
|
border: 1.5px solid #e2e8f0;
|
||||||
@ -1402,6 +1408,7 @@ body.o_restaurant_body #wrap {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
box-shadow: 0 4px 20px -2px rgba(15, 23, 42, 0.08), 0 2px 6px -1px rgba(15, 23, 42, 0.03);
|
box-shadow: 0 4px 20px -2px rgba(15, 23, 42, 0.08), 0 2px 6px -1px rgba(15, 23, 42, 0.03);
|
||||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_res_row_card:hover {
|
.o_res_row_card:hover {
|
||||||
@ -2231,4 +2238,33 @@ body.o_restaurant_body #wrap {
|
|||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------
|
||||||
|
POS & KANBAN GHOST SPACER REMOVAL
|
||||||
|
------------------------------------------------------------- */
|
||||||
|
.o_pos_kanban .o_kanban_record,
|
||||||
|
.o_kanban_dashboard .o_kanban_record {
|
||||||
|
max-width: 420px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_kanban_renderer .o_kanban_ghost,
|
||||||
|
.o_kanban_view .o_kanban_ghost,
|
||||||
|
.o_kanban_ghost {
|
||||||
|
display: none !important;
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
min-height: 0 !important;
|
||||||
|
max-height: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background: transparent !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1,19 +1,20 @@
|
|||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Dine360 Modern Theme Login & Authentication Styling
|
Dine360 Modern Theme Login & Authentication Styling
|
||||||
|
Luxury Bright Culinary Aesthetic - Matching User Reference Screenshot
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
/* 1. Global Reset & Body */
|
/* 1. Global Reset & Body */
|
||||||
body.o_custom_login_body {
|
body.o_custom_login_body {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
background: #090d16 !important;
|
background: #fafafc !important;
|
||||||
font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
||||||
min-height: 100vh !important;
|
min-height: 100vh !important;
|
||||||
overflow-x: hidden !important;
|
overflow-x: hidden !important;
|
||||||
color: #f8fafc !important;
|
color: #0f172a !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hide any standard website/frontend navigation & footer */
|
/* Hide standard website/frontend navigation & footer */
|
||||||
body.o_custom_login_body header,
|
body.o_custom_login_body header,
|
||||||
body.o_custom_login_body footer,
|
body.o_custom_login_body footer,
|
||||||
body.o_custom_login_body .o_footer_copyright,
|
body.o_custom_login_body .o_footer_copyright,
|
||||||
@ -32,228 +33,339 @@ body.o_custom_login_body #wrapwrap {
|
|||||||
padding-top: 0 !important;
|
padding-top: 0 !important;
|
||||||
margin-top: 0 !important;
|
margin-top: 0 !important;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
|
||||||
|
|
||||||
/* 2. Main Wrapper: Immersive Ambient Split */
|
|
||||||
.o_login_main_wrapper {
|
|
||||||
display: flex !important;
|
|
||||||
min-height: 100vh !important;
|
min-height: 100vh !important;
|
||||||
width: 100vw !important;
|
|
||||||
background:
|
|
||||||
radial-gradient(circle at 12% 20%, rgba(229, 0, 0, 0.22) 0%, transparent 45%),
|
|
||||||
radial-gradient(circle at 88% 80%, rgba(239, 68, 68, 0.15) 0%, transparent 50%),
|
|
||||||
linear-gradient(135deg, #070a12 0%, #0d1322 55%, #181428 100%) !important;
|
|
||||||
position: relative !important;
|
|
||||||
overflow-y: auto !important;
|
|
||||||
overflow-x: hidden !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3. Left Side: Brand Hero Showcase */
|
/* 2. Top Header Navigation Bar */
|
||||||
.o_login_left_side {
|
.o_login_top_header {
|
||||||
flex: 1.25 !important;
|
height: 64px !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
border-bottom: 1px solid rgba(226, 232, 240, 0.85) !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: space-between !important;
|
||||||
|
padding: 0 48px !important;
|
||||||
|
position: relative !important;
|
||||||
|
z-index: 20 !important;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02) !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_header_left {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_brand {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_brand_icon {
|
||||||
|
width: 32px !important;
|
||||||
|
height: 32px !important;
|
||||||
|
background: #dc2626 !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
padding: 60px 80px !important;
|
color: #ffffff !important;
|
||||||
|
font-size: 0.95rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_brand_name {
|
||||||
|
font-size: 1.35rem !important;
|
||||||
|
font-weight: 800 !important;
|
||||||
|
color: #0f172a !important;
|
||||||
|
letter-spacing: -0.5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_brand_accent {
|
||||||
|
color: #dc2626 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_header_divider {
|
||||||
|
width: 1px !important;
|
||||||
|
height: 20px !important;
|
||||||
|
background: #cbd5e1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_header_subtitle {
|
||||||
|
font-size: 0.88rem !important;
|
||||||
|
color: #64748b !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_top_header_right {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 18px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_lang_btn {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
color: #334155 !important;
|
||||||
|
font-size: 0.88rem !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 6px !important;
|
||||||
|
padding: 6px 10px !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
transition: background 0.15s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_lang_btn:hover {
|
||||||
|
background: #f1f5f9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_help_pill_btn {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 7px !important;
|
||||||
|
background: #fef2f2 !important;
|
||||||
|
border: 1px solid #fee2e2 !important;
|
||||||
|
color: #dc2626 !important;
|
||||||
|
border-radius: 50px !important;
|
||||||
|
padding: 7px 16px !important;
|
||||||
|
font-size: 0.85rem !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_help_pill_btn:hover {
|
||||||
|
background: #fee2e2 !important;
|
||||||
|
color: #b91c1c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Main Wrapper: Immersive Backdrop */
|
||||||
|
.o_login_main_wrapper {
|
||||||
|
display: flex !important;
|
||||||
|
min-height: calc(100vh - 64px) !important;
|
||||||
|
width: 100% !important;
|
||||||
|
background-color: #fbfbfe !important;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, rgba(255, 255, 255, 0.96) 0%, rgba(255, 255, 255, 0.90) 34%, rgba(255, 255, 255, 0.25) 60%, rgba(255, 255, 255, 0.05) 100%),
|
||||||
|
url('/dine360_dashboard/static/src/img/login_culinary_hero.jpg') !important;
|
||||||
|
background-size: cover !important;
|
||||||
|
background-position: center center !important;
|
||||||
|
background-repeat: no-repeat !important;
|
||||||
position: relative !important;
|
position: relative !important;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: space-between !important;
|
||||||
|
padding: 40px 72px !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Curved Red Accent Behind Card */
|
||||||
|
.o_curved_red_accent {
|
||||||
|
position: absolute !important;
|
||||||
|
right: 0 !important;
|
||||||
|
top: 5% !important;
|
||||||
|
width: 500px !important;
|
||||||
|
height: 550px !important;
|
||||||
|
pointer-events: none !important;
|
||||||
z-index: 1 !important;
|
z-index: 1 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.o_curved_red_accent svg {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Left Side: Brand Hero Showcase */
|
||||||
|
.o_login_left_side {
|
||||||
|
flex: 1.25 !important;
|
||||||
|
max-width: 580px !important;
|
||||||
|
position: relative !important;
|
||||||
|
z-index: 2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.o_login_hero_content {
|
.o_login_hero_content {
|
||||||
max-width: 540px !important;
|
max-width: 520px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_hero_badge {
|
.o_hero_badge {
|
||||||
display: inline-flex !important;
|
display: inline-flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
background: rgba(229, 0, 0, 0.12) !important;
|
background: #fef2f2 !important;
|
||||||
border: 1px solid rgba(229, 0, 0, 0.3) !important;
|
border: 1px solid #fee2e2 !important;
|
||||||
color: #ff6b6b !important;
|
color: #dc2626 !important;
|
||||||
font-size: 0.75rem !important;
|
font-size: 0.74rem !important;
|
||||||
font-weight: 700 !important;
|
font-weight: 700 !important;
|
||||||
letter-spacing: 1.5px !important;
|
letter-spacing: 1.2px !important;
|
||||||
border-radius: 50px !important;
|
border-radius: 50px !important;
|
||||||
padding: 6px 16px !important;
|
padding: 6px 14px !important;
|
||||||
margin-bottom: 24px !important;
|
margin-bottom: 20px !important;
|
||||||
text-transform: uppercase !important;
|
text-transform: uppercase !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_hero_badge_dot {
|
.o_hero_badge_dot {
|
||||||
width: 8px !important;
|
width: 7px !important;
|
||||||
height: 8px !important;
|
height: 7px !important;
|
||||||
background: #ef4444 !important;
|
background: #dc2626 !important;
|
||||||
border-radius: 50% !important;
|
border-radius: 50% !important;
|
||||||
box-shadow: 0 0 8px #ef4444 !important;
|
|
||||||
animation: o_pulse_dot 2s infinite ease-in-out !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes o_pulse_dot {
|
|
||||||
0%, 100% { opacity: 1; transform: scale(1); }
|
|
||||||
50% { opacity: 0.4; transform: scale(0.85); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_hero_title {
|
.o_hero_title {
|
||||||
font-size: 3.1rem !important;
|
font-size: 3.35rem !important;
|
||||||
font-weight: 800 !important;
|
font-weight: 800 !important;
|
||||||
letter-spacing: -1px !important;
|
letter-spacing: -1.2px !important;
|
||||||
color: #ffffff !important;
|
color: #0f172a !important;
|
||||||
line-height: 1.15 !important;
|
line-height: 1.12 !important;
|
||||||
margin-bottom: 18px !important;
|
margin-bottom: 18px !important;
|
||||||
text-shadow: 0 4px 20px rgba(0, 0, 0, 0.5) !important;
|
}
|
||||||
|
|
||||||
|
.o_title_accent {
|
||||||
|
color: #dc2626 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_hero_subtitle {
|
.o_hero_subtitle {
|
||||||
font-size: 1.1rem !important;
|
font-size: 1.05rem !important;
|
||||||
color: #94a3b8 !important;
|
color: #64748b !important;
|
||||||
line-height: 1.6 !important;
|
line-height: 1.6 !important;
|
||||||
margin-bottom: 36px !important;
|
margin-bottom: 30px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_hero_features {
|
.o_hero_features {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
gap: 14px !important;
|
gap: 12px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_hero_feature_item {
|
.o_hero_feature_item {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
gap: 16px !important;
|
gap: 16px !important;
|
||||||
background: rgba(255, 255, 255, 0.03) !important;
|
background: rgba(255, 255, 255, 0.92) !important;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.07) !important;
|
border: 1px solid rgba(226, 232, 240, 0.95) !important;
|
||||||
border-radius: 14px !important;
|
border-radius: 16px !important;
|
||||||
padding: 14px 18px !important;
|
padding: 13px 18px !important;
|
||||||
backdrop-filter: blur(8px) !important;
|
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.03) !important;
|
||||||
transition: all 0.25s ease !important;
|
transition: all 0.25s ease !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_hero_feature_item:hover {
|
.o_hero_feature_item:hover {
|
||||||
background: rgba(255, 255, 255, 0.06) !important;
|
background: #ffffff !important;
|
||||||
border-color: rgba(229, 0, 0, 0.3) !important;
|
border-color: #cbd5e1 !important;
|
||||||
transform: translateX(4px) !important;
|
transform: translateX(4px) !important;
|
||||||
|
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_feature_icon {
|
.o_feature_icon {
|
||||||
width: 40px !important;
|
width: 42px !important;
|
||||||
height: 40px !important;
|
height: 42px !important;
|
||||||
border-radius: 10px !important;
|
border-radius: 10px !important;
|
||||||
background: rgba(229, 0, 0, 0.15) !important;
|
background: #dc2626 !important;
|
||||||
color: #ef4444 !important;
|
color: #ffffff !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
font-size: 1.1rem !important;
|
font-size: 1.15rem !important;
|
||||||
flex-shrink: 0 !important;
|
flex-shrink: 0 !important;
|
||||||
|
box-shadow: 0 4px 10px rgba(220, 38, 38, 0.25) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_feature_icon svg {
|
||||||
|
fill: #ffffff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_feature_text h6 {
|
.o_feature_text h6 {
|
||||||
color: #ffffff !important;
|
color: #0f172a !important;
|
||||||
font-weight: 700 !important;
|
font-weight: 700 !important;
|
||||||
font-size: 0.95rem !important;
|
font-size: 0.94rem !important;
|
||||||
margin: 0 0 2px 0 !important;
|
margin: 0 0 2px 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_feature_text p {
|
.o_feature_text p {
|
||||||
color: #94a3b8 !important;
|
color: #64748b !important;
|
||||||
font-size: 0.82rem !important;
|
font-size: 0.82rem !important;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4. Right Side: Centered Glassmorphic Form */
|
/* 5. Right Side: Pure White Floating Card */
|
||||||
.o_login_right_side {
|
.o_login_right_side {
|
||||||
flex: 1 !important;
|
flex: 0.95 !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: flex-end !important;
|
||||||
padding: 40px 24px !important;
|
|
||||||
position: relative !important;
|
position: relative !important;
|
||||||
z-index: 2 !important;
|
z-index: 2 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_card {
|
.o_login_card {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
max-width: 440px !important;
|
max-width: 430px !important;
|
||||||
background: rgba(15, 23, 42, 0.8) !important;
|
background: #ffffff !important;
|
||||||
backdrop-filter: blur(28px) saturate(190%) !important;
|
border: 1px solid #f1f5f9 !important;
|
||||||
-webkit-backdrop-filter: blur(28px) saturate(190%) !important;
|
border-radius: 28px !important;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
box-shadow: 0 25px 60px -15px rgba(15, 23, 42, 0.12), 0 0 25px rgba(0, 0, 0, 0.03) !important;
|
||||||
border-radius: 24px !important;
|
|
||||||
box-shadow: 0 25px 60px -15px rgba(0, 0, 0, 0.7), 0 0 40px rgba(229, 0, 0, 0.12) !important;
|
|
||||||
padding: 38px 36px !important;
|
padding: 38px 36px !important;
|
||||||
box-sizing: border-box !important;
|
box-sizing: border-box !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Brand Header */
|
/* Brand Header inside card */
|
||||||
.o_login_logo_container {
|
.o_login_card_logo {
|
||||||
text-align: center !important;
|
display: flex !important;
|
||||||
margin-bottom: 20px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_login_brand_header {
|
|
||||||
display: inline-flex !important;
|
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
gap: 10px !important;
|
gap: 10px !important;
|
||||||
|
margin-bottom: 14px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_brand_icon {
|
.o_brand_icon {
|
||||||
width: 44px !important;
|
width: 44px !important;
|
||||||
height: 44px !important;
|
height: 44px !important;
|
||||||
background: linear-gradient(135deg, #e50000 0%, #b91c1c 100%) !important;
|
background: #dc2626 !important;
|
||||||
border-radius: 12px !important;
|
border-radius: 12px !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
font-size: 1.25rem !important;
|
font-size: 1.25rem !important;
|
||||||
box-shadow: 0 8px 20px -3px rgba(229, 0, 0, 0.5) !important;
|
box-shadow: 0 4px 12px rgba(220, 38, 38, 0.28) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_brand_name {
|
.o_brand_name {
|
||||||
font-size: 1.85rem !important;
|
font-size: 1.85rem !important;
|
||||||
font-weight: 800 !important;
|
font-weight: 800 !important;
|
||||||
color: #ffffff !important;
|
color: #0f172a !important;
|
||||||
letter-spacing: -0.5px !important;
|
letter-spacing: -0.5px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_brand_accent {
|
.o_brand_accent {
|
||||||
color: #ef4444 !important;
|
color: #dc2626 !important;
|
||||||
}
|
|
||||||
|
|
||||||
.o_login_logo_box {
|
|
||||||
margin-top: 8px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_company_tag {
|
|
||||||
background: rgba(239, 68, 68, 0.14) !important;
|
|
||||||
border: 1px solid rgba(239, 68, 68, 0.3) !important;
|
|
||||||
color: #fca5a5 !important;
|
|
||||||
font-size: 0.8rem !important;
|
|
||||||
font-weight: 600 !important;
|
|
||||||
padding: 4px 14px !important;
|
|
||||||
border-radius: 20px !important;
|
|
||||||
display: inline-block !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Header Text */
|
/* Header Text */
|
||||||
.o_login_header_text h3 {
|
.o_login_header_text h3 {
|
||||||
font-size: 1.45rem !important;
|
font-size: 1.55rem !important;
|
||||||
font-weight: 700 !important;
|
font-weight: 800 !important;
|
||||||
color: #ffffff !important;
|
color: #0f172a !important;
|
||||||
margin-bottom: 6px !important;
|
margin-bottom: 4px !important;
|
||||||
|
letter-spacing: -0.3px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_header_text p {
|
.o_login_header_text p {
|
||||||
font-size: 0.88rem !important;
|
font-size: 0.85rem !important;
|
||||||
color: #94a3b8 !important;
|
color: #64748b !important;
|
||||||
margin-bottom: 24px !important;
|
margin-bottom: 22px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5. Inputs & Form Controls */
|
/* 6. Inputs & Form Controls */
|
||||||
.o_login_form_container label,
|
.o_login_form_container label,
|
||||||
.oe_login_form label {
|
.oe_login_form label {
|
||||||
color: #cbd5e1 !important;
|
color: #334155 !important;
|
||||||
font-weight: 600 !important;
|
font-weight: 600 !important;
|
||||||
font-size: 0.84rem !important;
|
font-size: 0.84rem !important;
|
||||||
margin-bottom: 6px !important;
|
margin-bottom: 6px !important;
|
||||||
@ -262,186 +374,231 @@ body.o_custom_login_body #wrapwrap {
|
|||||||
|
|
||||||
.o_login_form_container .form-control,
|
.o_login_form_container .form-control,
|
||||||
.oe_login_form .form-control {
|
.oe_login_form .form-control {
|
||||||
background: rgba(255, 255, 255, 0.06) !important;
|
background: #ffffff !important;
|
||||||
border: 1.5px solid rgba(255, 255, 255, 0.14) !important;
|
border: 1.5px solid #e2e8f0 !important;
|
||||||
border-radius: 12px !important;
|
border-radius: 10px !important;
|
||||||
color: #ffffff !important;
|
color: #0f172a !important;
|
||||||
padding: 11px 15px !important;
|
padding: 10px 14px !important;
|
||||||
font-size: 0.95rem !important;
|
font-size: 0.92rem !important;
|
||||||
height: auto !important;
|
height: 44px !important;
|
||||||
transition: all 0.2s ease !important;
|
transition: all 0.2s ease !important;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_form_container .form-control::placeholder,
|
.o_login_form_container .form-control::placeholder,
|
||||||
.oe_login_form .form-control::placeholder {
|
.oe_login_form .form-control::placeholder {
|
||||||
color: rgba(255, 255, 255, 0.4) !important;
|
color: #94a3b8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_form_container .form-control:focus,
|
.o_login_form_container .form-control:focus,
|
||||||
.oe_login_form .form-control:focus {
|
.oe_login_form .form-control:focus {
|
||||||
background: rgba(255, 255, 255, 0.1) !important;
|
background: #ffffff !important;
|
||||||
border-color: #ef4444 !important;
|
border-color: #dc2626 !important;
|
||||||
color: #ffffff !important;
|
color: #0f172a !important;
|
||||||
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.25) !important;
|
box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12) !important;
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Chrome/Safari Autofill Dark Theme Override */
|
/* Input Icon Wrapper */
|
||||||
|
.o_input_icon_wrap {
|
||||||
|
position: relative !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_input_icon {
|
||||||
|
position: absolute !important;
|
||||||
|
left: 14px !important;
|
||||||
|
color: #94a3b8 !important;
|
||||||
|
font-size: 0.95rem !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
z-index: 3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_input_icon_wrap .form-control {
|
||||||
|
padding-left: 38px !important;
|
||||||
|
padding-right: 38px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Password Toggle Button */
|
||||||
|
.o_toggle_password_btn {
|
||||||
|
position: absolute !important;
|
||||||
|
right: 8px !important;
|
||||||
|
top: 50% !important;
|
||||||
|
transform: translateY(-50%) !important;
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
color: #94a3b8 !important;
|
||||||
|
padding: 6px 8px !important;
|
||||||
|
font-size: 0.95rem !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
z-index: 4 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o_toggle_password_btn:hover {
|
||||||
|
color: #334155 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Database Input Group */
|
||||||
|
.input-group {
|
||||||
|
border-radius: 10px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group #db {
|
||||||
|
border-top-right-radius: 0 !important;
|
||||||
|
border-bottom-right-radius: 0 !important;
|
||||||
|
border-right: none !important;
|
||||||
|
cursor: default !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
color: #0f172a !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group .btn-secondary,
|
||||||
|
.input-group a.btn {
|
||||||
|
background: #f1f5f9 !important;
|
||||||
|
border: 1.5px solid #e2e8f0 !important;
|
||||||
|
border-radius: 0 10px 10px 0 !important;
|
||||||
|
color: #334155 !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
font-size: 0.85rem !important;
|
||||||
|
padding: 10px 15px !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 6px !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group .btn-secondary:hover,
|
||||||
|
.input-group a.btn:hover {
|
||||||
|
background: #e2e8f0 !important;
|
||||||
|
color: #0f172a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chrome/Safari Autofill Light Theme Override */
|
||||||
.oe_login_form input:-webkit-autofill,
|
.oe_login_form input:-webkit-autofill,
|
||||||
.oe_login_form input:-webkit-autofill:hover,
|
.oe_login_form input:-webkit-autofill:hover,
|
||||||
.oe_login_form input:-webkit-autofill:focus,
|
.oe_login_form input:-webkit-autofill:focus,
|
||||||
.o_login_form_container input:-webkit-autofill,
|
.o_login_form_container input:-webkit-autofill,
|
||||||
.o_login_form_container input:-webkit-autofill:hover,
|
.o_login_form_container input:-webkit-autofill:hover,
|
||||||
.o_login_form_container input:-webkit-autofill:focus {
|
.o_login_form_container input:-webkit-autofill:focus {
|
||||||
-webkit-text-fill-color: #ffffff !important;
|
-webkit-text-fill-color: #0f172a !important;
|
||||||
-webkit-box-shadow: 0 0 0px 1000px #1e293b inset !important;
|
-webkit-box-shadow: 0 0 0px 1000px #ffffff inset !important;
|
||||||
border-color: rgba(255, 255, 255, 0.2) !important;
|
border-color: #e2e8f0 !important;
|
||||||
transition: background-color 5000s ease-in-out 0s !important;
|
transition: background-color 5000s ease-in-out 0s !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Database Input Group */
|
/* 7. Primary Action Button */
|
||||||
.input-group #db {
|
.oe_login_buttons .btn-primary,
|
||||||
border-top-right-radius: 0 !important;
|
.o_login_submit_btn {
|
||||||
border-bottom-right-radius: 0 !important;
|
background: #dc2626 !important;
|
||||||
cursor: default !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group .btn-secondary,
|
|
||||||
.input-group a.btn {
|
|
||||||
background: rgba(255, 255, 255, 0.08) !important;
|
|
||||||
border: 1.5px solid rgba(255, 255, 255, 0.14) !important;
|
|
||||||
border-left: none !important;
|
|
||||||
border-top-right-radius: 12px !important;
|
|
||||||
border-bottom-right-radius: 12px !important;
|
|
||||||
color: #e2e8f0 !important;
|
|
||||||
font-weight: 600 !important;
|
|
||||||
font-size: 0.85rem !important;
|
|
||||||
padding: 11px 16px !important;
|
|
||||||
transition: all 0.2s ease !important;
|
|
||||||
display: inline-flex !important;
|
|
||||||
align-items: center !important;
|
|
||||||
gap: 6px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group .btn-secondary:hover,
|
|
||||||
.input-group a.btn:hover {
|
|
||||||
background: #ef4444 !important;
|
|
||||||
border-color: #ef4444 !important;
|
|
||||||
color: #ffffff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 6. Primary Action Button */
|
|
||||||
.oe_login_buttons .btn-primary {
|
|
||||||
background: linear-gradient(135deg, #e50000 0%, #b91c1c 100%) !important;
|
|
||||||
border: none !important;
|
border: none !important;
|
||||||
border-radius: 12px !important;
|
border-radius: 10px !important;
|
||||||
padding: 13px !important;
|
height: 46px !important;
|
||||||
font-weight: 700 !important;
|
font-weight: 700 !important;
|
||||||
font-size: 1rem !important;
|
font-size: 0.98rem !important;
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
box-shadow: 0 8px 24px -4px rgba(229, 0, 0, 0.45) !important;
|
display: inline-flex !important;
|
||||||
transition: all 0.25s ease !important;
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
gap: 8px !important;
|
||||||
|
box-shadow: 0 4px 14px rgba(220, 38, 38, 0.32) !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oe_login_buttons .btn-primary:hover {
|
.oe_login_buttons .btn-primary:hover,
|
||||||
background: linear-gradient(135deg, #dc2626 0%, #991b1b 100%) !important;
|
.o_login_submit_btn:hover {
|
||||||
transform: translateY(-2px) !important;
|
background: #b91c1c !important;
|
||||||
box-shadow: 0 12px 28px -4px rgba(229, 0, 0, 0.6) !important;
|
transform: translateY(-1px) !important;
|
||||||
|
box-shadow: 0 6px 18px rgba(220, 38, 38, 0.42) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oe_login_buttons .btn-primary:active {
|
.oe_login_buttons .btn-primary:active,
|
||||||
|
.o_login_submit_btn:active {
|
||||||
transform: translateY(0) !important;
|
transform: translateY(0) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Superuser button */
|
/* Reset Password link */
|
||||||
.oe_login_buttons .btn-link {
|
.justify-content-between.mt-2 a[href*="/web/signup"] {
|
||||||
color: #94a3b8 !important;
|
display: none !important;
|
||||||
font-size: 0.85rem !important;
|
}
|
||||||
|
|
||||||
|
.justify-content-between.mt-2 a[href*="/web/reset_password"],
|
||||||
|
a[href*="/web/reset_password"] {
|
||||||
|
color: #dc2626 !important;
|
||||||
|
font-size: 0.84rem !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oe_login_buttons .btn-link:hover {
|
a[href*="/web/reset_password"]:hover {
|
||||||
color: #ef4444 !important;
|
|
||||||
text-decoration: underline !important;
|
text-decoration: underline !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 7. Alerts */
|
/* Alerts */
|
||||||
.o_login_form_container .alert-danger,
|
.o_login_form_container .alert-danger,
|
||||||
.oe_login_form .alert-danger {
|
.oe_login_form .alert-danger {
|
||||||
background: rgba(220, 38, 38, 0.25) !important;
|
background: #fef2f2 !important;
|
||||||
border: 1px solid rgba(220, 38, 38, 0.5) !important;
|
border: 1px solid #fecaca !important;
|
||||||
color: #fca5a5 !important;
|
color: #b91c1c !important;
|
||||||
border-radius: 12px !important;
|
border-radius: 10px !important;
|
||||||
padding: 12px 14px !important;
|
padding: 10px 14px !important;
|
||||||
font-size: 0.88rem !important;
|
font-size: 0.86rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_form_container .alert-success,
|
.o_login_form_container .alert-success,
|
||||||
.oe_login_form .alert-success {
|
.oe_login_form .alert-success {
|
||||||
background: rgba(16, 185, 129, 0.25) !important;
|
background: #f0fdf4 !important;
|
||||||
border: 1px solid rgba(16, 185, 129, 0.5) !important;
|
border: 1px solid #bbf7d0 !important;
|
||||||
color: #6ee7b7 !important;
|
color: #15803d !important;
|
||||||
border-radius: 12px !important;
|
border-radius: 10px !important;
|
||||||
padding: 12px 14px !important;
|
padding: 10px 14px !important;
|
||||||
font-size: 0.88rem !important;
|
font-size: 0.86rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 8. Links and Footer */
|
/* 8. Links and Footer */
|
||||||
.oe_login_buttons a,
|
.o_login_footer .o_login_link {
|
||||||
.o_login_footer a,
|
color: #64748b !important;
|
||||||
.o_login_link {
|
|
||||||
color: #94a3b8 !important;
|
|
||||||
font-size: 0.85rem !important;
|
font-size: 0.85rem !important;
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 6px !important;
|
||||||
transition: color 0.2s ease !important;
|
transition: color 0.2s ease !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oe_login_buttons a:hover,
|
.o_login_footer .o_login_link:hover {
|
||||||
.o_login_footer a:hover,
|
color: #0f172a !important;
|
||||||
.o_login_link:hover {
|
|
||||||
color: #ef4444 !important;
|
|
||||||
text-decoration: underline !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_brand_footer p {
|
.o_login_brand_footer p {
|
||||||
color: #64748b !important;
|
color: #94a3b8 !important;
|
||||||
font-size: 0.82rem !important;
|
font-size: 0.82rem !important;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_brand_footer a {
|
.o_powered_brand {
|
||||||
color: #ef4444 !important;
|
color: #dc2626 !important;
|
||||||
font-weight: 600 !important;
|
font-weight: 700 !important;
|
||||||
text-decoration: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_login_brand_footer a:hover {
|
|
||||||
text-decoration: underline !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Database Selector / List Modal Styling */
|
|
||||||
.o_database_list .list-group-item {
|
|
||||||
background: rgba(255, 255, 255, 0.05) !important;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
|
||||||
color: #ffffff !important;
|
|
||||||
border-radius: 10px !important;
|
|
||||||
margin-bottom: 8px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o_database_list .list-group-item:hover {
|
|
||||||
background: rgba(229, 0, 0, 0.15) !important;
|
|
||||||
border-color: rgba(229, 0, 0, 0.4) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 9. Responsive Breakpoints */
|
/* 9. Responsive Breakpoints */
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
|
.o_login_top_header {
|
||||||
|
padding: 0 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.o_login_main_wrapper {
|
.o_login_main_wrapper {
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
|
padding: 30px 20px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_left_side {
|
.o_login_left_side {
|
||||||
@ -450,7 +607,7 @@ body.o_custom_login_body #wrapwrap {
|
|||||||
|
|
||||||
.o_login_right_side {
|
.o_login_right_side {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
padding: 24px 16px !important;
|
justify-content: center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_login_card {
|
.o_login_card {
|
||||||
|
|||||||
@ -267,8 +267,8 @@ body,
|
|||||||
padding: 8px 0 !important;
|
padding: 8px 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_kanban_renderer .o_kanban_record,
|
.o_kanban_renderer .o_kanban_record:not(.o_kanban_ghost),
|
||||||
.o_kanban_view .o_kanban_record {
|
.o_kanban_view .o_kanban_record:not(.o_kanban_ghost) {
|
||||||
background: #ffffff !important;
|
background: #ffffff !important;
|
||||||
border: 1px solid #e2e8f0 !important;
|
border: 1px solid #e2e8f0 !important;
|
||||||
border-radius: 16px !important;
|
border-radius: 16px !important;
|
||||||
@ -279,13 +279,41 @@ body,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Hover Effect for Cards */
|
/* Hover Effect for Cards */
|
||||||
.o_kanban_renderer .o_kanban_record:hover,
|
.o_kanban_renderer .o_kanban_record:not(.o_kanban_ghost):hover,
|
||||||
.o_kanban_view .o_kanban_record:hover {
|
.o_kanban_view .o_kanban_record:not(.o_kanban_ghost):hover {
|
||||||
transform: translateY(-3px) !important;
|
transform: translateY(-3px) !important;
|
||||||
box-shadow: 0 12px 24px -2px rgba(15, 23, 42, 0.1) !important;
|
box-shadow: 0 12px 24px -2px rgba(15, 23, 42, 0.1) !important;
|
||||||
border-color: #fca5a5 !important;
|
border-color: #fca5a5 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Constrain dashboard/POS kanban card width so it stays compact without flex stretching */
|
||||||
|
.o_pos_kanban .o_kanban_record,
|
||||||
|
.o_kanban_dashboard .o_kanban_record {
|
||||||
|
max-width: 420px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure Odoo flex ghost spacers and empty cards remain completely removed and invisible */
|
||||||
|
.o_kanban_renderer .o_kanban_ghost,
|
||||||
|
.o_kanban_view .o_kanban_ghost,
|
||||||
|
.o_kanban_ghost {
|
||||||
|
display: none !important;
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
min-height: 0 !important;
|
||||||
|
max-height: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background: transparent !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Card Header/Title */
|
/* Card Header/Title */
|
||||||
.o_kanban_record .o_kanban_record_title,
|
.o_kanban_record .o_kanban_record_title,
|
||||||
.o_kanban_record strong {
|
.o_kanban_record strong {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 700 KiB After Width: | Height: | Size: 740 KiB |
BIN
addons/dine360_dashboard/static/src/img/login_culinary_hero.jpg
Normal file
BIN
addons/dine360_dashboard/static/src/img/login_culinary_hero.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 740 KiB |
@ -133,45 +133,47 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- App 2: Table Reservations -->
|
<!-- App 2: Table Reservations (Tenant Restaurants Only) -->
|
||||||
<div class="col-lg-4 col-md-6" data-search-item="true" data-filter-item="true" data-status="operations">
|
<t t-if="not is_saas_master">
|
||||||
<div class="o_settings_card h-100 d-flex flex-column justify-content-between">
|
<div class="col-lg-4 col-md-6" data-search-item="true" data-filter-item="true" data-status="operations">
|
||||||
<div>
|
<div class="o_settings_card h-100 d-flex flex-column justify-content-between">
|
||||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
<div>
|
||||||
<div class="o_settings_icon" style="background:#dbeafe; color:#2563eb;">
|
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||||
<i class="fa fa-calendar"/>
|
<div class="o_settings_icon" style="background:#dbeafe; color:#2563eb;">
|
||||||
|
<i class="fa fa-calendar"/>
|
||||||
|
</div>
|
||||||
|
<span class="o_badge_status success"><span class="o_badge_dot"/> Installed</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="o_badge_status success"><span class="o_badge_dot"/> Installed</span>
|
<h4 class="o_settings_title fs-5 mb-2">Table Reservations</h4>
|
||||||
|
<p class="o_settings_desc mb-3">Advance table booking calendar, guest dining occasions, automated WhatsApp booking confirmation notifications, and peak hours.</p>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center justify-content-between pt-3 border-top">
|
||||||
|
<span class="badge bg-light text-muted border">Front of House</span>
|
||||||
|
<a href="/dashboard/reservations" class="o_link_red fw-bold small">Open Bookings →</a>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="o_settings_title fs-5 mb-2">Table Reservations</h4>
|
|
||||||
<p class="o_settings_desc mb-3">Advance table booking calendar, guest dining occasions, automated WhatsApp booking confirmation notifications, and peak hours.</p>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center justify-content-between pt-3 border-top">
|
|
||||||
<span class="badge bg-light text-muted border">Front of House</span>
|
|
||||||
<a href="/dashboard/reservations" class="o_link_red fw-bold small">Open Bookings →</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- App 3: Table & Floor Manager -->
|
<!-- App 3: Table & Floor Manager (Tenant Restaurants Only) -->
|
||||||
<div class="col-lg-4 col-md-6" data-search-item="true" data-filter-item="true" data-status="operations">
|
<div class="col-lg-4 col-md-6" data-search-item="true" data-filter-item="true" data-status="operations">
|
||||||
<div class="o_settings_card h-100 d-flex flex-column justify-content-between">
|
<div class="o_settings_card h-100 d-flex flex-column justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||||
<div class="o_settings_icon" style="background:#fef3c7; color:#d97706;">
|
<div class="o_settings_icon" style="background:#fef3c7; color:#d97706;">
|
||||||
<i class="fa fa-th"/>
|
<i class="fa fa-th"/>
|
||||||
|
</div>
|
||||||
|
<span class="o_badge_status success"><span class="o_badge_dot"/> Installed</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="o_badge_status success"><span class="o_badge_dot"/> Installed</span>
|
<h4 class="o_settings_title fs-5 mb-2">Floor & Table Management</h4>
|
||||||
|
<p class="o_settings_desc mb-3">Visual dining floor plan matrix, seating occupancy tracking, live availability toggle, and POS table synchronization.</p>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center justify-content-between pt-3 border-top">
|
||||||
|
<span class="badge bg-light text-muted border">Floors</span>
|
||||||
|
<a href="/dashboard/tables" class="o_link_red fw-bold small">View Floors →</a>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="o_settings_title fs-5 mb-2">Floor & Table Management</h4>
|
|
||||||
<p class="o_settings_desc mb-3">Visual dining floor plan matrix, seating occupancy tracking, live availability toggle, and POS table synchronization.</p>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center justify-content-between pt-3 border-top">
|
|
||||||
<span class="badge bg-light text-muted border">Floors</span>
|
|
||||||
<a href="/dashboard/tables" class="o_link_red fw-bold small">View Floors →</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</t>
|
||||||
|
|
||||||
<!-- App 4: Point of Sale -->
|
<!-- App 4: Point of Sale -->
|
||||||
<div class="col-lg-4 col-md-6" data-search-item="true" data-filter-item="true" data-status="operations">
|
<div class="col-lg-4 col-md-6" data-search-item="true" data-filter-item="true" data-status="operations">
|
||||||
|
|||||||
@ -34,14 +34,6 @@
|
|||||||
<i class="fa fa-cutlery o_nav_icon"/>
|
<i class="fa fa-cutlery o_nav_icon"/>
|
||||||
<span>Restaurants</span>
|
<span>Restaurants</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="/dashboard/reservations" t-att-class="'o_nav_link ' + ('active' if active_page == 'reservations' else '')">
|
|
||||||
<i class="fa fa-calendar o_nav_icon"/>
|
|
||||||
<span>Reservations</span>
|
|
||||||
</a>
|
|
||||||
<a href="/dashboard/tables" t-att-class="'o_nav_link ' + ('active' if active_page == 'tables' else '')">
|
|
||||||
<i class="fa fa-th o_nav_icon"/>
|
|
||||||
<span>Table Management</span>
|
|
||||||
</a>
|
|
||||||
<a href="/dashboard/apps" t-att-class="'o_nav_link ' + ('active' if active_page == 'apps' else '')">
|
<a href="/dashboard/apps" t-att-class="'o_nav_link ' + ('active' if active_page == 'apps' else '')">
|
||||||
<i class="fa fa-th-large o_nav_icon"/>
|
<i class="fa fa-th-large o_nav_icon"/>
|
||||||
<span>Apps</span>
|
<span>Apps</span>
|
||||||
@ -160,8 +152,8 @@
|
|||||||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/home_menu.css?v=6.0"/>
|
<link rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/home_menu.css?v=6.2"/>
|
||||||
<script type="text/javascript" src="/dine360_dashboard/static/src/js/dashboard_pages.js?v=6.0"/>
|
<script type="text/javascript" src="/dine360_dashboard/static/src/js/dashboard_pages.js?v=6.2"/>
|
||||||
|
|
||||||
<div class="o_saas_layout">
|
<div class="o_saas_layout">
|
||||||
<!-- Shared Dine360 Sidebar -->
|
<!-- Shared Dine360 Sidebar -->
|
||||||
|
|||||||
@ -8,8 +8,8 @@
|
|||||||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous"/>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/home_menu.css?v=6.0"/>
|
<link rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/home_menu.css?v=6.2"/>
|
||||||
<script type="text/javascript" src="/dine360_dashboard/static/src/js/dashboard_pages.js?v=6.0"/>
|
<script type="text/javascript" src="/dine360_dashboard/static/src/js/dashboard_pages.js?v=6.2"/>
|
||||||
|
|
||||||
<!-- ============================================================== -->
|
<!-- ============================================================== -->
|
||||||
<!-- 1. ADMIN RESTAURANT ONBOARD MASTER DB DASHBOARD -->
|
<!-- 1. ADMIN RESTAURANT ONBOARD MASTER DB DASHBOARD -->
|
||||||
@ -191,13 +191,13 @@
|
|||||||
<div class="o_substats_col">
|
<div class="o_substats_col">
|
||||||
<div class="o_substat_item">
|
<div class="o_substat_item">
|
||||||
<div class="o_substat_icon_box">
|
<div class="o_substat_icon_box">
|
||||||
<i class="fa fa-calendar text-danger"/>
|
<i class="fa fa-cutlery text-danger"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="o_substat_title">Total Reservations</div>
|
<div class="o_substat_title">Active Restaurants</div>
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<span class="o_substat_val"><t t-esc="saas_dashboard_data['reservations_count']"/></span>
|
<span class="o_substat_val"><t t-esc="saas_stats['active']"/></span>
|
||||||
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> +12%</span>
|
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> 100%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,14 +6,70 @@
|
|||||||
<t t-set="body_classname" t-value="'o_custom_login_body'"/>
|
<t t-set="body_classname" t-value="'o_custom_login_body'"/>
|
||||||
<t t-set="no_header" t-value="True"/>
|
<t t-set="no_header" t-value="True"/>
|
||||||
<t t-set="no_footer" t-value="True"/>
|
<t t-set="no_footer" t-value="True"/>
|
||||||
<t t-set="title">Dine360 Restaurant - Login</t>
|
<t t-set="title">Dine360 - Smart Restaurant Management</t>
|
||||||
<t t-set="head">
|
<t t-set="head">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/login_style.css"/>
|
<link rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/login_style.css?v=3.5"/>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var btn = document.getElementById('togglePasswordBtn');
|
||||||
|
var pwd = document.getElementById('password');
|
||||||
|
var icon = document.getElementById('togglePasswordIcon');
|
||||||
|
if (btn && pwd && icon) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (pwd.type === 'password') {
|
||||||
|
pwd.type = 'text';
|
||||||
|
icon.classList.remove('fa-eye-slash');
|
||||||
|
icon.classList.add('fa-eye');
|
||||||
|
} else {
|
||||||
|
pwd.type = 'password';
|
||||||
|
icon.classList.remove('fa-eye');
|
||||||
|
icon.classList.add('fa-eye-slash');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
|
<!-- Top Navbar Header (Div container to prevent header resets) -->
|
||||||
|
<div class="o_login_top_header">
|
||||||
|
<div class="o_top_header_left">
|
||||||
|
<div class="o_top_brand">
|
||||||
|
<div class="o_top_brand_icon">
|
||||||
|
<i class="fa fa-cutlery"/>
|
||||||
|
</div>
|
||||||
|
<span class="o_top_brand_name">Dine<span class="o_top_brand_accent">360</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="o_top_header_divider"/>
|
||||||
|
<span class="o_top_header_subtitle">Smart Restaurant Management</span>
|
||||||
|
</div>
|
||||||
|
<div class="o_top_header_right">
|
||||||
|
<div class="o_lang_dropdown">
|
||||||
|
<button class="o_lang_btn" type="button">
|
||||||
|
<i class="fa fa-globe"/>
|
||||||
|
<span>English</span>
|
||||||
|
<i class="fa fa-angle-down"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<a href="mailto:support@dine360.com" class="o_help_pill_btn">
|
||||||
|
<i class="fa fa-headphones"/>
|
||||||
|
<span>Need Help?</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="o_login_main_wrapper">
|
<div class="o_login_main_wrapper">
|
||||||
|
<!-- Subtle background decorative curved swoosh SVG -->
|
||||||
|
<div class="o_curved_red_accent">
|
||||||
|
<svg viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M600 50C450 120 320 280 400 480C440 580 520 620 600 650" stroke="#dc2626" stroke-width="1.2" stroke-opacity="0.3" fill="none"/>
|
||||||
|
<path d="M600 120C480 180 370 320 440 500C475 585 540 620 600 640" stroke="#fca5a5" stroke-width="0.8" stroke-opacity="0.25" fill="none"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Left Side: Culinary Branding Hero Showcase -->
|
<!-- Left Side: Culinary Branding Hero Showcase -->
|
||||||
<div class="o_login_left_side">
|
<div class="o_login_left_side">
|
||||||
<div class="o_login_hero_content">
|
<div class="o_login_hero_content">
|
||||||
@ -21,7 +77,10 @@
|
|||||||
<span class="o_hero_badge_dot"/>
|
<span class="o_hero_badge_dot"/>
|
||||||
<span>NEXT-GEN RESTAURANT SUITE</span>
|
<span>NEXT-GEN RESTAURANT SUITE</span>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="o_hero_title">Elevate Your Dining Experience</h1>
|
<h1 class="o_hero_title">
|
||||||
|
Elevate Your Dining<br/>
|
||||||
|
<span class="o_title_accent">Experience</span>
|
||||||
|
</h1>
|
||||||
<p class="o_hero_subtitle">Unified Point of Sale, Kitchen Display System (KDS), Interactive Tables, and Online Orders — all in one modern platform.</p>
|
<p class="o_hero_subtitle">Unified Point of Sale, Kitchen Display System (KDS), Interactive Tables, and Online Orders — all in one modern platform.</p>
|
||||||
|
|
||||||
<div class="o_hero_features">
|
<div class="o_hero_features">
|
||||||
@ -29,40 +88,39 @@
|
|||||||
<div class="o_feature_icon"><i class="fa fa-cutlery"/></div>
|
<div class="o_feature_icon"><i class="fa fa-cutlery"/></div>
|
||||||
<div class="o_feature_text">
|
<div class="o_feature_text">
|
||||||
<h6>Interactive Floor Plans</h6>
|
<h6>Interactive Floor Plans</h6>
|
||||||
<p>Real-time visual table booking & occupancy tracking</p>
|
<p>Real-time visual table booking & occupancy tracking.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="o_hero_feature_item">
|
<div class="o_hero_feature_item">
|
||||||
<div class="o_feature_icon"><i class="fa fa-fire"/></div>
|
<div class="o_feature_icon">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M12 2C9.5 2 7.4 3.7 6.8 6c-.4-.1-.8-.1-1.2-.1C3 5.9 1 7.9 1 10.5 1 12.8 2.6 14.8 4.8 15.1L5 20h14l.2-4.9c2.2-.3 3.8-2.3 3.8-4.6 0-2.6-2-4.6-4.6-4.6-.4 0-.8 0-1.2.1C16.6 3.7 14.5 2 12 2zm-5 17h10v1H7v-1z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
<div class="o_feature_text">
|
<div class="o_feature_text">
|
||||||
<h6>Real-Time Kitchen Display</h6>
|
<h6>Real-Time Kitchen Display</h6>
|
||||||
<p>Automated order routing, prep timers, and status syncing</p>
|
<p>Automated order routing, prep times, and status syncing.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="o_hero_feature_item">
|
<div class="o_hero_feature_item">
|
||||||
<div class="o_feature_icon"><i class="fa fa-mobile"/></div>
|
<div class="o_feature_icon"><i class="fa fa-mobile"/></div>
|
||||||
<div class="o_feature_text">
|
<div class="o_feature_text">
|
||||||
<h6>Seamless QR & Online Orders</h6>
|
<h6>Seamless QR & Online Orders</h6>
|
||||||
<p>Zero-friction customer self-ordering and delivery dispatch</p>
|
<p>Zero-friction customer self-ordering and delivery dispatch.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right Side: Glassmorphic Login Card -->
|
<!-- Right Side: Clean White Floating Login Card -->
|
||||||
<div class="o_login_right_side">
|
<div class="o_login_right_side">
|
||||||
<div class="o_login_card">
|
<div class="o_login_card">
|
||||||
<div class="o_login_logo_container">
|
<div class="o_login_card_logo">
|
||||||
<div class="o_login_brand_header">
|
<div class="o_brand_icon">
|
||||||
<div class="o_brand_icon">
|
<i class="fa fa-cutlery"/>
|
||||||
<i class="fa fa-cutlery"/>
|
|
||||||
</div>
|
|
||||||
<span class="o_brand_name">Dine<span class="o_brand_accent">360</span></span>
|
|
||||||
</div>
|
|
||||||
<div class="o_login_logo_box" t-if="request and request.env and request.env.company and request.env.company.name != 'My Company'">
|
|
||||||
<span class="o_company_tag" t-esc="request.env.company.name"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span class="o_brand_name">Dine<span class="o_brand_accent">360</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="o_login_header_text text-center">
|
<div class="o_login_header_text text-center">
|
||||||
@ -81,7 +139,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="o_login_brand_footer text-center mt-3">
|
<div class="o_login_brand_footer text-center mt-3">
|
||||||
<p>Powered by <a href="https://dine360.com/" target="_blank">Dine360</a> Cloud ERP</p>
|
<p>Powered by <span class="o_powered_brand">Dine360</span> Cloud ERP</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -89,4 +147,35 @@
|
|||||||
</t>
|
</t>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- Custom Login Form Fields Inheritance (Icons + Eye Toggle + Arrow Button) -->
|
||||||
|
<template id="custom_login_form_fields" inherit_id="web.login" name="Custom Dine360 Login Fields" priority="99">
|
||||||
|
<xpath expr="//div[hasclass('field-login')]" position="replace">
|
||||||
|
<div class="mb-3 field-login">
|
||||||
|
<label for="login" class="form-label">Email</label>
|
||||||
|
<div class="o_input_icon_wrap">
|
||||||
|
<i class="fa fa-envelope-o o_input_icon"/>
|
||||||
|
<input type="text" placeholder="Email" name="login" t-att-value="login" id="login" class="form-control" required="required" autocomplete="username" autofocus="autofocus" autocapitalize="off"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//div[hasclass('mb-3')][label[@for='password']]" position="replace">
|
||||||
|
<div class="mb-3 field-password">
|
||||||
|
<label for="password" class="form-label">Password</label>
|
||||||
|
<div class="o_input_icon_wrap">
|
||||||
|
<i class="fa fa-lock o_input_icon"/>
|
||||||
|
<input type="password" placeholder="Password" name="password" id="password" class="form-control" required="required" autocomplete="current-password" t-att-autofocus="'autofocus' if login else None" maxlength="4096"/>
|
||||||
|
<button type="button" class="btn o_toggle_password_btn" id="togglePasswordBtn" tabindex="-1">
|
||||||
|
<i class="fa fa-eye-slash" id="togglePasswordIcon"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//button[@type='submit']" position="replace">
|
||||||
|
<button type="submit" class="btn btn-primary o_login_submit_btn">
|
||||||
|
<span>Log In</span>
|
||||||
|
<i class="fa fa-arrow-right ms-2"/>
|
||||||
|
</button>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@ -30,4 +30,10 @@
|
|||||||
parent="menu_restaurant_reservation_root"
|
parent="menu_restaurant_reservation_root"
|
||||||
action="action_reservation_holiday"
|
action="action_reservation_holiday"
|
||||||
sequence="40"/>
|
sequence="40"/>
|
||||||
|
|
||||||
|
<menuitem id="menu_reservation_custom_fields"
|
||||||
|
name="Additional Fields"
|
||||||
|
parent="menu_restaurant_reservation_root"
|
||||||
|
action="action_reservation_custom_fields"
|
||||||
|
sequence="50"/>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@ -63,10 +63,4 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Submenu under Table Reservation -->
|
|
||||||
<menuitem id="menu_reservation_custom_fields"
|
|
||||||
name="Additional Fields"
|
|
||||||
parent="dine360_reservation.menu_restaurant_reservation_root"
|
|
||||||
action="action_reservation_custom_fields"
|
|
||||||
sequence="40"/>
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@ -19,11 +19,17 @@ def _async_provisioning_worker(parent_db, saas_res_id, db_name, modules, company
|
|||||||
# Remove 'base' from modules list if present since exp_create_database already installs it
|
# Remove 'base' from modules list if present since exp_create_database already installs it
|
||||||
cli_modules = [m for m in modules if m != 'base']
|
cli_modules = [m for m in modules if m != 'base']
|
||||||
cmd = ["odoo", "-i", ",".join(cli_modules), "-d", db_name, "--db_host=db", "-r", "odoo", "-w", "odoo", "--stop-after-init"]
|
cmd = ["odoo", "-i", ",".join(cli_modules), "-d", db_name, "--db_host=db", "-r", "odoo", "-w", "odoo", "--stop-after-init"]
|
||||||
_logger.info(f"Executing background CLI installation: {' '.join(cmd)}")
|
log_file_path = f"/tmp/provision_{db_name}.log"
|
||||||
|
with open(log_file_path, "w") as log_file:
|
||||||
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
result = subprocess.run(cmd, stdout=log_file, stderr=subprocess.STDOUT, text=True)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
raise Exception(f"Odoo CLI installation failed (exit code {result.returncode}): {result.stderr or result.stdout}")
|
tail_msg = ""
|
||||||
|
try:
|
||||||
|
with open(log_file_path, "r") as log_file:
|
||||||
|
tail_msg = log_file.read()[-2000:]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
raise Exception(f"Odoo CLI installation failed (exit code {result.returncode}): {tail_msg}")
|
||||||
|
|
||||||
_logger.info(f"Background thread: Base modules installed on {db_name}. Configuring company & admin...")
|
_logger.info(f"Background thread: Base modules installed on {db_name}. Configuring company & admin...")
|
||||||
|
|
||||||
@ -32,16 +38,46 @@ def _async_provisioning_worker(parent_db, saas_res_id, db_name, modules, company
|
|||||||
with tenant_registry.cursor() as cr:
|
with tenant_registry.cursor() as cr:
|
||||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||||
|
|
||||||
# Company setup
|
# Company setup (safe update only non-empty fields)
|
||||||
company = env['res.company'].search([], limit=1)
|
company = env['res.company'].search([], limit=1)
|
||||||
company.write(company_vals)
|
if company and company_vals:
|
||||||
|
cleaned_company_vals = {k: v for k, v in company_vals.items() if v is not False and v is not None and v != ''}
|
||||||
|
if cleaned_company_vals:
|
||||||
|
company.write(cleaned_company_vals)
|
||||||
|
|
||||||
# Admin user setup (ID 2 is usually admin)
|
# Admin user setup (ID 2 is usually admin)
|
||||||
admin_user = env['res.users'].browse(2)
|
admin_user = env['res.users'].browse(2)
|
||||||
admin_user.write(admin_vals)
|
if admin_user.exists() and admin_vals:
|
||||||
|
cleaned_admin_vals = {k: v for k, v in admin_vals.items() if v is not False and v is not None and v != ''}
|
||||||
|
if cleaned_admin_vals:
|
||||||
|
admin_user.write(cleaned_admin_vals)
|
||||||
|
|
||||||
# Set timezone
|
# Set timezone
|
||||||
admin_user.partner_id.tz = timezone or 'America/New_York'
|
if timezone and admin_user.exists() and admin_user.partner_id:
|
||||||
|
admin_user.partner_id.tz = timezone or 'America/New_York'
|
||||||
|
|
||||||
|
# Ensure Restaurant POS Configuration is enabled
|
||||||
|
if 'pos.config' in env:
|
||||||
|
for p_cfg in env['pos.config'].search([]):
|
||||||
|
vals_to_write = {}
|
||||||
|
if hasattr(p_cfg, 'module_pos_restaurant') and not p_cfg.module_pos_restaurant:
|
||||||
|
vals_to_write['module_pos_restaurant'] = True
|
||||||
|
if hasattr(p_cfg, 'online_orders_enabled') and not p_cfg.online_orders_enabled:
|
||||||
|
vals_to_write['online_orders_enabled'] = True
|
||||||
|
if hasattr(p_cfg, 'use_qz_printer') and not p_cfg.use_qz_printer:
|
||||||
|
vals_to_write['use_qz_printer'] = True
|
||||||
|
if vals_to_write:
|
||||||
|
p_cfg.write(vals_to_write)
|
||||||
|
|
||||||
|
# Ensure default draft Uber config exists if uber module is installed
|
||||||
|
if 'uber.config' in env:
|
||||||
|
if not env['uber.config'].search([], limit=1):
|
||||||
|
env['uber.config'].create({
|
||||||
|
'name': f"{company.name if company else 'Restaurant'} Uber Eats / Direct",
|
||||||
|
'client_id': 'SANDBOX_CLIENT_ID',
|
||||||
|
'client_secret': 'SANDBOX_CLIENT_SECRET',
|
||||||
|
'environment': 'sandbox',
|
||||||
|
})
|
||||||
|
|
||||||
# Force Odoo registry signaling update
|
# Force Odoo registry signaling update
|
||||||
env.registry.registry_invalidated = True
|
env.registry.registry_invalidated = True
|
||||||
@ -150,12 +186,49 @@ class SaasRestaurant(models.Model):
|
|||||||
currency_id = fields.Many2one('res.currency', string='Base Currency')
|
currency_id = fields.Many2one('res.currency', string='Base Currency')
|
||||||
timezone = fields.Char(string='Timezone', default='America/New_York')
|
timezone = fields.Char(string='Timezone', default='America/New_York')
|
||||||
logo = fields.Binary(string='Restaurant Logo')
|
logo = fields.Binary(string='Restaurant Logo')
|
||||||
|
# Onboarding Features for Restaurant Tenant
|
||||||
|
feature_online_orders = fields.Boolean(
|
||||||
|
string='Online Orders (POS & Web)',
|
||||||
|
default=True,
|
||||||
|
help='Installs Dine360 Online Orders with POS integration and KDS.'
|
||||||
|
)
|
||||||
|
feature_table_reservation = fields.Boolean(
|
||||||
|
string='Table Reservation & Theme',
|
||||||
|
default=True,
|
||||||
|
help='Installs Dine360 Table Reservation and Theme Customizer.'
|
||||||
|
)
|
||||||
|
feature_uber_integration = fields.Boolean(
|
||||||
|
string='Uber Integration (Eats & Direct)',
|
||||||
|
default=True,
|
||||||
|
help='Installs Dine360 Uber Integration for Eats and Direct delivery.'
|
||||||
|
)
|
||||||
|
feature_dashboard = fields.Boolean(
|
||||||
|
string='Modern Unified Dashboard',
|
||||||
|
default=True,
|
||||||
|
help='Installs Dine360 Modern Dashboard with unified navigation and module pages.'
|
||||||
|
)
|
||||||
|
feature_qz_printer = fields.Boolean(
|
||||||
|
string='QZ Tray Thermal Printer',
|
||||||
|
default=True,
|
||||||
|
help='Installs Dine360 QZ Printer module for Star/Epson direct thermal receipt printing.'
|
||||||
|
)
|
||||||
activate_table_reservation = fields.Boolean(
|
activate_table_reservation = fields.Boolean(
|
||||||
string='Activate Table Reservation Theme',
|
string='Activate Table Reservation Theme',
|
||||||
default=False,
|
compute='_compute_activate_table_reservation',
|
||||||
help='If checked, automatically installs and configures the themed Table Reservation module on this restaurant database.'
|
inverse='_inverse_activate_table_reservation',
|
||||||
|
store=True,
|
||||||
|
help='Legacy flag mapped to Table Reservation.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@api.depends('feature_table_reservation')
|
||||||
|
def _compute_activate_table_reservation(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.activate_table_reservation = rec.feature_table_reservation
|
||||||
|
|
||||||
|
def _inverse_activate_table_reservation(self):
|
||||||
|
for rec in self:
|
||||||
|
rec.feature_table_reservation = rec.activate_table_reservation
|
||||||
|
|
||||||
_sql_constraints = [
|
_sql_constraints = [
|
||||||
('unique_subdomain', 'unique(subdomain)', 'This subdomain is already taken!'),
|
('unique_subdomain', 'unique(subdomain)', 'This subdomain is already taken!'),
|
||||||
('unique_database_name', 'unique(database_name)', 'This database name is already registered!')
|
('unique_database_name', 'unique(database_name)', 'This database name is already registered!')
|
||||||
@ -222,13 +295,31 @@ class SaasRestaurant(models.Model):
|
|||||||
'password': admin_pass,
|
'password': admin_pass,
|
||||||
}
|
}
|
||||||
|
|
||||||
modules_to_install = [
|
# Clean values to avoid DB constraint failures (such as null currency_id)
|
||||||
'base', 'contacts', 'sale', 'stock', 'purchase',
|
company_vals = {k: v for k, v in company_vals.items() if v is not False and v is not None and v != ''}
|
||||||
'account', 'point_of_sale', 'hr', 'pos_restaurant',
|
admin_vals = {k: v for k, v in admin_vals.items() if v is not False and v is not None and v != ''}
|
||||||
'dine360_table', 'dine360_dashboard'
|
|
||||||
]
|
# Only install requested onboard features and their dependencies
|
||||||
if self.activate_table_reservation:
|
modules_to_install = []
|
||||||
modules_to_install.extend(['website', 'dine360_reservation', 'dine360_theme_reservation'])
|
if self.feature_online_orders:
|
||||||
|
modules_to_install.append('dine360_online_orders')
|
||||||
|
if self.feature_table_reservation:
|
||||||
|
modules_to_install.append('dine360_theme_reservation')
|
||||||
|
if self.feature_uber_integration:
|
||||||
|
modules_to_install.append('dine360_uber')
|
||||||
|
if self.feature_dashboard:
|
||||||
|
modules_to_install.append('dine360_dashboard')
|
||||||
|
if self.feature_qz_printer:
|
||||||
|
modules_to_install.append('dine360_qz_printer')
|
||||||
|
|
||||||
|
if not modules_to_install:
|
||||||
|
modules_to_install = [
|
||||||
|
'dine360_online_orders',
|
||||||
|
'dine360_theme_reservation',
|
||||||
|
'dine360_uber',
|
||||||
|
'dine360_dashboard',
|
||||||
|
'dine360_qz_printer'
|
||||||
|
]
|
||||||
|
|
||||||
# Set status to provisioning
|
# Set status to provisioning
|
||||||
self.status = 'provisioning'
|
self.status = 'provisioning'
|
||||||
|
|||||||
@ -54,7 +54,13 @@
|
|||||||
<group string="Tenant Deployment">
|
<group string="Tenant Deployment">
|
||||||
<field name="database_name"/>
|
<field name="database_name"/>
|
||||||
<field name="subdomain"/>
|
<field name="subdomain"/>
|
||||||
<field name="activate_table_reservation"/>
|
</group>
|
||||||
|
<group string="Restaurant Features (Activated by Default)">
|
||||||
|
<field name="feature_online_orders"/>
|
||||||
|
<field name="feature_table_reservation"/>
|
||||||
|
<field name="feature_uber_integration"/>
|
||||||
|
<field name="feature_dashboard"/>
|
||||||
|
<field name="feature_qz_printer"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="Subscription Details">
|
<group string="Subscription Details">
|
||||||
<field name="plan_id"/>
|
<field name="plan_id"/>
|
||||||
|
|||||||
@ -12,5 +12,5 @@
|
|||||||
name="Theme Settings"
|
name="Theme Settings"
|
||||||
parent="dine360_reservation.menu_restaurant_reservation_root"
|
parent="dine360_reservation.menu_restaurant_reservation_root"
|
||||||
action="action_reservation_theme_settings"
|
action="action_reservation_theme_settings"
|
||||||
sequence="50"/>
|
sequence="60"/>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user