diff --git a/cleaning_management/README.rst b/cleaning_management/README.rst new file mode 100644 index 000000000..49aadcdc8 --- /dev/null +++ b/cleaning_management/README.rst @@ -0,0 +1,48 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +Cleaning Management +=================== +This module allows users to manage cleaning processes easily. + +Configuration +============= +* Choose a user within the settings to provide access to the module. + +Company +------- +* `Cybrosys Techno Solutions `__ + +License +------- +General Public License, Version 3 (AGPL v3). +(https://www.gnu.org/licenses/agpl-3.0-standalone.html) + +Credits +------- +* Developer: (V17) Mohammed Dilshad TK , + (V18) Gayathri V +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 `__ + +Further information +=================== +HTML Description: ``__ diff --git a/cleaning_management/__init__.py b/cleaning_management/__init__.py new file mode 100644 index 000000000..6940ff46d --- /dev/null +++ b/cleaning_management/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V(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 . +# +############################################################################# +from . import controllers +from . import models diff --git a/cleaning_management/__manifest__.py b/cleaning_management/__manifest__.py new file mode 100644 index 000000000..c185ba18f --- /dev/null +++ b/cleaning_management/__manifest__.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +{ + 'name': 'Cleaning Management', + 'version': '18.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, +} diff --git a/cleaning_management/controllers/__init__.py b/cleaning_management/controllers/__init__.py new file mode 100644 index 000000000..192ca582d --- /dev/null +++ b/cleaning_management/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +from . import cleaning_management diff --git a/cleaning_management/controllers/cleaning_management.py b/cleaning_management/controllers/cleaning_management.py new file mode 100644 index 000000000..e94ef0724 --- /dev/null +++ b/cleaning_management/controllers/cleaning_management.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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) diff --git a/cleaning_management/data/building_type_demo.xml b/cleaning_management/data/building_type_demo.xml new file mode 100644 index 000000000..4a2464efd --- /dev/null +++ b/cleaning_management/data/building_type_demo.xml @@ -0,0 +1,18 @@ + + + + + + House + + + Hospital + + + Institution + + + Office + + + diff --git a/cleaning_management/data/cleaning_management_data.xml b/cleaning_management/data/cleaning_management_data.xml new file mode 100644 index 000000000..611231aa3 --- /dev/null +++ b/cleaning_management/data/cleaning_management_data.xml @@ -0,0 +1,13 @@ + + + + + + Cleaning Online Request + /cleaning/request/form + + 55 + + + diff --git a/cleaning_management/data/cleaning_shift_demo.xml b/cleaning_management/data/cleaning_shift_demo.xml new file mode 100644 index 000000000..902793b46 --- /dev/null +++ b/cleaning_management/data/cleaning_shift_demo.xml @@ -0,0 +1,21 @@ + + + + + + Morning Shift + 7.5 + 15.5 + + + Evening Shift + 15.5 + 23.5 + + + Night Shift + 23.5 + 07.5 + + + diff --git a/cleaning_management/doc/RELEASE_NOTES.md b/cleaning_management/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..f0a534db7 --- /dev/null +++ b/cleaning_management/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module +#### 24.12.2024 +#### Version 18.0.1.0.0 +##### ADD + +- Initial commit for Cleaning Management diff --git a/cleaning_management/models/__init__.py b/cleaning_management/models/__init__.py new file mode 100644 index 000000000..120b82123 --- /dev/null +++ b/cleaning_management/models/__init__.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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 diff --git a/cleaning_management/models/account_move.py b/cleaning_management/models/account_move.py new file mode 100644 index 000000000..9e5ddaeb6 --- /dev/null +++ b/cleaning_management/models/account_move.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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 diff --git a/cleaning_management/models/building_type.py b/cleaning_management/models/building_type.py new file mode 100644 index 000000000..c2c1c100c --- /dev/null +++ b/cleaning_management/models/building_type.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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) diff --git a/cleaning_management/models/cleaning_booking.py b/cleaning_management/models/cleaning_booking.py new file mode 100644 index 000000000..451c09c73 --- /dev/null +++ b/cleaning_management/models/cleaning_booking.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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' + + def _default_cleaning_team_ids(self): + """Returns default values for cleaning_team_ids records""" + return self.env['cleaning.team'].search([]).ids + + 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_ids = fields.Many2many('cleaning.team', + string='Cleaning Team', + help="Store cleaning team based on " + "cleaning_time", + default=_default_cleaning_team_ids) + cleaning_team_id = fields.Many2one('cleaning.team', + string='Cleaning Team', + help="Choose cleaning team", + required=True, + domain="[('id', 'in', " + "cleaning_team_ids)]") + 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', 'not in', ['cancelled', 'cleaned'])]) + if res: + domain = [('duty_type', '=', self.cleaning_time), + ('id', 'not in', [duty.team_id.id for duty in res])] + else: + domain.append(('duty_type', '=', self.cleaning_time)) + self.write({'cleaning_team_ids': [(6, 0, self.env + ['cleaning.team'].search(domain).ids)]}) + + @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': 'list,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)]) diff --git a/cleaning_management/models/cleaning_inspection.py b/cleaning_management/models/cleaning_inspection.py new file mode 100644 index 000000000..543383303 --- /dev/null +++ b/cleaning_management/models/cleaning_inspection.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V(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 . +# +############################################################################# +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'}) diff --git a/cleaning_management/models/cleaning_management_dashboard.py b/cleaning_management/models/cleaning_management_dashboard.py new file mode 100644 index 000000000..86cb5f010 --- /dev/null +++ b/cleaning_management/models/cleaning_management_dashboard.py @@ -0,0 +1,310 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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([])] + } diff --git a/cleaning_management/models/cleaning_management_website.py b/cleaning_management/models/cleaning_management_website.py new file mode 100644 index 000000000..ce16767cb --- /dev/null +++ b/cleaning_management/models/cleaning_management_website.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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([])]} diff --git a/cleaning_management/models/cleaning_shift.py b/cleaning_management/models/cleaning_shift.py new file mode 100644 index 000000000..4057da9ec --- /dev/null +++ b/cleaning_management/models/cleaning_shift.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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) diff --git a/cleaning_management/models/cleaning_team.py b/cleaning_management/models/cleaning_team.py new file mode 100644 index 000000000..336958083 --- /dev/null +++ b/cleaning_management/models/cleaning_team.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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'] + + def _default_emp_detail_ids(self): + """Returns default values for emp_detail_ids records""" + return self.env['employee.details'].search([]).ids + + name = fields.Char(string='Team Name', required=True, + help="Choose Team Name") + _sql_constraints = [ + ('name_unique', 'unique(name)', 'The team already exists')] + + emp_detail_ids = fields.Many2many('employee.details', + help="Stores records to define domain " + "for field.", + relation="emp_detail_ids_rel", + default=_default_emp_detail_ids) + team_leader_id = fields.Many2one('employee.details', + string='Leader', required=True, + help="Choose Leader For Team", + domain="[('id', 'in', " + "emp_detail_ids)]") + members_ids = fields.Many2many('employee.details', + string='Members', + help="Choose Members For Team", + required=True, + domain="[('id', 'in', " + "emp_detail_ids)]") + 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] + self.write({'emp_detail_ids': [(6, 0, self.env[ + 'employee.details'].search([('id', 'in', val)]).ids)]}) + else: + self.write({'emp_detail_ids': [(6, 0, self.env[ + 'employee.details'].search([]).ids)]}) diff --git a/cleaning_management/models/cleaning_team_duty.py b/cleaning_management/models/cleaning_team_duty.py new file mode 100644 index 000000000..7c8c01529 --- /dev/null +++ b/cleaning_management/models/cleaning_team_duty.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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': 'list,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)]) diff --git a/cleaning_management/models/employee_details.py b/cleaning_management/models/employee_details.py new file mode 100644 index 000000000..8062aae15 --- /dev/null +++ b/cleaning_management/models/employee_details.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Gayathri V (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 . +# +############################################################################# +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) diff --git a/cleaning_management/security/cleaning_management_groups.xml b/cleaning_management/security/cleaning_management_groups.xml new file mode 100644 index 000000000..d32a158d7 --- /dev/null +++ b/cleaning_management/security/cleaning_management_groups.xml @@ -0,0 +1,27 @@ + + + + + + Cleaning Management + Cleaning management + 5 + + + + User + + + + + Cleaning Manager + + + + + + diff --git a/cleaning_management/security/ir.model.access.csv b/cleaning_management/security/ir.model.access.csv new file mode 100644 index 000000000..3cb6ed0bd --- /dev/null +++ b/cleaning_management/security/ir.model.access.csv @@ -0,0 +1,14 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_cleaning_booking,access.cleaning.booking,model_cleaning_booking,base.group_user,1,1,1,1 +access_cleaning_team_manager,access.cleaning.team.manager,model_cleaning_team,cleaning_management.cleaning_management_group_manager,1,1,1,1 +access_cleaning_team_user,access.cleaning.team.user,model_cleaning_team,cleaning_management.cleaning_management_group_user,1,0,0,0 +access_cleaning_team_duty,access.cleaning.team.duty,model_cleaning_team_duty,base.group_user,1,1,1,1 +access_cleaning_inspection_manager,access.cleaning.inspection.manager,model_cleaning_inspection,cleaning_management.cleaning_management_group_manager,1,1,1,1 +access_cleaning_inspection_user,access.cleaning.inspection.user,model_cleaning_inspection,cleaning_management.cleaning_management_group_user,1,1,1,0 +access_building_type_user,access.building.type.user,model_building_type,cleaning_management.cleaning_management_group_user,1,0,0,0 +access_building_type_manager,access.building.type.manager,model_building_type,cleaning_management.cleaning_management_group_manager,1,1,1,1 +access_cleaning_shift_user,access.cleaning.shift,model_cleaning_shift,base.group_user,1,1,1,1 +access_employee_details_manager,access.employee.details.manger,model_employee_details,cleaning_management.cleaning_management_group_manager,1,1,1,1 +access_employee_details_user,access.employee.details.user,model_employee_details,cleaning_management.cleaning_management_group_user,1,0,0,0 +access_cleaning_management_dashboard,access_cleaning_management_dashboard,cleaning_management.model_cleaning_management_dashboard,base.group_user,1,0,0,0 +access_cleaning_management_website,access_cleaning_management_website,cleaning_management.model_cleaning_management_website,base.group_user,1,0,0,0 diff --git a/cleaning_management/static/description/assets/cybro-icon.png b/cleaning_management/static/description/assets/cybro-icon.png new file mode 100644 index 000000000..06e73e11d Binary files /dev/null and b/cleaning_management/static/description/assets/cybro-icon.png differ diff --git a/cleaning_management/static/description/assets/cybro-odoo.png b/cleaning_management/static/description/assets/cybro-odoo.png new file mode 100644 index 000000000..ed02e07a4 Binary files /dev/null and b/cleaning_management/static/description/assets/cybro-odoo.png differ diff --git a/cleaning_management/static/description/assets/h2.png b/cleaning_management/static/description/assets/h2.png new file mode 100644 index 000000000..0bfc4707d Binary files /dev/null and b/cleaning_management/static/description/assets/h2.png differ diff --git a/cleaning_management/static/description/assets/icons/arrows-repeat.svg b/cleaning_management/static/description/assets/icons/arrows-repeat.svg new file mode 100644 index 000000000..1d7efabc5 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/arrows-repeat.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/banner-1.png b/cleaning_management/static/description/assets/icons/banner-1.png new file mode 100644 index 000000000..c180db172 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/banner-1.png differ diff --git a/cleaning_management/static/description/assets/icons/banner-2.svg b/cleaning_management/static/description/assets/icons/banner-2.svg new file mode 100644 index 000000000..e606d97d9 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/banner-2.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/banner-bg.png b/cleaning_management/static/description/assets/icons/banner-bg.png new file mode 100644 index 000000000..a8238d3c0 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/banner-bg.png differ diff --git a/cleaning_management/static/description/assets/icons/banner-bg.svg b/cleaning_management/static/description/assets/icons/banner-bg.svg new file mode 100644 index 000000000..b1378103e --- /dev/null +++ b/cleaning_management/static/description/assets/icons/banner-bg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/banner-call.svg b/cleaning_management/static/description/assets/icons/banner-call.svg new file mode 100644 index 000000000..96c687e81 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/banner-call.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/cleaning_management/static/description/assets/icons/banner-mail.svg b/cleaning_management/static/description/assets/icons/banner-mail.svg new file mode 100644 index 000000000..cbf0d158d --- /dev/null +++ b/cleaning_management/static/description/assets/icons/banner-mail.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/cleaning_management/static/description/assets/icons/banner-pattern.svg b/cleaning_management/static/description/assets/icons/banner-pattern.svg new file mode 100644 index 000000000..9c1c7e101 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/banner-pattern.svg @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/banner-promo.svg b/cleaning_management/static/description/assets/icons/banner-promo.svg new file mode 100644 index 000000000..d52791b11 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/banner-promo.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/brand-pair.svg b/cleaning_management/static/description/assets/icons/brand-pair.svg new file mode 100644 index 000000000..d8db7fc1e --- /dev/null +++ b/cleaning_management/static/description/assets/icons/brand-pair.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/capture (1).png b/cleaning_management/static/description/assets/icons/capture (1).png new file mode 100644 index 000000000..8824deafc Binary files /dev/null and b/cleaning_management/static/description/assets/icons/capture (1).png differ diff --git a/cleaning_management/static/description/assets/icons/check.png b/cleaning_management/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/cleaning_management/static/description/assets/icons/check.png differ diff --git a/cleaning_management/static/description/assets/icons/chevron.png b/cleaning_management/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/chevron.png differ diff --git a/cleaning_management/static/description/assets/icons/close-icon.svg b/cleaning_management/static/description/assets/icons/close-icon.svg new file mode 100644 index 000000000..df8cce37a --- /dev/null +++ b/cleaning_management/static/description/assets/icons/close-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/cleaning_management/static/description/assets/icons/cogs.png b/cleaning_management/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/cogs.png differ diff --git a/cleaning_management/static/description/assets/icons/collabarate-icon.svg b/cleaning_management/static/description/assets/icons/collabarate-icon.svg new file mode 100644 index 000000000..dd4e10518 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/collabarate-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/cleaning_management/static/description/assets/icons/consultation.png b/cleaning_management/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/cleaning_management/static/description/assets/icons/consultation.png differ diff --git a/cleaning_management/static/description/assets/icons/cybro-logo.png b/cleaning_management/static/description/assets/icons/cybro-logo.png new file mode 100644 index 000000000..ff4b78220 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/cybro-logo.png differ diff --git a/cleaning_management/static/description/assets/icons/down.svg b/cleaning_management/static/description/assets/icons/down.svg new file mode 100644 index 000000000..f21c36271 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cleaning_management/static/description/assets/icons/ecom-black.png b/cleaning_management/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/ecom-black.png differ diff --git a/cleaning_management/static/description/assets/icons/education-black.png b/cleaning_management/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/cleaning_management/static/description/assets/icons/education-black.png differ diff --git a/cleaning_management/static/description/assets/icons/faq.png b/cleaning_management/static/description/assets/icons/faq.png new file mode 100644 index 000000000..4250b5b81 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/faq.png differ diff --git a/cleaning_management/static/description/assets/icons/feature-icon.svg b/cleaning_management/static/description/assets/icons/feature-icon.svg new file mode 100644 index 000000000..fa0ea6850 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/feature-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/feature.png b/cleaning_management/static/description/assets/icons/feature.png new file mode 100644 index 000000000..ac7a785c0 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/feature.png differ diff --git a/cleaning_management/static/description/assets/icons/gear.svg b/cleaning_management/static/description/assets/icons/gear.svg new file mode 100644 index 000000000..0cc66b6ea --- /dev/null +++ b/cleaning_management/static/description/assets/icons/gear.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/hero.gif b/cleaning_management/static/description/assets/icons/hero.gif new file mode 100644 index 000000000..9ac59bb63 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/hero.gif differ diff --git a/cleaning_management/static/description/assets/icons/hire-odoo.svg b/cleaning_management/static/description/assets/icons/hire-odoo.svg new file mode 100644 index 000000000..e1ac089b0 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/hire-odoo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/hotel-black.png b/cleaning_management/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/cleaning_management/static/description/assets/icons/hotel-black.png differ diff --git a/cleaning_management/static/description/assets/icons/img.png b/cleaning_management/static/description/assets/icons/img.png new file mode 100644 index 000000000..70197f477 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/img.png differ diff --git a/cleaning_management/static/description/assets/icons/license.png b/cleaning_management/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/cleaning_management/static/description/assets/icons/license.png differ diff --git a/cleaning_management/static/description/assets/icons/life-ring-icon.svg b/cleaning_management/static/description/assets/icons/life-ring-icon.svg new file mode 100644 index 000000000..3ae6e1d89 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/life-ring-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/lifebuoy.png b/cleaning_management/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/cleaning_management/static/description/assets/icons/lifebuoy.png differ diff --git a/cleaning_management/static/description/assets/icons/mail.svg b/cleaning_management/static/description/assets/icons/mail.svg new file mode 100644 index 000000000..1eedde695 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/mail.svg @@ -0,0 +1,3 @@ + + + diff --git a/cleaning_management/static/description/assets/icons/manufacturing-black.png b/cleaning_management/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/cleaning_management/static/description/assets/icons/manufacturing-black.png differ diff --git a/cleaning_management/static/description/assets/icons/notes.png b/cleaning_management/static/description/assets/icons/notes.png new file mode 100644 index 000000000..ee5e95404 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/notes.png differ diff --git a/cleaning_management/static/description/assets/icons/notification icon.svg b/cleaning_management/static/description/assets/icons/notification icon.svg new file mode 100644 index 000000000..053189973 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/notification icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/odoo-consultancy.svg b/cleaning_management/static/description/assets/icons/odoo-consultancy.svg new file mode 100644 index 000000000..e05f65bde --- /dev/null +++ b/cleaning_management/static/description/assets/icons/odoo-consultancy.svg @@ -0,0 +1,4 @@ + + + + diff --git a/cleaning_management/static/description/assets/icons/odoo-licencing.svg b/cleaning_management/static/description/assets/icons/odoo-licencing.svg new file mode 100644 index 000000000..2606c88b0 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/odoo-licencing.svg @@ -0,0 +1,3 @@ + + + diff --git a/cleaning_management/static/description/assets/icons/odoo-logo.png b/cleaning_management/static/description/assets/icons/odoo-logo.png new file mode 100644 index 000000000..0e4d0eb5a Binary files /dev/null and b/cleaning_management/static/description/assets/icons/odoo-logo.png differ diff --git a/cleaning_management/static/description/assets/icons/patter.svg b/cleaning_management/static/description/assets/icons/patter.svg new file mode 100644 index 000000000..25c9c0a8f --- /dev/null +++ b/cleaning_management/static/description/assets/icons/patter.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/pattern1.png b/cleaning_management/static/description/assets/icons/pattern1.png new file mode 100644 index 000000000..09ab0fb2d Binary files /dev/null and b/cleaning_management/static/description/assets/icons/pattern1.png differ diff --git a/cleaning_management/static/description/assets/icons/photo-capture.png b/cleaning_management/static/description/assets/icons/photo-capture.png new file mode 100644 index 000000000..06c111758 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/photo-capture.png differ diff --git a/cleaning_management/static/description/assets/icons/pos-black.png b/cleaning_management/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/pos-black.png differ diff --git a/cleaning_management/static/description/assets/icons/puzzle-piece-icon.svg b/cleaning_management/static/description/assets/icons/puzzle-piece-icon.svg new file mode 100644 index 000000000..3e9ad9373 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/puzzle-piece-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/puzzle.png b/cleaning_management/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/puzzle.png differ diff --git a/cleaning_management/static/description/assets/icons/replace-icon.svg b/cleaning_management/static/description/assets/icons/replace-icon.svg new file mode 100644 index 000000000..d0e3a7af1 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/replace-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/restaurant-black.png b/cleaning_management/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/restaurant-black.png differ diff --git a/cleaning_management/static/description/assets/icons/screenshot-main.png b/cleaning_management/static/description/assets/icons/screenshot-main.png new file mode 100644 index 000000000..575f8e676 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/screenshot-main.png differ diff --git a/cleaning_management/static/description/assets/icons/screenshot.png b/cleaning_management/static/description/assets/icons/screenshot.png new file mode 100644 index 000000000..cef272529 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/screenshot.png differ diff --git a/cleaning_management/static/description/assets/icons/service-black.png b/cleaning_management/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/cleaning_management/static/description/assets/icons/service-black.png differ diff --git a/cleaning_management/static/description/assets/icons/skype-fill.svg b/cleaning_management/static/description/assets/icons/skype-fill.svg new file mode 100644 index 000000000..c17423639 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/skype-fill.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/skype.png b/cleaning_management/static/description/assets/icons/skype.png new file mode 100644 index 000000000..51b409fb3 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/skype.png differ diff --git a/cleaning_management/static/description/assets/icons/skype.svg b/cleaning_management/static/description/assets/icons/skype.svg new file mode 100644 index 000000000..df3dad39b --- /dev/null +++ b/cleaning_management/static/description/assets/icons/skype.svg @@ -0,0 +1,3 @@ + + + diff --git a/cleaning_management/static/description/assets/icons/star-1.svg b/cleaning_management/static/description/assets/icons/star-1.svg new file mode 100644 index 000000000..7e55ab162 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/star-1.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/star-2.svg b/cleaning_management/static/description/assets/icons/star-2.svg new file mode 100644 index 000000000..5ae9f507a --- /dev/null +++ b/cleaning_management/static/description/assets/icons/star-2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/support.png b/cleaning_management/static/description/assets/icons/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/support.png differ diff --git a/cleaning_management/static/description/assets/icons/test-1 - Copy.png b/cleaning_management/static/description/assets/icons/test-1 - Copy.png new file mode 100644 index 000000000..f6a902663 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/test-1 - Copy.png differ diff --git a/cleaning_management/static/description/assets/icons/test-1.png b/cleaning_management/static/description/assets/icons/test-1.png new file mode 100644 index 000000000..0908add2b Binary files /dev/null and b/cleaning_management/static/description/assets/icons/test-1.png differ diff --git a/cleaning_management/static/description/assets/icons/test-2.png b/cleaning_management/static/description/assets/icons/test-2.png new file mode 100644 index 000000000..4671fe91e Binary files /dev/null and b/cleaning_management/static/description/assets/icons/test-2.png differ diff --git a/cleaning_management/static/description/assets/icons/trading-black.png b/cleaning_management/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/trading-black.png differ diff --git a/cleaning_management/static/description/assets/icons/training.png b/cleaning_management/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/cleaning_management/static/description/assets/icons/training.png differ diff --git a/cleaning_management/static/description/assets/icons/translate.svg b/cleaning_management/static/description/assets/icons/translate.svg new file mode 100644 index 000000000..af9c8a1aa --- /dev/null +++ b/cleaning_management/static/description/assets/icons/translate.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/update.png b/cleaning_management/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/cleaning_management/static/description/assets/icons/update.png differ diff --git a/cleaning_management/static/description/assets/icons/user.png b/cleaning_management/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/cleaning_management/static/description/assets/icons/user.png differ diff --git a/cleaning_management/static/description/assets/icons/video.png b/cleaning_management/static/description/assets/icons/video.png new file mode 100644 index 000000000..576705b17 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/video.png differ diff --git a/cleaning_management/static/description/assets/icons/whatsapp.png b/cleaning_management/static/description/assets/icons/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/cleaning_management/static/description/assets/icons/whatsapp.png differ diff --git a/cleaning_management/static/description/assets/icons/wrench-icon.svg b/cleaning_management/static/description/assets/icons/wrench-icon.svg new file mode 100644 index 000000000..174b5a465 --- /dev/null +++ b/cleaning_management/static/description/assets/icons/wrench-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/icons/wrench.png b/cleaning_management/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/cleaning_management/static/description/assets/icons/wrench.png differ diff --git a/cleaning_management/static/description/assets/misc/Cybrosys R.png b/cleaning_management/static/description/assets/misc/Cybrosys R.png new file mode 100644 index 000000000..da4058087 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/Cybrosys R.png differ diff --git a/cleaning_management/static/description/assets/misc/categories.png b/cleaning_management/static/description/assets/misc/categories.png new file mode 100755 index 000000000..bedf1e0b1 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/categories.png differ diff --git a/cleaning_management/static/description/assets/misc/check-box.png b/cleaning_management/static/description/assets/misc/check-box.png new file mode 100755 index 000000000..42caf24b9 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/check-box.png differ diff --git a/cleaning_management/static/description/assets/misc/compass.png b/cleaning_management/static/description/assets/misc/compass.png new file mode 100755 index 000000000..d5fed8faa Binary files /dev/null and b/cleaning_management/static/description/assets/misc/compass.png differ diff --git a/cleaning_management/static/description/assets/misc/corporate.png b/cleaning_management/static/description/assets/misc/corporate.png new file mode 100755 index 000000000..2eb13edbf Binary files /dev/null and b/cleaning_management/static/description/assets/misc/corporate.png differ diff --git a/cleaning_management/static/description/assets/misc/customer-support.png b/cleaning_management/static/description/assets/misc/customer-support.png new file mode 100755 index 000000000..79efc72ed Binary files /dev/null and b/cleaning_management/static/description/assets/misc/customer-support.png differ diff --git a/cleaning_management/static/description/assets/misc/email.svg b/cleaning_management/static/description/assets/misc/email.svg new file mode 100644 index 000000000..15291cdc3 --- /dev/null +++ b/cleaning_management/static/description/assets/misc/email.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/misc/features.png b/cleaning_management/static/description/assets/misc/features.png new file mode 100755 index 000000000..b41769f77 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/features.png differ diff --git a/cleaning_management/static/description/assets/misc/logo.png b/cleaning_management/static/description/assets/misc/logo.png new file mode 100755 index 000000000..478462d3e Binary files /dev/null and b/cleaning_management/static/description/assets/misc/logo.png differ diff --git a/cleaning_management/static/description/assets/misc/phone.svg b/cleaning_management/static/description/assets/misc/phone.svg new file mode 100644 index 000000000..b7bd7f251 --- /dev/null +++ b/cleaning_management/static/description/assets/misc/phone.svg @@ -0,0 +1,3 @@ + + + diff --git a/cleaning_management/static/description/assets/misc/pictures.png b/cleaning_management/static/description/assets/misc/pictures.png new file mode 100755 index 000000000..56d255fe9 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/pictures.png differ diff --git a/cleaning_management/static/description/assets/misc/pie-chart.png b/cleaning_management/static/description/assets/misc/pie-chart.png new file mode 100755 index 000000000..426e05244 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/pie-chart.png differ diff --git a/cleaning_management/static/description/assets/misc/right-arrow.png b/cleaning_management/static/description/assets/misc/right-arrow.png new file mode 100755 index 000000000..730984a06 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/right-arrow.png differ diff --git a/cleaning_management/static/description/assets/misc/star (1) 2.svg b/cleaning_management/static/description/assets/misc/star (1) 2.svg new file mode 100644 index 000000000..5ae9f507a --- /dev/null +++ b/cleaning_management/static/description/assets/misc/star (1) 2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cleaning_management/static/description/assets/misc/star.png b/cleaning_management/static/description/assets/misc/star.png new file mode 100755 index 000000000..2eb9ab29f Binary files /dev/null and b/cleaning_management/static/description/assets/misc/star.png differ diff --git a/cleaning_management/static/description/assets/misc/support (1) 1.svg b/cleaning_management/static/description/assets/misc/support (1) 1.svg new file mode 100644 index 000000000..7d37a8f30 --- /dev/null +++ b/cleaning_management/static/description/assets/misc/support (1) 1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cleaning_management/static/description/assets/misc/support-email.svg b/cleaning_management/static/description/assets/misc/support-email.svg new file mode 100644 index 000000000..eb70370d6 --- /dev/null +++ b/cleaning_management/static/description/assets/misc/support-email.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/cleaning_management/static/description/assets/misc/support.png b/cleaning_management/static/description/assets/misc/support.png new file mode 100755 index 000000000..4f18b8b82 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/support.png differ diff --git a/cleaning_management/static/description/assets/misc/tick-mark.svg b/cleaning_management/static/description/assets/misc/tick-mark.svg new file mode 100644 index 000000000..2dbb40187 --- /dev/null +++ b/cleaning_management/static/description/assets/misc/tick-mark.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/misc/whatsapp 1.svg b/cleaning_management/static/description/assets/misc/whatsapp 1.svg new file mode 100644 index 000000000..0bfaf8fc6 --- /dev/null +++ b/cleaning_management/static/description/assets/misc/whatsapp 1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/cleaning_management/static/description/assets/misc/whatsapp.png b/cleaning_management/static/description/assets/misc/whatsapp.png new file mode 100755 index 000000000..d513a5356 Binary files /dev/null and b/cleaning_management/static/description/assets/misc/whatsapp.png differ diff --git a/cleaning_management/static/description/assets/misc/whatsapp.svg b/cleaning_management/static/description/assets/misc/whatsapp.svg new file mode 100644 index 000000000..b618aea1d --- /dev/null +++ b/cleaning_management/static/description/assets/misc/whatsapp.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cleaning_management/static/description/assets/modules/1.gif b/cleaning_management/static/description/assets/modules/1.gif new file mode 100644 index 000000000..ae3a880a2 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/1.gif differ diff --git a/cleaning_management/static/description/assets/modules/1.jpg b/cleaning_management/static/description/assets/modules/1.jpg new file mode 100644 index 000000000..08bbafeb6 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/1.jpg differ diff --git a/cleaning_management/static/description/assets/modules/2.gif b/cleaning_management/static/description/assets/modules/2.gif new file mode 100644 index 000000000..d19e2b352 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/2.gif differ diff --git a/cleaning_management/static/description/assets/modules/2.png b/cleaning_management/static/description/assets/modules/2.png new file mode 100644 index 000000000..a1209a01f Binary files /dev/null and b/cleaning_management/static/description/assets/modules/2.png differ diff --git a/cleaning_management/static/description/assets/modules/3.jpg b/cleaning_management/static/description/assets/modules/3.jpg new file mode 100644 index 000000000..3d171226b Binary files /dev/null and b/cleaning_management/static/description/assets/modules/3.jpg differ diff --git a/cleaning_management/static/description/assets/modules/3.png b/cleaning_management/static/description/assets/modules/3.png new file mode 100644 index 000000000..8513873ea Binary files /dev/null and b/cleaning_management/static/description/assets/modules/3.png differ diff --git a/cleaning_management/static/description/assets/modules/4.jpg b/cleaning_management/static/description/assets/modules/4.jpg new file mode 100644 index 000000000..1f3f2e27f Binary files /dev/null and b/cleaning_management/static/description/assets/modules/4.jpg differ diff --git a/cleaning_management/static/description/assets/modules/4.png b/cleaning_management/static/description/assets/modules/4.png new file mode 100644 index 000000000..3bedf7981 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/4.png differ diff --git a/cleaning_management/static/description/assets/modules/5.jpg b/cleaning_management/static/description/assets/modules/5.jpg new file mode 100644 index 000000000..0db717519 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/5.jpg differ diff --git a/cleaning_management/static/description/assets/modules/5.png b/cleaning_management/static/description/assets/modules/5.png new file mode 100644 index 000000000..0e311ca87 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/5.png differ diff --git a/cleaning_management/static/description/assets/modules/6.jpg b/cleaning_management/static/description/assets/modules/6.jpg new file mode 100644 index 000000000..67c7f7062 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/6.jpg differ diff --git a/cleaning_management/static/description/assets/modules/6.png b/cleaning_management/static/description/assets/modules/6.png new file mode 100644 index 000000000..0e311ca87 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/6.png differ diff --git a/cleaning_management/static/description/assets/modules/module_image (1).jpeg b/cleaning_management/static/description/assets/modules/module_image (1).jpeg new file mode 100644 index 000000000..5ae24843e Binary files /dev/null and b/cleaning_management/static/description/assets/modules/module_image (1).jpeg differ diff --git a/cleaning_management/static/description/assets/modules/module_image (1).png b/cleaning_management/static/description/assets/modules/module_image (1).png new file mode 100644 index 000000000..0dea4f332 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/module_image (1).png differ diff --git a/cleaning_management/static/description/assets/modules/module_image (2).png b/cleaning_management/static/description/assets/modules/module_image (2).png new file mode 100644 index 000000000..a5dc79613 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/module_image (2).png differ diff --git a/cleaning_management/static/description/assets/modules/module_image-1.jpeg b/cleaning_management/static/description/assets/modules/module_image-1.jpeg new file mode 100644 index 000000000..31f066e9c Binary files /dev/null and b/cleaning_management/static/description/assets/modules/module_image-1.jpeg differ diff --git a/cleaning_management/static/description/assets/modules/module_image.jpeg b/cleaning_management/static/description/assets/modules/module_image.jpeg new file mode 100644 index 000000000..0cbac311c Binary files /dev/null and b/cleaning_management/static/description/assets/modules/module_image.jpeg differ diff --git a/cleaning_management/static/description/assets/modules/module_image.png b/cleaning_management/static/description/assets/modules/module_image.png new file mode 100644 index 000000000..612be4b77 Binary files /dev/null and b/cleaning_management/static/description/assets/modules/module_image.png differ diff --git a/cleaning_management/static/description/assets/screenshots/1.png b/cleaning_management/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..a48242e09 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/1.png differ diff --git a/cleaning_management/static/description/assets/screenshots/10.png b/cleaning_management/static/description/assets/screenshots/10.png new file mode 100644 index 000000000..cbacf97f0 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/10.png differ diff --git a/cleaning_management/static/description/assets/screenshots/11.png b/cleaning_management/static/description/assets/screenshots/11.png new file mode 100644 index 000000000..5d9ff1675 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/11.png differ diff --git a/cleaning_management/static/description/assets/screenshots/12.png b/cleaning_management/static/description/assets/screenshots/12.png new file mode 100644 index 000000000..d6c98b9ce Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/12.png differ diff --git a/cleaning_management/static/description/assets/screenshots/13.png b/cleaning_management/static/description/assets/screenshots/13.png new file mode 100644 index 000000000..ca19d0fa1 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/13.png differ diff --git a/cleaning_management/static/description/assets/screenshots/14.png b/cleaning_management/static/description/assets/screenshots/14.png new file mode 100644 index 000000000..52461a4ba Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/14.png differ diff --git a/cleaning_management/static/description/assets/screenshots/15.png b/cleaning_management/static/description/assets/screenshots/15.png new file mode 100644 index 000000000..ee94dc76b Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/15.png differ diff --git a/cleaning_management/static/description/assets/screenshots/16.png b/cleaning_management/static/description/assets/screenshots/16.png new file mode 100644 index 000000000..81ca38f9f Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/16.png differ diff --git a/cleaning_management/static/description/assets/screenshots/2.png b/cleaning_management/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..8474c0d81 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/2.png differ diff --git a/cleaning_management/static/description/assets/screenshots/3.png b/cleaning_management/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..5fd89a065 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/3.png differ diff --git a/cleaning_management/static/description/assets/screenshots/4.png b/cleaning_management/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..60ac8838e Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/4.png differ diff --git a/cleaning_management/static/description/assets/screenshots/5.png b/cleaning_management/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..55deebb9d Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/5.png differ diff --git a/cleaning_management/static/description/assets/screenshots/6.png b/cleaning_management/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..2f32db423 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/6.png differ diff --git a/cleaning_management/static/description/assets/screenshots/7.png b/cleaning_management/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..0d7d870ab Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/7.png differ diff --git a/cleaning_management/static/description/assets/screenshots/8.png b/cleaning_management/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..b1551d305 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/8.png differ diff --git a/cleaning_management/static/description/assets/screenshots/9.png b/cleaning_management/static/description/assets/screenshots/9.png new file mode 100644 index 000000000..6a71709d0 Binary files /dev/null and b/cleaning_management/static/description/assets/screenshots/9.png differ diff --git a/cleaning_management/static/description/assets/y18.jpg b/cleaning_management/static/description/assets/y18.jpg new file mode 100644 index 000000000..eea1714f2 Binary files /dev/null and b/cleaning_management/static/description/assets/y18.jpg differ diff --git a/cleaning_management/static/description/banner.jpg b/cleaning_management/static/description/banner.jpg new file mode 100644 index 000000000..d7d5b76c8 Binary files /dev/null and b/cleaning_management/static/description/banner.jpg differ diff --git a/cleaning_management/static/description/icon.png b/cleaning_management/static/description/icon.png new file mode 100644 index 000000000..1689b953f Binary files /dev/null and b/cleaning_management/static/description/icon.png differ diff --git a/cleaning_management/static/description/index.html b/cleaning_management/static/description/index.html new file mode 100644 index 000000000..8e72150e2 --- /dev/null +++ b/cleaning_management/static/description/index.html @@ -0,0 +1,1486 @@ + + + + + + Cleaning Management + + + + + + + + + + +
+
+ + + +
+
+ Community +
+
+ Enterprise +
+
+
+ +
+
+
+
+

+ This Module Assists with Booking for Cleaning + and Manages Cleaning Processes. +

+

Cleaning Management +

+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+

Key + Highlights

+
+
+
+
+ +
+
+ Online Booking Facility +
+
+
+
+
+
+ +
+
+ Different access levels for Users and + Manager +
+
+
+
+
+
+ +
+
+ Activity dashboard is available +
+
+
+
+
+
+ +
+
+ Various shifts are available for Employees +
+
+
+
+
+ +
+
+
+ Cleaning Management +

+ Are you ready to make your business more + organized? +
Improve now! +

+ +
+
+ +
+
+
+ + + + +
+
+ +
+
+
+
+ acc_bg +
+ +
+
+
+
+

+ App access for User + + or Manager +

+
+
+

+ Choose + "Cleaning Manager" or "User" in + the settings. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Main Apps + + menu. +

+
+
+

+ Once access is granted, you will + find the Cleaning Management app + in the Main Apps menu. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Website view of Cleaning + + Management. +

+
+
+

+ When you click on 'Cleaning + Online Request,' a form will + appear, allowing you to book + Cleaning processes by providing + your details. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Employee + + Details. +

+
+
+

+ 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. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Cleaning + + Team. +

+
+
+

+ Cleaning Management -> + Cleaning Team. Where you can + specify the Duty Type, Leader, + and Members of a particular + team. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Booking + +

+
+
+

+ Cleaning Management -> + Booking. Where all created + bookings are listed, and you can + also create a new booking here. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Cleaning Team with corresponding + + Cleaning Time. + +

+
+
+

+ You can get the Team + when they are available on that + day. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Confirm + + Booking. + +

+
+
+

+ After verifying the + cleaning process and confirming + its completion, the stage + changes to "BOOKED." At this + stage, you will be presented + with "CANCEL" button. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Cleaning Team + + Duty. + +

+
+
+

+ Can track cleaning + process time by clicking 'Start' + button. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + INSPECTION + +

+
+
+

+ 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. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Result + +

+
+
+

+ You can inspect the + process by clicking the "CLEAN" + or "DIRT" button. +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + When click on 'CLEAN' Button stage changed + + to 'CLEANED'. +

+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Invoice + + Creation. +

+
+
+

+ You can create invoice by + clicking 'CREATE INVOICE' Button + after defining 'Unit Price'. + +

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Invoice form of + + Cleaning Management. +

+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Invoice Smart + + Button. +

+
+
+

+ Invoice Smart Button in + Cleaning Booking Form.

+
+
+
+ +
+
+
+
+
+
+
+
+
+

+ + Dashboard + + View. +

+
+
+

+ 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.

+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+

+ Online Booking Facility

+
+ +
+
+
+
+
+
+ +
+

+ We can see a preview of + attachments while downloading + them. .

+
+
+
+
+
+
+
+ +
+

+ Different access levels for + Users and Manager

+
+ +
+
+
+
+
+
+ +
+

+ Activity dashboard is + available

+
+ +
+
+
+
+
+
+ +
+

+ Various shifts are available for + Employees

+
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+ +
+

+ The Cleaning + Management module in + Odoo 17.0 is + designed to help + businesses manage + their cleaning + operations. It + allows you to + schedule cleaning + tasks, assign them + to staff, track + progress, and + maintain records of + cleaning activities. +

+
+
+ +
+ +
+

+ * Facility management companies + * Office administrators + * Residential or commercial cleaning services + * Organizations managing internal cleaning operations +

+
+
+ +
+ +
+

+ Yes, the module provides a progress tracker for each task. Managers can see whether a task is pending, in progress, or completed. +

+
+
+
+ +
+
+
+
+
+
+ +
+
+

+ Latest Release 18.0.1.0.0 +

+ + 24th December, 2024 + +
+
+
+
+
+ Add +
+
+
+
    +
  • + Initial Commit +
  • + +
+
+
+
+
+
+
+
+
+
+ + + +
+

+ Related Products +

+ +
+ + +
+

+ Our Services

+ +
+
+ +
+
+ .... +
+
+ +
+ +
+
+ + + + + + diff --git a/cleaning_management/static/src/css/cleaning_management_dashboard.css b/cleaning_management/static/src/css/cleaning_management_dashboard.css new file mode 100644 index 000000000..b00c2ee89 --- /dev/null +++ b/cleaning_management/static/src/css/cleaning_management_dashboard.css @@ -0,0 +1,178 @@ +.o_action_manager { + overflow: auto !important; +} + +.cleaning_dashboards { + padding-top: 10px; + background-color: #f8faff !important; +} + +.cleaning-card h4 { + font-size: 1.1rem; +} +/* Widget One +---------------------------*/ +.stat-content { + display: inline-block; + width: 66%; +} + +.stat-icon { + display: inline-block; +} + +.stat-widget-one .stat-icon { + vertical-align: top; + margin: auto; + width: 100%; + color: #01c490; +} + +.stat-widget-one .stat-icon i { + font-size: 30px; + font-weight: 900; + display: inline-block; + color: #01c490; +} + +.stat-widget-one .stat-text { + font-size: 14px; + color: #868e96; + font-weight: bold; +} + +.stat-widget-one .stat-digit { + font-size: 24px; + color: #02448b; +} + +.stat-count { + font-size: 20px; + text-align: center; + color: #00438b; +} + +.stat-title { + font-size: 17px; + text-align: center; + color: #00438b; +} + +/*=====================Dashboard===========================*/ + +.cleaning_dashboards { + background-color: #f8faff !important; + padding: 0px !important; +} + +.container-fluid.o_hr_dashboard { + padding: 0px !important; +} + +.cleaning-card { + padding: 0px; + margin-bottom: 1.5rem; + border-radius: 0px; + box-shadow: none; + background: none; + transition: transform 0.2s ease, box-shadow 0.2s ease; + will-change: transform, box-shadow; +} + +.cleaning-card:hover { + transform: translateY(-2px) translateZ(0) !important; + box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important; +} + +.cleaning { + margin-top: 3%; + margin-bottom: 2%; +} + +.cleaning .stat-icon { + border-radius: 15px 0 0 15px; + width: 30%; + height: 100px; + text-align: center; + padding-top: 10%; + background: #314384ff; + color: #fff; +} + +.cleaning .cleaning-card { + border-radius: 15px; + transition: transform 0.2s ease, box-shadow 0.2s ease; + will-change: transform, box-shadow; + box-shadow: 0 10px 40px 0 rgba(62, 57, 107, 0.07), + 0 2px 9px 0 rgba(62, 57, 107, 0.06); +} + +.stat-widget-one .stat-text { + font-size: 14px; + color: #314384ff; + margin: 2rem 0rem 1rem 0rem; + text-align: center; +} + +.stat-widget-one .stat-digit { + font-size: 20px; + font-weight: bolder; + padding: 1px 10px 2px 0; + color: #8061a9; + text-shadow: 0px 0px 20px #000000; + text-align: center; +} + +.stat-widget-one .stat-icon i { + /*border-radius: 15px 0 0 15px;*/ + font-size: 25px; + font-weight: 900; + display: inline-block; + color: #fff; +} + +.stat-widget-one { + border-radius: 15px; + background-color: white; + text-align: inherit !important; +} + +.stat-widget-one { + width: 100%; +} + +.cleaning_count .stat-icon { + background: #964ec2 !important; +} + +.dirty_count .stat-icon { + background: #813de6 !important; +} + +.cleaning_teams .stat-icon { + background: #6f23a9 !important; +} + +.cleaning_count .stat-widget-one .stat-text { + color: #964ec2; +} + +.dirty_count .stat-widget-one .stat-text { + color: #813de6; +} + +.cleaning_teams .stat-widget-one .stat-text { + color: #6f23a9; +} + +.cleaning-card-body { + display: flex; + justify-content: space-between; + align-items: center; +} + +.counting{ + width: 414px; + margin-left: 762px; + margin-top: -291px; +} diff --git a/cleaning_management/static/src/js/cleaning_management_dashboard.js b/cleaning_management/static/src/js/cleaning_management_dashboard.js new file mode 100644 index 000000000..6452e53ca --- /dev/null +++ b/cleaning_management/static/src/js/cleaning_management_dashboard.js @@ -0,0 +1,478 @@ +/** @odoo-module */ +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +import { Component } from "@odoo/owl"; +import { onMounted, useRef } from "@odoo/owl"; +const actionRegistry = registry.category("actions"); + /** Create component 'CleaningDashboard' by extending Component **/ +export class CleaningDashboard extends Component { + /** + * Obtain yearly, monthly, quarterly, and weekly bookings, + as well as clean and dirt reports. + */ + setup() { + super.setup(...arguments); + this.orm = useService('orm'); + this.rootRef = useRef('main-content'); + this.today_sale = []; + + // When the component is mounted, render various charts + onMounted(async () => { + await this.RenderDashboard(); + await this.render_graph(); + const Ref = this.rootRef.el; + + // Hide and show elements using native JavaScript + Ref.querySelector("#activity_week").style.display = 'none'; + Ref.querySelector("#activity_year").style.display = 'none'; + Ref.querySelector("#activity_quarter").style.display = 'none'; + Ref.querySelector("#activity_month").style.display = 'block'; + + Ref.querySelector("#quality_week").style.display = 'none'; + Ref.querySelector("#quality_month").style.display = 'block'; + Ref.querySelector("#quality_quarter").style.display = 'none'; + Ref.querySelector("#quality_year").style.display = 'none'; + + // ORM call + await this.orm.call('cleaning.management.dashboard', 'cleaning_count', [0]).then(function(result) { + const report = Ref.querySelector(".report"); + const bookings = Ref.querySelector(".bookings"); + const quality = Ref.querySelector(".quality"); + + if (result['inspections'].length > 0 && result['bookings'].length > 0) { + report.style.display = 'block'; + bookings.style.display = 'block'; + quality.style.display = 'block'; + } else if (result['bookings'].length > 0) { + report.style.display = 'block'; + bookings.style.display = 'block'; + quality.style.display = 'none'; + } else if (result['inspections'].length > 0) { + report.style.display = 'block'; + bookings.style.display = 'block'; + quality.style.display = 'block'; + } else { + report.style.display = 'none'; + bookings.style.display = 'none'; + quality.style.display = 'none'; + } + }); + }); + } + ChangeFiltration(ev) { + console.log("ChangeFiltration", ev) + ev.stopPropagation(); + // Return elements where event occurred + var option_val = ev.target.value; + if (option_val == "this_year") { + this.OnclickThisYear(option_val); + } else if (option_val == "this_quarter") { + this.OnclickThisQuarter(option_val); + } else if (option_val == "this_month") { + this.OnclickThisMonth(option_val); + } else if (option_val == "this_week") { + this.OnclickThisWeek(option_val); + } + } + //Generate a dashboard displaying the count of bookings, dirty instances, completed cleanings, and the cleaning team. + RenderDashboard() { + console.log("RenderDashboard") + var self = this; + this.orm.call('cleaning.management.dashboard', + 'get_dashboard_count', [0]).then(function(result) { + const MainDiv = self.rootRef.el + const bookings_count = MainDiv.querySelector("#bookings_count") + bookings_count.classList.add("stat-digit"); + bookings_count.textContent = result.bookings; + const teams_count = MainDiv.querySelector("#teams_count") + teams_count.classList.add("stat-digit"); + teams_count.textContent = result.teams; + const cleaning_count = MainDiv.querySelector("#cleaning_count") + cleaning_count.classList.add("stat-digit"); + cleaning_count.textContent = result.cleaned; + const dirty_count = MainDiv.querySelector("#dirty_count") + dirty_count.classList.add("stat-digit"); + dirty_count.textContent = result.dirty; + }); + } + //Get booking records + GetBookings() { + console.log("GetBookings", ) + this.env.services.action.doAction({ + name: ("Bookings"), + type: 'ir.actions.act_window', + res_model: 'cleaning.booking', + view_mode: 'list,form,calendar', + views: [ + [false, 'list'], + [false, 'form'] + ], + domain: [ + ['state', '=', 'booked'] + ], + target: 'current', + }) + } + //Get team count records + GetTeams() { + this.env.services.action.doAction({ + name: ("Teams"), + type: 'ir.actions.act_window', + res_model: 'cleaning.team', + view_mode: 'list,form,calendar', + views: [ + [false, 'list'], + [false, 'form'] + ], + target: 'current', + }) + } + //Get cleaning count + GetCleaning() { + this.env.services.action.doAction({ + name: ("Count of Cleaning"), + type: 'ir.actions.act_window', + res_model: 'cleaning.inspection', + view_mode: 'list,form,calendar', + views: [ + [false, 'list'], + [false, 'form'] + ], + domain: [ + ['state', '=', 'cleaned'] + ], + target: 'current', + }) + } + //Get dirty count + GetDirty() { + this.env.services.action.doAction({ + name: ("Count of dirty"), + type: 'ir.actions.act_window', + res_model: 'cleaning.inspection', + view_mode: 'list,form,calendar', + views: [[false, 'list'], [false, 'form']], + domain: [['state', '=', 'dirty']], + target: 'current', + }) + } + //Generate a graph representing the yearly, monthly, weekly, and quarterly records. + render_graph() { + console.log("render_graph") + var self = this + var ctx = self.rootRef.el.querySelector(".total_bookings_year") + console.log("ctx", ctx) + this.orm.call('cleaning.management.dashboard', 'get_the_booking_year', [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'] + var ctx = self.rootRef.el.querySelector("#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.rootRef.el.querySelector(".total_bookings_week") + this.orm.call('cleaning.management.dashboard', 'get_the_booking_week', [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'] + var ctx = self.rootRef.el.querySelector("#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.rootRef.el.querySelector(".total_bookings_month") + this.orm.call('cleaning.management.dashboard', 'get_the_booking_month', [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); + var ctx = self.rootRef.el.querySelector("#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.rootRef.el.querySelector(".total_bookings_quarter") + this.orm.call('cleaning.management.dashboard', 'get_the_booking_quarter', [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.rootRef.el.querySelector("#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.rootRef.el.querySelector(".total_quality_year") + this.orm.call('cleaning.management.dashboard', 'quality_year', [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.rootRef.el.querySelector("#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.rootRef.el.querySelector(".total_quality_week") + this.orm.call('cleaning.management.dashboard', 'quality_week', [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.rootRef.el.querySelector("#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.rootRef.el.querySelector(".total_quality_month") + this.orm.call('cleaning.management.dashboard', 'quality_month', [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.rootRef.el.querySelector("#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.rootRef.el.querySelector(".total_quality_quarter") + this.orm.call('cleaning.management.dashboard', 'quality_quarter', [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.rootRef.el.querySelector("#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 + OnclickThisYear(ev) { + console.log("OnclickThisYear"); + const Ref = this.rootRef.el; // Assuming you already have a reference to the root element + + Ref.querySelector("#activity_week").style.display = 'none'; + Ref.querySelector("#activity_month").style.display = 'none'; + Ref.querySelector("#activity_quarter").style.display = 'none'; + Ref.querySelector("#activity_year").style.display = 'block'; + + Ref.querySelector("#quality_week").style.display = 'none'; + Ref.querySelector("#quality_month").style.display = 'none'; + Ref.querySelector("#quality_quarter").style.display = 'none'; + Ref.querySelector("#quality_year").style.display = 'block'; + } + // Show monthly result + OnclickThisMonth(ev) { + const Ref = this.rootRef.el; // Assuming you already have a reference to the root element + Ref.querySelector("#activity_week").style.display = 'none'; + Ref.querySelector("#activity_year").style.display = 'none'; + Ref.querySelector("#activity_quarter").style.display = 'none'; + Ref.querySelector("#activity_month").style.display = 'block'; + + Ref.querySelector("#quality_week").style.display = 'none'; + Ref.querySelector("#quality_month").style.display = 'block'; + Ref.querySelector("#quality_quarter").style.display = 'none'; + Ref.querySelector("#quality_year").style.display = 'none'; + } + // Show weekly result + OnclickThisWeek(ev) { + const Ref = this.rootRef.el; // Assuming you already have a reference to the root element + Ref.querySelector("#activity_year").style.display = 'none'; + Ref.querySelector("#activity_month").style.display = 'none'; + Ref.querySelector("#activity_quarter").style.display = 'none'; + Ref.querySelector("#activity_week").style.display = 'block'; + + Ref.querySelector("#quality_week").style.display = 'block'; + Ref.querySelector("#quality_month").style.display = 'none'; + Ref.querySelector("#quality_quarter").style.display = 'none'; + Ref.querySelector("#quality_year").style.display = 'none'; + + } + // Show quarterly result + OnclickThisQuarter(ev) { + const Ref = this.rootRef.el; // Assuming you already have a reference to the root element + Ref.querySelector("#activity_week").style.display = 'none'; + Ref.querySelector("#activity_month").style.display = 'none'; + Ref.querySelector("#activity_year").style.display = 'none'; + Ref.querySelector("#activity_quarter").style.display = 'block'; + + Ref.querySelector("#quality_week").style.display = 'none'; + Ref.querySelector("#quality_month").style.display = 'none'; + Ref.querySelector("#quality_quarter").style.display = 'block'; + Ref.querySelector("#quality_year").style.display = 'none'; + + } +} +CleaningDashboard.template = "CleaningDashBoard"; +actionRegistry.add("cleaning_dashboard_tags", CleaningDashboard); diff --git a/cleaning_management/static/src/js/cleaning_management_website.js b/cleaning_management/static/src/js/cleaning_management_website.js new file mode 100644 index 000000000..6ebca556d --- /dev/null +++ b/cleaning_management/static/src/js/cleaning_management_website.js @@ -0,0 +1,99 @@ +/** @odoo-module **/ +import publicWidget from "@web/legacy/js/public/public_widget"; +import { useService } from "@web/core/utils/hooks"; + 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', + }, + /** Super start function to define orm **/ + start: function() { + this._super.apply(this, arguments); + this.orm = this.bindService("orm"); + }, + /** 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 = ` + + `; + console.log("$('body')", $("body")) + $("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; + this.orm.call('cleaning.management.website', 'get_team_details', [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'], + ]; + self.orm.call('cleaning.team.duty', 'search_read', [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]], + ]; + self.orm.call('cleaning.team', 'search_read', [domain_for_duty, ['id', 'name']]).then(function(res) { + res.forEach(team => { + if (!team_array.includes(team.id)) { + team_array.push(team.id); + + var option = $('