diff --git a/pos_timesheet/README.rst b/pos_timesheet/README.rst new file mode 100644 index 000000000..2a0c28be3 --- /dev/null +++ b/pos_timesheet/README.rst @@ -0,0 +1,46 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg + :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +POS Timesheet +============= +Efficiently track employees' work hours in POS. + +Configuration +============= +No configuration + +Company +------- +* `Cybrosys Techno Solutions `__ + +License +------- +General Public License, Version 3 (LGPL v3). +(http://www.gnu.org/licenses/lgpl-3.0-standalone.html) + +Credits +------- +Developer: (V15) Mohammed Dilshad Tk , Contact: odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ diff --git a/pos_timesheet/__init__.py b/pos_timesheet/__init__.py new file mode 100644 index 000000000..d964cebe2 --- /dev/null +++ b/pos_timesheet/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Mohammed Dilshad Tk (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import models diff --git a/pos_timesheet/__manifest__.py b/pos_timesheet/__manifest__.py new file mode 100644 index 000000000..38a13f043 --- /dev/null +++ b/pos_timesheet/__manifest__.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Mohammed Dilshad Tk (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +{ + 'name': 'POS Timesheet', + 'version': '15.0.1.0.0', + 'category': 'Point of Sale', + 'summary': """Efficiently track employees work hours in POS.""", + 'description': """This module enhances the Point of Sale (POS) + functionality by automatically calculating timesheet for employees based + on their activities in the POS.""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['point_of_sale', 'hr_timesheet', 'project'], + 'data': [ + 'views/pos_config_views.xml', + 'views/pos_session_view.xml', + ], + 'assets': { + 'point_of_sale.assets': [ + 'pos_timesheet/static/src/css/worked_hour_popup.css', + 'pos_timesheet/static/src/js/HeaderLockButton.js', + 'pos_timesheet/static/src/js/model.js', + 'pos_timesheet/static/src/js/Chrome.js', + 'pos_timesheet/static/src/js/Popups/ClosePosPopup.js', + 'pos_timesheet/static/src/js/Popups/WorkedHourPopup.js', + ], + 'web.assets_qweb': [ + 'pos_timesheet/static/src/xml/**/*', + ], + }, + 'images': ['static/description/banner.png'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/pos_timesheet/doc/RELEASE_NOTES.md b/pos_timesheet/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..41fa2dc68 --- /dev/null +++ b/pos_timesheet/doc/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +## Module + +#### 09.04.2024 +#### Version 15.0.1.0.0 +#### ADD + +- Initial commit for POS Timesheet diff --git a/pos_timesheet/models/__init__.py b/pos_timesheet/models/__init__.py new file mode 100644 index 000000000..217f63029 --- /dev/null +++ b/pos_timesheet/models/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Mohammed Dilshad Tk (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import account_analytic_line +from . import pos_config +from . import pos_session diff --git a/pos_timesheet/models/account_analytic_line.py b/pos_timesheet/models/account_analytic_line.py new file mode 100644 index 000000000..6e3791915 --- /dev/null +++ b/pos_timesheet/models/account_analytic_line.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Mohammed Dilshad Tk (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import fields, models + + +class AccountAnalyticLine(models.Model): + """Inherits the AccountAnalyticLine class for adding field""" + _inherit = 'account.analytic.line' + + pos_created = fields.Boolean(help="To filter records created via pos") diff --git a/pos_timesheet/models/pos_config.py b/pos_timesheet/models/pos_config.py new file mode 100644 index 000000000..8d8959708 --- /dev/null +++ b/pos_timesheet/models/pos_config.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Mohammed Dilshad Tk (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import fields, models + + +class PosConfig(models.Model): + """Inherits the PosConfig class for adding fields""" + _inherit = 'pos.config' + + time_log = fields.Boolean(string="Time Log", + help="Track employees timesheet in pos") + project_id = fields.Many2one( + 'project.project', + string="Project", + ondelete='cascade', + help="Project for the timesheet") diff --git a/pos_timesheet/models/pos_session.py b/pos_timesheet/models/pos_session.py new file mode 100644 index 000000000..9c54f65c4 --- /dev/null +++ b/pos_timesheet/models/pos_session.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Mohammed Dilshad Tk (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import api, fields, models, _ + + +class PosSession(models.Model): + """Inherits the PosSession class for adding fields and functions""" + _inherit = 'pos.session' + + task_id = fields.Many2one("project.task", string="Task", + help="Session Timesheet Task", + ondelete='cascade') + + @api.model_create_multi + def create(self, vals_list): + """Create Task for add timesheet""" + result = super().create(vals_list) + if result.config_id.module_pos_hr and result.config_id.time_log: + result.task_id = self.env['project.task'].create({ + 'name': result.name, + 'project_id': result.config_id.project_id.id, + 'company_id': result.config_id.company_id.id + }) + return result + + def _loader_params_account_analytic_line(self): + """Returns loader params for account""" + return { + 'search_params': { + 'domain': [('task_id', '=', self.task_id.id), + ('date', '=', fields.Date.context_today(self))], + 'fields': ['employee_id', 'unit_amount'], + }, + } + + def set_timesheet(self, data): + """Update Timesheet of the employee""" + for timesheet in data: + if timesheet['workMinutes'] > 0: + hours = timesheet['workMinutes'] / 60 + session_id = self.browse(timesheet['sessionId']) + timestamp_seconds = timesheet['checkInTime'] / 1000 + date_time = fields.datetime.fromtimestamp(timestamp_seconds) + date_only = date_time.date() + sudo_timesheet = self.env['account.analytic.line'].sudo() + employee_timesheet = sudo_timesheet.search( + [('task_id', '=', session_id.task_id.id), + ('date', '=', date_only), + ('employee_id', '=', timesheet['cashierId'])], limit=1) + if employee_timesheet: + employee_timesheet.unit_amount += hours + employee_timesheet.pos_created = True + else: + sudo_timesheet.create({ + 'task_id': session_id.task_id.id, + 'account_id': self.config_id.project_id. + analytic_account_id, + 'pos_created': True, + 'employee_id': timesheet['cashierId'], + 'name': session_id.name, + 'date': date_only, + 'unit_amount': hours + }) + return True + + def show_time_log(self): + """Show the task its contained timesheet for the session""" + return { + 'name': _('Time Log'), + 'type': 'ir.actions.act_window', + 'res_model': 'project.task', + 'view_mode': 'form', + 'res_id': self.task_id.id, + } diff --git a/pos_timesheet/static/description/assets/icons/check.png b/pos_timesheet/static/description/assets/icons/check.png new file mode 100755 index 000000000..c8e85f51d Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/check.png differ diff --git a/pos_timesheet/static/description/assets/icons/chevron.png b/pos_timesheet/static/description/assets/icons/chevron.png new file mode 100755 index 000000000..2089293d6 Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/chevron.png differ diff --git a/pos_timesheet/static/description/assets/icons/cogs.png b/pos_timesheet/static/description/assets/icons/cogs.png new file mode 100755 index 000000000..95d0bad62 Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/cogs.png differ diff --git a/pos_timesheet/static/description/assets/icons/consultation.png b/pos_timesheet/static/description/assets/icons/consultation.png new file mode 100755 index 000000000..8319d4baa Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/consultation.png differ diff --git a/pos_timesheet/static/description/assets/icons/ecom-black.png b/pos_timesheet/static/description/assets/icons/ecom-black.png new file mode 100755 index 000000000..a9385ff13 Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/ecom-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/education-black.png b/pos_timesheet/static/description/assets/icons/education-black.png new file mode 100755 index 000000000..3eb09b27b Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/education-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/hotel-black.png b/pos_timesheet/static/description/assets/icons/hotel-black.png new file mode 100755 index 000000000..130f613be Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/hotel-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/license.png b/pos_timesheet/static/description/assets/icons/license.png new file mode 100755 index 000000000..a5869797e Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/license.png differ diff --git a/pos_timesheet/static/description/assets/icons/lifebuoy.png b/pos_timesheet/static/description/assets/icons/lifebuoy.png new file mode 100755 index 000000000..658d56ccc Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/lifebuoy.png differ diff --git a/pos_timesheet/static/description/assets/icons/manufacturing-black.png b/pos_timesheet/static/description/assets/icons/manufacturing-black.png new file mode 100755 index 000000000..697eb0e9f Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/manufacturing-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/pos-black.png b/pos_timesheet/static/description/assets/icons/pos-black.png new file mode 100755 index 000000000..97c0f90c1 Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/pos-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/puzzle.png b/pos_timesheet/static/description/assets/icons/puzzle.png new file mode 100755 index 000000000..65cf854e7 Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/puzzle.png differ diff --git a/pos_timesheet/static/description/assets/icons/restaurant-black.png b/pos_timesheet/static/description/assets/icons/restaurant-black.png new file mode 100755 index 000000000..4a35eb939 Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/restaurant-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/service-black.png b/pos_timesheet/static/description/assets/icons/service-black.png new file mode 100755 index 000000000..301ab51cb Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/service-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/trading-black.png b/pos_timesheet/static/description/assets/icons/trading-black.png new file mode 100755 index 000000000..9398ba2f1 Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/trading-black.png differ diff --git a/pos_timesheet/static/description/assets/icons/training.png b/pos_timesheet/static/description/assets/icons/training.png new file mode 100755 index 000000000..884ca024d Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/training.png differ diff --git a/pos_timesheet/static/description/assets/icons/update.png b/pos_timesheet/static/description/assets/icons/update.png new file mode 100755 index 000000000..ecbc5a01a Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/update.png differ diff --git a/pos_timesheet/static/description/assets/icons/user.png b/pos_timesheet/static/description/assets/icons/user.png new file mode 100755 index 000000000..6ffb23d9f Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/user.png differ diff --git a/pos_timesheet/static/description/assets/icons/wrench.png b/pos_timesheet/static/description/assets/icons/wrench.png new file mode 100755 index 000000000..6c04dea0f Binary files /dev/null and b/pos_timesheet/static/description/assets/icons/wrench.png differ diff --git a/pos_timesheet/static/description/assets/misc/categories.png b/pos_timesheet/static/description/assets/misc/categories.png new file mode 100755 index 000000000..bedf1e0b1 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/categories.png differ diff --git a/pos_timesheet/static/description/assets/misc/check-box.png b/pos_timesheet/static/description/assets/misc/check-box.png new file mode 100755 index 000000000..42caf24b9 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/check-box.png differ diff --git a/pos_timesheet/static/description/assets/misc/compass.png b/pos_timesheet/static/description/assets/misc/compass.png new file mode 100755 index 000000000..d5fed8faa Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/compass.png differ diff --git a/pos_timesheet/static/description/assets/misc/corporate.png b/pos_timesheet/static/description/assets/misc/corporate.png new file mode 100755 index 000000000..2eb13edbf Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/corporate.png differ diff --git a/pos_timesheet/static/description/assets/misc/customer-support.png b/pos_timesheet/static/description/assets/misc/customer-support.png new file mode 100755 index 000000000..79efc72ed Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/customer-support.png differ diff --git a/pos_timesheet/static/description/assets/misc/cybrosys-logo.png b/pos_timesheet/static/description/assets/misc/cybrosys-logo.png new file mode 100755 index 000000000..cc3cc0ccf Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/cybrosys-logo.png differ diff --git a/pos_timesheet/static/description/assets/misc/features.png b/pos_timesheet/static/description/assets/misc/features.png new file mode 100755 index 000000000..b41769f77 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/features.png differ diff --git a/pos_timesheet/static/description/assets/misc/logo.png b/pos_timesheet/static/description/assets/misc/logo.png new file mode 100755 index 000000000..478462d3e Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/logo.png differ diff --git a/pos_timesheet/static/description/assets/misc/pictures.png b/pos_timesheet/static/description/assets/misc/pictures.png new file mode 100755 index 000000000..56d255fe9 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/pictures.png differ diff --git a/pos_timesheet/static/description/assets/misc/pie-chart.png b/pos_timesheet/static/description/assets/misc/pie-chart.png new file mode 100755 index 000000000..426e05244 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/pie-chart.png differ diff --git a/pos_timesheet/static/description/assets/misc/right-arrow.png b/pos_timesheet/static/description/assets/misc/right-arrow.png new file mode 100755 index 000000000..730984a06 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/right-arrow.png differ diff --git a/pos_timesheet/static/description/assets/misc/star.png b/pos_timesheet/static/description/assets/misc/star.png new file mode 100755 index 000000000..2eb9ab29f Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/star.png differ diff --git a/pos_timesheet/static/description/assets/misc/support.png b/pos_timesheet/static/description/assets/misc/support.png new file mode 100755 index 000000000..4f18b8b82 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/support.png differ diff --git a/pos_timesheet/static/description/assets/misc/whatsapp.png b/pos_timesheet/static/description/assets/misc/whatsapp.png new file mode 100755 index 000000000..d513a5356 Binary files /dev/null and b/pos_timesheet/static/description/assets/misc/whatsapp.png differ diff --git a/pos_timesheet/static/description/assets/modules/module_1.png b/pos_timesheet/static/description/assets/modules/module_1.png new file mode 100755 index 000000000..09e2d45b2 Binary files /dev/null and b/pos_timesheet/static/description/assets/modules/module_1.png differ diff --git a/pos_timesheet/static/description/assets/modules/module_2.png b/pos_timesheet/static/description/assets/modules/module_2.png new file mode 100755 index 000000000..94c023fe1 Binary files /dev/null and b/pos_timesheet/static/description/assets/modules/module_2.png differ diff --git a/pos_timesheet/static/description/assets/modules/module_3.png b/pos_timesheet/static/description/assets/modules/module_3.png new file mode 100755 index 000000000..6547c3081 Binary files /dev/null and b/pos_timesheet/static/description/assets/modules/module_3.png differ diff --git a/pos_timesheet/static/description/assets/modules/module_4.png b/pos_timesheet/static/description/assets/modules/module_4.png new file mode 100755 index 000000000..0bbad468d Binary files /dev/null and b/pos_timesheet/static/description/assets/modules/module_4.png differ diff --git a/pos_timesheet/static/description/assets/modules/module_5.png b/pos_timesheet/static/description/assets/modules/module_5.png new file mode 100755 index 000000000..3ad04ecfd Binary files /dev/null and b/pos_timesheet/static/description/assets/modules/module_5.png differ diff --git a/pos_timesheet/static/description/assets/modules/module_6.png b/pos_timesheet/static/description/assets/modules/module_6.png new file mode 100755 index 000000000..84a21072b Binary files /dev/null and b/pos_timesheet/static/description/assets/modules/module_6.png differ diff --git a/pos_timesheet/static/description/assets/screenshots/1img.png b/pos_timesheet/static/description/assets/screenshots/1img.png new file mode 100644 index 000000000..1695ed5d6 Binary files /dev/null and b/pos_timesheet/static/description/assets/screenshots/1img.png differ diff --git a/pos_timesheet/static/description/assets/screenshots/2img.png b/pos_timesheet/static/description/assets/screenshots/2img.png new file mode 100644 index 000000000..cd6460014 Binary files /dev/null and b/pos_timesheet/static/description/assets/screenshots/2img.png differ diff --git a/pos_timesheet/static/description/assets/screenshots/3img.png b/pos_timesheet/static/description/assets/screenshots/3img.png new file mode 100644 index 000000000..69dadbb1a Binary files /dev/null and b/pos_timesheet/static/description/assets/screenshots/3img.png differ diff --git a/pos_timesheet/static/description/assets/screenshots/4img.png b/pos_timesheet/static/description/assets/screenshots/4img.png new file mode 100644 index 000000000..323a281c6 Binary files /dev/null and b/pos_timesheet/static/description/assets/screenshots/4img.png differ diff --git a/pos_timesheet/static/description/assets/screenshots/5img.png b/pos_timesheet/static/description/assets/screenshots/5img.png new file mode 100644 index 000000000..2e2ed306e Binary files /dev/null and b/pos_timesheet/static/description/assets/screenshots/5img.png differ diff --git a/pos_timesheet/static/description/assets/screenshots/v15-hero.gif b/pos_timesheet/static/description/assets/screenshots/v15-hero.gif new file mode 100644 index 000000000..152a3e644 Binary files /dev/null and b/pos_timesheet/static/description/assets/screenshots/v15-hero.gif differ diff --git a/pos_timesheet/static/description/banner.png b/pos_timesheet/static/description/banner.png new file mode 100644 index 000000000..1e02bd16a Binary files /dev/null and b/pos_timesheet/static/description/banner.png differ diff --git a/pos_timesheet/static/description/icon.png b/pos_timesheet/static/description/icon.png new file mode 100644 index 000000000..0bbe2a198 Binary files /dev/null and b/pos_timesheet/static/description/icon.png differ diff --git a/pos_timesheet/static/description/index.html b/pos_timesheet/static/description/index.html new file mode 100755 index 000000000..422195a3f --- /dev/null +++ b/pos_timesheet/static/description/index.html @@ -0,0 +1,524 @@ +
+ +
+ +
+
+ Community +
+
+ Enterprise +
+
+ Odoo.sh +
+
+
+ +
+
+
+ +

