Browse Source

Jun 12: [ADD] Initial Commit 'cleaning_management'

pull/254/merge
RisvanaCybro 11 months ago
parent
commit
7f80c22d5e
  1. 46
      cleaning_management/README.rst
  2. 23
      cleaning_management/__init__.py
  3. 73
      cleaning_management/__manifest__.py
  4. 22
      cleaning_management/controllers/__init__.py
  5. 70
      cleaning_management/controllers/cleaning_management.py
  6. 18
      cleaning_management/data/building_type_demo.xml
  7. 13
      cleaning_management/data/cleaning_management_data.xml
  8. 21
      cleaning_management/data/cleaning_shift_demo.xml
  9. 7
      cleaning_management/doc/RELEASE_NOTES.md
  10. 31
      cleaning_management/models/__init__.py
  11. 40
      cleaning_management/models/account_move.py
  12. 32
      cleaning_management/models/building_type.py
  13. 221
      cleaning_management/models/cleaning_booking.py
  14. 92
      cleaning_management/models/cleaning_inspection.py
  15. 310
      cleaning_management/models/cleaning_management_dashboard.py
  16. 41
      cleaning_management/models/cleaning_management_website.py
  17. 41
      cleaning_management/models/cleaning_shift.py
  18. 89
      cleaning_management/models/cleaning_team.py
  19. 152
      cleaning_management/models/cleaning_team_duty.py
  20. 40
      cleaning_management/models/employee_details.py
  21. 27
      cleaning_management/security/cleaning_management_groups.xml
  22. 13
      cleaning_management/security/ir.model.access.csv
  23. BIN
      cleaning_management/static/description/assets/icons/cogs.png
  24. BIN
      cleaning_management/static/description/assets/icons/consultation.png
  25. BIN
      cleaning_management/static/description/assets/icons/ecom-black.png
  26. BIN
      cleaning_management/static/description/assets/icons/education-black.png
  27. BIN
      cleaning_management/static/description/assets/icons/hotel-black.png
  28. BIN
      cleaning_management/static/description/assets/icons/license.png
  29. BIN
      cleaning_management/static/description/assets/icons/lifebuoy.png
  30. BIN
      cleaning_management/static/description/assets/icons/manufacturing-black.png
  31. BIN
      cleaning_management/static/description/assets/icons/pos-black.png
  32. BIN
      cleaning_management/static/description/assets/icons/puzzle.png
  33. BIN
      cleaning_management/static/description/assets/icons/restaurant-black.png
  34. BIN
      cleaning_management/static/description/assets/icons/service-black.png
  35. BIN
      cleaning_management/static/description/assets/icons/trading-black.png
  36. BIN
      cleaning_management/static/description/assets/icons/training.png
  37. BIN
      cleaning_management/static/description/assets/icons/update.png
  38. BIN
      cleaning_management/static/description/assets/icons/user.png
  39. BIN
      cleaning_management/static/description/assets/icons/wrench.png
  40. BIN
      cleaning_management/static/description/assets/misc/categories.png
  41. BIN
      cleaning_management/static/description/assets/misc/check-box.png
  42. BIN
      cleaning_management/static/description/assets/misc/compass.png
  43. BIN
      cleaning_management/static/description/assets/misc/corporate.png
  44. BIN
      cleaning_management/static/description/assets/misc/customer-support.png
  45. BIN
      cleaning_management/static/description/assets/misc/cybrosys-logo.png
  46. BIN
      cleaning_management/static/description/assets/misc/features.png
  47. BIN
      cleaning_management/static/description/assets/misc/logo.png
  48. BIN
      cleaning_management/static/description/assets/misc/pictures.png
  49. BIN
      cleaning_management/static/description/assets/misc/pie-chart.png
  50. BIN
      cleaning_management/static/description/assets/misc/right-arrow.png
  51. BIN
      cleaning_management/static/description/assets/misc/star.png
  52. BIN
      cleaning_management/static/description/assets/misc/support.png
  53. BIN
      cleaning_management/static/description/assets/misc/whatsapp.png
  54. BIN
      cleaning_management/static/description/assets/modules/fleet_car_workshop.jpg
  55. BIN
      cleaning_management/static/description/assets/modules/fleet_rental.png
  56. BIN
      cleaning_management/static/description/assets/modules/front_office_management.png
  57. BIN
      cleaning_management/static/description/assets/modules/insurance_management_cybro.png
  58. BIN
      cleaning_management/static/description/assets/modules/medical_lab_management.png
  59. BIN
      cleaning_management/static/description/assets/modules/salon_management.png
  60. BIN
      cleaning_management/static/description/assets/screenshots/1.png
  61. BIN
      cleaning_management/static/description/assets/screenshots/10.png
  62. BIN
      cleaning_management/static/description/assets/screenshots/11.png
  63. BIN
      cleaning_management/static/description/assets/screenshots/12.png
  64. BIN
      cleaning_management/static/description/assets/screenshots/13.png
  65. BIN
      cleaning_management/static/description/assets/screenshots/14.png
  66. BIN
      cleaning_management/static/description/assets/screenshots/15.png
  67. BIN
      cleaning_management/static/description/assets/screenshots/16.png
  68. BIN
      cleaning_management/static/description/assets/screenshots/2.png
  69. BIN
      cleaning_management/static/description/assets/screenshots/3.png
  70. BIN
      cleaning_management/static/description/assets/screenshots/4.png
  71. BIN
      cleaning_management/static/description/assets/screenshots/5.png
  72. BIN
      cleaning_management/static/description/assets/screenshots/6.png
  73. BIN
      cleaning_management/static/description/assets/screenshots/7.png
  74. BIN
      cleaning_management/static/description/assets/screenshots/8.png
  75. BIN
      cleaning_management/static/description/assets/screenshots/9.png
  76. BIN
      cleaning_management/static/description/assets/screenshots/hero.gif
  77. BIN
      cleaning_management/static/description/assets/screenshots/insp.png
  78. BIN
      cleaning_management/static/description/banner.jpg
  79. BIN
      cleaning_management/static/description/icon.png
  80. 787
      cleaning_management/static/description/index.html
  81. 178
      cleaning_management/static/src/css/cleaning_management_dashboard.css
  82. 518
      cleaning_management/static/src/js/cleaning_management_dashboard.js
  83. 117
      cleaning_management/static/src/js/cleaning_management_website.js
  84. 157
      cleaning_management/static/src/xml/cleaning_management_dashboard_template.xml
  85. 39
      cleaning_management/views/building_type_views.xml
  86. 97
      cleaning_management/views/cleaning_booking_views.xml
  87. 66
      cleaning_management/views/cleaning_inspection_views.xml
  88. 8
      cleaning_management/views/cleaning_management_dashboard_views.xml
  89. 31
      cleaning_management/views/cleaning_management_menus.xml
  90. 215
      cleaning_management/views/cleaning_management_website_template.xml
  91. 48
      cleaning_management/views/cleaning_shift_views.xml
  92. 84
      cleaning_management/views/cleaning_team_duty_views.xml
  93. 51
      cleaning_management/views/cleaning_team_views.xml
  94. 46
      cleaning_management/views/employee_details_views.xml

46
cleaning_management/README.rst

