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)
|
||||
def dashboard_reservations(self, **kwargs):
|
||||
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)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
@ -402,6 +404,8 @@ class Dine360DashboardController(http.Controller):
|
||||
@http.route('/dashboard/tables', type='http', auth='user', website=True)
|
||||
def dashboard_tables(self, **kwargs):
|
||||
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)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
|
||||
@ -13,7 +13,15 @@ class IrUiMenu(models.Model):
|
||||
user = self.env.user
|
||||
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']:
|
||||
new_children = []
|
||||
@ -23,12 +31,17 @@ class IrUiMenu(models.Model):
|
||||
continue
|
||||
name = child_menu.get('name')
|
||||
|
||||
# Allow matching menus (with fallback for Table Reservation naming variations)
|
||||
if name in allowed_menus or name == 'Table Reservation':
|
||||
# Hide Apps and Settings for non-admins
|
||||
if name in ['Apps', 'Settings'] and not is_admin:
|
||||
continue
|
||||
new_children.append(child_id)
|
||||
if is_saas_master:
|
||||
if name in allowed_menus:
|
||||
if name in ['Apps', 'Settings'] and not is_admin:
|
||||
continue
|
||||
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
|
||||
|
||||
return menus
|
||||
|
||||
@ -1390,6 +1390,12 @@ body.o_restaurant_body #wrap {
|
||||
}
|
||||
|
||||
/* Onboarded Restaurant Card Row - Highlighted Signature Card */
|
||||
.o_restaurants_list {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
gap: 5px !important;
|
||||
}
|
||||
|
||||
.o_res_row_card {
|
||||
background: #ffffff;
|
||||
border: 1.5px solid #e2e8f0;
|
||||
@ -1402,6 +1408,7 @@ body.o_restaurant_body #wrap {
|
||||
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);
|
||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.o_res_row_card:hover {
|
||||
@ -2231,4 +2238,33 @@ body.o_restaurant_body #wrap {
|
||||
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
|
||||
Luxury Bright Culinary Aesthetic - Matching User Reference Screenshot
|
||||
========================================================================== */
|
||||
|
||||
/* 1. Global Reset & Body */
|
||||
body.o_custom_login_body {
|
||||
margin: 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;
|
||||
min-height: 100vh !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 footer,
|
||||
body.o_custom_login_body .o_footer_copyright,
|
||||
@ -32,228 +33,339 @@ body.o_custom_login_body #wrapwrap {
|
||||
padding-top: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* 2. Main Wrapper: Immersive Ambient Split */
|
||||
.o_login_main_wrapper {
|
||||
display: flex !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 */
|
||||
.o_login_left_side {
|
||||
flex: 1.25 !important;
|
||||
/* 2. Top Header Navigation Bar */
|
||||
.o_login_top_header {
|
||||
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;
|
||||
align-items: 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;
|
||||
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;
|
||||
}
|
||||
|
||||
.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 {
|
||||
max-width: 540px !important;
|
||||
max-width: 520px !important;
|
||||
}
|
||||
|
||||
.o_hero_badge {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
gap: 8px !important;
|
||||
background: rgba(229, 0, 0, 0.12) !important;
|
||||
border: 1px solid rgba(229, 0, 0, 0.3) !important;
|
||||
color: #ff6b6b !important;
|
||||
font-size: 0.75rem !important;
|
||||
background: #fef2f2 !important;
|
||||
border: 1px solid #fee2e2 !important;
|
||||
color: #dc2626 !important;
|
||||
font-size: 0.74rem !important;
|
||||
font-weight: 700 !important;
|
||||
letter-spacing: 1.5px !important;
|
||||
letter-spacing: 1.2px !important;
|
||||
border-radius: 50px !important;
|
||||
padding: 6px 16px !important;
|
||||
margin-bottom: 24px !important;
|
||||
padding: 6px 14px !important;
|
||||
margin-bottom: 20px !important;
|
||||
text-transform: uppercase !important;
|
||||
}
|
||||
|
||||
.o_hero_badge_dot {
|
||||
width: 8px !important;
|
||||
height: 8px !important;
|
||||
background: #ef4444 !important;
|
||||
width: 7px !important;
|
||||
height: 7px !important;
|
||||
background: #dc2626 !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 {
|
||||
font-size: 3.1rem !important;
|
||||
font-size: 3.35rem !important;
|
||||
font-weight: 800 !important;
|
||||
letter-spacing: -1px !important;
|
||||
color: #ffffff !important;
|
||||
line-height: 1.15 !important;
|
||||
letter-spacing: -1.2px !important;
|
||||
color: #0f172a !important;
|
||||
line-height: 1.12 !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 {
|
||||
font-size: 1.1rem !important;
|
||||
color: #94a3b8 !important;
|
||||
font-size: 1.05rem !important;
|
||||
color: #64748b !important;
|
||||
line-height: 1.6 !important;
|
||||
margin-bottom: 36px !important;
|
||||
margin-bottom: 30px !important;
|
||||
}
|
||||
|
||||
.o_hero_features {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
gap: 14px !important;
|
||||
gap: 12px !important;
|
||||
}
|
||||
|
||||
.o_hero_feature_item {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
gap: 16px !important;
|
||||
background: rgba(255, 255, 255, 0.03) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.07) !important;
|
||||
border-radius: 14px !important;
|
||||
padding: 14px 18px !important;
|
||||
backdrop-filter: blur(8px) !important;
|
||||
background: rgba(255, 255, 255, 0.92) !important;
|
||||
border: 1px solid rgba(226, 232, 240, 0.95) !important;
|
||||
border-radius: 16px !important;
|
||||
padding: 13px 18px !important;
|
||||
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.03) !important;
|
||||
transition: all 0.25s ease !important;
|
||||
}
|
||||
|
||||
.o_hero_feature_item:hover {
|
||||
background: rgba(255, 255, 255, 0.06) !important;
|
||||
border-color: rgba(229, 0, 0, 0.3) !important;
|
||||
background: #ffffff !important;
|
||||
border-color: #cbd5e1 !important;
|
||||
transform: translateX(4px) !important;
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06) !important;
|
||||
}
|
||||
|
||||
.o_feature_icon {
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
width: 42px !important;
|
||||
height: 42px !important;
|
||||
border-radius: 10px !important;
|
||||
background: rgba(229, 0, 0, 0.15) !important;
|
||||
color: #ef4444 !important;
|
||||
background: #dc2626 !important;
|
||||
color: #ffffff !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
font-size: 1.1rem !important;
|
||||
font-size: 1.15rem !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 {
|
||||
color: #ffffff !important;
|
||||
color: #0f172a !important;
|
||||
font-weight: 700 !important;
|
||||
font-size: 0.95rem !important;
|
||||
font-size: 0.94rem !important;
|
||||
margin: 0 0 2px 0 !important;
|
||||
}
|
||||
|
||||
.o_feature_text p {
|
||||
color: #94a3b8 !important;
|
||||
color: #64748b !important;
|
||||
font-size: 0.82rem !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 {
|
||||
flex: 1 !important;
|
||||
flex: 0.95 !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
padding: 40px 24px !important;
|
||||
justify-content: flex-end !important;
|
||||
position: relative !important;
|
||||
z-index: 2 !important;
|
||||
}
|
||||
|
||||
.o_login_card {
|
||||
width: 100% !important;
|
||||
max-width: 440px !important;
|
||||
background: rgba(15, 23, 42, 0.8) !important;
|
||||
backdrop-filter: blur(28px) saturate(190%) !important;
|
||||
-webkit-backdrop-filter: blur(28px) saturate(190%) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12) !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;
|
||||
max-width: 430px !important;
|
||||
background: #ffffff !important;
|
||||
border: 1px solid #f1f5f9 !important;
|
||||
border-radius: 28px !important;
|
||||
box-shadow: 0 25px 60px -15px rgba(15, 23, 42, 0.12), 0 0 25px rgba(0, 0, 0, 0.03) !important;
|
||||
padding: 38px 36px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
/* Brand Header */
|
||||
.o_login_logo_container {
|
||||
text-align: center !important;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
|
||||
.o_login_brand_header {
|
||||
display: inline-flex !important;
|
||||
/* Brand Header inside card */
|
||||
.o_login_card_logo {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
gap: 10px !important;
|
||||
margin-bottom: 14px !important;
|
||||
}
|
||||
|
||||
.o_brand_icon {
|
||||
width: 44px !important;
|
||||
height: 44px !important;
|
||||
background: linear-gradient(135deg, #e50000 0%, #b91c1c 100%) !important;
|
||||
background: #dc2626 !important;
|
||||
border-radius: 12px !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
color: #ffffff !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 {
|
||||
font-size: 1.85rem !important;
|
||||
font-weight: 800 !important;
|
||||
color: #ffffff !important;
|
||||
color: #0f172a !important;
|
||||
letter-spacing: -0.5px !important;
|
||||
}
|
||||
|
||||
.o_brand_accent {
|
||||
color: #ef4444 !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;
|
||||
color: #dc2626 !important;
|
||||
}
|
||||
|
||||
/* Header Text */
|
||||
.o_login_header_text h3 {
|
||||
font-size: 1.45rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: #ffffff !important;
|
||||
margin-bottom: 6px !important;
|
||||
font-size: 1.55rem !important;
|
||||
font-weight: 800 !important;
|
||||
color: #0f172a !important;
|
||||
margin-bottom: 4px !important;
|
||||
letter-spacing: -0.3px !important;
|
||||
}
|
||||
|
||||
.o_login_header_text p {
|
||||
font-size: 0.88rem !important;
|
||||
color: #94a3b8 !important;
|
||||
margin-bottom: 24px !important;
|
||||
font-size: 0.85rem !important;
|
||||
color: #64748b !important;
|
||||
margin-bottom: 22px !important;
|
||||
}
|
||||
|
||||
/* 5. Inputs & Form Controls */
|
||||
/* 6. Inputs & Form Controls */
|
||||
.o_login_form_container label,
|
||||
.oe_login_form label {
|
||||
color: #cbd5e1 !important;
|
||||
color: #334155 !important;
|
||||
font-weight: 600 !important;
|
||||
font-size: 0.84rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
@ -262,186 +374,231 @@ body.o_custom_login_body #wrapwrap {
|
||||
|
||||
.o_login_form_container .form-control,
|
||||
.oe_login_form .form-control {
|
||||
background: rgba(255, 255, 255, 0.06) !important;
|
||||
border: 1.5px solid rgba(255, 255, 255, 0.14) !important;
|
||||
border-radius: 12px !important;
|
||||
color: #ffffff !important;
|
||||
padding: 11px 15px !important;
|
||||
font-size: 0.95rem !important;
|
||||
height: auto !important;
|
||||
background: #ffffff !important;
|
||||
border: 1.5px solid #e2e8f0 !important;
|
||||
border-radius: 10px !important;
|
||||
color: #0f172a !important;
|
||||
padding: 10px 14px !important;
|
||||
font-size: 0.92rem !important;
|
||||
height: 44px !important;
|
||||
transition: all 0.2s ease !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.o_login_form_container .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,
|
||||
.oe_login_form .form-control:focus {
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
border-color: #ef4444 !important;
|
||||
color: #ffffff !important;
|
||||
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.25) !important;
|
||||
background: #ffffff !important;
|
||||
border-color: #dc2626 !important;
|
||||
color: #0f172a !important;
|
||||
box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12) !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:hover,
|
||||
.oe_login_form input:-webkit-autofill:focus,
|
||||
.o_login_form_container input:-webkit-autofill,
|
||||
.o_login_form_container input:-webkit-autofill:hover,
|
||||
.o_login_form_container input:-webkit-autofill:focus {
|
||||
-webkit-text-fill-color: #ffffff !important;
|
||||
-webkit-box-shadow: 0 0 0px 1000px #1e293b inset !important;
|
||||
border-color: rgba(255, 255, 255, 0.2) !important;
|
||||
-webkit-text-fill-color: #0f172a !important;
|
||||
-webkit-box-shadow: 0 0 0px 1000px #ffffff inset !important;
|
||||
border-color: #e2e8f0 !important;
|
||||
transition: background-color 5000s ease-in-out 0s !important;
|
||||
}
|
||||
|
||||
/* Database Input Group */
|
||||
.input-group #db {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !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;
|
||||
/* 7. Primary Action Button */
|
||||
.oe_login_buttons .btn-primary,
|
||||
.o_login_submit_btn {
|
||||
background: #dc2626 !important;
|
||||
border: none !important;
|
||||
border-radius: 12px !important;
|
||||
padding: 13px !important;
|
||||
border-radius: 10px !important;
|
||||
height: 46px !important;
|
||||
font-weight: 700 !important;
|
||||
font-size: 1rem !important;
|
||||
font-size: 0.98rem !important;
|
||||
color: #ffffff !important;
|
||||
width: 100% !important;
|
||||
box-shadow: 0 8px 24px -4px rgba(229, 0, 0, 0.45) !important;
|
||||
transition: all 0.25s ease !important;
|
||||
display: inline-flex !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;
|
||||
}
|
||||
|
||||
.oe_login_buttons .btn-primary:hover {
|
||||
background: linear-gradient(135deg, #dc2626 0%, #991b1b 100%) !important;
|
||||
transform: translateY(-2px) !important;
|
||||
box-shadow: 0 12px 28px -4px rgba(229, 0, 0, 0.6) !important;
|
||||
.oe_login_buttons .btn-primary:hover,
|
||||
.o_login_submit_btn:hover {
|
||||
background: #b91c1c !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;
|
||||
}
|
||||
|
||||
/* Superuser button */
|
||||
.oe_login_buttons .btn-link {
|
||||
color: #94a3b8 !important;
|
||||
font-size: 0.85rem !important;
|
||||
/* Reset Password link */
|
||||
.justify-content-between.mt-2 a[href*="/web/signup"] {
|
||||
display: none !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;
|
||||
}
|
||||
|
||||
.oe_login_buttons .btn-link:hover {
|
||||
color: #ef4444 !important;
|
||||
a[href*="/web/reset_password"]:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
/* 7. Alerts */
|
||||
/* Alerts */
|
||||
.o_login_form_container .alert-danger,
|
||||
.oe_login_form .alert-danger {
|
||||
background: rgba(220, 38, 38, 0.25) !important;
|
||||
border: 1px solid rgba(220, 38, 38, 0.5) !important;
|
||||
color: #fca5a5 !important;
|
||||
border-radius: 12px !important;
|
||||
padding: 12px 14px !important;
|
||||
font-size: 0.88rem !important;
|
||||
background: #fef2f2 !important;
|
||||
border: 1px solid #fecaca !important;
|
||||
color: #b91c1c !important;
|
||||
border-radius: 10px !important;
|
||||
padding: 10px 14px !important;
|
||||
font-size: 0.86rem !important;
|
||||
}
|
||||
|
||||
.o_login_form_container .alert-success,
|
||||
.oe_login_form .alert-success {
|
||||
background: rgba(16, 185, 129, 0.25) !important;
|
||||
border: 1px solid rgba(16, 185, 129, 0.5) !important;
|
||||
color: #6ee7b7 !important;
|
||||
border-radius: 12px !important;
|
||||
padding: 12px 14px !important;
|
||||
font-size: 0.88rem !important;
|
||||
background: #f0fdf4 !important;
|
||||
border: 1px solid #bbf7d0 !important;
|
||||
color: #15803d !important;
|
||||
border-radius: 10px !important;
|
||||
padding: 10px 14px !important;
|
||||
font-size: 0.86rem !important;
|
||||
}
|
||||
|
||||
/* 8. Links and Footer */
|
||||
.oe_login_buttons a,
|
||||
.o_login_footer a,
|
||||
.o_login_link {
|
||||
color: #94a3b8 !important;
|
||||
.o_login_footer .o_login_link {
|
||||
color: #64748b !important;
|
||||
font-size: 0.85rem !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;
|
||||
}
|
||||
|
||||
.oe_login_buttons a:hover,
|
||||
.o_login_footer a:hover,
|
||||
.o_login_link:hover {
|
||||
color: #ef4444 !important;
|
||||
text-decoration: underline !important;
|
||||
.o_login_footer .o_login_link:hover {
|
||||
color: #0f172a !important;
|
||||
}
|
||||
|
||||
.o_login_brand_footer p {
|
||||
color: #64748b !important;
|
||||
color: #94a3b8 !important;
|
||||
font-size: 0.82rem !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.o_login_brand_footer a {
|
||||
color: #ef4444 !important;
|
||||
font-weight: 600 !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;
|
||||
.o_powered_brand {
|
||||
color: #dc2626 !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
/* 9. Responsive Breakpoints */
|
||||
@media (max-width: 992px) {
|
||||
.o_login_top_header {
|
||||
padding: 0 20px !important;
|
||||
}
|
||||
|
||||
.o_login_main_wrapper {
|
||||
flex-direction: column !important;
|
||||
justify-content: center !important;
|
||||
align-items: center !important;
|
||||
padding: 30px 20px !important;
|
||||
}
|
||||
|
||||
.o_login_left_side {
|
||||
@ -450,7 +607,7 @@ body.o_custom_login_body #wrapwrap {
|
||||
|
||||
.o_login_right_side {
|
||||
width: 100% !important;
|
||||
padding: 24px 16px !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
.o_login_card {
|
||||
|
||||
@ -267,8 +267,8 @@ body,
|
||||
padding: 8px 0 !important;
|
||||
}
|
||||
|
||||
.o_kanban_renderer .o_kanban_record,
|
||||
.o_kanban_view .o_kanban_record {
|
||||
.o_kanban_renderer .o_kanban_record:not(.o_kanban_ghost),
|
||||
.o_kanban_view .o_kanban_record:not(.o_kanban_ghost) {
|
||||
background: #ffffff !important;
|
||||
border: 1px solid #e2e8f0 !important;
|
||||
border-radius: 16px !important;
|
||||
@ -279,13 +279,41 @@ body,
|
||||
}
|
||||
|
||||
/* Hover Effect for Cards */
|
||||
.o_kanban_renderer .o_kanban_record:hover,
|
||||
.o_kanban_view .o_kanban_record:hover {
|
||||
.o_kanban_renderer .o_kanban_record:not(.o_kanban_ghost):hover,
|
||||
.o_kanban_view .o_kanban_record:not(.o_kanban_ghost):hover {
|
||||
transform: translateY(-3px) !important;
|
||||
box-shadow: 0 12px 24px -2px rgba(15, 23, 42, 0.1) !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 */
|
||||
.o_kanban_record .o_kanban_record_title,
|
||||
.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>
|
||||
|
||||
<!-- App 2: Table Reservations -->
|
||||
<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>
|
||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||
<div class="o_settings_icon" style="background:#dbeafe; color:#2563eb;">
|
||||
<i class="fa fa-calendar"/>
|
||||
<!-- App 2: Table Reservations (Tenant Restaurants Only) -->
|
||||
<t t-if="not is_saas_master">
|
||||
<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>
|
||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<!-- App 3: Table & Floor Manager -->
|
||||
<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>
|
||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||
<div class="o_settings_icon" style="background:#fef3c7; color:#d97706;">
|
||||
<i class="fa fa-th"/>
|
||||
<!-- 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="o_settings_card h-100 d-flex flex-column justify-content-between">
|
||||
<div>
|
||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||
<div class="o_settings_icon" style="background:#fef3c7; color:#d97706;">
|
||||
<i class="fa fa-th"/>
|
||||
</div>
|
||||
<span class="o_badge_status success"><span class="o_badge_dot"/> Installed</span>
|
||||
</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>
|
||||
<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>
|
||||
</t>
|
||||
|
||||
<!-- App 4: Point of Sale -->
|
||||
<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"/>
|
||||
<span>Restaurants</span>
|
||||
</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 '')">
|
||||
<i class="fa fa-th-large o_nav_icon"/>
|
||||
<span>Apps</span>
|
||||
@ -160,8 +152,8 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||||
<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 rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/home_menu.css?v=6.0"/>
|
||||
<script type="text/javascript" src="/dine360_dashboard/static/src/js/dashboard_pages.js?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.2"/>
|
||||
|
||||
<div class="o_saas_layout">
|
||||
<!-- Shared Dine360 Sidebar -->
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||||
<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 rel="stylesheet" type="text/css" href="/dine360_dashboard/static/src/css/home_menu.css?v=6.0"/>
|
||||
<script type="text/javascript" src="/dine360_dashboard/static/src/js/dashboard_pages.js?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.2"/>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- 1. ADMIN RESTAURANT ONBOARD MASTER DB DASHBOARD -->
|
||||
@ -191,13 +191,13 @@
|
||||
<div class="o_substats_col">
|
||||
<div class="o_substat_item">
|
||||
<div class="o_substat_icon_box">
|
||||
<i class="fa fa-calendar text-danger"/>
|
||||
<i class="fa fa-cutlery text-danger"/>
|
||||
</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">
|
||||
<span class="o_substat_val"><t t-esc="saas_dashboard_data['reservations_count']"/></span>
|
||||
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> +12%</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"/> 100%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -6,14 +6,70 @@
|
||||
<t t-set="body_classname" t-value="'o_custom_login_body'"/>
|
||||
<t t-set="no_header" 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">
|
||||
<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"/>
|
||||
<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>
|
||||
|
||||
<!-- 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">
|
||||
<!-- 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 -->
|
||||
<div class="o_login_left_side">
|
||||
<div class="o_login_hero_content">
|
||||
@ -21,7 +77,10 @@
|
||||
<span class="o_hero_badge_dot"/>
|
||||
<span>NEXT-GEN RESTAURANT SUITE</span>
|
||||
</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>
|
||||
|
||||
<div class="o_hero_features">
|
||||
@ -29,40 +88,39 @@
|
||||
<div class="o_feature_icon"><i class="fa fa-cutlery"/></div>
|
||||
<div class="o_feature_text">
|
||||
<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 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">
|
||||
<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 class="o_hero_feature_item">
|
||||
<div class="o_feature_icon"><i class="fa fa-mobile"/></div>
|
||||
<div class="o_feature_text">
|
||||
<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>
|
||||
|
||||
<!-- Right Side: Glassmorphic Login Card -->
|
||||
<!-- Right Side: Clean White Floating Login Card -->
|
||||
<div class="o_login_right_side">
|
||||
<div class="o_login_card">
|
||||
<div class="o_login_logo_container">
|
||||
<div class="o_login_brand_header">
|
||||
<div class="o_brand_icon">
|
||||
<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 class="o_login_card_logo">
|
||||
<div class="o_brand_icon">
|
||||
<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_header_text text-center">
|
||||
@ -81,7 +139,7 @@
|
||||
</div>
|
||||
|
||||
<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>
|
||||
@ -89,4 +147,35 @@
|
||||
</t>
|
||||
</xpath>
|
||||
</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>
|
||||
|
||||
@ -30,4 +30,10 @@
|
||||
parent="menu_restaurant_reservation_root"
|
||||
action="action_reservation_holiday"
|
||||
sequence="40"/>
|
||||
|
||||
<menuitem id="menu_reservation_custom_fields"
|
||||
name="Additional Fields"
|
||||
parent="menu_restaurant_reservation_root"
|
||||
action="action_reservation_custom_fields"
|
||||
sequence="50"/>
|
||||
</odoo>
|
||||
|
||||
@ -63,10 +63,4 @@
|
||||
</field>
|
||||
</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>
|
||||
|
||||
@ -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
|
||||
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"]
|
||||
_logger.info(f"Executing background CLI installation: {' '.join(cmd)}")
|
||||
|
||||
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
log_file_path = f"/tmp/provision_{db_name}.log"
|
||||
with open(log_file_path, "w") as log_file:
|
||||
result = subprocess.run(cmd, stdout=log_file, stderr=subprocess.STDOUT, text=True)
|
||||
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...")
|
||||
|
||||
@ -32,16 +38,46 @@ def _async_provisioning_worker(parent_db, saas_res_id, db_name, modules, company
|
||||
with tenant_registry.cursor() as cr:
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
|
||||
# Company setup
|
||||
# Company setup (safe update only non-empty fields)
|
||||
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 = 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
|
||||
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
|
||||
env.registry.registry_invalidated = True
|
||||
@ -150,12 +186,49 @@ class SaasRestaurant(models.Model):
|
||||
currency_id = fields.Many2one('res.currency', string='Base Currency')
|
||||
timezone = fields.Char(string='Timezone', default='America/New_York')
|
||||
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(
|
||||
string='Activate Table Reservation Theme',
|
||||
default=False,
|
||||
help='If checked, automatically installs and configures the themed Table Reservation module on this restaurant database.'
|
||||
compute='_compute_activate_table_reservation',
|
||||
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 = [
|
||||
('unique_subdomain', 'unique(subdomain)', 'This subdomain is already taken!'),
|
||||
('unique_database_name', 'unique(database_name)', 'This database name is already registered!')
|
||||
@ -222,13 +295,31 @@ class SaasRestaurant(models.Model):
|
||||
'password': admin_pass,
|
||||
}
|
||||
|
||||
modules_to_install = [
|
||||
'base', 'contacts', 'sale', 'stock', 'purchase',
|
||||
'account', 'point_of_sale', 'hr', 'pos_restaurant',
|
||||
'dine360_table', 'dine360_dashboard'
|
||||
]
|
||||
if self.activate_table_reservation:
|
||||
modules_to_install.extend(['website', 'dine360_reservation', 'dine360_theme_reservation'])
|
||||
# Clean values to avoid DB constraint failures (such as null currency_id)
|
||||
company_vals = {k: v for k, v in company_vals.items() if v is not False and v is not None and v != ''}
|
||||
admin_vals = {k: v for k, v in admin_vals.items() if v is not False and v is not None and v != ''}
|
||||
|
||||
# Only install requested onboard features and their dependencies
|
||||
modules_to_install = []
|
||||
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
|
||||
self.status = 'provisioning'
|
||||
|
||||
@ -54,7 +54,13 @@
|
||||
<group string="Tenant Deployment">
|
||||
<field name="database_name"/>
|
||||
<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 string="Subscription Details">
|
||||
<field name="plan_id"/>
|
||||
|
||||
@ -12,5 +12,5 @@
|
||||
name="Theme Settings"
|
||||
parent="dine360_reservation.menu_restaurant_reservation_root"
|
||||
action="action_reservation_theme_settings"
|
||||
sequence="50"/>
|
||||
sequence="60"/>
|
||||
</odoo>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user