+ POS Timesheet +

+

Add Timesheet For + POS

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

Explore This + Module

+
+ + + +
+
+ +
+

Overview +

+
+
+
This module enhances the Point of Sale (POS) + functionality by automatically calculating timesheet for employees based + on their activities in the POS. +
+
+ + +
+
+ +
+

Features +

+
+
+
+
+ + Add Timesheet for employees based on + their activities in the POS +
+
+ + Track Employee activity in POS offline mode +
+
+ + Using Project and Tasks +
+
+ + View worked hours in the POS menu +
+
+
+ + +
+
+ +
+

Screenshots +

+
+
+
+
+

Enable Multi Employee + per Session

+

Enable Multi Employee + per Session, then the + Time Log option will be visible in the + Configuration + Settings of POS and you can also set a + project for the timesheet.

+ +
+
+

View total work + hours, + check-in time and time worked +

+

The employee can view + the total work hours, + last check-in time, and time worked since + the last check-in time by clicking the clock + icon in the header.

+ +
+
+

Timelog smart tab

+

You can easily navigate + to the task + associated with the session by clicking + timelog smart tab. +

+ +
+
+

You can see all the + employees timesheet in + the task timesheet tab

+ +
+
+
+ + +
+
+ +
+

Related + Products +

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

Our Services +

