@ -0,0 +1,46 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-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: (V16)Farhana Jahan PT , 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>`__ |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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 |
@ -0,0 +1,67 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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': '16.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_backend': [ |
||||
|
'cleaning_management/static/src/css/cleaning_management_dashboard.css', |
||||
|
'cleaning_management/static/src/xml/cleaning_management_dashboard_template.xml', |
||||
|
'cleaning_management/static/src/js/cleaning_management_dashboard.js', |
||||
|
'https://cdn.jsdelivr.net/npm/chart.js', |
||||
|
], |
||||
|
'web.assets_frontend': [ |
||||
|
'cleaning_management/static/src/js/cleaning_management_website.js', |
||||
|
], |
||||
|
}, |
||||
|
'images': ['static/description/banner.jpg'], |
||||
|
'license': 'AGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': True, |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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 |
@ -0,0 +1,70 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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) |
@ -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> |
@ -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> |
@ -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> |
@ -0,0 +1,5 @@ |
|||||
|
## Module <cleaning_management> |
||||
|
#### 30.12.2023 |
||||
|
#### Version 16.0.1.0.0 |
||||
|
##### ADD |
||||
|
- Initial commit for Cleaning Management |
@ -0,0 +1,31 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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 |
@ -0,0 +1,40 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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 |
@ -0,0 +1,32 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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) |
@ -0,0 +1,221 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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)]) |
@ -0,0 +1,92 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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'}) |
@ -0,0 +1,310 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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([])] |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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([])]} |
@ -0,0 +1,41 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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) |
@ -0,0 +1,89 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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': []}} |
@ -0,0 +1,153 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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)]) |
||||
|
|
@ -0,0 +1,40 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Farhana Jahan PT (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) |
@ -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> |
|
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 147 KiB |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 143 KiB |
After Width: | Height: | Size: 947 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 118 KiB |
After Width: | Height: | Size: 125 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 330 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 11 KiB |
@ -0,0 +1,786 @@ |
|||||
|
<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/13.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/14.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/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;"> |
||||
|
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/16.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/12.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/16.0/whatsapp_redirect/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius:0px" |
||||
|
src="assets/modules/1.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/16.0/hr_payroll_community/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius:0px" |
||||
|
src="assets/modules/2.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/16.0/crm_dashboard/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius:0px" |
||||
|
src="assets/modules/3.png"> |
||||
|
</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/16.0/export_stockinfo_xls/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius:0px" |
||||
|
src="assets/modules/4.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/16.0/sale_discount_total/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius:0px" |
||||
|
src="assets/modules/5.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/16.0/fleet_rental/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius:0px" |
||||
|
src="assets/modules/6.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 & 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> |
@ -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; |
||||
|
} |
@ -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; |
||||
|
}) |
@ -0,0 +1,118 @@ |
|||||
|
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"></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(""); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,157 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8" ?> |
||||
|
<template> |
||||
|
<!-- 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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -0,0 +1,213 @@ |
|||||
|
<?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" |
||||
|
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="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="building_type_id" |
||||
|
class="control-label"> |
||||
|
Building Type : |
||||
|
</label> |
||||
|
<div class="col-sm"> |
||||
|
<select name="building_type_id" |
||||
|
class="form-control link-style" |
||||
|
style="width:81%;margin-left:20%; |
||||
|
margin-top:-3%;padding-bottom: 1%;"> |
||||
|
<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="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_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" |
||||
|
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" |
||||
|
style="width:81%;margin-left:20%; |
||||
|
margin-top:-3%;padding-bottom: 1%;"> |
||||
|
|
||||
|
<option t-att-value=" "/> |
||||
|
<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" |
||||
|
class="form-control link-style" |
||||
|
style="width:81%;margin-left:20%; |
||||
|
margin-top:-3%;padding-bottom: 1%;"> |
||||
|
<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> |
@ -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="False"> |
||||
|
<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="false"> |
||||
|
<field name="shift_type"/> |
||||
|
<field name="shift_time_from" widget="float_time"/> |
||||
|
<field name="shift_time_to" widget="float_time"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -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="False"> |
||||
|
<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="False"> |
||||
|
<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> |
@ -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> |
@ -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> |