Skip to content

[ADD] estate training : Created a new training module #350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 43 commits into
base: 18.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a0218e3
[ADD] estate: Created initial scaffold of a Real Estate module
jhra-odoo Feb 12, 2025
c4b7e7c
[IMP] estate: Make module installable and add access control
jhra-odoo Feb 12, 2025
618300d
[IMP] estate: Made the module interactive
jhra-odoo Feb 12, 2025
8ea37d6
[IMP] estate: Added basic views and categorisation options for easier…
jhra-odoo Feb 13, 2025
a89b058
[IMP] estate: Added ability to propose offers for properties
jhra-odoo Feb 13, 2025
cf9fd2d
[IMP] estate: Added validity and deadline for property offers
jhra-odoo Feb 13, 2025
8050918
[IMP] estate: Improved user actions and implemented proper access rules
jhra-odoo Feb 13, 2025
ea43df0
[IMP] estate: Added kanban view for more interactive property management
jhra-odoo Feb 13, 2025
90f06d2
[IMP] estate: Added multi-company support for estate properties
jhra-odoo Feb 14, 2025
d2e41d2
[IMP] estate: Implement data access restrictions
jhra-odoo Feb 17, 2025
cad9653
[IMP] estate: Added demo data for the module
jhra-odoo Feb 18, 2025
f2adfe0
[IMP] estate: Added ability to generate and print reports
jhra-odoo Feb 18, 2025
89ce3de
[ADD] warranty_extension: Created a module for warranty extension
jhra-odoo Feb 20, 2025
9b8e8c5
[IMP] warranty_extension: Overridden the unlink logic for sale.order.…
jhra-odoo Feb 21, 2025
21a1327
[ADD] awesome_owl: Initial commit
jhra-odoo Feb 24, 2025
64dc00d
[IMP] awesome_owl: Extracted counter
jhra-odoo Feb 24, 2025
05e619d
[ADD] awesome_owl: Added a card component
jhra-odoo Feb 24, 2025
5ca0a27
[IMP] awesome_owl: Updated a card component
jhra-odoo Feb 24, 2025
8c4851b
[IMP] awesome_owl: Added props validation in card component
jhra-odoo Feb 24, 2025
a4f6133
[IMP] awesome_owl: Added props validation in card component
jhra-odoo Feb 24, 2025
49687dc
[IMP] awesome_owl: Added callback prop for sum calculation
jhra-odoo Feb 24, 2025
8d956f6
[ADD] awesome_owl: Started working on a basic todo app
jhra-odoo Feb 24, 2025
5c1c6a1
[IMP] awesome_owl: Made the app reactive
jhra-odoo Feb 24, 2025
42b7462
[IMP] awesome_owl: Auto focus added
jhra-odoo Feb 24, 2025
2d9bc9e
[IMP] awesome_owl: Added ability to mark todo items as completed
jhra-odoo Feb 24, 2025
071e96e
[IMP] awesome_owl: Added ability to delete a todo item
jhra-odoo Feb 25, 2025
3a464d3
[IMP] awesome_owl: Card Content Update
jhra-odoo Feb 25, 2025
a3ef781
[IMP] awesome_dashboard: Started working on the dashboard
jhra-odoo Feb 25, 2025
b02b67c
[IMP] awesome_dashboard: Added navigation buttons
jhra-odoo Feb 25, 2025
45cde38
[IMP] awesome_dashboard: Added dashboard item
jhra-odoo Feb 25, 2025
7d9d642
[IMP] awesome_dashboard: Dashboard displays orders stats
jhra-odoo Feb 26, 2025
e81804c
[IMP] awesome_dashboard: Dashboard displays orders stats
jhra-odoo Feb 26, 2025
49e0ffc
[IMP] awesome_dashboard: Added piechart module
jhra-odoo Feb 26, 2025
ee37ae6
[IMP] awesome_dashboard: Data updation implemented
jhra-odoo Feb 26, 2025
73f18e8
[IMP] awesome_dashboard: Made dashboard a generic component
jhra-odoo Feb 26, 2025
9aeff93
[IMP] awesome_dashboard: Made dashboard extensible
jhra-odoo Feb 26, 2025
1a429b3
[IMP] awesome_dashboard: Added ability to toggle item visibility
jhra-odoo Feb 27, 2025
a4238f1
[ADD] mo_report: Added a new manufacturing order delivery report
jhra-odoo Feb 28, 2025
7d9f919
[ADD] update_discount: Enabled updation of discount on sale order
jhra-odoo Mar 3, 2025
cb80fb5
[IMP] update_discount: Changed method calling in sale order discount …
jhra-odoo Mar 3, 2025
9d7e690
[ADD] appointment_filters: Added various filters to the website's app…
jhra-odoo Mar 4, 2025
f0f938f
[ADD] supplier_portal: Added a new portal for suppliers
jhra-odoo Mar 5, 2025
c5874d7
[IMP] supplier_portal: Moved the portal
jhra-odoo Mar 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions appointment_filters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import controllers
13 changes: 13 additions & 0 deletions appointment_filters/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
'name': 'Appointment Filters',
'version': '18.0',
'description': 'Appointment Filters',
'depends': ['website_appointment','appointment_account_payment'],
'author': 'Rahul Jha (jhra)',
'website': 'https://www.odoo.com',
'category': 'Appointment/Filters',
'data': [
'views/appointment_filters.xml'
],
'license': 'LGPL-3',
}
1 change: 1 addition & 0 deletions appointment_filters/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import main
79 changes: 79 additions & 0 deletions appointment_filters/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
from odoo import http, _
from odoo.addons.website_appointment.controllers.appointment import WebsiteAppointment
from odoo.http import request