@ -0,0 +1,46 @@
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
Cleaning Management
===================
This module allows users to manage cleaning processes easily.
Configuration
=============
* Choose a user within the settings to provide access to the module.
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
General Public License, Version 3 (AGPL v3).
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Credits
-------
* Developer: (V15) Mohammed Dilshad Tk , Contact: odoo@cybrosys.com
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit `Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

23
cleaning_management/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import controllers
from . import models

73
cleaning_management/__manifest__.py

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'name': 'Cleaning Management',
'version': '15.0.1.0.0',
"category": "Industries",
'summary': """Cleaning Management with Online Booking System""",
'description': """This module facilitates the booking of cleaning processes
and effectively manages the cleaning procedures.""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "https://cybrosys.com/",
'depends': ['base', 'website', 'hr', 'account'],
'data': [
"security/cleaning_management_groups.xml",
'security/ir.model.access.csv',
'views/cleaning_team_views.xml',
'views/cleaning_team_duty_views.xml',
'views/employee_details_views.xml',
'views/cleaning_shift_views.xml',
'views/cleaning_booking_views.xml',
'views/cleaning_inspection_views.xml',
'views/cleaning_management_website_template.xml',
'views/building_type_views.xml',
'views/cleaning_management_dashboard_views.xml',
'views/cleaning_management_menus.xml',
'data/cleaning_management_data.xml',
'data/building_type_demo.xml',
'data/cleaning_shift_demo.xml',
],
'assets': {
'web.assets_frontend': [
'/cleaning_management/static/src/js/cleaning_management_website.js',
],
'web.assets_backend': [
'/cleaning_management/static/src/js/'
'cleaning_management_dashboard.js',
'/cleaning_management/static/src/css/'
'cleaning_management_dashboard.css',
'https://cdn.jsdelivr.net/npm/chart.js',
],
'web.assets_qweb': [
'/cleaning_management/static/src/xml/'
'cleaning_management_dashboard_template.xml',
],
},
'images': ['static/description/banner.jpg'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': True,
}

22
cleaning_management/controllers/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import cleaning_management

70
cleaning_management/controllers/cleaning_management.py

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import datetime
from odoo import http
from odoo.http import request
class CleaningRequest(http.Controller):
"""Create a controller function that retrieves all data from the backend,
sends it to the frontend, and handles the storage of data sent from
the frontend back to the backend."""
@http.route(['/cleaning/request/form'], type='http',
auth="user", website=True)
def request_form(self):
"""Retrieving data from the backend."""
customer_name_rec = http.request.env['res.partner'].sudo().search([])
building_type_rec = http.request.env['building.type'].sudo().search([])
cleaning_team_id = http.request.env['cleaning.team'].sudo().search([])
location_state_id = http.request.env['res.country.state'].sudo().search(
[])
return http.request.render(
"cleaning_management.cleaning_online_request", {
'customer_name_rec': customer_name_rec,
'building_type_rec': building_type_rec,
'location_state_id': location_state_id,
'cleaning_team_id': cleaning_team_id,
})
@http.route(['/cleaning/request/form/submit'], type='http',
auth="public", website=True)
def online_request_cleaning_form(self, **kw):
"""Storing data into the backend."""
bookings = request.env['cleaning.booking'].sudo().create({
'customer_name_id': kw.get('customer_name_id'),
'address': kw.get('address'),
'building_type_id': kw.get('building_type_id'),
'booking_date': kw.get('booking_date'),
'cleaning_date': str(
datetime.fromisoformat(kw.get('cleaning_date'))),
'cleaning_time': (kw.get('cleaning_time')),
'cleaning_team_id': (kw.get('cleaning_team_id')),
'location_state_id': (kw.get('location_state_id')),
'description': kw.get('description')
})
value = {
'vals': bookings,
}
return http.request.render("cleaning_management.cleaning_online_thanks",
value)

18
cleaning_management/data/building_type_demo.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!--Provide predefined values for the building type.-->
<record id="building_type_house" model="building.type">
<field name="name">House</field>
</record>
<record id="building_type_hospital" model="building.type">
<field name="name">Hospital</field>
</record>
<record id="building_type_institution" model="building.type">
<field name="name">Institution</field>
</record>
<record id="building_type_office" model="building.type">
<field name="name">Office</field>
</record>
</data>
</odoo>

13
cleaning_management/data/cleaning_management_data.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- By clicking the menu on the website,
users can access links to different pages. -->
<record id="menu_cleaning_request" model="website.menu">
<field name="name">Cleaning Online Request</field>
<field name="url">/cleaning/request/form</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence">55</field>
</record>
</data>
</odoo>

21
cleaning_management/data/cleaning_shift_demo.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!--Provide predefined values for the cleaning shift-->
<record id="morning_shift" model="cleaning.shift">
<field name="shift_type">Morning Shift</field>
<field name="shift_time_from">7.5</field>
<field name="shift_time_to">15.5</field>
</record>
<record id="evening_shift" model="cleaning.shift">
<field name="shift_type">Evening Shift</field>
<field name="shift_time_from">15.5</field>
<field name="shift_time_to">23.5</field>
</record>
<record id="night_shift" model="cleaning.shift">
<field name="shift_type">Night Shift</field>
<field name="shift_time_from">23.5</field>
<field name="shift_time_to">07.5</field>
</record>
</data>
</odoo>

7
cleaning_management/doc/RELEASE_NOTES.md

@ -0,0 +1,7 @@
## Module <cleaning_management>
#### 07.05.2024
#### Version 15.0.1.0.0
##### ADD
- Initial commit for Cleaning Management

31
cleaning_management/models/__init__.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import building_type
from . import cleaning_booking
from . import cleaning_team
from . import cleaning_team_duty
from . import cleaning_inspection
from . import cleaning_shift
from . import cleaning_management_dashboard
from . import cleaning_management_website
from . import employee_details
from . import account_move

40
cleaning_management/models/account_move.py

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models, _
class AccountMove(models.Model):
"""Inherit account_move for adding cleaning_id to get invoices"""
_inherit = "account.move"
cleaning_id = fields.Many2one("cleaning.booking",
string='Cleaning',
help="Choose Cleaning Management")
def _invoice_paid_hook(self):
"""Function for getting chatter activity for invoice"""
res = super(AccountMove, self)._invoice_paid_hook()
[rec.cleaning_id.message_post(
body=_('Invoice %s paid', rec._get_html_link()))
for rec in self if
rec.cleaning_id and rec.payment_state == 'paid']
return res

32
cleaning_management/models/building_type.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class BuildingType(models.Model):
"""Create a new model for specifying the building category
in order to facilitate cleaning services."""
_name = "building.type"
_description = "Building Type"
name = fields.Char(string='Building Type',
help="Enter building type", required=True)

221
cleaning_management/models/cleaning_booking.py

@ -0,0 +1,221 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import date
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class CleaningBooking(models.Model):
"""Create a new model for booking purposes.
The system will incorporate three buttons to indicate the
booking and cleaning status: "Confirm", "Clean" and "Cancel"."""
_name = "cleaning.booking"
_description = "Cleaning Booking"
_inherit = ['mail.thread', 'mail.activity.mixin']
_rec_name = 'customer_name_id'
customer_name_id = fields.Many2one('res.partner',
string='Name of Customer',
required=True,
help="Choose customer name")
address = fields.Char(string='Address',
required=True,
help="Enter address of customer")
building_type_id = fields.Many2one('building.type',
string='Building Type',
required=True,
help="Choose building type")
booking_date = fields.Date(default=fields.date.today(),
help="Choose the booking date",
string='Booking Date')
cleaning_team_id = fields.Many2one('cleaning.team',
string='Cleaning Team',
help="Choose cleaning team",
required=True)
cleaning_inspection_id = fields.Many2one('cleaning.inspection',
string="Cleaning Inspection",
help="Choose Cleaning Inspection")
cleaning_team_duty_id = fields.Many2one('cleaning.team.duty',
string="Cleaning Team Duty",
help="Choose Cleaning Team Duty")
cleaning_date = fields.Date(string='Cleaning Date',
required=True,
help="Choose Date for cleaning")
cleaning_time = fields.Selection([('morning', 'Morning'),
('evening', 'Evening'),
('night', 'Night')],
string='Cleaning Time',
help="Choose Time for cleaning",
required=True)
description = fields.Char(string='Description',
help="Enter Description For Booking")
duration = fields.Selection([('forever', 'Forever'),
('fixed', 'Fixed')],
default='forever', string='Duration',
help="Choose Duration For Cleaning")
end_after = fields.Integer(string='End After',
help="Choose End of cleaning management")
end_duration = fields.Selection([('months', 'Months'),
('years', 'Years')],
string="End Duration",
help="Choose End duration of booking")
cleaning_shift_id = fields.Many2one("cleaning.shift",
help="Cleaning Shift",
string="Choose Cleaning Shift")
self_closable = fields.Boolean(string='Is Self Closable',
help="When checked reservations will"
"be automatically closed.")
automatic_closing = fields.Integer(string='Automatic Closing',
help="Automatic Closing Chooser")
location_state_id = fields.Many2one('res.country.state',
string="State",
required=True,
help="Choose State For Cleaning")
place = fields.Char(string="Place", help="Enter Place of Customer")
state = fields.Selection([('draft', 'Draft'),
('booked', 'Booked'),
('cleaned', 'Cleaned'),
('cancelled', 'Cancelled')],
default='draft', string='Status',
help="Stages For Cleaning Processes",
tracking=True)
confirm_stage = fields.Boolean(string="Is Confirm", default=True,
help="When checked,the status" ""
"will be 'Confirm'.")
clean_stage = fields.Boolean(string="Clean", default=True,
help="When checked,the status will be 'Clean'")
cancel_stage = fields.Boolean(string="Cancel", default=True,
help="When checked,the status"
"will be 'Cancel'.")
unit_price = fields.Float(string="Unit Price", default=0.0, required=True,
help="Uit Price for an hour")
total_hour_of_working = fields.Char(string="Total working hours",
help="Total working hours done by Team")
invoice_count = fields.Integer(compute="_compute_invoice_count",
string='Invoice Count')
@api.onchange('cleaning_time')
def _onchange_cleaning_time(self):
"""The team leader will appear at the scheduled cleaning time."""
domain = []
if self.cleaning_time:
res = self.env['cleaning.team.duty'].search(
[('cleaning_date', '=', self.cleaning_date),
('cleaning_time', '=', self.cleaning_time),
('state', '!=', ['cancelled', 'cleaned'])])
if res:
team_ids_in_use = [duty.team_id.id for duty in res]
domain = [('duty_type', '=', self.cleaning_time),
('id', 'not in', team_ids_in_use)]
else:
domain.append(('duty_type', '=', self.cleaning_time))
return {
'domain': {'cleaning_team_id': domain}
}
@api.onchange('cleaning_team_id')
def _onchange_cleaning_team_id(self):
"""The team leader's time will appear when changing the leader."""
self.cleaning_time = self.cleaning_team_id.duty_type
def action_booking(self):
"""The button action for "Confirm" typically involves
finalizing and saving the booking details entered
by the user."""
duty_ids_to_add = []
for rec in self:
cleaning_team_duty = rec.cleaning_team_duty_id.create({
"team_id": rec.cleaning_team_id.id,
"team_leader_id": rec.cleaning_team_id.team_leader_id.employee_name_id.id,
"members_ids": rec.cleaning_team_id.members_ids.ids,
"location_state_id": rec.location_state_id.id,
"place": rec.place,
"customer_id": rec.customer_name_id.id,
"cleaning_date": rec.cleaning_date,
"cleaning_time": rec.cleaning_time,
"cleaning_id": rec.id
})
rec.write(
{'state': 'booked', 'confirm_stage': False,
'clean_stage': False,
'cancel_stage': False,
'cleaning_team_duty_id': cleaning_team_duty.id})
duty_ids_to_add.append((4, cleaning_team_duty.id))
def action_cancel(self):
"""The button action for "Cancel" typically involves canceling
and removing a booking that was previously confirmed or reserved."""
for rec in self:
rec.cleaning_team_duty_id.write({'state': 'cancelled'})
rec.write(
{'state': 'cancelled', 'confirm_stage': False,
'cancel_stage': True,
'clean_stage': True})
def action_create_invoice(self):
"""Function for create an invoice for cleaning processes"""
for rec in self:
if rec.unit_price > 0.0:
invoice = rec.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': rec.customer_name_id.id,
'invoice_date': date.today(),
'payment_reference': rec.cleaning_date,
'cleaning_id': rec.id,
'invoice_line_ids': [(0, 0, {
'name': f"{rec.cleaning_team_id.name} ({rec.cleaning_inspection_id.inspection_date_and_time})",
'price_unit': float(rec.unit_price) * float(
rec.total_hour_of_working),
})],
})
return {
'name': 'account.move.form',
'res_model': 'account.move',
'type': 'ir.actions.act_window',
'view_mode': 'form',
'view_type': 'form',
'view_id': rec.env.ref("account.view_move_form").id,
'res_id': invoice.id,
'target': 'current'
}
else:
raise ValidationError(_("Specify the Unit Price for a hour"))
def action_view_invoice(self):
"""Function for open Invoice Smart Button"""
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Invoice',
'view_mode': 'tree,form',
'res_model': 'account.move',
'domain': [('cleaning_id', '=', self.id)],
'context': "{'create': False}"
}
def _compute_invoice_count(self):
"""Function for count number of Invoices"""
for record in self:
record.invoice_count = self.env['account.move'].search_count(
[('cleaning_id', '=', self.id)])

92
cleaning_management/models/cleaning_inspection.py

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class CleaningInspection(models.Model):
"""Create a new model for detailing cleaning inspection specifics.
The system will incorporate two buttons to indicate the
cleaning status: "Clean" and "Dirty"."""
_name = "cleaning.inspection"
_description = "Cleaning Inspection"
_inherit = ['mail.thread', 'mail.activity.mixin']
_rec_name = 'cleaning_team_id'
inspector_name_id = fields.Many2one('res.users',
string='Inspector Name',
required=True,
help="Choose Inspector Name")
cleaning_id = fields.Many2one('cleaning.booking',
help="Cleaning Management",
string="Select Cleaning Management")
inspection_date_and_time = fields.Datetime(
string='Inspection Date and Time',
required=True,
help="Choose Inspection date and time")
cleaning_team_id = fields.Many2one('cleaning.team',
string='Cleaning Team',
required=True,
help="Choose cleaning team")
cleaning_team_duty_id = fields.Many2one('cleaning.team.duty',
string='Cleaning Team Duty',
required=True,
help="Choose cleaning team Duty")
team_leader_id = fields.Many2one('hr.employee',
string='Team Leader',
help="Choose team leader")
date_from = fields.Char(string='Cleaning Start Time',
help="Choose Cleaning Start Time", readonly=True)
date_to = fields.Char(string='Cleaning End Date',
help="Choose Cleaning End Time", readonly=True)
state = fields.Selection([('draft', 'Draft'),
('cleaned', 'Cleaned'),
('dirty', 'Dirty')
], string='Status',
default='draft',
help="Inspection stages for cleaning")
dirty_clean = fields.Boolean('Is Dirty or Clean',
help="When the button is disabled,"
" it signifies a Dirty state, "
"while an enabled button signifies"
" a Clean state.")
def action_clean(self):
"""The button action for "Clean" involves executing a process
to perform cleaning tasks"""
self.write({'state': 'cleaned', 'dirty_clean': True})
self.cleaning_id.write({'state': 'cleaned', 'clean_stage': True,
'cleaning_inspection_id': self.id})
self.cleaning_team_duty_id.write(
{'state': 'cleaned'})
if not self.cleaning_id.cancel_stage:
self.cleaning_id.cancel_stage = True
def action_dirt(self):
"""The button action for "Dirty" typically
involves marking task as dirty. """
self.write({'state': 'dirty', 'dirty_clean': True})
self.cleaning_team_duty_id.write(
{'state': 'dirty'})
def action_reclean(self):
"""Function for Reclean processes"""
self.write({'state': 'draft'})

310
cleaning_management/models/cleaning_management_dashboard.py

@ -0,0 +1,310 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
from odoo.tools import date_utils
class CleaningManagementDashBoard(models.Model):
"""Creating new model to extract counts for bookings, cleanings,
and dirty states, intended for visualization on a dashboard."""
_name = "cleaning.management.dashboard"
_description = "Cleaning Management Dashboard"
def get_dashboard_count(self):
"""Getting count of bookings,teams,cleaning and dirty count"""
bookings = self.env['cleaning.booking'].search_count([
('state', '=', 'booked')])
teams = self.env['cleaning.team'].search_count([])
cleaning_counts = self.env['cleaning.inspection'].search_count([
('state', '=', 'cleaned')])
dirty_counts = self.env['cleaning.inspection'].search_count([
('state', '=', 'dirty')])
values = {
'bookings': bookings,
'teams': teams,
'cleaned': cleaning_counts,
'dirty': dirty_counts
}
return values
def get_the_booking_year(self):
"""Get year wise booking"""
cleaning = self.env['cleaning.booking']
total_booking_stage_year = cleaning.search([]).filtered(
lambda l: l.booking_date.year == fields.date.today().year).mapped(
'state')
year_stage = [*set(total_booking_stage_year)]
order_of_stages = ['draft', 'booked', 'cleaned', 'cancelled']
# Sort the stages based on the predefined order
sorted_stages = sorted(year_stage,
key=lambda x: order_of_stages.index(x))
year_booking_stages = [stage.capitalize() for stage in sorted_stages]
total_booking_stage_draft_year = cleaning.search([
('state', '=', 'draft')]).filtered(
lambda l: l.booking_date.year == fields.date.today().year)
total_booking_stage_booked_year = cleaning.search([
('state', '=', 'booked')]).filtered(
lambda l: l.booking_date.year == fields.date.today().year)
total_booking_stage_cleaned_year = cleaning.search([
('state', '=', 'cleaned')]).filtered(
lambda l: l.booking_date.year == fields.date.today().year)
total_booking_stage_canceled_year = cleaning.search([
('state', '=', 'cancelled')]).filtered(
lambda l: l.booking_date.year == fields.date.today().year)
return {
'total_booking_stage_year': year_booking_stages,
'total_booking_stage_draft_year': len(
total_booking_stage_draft_year),
'total_booking_stage_booked_year': len(
total_booking_stage_booked_year),
'total_booking_stage_cleaned_year': len(
total_booking_stage_cleaned_year),
'total_booking_stage_canceled_year': len(
total_booking_stage_canceled_year)
}
def get_the_booking_month(self):
"""Get month wise booking"""
cleaning = self.env['cleaning.booking']
total_booking_stage_month = cleaning.search([]).filtered(
lambda l: l.booking_date.month == fields.date.today().month).mapped(
'state')
month_stage = [*set(total_booking_stage_month)]
order_of_stages = ['draft', 'booked', 'cleaned', 'cancelled']
# Sort the stages based on the predefined order
sorted_stages = sorted(month_stage,
key=lambda x: order_of_stages.index(x))
monthly_booking_stages = [stage.capitalize() for stage in sorted_stages]
total_booking_stage_draft_month = cleaning.search(
[('state', '=', 'draft')]).filtered(
lambda l: l.booking_date.month == fields.date.today().month)
total_booking_stage_booked_month = cleaning.search([
('state', '=', 'booked')]).filtered(
lambda l: l.booking_date.month == fields.date.today().month)
total_booking_stage_cleaned_month = cleaning.search([
('state', '=', 'cleaned')]).filtered(
lambda l: l.booking_date.month == fields.date.today().month)
total_booking_stage_canceled_month = cleaning.search([
('state', '=', 'cancelled')]).filtered(
lambda l: l.booking_date.month == fields.date.today().month)
return {
'total_booking_stage_month': monthly_booking_stages,
'total_booking_stage_draft_month': len(
total_booking_stage_draft_month),
'total_booking_stage_booked_month': len(
total_booking_stage_booked_month),
'total_booking_stage_cleaned_month': len(
total_booking_stage_cleaned_month),
'total_booking_stage_canceled_month': len(
total_booking_stage_canceled_month),
}
def get_the_booking_week(self):
"""Get week wise booking"""
cleaning = self.env['cleaning.booking']
total_booking_stage_week = cleaning.search([]).filtered(
lambda l: l.booking_date.isocalendar()[1] ==
fields.date.today().isocalendar()[1]).mapped('state')
week_stage = [*set(total_booking_stage_week)]
order_of_stages = ['draft', 'booked', 'cleaned', 'cancelled']
# Sort the stages based on the predefined order
sorted_stages = sorted(week_stage,
key=lambda x: order_of_stages.index(x))
weekly_booking_stages = [stage.capitalize() for stage in sorted_stages]
total_booking_stage_draft_week = cleaning.search([
('state', '=', 'draft')]).filtered(
lambda l: l.booking_date.isocalendar()[1] ==
fields.date.today().isocalendar()[1])
total_booking_stage_booked_week = cleaning.search([
('state', '=', 'booked')]).filtered(
lambda l: l.booking_date.isocalendar()[1] ==
fields.date.today().isocalendar()[1])
total_booking_stage_cleaned_week = cleaning.search([
('state', '=', 'cleaned')]).filtered(
lambda l: l.booking_date.isocalendar()[1] ==
fields.date.today().isocalendar()[1])
total_booking_stage_canceled_week = cleaning.search([
('state', '=', 'cancelled')]).filtered(
lambda l: l.booking_date.isocalendar()[1] ==
fields.date.today().isocalendar()[1])
return {
'total_booking_stage_week': weekly_booking_stages,
'total_booking_stage_draft_week': len(
total_booking_stage_draft_week),
'total_booking_stage_booked_week': len(
total_booking_stage_booked_week),
'total_booking_stage_cleaned_week': len(
total_booking_stage_cleaned_week),
'total_booking_stage_canceled_week': len(
total_booking_stage_canceled_week),
}
def get_the_booking_quarter(self):
"""Get quarter wise booking"""
cleaning = self.env['cleaning.booking']
start_date, end_date = date_utils.get_quarter(fields.date.today())
total_booking_stage_quarter = cleaning.search([]).filtered(
lambda l: start_date <= l.booking_date <= end_date).mapped('state')
quarter_stage = [*set(total_booking_stage_quarter)]
order_of_stages = ['draft', 'booked', 'cleaned', 'cancelled']
# Sort the stages based on the predefined order
sorted_stages = sorted(quarter_stage,
key=lambda x: order_of_stages.index(x))
quarterly_booking_stages = [stage.capitalize() for stage in sorted_stages]
total_booking_stage_draft_quarter = cleaning.search([
('state', '=', 'draft')]).filtered(
lambda l: start_date <= l.booking_date <= end_date)
total_booking_stage_booked_quarter = cleaning.search([
('state', '=', 'booked')]).filtered(
lambda l: start_date <= l.booking_date <= end_date)
total_booking_stage_cleaned_quarter = cleaning.search([
('state', '=', 'cleaned')]).filtered(
lambda l: start_date <= l.booking_date <= end_date)
total_booking_stage_canceled_quarter = cleaning.search([
('state', '=', 'cancelled')]).filtered(
lambda l: start_date <= l.booking_date <= end_date)
return {
'total_booking_stage_quarter': quarterly_booking_stages,
'total_booking_stage_draft_quarter': len(
total_booking_stage_draft_quarter),
'total_booking_stage_booked_quarter': len(
total_booking_stage_booked_quarter),
'total_booking_stage_cleaned_quarter': len(
total_booking_stage_cleaned_quarter),
'total_booking_stage_canceled_quarter': len(
total_booking_stage_canceled_quarter),
}
def quality_year(self):
"""Get year wise quality of cleaning"""
quality = self.env['cleaning.inspection']
quality_year = quality.search([]).filtered(
lambda
l: l.inspection_date_and_time.year == fields.date.today().year).mapped(
'state')
year_stage = [*set(quality_year)]
order_of_stages = ['cleaned', 'dirty']
# Sort the stages based on the predefined order
sorted_stages = sorted(year_stage,
key=lambda x: order_of_stages.index(x))
yearly_quality_stages = [stage.capitalize() for stage in sorted_stages]
cleaned_quality_year = quality.search([
('state', '=', 'cleaned')]).filtered(
lambda
l: l.inspection_date_and_time.year == fields.date.today().year)
dirty_quality_year = quality.search([('state', '=', 'dirty')]).filtered(
lambda
l: l.inspection_date_and_time.year == fields.date.today().year)
return {
'quality_year': yearly_quality_stages,
'cleaned_quality_year': len(cleaned_quality_year),
'dirty_quality_year': len(dirty_quality_year)
}
def quality_month(self):
"""Get month wise quality of cleaning"""
quality = self.env['cleaning.inspection'].search([])
quality_month = quality.search([]).filtered(
lambda
l: l.inspection_date_and_time.month == fields.date.today().month).mapped(
'state')
month_stage = [*set(quality_month)]
order_of_stages = ['cleaned', 'dirty']
# Sort the stages based on the predefined order
sorted_stages = sorted(month_stage,
key=lambda x: order_of_stages.index(x))
monthly_quality_stages = [stage.capitalize() for stage in sorted_stages]
cleaned_quality_month = quality.search([
('state', '=', 'cleaned')]).filtered(
lambda
l: l.inspection_date_and_time.month == fields.date.today().month)
dirty_quality_month = quality.search(
[('state', '=', 'dirty')]).filtered(
lambda
l: l.inspection_date_and_time.month == fields.date.today().month)
return {
'quality_month': monthly_quality_stages,
'cleaned_quality_month': len(cleaned_quality_month),
'dirty_quality_month': len(dirty_quality_month)
}
def quality_week(self):
"""Get week wise quality of cleaning"""
quality = self.env['cleaning.inspection']
quality_week = quality.search([]).filtered(
lambda l: l.inspection_date_and_time.isocalendar()[1] ==
fields.date.today().isocalendar()[1]).mapped('state')
week_stage = [*set(quality_week)]
order_of_stages = ['cleaned', 'dirty']
# Sort the stages based on the predefined order
sorted_stages = sorted(week_stage,
key=lambda x: order_of_stages.index(x))
capitalized_stages = [stage.capitalize() for stage in sorted_stages]
cleaned_quality_week = quality.search([
('state', '=', 'cleaned')]).filtered(
lambda l: l.inspection_date_and_time.isocalendar()[1] ==
fields.date.today().isocalendar()[1])
dirty_quality_week = quality.search([
('state', '=', 'dirty')]).filtered(
lambda l: l.inspection_date_and_time.isocalendar()[1] ==
fields.date.today().isocalendar()[1])
return {
'quality_week': capitalized_stages,
'cleaned_quality_week': len(cleaned_quality_week),
'dirty_quality_week': len(dirty_quality_week)
}
def quality_quarter(self):
"""Get quarter wise quality of cleaning"""
start_date, end_date = date_utils.get_quarter(fields.datetime.today())
quality = self.env['cleaning.inspection']
quality_quarter = quality.search([]).filtered(
lambda
l: start_date <= l.inspection_date_and_time <= end_date).mapped(
'state')
quarter_stage = [*set(quality_quarter)]
order_of_stages = ['cleaned', 'dirty']
# Sort the stages based on the predefined order
sorted_stages = sorted(quarter_stage,
key=lambda x: order_of_stages.index(x))
capitalized_stages = [stage.capitalize() for stage in sorted_stages]
cleaned_quality_quarter = quality.search([
('state', '=', 'cleaned')]).filtered(
lambda l: start_date <= l.inspection_date_and_time <= end_date)
dirty_quality_quarter = quality.search([
('state', '=', 'dirty')]).filtered(
lambda l: start_date <= l.inspection_date_and_time <= end_date)
return {
'quality_quarter': capitalized_stages,
'cleaned_quality_quarter': len(cleaned_quality_quarter),
'dirty_quality_quarter': len(dirty_quality_quarter)
}
def cleaning_count(self):
"""Creating a function to retrieve the counts of bookings,
cleanings, and dirty states."""
return {
'bookings': [rec for rec in
self.env['cleaning.booking'].search([])],
'inspections': [rec for rec in
self.env['cleaning.inspection'].search([])]
}

41
cleaning_management/models/cleaning_management_website.py

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import models
class CleaningManagementWebsite(models.Model):
"""Creating new model to search teams for website """
_name = "cleaning.management.website"
_description = "Cleaning Management Website"
def get_team_details(self):
"""Search for teams from the cleaning_team model and
pass all data to the frontend."""
teams = self.env["cleaning.team"].search([])
return {'team_list': [
{'id': team.id, 'name': team.name, 'duty': team.duty_type}
for team in teams],
'duty': [{'id': duty.id, 'team_id': duty.team_id.id,
'team_name': duty.team_id.name,
'duty': duty.cleaning_time,
'date': duty.cleaning_date}
for duty in self.env["cleaning.team.duty"].search([])]}

41
cleaning_management/models/cleaning_shift.py

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class CleaningShift(models.Model):
"""Creating a new model to acquire cleaning shifts for all employees,
it includes type, start time, and end time details."""
_name = "cleaning.shift"
_description = "Cleaning Shift"
_inherit = ['mail.thread', 'mail.activity.mixin']
_rec_name = 'shift_type'
shift_type = fields.Char(string='Shift Type',
help="Shift type for an employee", required=True,
readonly=True)
shift_time_from = fields.Float(string='Shift Time From',
help="Enter the start time for shift",
required=True)
shift_time_to = fields.Float(string='Shift Time To',
help="Enter the End time for shift",
required=True)

89
cleaning_management/models/cleaning_team.py

@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import api, fields, models
class CleaningTeam(models.Model):
"""Creating a new model for specifying cleaning teams and
their associated leaders, members and other details."""
_name = "cleaning.team"
_description = "Cleaning Team"
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string='Team Name', required=True,
help="Choose Team Name")
_sql_constraints = [
('name_unique', 'unique(name)', 'The team already exists')]
team_leader_id = fields.Many2one('employee.details',
string='Leader',
help="Choose Leader For Team",
required=True)
members_ids = fields.Many2many('employee.details',
string='Members',
help="Choose Members For Team",
required=True)
duty_type = fields.Selection([('morning', 'Morning'),
('night', 'Night'),
('evening', 'Evening')], string='Duty Type',
required=True,
help="Select Duty Type Of The Team")
cleaning_date = fields.Date(string='Cleaning Date and Time',
help="Choose Cleaning Date For Team")
cleaning_time = fields.Selection([('morning', 'Morning'),
('evening', 'Evening'),
('night', 'Night')],
string='Cleaning Time',
help="Choose Cleaning Time For Team")
cleaning_duty_id = fields.Many2one("cleaning.team.duty",
string="Cleaning Duty",
help="Choose Cleaning Duty")
cleaning_duty_ids = fields.Many2many("cleaning.team.duty",
string="Cleaning Team Duty",
readonly=False,
help="Choose Cleaning Duty")
inspection_id = fields.Many2one('cleaning.inspection',
string="Cleaning Inspection",
help="Choose Cleaning Inspection")
@api.onchange('team_leader_id', 'duty_type')
def _onchange_team_leader_or_duty_type(self):
"""Function for getting Employees with respect to Duty Type"""
if self.team_leader_id:
self.write({'members_ids': [(6, 0, [self.team_leader_id.id])]})
if self.duty_type in ["morning", "evening", "night"]:
teams_with_same_shift = self.env['cleaning.team'].search([
('duty_type', '=', self.duty_type),
])
excluded_leaders = [team.team_leader_id.id for team in
teams_with_same_shift]
excluded_members = [member.id for team in teams_with_same_shift for
member in team.members_ids]
shift = self.env['employee.details'].search([
('time_shift_id', '=', f"{self.duty_type.capitalize()} Shift"),
('id', 'not in', excluded_leaders)])
val = [rec.id for rec in shift if
rec.id != self.team_leader_id.id and rec.id not in excluded_members]
return {'domain': {'team_leader_id': [('id', 'in', val)],
'members_ids': [('id', 'in', val)]}}
else:
return {'domain': {'team_leader_id': [], 'members_ids': []}}

152
cleaning_management/models/cleaning_team_duty.py

@ -0,0 +1,152 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
from pytz import timezone
class CleaningTeamDuty(models.Model):
"""Creating new model to retrieve comprehensive details regarding
the duties assigned to each team."""
_name = "cleaning.team.duty"
_description = "Cleaning Team Duty"
_inherit = ['mail.thread', 'mail.activity.mixin']
_rec_name = 'team_id'
team_leader_id = fields.Many2one('hr.employee',
readonly=True,
string="Team Leader",
help="Choose Leader of Corresponding Team")
team_id = fields.Many2one('cleaning.team', string='Team Name',
readonly=True, help="Choose Cleaning team")
inspection_id = fields.Many2one('cleaning.inspection',
string="Cleaning Inspection",
help="Choose Cleaning Inspection")
cleaning_id = fields.Many2one('cleaning.booking',
string="Cleaning Booking",
help="Choose Cleaning Booking")
members_ids = fields.Many2many('hr.employee', string='Members',
readonly=True,
help="Choose Members Of Corresponding Team")
location_state_id = fields.Many2one('res.country.state',
string="State", readonly=True,
help="Location for Team To Work")
place = fields.Char(string="Place", readonly=True,
help="Enter Place For The Work")
customer_id = fields.Many2one('res.partner', string='Customer',
readonly=True, help="Choose Customer Name")
cleaning_time = fields.Selection([('morning', 'Morning'),
('evening', 'Evening'),
('night', 'Night')],
string='Cleaning Time',
readonly=True,
help="Cleaning Time, Booked By Customer")
cleaning_date = fields.Date(string='Cleaning Date',
readonly=True,
help="Cleaning Date That Booked By Customer")
inspection_boolean = fields.Boolean(string="Is Inspection", default=True,
readonly=True,
help="Got 'INSPECTION' button in"
" form view")
start_time = fields.Char(string="Start Time",
help="Real time to complete all cleaning process")
start_cleaning = fields.Boolean(string="Is Started")
end_time = fields.Char(string="End Time",
help="Real time to complete all cleaning process")
end_cleaning = fields.Boolean(string="Is Ended",
help="Real time to end all cleaning process")
state = fields.Selection([('draft', 'Draft'),
('dirty', 'Dirty'),
('cleaned', 'Cleaned'),
('cancelled', 'Cancelled')],
default='draft', string='Status',
help="Stages For Cleaning Team Duty",
tracking=True)
inspection_count = fields.Integer(compute="_compute_inspection_count",
string='Inspection Count')
def action_start(self):
"""Function for start cleaning processes"""
user_tz = self.env.user.tz or 'UTC'
start_time_utc = fields.Datetime.now()
start_time_user_tz = fields.Datetime.to_string(
fields.Datetime.context_timestamp(self, start_time_utc).astimezone(
timezone(user_tz)))
self.write({
'start_time': start_time_user_tz,
'start_cleaning': True
})
def action_finish(self):
"""Function for finish cleaning processes"""
if self.start_cleaning:
user_tz = self.env.user.tz or 'UTC'
end_time_utc = fields.Datetime.now()
end_time_user_tz = fields.Datetime.to_string(
fields.Datetime.context_timestamp(self,
end_time_utc).astimezone(
timezone(user_tz)))
self.write({
'end_time': end_time_user_tz,
'inspection_boolean': False,
'end_cleaning': True
})
start_time_utc = fields.Datetime.from_string(self.start_time)
end_time_utc = fields.Datetime.from_string(end_time_user_tz)
total_hours = (end_time_utc - start_time_utc).total_seconds() / 3600
self.cleaning_id.total_hour_of_working = total_hours
def action_inspection(self):
"""Clicking the "Inspection" button will direct the user
to the inspection page."""
self.inspection_boolean = True
return {
'name': 'cleaning_team_id',
'res_model': 'cleaning.inspection',
'type': 'ir.actions.act_window',
'view_mode': 'form',
'context': {'default_cleaning_team_id': self.team_id.id,
'default_inspector_name_id': self.env.user.id,
'default_cleaning_id': self.cleaning_id.id,
'default_date_from': self.start_time,
'default_date_to': self.end_time,
'default_cleaning_team_duty_id': self.id
}
}
def action_view_inspection(self):
"""Function for Open Inspection Smart Button"""
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Inspection',
'view_mode': 'tree,form',
'res_model': 'cleaning.inspection',
'domain': [('cleaning_team_duty_id', '=', self.id)],
'context': "{'create': False}"
}
def _compute_inspection_count(self):
"""Function for getting total count of inspections"""
for record in self:
record.inspection_count = self.env['cleaning.inspection'].search_count(
[('cleaning_team_duty_id', '=', self.id)])

40
cleaning_management/models/employee_details.py

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Mohammed Dilshad TK (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class EmployeeDetails(models.Model):
"""Creating new model for inputting employee information
such as names and shifts."""
_name = "employee.details"
_description = "Employee Details"
_inherit = ['mail.thread', 'mail.activity.mixin']
_rec_name = 'employee_name_id'
employee_name_id = fields.Many2one('hr.employee',
string='Employee Name',
help="Choose Employee Name",
required=True)
time_shift_id = fields.Many2one('cleaning.shift',
string='Time Shift',
help="Choose Time Shift for Employee",
required=True)

27
cleaning_management/security/cleaning_management_groups.xml

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data noupdate="1">
<!-- Set a category selection field for users-->
<record id="cleaning_management_groups" model="ir.module.category">
<field name="name">Cleaning Management</field>
<field name="description">Cleaning management</field>
<field name="sequence">5</field>
</record>
<!-- Action for manager-->
<record id="cleaning_management_group_manager" model="res.groups">
<field name="name">Cleaning Manager</field>
<field name="category_id"
ref="cleaning_management.cleaning_management_groups"/>
<field name="users"
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
<!-- Action for user-->
<record id="cleaning_management_group_user" model="res.groups">
<field name="name">User</field>
<field name="category_id"
ref="cleaning_management.cleaning_management_groups"/>
<field name="implied_ids"
eval="[(4, ref('cleaning_management_group_manager'))]"/>
</record>
</data>
</odoo>

13
cleaning_management/security/ir.model.access.csv

@ -0,0 +1,13 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_cleaning_booking,access.cleaning.booking,model_cleaning_booking,base.group_user,1,1,1,1
access_cleaning_team_manager,access.cleaning.team,model_cleaning_team,cleaning_management.cleaning_management_group_manager,1,1,1,1
access_cleaning_team_user,access.cleaning.team,model_cleaning_team,cleaning_management.cleaning_management_group_user,1,0,0,0
access_cleaning_team_duty,access.cleaning.team.duty,model_cleaning_team_duty,base.group_user,1,1,1,1
access_cleaning_inspection_manager,access.cleaning.inspection,model_cleaning_inspection,cleaning_management.cleaning_management_group_manager,1,1,1,1
access_cleaning_inspection_user,access.cleaning.inspection,model_cleaning_inspection,cleaning_management.cleaning_management_group_user,1,1,1,0
access_building_type_manager,access.building.type,model_building_type,base.group_user,1,1,1,1
access_cleaning_shift_user,access.cleaning.shift,model_cleaning_shift,base.group_user,1,1,1,1
access_employee_details_manager,access.employee.details,model_employee_details,cleaning_management.cleaning_management_group_manager,1,1,1,1
access_employee_details_user,access.employee.details,model_employee_details,cleaning_management.cleaning_management_group_user,1,0,0,0
access_cleaning_management_dashboard,access_cleaning_management_dashboard,cleaning_management.model_cleaning_management_dashboard,base.group_user,1,0,0,0
access_cleaning_management_website,access_cleaning_management_website,cleaning_management.model_cleaning_management_website,base.group_user,1,0,0,0
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 access_cleaning_booking access.cleaning.booking model_cleaning_booking base.group_user 1 1 1 1
3 access_cleaning_team_manager access.cleaning.team model_cleaning_team cleaning_management.cleaning_management_group_manager 1 1 1 1
4 access_cleaning_team_user access.cleaning.team model_cleaning_team cleaning_management.cleaning_management_group_user 1 0 0 0
5 access_cleaning_team_duty access.cleaning.team.duty model_cleaning_team_duty base.group_user 1 1 1 1
6 access_cleaning_inspection_manager access.cleaning.inspection model_cleaning_inspection cleaning_management.cleaning_management_group_manager 1 1 1 1
7 access_cleaning_inspection_user access.cleaning.inspection model_cleaning_inspection cleaning_management.cleaning_management_group_user 1 1 1 0
8 access_building_type_manager access.building.type model_building_type base.group_user 1 1 1 1
9 access_cleaning_shift_user access.cleaning.shift model_cleaning_shift base.group_user 1 1 1 1
10 access_employee_details_manager access.employee.details model_employee_details cleaning_management.cleaning_management_group_manager 1 1 1 1
11 access_employee_details_user access.employee.details model_employee_details cleaning_management.cleaning_management_group_user 1 0 0 0
12 access_cleaning_management_dashboard access_cleaning_management_dashboard cleaning_management.model_cleaning_management_dashboard base.group_user 1 0 0 0
13 access_cleaning_management_website access_cleaning_management_website cleaning_management.model_cleaning_management_website base.group_user 1 0 0 0

BIN
cleaning_management/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
cleaning_management/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
cleaning_management/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
cleaning_management/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
cleaning_management/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
cleaning_management/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
cleaning_management/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
cleaning_management/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
cleaning_management/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
cleaning_management/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
cleaning_management/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
cleaning_management/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
cleaning_management/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
cleaning_management/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
cleaning_management/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
cleaning_management/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
cleaning_management/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
cleaning_management/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
cleaning_management/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
cleaning_management/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
cleaning_management/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
cleaning_management/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
cleaning_management/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
cleaning_management/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
cleaning_management/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
cleaning_management/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
cleaning_management/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
cleaning_management/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
cleaning_management/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
cleaning_management/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
cleaning_management/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
cleaning_management/static/description/assets/modules/fleet_car_workshop.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
cleaning_management/static/description/assets/modules/fleet_rental.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
cleaning_management/static/description/assets/modules/front_office_management.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
cleaning_management/static/description/assets/modules/insurance_management_cybro.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
cleaning_management/static/description/assets/modules/medical_lab_management.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
cleaning_management/static/description/assets/modules/salon_management.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
cleaning_management/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
cleaning_management/static/description/assets/screenshots/10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
cleaning_management/static/description/assets/screenshots/11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
cleaning_management/static/description/assets/screenshots/12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
cleaning_management/static/description/assets/screenshots/13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
cleaning_management/static/description/assets/screenshots/14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
cleaning_management/static/description/assets/screenshots/15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
cleaning_management/static/description/assets/screenshots/16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
cleaning_management/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

BIN
cleaning_management/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
cleaning_management/static/description/assets/screenshots/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
cleaning_management/static/description/assets/screenshots/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
cleaning_management/static/description/assets/screenshots/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
cleaning_management/static/description/assets/screenshots/7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
cleaning_management/static/description/assets/screenshots/8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
cleaning_management/static/description/assets/screenshots/9.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
cleaning_management/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
cleaning_management/static/description/assets/screenshots/insp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
cleaning_management/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
cleaning_management/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

787
cleaning_management/static/description/index.html

@ -0,0 +1,787 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42"
style="width: 42px; height: 42px;"/>
<div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Cleaning Management</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">
This Module Assists with Booking for Cleaning and Manages
Cleaning Processes.
</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif" class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;"/>
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Overview
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
<p>This module facilitates the booking of cleaning services through the
website and efficiently manages all cleaning processes within its
functionalities.</p>
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Features
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Community and Enterprise Support.</span>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Online Booking Facility.</span>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Different access levels for Users and Manager.</span>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Activity dashboard is available.</span>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Various shifts are available for Employees.</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
App access for User or Manager.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Choose "Cleaning Manager" or "User" in the settings.
</p>
<img src="assets/screenshots/1.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Main Apps menu.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Once access is granted, you will find the Cleaning Management
app in the Main Apps menu.
</p>
<img src="assets/screenshots/2.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Website view of Cleaning Management.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
When you click on '<b>Cleaning Online Request</b>,' a form will
appear, allowing you to book Cleaning processes by providing
your details.
</p>
<img src="assets/screenshots/3.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Employee Details.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
To access the Employee Details in the Cleaning Management
module, navigate to 'Cleaning Management,' and then select
'Employee Details' where shifts for all employees can be
specified.
</p>
<img src="assets/screenshots/4.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Cleaning Team.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Cleaning Management -> Cleaning Team. Where you can specify the
Duty Type, Leader, and Members of a particular team.
</p>
<img src="assets/screenshots/5.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Booking.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Cleaning Management -> Booking. Where all created bookings are
listed, and you can also create a new booking here.
</p>
<img src="assets/screenshots/6.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Cleaning Team with corresponding Cleaning Time.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
You can get the Team when they are available on that day.
</p>
<img src="assets/screenshots/7.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Confirm Booking.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
After verifying the cleaning process and confirming its
completion, the stage changes to "BOOKED." At this stage, you
will be presented with "CANCEL" button.
</p>
<img src="assets/screenshots/8.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Cleaning Team Duty.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Can track cleaning process time by clicking 'Start' button.
</p>
<img src="assets/screenshots/9.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
INSPECTION.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
To inspect the cleaning process, click on the "INSPECTION"
button. This will allow you to verify whether the cleaning has
been performed successfully or not.
</p>
<img src="assets/screenshots/10.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Cleaning Team Duty.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
You can inspect the process by clicking the "CLEAN" or "DIRT"
button.
</p>
<img src="assets/screenshots/11.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
When click on 'CLEAN' Button stage changed to 'CLEANED'
</p>
<img src="assets/screenshots/insp.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Invoice</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
You can create invoice by clicking 'CREATE INVOICE' Button after defining 'Unit Price'.
</p>
<img src="assets/screenshots/13.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Invoice form of Cleaning Management.
</p>
<img src="assets/screenshots/14.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Invoice Smart Button.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Invoice Smart Button in Cleaning Booking Form.
</p>
<img src="assets/screenshots/15.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h1 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Dashboard View.</h1>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Access the dashboard to view the total number of Bookings,
Cleaning Team data, and Clean and Dirty counts. The dashboard
will also include two bar graphs representing Bookings and
Quality of work. Graphs can be filtered by This Month, This
Quarter, This Year, and This Week for comprehensive analysis.
</p>
<img src="assets/screenshots/16.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="./assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/fleet_rental/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/fleet_rental.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/salon_management/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/salon_management.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/fleet_car_workshop/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/fleet_car_workshop.jpg">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/medical_lab_management/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/medical_lab_management.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/front_office_management/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/front_office_management.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/insurance_management_cybro/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/insurance_management_cybro.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i
class="fa fa-chevron-left"
style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1"
data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i
class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!--END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48"
style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help?
Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52"
style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>

178
cleaning_management/static/src/css/cleaning_management_dashboard.css

@ -0,0 +1,178 @@
.o_action_manager {
overflow: auto !important;
}
.cleaning_dashboards {
padding-top: 10px;
background-color: #f8faff !important;
}
.cleaning-card h4 {
font-size: 1.1rem;
}
/* Widget One
---------------------------*/
.stat-content {
display: inline-block;
width: 66%;
}
.stat-icon {
display: inline-block;
}
.stat-widget-one .stat-icon {
vertical-align: top;
margin: auto;
width: 100%;
color: #01c490;
}
.stat-widget-one .stat-icon i {
font-size: 30px;
font-weight: 900;
display: inline-block;
color: #01c490;
}
.stat-widget-one .stat-text {
font-size: 14px;
color: #868e96;
font-weight: bold;
}
.stat-widget-one .stat-digit {
font-size: 24px;
color: #02448b;
}
.stat-count {
font-size: 20px;
text-align: center;
color: #00438b;
}
.stat-title {
font-size: 17px;
text-align: center;
color: #00438b;
}
/*=====================Dashboard===========================*/
.cleaning_dashboards {
background-color: #f8faff !important;
padding: 0px !important;
}
.container-fluid.o_hr_dashboard {
padding: 0px !important;
}
.cleaning-card {
padding: 0px;
margin-bottom: 1.5rem;
border-radius: 0px;
box-shadow: none;
background: none;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
}
.cleaning-card:hover {
transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important;
}
.cleaning {
margin-top: 3%;
margin-bottom: 2%;
}
.cleaning .stat-icon {
border-radius: 15px 0 0 15px;
width: 30%;
height: 100px;
text-align: center;
padding-top: 10%;
background: #314384ff;
color: #fff;
}
.cleaning .cleaning-card {
border-radius: 15px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
will-change: transform, box-shadow;
box-shadow: 0 10px 40px 0 rgba(62, 57, 107, 0.07),
0 2px 9px 0 rgba(62, 57, 107, 0.06);
}
.stat-widget-one .stat-text {
font-size: 14px;
color: #314384ff;
margin: 2rem 0rem 1rem 0rem;
text-align: center;
}
.stat-widget-one .stat-digit {
font-size: 20px;
font-weight: bolder;
padding: 1px 10px 2px 0;
color: #8061a9;
text-shadow: 0px 0px 20px #000000;
text-align: center;
}
.stat-widget-one .stat-icon i {
/*border-radius: 15px 0 0 15px;*/
font-size: 25px;
font-weight: 900;
display: inline-block;
color: #fff;
}
.stat-widget-one {
border-radius: 15px;
background-color: white;
text-align: inherit !important;
}
.stat-widget-one {
width: 100%;
}
.cleaning_count .stat-icon {
background: #964ec2 !important;
}
.dirty_count .stat-icon {
background: #813de6 !important;
}
.cleaning_teams .stat-icon {
background: #6f23a9 !important;
}
.cleaning_count .stat-widget-one .stat-text {
color: #964ec2;
}
.dirty_count .stat-widget-one .stat-text {
color: #813de6;
}
.cleaning_teams .stat-widget-one .stat-text {
color: #6f23a9;
}
.cleaning-card-body {
display: flex;
justify-content: space-between;
align-items: center;
}
.counting{
width: 414px;
margin-left: 762px;
margin-top: -291px;
}

518
cleaning_management/static/src/js/cleaning_management_dashboard.js

@ -0,0 +1,518 @@
odoo.define('cleaning_management.dashboard_action', function(require) {
"use strict";
var AbstractAction = require('web.AbstractAction');
var core = require('web.core');
var QWeb = core.qweb;
var rpc = require('web.rpc');
var CustomDashBoard = AbstractAction.extend({
/**
* Obtain yearly, monthly, quarterly, and weekly bookings,
as well as clean and dirt reports.
*/
template: 'CleaningDashBoard',
events: {
'click .cleaning_cooking': 'get_bookings',
'click .cleaning_teams': 'get_teams',
'click .cleaning_count': 'get_cleaning',
'click .dirty_count': 'get_dirty',
'change #filtration': function(e) {
e.stopPropagation();
// Return elements where event occurred
var target = this.$(e.target);
if (target.val() == "this_year") {
this.onclick_this_year(target.val());
} else if (target.val() == "this_quarter") {
this.onclick_this_quarter(target.val());
} else if (target.val() == "this_month") {
this.onclick_this_month(target.val());
} else if (target.val() == "this_week") {
this.onclick_this_week(target.val());
}
},
},
init: function(parent, context) {
this._super(parent, context);
this.dashboards_templates = ['CleaningDashboardProject',
'DashboardProject', 'CleaningProject'
];
this.today_sale = [];
},
// Begin the function with the monthly records of bookings and inspections.
start: function() {
var self = this;
this.set("title", 'Dashboard');
return this._super().then(function() {
self.render_dashboards();
self.render_graphs();
self.$("#activity_week").hide();
self.$("#activity_year").hide();
self.$("#activity_quarter").hide();
self.$("#activity_month").show();
self.$("#quality_week").hide();
self.$("#quality_month").show();
self.$("#quality_quarter").hide();
self.$("#quality_year").hide();
rpc.query({
model: "cleaning.management.dashboard",
method: "cleaning_count",
args: [0],
})
.then(function(result) {
if ((result['inspections'].length > 0) &&
(result['bookings'].length > 0)) {
self.$(".report").show();
self.$(".bookings").show();
self.$(".quality").show();
} else if (result['bookings'].length > 0) {
self.$(".report").show();
self.$(".bookings").show();
self.$(".quality").hide();
} else if (result['inspections'].length > 0) {
self.$(".report").show();
self.$(".bookings").hide();
self.$(".quality").show();
} else {
self.$(".report").hide();
self.$(".bookings").hide();
self.$(".quality").hide();
}
})
});
},
//Generate a dashboard displaying the count of bookings, dirty instances, completed cleanings, and the cleaning team.
render_dashboards: function() {
var self = this;
_.each(this.dashboards_templates, function(template) {
self.$('.o_pj_dashboard').append(QWeb.render(template, {
widget: self
}));
});
rpc.query({
model: "cleaning.management.dashboard",
method: "get_dashboard_count",
args: [0],
})
.then(function(result) {
self.$("#bookings_count").append("<span class='stat-digit'>" + result.bookings +
"</span>");
self.$("#teams_count").append("<span class='stat-digit'>" + result.teams +
"</span>");
self.$("#cleaning_count").append("<span class='stat-digit'>" + result.cleaned +
"</span>");
self.$("#dirty_count").append("<span class='stat-digit'>" + result.dirty +
"</span>");
});
},
on_reverse_breadcrumb: function() {
var self = this;
self.$('.o_pj_dashboard').empty();
self.render_dashboards();
},
// Get booking records
get_bookings: function() {
this.do_action({
name: ("Bookings"),
type: 'ir.actions.act_window',
res_model: 'cleaning.booking',
view_mode: 'tree,form,calendar',
views: [
[false, 'list'],
[false, 'form']
],
domain: [
['state', '=', 'booked']
],
target: 'current',
})
},
// Get team count records
get_teams: function() {
this.do_action({
name: ("Teams"),
type: 'ir.actions.act_window',
res_model: 'cleaning.team',
view_mode: 'tree,form,calendar',
views: [
[false, 'list'],
[false, 'form']
],
target: 'current',
})
},
// Get cleaning count
get_cleaning: function() {
this.do_action({
name: ("Count of Cleaning"),
type: 'ir.actions.act_window',
res_model: 'cleaning.inspection',
view_mode: 'tree,form,calendar',
views: [
[false, 'list'],
[false, 'form']
],
domain: [
['state', '=', 'cleaned']
],
target: 'current',
})
},
// Get dirty count
get_dirty: function() {
this.do_action({
name: ("Count of dirty"),
type: 'ir.actions.act_window',
res_model: 'cleaning.inspection',
view_mode: 'tree,form,calendar',
views: [
[false, 'list'],
[false, 'form']
],
domain: [
['state', '=', 'dirty']
],
target: 'current',
})
},
render_graphs: function() {
var self = this;
self.render_the_graph();
},
//Generate a graph representing the yearly, monthly, weekly, and quarterly records.
render_the_graph: function() {
var self = this
var ctx = self.$(".total_bookings_year");
rpc.query({
model: "cleaning.management.dashboard",
method: "get_the_booking_year",
args: [0],
}).then(function(result) {
self.total_booking_stage =
result['total_booking_stage_year'],
self.total_booking_stage_draft_year =
result['total_booking_stage_draft_year'],
self.total_booking_stage_booked_year =
result['total_booking_stage_booked_year'],
self.total_booking_stage_cleaned_year =
result['total_booking_stage_cleaned_year'],
self.total_booking_stage_canceled_year =
result['total_booking_stage_canceled_year']
const ctx = self.$('#activity_year')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['total_booking_stage_year'],
datasets: [{
label: 'Stage',
data: [
result['total_booking_stage_draft_year'],
result['total_booking_stage_booked_year'],
result['total_booking_stage_cleaned_year'],
result['total_booking_stage_canceled_year']
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var self = this
var ctx = self.$(".total_bookings_week");
rpc.query({
model: "cleaning.management.dashboard",
method: "get_the_booking_week",
args: [0],
}).then(function(result) {
self.total_booking_stage =
result['total_booking_stage_week'],
self.total_booking_stage_draft =
result['total_booking_stage_draft_week'],
self.total_booking_stage_booked =
result['total_booking_stage_booked_week'],
self.total_booking_stage_cleaned =
result['total_booking_stage_cleaned_week'],
self.total_booking_stage_canceled =
result['total_booking_stage_canceled_week']
const ctx = self.$('#activity_week')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['total_booking_stage_week'],
datasets: [{
label: 'Stage',
data: [
result['total_booking_stage_draft_week'],
result['total_booking_stage_booked_week'],
result['total_booking_stage_cleaned_week'],
result['total_booking_stage_canceled_week']
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var self = this
var ctx = self.$(".total_bookings_month");
rpc.query({
model: "cleaning.management.dashboard",
method: "get_the_booking_month",
args: [0],
}).then(function(result) {
const dataPoints = [
result['total_booking_stage_draft_month'],
result['total_booking_stage_booked_month'],
result['total_booking_stage_cleaned_month'],
result['total_booking_stage_canceled_month']
].filter(value => value !== null && value !== '' &&
value !== 0);
const ctx = self.$('#activity_month')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['total_booking_stage_month'],
datasets: [{
label: 'Stage',
data: dataPoints,
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var self = this
var ctx = self.$(".total_bookings_quarter");
rpc.query({
model: "cleaning.management.dashboard",
method: "get_the_booking_quarter",
args: [0],
}).then(function(result) {
self.total_booking_stage =
result['total_booking_stage_quarter'],
self.total_booking_stage_draft =
result['total_booking_stage_draft_quarter'],
self.total_booking_stage_booked =
result['total_booking_stage_booked_quarter'],
self.total_booking_stage_cleaned =
result['total_booking_stage_cleaned_quarter'],
self.total_booking_stage_canceled =
result['total_booking_stage_canceled_quarter']
const ctx = self.$('#activity_quarter')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['total_booking_stage_quarter'],
datasets: [{
label: 'Stage',
data: [
result['total_booking_stage_draft_quarter'],
result['total_booking_stage_booked_quarter'],
result['total_booking_stage_cleaned_quarter'],
result['total_booking_stage_canceled_quarter']
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var self = this
var ctx = self.$(".total_quality_year");
rpc.query({
model: "cleaning.management.dashboard",
method: "quality_year",
args: [0],
}).then(function(result) {
self.quality_year = result['quality_year'],
self.cleaned_quality_year = result['cleaned_quality_year'],
self.dirty_quality_year = result['dirty_quality_year']
const ctx = self.$('#quality_year')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['quality_year'],
datasets: [{
label: 'Stage',
data: [result['cleaned_quality_year'],
result['dirty_quality_year']
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var self = this
var ctx = self.$(".total_quality_week");
rpc.query({
model: "cleaning.management.dashboard",
method: "quality_week",
args: [0],
}).then(function(result) {
self.quality_week = result['quality_week'],
self.cleaned_quality_week = result['cleaned_quality_week'],
self.dirty_quality_week = result['dirty_quality_week']
const ctx = self.$('#quality_week')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['quality_week'],
datasets: [{
label: 'Stage',
data: [result['cleaned_quality_week'],
result['dirty_quality_week']
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var self = this
var ctx = self.$(".total_quality_month");
rpc.query({
model: "cleaning.management.dashboard",
method: "quality_month",
args: [0],
}).then(function(result) {
self.quality_month = result['quality_month'],
self.cleaned_quality_month = result['cleaned_quality_month'],
self.dirty_quality_month = result['dirty_quality_month']
const ctx = self.$('#quality_month')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['quality_month'],
datasets: [{
label: 'Stage',
data: [result['cleaned_quality_month'],
result['dirty_quality_month']
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
var self = this
var ctx = self.$(".total_quality_quarter");
rpc.query({
model: "cleaning.management.dashboard",
method: "quality_quarter",
args: [0],
}).then(function(result) {
self.quality_quarter = result['quality_quarter'],
self.cleaned_quality_year = result['cleaned_quality_quarter'],
self.dirty_quality_year = result['dirty_quality_quarter']
const ctx = self.$('#quality_quarter')
new Chart(ctx, {
type: 'bar',
data: {
labels: result['quality_quarter'],
datasets: [{
label: 'Stage',
data: [result['cleaned_quality_quarter'],
result['dirty_quality_quarter']
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
},
// Show yearly result
onclick_this_year: function(ev) {
self.$("#activity_week").hide();
self.$("#activity_month").hide();
self.$("#activity_quarter").hide();
self.$("#activity_year").show();
self.$("#quality_week").hide();
self.$("#quality_month").hide();
self.$("#quality_quarter").hide();
self.$("#quality_year").show();
},
// Show monthly result
onclick_this_month: function(ev) {
self.$("#activity_week").hide();
self.$("#activity_year").hide();
self.$("#activity_quarter").hide();
self.$("#activity_month").show();
self.$("#quality_week").hide();
self.$("#quality_month").show();
self.$("#quality_quarter").hide();
self.$("#quality_year").hide();
},
// Show weekly result
onclick_this_week: function(ev) {
self.$("#activity_year").hide();
self.$("#activity_month").hide();
self.$("#activity_quarter").hide();
self.$("#activity_week").show();
self.$("#quality_week").show();
self.$("#quality_month").hide();
self.$("#quality_quarter").hide();
self.$("#quality_year").hide();
},
// Show quarterly result
onclick_this_quarter: function(ev) {
self.$("#activity_week").hide();
self.$("#activity_month").hide();
self.$("#activity_year").hide();
self.$("#activity_quarter").show();
self.$("#quality_week").hide();
self.$("#quality_month").hide();
self.$("#quality_quarter").show();
self.$("#quality_year").hide();
},
})
core.action_registry.add('cleaning_dashboard_tags', CustomDashBoard);
return CustomDashBoard;
})

117
cleaning_management/static/src/js/cleaning_management_website.js

@ -0,0 +1,117 @@
odoo.define('cleaning_management.website_cleaning_booking', function(require) {
"use strict";
var publicWidget = require('web.public.widget');
var rpc = require('web.rpc');
publicWidget.registry.portalDetails = publicWidget.Widget.extend({
/**
* Retrieve all the data from the table.
*/
selector: '.form',
events: {
'change select[name="cleaning_time"]': '_onChangeTime',
'change input[name="cleaning_date"]': '_onChangeDate',
},
//Function to start a website.
start: function() {
this._super.apply(this, arguments);
},
//Function to retrieve the team corresponding to the cleaning time.
_onChangeTime: function() {
if (!this.$el.find('#cleaning_date').val()) {
const open_deactivate_modal = true;
const modalHTML = `
<div class="modal ${open_deactivate_modal ? 'show d-block' : ''}" id="popup_error_message" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button"
class="btn-close"
data-dismiss="modal"><i class="fa fa-window-close"/></button>
</div>
<form class="oe_login_form modal-body" role="form">
Please Choose a Cleaning Date.
</form>
</div>
</div>
</div>
`;
$("body").append(modalHTML);
$("body").find("#popup_error_message").find(".btn-close").on("click", function() {
$("body").find("#popup_error_message").remove();
});
} else {
this.$el.find('#cleaning_team_id').empty();
var self = this;
rpc.query({
model: 'cleaning.management.website',
method: 'get_team_details',
args: [0],
})
.then(function(result) {
result.team_list.forEach(element => {
var change_time = self.$el.find('#cleaning_time').val();
var change_date = self.$el.find('#cleaning_date').val();
if (change_time == element.duty) {
var domain = [
['cleaning_date', '=', change_date],
['cleaning_time', '=', change_time],
['state', '=', 'draft'],
];
rpc.query({
model: 'cleaning.team.duty',
method: 'search_read',
args: [domain, ['team_id']],
})
.then(function(res) {
if (res.length > 0) {
var team_array = [];
res.forEach(e => {
var domain_for_duty = [
['cleaning_duty_ids', 'not in', e.id],
['id', 'not in', e.team_id[0]],
];
rpc.query({
model: 'cleaning.team',
method: 'search_read',
args: [domain_for_duty, ['id', 'name']],
}).then(function(res) {
res.forEach(team => {
if (!team_array.includes(team.id)) {
team_array.push(team.id);
var option = $('<option>').val(team.id).text(team.name);
self.$el.find('#cleaning_team_id').append(option);
}
});
})
})
} else {
var change_time = self.$el.find('#cleaning_time').val();
var domain_for_time = [
['duty_type', '=', change_time],
];
rpc.query({
model: 'cleaning.team',
method: 'search_read',
args: [domain_for_time, ['id', 'name']],
}).then(function(res) {
res.forEach(team => {
var option = $('<option>').val(team.id).text(team.name);
self.$el.find('#cleaning_team_id').append(option);
})
})
}
});
}
})
});
}
},
_onChangeDate: function() {
this.$el.find('#cleaning_team_id').empty();
if (this.$el.find('#cleaning_time').val() != 'null') {
this.$el.find('#cleaning_time').val("");
}
},
});
});

157
cleaning_management/static/src/xml/cleaning_management_dashboard_template.xml

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8" ?>
<template id="cleaning_dashboard">
<!-- Template for cleaning dashboard-->
<t t-name="CleaningDashBoard">
<div class="cleaning_dashboards" style="margin-top: 20px;">
<div class="container-fluid o_pj_dashboard">
</div>
</div>
</t>
<!-- This template is for adding buttons to the cleaning dashboard
to display visible bookings, cleaning teams, cleaning counts,
and dirty counts.-->
<t t-name="CleaningDashboardProject">
<div class="row main-section">
<div class="col-sm-6 col-md-3-12 col-md-6 col-lg-3 cleaning_cooking
cleaning cleaning_orders">
<div class="cleaning-card">
<div class="cleaning-card-body">
<div class="stat-widget-one">
<div class="stat-icon">
<i class="fa fa-calendar"/>
</div>
<div class="stat-content">
<div class="stat-text">Bookings</div>
<div class="stat-digit" id="bookings_count"/>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-md-3-12 col-md-6 col-lg-3 salon_spa_orders
cleaning cleaning_teams">
<div class="cleaning-card">
<div class="cleaning-card-body">
<div class="stat-widget-one">
<div class="stat-icon">
<i class="fa fa-users"/>
</div>
<div class="stat-content">
<div class="stat-text">Cleaning Teams</div>
<div class="stat-digit" id="teams_count"/>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-md-3-12 col-md-6 col-lg-3 salon_spa_sales
cleaning cleaning_count">
<div class="cleaning-card">
<div class="cleaning-card-body">
<div class="stat-widget-one">
<div class="stat-icon">
<i class="fa fa-check"/>
</div>
<div class="stat-content">
<div class="stat-text">Cleaning Counts</div>
<div class="stat-digit" id="cleaning_count"/>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-md-3-12 col-md-6 col-lg-3 salon_spa_clients
cleaning dirty_count">
<div class="cleaning-card">
<div class="cleaning-card-body">
<div class="stat-widget-one">
<div class="stat-icon">
<i class="fa fa-times "/>
</div>
<div class="stat-content">
<div class="stat-text">Dirty Counts</div>
<div class="stat-digit" id="dirty_count"/>
</div>
</div>
</div>
</div>
</div>
</div>
</t>
<!-- This template is for creating a filtering option on a dashboard
with options for monthly, quarterly, yearly, and weekly filtering.-->
<t t-name="DashboardProject">
<section class="dashboard_main_section" id="main_section_login">
<div style="height:50px">
</div>
<div class="report">
<div class="col-sm-12 mb-4">
<div class="row">
<div class="col-12 col-sm-12 col-md-8">
<h2 class="section-header">Cleaning Reports</h2>
</div>
<div class="col-12 col-sm-12 col-md-4">
<form class="form-group">
<select id="filtration" class="form-control">
<option id="this_year" value="this_year">
This Year
</option>
<option id="this_quarter"
value="this_quarter">This Quarter
</option>
<option id="this_month" value="this_month"
selected="">This Month
</option>
<option id="this_week" value="this_week">
This Week
</option>
</select>
</form>
</div>
</div>
<hr/>
</div>
</div>
</section>
</t>
<!-- This template is for displaying a graph that shows the visible
bookings and the quality of work on a dashboard.-->
<t t-name="CleaningProject">
<div class="col-sm-12 mb-4">
<div class="row">
<div class="col-12 col-sm-12 col-md-8">
<div class="bookings" style="width:500px;">
<h2 class="cleaning_bookings">Bookings</h2>
<hr/>
<div class="graph_canvas">
<canvas class="total_bookings_year" width="200"
height="120" id="activity_year"/>
<canvas class="total_bookings_week" width="200"
height="120" id="activity_week"/>
<canvas class="total_bookings_month" width="200"
height="120" id="activity_month"/>
<canvas class="total_bookings_quarter" width="200"
height="120" id="activity_quarter"/>
</div>
</div>
</div>
<div class="col-12 col-sm-12 col-md-4">
<div class="quality" style="width:500px;">
<h2 class="qty_header">Quality of work</h2>
<hr/>
<div class="graph_canvas">
<canvas class="total_quality_year" width="200"
height="120" id="quality_year"/>
<canvas class="total_quality_week" width="200"
height="120" id="quality_week"/>
<canvas class="total_quality_month" width="200"
height="120" id="quality_month"/>
<canvas class="total_quality_quarter" width="200"
height="120" id="quality_quarter"/>
</div>
</div>
</div>
</div>
</div>
</t>
</template>

39
cleaning_management/views/building_type_views.xml

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Allows users to view the building type as a tree and
provides a form for inputting building information.-->
<record id="building_type_action" model="ir.actions.act_window">
<field name="name">Building Type</field>
<field name="res_model">building.type</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a New Building Type
</p>
</field>
</record>
<!--Building type form view-->
<record id="building_type_view_form" model="ir.ui.view">
<field name="name">building.type.view.form</field>
<field name="model">building.type</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>
<!--Building type tree view-->
<record id="building_type_view_tree" model="ir.ui.view">
<field name="name">building.type.view.tree</field>
<field name="model">building.type</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
</tree>
</field>
</record>
</odoo>

97
cleaning_management/views/cleaning_booking_views.xml

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--Allows users to view the cleaning management as a tree and
provides a form for inputting cleaning management-->
<record id="cleaning_booking_action" model="ir.actions.act_window">
<field name="name">Cleaning Booking</field>
<field name="res_model">cleaning.booking</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a New Booking
</p>
</field>
</record>
<!--Cleaning management form view-->
<record id="cleaning_booking_view_form" model="ir.ui.view">
<field name="name">cleaning.booking.view.form</field>
<field name="model">cleaning.booking</field>
<field name="arch" type="xml">
<form duplicate="0">
<header>
<button name="action_booking" string="Confirm"
class="oe_highlight" type="object"
attrs="{'invisible':
[('confirm_stage', '=', False)]}"/>
<button name="action_cancel" string="Cancel"
class="oe_highlight" type="object"
attrs="{'invisible':
[('cancel_stage', '=', True)]}"/>
<button name="action_create_invoice" type="object"
string="Create Invoice"
attrs="{'invisible': ['|', ('state', '!=', 'cleaned'),('invoice_count', '>', 0)]}"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,booked,cleaned"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button type="object" name="action_view_invoice"
class="oe_stat_button"
icon="fa-pencil-square-o"
attrs="{'invisible':['|', ('invoice_count', '=', 0), ('state', 'in', ('draft','booked','cancelled'))]}">
<field name="invoice_count" widget="statinfo"
string="Invoice"/>
</button>
</div>
<group>
<group>
<field name="customer_name_id"/>
<field name="address"/>
<field name="building_type_id"/>
<field name="booking_date"/>
<field name="location_state_id"/>
<field name="place"/>
<field name="confirm_stage" invisible="1"/>
<field name="clean_stage" invisible="1"/>
<field name="cancel_stage" invisible="1"/>
</group>
<group position="right">
<field name="cleaning_date"/>
<field name="cleaning_time"/>
<field name="cleaning_team_id"/>
<field name="description"/>
<field name="unit_price"/>
<field name="total_hour_of_working" invisible="1"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
<field name="activity_ids" widget="mail_activity"/>
</div>
</form>
</field>
</record>
<!--Cleaning management tree view-->
<record id="cleaning_booking_view_tree" model="ir.ui.view">
<field name="name">cleaning.booking.view.tree</field>
<field name="model">cleaning.booking</field>
<field name="arch" type="xml">
<tree>
<field name="customer_name_id"/>
<field name="address"/>
<field name="building_type_id"/>
<field name="booking_date"/>
<field name="cleaning_team_id"/>
<field name="cleaning_date"/>
<field name="cleaning_time"/>
<field name="state" widget="badge"
decoration-success="state == 'cleaned'"
decoration-info="state == 'booked'"
decoration-danger="state == 'cancelled'"
optional="show"/>
</tree>
</field>
</record>
</odoo>

66
cleaning_management/views/cleaning_inspection_views.xml

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--Allows users to view the cleaning inspection as a tree and
provides a form for inputting cleaning inspection-->
<record id="cleaning_inspection_action" model="ir.actions.act_window">
<field name="name">Cleaning Inspection</field>
<field name="res_model">cleaning.inspection</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a New Cleaning Inspection
</p>
</field>
</record>
<!--View cleaning inspection form-->
<record id="cleaning_inspection_view_form" model="ir.ui.view">
<field name="name">cleaning.inspection.view.form</field>
<field name="model">cleaning.inspection</field>
<field name="arch" type="xml">
<form>
<header>
<button name="action_clean" type="object" string="Clean"
class="oe_highlight" attrs="{'invisible':
['|',('state', '=', 'cleaned'),('state', '=', 'dirty')]}"/>
<button name="action_dirt" type="object" string="Dirt"
class="oe_highlight"
attrs="{'invisible': ['|',('state', '=', 'cleaned'),
('state', '=', 'dirty')]}"/>
<button name="action_reclean" type="object" string="ReClean"
class="oe_highlight"
attrs="{'invisible': ['|',('state', '=', 'draft'),('state', '=', 'cleaned')]}"/>
<field name="state" widget="statusbar"
statusbar_visisble="draft,cleaned,dirty"/>
</header>
<sheet>
<group>
<field name="inspector_name_id"/>
<field name="inspection_date_and_time"/>
<field name="cleaning_team_id"/>
<field name="date_from"/>
<field name="date_to"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
<field name="activity_ids" widget="mail_activity"/>
</div>
</form>
</field>
</record>
<!--Cleaning inspection tree view-->
<record id="cleaning_inspection_view_tree" model="ir.ui.view">
<field name="name">cleaning.inspection.view.tree</field>
<field name="model">cleaning.inspection</field>
<field name="arch" type="xml">
<tree>
<field name="inspector_name_id"/>
<field name="inspection_date_and_time"/>
<field name="cleaning_team_id"/>
<field name="date_from"/>
<field name="date_to"/>
</tree>
</field>
</record>
</odoo>

8
cleaning_management/views/cleaning_management_dashboard_views.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Provide client action for dashboard menu-->
<record id="cleaning_management_dashboard_action" model="ir.actions.client">
<field name="name">Dashboard</field>
<field name="tag">cleaning_dashboard_tags</field>
</record>
</odoo>

31
cleaning_management/views/cleaning_management_menus.xml

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--Create menus for cleaning management-->
<menuitem id="cleaning_management_menu_root" name="Cleaning Management"
groups="cleaning_management.cleaning_management_group_manager,cleaning_management.cleaning_management_group_user"
web_icon="cleaning_management,static/description/icon.png">
<menuitem id="cleaning_management_menu_dashboard_datas" name="Dashboard"
action="cleaning_management_dashboard_action" sequence="0"/>
<menuitem id="cleaning_management_main_menu" name="Cleaning Management">
<menuitem id="cleaning_management_menu" name="Booking"
action="cleaning_booking_action" sequence="10"/>
<menuitem id="cleaning_team_duty_menu" name="Cleaning Team Duty"
action="cleaning_team_duty_action"
sequence="20"/>
<menuitem id="cleaning_inspection_menu" name="Inspection"
action="cleaning_inspection_action"
sequence="30"/>
</menuitem>
<menuitem id="cleaning_management_menu_configuration" name="Configuration">
<menuitem id="cleaning_shift_menu" name="Timeshift"
action="cleaning_shift_action" sequence="10"/>
<menuitem id="cleaning_management_menu_building_type" name="Building Type"
action="building_type_action" sequence="20"/>
<menuitem id="employee_details_menu" name="Employee Details"
action="employee_details_action"
sequence="30"/>
<menuitem id="cleaning_team_menu" name="Cleaning Team"
action="cleaning_team_action" sequence="40"/>
</menuitem>
</menuitem>
</odoo>

215
cleaning_management/views/cleaning_management_website_template.xml

@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!--Website view for creating an order-->
<template id="cleaning_online_request" name="Cleaning Online Request Form">
<t t-call="website.layout">
<div id="wrap" class="website">
<div class="container">
<div style="height:20px"/>
<div>
<h1 id="heading" align="center">Cleaning Management</h1>
</div>
<div style="height:50px"/>
<form role="form" action="/cleaning/request/form/submit"
method="POST">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="form">
<div class="form-group">
<label for="customer_name_id"
class="control-label">
Customer Name :
</label>
<div class="col-sm">
<select name="customer_name_id" required="1"
class="form-control link-style"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;">
<t t-foreach="customer_name_rec"
t-as="customer_name">
<option t-esc="customer_name.name"
t-att-value="customer_name.id"/>
</t>
</select>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="address" class="control-label">
Address :
</label>
<div class="col-sm">
<input type="Char" name="address"
t-att-value="address"
id="cleaning_address"
class="form-control"
required="1"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;"/>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="building_type_id"
class="control-label">
Building Type :
</label>
<div class="col-sm">
<select name="building_type_id" required="1"
class="form-control link-style"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;">
<option/>
<t t-foreach="building_type_rec"
t-as="building_type">
<option t-esc="building_type.name"
t-att-value="building_type.id"/>
</t>
</select>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="booking_date" class="control-label">
Booking Date :
</label>
<div class="col-sm">
<input type="Date" name="booking_date"
t-att-value="booking_date"
id="cleaning_booking_date"
class="form-control"
required="required"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;"/>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="cleaning_date"
class="control-label">
Cleaning Date :
</label>
<div class="col-sm">
<input type="Date" name="cleaning_date"
t-att-value="cleaning_date"
id="cleaning_date"
class="form-control"
required="1"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;"/>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="cleaning_time"
class="control-label">
Cleaning Time :
</label>
<div class="col-sm">
<select name="cleaning_time"
t-att-value="cleaning_time"
class="form-control link-style"
id="cleaning_time" required="1"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;">
<option value="null"> </option>
<option value="morning">Morning</option>
<option value="evening">Evening</option>
<option value="night">Night</option>
</select>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="cleaning_team_id"
class="control-label">
Cleaning Team :
</label>
<div class="col-sm">
<select name="cleaning_team_id"
class="form-control link-style"
id="cleaning_team_id" required="1"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;">
<option/>
<t t-foreach="cleaning_team_id"
t-as="team">
<option t-esc="team.name"
t-att-value="team.id"/>
</t>
</select>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="location_state_id"
class="control-label">Location :
</label>
<div class="col-sm">
<select name="location_state_id"
required="1"
class="form-control link-style"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;">
<option/>
<t t-foreach="location_state_id"
t-as="location">
<option t-esc="location.name"
t-att-value="location.id"/>
</t>
</select>
</div>
</div>
<div style="height:22px"/>
<div class="form-group">
<label for="description" class="control-label">
Description :
</label>
<div class="col-sm">
<input type="Char" name="description"
t-att-value="description"
id="cleaning_description"
class="form-control"
required="required"
style="width:81%;margin-left:20%;
margin-top:-3%;padding-bottom: 1%;"/>
</div>
</div>
<div style="height:22px"/>
<div class="form-group col-12 s_website_form_submit"
data-name="Submit Button">
<div style="width: 150px;"
class="s_website_form_label"/>
<button type="submit" class="btn btn-primary"
style="margin-left: 86%;width: 15%;">
Submit
</button>
</div>
<div style="height:10px"/>
</div>
</form>
</div>
</div>
</t>
</template>
<!--Receive a thankyou message upon submitting the form.-->
<template id="cleaning_online_thanks" name="Cleaning Online Request Form">
<t t-call="website.layout">
<div id="wrap" class="website">
<div style="height:100px"/>
<div class="container" style="border: 6px solid #454a45;
width: 655px;">
<div style="height:30px"/>
<h1 style="padding-left: 194px;">Thank You..!!</h1>
<div style="height:30px"/>
<p style="margin-left: 172px;background-color: #c0d79c;
width: fit-content;
font-family: ui-serif;font-size: 26px;;">
Your record has been saved
</p>
<div style="height:20px"/>
</div>
</div>
</t>
</template>
</odoo>

48
cleaning_management/views/cleaning_shift_views.xml

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Allows users to view the cleaning shift as tree and
provides a form for inputting cleaning shift-->
<record id="cleaning_shift_action" model="ir.actions.act_window">
<field name="name">Cleaning Shift</field>
<field name="res_model">cleaning.shift</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a New Cleaning Shift
</p>
</field>
</record>
<!--Cleaning shift view form-->
<record id="cleaning_shift_view_form" model="ir.ui.view">
<field name="name">>cleaning.shift.view.form</field>
<field name="model">cleaning.shift</field>
<field name="arch" type="xml">
<form create="0">
<sheet>
<group>
<field name="shift_type"/>
<field name="shift_time_from" widget="float_time"/>
<field name="shift_time_to" widget="float_time"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
<field name="activity_ids" widget="mail_activity"/>
</div>
</form>
</field>
</record>
<!--Cleaning shift tree view-->
<record id="cleaning_shift_view_tree" model="ir.ui.view">
<field name="name">cleaning.shift.view.tree</field>
<field name="model">cleaning.shift</field>
<field name="arch" type="xml">
<tree create="0">
<field name="shift_type"/>
<field name="shift_time_from" widget="float_time"/>
<field name="shift_time_to" widget="float_time"/>
</tree>
</field>
</record>
</odoo>

84
cleaning_management/views/cleaning_team_duty_views.xml

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--Allows users to view the cleaning team duty as a tree and
provides a form for inputting cleaning team duty-->
<record id="cleaning_team_duty_action" model="ir.actions.act_window">
<field name="name">Cleaning Team Duty</field>
<field name="res_model">cleaning.team.duty</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a New Cleaning Team Duty
</p>
</field>
</record>
<!--Cleaning team duty form view-->
<record id="cleaning_team_duty_view_form" model="ir.ui.view">
<field name="name">cleaning.team.duty.view.form</field>
<field name="model">cleaning.team.duty</field>
<field name="arch" type="xml">
<form create="0">
<header>
<button name="action_start" type="object" string="Start"
class="btn-success" attrs="{'invisible':
['|',('start_cleaning', '=', True),('state', '=', 'cancelled')]}"/>
<button name="action_finish" type="object" string="Done"
class="btn-success" attrs="{'invisible':
['|',('end_cleaning', '=', True),('state', '=', 'cancelled')]}"/>
<button name="action_inspection" type="object"
string="Inspection" class="oe_highlight"
attrs="{'invisible':
[('inspection_boolean', '=', True)]}"/>
<field name="state" widget="statusbar" statusbar_visible="draft"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button type="object" name="action_view_inspection"
class="oe_stat_button"
icon="fa-pencil-square-o">
<field name="inspection_count" widget="statinfo"
string="Inspection"/>
</button>
</div>
<group>
<field name="team_id"/>
<field name="team_leader_id"/>
<field name="cleaning_date"/>
<field name="cleaning_time"/>
<field name="members_ids" widget="many2many_tags"/>
<field name="customer_id"/>
<field name="location_state_id"/>
<field name="place"/>
<field name="inspection_boolean" invisible="1"/>
<field name="start_cleaning" invisible="1"/>
<field name="end_cleaning" invisible="1"/>
<field name="start_time"/>
<field name="end_time"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
<field name="activity_ids" widget="mail_activity"/>
</div>
</form>
</field>
</record>
<!--Cleaning team duty tree view-->
<record id="cleaning_team_duty_view_tree" model="ir.ui.view">
<field name="name">cleaning.team.duty.view.tree</field>
<field name="model">cleaning.team.duty</field>
<field name="arch" type="xml">
<tree create="0">
<field name="team_id"/>
<field name="team_leader_id"/>
<field name="members_ids" widget="many2many_tags"/>
<field name="cleaning_date"/>
<field name="state" widget="badge"
decoration-success="state == 'cleaned'"
decoration-danger="state == 'dirty'" optional="show"/>
</tree>
</field>
</record>
</odoo>

51
cleaning_management/views/cleaning_team_views.xml

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--Allows users to view the cleaning team as a tree and
provides a form for inputting cleaning team-->
<record id="cleaning_team_action" model="ir.actions.act_window">
<field name="name">Cleaning Team</field>
<field name="res_model">cleaning.team</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a New Cleaning Team
</p>
</field>
</record>
<!--Cleaning team form view-->
<record id="cleaning_team_view_form" model="ir.ui.view">
<field name="name">cleaning.team.view.form</field>
<field name="model">cleaning.team</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
<field name="duty_type"/>
<field name="team_leader_id" options="{'no_create': True}"/>
<field name="members_ids" widget="many2many_tags" options="{'no_create': True}"/>
<field name="cleaning_date" invisible="1"/>
<field name="cleaning_duty_ids" widget="many2many_tags" invisible="1"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
<field name="activity_ids" widget="mail_activity"/>
</div>
</form>
</field>
</record>
<!--Cleaning team tree view-->
<record id="cleaning_team_view_tree" model="ir.ui.view">
<field name="name">cleaning.team.view.tree</field>
<field name="model">cleaning.team</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="team_leader_id"/>
<field name="members_ids" widget="many2many_tags"/>
</tree>
</field>
</record>
</odoo>

46
cleaning_management/views/employee_details_views.xml

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Allows users to view the employee details as a tree and
provides a form for inputting employee details-->
<record id="employee_details_action" model="ir.actions.act_window">
<field name="name">Employee Details</field>
<field name="res_model">employee.details</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a New Employee Details
</p>
</field>
</record>
<!--Employee details form view-->
<record id="employee_details_view_form" model="ir.ui.view">
<field name="name">employee.details.view.form</field>
<field name="model">employee.details</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="employee_name_id"/>
<field name="time_shift_id" options="{'no_create': True}"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
<field name="activity_ids" widget="mail_activity"/>
</div>
</form>
</field>
</record>
<!--Employee details tree view-->
<record id="employee_details_view_tree" model="ir.ui.view">
<field name="name">employee.details.view.tree</field>
<field name="model">employee.details</field>
<field name="arch" type="xml">
<tree>
<field name="employee_name_id"/>
<field name="time_shift_id"/>
</tree>
</field>
</record>
</odoo>
Loading…
Cancel
Save