+
+
+
+
+
+ +
+
+ Odoo + Customization
+
+
+
+ +
+
+ Odoo + Implementation
+
+
+
+ +
+
Odoo + Support
+
+
+
+ +
+
+ Hire Odoo Developer
+
+
+
+ +
+
+ Odoo + Integration
+
+
+
+ +
+
+ Odoo + Migration
+
+
+
+ +
+
+ Odoo + Consultancy
+
+
+
+ +
+
+ Odoo + Implementation
+
+
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + +
+
+ +
+

Our + Industries +

+
+
+
+
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+
+
+ + +
+
+ +
+

Support +

+
+
+
+
+
+
+ +
+
+

Need Help?

+

Got questions or need help? Get in touch.

+ +

+ odoo@cybrosys.com

+
+
+
+
+
+
+
+ +
+
+

WhatsApp

+

Say hi to us on WhatsApp!

+ +

+91 + 8606827707

+
+
+
+
+
+
+
+ +
+
+
+ diff --git a/pos_timesheet/static/src/css/worked_hour_popup.css b/pos_timesheet/static/src/css/worked_hour_popup.css new file mode 100644 index 000000000..fd5cdb9f1 --- /dev/null +++ b/pos_timesheet/static/src/css/worked_hour_popup.css @@ -0,0 +1,12 @@ +.total-worked { + color: #714B67; + font-weight: bold; +} +.current-worked { + color: #017e84; + font-weight: bold; + margin-left: 10px; +} +.checked-in { + color: #5eb937; +} diff --git a/pos_timesheet/static/src/js/Chrome.js b/pos_timesheet/static/src/js/Chrome.js new file mode 100644 index 000000000..3b1b9c0db --- /dev/null +++ b/pos_timesheet/static/src/js/Chrome.js @@ -0,0 +1,34 @@ +/** @odoo-module **/ +import Chrome from "point_of_sale.Chrome"; +import Registries from "point_of_sale.Registries"; +const { _lt } = require('@web/core/l10n/translation'); +const PosTimeSheetChrome = (Chrome) => + class extends Chrome { + /** + * @override + * Add timesheet in to server when go to backend + */ + async onClickClock(){ + await this.showPopup('WorkedHourPopup'); + } + async _closePos() { + if (this.env.pos.config.module_pos_hr & this.env.pos.config.time_log) { + return this.env.pos._handleTimesheet(() => super._closePos(...arguments)); + } else { + return await super._closePos(...arguments); + } + } + + /** + *@override + * Save Worked hours with CheckoutTime and WorkedMinutes in localStorage + * on beforeunload - closing the browser, reloading or going to other page. + */ + _onBeforeUnload() { + super._onBeforeUnload(...arguments); + const timesheetData = this.env.pos.prepareTimesheet(); + localStorage.setItem('timesheetData', JSON.stringify(timesheetData)); + } + }; + +Registries.Component.extend(Chrome, PosTimeSheetChrome); diff --git a/pos_timesheet/static/src/js/HeaderLockButton.js b/pos_timesheet/static/src/js/HeaderLockButton.js new file mode 100644 index 000000000..3495add10 --- /dev/null +++ b/pos_timesheet/static/src/js/HeaderLockButton.js @@ -0,0 +1,15 @@ +odoo.define('pos_timesheet.PosHeaderLockButton', function(require) { + 'use strict'; + const HeaderLockButton = require('point_of_sale.HeaderLockButton'); + const Registries = require('point_of_sale.Registries'); + /** Extends HeaderLockButton to super showLoginScreen function */ + const PosHeaderLockButton = HeaderLockButton => + class extends HeaderLockButton { + async showLoginScreen() { + await this.env.pos._handleTimesheet(this.env.pos.get('cashier')) + super.showLoginScreen() + } + }; + Registries.Component.extend(HeaderLockButton, PosHeaderLockButton); + return HeaderLockButton; +}); diff --git a/pos_timesheet/static/src/js/Popups/ClosePosPopup.js b/pos_timesheet/static/src/js/Popups/ClosePosPopup.js new file mode 100644 index 000000000..93ec1cac9 --- /dev/null +++ b/pos_timesheet/static/src/js/Popups/ClosePosPopup.js @@ -0,0 +1,23 @@ +/** @odoo-module **/ + +import ClosePosPopup from "point_of_sale.ClosePosPopup"; +import Registries from "point_of_sale.Registries"; + +const NewClosePosPopup = (ClosePosPopup) => + class extends ClosePosPopup { + + /** + * @override + * Add timesheet in to server when Close Session. + */ + async closeSession() { + if (this.env.pos.config.module_pos_hr & this.env.pos.config.time_log) { + this.env.pos._handleTimesheet(this.env.pos.get('cashier')) + return super.closeSession(...arguments) + } else { + return await super.closeSession(...arguments); + } + } + }; + +Registries.Component.extend(ClosePosPopup, NewClosePosPopup); diff --git a/pos_timesheet/static/src/js/Popups/WorkedHourPopup.js b/pos_timesheet/static/src/js/Popups/WorkedHourPopup.js new file mode 100644 index 000000000..aeb334ab5 --- /dev/null +++ b/pos_timesheet/static/src/js/Popups/WorkedHourPopup.js @@ -0,0 +1,101 @@ +odoo.define('point_of_sale.WorkedHourPopup', function(require) { + 'use strict'; +const AbstractAwaitablePopup = require('point_of_sale.AbstractAwaitablePopup'); +const Registries = require('point_of_sale.Registries'); +const { _lt } = require('@web/core/l10n/translation'); +class WorkedHourPopup extends AbstractAwaitablePopup { + /** + * @super + * Sets up: SetInterval to show realtime worked time. + */ + setup() { + super.setup(...arguments); + this.state = owl.hooks.useState({ + workedTime: '', + totalWorkedTime: '' + }) + owl.hooks.onMounted(() => { + this.workedTime(); + this.totalWorkedTime(); + this.interval = setInterval(()=>{ + this.workedTime(); + this.totalWorkedTime(); + }, 1000); + }) + owl.hooks.onWillUnmount(() => { + clearInterval(this.interval); + }) + + } + /** + * Getter for the check-in time. + * @returns {string} Formatted check-in time. + */ + get checkInTime() { + const timesheetData = JSON.parse(localStorage.getItem('timesheetData')); + const checkInTime = timesheetData ? timesheetData.at(-1)['checkInTime'] : Date.now(); + const formattedDate = new Intl.DateTimeFormat('en-US', { + hour: '2-digit', + minute: '2-digit', + hour12: true + }).format(checkInTime); + return formattedDate; + } + + /** + * Getter for the current worked time. + * Assign {string} Formatted current worked time in to this.state.workedTime. + */ + workedTime() { + const [hours, minutes, seconds] = this.currentWorkedTime(); + this.state.workedTime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; + } + + /** + * Getter for the total today's worked time. + * Assign {string} Formatted total worked time in to this.state.totalWorkedTime. + */ + totalWorkedTime() { + let minutes = 0; + const workerData = this.env.pos.workedTime; + const timesheetData = JSON.parse(localStorage.getItem('timesheetData')); + const cashierId = this.env.pos.get_cashier().id; + if (timesheetData) { + const cashierLocalTimesheet = timesheetData.filter(data => data.cashierId === cashierId && data?.workMinutes); + minutes += cashierLocalTimesheet.reduce((sum, data) => sum + data.workMinutes, 0); + } + const cashierData = workerData.find(data => data['cashierId'] === cashierId); + minutes += cashierData ? parseInt(cashierData['minutes']) : 0; + const [currentHours, currentMinutes, seconds] = this.currentWorkedTime(); + let hours = currentHours; + minutes += currentMinutes; + const extraHour = Math.floor(minutes / 60); + minutes %= 60; + hours += extraHour; + + this.state.totalWorkedTime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; + } + + /** + * Retrieves the current worked time. + * @returns {Array} Array containing hours and minutes of current worked time. + */ + currentWorkedTime() { + const timesheetData = JSON.parse(localStorage.getItem('timesheetData')); + const checkInTime = timesheetData ? timesheetData.at(-1)['checkInTime'] : Date.now(); + const currentTime = Date.now(); + const differenceMs = Math.abs(currentTime - checkInTime); + const hours = Math.floor(differenceMs / (1000 * 60 * 60)); + const minutes = Math.floor((differenceMs % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((differenceMs % (1000 * 60)) / 1000); + return [hours, minutes, seconds]; + }} +WorkedHourPopup.template = "pos_timesheet.WorkedHourPopup"; +WorkedHourPopup.defaultProps = { + cancelText: _lt("Cancel"), + title: _lt("Worked Hours"), + confirmKey: false, +}; +Registries.Component.add(WorkedHourPopup); +return WorkedHourPopup; +}); diff --git a/pos_timesheet/static/src/js/model.js b/pos_timesheet/static/src/js/model.js new file mode 100644 index 000000000..ced02819a --- /dev/null +++ b/pos_timesheet/static/src/js/model.js @@ -0,0 +1,163 @@ +odoo.define('pos_timesheet.pos', function(require) { + "use strict"; + const models = require('point_of_sale.models'); + const { DateTime } = luxon; + var super_pos_model = models.PosModel.prototype; + models.PosModel = models.PosModel.extend({ + /** @override + * load employees timesheet of this session + */ + after_load_server_data: async function() { + await this._processData(); + return super_pos_model.after_load_server_data.apply(this, arguments) + }, + _processData: async function() { + var self = this + if (this.config.module_pos_hr && this.config.time_log) { + this.models.push({ + model: 'account.analytic.line', + fields: ['name', 'employee_id', 'id', 'unit_amount', 'date', 'task_id', 'pos_created'], + loaded: function(self, analytic_lines) { + self.timesheet = analytic_lines; + }, + }); + var employee_list = []; + for (const employee in this.employees){ + employee_list.push(this.employees[employee].id) + } + var today = DateTime.local().c['day'] + '/' + + DateTime.local().c['month'] + '/' + DateTime.local().c['year'] + var fields = ['employee_id', 'id', 'unit_amount',]; + var result = await this.env.services.rpc({ + model: 'account.analytic.line', + method: 'search_read', + kwargs: { + domain: [['employee_id', 'in', employee_list], + ['pos_created', '=', true], + ['date', '=', today]], + fields + }, + }) + this.timesheet = result; + this.workedTime = this.getWorkedTime(); + } + }, + /** Retrieves worked time data and sets it to the POS instance. */ + getWorkedTime: function() { + const datas = this.timesheet; + const workedTime = datas.map(data => ({ + 'cashierId': data['employee_id'][0], + 'minutes': Math.floor(data['unit_amount'] * 60) + })); + return workedTime; + }, + /** + * @override + * If the 'Multi Employee persession' and 'Time Log' enabled in POS configuration, + * handles timesheet processing before setting cashier. + * @param {Object} employee - Employee object representing the cashier. + */ + set_cashier: function(employee) { + this.super_set_cashier = super_pos_model.set_cashier.apply(this, arguments); + if (this.config.module_pos_hr && this.config.time_log) { + return this._handleTimesheet(this.get('cashier')); + } else { + return this.super_set_cashier; + } + }, + /** + * Handles timesheet processing asynchronously. + * Executes a callback function and handles timesheet operations based on the POS configuration. + * @param {Function} callback - Callback function to execute. + * @param {Object} employee - Employee object representing the cashier or null. + */ + _handleTimesheet: function(employee = null) { + const data = this.prepareTimesheet(); + return this.sendTimesheet(data).then(response => { + this.setTimesheet(response, employee); + }) + .catch(errData => { + this.setTimesheet(errData, employee); + }) + }, + /** + * Sets the timesheet data to localStorage. + * @param {Array} timesheetData - Timesheet data to set. + * @param {Object} employee - Employee object representing the cashier. + */ + setTimesheet: function(timesheetData, employee = null) { + if (employee) { + let cashierId; + if (employee.id) {cashierId = employee.id} + else {cashierId = null; } + const cashierData = { + cashierId: cashierId, + checkInTime: Date.now(), + sessionId: this.pos_session.id + }; + if (timesheetData) { + timesheetData.push(cashierData); + } else { + timesheetData = [cashierData]; + } + } + localStorage.setItem('timesheetData', JSON.stringify(timesheetData)); + }, + /** + * Sends timesheet data to the server. + * @param {Array} timesheetData - Timesheet data to send. + * @return {null} success or no timesheetData, if error {Object} timesheetData + */ + sendTimesheet: function(timesheetData) { + return new Promise((resolve, reject) => { + if (timesheetData) { + this.env.services.rpc({ + model: 'pos.session', + method: 'set_timesheet', + args: [ + [], timesheetData + ], + }).then(res => { + timesheetData.forEach(data => { + let index = this.workedTime.findIndex(item => item.cashierId === data.cashierId); + if (index !== -1) { + this.workedTime[index].minutes += data.workMinutes; + } else { + this.workedTime.push({ + cashierId: data.cashierId, + minutes: data.workMinutes + }); + } + }); + resolve(null); + }) + .catch(err => { + reject(timesheetData); + }); + } else { + resolve(null); + } + }); + }, + /** + * Prepares timesheet data for sending to the server. + * Checks for existing timesheet data in localStorage and adjusts work minutes. + * @returns {Array|null} Prepared timesheet data. + */ + prepareTimesheet: function() { + const timesheetData = JSON.parse(localStorage.getItem('timesheetData')); + if (timesheetData && timesheetData.length != 0) { + if (!timesheetData.at(-1).hasOwnProperty('checkOutTime')) { + timesheetData.at(-1)['checkOutTime'] = Date.now(); + const timeDiff = timesheetData.at(-1)['checkOutTime'] - timesheetData.at(-1)['checkInTime']; + timesheetData.at(-1)['workMinutes'] = Math.floor(timeDiff / (1000 * 60)); + if (timesheetData.at(-1)['workMinutes'] <= 0) { + timesheetData.pop(); + } + } + return timesheetData; + } + return null; + }, + }); +}); \ No newline at end of file diff --git a/pos_timesheet/static/src/xml/CashMoveButton.xml b/pos_timesheet/static/src/xml/CashMoveButton.xml new file mode 100644 index 000000000..d2cebd896 --- /dev/null +++ b/pos_timesheet/static/src/xml/CashMoveButton.xml @@ -0,0 +1,14 @@ + + + + + + +
+ + Cash In/Out +
+
+
+
diff --git a/pos_timesheet/static/src/xml/Popups/WorkedHourPopup.xml b/pos_timesheet/static/src/xml/Popups/WorkedHourPopup.xml new file mode 100644 index 000000000..36c2d49d8 --- /dev/null +++ b/pos_timesheet/static/src/xml/Popups/WorkedHourPopup.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/pos_timesheet/static/src/xml/TimeSheetButton.xml b/pos_timesheet/static/src/xml/TimeSheetButton.xml new file mode 100644 index 000000000..2122c45c1 --- /dev/null +++ b/pos_timesheet/static/src/xml/TimeSheetButton.xml @@ -0,0 +1,14 @@ + + + + +
+ + + +
+
+
+
diff --git a/pos_timesheet/views/pos_config_views.xml b/pos_timesheet/views/pos_config_views.xml new file mode 100644 index 000000000..970e816bc --- /dev/null +++ b/pos_timesheet/views/pos_config_views.xml @@ -0,0 +1,41 @@ + + + + + pos.config.view.form.inherit.pos.timesheet + pos.config + + + +
+
+ +
+
+ Time Log + +
+ Automatically record employees' work hours in the + timesheet +
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_timesheet/views/pos_session_view.xml b/pos_timesheet/views/pos_session_view.xml new file mode 100644 index 000000000..4e0112149 --- /dev/null +++ b/pos_timesheet/views/pos_session_view.xml @@ -0,0 +1,19 @@ + + + + pos.session.view.form.inherit.pos.timesheet + pos.session + + + + + + + + + +