class WebsiteAppointmentFiltersController(WebsiteAppointment):
@http.route(['/appointment'], type='http', auth='public', website=True)
def appointment_type_index(self, **kwargs):
response = super().appointment_type_index()

# Get all initial appointment types from the parent method
all_appointment_types = response.qcontext.get('appointment_types', request.env['appointment.type'].sudo())

# Extract filter parameters
filter_type = kwargs.get('type')
filter_payment = kwargs.get('payment_step')
filter_schedule = kwargs.get('schedule')

# Start with the base domain - maintaining compatibility with parent controller
domain = [('website_published', '=', True)]
filter_descriptions = []

# Apply type filter (online/offline)
if filter_type == 'online':
domain.append(('location_id', '=', False))
filter_descriptions.append(_("Online appointments"))
elif filter_type == 'offline':
domain.append(('location_id', '!=', False))
filter_descriptions.append(_("Offline appointments"))

# Apply payment filter
if filter_payment == 'paid':
domain.append(('has_payment_step', '=', True))
filter_descriptions.append(_("Paid appointments"))
elif filter_payment == 'free':
domain.append(('has_payment_step', '=', False))
filter_descriptions.append(_("Free appointments"))

# Apply schedule filter
if filter_schedule == 'users':
domain.append(('schedule_based_on', '=', 'users'))
filter_descriptions.append(_("User-based scheduling"))
elif filter_schedule == 'resources':
domain.append(('schedule_based_on', '=', 'resources'))
filter_descriptions.append(_("Resource-based scheduling"))

# Get filtered appointment types if any filters are applied
total_count = len(all_appointment_types)
filtered_count = None
if len(domain) > 1: # More than just the website_published filter
filtered_types = request.env['appointment.type'].sudo().search(domain)
response.qcontext['appointment_types'] = filtered_types
filtered_count = len(filtered_types)

# Add filter information to context
has_filters = bool(filter_type and filter_type != 'all' or
filter_payment and filter_payment != 'all' or
filter_schedule and filter_schedule != 'all')

# Format the active filters text for display
active_filters_text = []
if filter_descriptions:
active_filters_text.extend(filter_descriptions)
print("active_filters_text", active_filters_text)

response.qcontext.update({
'active_filters': filter_descriptions,
'current_filters': {
'type': filter_type,
'payment_step': filter_payment,
'schedule': filter_schedule
},
'has_filters': has_filters,
'filtered_count': filtered_count,
'total_count': total_count,
'print_active_filters': active_filters_text,
})

return response
194 changes: 194 additions & 0 deletions appointment_filters/views/appointment_filters.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="website_filter_buttons" name="Appointment Filter Buttons" inherit_id="website_appointment.website_calendar_index_topbar">
<xpath expr="//t[@t-call='website.website_search_box_input']" position="before">
<div class="d-flex flex-wrap align-items-center">
<div class="dropdown d-none d-lg-block me-3 mb-2">
<a href="#" role="button" class="btn btn-light dropdown-toggle" data-bs-toggle="dropdown" title="Filter by Type">
<i class="fa fa-video-camera me-1" aria-hidden="true"></i>
<t t-if="current_filters.get('type')">
<t t-if="current_filters['type'] == 'online'"><span class="text-success">Online</span></t>
<t t-elif="current_filters['type'] == 'offline'"><span class="text-danger">Offline</span></t>
<t t-else="">Type</t>
</t>
<t t-else="">Type</t>
</a>
<div class="dropdown-menu">
<span t-attf-data-post="/appointment?#{keep_query('*', type='all')}" class="post_link cursor-pointer dropdown-item">All</span>
<span t-attf-data-post="/appointment?#{keep_query('*', type='online')}"
t-attf-class="post_link cursor-pointer dropdown-item text-success #{current_filters.get('type') == 'online' and 'active' or ''}">
<i class="fa fa-check me-2" t-if="current_filters.get('type') == 'online'"></i>Online
</span>
<span t-attf-data-post="/appointment?#{keep_query('*', type='offline')}"
t-attf-class="post_link cursor-pointer dropdown-item text-danger #{current_filters.get('type') == 'offline' and 'active' or ''}">
<i class="fa fa-check me-2" t-if="current_filters.get('type') == 'offline'"></i>Offline
</span>
</div>
</div>
<div class="dropdown d-none d-lg-block me-3 mb-2">
<a href="#" role="button" class="btn btn-light dropdown-toggle" data-bs-toggle="dropdown" title="Filter by Payment Step">
<i class="fa fa-credit-card me-1" aria-hidden="true"></i>
<t t-if="current_filters.get('payment_step')">
<t t-if="current_filters['payment_step'] == 'paid'"><span class="text-success">Paid</span></t>
<t t-elif="current_filters['payment_step'] == 'free'"><span class="text-danger">Free</span></t>
<t t-else="">Payment</t>
</t>
<t t-else="">Payment</t>
</a>
<div class="dropdown-menu">
<span t-attf-data-post="/appointment?#{keep_query('*', payment_step='all')}" class="post_link cursor-pointer dropdown-item">All</span>
<span t-attf-data-post="/appointment?#{keep_query('*', payment_step='paid')}"
t-attf-class="post_link cursor-pointer dropdown-item text-success #{current_filters.get('payment_step') == 'paid' and 'active' or ''}">
<i class="fa fa-check me-2" t-if="current_filters.get('payment_step') == 'paid'"></i>Paid
</span>
<span t-attf-data-post="/appointment?#{keep_query('*', payment_step='free')}"
t-attf-class="post_link cursor-pointer dropdown-item text-danger #{current_filters.get('payment_step') == 'free' and 'active' or ''}">
<i class="fa fa-check me-2" t-if="current_filters.get('payment_step') == 'free'"></i>Free
</span>
</div>
</div>
<div class="dropdown d-none d-lg-block me-3 mb-2">
<a href="#" role="button" class="btn btn-light dropdown-toggle" data-bs-toggle="dropdown" title="Filter by Schedule">
<i class="fa fa-calendar me-1" aria-hidden="true"></i>
<t t-if="current_filters.get('schedule')">
<t t-if="current_filters['schedule'] == 'users'"><span class="text-primary">Users</span></t>
<t t-elif="current_filters['schedule'] == 'resources'"><span class="text-secondary">Resources</span></t>
<t t-else="">Schedule</t>
</t>
<t t-else="">Schedule</t>
</a>
<div class="dropdown-menu">
<span t-attf-data-post="/appointment?#{keep_query('*', schedule='all')}" class="post_link cursor-pointer dropdown-item">All</span>
<span t-attf-data-post="/appointment?#{keep_query('*', schedule='users')}"
t-attf-class="post_link cursor-pointer dropdown-item text-primary #{current_filters.get('schedule') == 'users' and 'active' or ''}">
<i class="fa fa-check me-2" t-if="current_filters.get('schedule') == 'users'"></i>Users
</span>
<span t-attf-data-post="/appointment?#{keep_query('*', schedule='resources')}"
t-attf-class="post_link cursor-pointer dropdown-item text-secondary #{current_filters.get('schedule') == 'resources' and 'active' or ''}">
<i class="fa fa-check me-2" t-if="current_filters.get('schedule') == 'resources'"></i>Resources
</span>
</div>
</div>
<a href="/appointment" t-attf-class="btn btn-danger d-none d-lg-block mb-2 #{has_filters and '' or 'd-none'}">
<i class="fa fa-times me-1"></i> Reset Filters
</a>
</div>
</xpath>
</template>

<template id="applied_filters" name="Applied Filters" inherit_id="website_appointment.website_calendar_index_topbar">
<xpath expr="//div[hasclass('d-flex', 'flex-wrap', 'align-items-center', 'justify-content-between', 'w-100')]" position="after">
<t t-if="has_filters and active_filters">
<div class="mt-4 mb-3">
<div class="d-flex flex-wrap align-items-center">
<div class="me-2 mb-2">
<span class="badge rounded-pill bg-primary p-2">
<i class="fa fa-filter me-1"></i> Filtered Results:
<t t-if="filtered_count is not None">
<strong t-esc="filtered_count"/> / <span t-esc="total_count"/> appointments
</t>
</span>
</div>
<t t-foreach="active_filters" t-as="active">
<div class="me-2 mb-2">
<span class="badge rounded-pill bg-info p-2">
<i class="fa fa-tag me-1"></i>
<span t-esc="active"/>
</span>
</div>
</t>
</div>
</div>
</t>
<t t-if="has_filters and filtered_count == 0">
<div class="alert alert-warning mt-3">
<i class="fa fa-exclamation-triangle me-2"></i>
No appointments match your selected filters. <a href="/appointment" class="alert-link">Reset filters</a> to see all available appointments.
</div>
</t>
</xpath>
</template>

<!-- Add a responsive view for mobile devices -->
<template id="mobile_filter_buttons" name="Mobile Appointment Filters" inherit_id="website_appointment.website_calendar_index_topbar">
<xpath expr="//div[hasclass('d-flex', 'flex-wrap', 'align-items-center', 'justify-content-between', 'w-100')]" position="after">
<div class="d-block d-lg-none mt-3 mb-3">
<button class="btn btn-primary w-100 mb-2" type="button" data-bs-toggle="collapse" data-bs-target="#mobileFilters"
aria-expanded="false" aria-controls="mobileFilters">
<i class="fa fa-filter me-1"></i> Filter Appointments
<t t-if="has_filters">
<span class="badge bg-light text-dark ms-1" t-esc="len([f for f in [current_filters.get('type'), current_filters.get('payment_step'), current_filters.get('schedule')] if f and f != 'all'])"></span>
</t>
</button>
<div class="collapse" id="mobileFilters">
<div class="card card-body">
<div class="row g-2">
<div class="col-12 mb-2">
<label class="fw-bold">
<i class="fa fa-video-camera me-1"></i> Type
</label>
<div class="btn-group w-100" role="group">
<a t-attf-href="/appointment?#{keep_query('*', type='online')}"
t-attf-class="btn btn-sm #{current_filters.get('type') == 'online' and 'btn-success' or 'btn-outline-success'}">
Online
</a>
<a t-attf-href="/appointment?#{keep_query('*', type='offline')}"
t-attf-class="btn btn-sm #{current_filters.get('type') == 'offline' and 'btn-danger' or 'btn-outline-danger'}">
Offline
</a>
<a t-attf-href="/appointment?#{keep_query('*', type='all')}"
t-attf-class="btn btn-sm #{not current_filters.get('type') or current_filters.get('type') == 'all' and 'btn-secondary' or 'btn-outline-secondary'}">
All
</a>
</div>
</div>
<div class="col-12 mb-2">
<label class="fw-bold">
<i class="fa fa-credit-card me-1"></i> Payment
</label>
<div class="btn-group w-100" role="group">
<a t-attf-href="/appointment?#{keep_query('*', payment_step='paid')}"
t-attf-class="btn btn-sm #{current_filters.get('payment_step') == 'paid' and 'btn-success' or 'btn-outline-success'}">
Paid
</a>
<a t-attf-href="/appointment?#{keep_query('*', payment_step='free')}"
t-attf-class="btn btn-sm #{current_filters.get('payment_step') == 'free' and 'btn-danger' or 'btn-outline-danger'}">
Free
</a>
<a t-attf-href="/appointment?#{keep_query('*', payment_step='all')}"
t-attf-class="btn btn-sm #{not current_filters.get('payment_step') or current_filters.get('payment_step') == 'all' and 'btn-secondary' or 'btn-outline-secondary'}">
All
</a>
</div>
</div>
<div class="col-12 mb-2">
<label class="fw-bold">
<i class="fa fa-calendar me-1"></i> Schedule
</label>
<div class="btn-group w-100" role="group">
<a t-attf-href="/appointment?#{keep_query('*', schedule='users')}"
t-attf-class="btn btn-sm #{current_filters.get('schedule') == 'users' and 'btn-primary' or 'btn-outline-primary'}">
Users
</a>
<a t-attf-href="/appointment?#{keep_query('*', schedule='resources')}"
t-attf-class="btn btn-sm #{current_filters.get('schedule') == 'resources' and 'btn-secondary' or 'btn-outline-secondary'}">
Resources
</a>
<a t-attf-href="/appointment?#{keep_query('*', schedule='all')}"
t-attf-class="btn btn-sm #{not current_filters.get('schedule') or current_filters.get('schedule') == 'all' and 'btn-secondary' or 'btn-outline-secondary'}">
All
</a>
</div>
</div>
<div class="col-12 mt-2">
<a href="/appointment" class="btn btn-danger btn-sm w-100">
<i class="fa fa-times me-1"></i> Reset All Filters
</a>
</div>
</div>
</div>
</div>
</div>
</xpath>
</template>
</odoo>
3 changes: 3 additions & 0 deletions awesome_dashboard/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
'web.assets_backend': [
'awesome_dashboard/static/src/**/*',
],
'awesome_dashboard.dashboard': [
'awesome_dashboard/static/src/dashboard/**/*',
]
},
'license': 'AGPL-3'
}
10 changes: 0 additions & 10 deletions awesome_dashboard/static/src/dashboard.js

This file was deleted.

8 changes: 0 additions & 8 deletions awesome_dashboard/static/src/dashboard.xml

This file was deleted.

Loading