diff --git a/.gitignore b/.gitignore index ba7466050..0420d9dd6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,11 +14,11 @@ dist/ downloads/ eggs/ .eggs/ -lib/ lib64/ parts/ sdist/ var/ +*.pyc *.egg-info/ .installed.cfg *.egg diff --git a/access_restriction_by_ip/README.rst b/access_restriction_by_ip/README.rst new file mode 100644 index 000000000..fcff8b126 --- /dev/null +++ b/access_restriction_by_ip/README.rst @@ -0,0 +1,17 @@ +Access Restriction By IP V10 +============================ + +This module will restrict users access to his account from the specified IP only. If user access his +account from non-specified IP, login will be restricted and a warning message will be displayed in +login page. + +If no IP is specified for a user, then there will not be restriction by IP. He can access from any IP. + + +Credits +======= +Cybrosys Techno Solutions + +Author +------ +* Niyas Raphy diff --git a/access_restriction_by_ip/__init__.py b/access_restriction_by_ip/__init__.py new file mode 100644 index 000000000..34ede4b19 --- /dev/null +++ b/access_restriction_by_ip/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Niyas Raphy() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import controllers +import models + diff --git a/access_restriction_by_ip/__manifest__.py b/access_restriction_by_ip/__manifest__.py new file mode 100644 index 000000000..e771bbeb1 --- /dev/null +++ b/access_restriction_by_ip/__manifest__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Niyas Raphy() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Access Restriction By IP', + 'summary': """User Can Access His Account Only From Specified IP Address""", + 'version': '10.0.1.0.0', + 'description': """User Can Access His Account Only From Specified IP Address""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': 'http://www.cybrosys.com', + 'category': 'Tools', + 'depends': ['base', 'mail'], + 'license': 'AGPL-3', + 'data': [ + 'views/allowed_ips_view.xml', + ], + 'images': ['static/description/banner.jpg'], + 'demo': [], + 'installable': True, + 'auto_install': False, +} diff --git a/access_restriction_by_ip/controllers/__init__.py b/access_restriction_by_ip/controllers/__init__.py new file mode 100644 index 000000000..d9f35f393 --- /dev/null +++ b/access_restriction_by_ip/controllers/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Niyas Raphy() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import main diff --git a/access_restriction_by_ip/controllers/main.py b/access_restriction_by_ip/controllers/main.py new file mode 100644 index 000000000..9a6f1d71e --- /dev/null +++ b/access_restriction_by_ip/controllers/main.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Niyas Raphy() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo.addons.web.controllers import main +from odoo.http import request +from odoo.exceptions import Warning +import odoo +import odoo.modules.registry +from odoo.tools.translate import _ +from odoo import http + + +class Home(main.Home): + + @http.route('/web/login', type='http', auth="public") + def web_login(self, redirect=None, **kw): + main.ensure_db() + request.params['login_success'] = False + if request.httprequest.method == 'GET' and redirect and request.session.uid: + return http.redirect_with_hash(redirect) + + if not request.uid: + request.uid = odoo.SUPERUSER_ID + + values = request.params.copy() + try: + values['databases'] = http.db_list() + except odoo.exceptions.AccessDenied: + values['databases'] = None + if request.httprequest.method == 'POST': + old_uid = request.uid + ip_address = request.httprequest.environ['REMOTE_ADDR'] + if request.params['login']: + user_rec = request.env['res.users'].sudo().search([('login', '=', request.params['login'])]) + if user_rec.allowed_ips: + ip_list = [] + for rec in user_rec.allowed_ips: + ip_list.append(rec.ip_address) + if ip_address in ip_list: + uid = request.session.authenticate(request.session.db, request.params['login'], request.params['password']) + if uid is not False: + request.params['login_success'] = True + if not redirect: + redirect = '/web' + return http.redirect_with_hash(redirect) + request.uid = old_uid + values['error'] = _("Wrong login/password") + request.uid = old_uid + values['error'] = _("Not allowed to login from this IP") + else: + uid = request.session.authenticate(request.session.db, request.params['login'], + request.params['password']) + if uid is not False: + request.params['login_success'] = True + if not redirect: + redirect = '/web' + return http.redirect_with_hash(redirect) + request.uid = old_uid + values['error'] = _("Wrong login/password") + + return request.render('web.login', values) diff --git a/access_restriction_by_ip/models/__init__.py b/access_restriction_by_ip/models/__init__.py new file mode 100644 index 000000000..2968d31fe --- /dev/null +++ b/access_restriction_by_ip/models/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Niyas Raphy() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import allowed_ips + diff --git a/access_restriction_by_ip/models/allowed_ips.py b/access_restriction_by_ip/models/allowed_ips.py new file mode 100644 index 000000000..4538ea310 --- /dev/null +++ b/access_restriction_by_ip/models/allowed_ips.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Niyas Raphy() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields + + +class ResUsersInherit(models.Model): + _inherit = 'res.users' + + allowed_ips = fields.One2many('allowed.ips', 'users_ip', string='IP') + + +class AllowedIPs(models.Model): + _name = 'allowed.ips' + + users_ip = fields.Many2one('res.users', string='IP') + ip_address = fields.Char(string='Allowed IP') diff --git a/access_restriction_by_ip/static/description/access_non_set_ip.png b/access_restriction_by_ip/static/description/access_non_set_ip.png new file mode 100644 index 000000000..1b8f41526 Binary files /dev/null and b/access_restriction_by_ip/static/description/access_non_set_ip.png differ diff --git a/access_restriction_by_ip/static/description/banner.jpg b/access_restriction_by_ip/static/description/banner.jpg new file mode 100644 index 000000000..f5bbd4859 Binary files /dev/null and b/access_restriction_by_ip/static/description/banner.jpg differ diff --git a/access_restriction_by_ip/static/description/cybro_logo.png b/access_restriction_by_ip/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/access_restriction_by_ip/static/description/cybro_logo.png differ diff --git a/access_restriction_by_ip/static/description/icon.png b/access_restriction_by_ip/static/description/icon.png new file mode 100644 index 000000000..401fd1ed3 Binary files /dev/null and b/access_restriction_by_ip/static/description/icon.png differ diff --git a/access_restriction_by_ip/static/description/index.html b/access_restriction_by_ip/static/description/index.html new file mode 100644 index 000000000..9f03c006e --- /dev/null +++ b/access_restriction_by_ip/static/description/index.html @@ -0,0 +1,69 @@ +
+
+

Access Restriction By IP

+

User can access his account only from specified IP's

+

Cybrosys Technologies

+
+

This module will restrict the users access to his account from specified IP address only

+
+
+

Features:

+
    +
  •    Administrator can set a IP or a group of IP address for each users
  • +
  •    Users can access their account only from the specified IP's
  • +
  •    Accessing system from a non-specified IP will restrict the user login
  • +
  •    A warning message will be displayed
  • +
  •    If no IP is set to user means there is no any restriction by IP
  • +
  •    IP Address for each users can be set from users form view
  • +
+
+
+
+ +
+
+

Setting IP address for User

+
+

Setting IP address for user from users form view

+

User will be able to access his account only from this IP's

+
+ +
+
+

User accessing his account

+
+

On accessing account from a non specified IP

+
+ +
+

Warning message will be displayed

+
+
+
+ + +
+

Need Any Help?

+ +
diff --git a/access_restriction_by_ip/static/description/index.html~ b/access_restriction_by_ip/static/description/index.html~ new file mode 100644 index 000000000..7f747cbbb --- /dev/null +++ b/access_restriction_by_ip/static/description/index.html~ @@ -0,0 +1,82 @@ +
+
+

Birthday Notification By E-mail

+

This module will wish the employees on their birthday

+ +

Author : Cybrosys Techno Solutions , www.cybrosys.com

+
+

Features:

+
    +
  •    Adds a cron job to invoke email
  • +
  •    Adds an email template
  • +
+
+
+
+ +
+
+
+

Overview

+

+ HR departments need not worry to wish their employees for their Birthday. In this module we have included the feature to send an email Birthday notification to the employee. +

+
+
+
+ +
+
+

Employee Form

+
+

+ ☛ Give Date of Birth for employee.
+ ☛ Give work email.
+

+
+ +
+
+
+
+ +
+
+

Email Template

+
+

+ ☛ The cron job will invoke the email
+ ☛ Email template is very simple
+

+
+ +
+
+
+
+ +
+

Need Any Help?

+ +
diff --git a/access_restriction_by_ip/static/description/user_set_ip.png b/access_restriction_by_ip/static/description/user_set_ip.png new file mode 100644 index 000000000..e6f03f8d1 Binary files /dev/null and b/access_restriction_by_ip/static/description/user_set_ip.png differ diff --git a/access_restriction_by_ip/views/allowed_ips_view.xml b/access_restriction_by_ip/views/allowed_ips_view.xml new file mode 100644 index 000000000..3b7f244d4 --- /dev/null +++ b/access_restriction_by_ip/views/allowed_ips_view.xml @@ -0,0 +1,21 @@ + + + + + res.users + res.users + + + + + + + + + + + + + + + diff --git a/account_budget_report/__init__.py b/account_budget_report/__init__.py new file mode 100644 index 000000000..a425858d5 --- /dev/null +++ b/account_budget_report/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models +import reports diff --git a/account_budget_report/__manifest__.py b/account_budget_report/__manifest__.py new file mode 100644 index 000000000..4851af47a --- /dev/null +++ b/account_budget_report/__manifest__.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Account Budget Report', + 'version': '10.0.1.0.0', + 'summary': """Enables Budget Summary Report""", + 'description': """Providing budget analysis through different pdf reports. So we can take + quick budget analysis.""", + 'category': 'Accounting', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'account_budget'], + 'data': [ + 'views/budget_report_view.xml', + 'views/budget_summary_view.xml', + 'views/budget_print_view.xml', + 'views/analytic_budget_report_view.xml', + 'reports/account_budget_report.xml', + 'reports/report_crossovered_budget.xml', + 'reports/report_analytic_account_budget.xml', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'demo': [], + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/account_budget_report/models/__init__.py b/account_budget_report/models/__init__.py new file mode 100644 index 000000000..021a338e4 --- /dev/null +++ b/account_budget_report/models/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import budget_report +import budget_summary +import budget +import analytic_budget_report + + diff --git a/account_budget_report/models/analytic_budget_report.py b/account_budget_report/models/analytic_budget_report.py new file mode 100644 index 000000000..f393f3dc3 --- /dev/null +++ b/account_budget_report/models/analytic_budget_report.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import time +from odoo import fields, models + + +class AccountBudgetAnalytic(models.TransientModel): + + _name = 'account.budget.analytic' + _description = 'Account Budget report for analytic account' + + date_from = fields.Date('Start of period', required=True, default=lambda *a: time.strftime('%Y-01-01')) + date_to = fields.Date('End of period', required=True, default=lambda *a: time.strftime('%Y-%m-%d')) + + def check_report(self): + data = self.read()[0] + active_ids = self.env.context.get('active_ids', []) + datas = { + 'ids': active_ids, + 'model': 'account.analytic.account', + 'form': data + } + datas['form']['ids'] = datas['ids'] + return self.env['report'].get_action([], 'account_budget_report.report_analytic_account_budget', data=datas) diff --git a/account_budget_report/models/budget.py b/account_budget_report/models/budget.py new file mode 100644 index 000000000..bfa1e3a05 --- /dev/null +++ b/account_budget_report/models/budget.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import time +from odoo import models, fields + + +class AccountBudgetCrossOverReport(models.TransientModel): + _name = "account.budget.cross.over.report" + _description = "Account Budget cross over report" + + date_from = fields.Date('Start of period', required=True, default=lambda *a: time.strftime('%Y-01-01')) + date_to = fields.Date('End of period', required=True, default=lambda *a: time.strftime('%Y-%m-%d')) + + def check_report(self): + data = self.read()[0] + active_ids = self.env.context.get('active_ids', []) + datas = { + 'ids': active_ids, + 'model': 'crossovered.budget', + 'form': data + } + datas['form']['ids'] = datas['ids'] + datas['form']['report'] = 'analytic-full' + return self.env['report'].get_action([], 'account_budget_report.report_cross_over_budget', data=datas) diff --git a/account_budget_report/models/budget_report.py b/account_budget_report/models/budget_report.py new file mode 100644 index 000000000..f5f7e487d --- /dev/null +++ b/account_budget_report/models/budget_report.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import time +from odoo import models, fields + + +class AccountBudgetAnalytic(models.TransientModel): + _name = 'account.budget.report' + _description = 'Account Budget report for analytic account' + + date_from = fields.Date('Start of period', required=True, default=lambda *a: time.strftime('%Y-01-01')) + date_to = fields.Date('End of period', required=True, default=lambda *a: time.strftime('%Y-%m-%d')) + + def check_report(self): + active_ids = self.env.context.get('active_ids', []) + data = self.read()[0] + datas = { + 'ids': active_ids, + 'model': 'account.budget.post', + 'form': data + } + datas['form']['ids'] = datas['ids'] + datas['form']['report'] = 'analytic-full' + return self.env['report'].get_action([], 'account_budget_report.report_budget', data=datas) + + diff --git a/account_budget_report/models/budget_summary.py b/account_budget_report/models/budget_summary.py new file mode 100644 index 000000000..4cd7fe8b7 --- /dev/null +++ b/account_budget_report/models/budget_summary.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import time +from odoo import models, fields + + +class AccountBudgetCrossOverSummaryReport(models.TransientModel): + _name = 'account.budget.cross.over.summary.report' + _description = 'Account Budget cross over summary report' + + date_from = fields.Date('Start of period', required=True, default=lambda *a: time.strftime('%Y-01-01')) + date_to = fields.Date('End of period', required=True, default=lambda *a: time.strftime('%Y-%m-%d')) + + def check_report(self): + data = self.read()[0] + active_ids = self.env.context.get('active_ids', []) + datas = { + 'ids': active_ids, + 'model': 'crossovered.budget', + 'form': data + } + datas['form']['ids'] = datas['ids'] + datas['form']['report'] = 'analytic-one' + return self.env['report'].get_action([], 'account_budget_report.report_cross_over_budget', data=datas) diff --git a/account_budget_report/reports/__init__.py b/account_budget_report/reports/__init__.py new file mode 100644 index 000000000..08af8422c --- /dev/null +++ b/account_budget_report/reports/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import budget_parser +import cross_overed_budget_report +import analytic_budget + diff --git a/account_budget_report/reports/account_budget_report.xml b/account_budget_report/reports/account_budget_report.xml new file mode 100644 index 000000000..4a8951c63 --- /dev/null +++ b/account_budget_report/reports/account_budget_report.xml @@ -0,0 +1,85 @@ + + + + + + \ No newline at end of file diff --git a/account_budget_report/reports/analytic_budget.py b/account_budget_report/reports/analytic_budget.py new file mode 100644 index 000000000..708ebc36a --- /dev/null +++ b/account_budget_report/reports/analytic_budget.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import time +from odoo.osv import osv +from odoo.report import report_sxw +from odoo.http import request + + +class AnalyticAccountBudgetReport(report_sxw.rml_parse): + def __init__(self, cr, uid, name, context): + super(AnalyticAccountBudgetReport, self).__init__(cr, uid, name, context=context) + self.localcontext.update({ + 'funct': self.funct, + 'funct_total': self.funct_total, + 'time': time, + }) + self.context = context + + def funct(self, object, form, ids=None, done=None, level=1): + if ids is None: + ids = {} + if not ids: + ids = self.ids + if not done: + done = {} + + global tot + tot = { + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + result = [] + accounts = request.env['account.analytic.account'].browse(object.id) + c_b_lines_obj = request.env['crossovered.budget.lines'] + obj_c_budget = request.env['crossovered.budget'] + + for account_id in accounts: + res = {} + b_line_ids = [] + for line in account_id.crossovered_budget_line: + b_line_ids.append(line.id) + if not b_line_ids: + return [] + d_from = form['date_from'] + d_to = form['date_to'] + self.cr.execute('SELECT DISTINCT(crossovered_budget_id) FROM ' + 'crossovered_budget_lines WHERE id =ANY(%s)', (b_line_ids,)) + budget_ids = self.cr.fetchall() + + context = {'wizard_date_from': d_from, 'wizard_date_to': d_to} + for i in range(0, len(budget_ids)): + budget_name = obj_c_budget.browse([budget_ids[i][0]]) + res = { + 'b_id': '-1', + 'a_id': '-1', + 'name': budget_name[0].name, + 'status': 1, + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + result.append(res) + + line_ids = c_b_lines_obj.search([('id', 'in', b_line_ids), + ('crossovered_budget_id', '=', budget_ids[i][0])]) + line_id = line_ids + tot_theo = tot_pln = tot_prac = tot_perc = 0 + + done_budget = [] + for line in line_id: + if line.id in b_line_ids: + theo = pract = 0.00 + theo = line.theoritical_amount + pract = line.practical_amount + if line.general_budget_id.id in done_budget: + for record in result: + if record['b_id'] == line.general_budget_id.id and \ + record['a_id'] == line.analytic_account_id.id: + record['theo'] += theo + record['pln'] += line.planned_amount + record['prac'] += pract + record['perc'] += line.percentage + tot_theo += theo + tot_pln += line.planned_amount + tot_prac += pract + tot_perc += line.percentage + else: + res1 = { + 'b_id': line.general_budget_id.id, + 'a_id': line.analytic_account_id.id, + 'name': line.general_budget_id.name, + 'status': 2, + 'theo': theo, + 'pln': line.planned_amount, + 'prac': pract, + 'perc': line.percentage + } + tot_theo += theo + tot_pln += line.planned_amount + tot_prac += pract + tot_perc += line.percentage + result.append(res1) + done_budget.append(line.general_budget_id.id) + else: + if line.general_budget_id.id in done_budget: + continue + else: + res1 = { + 'b_id': line.general_budget_id.id, + 'a_id': line.analytic_account_id.id, + 'name': line.general_budget_id.name, + 'status': 2, + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + result.append(res1) + done_budget.append(line.general_budget_id.id) + if tot_theo == 0.00: + tot_perc = 0.00 + else: + tot_perc = float(tot_prac / tot_theo) * 100 + + result[-(len(done_budget) + 1)]['theo'] = tot_theo + tot['theo'] += tot_theo + result[-(len(done_budget) + 1)]['pln'] = tot_pln + tot['pln'] += tot_pln + result[-(len(done_budget) + 1)]['prac'] = tot_prac + tot['prac'] += tot_prac + result[-(len(done_budget) + 1)]['perc'] = tot_perc + if tot['theo'] == 0.00: + tot['perc'] = 0.00 + else: + tot['perc'] = float(tot['prac'] / tot['theo']) * 100 + return result + + def funct_total(self, form): + result = [] + res = { + 'tot_theo': tot['theo'], + 'tot_pln': tot['pln'], + 'tot_prac': tot['prac'], + 'tot_perc': tot['perc'] + } + result.append(res) + return result + + +class ReportAnalyticAccountBudget(osv.AbstractModel): + _name = 'report.account_budget_report.report_analytic_account_budget' + _inherit = 'report.abstract_report' + _template = 'account_budget_report.report_analytic_account_budget' + _wrapped_report_class = AnalyticAccountBudgetReport diff --git a/account_budget_report/reports/budget_parser.py b/account_budget_report/reports/budget_parser.py new file mode 100644 index 000000000..90c7af443 --- /dev/null +++ b/account_budget_report/reports/budget_parser.py @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import time +from odoo.osv import osv +from odoo.report import report_sxw +from odoo.http import request + +tot = {} + + +class BudgetReport(report_sxw.rml_parse): + def __init__(self, cr, uid, name, context): + super(BudgetReport, self).__init__(cr, uid, name, context=context) + self.localcontext.update({ + 'funct': self.funct, + 'funct_total': self.funct_total, + 'time': time, + }) + self.context = context + + def funct(self, object, form, ids=None, done=None, level=1): + if ids is None: + ids = {} + if not ids: + ids = self.ids + if not done: + done = {} + global tot + tot = { + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + result = [] + + budgets = request.env['account.budget.post'].browse(object.id) + c_b_lines_obj = request.env['crossovered.budget.lines'] + acc_analytic_obj = request.env['account.analytic.account'] + for budget_id in budgets: + res = {} + budget_ids = [] + d_from = form['date_from'] + d_to = form['date_to'] + + for line in budget_id.crossovered_budget_line: + budget_ids.append(line.id) + + if not budget_ids: + return [] + self.cr.execute('SELECT DISTINCT(analytic_account_id) FROM ' + 'crossovered_budget_lines WHERE id = ANY(%s)', (budget_ids,)) + an_ids = self.cr.fetchall() + context = {'wizard_date_from': d_from, 'wizard_date_to': d_to} + for i in range(0, len(an_ids)): + if not an_ids[i][0]: + continue + analytic_name = acc_analytic_obj.browse(an_ids[i][0]) + res= { + 'b_id': '-1', + 'a_id': '-1', + 'name': analytic_name[0].name, + 'status': 1, + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + result.append(res) + line_ids = c_b_lines_obj.search([('id', 'in', budget_ids), ('analytic_account_id', '=', an_ids[i][0])]) + line_id = line_ids + tot_theo = tot_pln = tot_prac = tot_perc = 0.00 + + done_budget = [] + for line in line_id: + if line.id in budget_ids: + theo = pract = 0.00 + theo = line.theoritical_amount + pract = line.practical_amount + if line.general_budget_id.id in done_budget: + for record in result: + if record['b_id'] == line.general_budget_id.id and \ + record['a_id'] == line.analytic_account_id.id: + record['theo'] += theo + record['pln'] += line.planned_amount + record['prac'] += pract + if record['theo'] <> 0.00: + perc = (record['prac'] / record['theo']) * 100 + else: + perc = 0.00 + record['perc'] = perc + tot_theo += theo + tot_pln += line.planned_amount + tot_prac += pract + tot_perc += perc + else: + if theo <> 0.00: + perc = (pract / theo) * 100 + else: + perc = 0.00 + res1 = { + 'a_id': line.analytic_account_id.id, + 'b_id': line.general_budget_id.id, + 'name': line.general_budget_id.name, + 'status': 2, + 'theo': theo, + 'pln': line.planned_amount, + 'prac': pract, + 'perc': perc, + } + tot_theo += theo + tot_pln += line.planned_amount + tot_prac += pract + tot_perc += perc + if form['report'] == 'analytic-full': + result.append(res1) + done_budget.append(line.general_budget_id.id) + else: + + if line.general_budget_id.id in done_budget: + continue + else: + res1 = { + 'a_id': line.analytic_account_id.id, + 'b_id': line.general_budget_id.id, + 'name': line.general_budget_id.name, + 'status': 2, + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + if form['report'] == 'analytic-full': + result.append(res1) + done_budget.append(line.general_budget_id.id) + if tot_theo == 0.00: + tot_perc = 0.00 + else: + tot_perc = float(tot_prac / tot_theo) * 100 + if form['report'] == 'analytic-full': + result[-(len(done_budget) + 1)]['theo'] = tot_theo + tot['theo'] += tot_theo + result[-(len(done_budget) + 1)]['pln'] = tot_pln + tot['pln'] += tot_pln + result[-(len(done_budget) + 1)]['prac'] = tot_prac + tot['prac'] += tot_prac + result[-(len(done_budget) + 1)]['perc'] = tot_perc + else: + result[-1]['theo'] = tot_theo + tot['theo'] += tot_theo + result[-1]['pln'] = tot_pln + tot['pln'] += tot_pln + result[-1]['prac'] = tot_prac + tot['prac'] += tot_prac + result[-1]['perc'] = tot_perc + if tot['theo'] == 0.00: + tot['perc'] = 0.00 + else: + tot['perc'] = float(tot['prac'] / tot['theo']) * 100 + return result + + def funct_total(self, form): + result = [] + res = { + 'tot_theo': tot['theo'], + 'tot_pln': tot['pln'], + 'tot_prac': tot['prac'], + 'tot_perc': tot['perc'] + } + result.append(res) + return result + + +class ReportBudget(osv.AbstractModel): + _name = 'report.account_budget_report.report_budget' + _inherit = 'report.abstract_report' + _template = 'account_budget_report.report_budget' + _wrapped_report_class = BudgetReport diff --git a/account_budget_report/reports/cross_overed_budget_report.py b/account_budget_report/reports/cross_overed_budget_report.py new file mode 100644 index 000000000..4ff1c7418 --- /dev/null +++ b/account_budget_report/reports/cross_overed_budget_report.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import time +from odoo.osv import osv +from odoo.report import report_sxw +from odoo.http import request + + +class BudgetReport(report_sxw.rml_parse): + def __init__(self, cr, uid, name, context): + super(BudgetReport, self).__init__(cr, uid, name, context=context) + self.localcontext.update({ + 'funct': self.funct, + 'funct_total': self.funct_total, + 'time': time, + }) + self.context = context + + def funct(self, object, form, ids=None, done=None, level=1): + if ids is None: + ids = {} + if not ids: + ids = self.ids + if not done: + done = {} + global tot + tot = { + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + result = [] + + budgets = request.env['crossovered.budget'].browse(object.id) + c_b_lines_obj = request.env['crossovered.budget.lines'] + acc_analytic_obj = request.env['account.analytic.account'] + for budget_id in budgets: + res = {} + budget_lines = [] + budget_ids = [] + d_from = form['date_from'] + d_to = form['date_to'] + + for line in budget_id.crossovered_budget_line: + budget_ids.append(line.id) + + if not budget_ids: + return [] + + self.cr.execute('SELECT DISTINCT(analytic_account_id) FROM crossovered_budget_lines ' + 'WHERE id = ANY(%s)', (budget_ids,)) + an_ids = self.cr.fetchall() + + context = {'wizard_date_from': d_from, 'wizard_date_to': d_to} + for i in range(0, len(an_ids)): + if not an_ids[i][0]: + continue + analytic_name = acc_analytic_obj.browse([an_ids[i][0]]) + res = { + 'b_id': '-1', + 'a_id': '-1', + 'name': analytic_name[0].name, + 'status': 1, + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + result.append(res) + + line_ids = c_b_lines_obj.search([('id', 'in', budget_ids), ('analytic_account_id', '=', an_ids[i][0]), + ('date_to', '>=', d_from), ('date_from', '<=', d_to)]) + line_id = line_ids + tot_theo = tot_pln = tot_prac = tot_perc = 0.00 + + done_budget = [] + for line in line_id: + if line.id in budget_ids: + theo = pract = 0.00 + theo = line.theoritical_amount + pract = c_b_lines_obj.practical_amount + if line.general_budget_id.id in done_budget: + for record in result: + if record['b_id'] == line.general_budget_id.id and \ + record['a_id'] == line.analytic_account_id.id: + record['theo'] += theo + record['pln'] += line.planned_amount + record['prac'] += pract + if record['theo'] <> 0.00: + perc = (record['prac'] / record['theo']) * 100 + else: + perc = 0.00 + record['perc'] = perc + tot_theo += theo + tot_pln += line.planned_amount + tot_prac += pract + tot_perc += perc + else: + if theo <> 0.00: + perc = (pract / theo) * 100 + else: + perc = 0.00 + res1 = { + 'a_id': line.analytic_account_id.id, + 'b_id': line.general_budget_id.id, + 'name': line.general_budget_id.name, + 'status': 2, + 'theo': theo, + 'pln': line.planned_amount, + 'prac': pract, + 'perc': perc, + } + tot_theo += theo + tot_pln += line.planned_amount + tot_prac += pract + tot_perc += perc + if form['report'] == 'analytic-full': + result.append(res1) + done_budget.append(line.general_budget_id.id) + else: + + if line.general_budget_id.id in done_budget: + continue + else: + res1 = { + 'a_id': line.analytic_account_id.id, + 'b_id': line.general_budget_id.id, + 'name': line.general_budget_id.name, + 'status': 2, + 'theo': 0.00, + 'pln': 0.00, + 'prac': 0.00, + 'perc': 0.00 + } + if form['report'] == 'analytic-full': + result.append(res1) + done_budget.append(line.general_budget_id.id) + if tot_theo == 0.00: + tot_perc = 0.00 + else: + tot_perc = float(tot_prac / tot_theo) * 100 + if form['report'] == 'analytic-full': + result[-(len(done_budget) + 1)]['theo'] = tot_theo + tot['theo'] += tot_theo + result[-(len(done_budget) + 1)]['pln'] = tot_pln + tot['pln'] += tot_pln + result[-(len(done_budget) + 1)]['prac'] = tot_prac + tot['prac'] += tot_prac + result[-(len(done_budget) + 1)]['perc'] = tot_perc + else: + result[-1]['theo'] = tot_theo + tot['theo'] += tot_theo + result[-1]['pln'] = tot_pln + tot['pln'] += tot_pln + result[-1]['prac'] = tot_prac + tot['prac'] += tot_prac + result[-1]['perc'] = tot_perc + if tot['theo'] == 0.00: + tot['perc'] = 0.00 + else: + tot['perc'] = float(tot['prac'] / tot['theo']) * 100 + return result + + def funct_total(self, form): + result = [] + res = { + 'tot_theo': tot['theo'], + 'tot_pln': tot['pln'], + 'tot_prac': tot['prac'], + 'tot_perc': tot['perc'] + } + result.append(res) + return result + + +class ReportCrossOverBudget(osv.AbstractModel): + _name = 'report.account_budget_report.report_cross_over_budget' + _inherit = 'report.abstract_report' + _template = 'account_budget_report.report_cross_over_budget' + _wrapped_report_class = BudgetReport diff --git a/account_budget_report/reports/report_analytic_account_budget.xml b/account_budget_report/reports/report_analytic_account_budget.xml new file mode 100644 index 000000000..a3b21c730 --- /dev/null +++ b/account_budget_report/reports/report_analytic_account_budget.xml @@ -0,0 +1,77 @@ + + + + + + \ No newline at end of file diff --git a/account_budget_report/reports/report_crossovered_budget.xml b/account_budget_report/reports/report_crossovered_budget.xml new file mode 100644 index 000000000..264e8a774 --- /dev/null +++ b/account_budget_report/reports/report_crossovered_budget.xml @@ -0,0 +1,89 @@ + + + + + + \ No newline at end of file diff --git a/account_budget_report/static/description/analytic_budget.png b/account_budget_report/static/description/analytic_budget.png new file mode 100644 index 000000000..71efa3f19 Binary files /dev/null and b/account_budget_report/static/description/analytic_budget.png differ diff --git a/account_budget_report/static/description/analytic_budget_report.png b/account_budget_report/static/description/analytic_budget_report.png new file mode 100644 index 000000000..e12253937 Binary files /dev/null and b/account_budget_report/static/description/analytic_budget_report.png differ diff --git a/account_budget_report/static/description/banner.jpg b/account_budget_report/static/description/banner.jpg new file mode 100644 index 000000000..9502ebcb6 Binary files /dev/null and b/account_budget_report/static/description/banner.jpg differ diff --git a/account_budget_report/static/description/budget_adviser.png b/account_budget_report/static/description/budget_adviser.png new file mode 100644 index 000000000..32241515f Binary files /dev/null and b/account_budget_report/static/description/budget_adviser.png differ diff --git a/account_budget_report/static/description/budgetry_position.png b/account_budget_report/static/description/budgetry_position.png new file mode 100644 index 000000000..cbdfb25f3 Binary files /dev/null and b/account_budget_report/static/description/budgetry_position.png differ diff --git a/account_budget_report/static/description/budgetry_position_report.png b/account_budget_report/static/description/budgetry_position_report.png new file mode 100644 index 000000000..73474fc38 Binary files /dev/null and b/account_budget_report/static/description/budgetry_position_report.png differ diff --git a/account_budget_report/static/description/cybro_logo.png b/account_budget_report/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/account_budget_report/static/description/cybro_logo.png differ diff --git a/account_budget_report/static/description/icon.png b/account_budget_report/static/description/icon.png new file mode 100644 index 000000000..acfb759cc Binary files /dev/null and b/account_budget_report/static/description/icon.png differ diff --git a/account_budget_report/static/description/index.html b/account_budget_report/static/description/index.html new file mode 100644 index 000000000..1044d2a30 --- /dev/null +++ b/account_budget_report/static/description/index.html @@ -0,0 +1,145 @@ +
+
+

Advanced Account Budget Report

+

Helps You To Analyse Budget Summary

+

Cybrosys Technologies

+
+
+

Features:

+
+ Option to print budget summary
+ Option to print budgets
+ Option to print budgets from analytic accounts
+ Option to print budgets from budgetary positions
+
+
+
+ +
+
+
+

Overview

+

+ In odoo we can manage different budgets for every accounts. But currently there is no any option to take + budget report. So here we are providing budget analysis through different pdf reports. So we can take + quick budget analysis. +

+
+
+
+ +
+
+
+

+

Budget Summary

+

+

+
+
+ +
+ Go to Account -> Adviser -> Budgets. Then select one or more budgets. Then click on 'Print' + menu and choose 'Print Summary'. +
+ +
+ You can choose start date and end date then click on 'Print' button. +
+ +
+
+
+
+ +
+
+
+

+

Budgets

+

+

+
+ Go to Account -> Adviser -> Budgets. Then select one or more budgets. Then click on 'Print' + menu and choose 'Print Budgets'. +
+ +
+ You can choose start date and end date then click on 'Print' button. +
+ +
+
+
+
+ +
+
+
+

+

Analytic Accounts

+

+

+
+ Go to Account -> Adviser -> Analytic Accounts. Then select one analytic accounts. Then click on 'Print' + menu and choose 'Print Budgets'. +
+ +
+ You can choose start date and end date then click on 'Print' button. +
+ +
+
+
+
+ +
+
+
+

+

Budgetary Positions

+

+

+
+ Go to Account -> Configuration -> Management -> Budgetary Positions. Then select one budgetary position. + Then click on 'Print' menu and choose 'Budgets'. +
+ +
+ You can choose start date and end date then click on 'Print' button. +
+ +
+
+
+
+ +
+

Need Any Help?

+ +
+ + + diff --git a/account_budget_report/static/description/report2.png b/account_budget_report/static/description/report2.png new file mode 100644 index 000000000..2d5768d06 Binary files /dev/null and b/account_budget_report/static/description/report2.png differ diff --git a/account_budget_report/static/description/summary_report.png b/account_budget_report/static/description/summary_report.png new file mode 100644 index 000000000..f419c2dde Binary files /dev/null and b/account_budget_report/static/description/summary_report.png differ diff --git a/account_budget_report/static/description/wizard.png b/account_budget_report/static/description/wizard.png new file mode 100644 index 000000000..0541f748e Binary files /dev/null and b/account_budget_report/static/description/wizard.png differ diff --git a/account_budget_report/static/description/wizard1.png b/account_budget_report/static/description/wizard1.png new file mode 100644 index 000000000..c9d892fbc Binary files /dev/null and b/account_budget_report/static/description/wizard1.png differ diff --git a/account_budget_report/views/analytic_budget_report_view.xml b/account_budget_report/views/analytic_budget_report_view.xml new file mode 100644 index 000000000..cf5cf20e7 --- /dev/null +++ b/account_budget_report/views/analytic_budget_report_view.xml @@ -0,0 +1,38 @@ + + + + account.budget.analytic.form + account.budget.analytic + +
+ + + + +
+
+
+
+
+ + + Print Budgets + ir.actions.act_window + account.budget.analytic + form + form + + new + + + + + Print Budgets + client_print_multi + + action + account.analytic.account + +
\ No newline at end of file diff --git a/account_budget_report/views/budget_print_view.xml b/account_budget_report/views/budget_print_view.xml new file mode 100644 index 000000000..6a8df6fa6 --- /dev/null +++ b/account_budget_report/views/budget_print_view.xml @@ -0,0 +1,37 @@ + + + + account.budget.cross.over.report.form + account.budget.cross.over.report + +
+ + + + +
+
+
+
+
+ + + Print Budgets + ir.actions.act_window + account.budget.cross.over.report + form + form + + new + + + + Print Budgets + client_print_multi + + action + crossovered.budget + +
\ No newline at end of file diff --git a/account_budget_report/views/budget_report_view.xml b/account_budget_report/views/budget_report_view.xml new file mode 100644 index 000000000..604eba6bc --- /dev/null +++ b/account_budget_report/views/budget_report_view.xml @@ -0,0 +1,39 @@ + + + + account.budget.report.form + account.budget.report + +
+ + + + +
+
+
+
+
+ + + Budgets + ir.actions.act_window + account.budget.report + form + form + + new + + + + + Budgets + client_print_multi + + action + account.budget.post + +
\ No newline at end of file diff --git a/account_budget_report/views/budget_summary_view.xml b/account_budget_report/views/budget_summary_view.xml new file mode 100644 index 000000000..ad45b079c --- /dev/null +++ b/account_budget_report/views/budget_summary_view.xml @@ -0,0 +1,38 @@ + + + + account.budget.cross.over.summary.report.form + account.budget.cross.over.summary.report + +
+ + + + +
+
+
+
+
+ + + Print Summary + ir.actions.act_window + account.budget.cross.over.summary.report + form + form + + new + + + + + Print Summary + client_print_multi + + action + crossovered.budget + +
\ No newline at end of file diff --git a/account_limit/README.rst b/account_limit/README.rst new file mode 100644 index 000000000..2e2b5bb00 --- /dev/null +++ b/account_limit/README.rst @@ -0,0 +1,20 @@ +======================== +Account Credit Limit v10 +======================== +Account credit limit is a handy plugin for Odoo Accounting module to set a Credit limit for each Account. +The module will bring new fields total Credit, Debit and Balance in ‘Accounts tree view’ and ‘Account form view’. +The module also produce a warning message while making journal entries which will exceed the credit limit. +The features can simplify the credit evaluation +process of accounts like Customers accounts, Overdraft accounts, Bank accounts etc. + +Features +======== +* Know Total Debit of an account. +* Know Total Credit of an account. +* Know Balance of the account. +* Set the Credit limit for accounts. +* Stop an account exceeding the credit limit. + +Credits +======= +Nikhil Krishnan @ cybrosys, nikhil@cybrosys.in \ No newline at end of file diff --git a/account_limit/__init__.py b/account_limit/__init__.py new file mode 100644 index 000000000..a341bab17 --- /dev/null +++ b/account_limit/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan(nikhil@cybrosys.in) +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +import models diff --git a/account_limit/__manifest__.py b/account_limit/__manifest__.py new file mode 100644 index 000000000..a5bfc5c4d --- /dev/null +++ b/account_limit/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +{ + 'name': 'Account Credit Limit', + 'version': '10.0.2.0', + 'summary': """Generate Warning Message When Credit Limit of an Account is Exceed.""", + 'description': """Account credit limit is a handy plugin for Odoo Accounting module to set a Credit limit + for each Account. The module will bring new fields total Credit, Debit and Balance in ‘Accounts tree view’ and + ‘Account form view’. The module also produce a warning message while making journal entries which will exceed + the credit limit. The features can simplify the credit evaluation process of accounts like Customers accounts, + Overdraft accounts, Bank accounts etc.""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'category': 'Accounting', + 'depends': ['account', 'account_accountant'], + 'license': 'LGPL-3', + 'data': ['views/account_credit_limit_view.xml'], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'installable': True, + 'auto_install': False, +} diff --git a/account_limit/models/__init__.py b/account_limit/models/__init__.py new file mode 100644 index 000000000..f7876db2e --- /dev/null +++ b/account_limit/models/__init__.py @@ -0,0 +1 @@ +import account diff --git a/account_limit/models/account.py b/account_limit/models/account.py new file mode 100644 index 000000000..edb7287fc --- /dev/null +++ b/account_limit/models/account.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import fields, api, _, models +from odoo.exceptions import Warning + + +class AccountAccount(models.Model): + _inherit = 'account.account' + + @api.multi + def get_credit_debit_balance(self): + for obj in self: + credit = 0 + debit = 0 + account_lines = self.env['account.move.line'].search([('account_id', '=', obj.id)]) + for line in account_lines: + credit += line.credit + debit += line.debit + obj.credit = credit + obj.debit = debit + obj.balance = debit - credit + + credit = fields.Float(string='Credit', compute='get_credit_debit_balance') + debit = fields.Float(string='Debit', compute='get_credit_debit_balance') + balance = fields.Float(string='Balance', compute='get_credit_debit_balance') + account_credit_limit = fields.Float(string='Credit Limit', Help="Credit Limit for this particular Account.") + + +class AccountMove(models.Model): + _inherit = "account.move" + + @api.model + def create(self, vals): + credit = 0 + debit = 0 + if "line_ids" in vals.keys(): + for line in vals['line_ids']: + if line[2]['credit']: + account = self.env['account.account'].browse(line[2]['account_id']) + account_lines = self.env['account.move.line'].search([('account_id', '=', account.id)]) + for lines in account_lines: + credit += lines.credit + debit += lines.debit + if account.account_credit_limit: + if (credit+line[2]['credit'] - debit) > account.account_credit_limit: + raise Warning(_('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + result = super(AccountMove, self).create(vals) + return result + + @api.multi + def write(self, vals): + if "line_ids" in vals.keys(): + for line in vals['line_ids']: + account_lines = self.env['account.move.line'].browse(line[1]) + if line[2]: + if 'account_id' in line[2]: + if line[2]['account_id']: + account = self.env['account.account'].browse(line[2]['account_id']) + if account.account_credit_limit: + if 'debit' in line[2]: + new_debit = line[2]['debit'] + else: + new_debit = account_lines.debit + if 'credit' in line[2]: + new_credit = line[2]['credit'] + else: + new_credit = account_lines.credit + if (account.credit + new_credit - new_debit - account.debit) > account.account_credit_limit: + raise Warning( + _('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + else: + account = account_lines.account_id + if account.account_credit_limit: + if 'debit' in line[2]: + if line[2]['debit']: + old_debit = account_lines.debit + if (account.credit - line[2]['debit'] - account.debit + old_debit) > account.account_credit_limit: + raise Warning( + _('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + if 'credit' in line[2]: + if line[2]['credit']: + old_credit = account_lines.credit + if (account.credit+line[2]['credit']-account.debit-old_credit) > account.account_credit_limit: + raise Warning( + _('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + result = super(AccountMove, self).write(vals) + return result diff --git a/account_limit/models/account.py~ b/account_limit/models/account.py~ new file mode 100644 index 000000000..7295d2026 --- /dev/null +++ b/account_limit/models/account.py~ @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import fields, api, _, models +from odoo.exceptions import Warning + + +class AccountAccount(models.Model): + _inherit = 'account.account' + + @api.multi + def get_credit_debit_balance(self): + print "get_credit_debit_balance", self + for obj in self: + credit = 0 + debit = 0 + account_lines = self.env['account.move.line'].search([('account_id', '=', obj.id)]) + for line in account_lines: + credit += line.credit + debit += line.debit + obj.credit = credit + obj.debit = debit + obj.balance = debit - credit + + credit = fields.Float(string='Credit', compute='get_credit_debit_balance') + debit = fields.Float(string='Debit', compute='get_credit_debit_balance') + balance = fields.Float(string='Balance', compute='get_credit_debit_balance') + account_credit_limit = fields.Float(string='Credit Limit', Help="Credit Limit for this particular Account.") + + +class AccountMove(models.Model): + _inherit = "account.move" + + @api.model + def create(self, vals): + credit = 0 + debit = 0 + if "line_ids" in vals.keys(): + for line in vals['line_ids']: + if line[2]['credit']: + account = self.env['account.account'].browse(line[2]['account_id']) + account_lines = self.env['account.move.line'].search([('account_id', '=', account.id)]) + for lines in account_lines: + credit += lines.credit + debit += lines.debit + if account.account_credit_limit: + if (credit+line[2]['credit'] - debit) > account.account_credit_limit: + raise Warning(_('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + result = super(AccountMove, self).create(vals) + return result + + @api.multi + def write(self, vals): + if "line_ids" in vals.keys(): + for line in vals['line_ids']: + account_lines = self.env['account.move.line'].browse(line[1]) + if line[2]: + if 'account_id' in line[2]: + if line[2]['account_id']: + account = self.env['account.account'].browse(line[2]['account_id']) + if account.account_credit_limit: + if 'debit' in line[2]: + new_debit = line[2]['debit'] + else: + new_debit = account_lines.debit + if 'credit' in line[2]: + new_credit = line[2]['credit'] + else: + new_credit = account_lines.credit + if (account.credit + new_credit - new_debit - account.debit) > account.account_credit_limit: + raise Warning( + _('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + else: + account = account_lines.account_id + if account.account_credit_limit: + if 'debit' in line[2]: + if line[2]['debit']: + old_debit = account_lines.debit + if (account.credit - line[2]['debit'] - account.debit + old_debit) > account.account_credit_limit: + raise Warning( + _('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + if 'credit' in line[2]: + if line[2]['credit']: + old_credit = account_lines.credit + if (account.credit+line[2]['credit']-account.debit-old_credit) > account.account_credit_limit: + raise Warning( + _('Limit will Exceed .! \n Making this transaction will exceed the limit ' + 'defined for " %s " account') % account.name) + result = super(AccountMove, self).write(vals) + return result diff --git a/account_limit/static/description/Cash.png b/account_limit/static/description/Cash.png new file mode 100644 index 000000000..15aaade81 Binary files /dev/null and b/account_limit/static/description/Cash.png differ diff --git a/account_limit/static/description/Tree view account.png b/account_limit/static/description/Tree view account.png new file mode 100644 index 000000000..f4c6328c2 Binary files /dev/null and b/account_limit/static/description/Tree view account.png differ diff --git a/account_limit/static/description/Warning.png b/account_limit/static/description/Warning.png new file mode 100644 index 000000000..df259aca4 Binary files /dev/null and b/account_limit/static/description/Warning.png differ diff --git a/account_limit/static/description/banner.jpg b/account_limit/static/description/banner.jpg new file mode 100644 index 000000000..cce2d71e6 Binary files /dev/null and b/account_limit/static/description/banner.jpg differ diff --git a/account_limit/static/description/cybro_logo.png b/account_limit/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/account_limit/static/description/cybro_logo.png differ diff --git a/account_limit/static/description/icon.png b/account_limit/static/description/icon.png new file mode 100644 index 000000000..49d3388fa Binary files /dev/null and b/account_limit/static/description/icon.png differ diff --git a/account_limit/static/description/index.html b/account_limit/static/description/index.html new file mode 100644 index 000000000..81857563b --- /dev/null +++ b/account_limit/static/description/index.html @@ -0,0 +1,105 @@ +
+
+
+

Account Credit Limit

+

Get total credit, total debit, balance of each account.

+

Set credit limits for accounts.

+

Cybrosys Technologies

+
+
+

Major Features:

+
    +
  •    Know Total Debit of an account.
  • +
  •    Know Total Credit of an account.
  • +
  •    Know Balance of the account.
  • +
  •    Set the Credit limit for accounts.
  • +
  •    Stop an account exceeding the credit limit.
  • +
+
+
+
+ +
+
+
+

Overview

+

Account credit limit is a handy plugin for Odoo Accounting module to set a Credit limit for each Account. The module will bring new fields total Credit, Debit and Balance in ‘Accounts tree view’ and ‘Account form view’. The module also produce a warning message while making journal entries which will exceed the credit limit. + The features can simplify the credit evaluation process of accounts like Customers accounts, Overdraft accounts, Bank accounts etc.

+
+
+
+ +
+
+
+

Account List/Tree view

+

+

Install the module and open chart of Accounts.

+

+
+ +
+
+
+

+

You can see that a new tree view is created here which lists Debit, Credit, and Balance of the respective accounts.

+

+
+
+
+ +
+
+
+

Account Form view

+
+ +
+
+
+

+

The fields i.e. Debit, Credit, and Balance will be displayed in individual account form also. + From here you can set the credit limit for the individual account.

+

+
+
+
+
+
+
+

Warning

+

+

The app will pop up a warning message while you make a journal entry which exceeds the credit limit.

+

+
+ +
+
+
+
+ +
+

Need Any Help?

+ +
diff --git a/account_limit/views/account_credit_limit_view.xml b/account_limit/views/account_credit_limit_view.xml new file mode 100644 index 000000000..34f6c8e34 --- /dev/null +++ b/account_limit/views/account_credit_limit_view.xml @@ -0,0 +1,31 @@ + + + + + account.account.form + account.account + + + + + + + + + + + + + account.account.list + account.account + + + + + + + + + + + diff --git a/account_partner_ledger_filter/__init__.py b/account_partner_ledger_filter/__init__.py new file mode 100644 index 000000000..a957a587e --- /dev/null +++ b/account_partner_ledger_filter/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +import wizard +import models diff --git a/account_partner_ledger_filter/__manifest__.py b/account_partner_ledger_filter/__manifest__.py new file mode 100644 index 000000000..8d0cdede0 --- /dev/null +++ b/account_partner_ledger_filter/__manifest__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Fasluca() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Partner Ledger with Partner Filter', + 'version': '10.0.1.0', + 'summary': """Partner Ledger Report with Partner Filter""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://cybrosys.com/", + 'category': 'Accounting', + 'depends': ['account'], + 'data': [ + 'views/report.xml', + 'wizard/account_report_general_ledger_view.xml' + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'application': False +} diff --git a/account_partner_ledger_filter/models/__init__.py b/account_partner_ledger_filter/models/__init__.py new file mode 100644 index 000000000..f22d63076 --- /dev/null +++ b/account_partner_ledger_filter/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +import account_partner_ledger diff --git a/account_partner_ledger_filter/models/account_partner_ledger.py b/account_partner_ledger_filter/models/account_partner_ledger.py new file mode 100644 index 000000000..47ca86daa --- /dev/null +++ b/account_partner_ledger_filter/models/account_partner_ledger.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +import time +import logging +from odoo import api, models + + +_logger = logging.getLogger(__name__) + + +class ReportPartnerLedger(models.AbstractModel): + _inherit = 'report.account.report_partnerledger' + + @api.model + def render_html(self, docids, data=None): + self.model = self.env.context.get('active_model') + docs = self.env[self.model].browse(self.env.context.get('active_ids', [])).id + + data['computed'] = {} + + obj_partner = self.env['res.partner'] + query_get_data = self.env['account.move.line'].with_context(data['form'].get('used_context', {}))._query_get() + data['computed']['move_state'] = ['draft', 'posted'] + if data['form'].get('target_move', 'all') == 'posted': + data['computed']['move_state'] = ['posted'] + result_selection = data['form'].get('result_selection', 'customer') + if result_selection == 'supplier': + data['computed']['ACCOUNT_TYPE'] = ['payable'] + elif result_selection == 'customer': + data['computed']['ACCOUNT_TYPE'] = ['receivable'] + else: + data['computed']['ACCOUNT_TYPE'] = ['payable', 'receivable'] + + self.env.cr.execute(""" + SELECT a.id + FROM account_account a + WHERE a.internal_type IN %s + AND NOT a.deprecated""", (tuple(data['computed']['ACCOUNT_TYPE']),)) + data['computed']['account_ids'] = [a for (a,) in self.env.cr.fetchall()] + params = [tuple(data['computed']['move_state']), tuple(data['computed']['account_ids'])] + query_get_data[2] + reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".reconciled = false ' + query = """ + SELECT DISTINCT "account_move_line".partner_id + FROM """ + query_get_data[0] + """, account_account AS account, account_move AS am + WHERE "account_move_line".partner_id IS NOT NULL + AND "account_move_line".account_id = account.id + AND am.id = "account_move_line".move_id + AND am.state IN %s + AND "account_move_line".account_id IN %s + AND NOT account.deprecated + AND """ + query_get_data[1] + reconcile_clause + self.env.cr.execute(query, tuple(params)) + #---------------------Taking only selected partners--------------------------- + if data['form']['partner_ids']: + partner_ids = data['form']['partner_ids'] + else: + partner_ids = [res['partner_id'] for res in self.env.cr.dictfetchall()] + #----------------------------------------------------------------------------- + partners = obj_partner.browse(partner_ids) + partners = sorted(partners, key=lambda x: (x.ref, x.name)) + + docargs = { + 'doc_ids': partner_ids, + 'doc_model': self.env['res.partner'], + 'data': data, + 'docs': partners, + 'time': time, + 'lines': self._lines, + 'sum_partner': self._sum_partner, + } + return self.env['report'].render('account.report_partnerledger', docargs) \ No newline at end of file diff --git a/account_partner_ledger_filter/static/description/banner.jpg b/account_partner_ledger_filter/static/description/banner.jpg new file mode 100644 index 000000000..cad4d04ac Binary files /dev/null and b/account_partner_ledger_filter/static/description/banner.jpg differ diff --git a/account_partner_ledger_filter/static/description/cybro_logo.png b/account_partner_ledger_filter/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/account_partner_ledger_filter/static/description/cybro_logo.png differ diff --git a/account_partner_ledger_filter/static/description/icon.png b/account_partner_ledger_filter/static/description/icon.png new file mode 100644 index 000000000..b1256ef4c Binary files /dev/null and b/account_partner_ledger_filter/static/description/icon.png differ diff --git a/account_partner_ledger_filter/static/description/index.html b/account_partner_ledger_filter/static/description/index.html new file mode 100644 index 000000000..26f213412 --- /dev/null +++ b/account_partner_ledger_filter/static/description/index.html @@ -0,0 +1,62 @@ +
+

Partner Ledger report with Partner Filter

+

Cybrosys Techno Solutions - www.cybrosys.com

+
+ +
+
+
You can generate partner ledger report from partner form and list
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+
+
This will open partner ledger report wizard with the selected partner.
+
You can add or remove partner from wizard in case of fault selection
+
+
+ + +
+
+
+
+ +
+

Need Any Help?

+ +
+ diff --git a/account_partner_ledger_filter/static/description/index.html~ b/account_partner_ledger_filter/static/description/index.html~ new file mode 100644 index 000000000..9ea2e1f7c --- /dev/null +++ b/account_partner_ledger_filter/static/description/index.html~ @@ -0,0 +1,68 @@ +
+

Partner Ledger report with Partner Filter

+

Cybrosys Techno Solutions - www.cybrosys.com

+
+ +
+
+
You can generate partner ledger report from partner form and list
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+
+
+ +
+
This will open partner ledger report wizard with the selected partner.
+
You can add or remove partner from wizard in case of fault selection
+
+
+
+ + +
+
+ +
+
+
+ +
+

Need Any Help?

+ +
+ diff --git a/account_partner_ledger_filter/static/description/partner_form.png b/account_partner_ledger_filter/static/description/partner_form.png new file mode 100644 index 000000000..33489e711 Binary files /dev/null and b/account_partner_ledger_filter/static/description/partner_form.png differ diff --git a/account_partner_ledger_filter/static/description/partner_list.png b/account_partner_ledger_filter/static/description/partner_list.png new file mode 100644 index 000000000..596a59108 Binary files /dev/null and b/account_partner_ledger_filter/static/description/partner_list.png differ diff --git a/account_partner_ledger_filter/static/description/report_wiz.png b/account_partner_ledger_filter/static/description/report_wiz.png new file mode 100644 index 000000000..ecc6ba734 Binary files /dev/null and b/account_partner_ledger_filter/static/description/report_wiz.png differ diff --git a/account_partner_ledger_filter/views/report.xml b/account_partner_ledger_filter/views/report.xml new file mode 100644 index 000000000..6f79d511b --- /dev/null +++ b/account_partner_ledger_filter/views/report.xml @@ -0,0 +1,25 @@ + + + + + + Partner Ledger + ir.actions.act_window + account.report.partner.ledger + form + form + + {'default_partner_ids':active_ids} + new + + + + + Partner Ledger + client_print_multi + + action + res.partner + + + \ No newline at end of file diff --git a/account_partner_ledger_filter/wizard/__init__.py b/account_partner_ledger_filter/wizard/__init__.py new file mode 100644 index 000000000..de9b8ac41 --- /dev/null +++ b/account_partner_ledger_filter/wizard/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +import account_report_partner_ledger diff --git a/account_partner_ledger_filter/wizard/account_report_general_ledger_view.xml b/account_partner_ledger_filter/wizard/account_report_general_ledger_view.xml new file mode 100644 index 000000000..87d691cd5 --- /dev/null +++ b/account_partner_ledger_filter/wizard/account_report_general_ledger_view.xml @@ -0,0 +1,15 @@ + + + + Partner Ledger + account.report.partner.ledger + + + + + + + + + + diff --git a/account_partner_ledger_filter/wizard/account_report_partner_ledger.py b/account_partner_ledger_filter/wizard/account_report_partner_ledger.py new file mode 100644 index 000000000..b8a87fc10 --- /dev/null +++ b/account_partner_ledger_filter/wizard/account_report_partner_ledger.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models + + +class AccountPartnerLedger(models.TransientModel): + _inherit = "account.report.partner.ledger" + + partner_ids = fields.Many2many('res.partner', 'partner_ledger_partner_rel', 'id', 'partner_id', string='Partners') + + def _print_report(self, data): + data = self.pre_print_report(data) + data['form'].update({'reconciled': self.reconciled, 'amount_currency': self.amount_currency, + 'partner_ids': self.partner_ids.ids}) + return self.env['report'].get_action(self, 'account.report_partnerledger', data=data) diff --git a/account_pdc/__init__.py b/account_pdc/__init__.py new file mode 100644 index 000000000..55e11f5a1 --- /dev/null +++ b/account_pdc/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models diff --git a/account_pdc/__manifest__.py b/account_pdc/__manifest__.py new file mode 100644 index 000000000..17bf3a37a --- /dev/null +++ b/account_pdc/__manifest__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'PDC Management', + 'version': '10.0.1.0', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': 'http://www.cybrosys.com', + 'category': 'Accounting', + 'summary': 'Extension on Cheques to handle Post Dated Cheques', + 'description': """ Extension on Cheques to handle Post Dated Cheques """, + 'depends': ['account_check_printing'], + 'data': [ + 'data/account_pdc_data.xml', + 'views/account_payment_view.xml', + ], + 'images': ['static/description/pdc_banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, +} diff --git a/account_pdc/data/account_pdc_data.xml b/account_pdc/data/account_pdc_data.xml new file mode 100644 index 000000000..54ec4ca7f --- /dev/null +++ b/account_pdc/data/account_pdc_data.xml @@ -0,0 +1,19 @@ + + + + + + PDC + pdc + inbound + + + PDC + pdc + outbound + + + + + + \ No newline at end of file diff --git a/account_pdc/models/__init__.py b/account_pdc/models/__init__.py new file mode 100644 index 000000000..fdd64429b --- /dev/null +++ b/account_pdc/models/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +import account_journal +import account_payment diff --git a/account_pdc/models/account_journal.py b/account_pdc/models/account_journal.py new file mode 100644 index 000000000..996a0f079 --- /dev/null +++ b/account_pdc/models/account_journal.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import models, api, _ + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + @api.one + @api.depends('outbound_payment_method_ids') + def _compute_check_printing_payment_method_selected(self): + self.check_printing_payment_method_selected = any( + pm.code in ['check_printing', 'pdc'] for pm in self.outbound_payment_method_ids) + + @api.model + def _enable_pdc_on_bank_journals(self): + """ Enables check printing payment method and add a check sequence on bank journals. + Called upon module installation via data file. + """ + pdcin = self.env.ref('account_pdc.account_payment_method_pdc_in') + pdcout = self.env.ref('account_pdc.account_payment_method_pdc_out') + bank_journals = self.search([('type', '=', 'bank')]) + for bank_journal in bank_journals: + # bank_journal._create_check_sequence() + bank_journal.write({ + 'inbound_payment_method_ids': [(4, pdcin.id, None)], + 'outbound_payment_method_ids': [(4, pdcout.id, None)], + }) diff --git a/account_pdc/models/account_payment.py b/account_pdc/models/account_payment.py new file mode 100644 index 000000000..3d0e4d61e --- /dev/null +++ b/account_pdc/models/account_payment.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import models, fields, api, _ +from odoo.exceptions import UserError + + +class AccountRegisterPayments(models.TransientModel): + _inherit = "account.register.payments" + + bank_reference = fields.Char(copy=False) + cheque_reference = fields.Char(copy=False) + effective_date = fields.Date('Effective Date', help='Effective date of PDC', copy=False, default=False) + + def get_payment_vals(self): + res = super(AccountRegisterPayments, self).get_payment_vals() + if self.payment_method_id == self.env.ref('account_check_printing.account_payment_method_check'): + res.update({ + 'check_amount_in_words': self.check_amount_in_words, + 'check_manual_sequencing': self.check_manual_sequencing, + 'effective_date': self.effective_date, + }) + return res + + +class AccountPayment(models.Model): + _inherit = "account.payment" + + bank_reference = fields.Char(copy=False) + cheque_reference = fields.Char(copy=False) + effective_date = fields.Date('Effective Date', help='Effective date of PDC', copy=False, default=False) + + @api.multi + def print_checks(self): + """ Check that the recordset is valid, set the payments state to sent and call print_checks() """ + # Since this method can be called via a client_action_multi, we need to make sure the received records are what we expect + self = self.filtered(lambda r: r.payment_method_id.code in ['check_printing', 'pdc'] and r.state != 'reconciled') + + if len(self) == 0: + raise UserError(_("Payments to print as a checks must have 'Check' or 'PDC' selected as payment method and " + "not have already been reconciled")) + if any(payment.journal_id != self[0].journal_id for payment in self): + raise UserError(_("In order to print multiple checks at once, they must belong to the same bank journal.")) + + if not self[0].journal_id.check_manual_sequencing: + # The wizard asks for the number printed on the first pre-printed check + # so payments are attributed the number of the check the'll be printed on. + last_printed_check = self.search([ + ('journal_id', '=', self[0].journal_id.id), + ('check_number', '!=', 0)], order="check_number desc", limit=1) + next_check_number = last_printed_check and last_printed_check.check_number + 1 or 1 + return { + 'name': _('Print Pre-numbered Checks'), + 'type': 'ir.actions.act_window', + 'res_model': 'print.prenumbered.checks', + 'view_type': 'form', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'payment_ids': self.ids, + 'default_next_check_number': next_check_number, + } + } + else: + self.filtered(lambda r: r.state == 'draft').post() + self.write({'state': 'sent'}) + return self.do_print_checks() + + + def _get_move_vals(self, journal=None): + """ Return dict to create the payment move + """ + journal = journal or self.journal_id + if not journal.sequence_id: + raise UserError(_('Configuration Error !'), + _('The journal %s does not have a sequence, please specify one.') % journal.name) + if not journal.sequence_id.active: + raise UserError(_('Configuration Error !'), _('The sequence of journal %s is deactivated.') % journal.name) + name = self.move_name or journal.with_context(ir_sequence_date=self.payment_date).sequence_id.next_by_id() + if self.payment_method_code =='pdc': + date = self.effective_date + else: + date = self.payment_date + return { + 'name': name, + 'date': date, + 'ref': self.communication or '', + 'company_id': self.company_id.id, + 'journal_id': journal.id, + } diff --git a/account_pdc/static/description/cybro_logo.png b/account_pdc/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/account_pdc/static/description/cybro_logo.png differ diff --git a/account_pdc/static/description/icon.png b/account_pdc/static/description/icon.png new file mode 100644 index 000000000..f47728351 Binary files /dev/null and b/account_pdc/static/description/icon.png differ diff --git a/account_pdc/static/description/index.html b/account_pdc/static/description/index.html new file mode 100644 index 000000000..bafcb0153 --- /dev/null +++ b/account_pdc/static/description/index.html @@ -0,0 +1,92 @@ +
+
+
+

PDC Management

+

...A simple way to handle Post Dated Cheques...

+

Cybrosys Techno Solutions, www.cybrosys.com

+
+
+
+ +
+
+
+

Configuration

+
+
+
+ +
+
+
+

+

Select PDC:

+

As shown here, You have to select PDC to enable the PDC payment.This is only available with Journal of type 'Bank'

+

+
+
+
+ +
+
+
+

At The Time of Payment You Will Have

+
+
+
+ +
+
+
+

+

Payment form have two extra fields to put Bank and Cheque Detail.

+

+
+
+
+
+

+

When you select PDC, You have to put 'effective date' of PDC.

+

+
+
+
+ +
+
+
+
+ +
+

Need Any Help?

+ +
+ + + + + + + + diff --git a/account_pdc/static/description/pdc_banner.jpg b/account_pdc/static/description/pdc_banner.jpg new file mode 100644 index 000000000..4725892dd Binary files /dev/null and b/account_pdc/static/description/pdc_banner.jpg differ diff --git a/account_pdc/static/description/pdc_config.png b/account_pdc/static/description/pdc_config.png new file mode 100644 index 000000000..c046b55c0 Binary files /dev/null and b/account_pdc/static/description/pdc_config.png differ diff --git a/account_pdc/static/description/pdc_payment.png b/account_pdc/static/description/pdc_payment.png new file mode 100644 index 000000000..39aa93b15 Binary files /dev/null and b/account_pdc/static/description/pdc_payment.png differ diff --git a/account_pdc/static/description/pdc_payment_eff.png b/account_pdc/static/description/pdc_payment_eff.png new file mode 100644 index 000000000..ff9b1eb04 Binary files /dev/null and b/account_pdc/static/description/pdc_payment_eff.png differ diff --git a/account_pdc/static/description/pdc_report.png b/account_pdc/static/description/pdc_report.png new file mode 100644 index 000000000..1ff2cf4f0 Binary files /dev/null and b/account_pdc/static/description/pdc_report.png differ diff --git a/account_pdc/views/account_payment_view.xml b/account_pdc/views/account_payment_view.xml new file mode 100644 index 000000000..0cd82fc50 --- /dev/null +++ b/account_pdc/views/account_payment_view.xml @@ -0,0 +1,77 @@ + + + + account.payment.form.inherited + account.payment + + + + + + + + + + mrp.bom.image.form + mrp.bom + + + + + + + + mo_line.bom.image.form + mrp.production + + + + + + + + + + \ No newline at end of file diff --git a/cab_booking_management/README.rst b/cab_booking_management/README.rst new file mode 100644 index 000000000..611a80e58 --- /dev/null +++ b/cab_booking_management/README.rst @@ -0,0 +1,34 @@ +Cab Booking Management System v10 +================================= + +This module was developed to manage the cab system.It helps booking the cab, maintains logs +and record every activity related to the cab management. + +Installation +============ + +Just select it from available modules to install it, there is no need to extra installations. + +Configuration +============= + +Nothing to configure. + +Usage +===== + +To use this functionality, you need to: +#.First create cabs(Cab Management > Cabs) +#.Then,you need to set timing for each cabs( Cab management > Timing) +#.On clicking Booking menu( Cab management > Booking) ,you have option to select cabs based on your time and location +#. Email is sent,once your booking is confirmed +#.To get total expense,first you need to set maintenance form ( Cab management > Maintenance).In this form ,you can +select cab and date, and all total activity of that cab on that day is fetched here. +#.To get data's on maintenance form ,first you must book one cab + + +Credits +======= +Developer: Saritha @ cybrosys +Guidance: Nilmar Shereef @ cybrosys, shereef@cybrosys.in + diff --git a/cab_booking_management/__init__.py b/cab_booking_management/__init__.py new file mode 100644 index 000000000..5f913be08 --- /dev/null +++ b/cab_booking_management/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from . import models diff --git a/cab_booking_management/__manifest__.py b/cab_booking_management/__manifest__.py new file mode 100644 index 000000000..d62298b99 --- /dev/null +++ b/cab_booking_management/__manifest__.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': "Cab Booking Management System", + 'summary': """Complete Cab Booking Management and its Related Records""", + 'author': "Cybrosys Techno Solutions", + 'website': "http://www.cybrosys.com", + 'category': 'Industries', + 'version': '10.0.1.0.0', + 'depends': ['base', 'mail'], + 'data': [ + 'views/templates.xml', + 'views/cab_log_view.xml', + 'views/cab_conf_view.xml', + 'views/cab_location_view.xml', + 'views/cab_timing_view.xml', + 'views/cab_booking_view.xml', + 'views/cab_creation_view.xml', + 'views/cab_maintanence_view.xml', + 'security/ir.model.access.csv' + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': True, +} diff --git a/cab_booking_management/models/__init__.py b/cab_booking_management/models/__init__.py new file mode 100644 index 000000000..e18e446e1 --- /dev/null +++ b/cab_booking_management/models/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from . import cab_creation +from . import cab_log +from . import cab_conf +from . import cab_booking +from . import cab_location +from . import cab_timing +from. import cab_maintanence + + diff --git a/cab_booking_management/models/cab_booking.py b/cab_booking_management/models/cab_booking.py new file mode 100644 index 000000000..a154df7d7 --- /dev/null +++ b/cab_booking_management/models/cab_booking.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api +from datetime import date + + +class CabBooking(models.Model): + _name = 'cab.booking' + _rec_name = 'booking_date' + + booking_date = fields.Date(string="Booking Date", default=date.today(), required=True) + cab_timing = fields.Many2one('cab.time', string="Timing", required=True) + cab_routes = fields.Many2one('cab.location', string="Route From", required=True) + cab_routes_to = fields.Many2one('cab.location', string="Route To", required=True) + seat_available = fields.One2many('cab.timing', compute="scheduled_details") + + @api.onchange('cab_routes', 'cab_timing', 'cab_routes_to') + def scheduled_details(self): + data = self.env['cab.timing'].search([('cab_route.name', '=', self.cab_routes.name), + ('cab_time.name', '=', self.cab_timing.name), + ('cab_route_to.name', '=', self.cab_routes_to.name)]) + self.seat_available = data + + + + + + + + + + diff --git a/cab_booking_management/models/cab_conf.py b/cab_booking_management/models/cab_conf.py new file mode 100644 index 000000000..93f9cccfb --- /dev/null +++ b/cab_booking_management/models/cab_conf.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields + + +class CabConfiguration(models.Model): + _name = 'cab.configuration' + _rec_name = 'cab_manager' + + auto_approve = fields.Boolean(string="Auto Approve") + cab_manager = fields.Many2one('res.users', string='Manager', required=True) diff --git a/cab_booking_management/models/cab_creation.py b/cab_booking_management/models/cab_creation.py new file mode 100644 index 000000000..c2f4b4484 --- /dev/null +++ b/cab_booking_management/models/cab_creation.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import models, fields, api +from odoo.exceptions import UserError,ValidationError + + +class CabManagement(models.Model): + _name = 'cab.management' + + name = fields.Char(compute="complete_name_compute", string="Cab Name") + ref_name = fields.Char(string="Cab Name", required=True) + cab_image = fields.Binary(string='Image', store=True, attachment=True) + licence_plate = fields.Char(string="Licence Plate", required=True) + activity_period_from = fields.Date(string="Activity Period") + activity_period_to = fields.Date(string="To") + driver_plot = fields.Char(string="Driver Ploted") + cab_value = fields.Float(string="Cab Value") + cab_model = fields.Char(string="Cab Model") + cab_color = fields.Char(string="Cab Color") + aq_date = fields.Date(string="Aquisition Date") + chas_no = fields.Char(string="Chasis No") + odo_reading = fields.Float(string="Odometre Reading") + seating_capacity = fields.Integer(string="Seating Capacity", required=True) + fuel_type = fields.Char(string="Fuel Type") + related_log_details = fields.One2many('cab.log', string="Log Details", compute="auto_fetch_log_details") + total_log_details = fields.One2many('cab.maintanence', string='Total Expenses', compute="auto_fetch_total_details") + location_log_details = fields.One2many('cab.log', string="Location", compute="auto_fetch_location_details") + + @api.onchange('licence_plate') + def check_unique_constraint(self): + for records in self.env['cab.management'].search([]): + if self.licence_plate == records.licence_plate: + raise ValidationError("Record already exists and violates unique field constraint") + + @api.one + def complete_name_compute(self): + self.name = self.ref_name + if self.licence_plate: + self.name = str(self.licence_plate) + ' / ' + str(self.ref_name) + + @api.onchange('activity_period_from', 'activity_period_to') + def auto_fetch_log_details(self): + if self.activity_period_from and self.activity_period_to: + if self.activity_period_from <= self.activity_period_to: + data = self.env['cab.log'].search([("cab_log_date", ">=", self.activity_period_from), + ("cab_log_date", "<=", self.activity_period_to)]) + self.related_log_details = data + else: + self.activity_period_to = 0 + raise UserError("Enter Valid Dates") + + @api.onchange('activity_period_from', 'activity_period_to') + def auto_fetch_total_details(self): + if self.activity_period_from and self.activity_period_to: + if self.activity_period_from <= self.activity_period_to: + data = self.env['cab.maintanence'].search([("cab_log_date", ">=", self.activity_period_from), + ("cab_log_date", "<=", self.activity_period_to)]) + self.total_log_details = data + else: + raise UserError("Enter Valid Dates") + + @api.onchange('activity_period_from', 'activity_period_to') + def auto_fetch_location_details(self): + if self.activity_period_from and self.activity_period_to: + if self.activity_period_from <= self.activity_period_to: + data = self.env['cab.log'].search([("cab_log_date", ">=", self.activity_period_from), + ("cab_log_date", "<=", self.activity_period_to)]) + self.location_log_details = data + else: + raise UserError("Enter Valid Dates") + diff --git a/cab_booking_management/models/cab_location.py b/cab_booking_management/models/cab_location.py new file mode 100644 index 000000000..f06deb9dd --- /dev/null +++ b/cab_booking_management/models/cab_location.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields + + +class CabLocation(models.Model): + _name = 'cab.location' + + name = fields.Char(string='City', required=True) + cab_zip = fields.Char(string='ZIP') + cab_code = fields.Char(string='City Code', size=64, help="The official code for the city") + state_id = fields.Many2one('res.country.state', string='State', required=True) + country_id = fields.Many2one('res.country', string='Country', required=True) + diff --git a/cab_booking_management/models/cab_log.py b/cab_booking_management/models/cab_log.py new file mode 100644 index 000000000..2c84ac808 --- /dev/null +++ b/cab_booking_management/models/cab_log.py @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import models, fields, api, _ +from odoo.exceptions import ValidationError +from datetime import date + + +class CabLog(models.Model): + _name = 'cab.log' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + _description = 'Cab' + + name = fields.Many2one('cab.management', string="Name", store=True, required=True) + cab_log_date = fields.Date(string="Date", default=date.today(), required=True) + fuel_used = fields.Float(string="Fuel Used", required=True, help="To get total fuel used in Litre") + seat_capacity = fields.Integer(string="Seat Capacity", related="name.seating_capacity") + seat_available = fields.Integer(string="Seat Available") + cab_location = fields.Char(string="Destination Point", required=True) + cab_location_from = fields.Char(string="Starting Point", required=True) + seat_booked = fields.Integer(string="How many seats you need to book?", required=True) + odo_metre = fields.Float(string="OdoMetre Reading", required=True, help="Total distance covered in Km") + cab_expense = fields.Float(string="Expense", required=True) + cab_log_timing = fields.Many2one('cab.time', string="Time", required=True) + total_passenger = fields.Integer(string="Total Passenger", required=True) + partner_id = fields.Many2one('res.users', string="Customer Name", required=True) + cab_image = fields.Binary(string='Image', store=True, attachment=True) + state = fields.Selection([ + ('draft', 'Draft'), + ('approved', 'Approved'), + ('discard', 'Discard'), + ('cancel', 'Cancelled'), + ('done', 'Done') + ], default='draft') + + @api.onchange('name') + def change_location(self): + for records in self.env['cab.timing'].search([('name.name', '=', self.name.name)]): + if self.name.name == records.name.name: + self.cab_location = records.cab_route_to.name + self.cab_location_from = records.cab_route.name + + @api.one + @api.constrains('cab_log_timing') + def change_time(self): + for records in self.env['cab.timing'].search([('name.name', '=', self.name.name)]): + if self.cab_log_timing: + if self.cab_log_timing not in records.cab_time: + raise ValidationError("No cabs available at given time") + + @api.one + @api.constrains('seat_booked') + def error_message(self): + if self.seat_available < self.seat_booked: + raise ValidationError("No Available Seats") + elif self.seat_booked != self.total_passenger: + raise ValidationError("No of seat requested for booking and total passenger must be equal") + + @api.onchange('seat_booked') + def change_total_passenger(self): + self.total_passenger = self.seat_booked + + @api.one + def action_approve(self): + self.state = "approved" + + @api.one + def action_cancel(self): + self.state = "cancel" + + @api.one + def action_discard(self): + self.state = "discard" + + @api.onchange('cab_log_date', 'state') + def auto_cabs_approve(self): + for data in self.env['cab.configuration'].search([]): + if data.auto_approve != False: + user_obj = self.env.user + if user_obj == data.cab_manager: + self.state = 'approved' + + @api.onchange('cab_log_date', 'name', 'cab_log_timing') + def change_available_seat(self): + for data in self.env['cab.management'].search([('name', '=', self.name.name)]): + flag = 0 + total_seat_booked = 0 + for records in self.env['cab.log'].search([('name.name', '=', data.name)]): + if self.cab_log_date == records.cab_log_date and self.cab_log_timing == records.cab_log_timing: + if self.cab_location == records.cab_location and self.cab_location_from == records.cab_location_from: + total_seat_booked = total_seat_booked+records.seat_booked + flag += 1 + if flag > 0: + test_val = self.seat_capacity - total_seat_booked + self.seat_available = test_val + + else: + self.seat_available = self.seat_capacity + + @api.multi + def action_sent(self): + self.ensure_one() + ir_model_data = self.env['ir.model.data'] + try: + template_id = ir_model_data.get_object_reference('cab_booking_management', 'email_template_edi_cab')[1] + except ValueError: + template_id = False + try: + compose_form_id = ir_model_data.get_object_reference('mail', 'email_compose_message_wizard_form')[1] + except ValueError: + compose_form_id = False + ctx = dict() + ctx.update({ + 'default_model': 'cab.log', + 'default_res_id': self.ids[0], + 'default_use_template': bool(template_id), + 'default_template_id': template_id, + 'default_composition_mode': 'comment', + }) + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form_id, 'form')], + 'view_id': compose_form_id, + 'target': 'new', + 'context': ctx, + } + + +class MailComposeMessage(models.TransientModel): + _inherit = 'mail.compose.message' + + @api.multi + def send_mail(self, auto_commit=False): + if self._context.get('default_model') == 'cab.log' and self._context.get('default_res_id'): + order = self.env['cab.log'].browse([self._context['default_res_id']]) + if order.state == 'approved': + order.state = 'done' + order.sent = True + self = self.with_context(mail_post_autofollow=True) + return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit) diff --git a/cab_booking_management/models/cab_maintanence.py b/cab_booking_management/models/cab_maintanence.py new file mode 100644 index 000000000..f854a3095 --- /dev/null +++ b/cab_booking_management/models/cab_maintanence.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import models, fields, api + + +class CabMaintanence(models.Model): + _name = 'cab.maintanence' + + name = fields.Many2one('cab.management', string="Name", required=True) + cab_log_date = fields.Date(string="Date", required=True) + fuel_used = fields.Float(string="Fuel Used") + odo_metre = fields.Float(string="OdoMetre Reading") + cab_expense = fields.Float(string="Expense") + total_passenger = fields.Integer(string="Total Passenger") + + @api.onchange('cab_log_date') + def total_log_details(self): + total_fuel = 0 + odo_metres = 0 + expense = 0 + passenger = 0 + for data in self.env['cab.log'].search([]): + if data.cab_log_date == self.cab_log_date: + total_fuel += data.fuel_used + odo_metres += data.odo_metre + expense += data.cab_expense + passenger += data.total_passenger + self.fuel_used = total_fuel + self.odo_metre = odo_metres + self.cab_expense = expense + self.total_passenger = passenger + + + diff --git a/cab_booking_management/models/cab_timing.py b/cab_booking_management/models/cab_timing.py new file mode 100644 index 000000000..8d33031e1 --- /dev/null +++ b/cab_booking_management/models/cab_timing.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api + + +class CabTiming(models.Model): + _name = 'cab.timing' + + name = fields.Many2one('cab.management', string="Cab Name", required=True) + cab_time = fields.Many2many('cab.time', 'cab_name_rel', string="Time", required=True, + help="Use this format 00:00,ex: 01:15") + cab_route = fields.Many2one('cab.location', string='Starting Place', required=True) + cab_route_to = fields.Many2one('cab.location', string='Destination Place', required=True) + seat = fields.Integer(string="Seating Capacity", related='name.seating_capacity', required=True) + + @api.multi + def action_log_form_view(self): + return { + 'name': 'CabLog', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'cab.log', + 'type': 'ir.actions.act_window', + 'target': 'current' + } + + +class Time(models.Model): + _name = 'cab.time' + + name = fields.Char(string="Name", required=True, help="Use this format 00:00,ex: 01:15") + + + + + diff --git a/cab_booking_management/security/ir.model.access.csv b/cab_booking_management/security/ir.model.access.csv new file mode 100644 index 000000000..68db70da6 --- /dev/null +++ b/cab_booking_management/security/ir.model.access.csv @@ -0,0 +1,16 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_cab_management,cab.management,model_cab_management,base.group_user,1,1,1,1 +access_cab_maintenanace,cab.maintanence,model_cab_maintanence,base.group_user,1,1,1,1 +access_cab_log,cab.log,model_cab_log,base.group_user,1,1,1,1 +access_cab_timing,cab.timing,model_cab_timing,base.group_user,1,1,1,1 +access_cab_location,cab.location,model_cab_location,base.group_user,1,1,1,1 +access_cab_booking,cab.booking,model_cab_booking,base.group_user,1,1,1,1 +access_cab_conf,cab.configuration,model_cab_configuration,base.group_user,1,1,1,1 +access_cab_time,cab.time,model_cab_time,base.group_user,1,1,1,1 + + + + + + + diff --git a/cab_booking_management/static/description/banner.jpg b/cab_booking_management/static/description/banner.jpg new file mode 100644 index 000000000..8c41b7664 Binary files /dev/null and b/cab_booking_management/static/description/banner.jpg differ diff --git a/cab_booking_management/static/description/booking.png b/cab_booking_management/static/description/booking.png new file mode 100644 index 000000000..da75ae380 Binary files /dev/null and b/cab_booking_management/static/description/booking.png differ diff --git a/cab_booking_management/static/description/cab_activity.png b/cab_booking_management/static/description/cab_activity.png new file mode 100644 index 000000000..f5ab7e04e Binary files /dev/null and b/cab_booking_management/static/description/cab_activity.png differ diff --git a/cab_booking_management/static/description/cab_booking.png b/cab_booking_management/static/description/cab_booking.png new file mode 100644 index 000000000..4d09f542c Binary files /dev/null and b/cab_booking_management/static/description/cab_booking.png differ diff --git a/cab_booking_management/static/description/cab_cancel.png b/cab_booking_management/static/description/cab_cancel.png new file mode 100644 index 000000000..0e97f0816 Binary files /dev/null and b/cab_booking_management/static/description/cab_cancel.png differ diff --git a/cab_booking_management/static/description/cab_conf.png b/cab_booking_management/static/description/cab_conf.png new file mode 100644 index 000000000..a6ff8e21f Binary files /dev/null and b/cab_booking_management/static/description/cab_conf.png differ diff --git a/cab_booking_management/static/description/cab_creation.png b/cab_booking_management/static/description/cab_creation.png new file mode 100644 index 000000000..10f83a8de Binary files /dev/null and b/cab_booking_management/static/description/cab_creation.png differ diff --git a/cab_booking_management/static/description/cab_details.png b/cab_booking_management/static/description/cab_details.png new file mode 100644 index 000000000..4aae5bd6a Binary files /dev/null and b/cab_booking_management/static/description/cab_details.png differ diff --git a/cab_booking_management/static/description/cab_maintain.png b/cab_booking_management/static/description/cab_maintain.png new file mode 100644 index 000000000..aaf675c90 Binary files /dev/null and b/cab_booking_management/static/description/cab_maintain.png differ diff --git a/cab_booking_management/static/description/cybro_logo.png b/cab_booking_management/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/cab_booking_management/static/description/cybro_logo.png differ diff --git a/cab_booking_management/static/description/icon.png b/cab_booking_management/static/description/icon.png new file mode 100644 index 000000000..53f81b27b Binary files /dev/null and b/cab_booking_management/static/description/icon.png differ diff --git a/cab_booking_management/static/description/index.html b/cab_booking_management/static/description/index.html new file mode 100644 index 000000000..086692564 --- /dev/null +++ b/cab_booking_management/static/description/index.html @@ -0,0 +1,177 @@ +
+
+

Cab Booking Management System (CBMS)

+

Manage the cabs with ease

+

Cybrosys Technologies , www.cybrosys.com

+
+

Major Features:

+
    +
  •   Booking the Cab.
  • +
  •   Auto approval Settings in Configuration.
  • +
  •   Cab Logs for Every Trip.
  • +
  •   Record Every Activity Related to CBMS.
  • +
  •   Email Notification for Successful Booking.
  • +
  •   Booking Status.
  • +
  •   View All Cab Activities with Advanced Filttrations.
  • +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+

Cab Booking

+
+

+ We can book cabs from list of cabs based on your time and location. +

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

Auto approval

+
+
+ +
+
+
+

+ Approve cab booking automatically. +

+
+
+
+ +
+
+

Cab Logs for Every Trip

+
+

+ It keep the record of all expenses of each cab trips. +

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

Record Every Activity Related to CBMS

+
+
+ +
+
+
+

+ It shows the total expenses for a cab, on daily basis. +

+
+
+
+ +
+
+

Email Notification for Successful Booking.

+
+

+ Email is sent to the user on successful booking of cab. +

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

Booking Status

+
+
+ +
+
+
+

+ View your status of booking.You can also cancel your booking. +

+
+
+
+ +
+
+

Cab Maintenance

+
+

+ It shows the total expenses for a cab, on daily basis. +

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

View All Cab Activities with Advanced Filttrations

+
+
+ +
+
+
+
+ +
+

You Looking for a free Documentation of this Application.?

+

Give a Request Mail to:    odoo@cybrosys.com

+
+ +
+

Need Any Help?

+ + +
+ + + + diff --git a/cab_booking_management/static/description/log_details.png b/cab_booking_management/static/description/log_details.png new file mode 100644 index 000000000..992758d39 Binary files /dev/null and b/cab_booking_management/static/description/log_details.png differ diff --git a/cab_booking_management/static/description/mail.png b/cab_booking_management/static/description/mail.png new file mode 100644 index 000000000..07eca6214 Binary files /dev/null and b/cab_booking_management/static/description/mail.png differ diff --git a/cab_booking_management/views/cab_booking_view.xml b/cab_booking_management/views/cab_booking_view.xml new file mode 100644 index 000000000..0c655cfd1 --- /dev/null +++ b/cab_booking_management/views/cab_booking_view.xml @@ -0,0 +1,71 @@ + + + + + Cab Booking + cab.booking + +
+
+ +
+

BOOK YOUR CAB

+
+ +
+ + + + + + + + + + + + + + + + + + +
+ + +
+
diff --git a/developer_mode/views/ir_rule_view.xml b/developer_mode/views/ir_rule_view.xml new file mode 100644 index 000000000..3f74bb72c --- /dev/null +++ b/developer_mode/views/ir_rule_view.xml @@ -0,0 +1,14 @@ + + + + + ir.rule + + + + + + + + + diff --git a/discuss_news/README.md b/discuss_news/README.md new file mode 100644 index 000000000..12458ceac --- /dev/null +++ b/discuss_news/README.md @@ -0,0 +1,37 @@ +# World News + +Subscribe to World news Channels from listed channels under Odoo News. Joined channels will be listed under Discuss Menu. + + - Goto https://newsapi.org/ + - Register a new account. + - Get API key. + - Paste under news configurations under News -> Configurations -> settings -> Apply. + - Check the Updated News channels Under menu News + - Join and Read + + +### Depends +[mail] addon Odoo + +### Tech + +* [Python] - Models +* [XML] - Odoo views + +### Installation +- www.odoo.com/documentation/10.0/setup/install.html +- Install our custom addon +- set up https://newsapi.org/ account + +### Usage +> Join News channels under News +> Got Discuss +> Select the joined channels & Read + +License +---- +GNU LESSER GENERAL PUBLIC LICENSE, Version 3 (LGPLv3) +(http://www.gnu.org/licenses/agpl.html) + + + diff --git a/discuss_news/__init__.py b/discuss_news/__init__.py new file mode 100644 index 000000000..d6948c82f --- /dev/null +++ b/discuss_news/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +# from . import controllers +from . import models diff --git a/discuss_news/__manifest__.py b/discuss_news/__manifest__.py new file mode 100644 index 000000000..0b9c891c3 --- /dev/null +++ b/discuss_news/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Hilar AK() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': "World News", + 'version': '10.0.1.0.0', + 'summary': """ World News as Discuss Channels""", + 'description': """ + Users can Maintain news channels and subscribe/unsubscribe from world news channels. + """, + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://cybrosys.com/", + 'category': 'Discuss', + 'depends': ['base', 'mail'], + 'data': [ + 'views/channel_views.xml', + 'views/res_config_view.xml', + 'data/data.xml', + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'application': False +} diff --git a/discuss_news/controllers/__init__.py b/discuss_news/controllers/__init__.py new file mode 100644 index 000000000..8ea93f627 --- /dev/null +++ b/discuss_news/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +# from . import controllers diff --git a/discuss_news/controllers/controllers.py b/discuss_news/controllers/controllers.py new file mode 100644 index 000000000..4c7e11e3b --- /dev/null +++ b/discuss_news/controllers/controllers.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from odoo import http + +# class DiscussNews(http.Controller): +# @http.route('/discuss_news/discuss_news/', auth='public') +# def index(self, **kw): +# return "Hello, world" + +# @http.route('/discuss_news/discuss_news/objects/', auth='public') +# def list(self, **kw): +# return http.request.render('discuss_news.listing', { +# 'root': '/discuss_news/discuss_news', +# 'objects': http.request.env['discuss_news.discuss_news'].search([]), +# }) + +# @http.route('/discuss_news/discuss_news/objects//', auth='public') +# def object(self, obj, **kw): +# return http.request.render('discuss_news.object', { +# 'object': obj +# }) \ No newline at end of file diff --git a/discuss_news/data/data.xml b/discuss_news/data/data.xml new file mode 100644 index 000000000..3856976d4 --- /dev/null +++ b/discuss_news/data/data.xml @@ -0,0 +1,18 @@ + + + + Sync News Channels + + + 30 + minutes + -1 + 1 + + + news_sync + + + + + \ No newline at end of file diff --git a/discuss_news/demo/demo.xml b/discuss_news/demo/demo.xml new file mode 100644 index 000000000..32ec72eed --- /dev/null +++ b/discuss_news/demo/demo.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/discuss_news/models/__init__.py b/discuss_news/models/__init__.py new file mode 100644 index 000000000..5305644df --- /dev/null +++ b/discuss_news/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models \ No newline at end of file diff --git a/discuss_news/models/models.py b/discuss_news/models/models.py new file mode 100644 index 000000000..f8b6161ba --- /dev/null +++ b/discuss_news/models/models.py @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields, api +import requests +import logging +import json + +_logger = logging.getLogger(__name__) + +class NewsChannel(models.Model): + _inherit = 'mail.channel' + + is_news_channel = fields.Boolean(default=False, invisible=True) + language_id = fields.Many2one('res.lang', 'Language') + url = fields.Char('URL') + category = fields.Char('Category') + channel_ref = fields.Char('Channel Reference', invisible=True) + last_updated = fields.Datetime("Last Updated") + + def update_news_content(self, channel, contents): + """ + { + 'body': HTML content of the message + 'model': u'res.partner', + 'record_name': u'Agrolait', + 'attachment_ids': [ + { + 'file_type_icon': u'webimage', + 'id': 45, + 'name': u'sample.png', + 'filename': u'sample.png' + } + ], + 'needaction_partner_ids': [], # list of partner ids + 'res_id': 7, + 'tracking_value_ids': [ + { + 'old_value': "", + 'changed_field': "Customer", + 'id': 2965, + 'new_value': "Axelor" + } + ], + 'author_id': (3, u'Administrator'), + 'email_from': 'sacha@pokemon.com' # email address or False + 'subtype_id': (1, u'Discussions'), + 'channel_ids': [], # list of channel ids + 'date': '2015-06-30 08:22:33', + 'partner_ids': [[7, "Sacha Du Bourg-Palette"]], # list of partner name_get + 'message_type': u'comment', + 'id': 59, + 'subject': False + 'is_note': True # only if the subtype is internal + } + """ + body = contents.get('articles', False) + body_contents = "" + for data in body: + body_contents += """ +

+

+

Title:%s

+

Description:%s

+

Author:%s publishedAt:%s

+

Read more..

+

+


+ """%(data.get('urlToImage', False), data.get('title', False), data.get('description', False), + data.get('author', False), data.get('publishedAt', False), data.get('url', False),) + + data = { + 'body': body_contents, + 'model': u'mail.channel', + 'record_name': channel.name, + 'res_id': channel.id, + 'author_id': 3, + 'email_from': u'Administrator ', # email address or False + 'subtype_id': 1, + 'channel_ids': [channel.id], # list of channel ids + 'message_type': u'notification', + 'subject': False, + 'parent_id': False, + 'reply_to': u'YourCompany ', + } + + data.update({'message_id': self.env['mail.message'].sudo()._get_message_id(data)}) + self.env['mail.message'].sudo().create(data) + + + @api.model + def news_sync(self): + """ + Sync the news according to the each channels, where the news api not providing a single sync for all channels, + so we are iterating here on each channels to sync. + Lets hope for a good Updated api from them in future + :return: + """ + default_key = self.env['news.channel.config.settings'].get_default_news_api_key([]) + api_key = default_key.get('news_api_key', False) + if api_key: + query = """delete from mail_message m where m.res_id in + (select distinct id from mail_channel c where c.is_news_channel = True)""" + self._cr.execute(query) + channels_pool = self.search([('is_news_channel', '=', True)]) + url = "https://newsapi.org/v1/articles" + querystring = { + "apiKey": api_key, + } + headers = { + 'cache-control': "no-cache", + } + for channels in channels_pool: + querystring.update({"source": channels.channel_ref, }) + response = requests.request("GET", url, headers=headers, params=querystring) + try: + if response.status_code == 200: + contents = json.loads(response.text) + if contents and contents.get('status') == 'ok': + self.update_news_content(channels, contents) + except Exception as e: + _logger.info(e) + continue + + + +class NewsChannelConfigSettings(models.Model): + _name = 'news.channel.config.settings' + _inherit = 'res.config.settings' + + news_api_key = fields.Char('Api Key') + + @api.model + def get_default_news_api_key(self, fields): + ir_values = self.env['ir.values'] + news_api_key = ir_values.get_default('news.channel.config.settings', 'news_api_key') + return {'news_api_key': news_api_key} + + @api.multi + def set_default_news_api_key(self): + ir_values = self.env['ir.values'] + for record in self: + ir_values.sudo().set_default('news.channel.config.settings', 'news_api_key', record.news_api_key) + + @api.multi + def execute(self): + """ + Which invokes when you click on apply button on config page + Here we update all channels from news api, list under menu 'News' + Url https://newsapi.org/v1/sources lists the sources + :return: {'tag': 'reload', 'type': 'ir.actions.client'} + """ + print self.news_api_key, "self.news_api_keyself.news_api_key" + if self.news_api_key: + try: + url = "https://newsapi.org/v1/sources" + querystring = {"language": "en"} + headers = { + 'cache-control': "no-cache" + } + response = requests.request("GET", url, headers=headers, params=querystring) + data = eval(response.text) + language_model = self.env['res.lang'] + Channel = self.env['mail.channel'] + channel_data = {} + if data.get('status') == 'ok': + for values in data['sources']: + channel_id = Channel.search([('channel_ref', '=', values['id'])]) + if not len(channel_id): + language = language_model.search([('iso_code', '=', values.get('language', False))]) + channel_data.update({ + 'name': values['name'], + 'channel_ref': values['id'], + 'language_id': language and language.id, + 'category': values['category'], + 'url': values['url'], + 'is_news_channel': True, + 'description': values['description'], + }) + Channel.create(channel_data) + return super(NewsChannelConfigSettings, self).execute() + else: + raise Exception + except Exception as e: + _logger.info(e) + else: + return Warning("Give Proper Api Key") diff --git a/discuss_news/security/ir.model.access.csv b/discuss_news/security/ir.model.access.csv new file mode 100644 index 000000000..74a91e99a --- /dev/null +++ b/discuss_news/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_discuss_news_discuss_news,discuss_news.discuss_news,model_discuss_news_discuss_news,,1,0,0,0 \ No newline at end of file diff --git a/discuss_news/static/description/API.png b/discuss_news/static/description/API.png new file mode 100644 index 000000000..391fa24cd Binary files /dev/null and b/discuss_news/static/description/API.png differ diff --git a/discuss_news/static/description/GET.png b/discuss_news/static/description/GET.png new file mode 100644 index 000000000..c2e9c30fb Binary files /dev/null and b/discuss_news/static/description/GET.png differ diff --git a/discuss_news/static/description/banner.jpg b/discuss_news/static/description/banner.jpg new file mode 100644 index 000000000..e88bd7b80 Binary files /dev/null and b/discuss_news/static/description/banner.jpg differ diff --git a/discuss_news/static/description/channels.png b/discuss_news/static/description/channels.png new file mode 100644 index 000000000..733d1b116 Binary files /dev/null and b/discuss_news/static/description/channels.png differ diff --git a/discuss_news/static/description/cybro_logo.png b/discuss_news/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/discuss_news/static/description/cybro_logo.png differ diff --git a/discuss_news/static/description/icon.png b/discuss_news/static/description/icon.png new file mode 100644 index 000000000..9af07091a Binary files /dev/null and b/discuss_news/static/description/icon.png differ diff --git a/discuss_news/static/description/index.html b/discuss_news/static/description/index.html new file mode 100644 index 000000000..b46128d04 --- /dev/null +++ b/discuss_news/static/description/index.html @@ -0,0 +1,155 @@ +
+
+

News Channels Subscription

+

Cybrosys Technologies

+
+
+
+
+

Subscribe News From listed news Channels

+

+ Subscribe to various news Channels provided under custom menu "NEWS". + Subscribed News channels will be listed under Discuss Menu. +

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

Need Any Help?

+ +
+ diff --git a/discuss_news/static/description/join.png b/discuss_news/static/description/join.png new file mode 100644 index 000000000..28411aba8 Binary files /dev/null and b/discuss_news/static/description/join.png differ diff --git a/discuss_news/static/description/news_discuss.png b/discuss_news/static/description/news_discuss.png new file mode 100644 index 000000000..eeb6d6877 Binary files /dev/null and b/discuss_news/static/description/news_discuss.png differ diff --git a/discuss_news/static/description/register.png b/discuss_news/static/description/register.png new file mode 100644 index 000000000..85e323ba8 Binary files /dev/null and b/discuss_news/static/description/register.png differ diff --git a/discuss_news/static/description/res_conf.png b/discuss_news/static/description/res_conf.png new file mode 100644 index 000000000..70b262bc2 Binary files /dev/null and b/discuss_news/static/description/res_conf.png differ diff --git a/discuss_news/views/channel_views.xml b/discuss_news/views/channel_views.xml new file mode 100644 index 000000000..49a29b892 --- /dev/null +++ b/discuss_news/views/channel_views.xml @@ -0,0 +1,34 @@ + + + + News Channels View + mail.channel + + + + + + + + + + + + + + News Channels + ir.actions.act_window + mail.channel + kanban,tree,form + [('is_news_channel', '=', True)] + + + + + \ No newline at end of file diff --git a/discuss_news/views/res_config_view.xml b/discuss_news/views/res_config_view.xml new file mode 100644 index 000000000..936709411 --- /dev/null +++ b/discuss_news/views/res_config_view.xml @@ -0,0 +1,39 @@ + + + + Configure News Channels + news.channel.config.settings + + +
+
+
+ + +
+
+
+ + + Configure News + news.channel.config.settings + form + inline + + + +
+
diff --git a/discuss_news/views/templates.xml b/discuss_news/views/templates.xml new file mode 100644 index 000000000..71a9d511c --- /dev/null +++ b/discuss_news/views/templates.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/email_id_validation/README.rst b/email_id_validation/README.rst new file mode 100644 index 000000000..ed6ce8c99 --- /dev/null +++ b/email_id_validation/README.rst @@ -0,0 +1,24 @@ +Validate E-mail ID v10 +====================== +With this plugin, you can validate the E-mail ID entered in Partner/Employee form. This app will help +you to maintain a consistent and reliable address details for your Partner/Employee. +The plugin uses 'addr-spec' portion of RFC 2822 for validating the ID.That is, with this plugin you can +correctly identify any email address that is likely to be in use as of 2011. + +Installation +============ +You must install following packages to work the App properly: +* pip install validate_email +* pip install pyDNS + +NOTE: Since the Plugin performs verification through online you must be connected to the internet while +checking the Id + +Configuration +============= + +Nothing to configure. + +Credits +======= +Developer: Saritha Sahadevan @ cybrosys, saritha@cybrosys.in diff --git a/email_id_validation/__init__.py b/email_id_validation/__init__.py new file mode 100644 index 000000000..59befdb62 --- /dev/null +++ b/email_id_validation/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Saritha Sahadevan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from . import models diff --git a/email_id_validation/__manifest__.py b/email_id_validation/__manifest__.py new file mode 100644 index 000000000..066c76552 --- /dev/null +++ b/email_id_validation/__manifest__.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Saritha Sahadevan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': "Validate E-mail ID", + 'version': '10.0.1.0.0', + 'summary': """Check Whether A Given E-mail ID Is Valid Or Not""", + 'description': """Check Whether A Given E-mail ID Is Valid Or Not In Partner And Employee Form""", + 'author': "Cybrosys Techno Solutions", + 'website': "https://www.cybrosys.com", + 'maintainer': 'Cybrosys Techno Solutions', + 'category': 'Extra Tools', + 'depends': ['base', 'hr', 'sale'], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'external_dependencies': {'python': ['validate_email', 'pyDNS']}, + 'application': False, +} diff --git a/email_id_validation/models/__init__.py b/email_id_validation/models/__init__.py new file mode 100644 index 000000000..85f906a1a --- /dev/null +++ b/email_id_validation/models/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Saritha Sahadevan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from . import email_id_validation diff --git a/email_id_validation/models/email_id_validation.py b/email_id_validation/models/email_id_validation.py new file mode 100644 index 000000000..4035d7bdf --- /dev/null +++ b/email_id_validation/models/email_id_validation.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Saritha Sahadevan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from validate_email import validate_email +from odoo.exceptions import ValidationError +from odoo import models, api, _ + + +class PartnerEmailValidation(models.Model): + _inherit = 'res.partner' + + @api.constrains('email') + def validate(self): + is_valid = validate_email(self.email, check_mx=False, verify=True, debug=False, smtp_timeout=10) + if is_valid is not True: + raise ValidationError(_('You can use only valid email address.Email address %s is invalid or does not exit') + % self.email) + + +class EmployeeEmailValidation(models.Model): + _inherit = 'hr.employee' + + @api.constrains('work_email') + def validate(self): + is_valid = validate_email(self.work_email, check_mx=False, verify=True, debug=False, smtp_timeout=10) + if is_valid is not True: + raise ValidationError(_('You can use only valid email address.Email address %s is invalid or does not exit') + % self.work_email) diff --git a/email_id_validation/static/description/banner.jpg b/email_id_validation/static/description/banner.jpg new file mode 100644 index 000000000..8b0a3aab9 Binary files /dev/null and b/email_id_validation/static/description/banner.jpg differ diff --git a/email_id_validation/static/description/cybro_logo.png b/email_id_validation/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/email_id_validation/static/description/cybro_logo.png differ diff --git a/email_id_validation/static/description/icon.png b/email_id_validation/static/description/icon.png new file mode 100644 index 000000000..a72272ed7 Binary files /dev/null and b/email_id_validation/static/description/icon.png differ diff --git a/email_id_validation/static/description/index.html b/email_id_validation/static/description/index.html new file mode 100644 index 000000000..56c820013 --- /dev/null +++ b/email_id_validation/static/description/index.html @@ -0,0 +1,93 @@ +
+
+

Validate E-mail ID

+

Check Whether A Given E-mail ID Is Valid Or Not .

+

Cybrosys Technologies

+
+
+ +
+
+
+

Overview

+

+ With this plugin, you can validate the E-mail ID entered in Partner/Employee form. This app will help + you to maintain a consistent and reliable address details for your Partner/Employee. + The plugin uses 'addr-spec' portion of RFC 2822 for validating the ID.That is, with this plugin you can + correctly identify any email address that is likely to be in use as of 2011. +

+
+
+
+ +
+
+

Validate Email ID

+

+ You will get a warning message if you entered an invalid ID. +

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

Installation

+

+ You must install following packages to work the App properly: +

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

+ Since the Plugin performs verification through online you must be connected to the internet while + checking the Id +

+
+
+ +
+

Need Any Help?

+ +
+ + + + diff --git a/email_id_validation/static/description/pyDns.png b/email_id_validation/static/description/pyDns.png new file mode 100644 index 000000000..1c8efa10c Binary files /dev/null and b/email_id_validation/static/description/pyDns.png differ diff --git a/email_id_validation/static/description/validate_email.png b/email_id_validation/static/description/validate_email.png new file mode 100644 index 000000000..2514271aa Binary files /dev/null and b/email_id_validation/static/description/validate_email.png differ diff --git a/email_id_validation/static/description/validation.png b/email_id_validation/static/description/validation.png new file mode 100644 index 000000000..bbef915ea Binary files /dev/null and b/email_id_validation/static/description/validation.png differ diff --git a/email_id_validation/static/description/validation_hr.png b/email_id_validation/static/description/validation_hr.png new file mode 100644 index 000000000..428b66e1f Binary files /dev/null and b/email_id_validation/static/description/validation_hr.png differ diff --git a/employee_check_list/__init__.py b/employee_check_list/__init__.py new file mode 100644 index 000000000..797b4cfba --- /dev/null +++ b/employee_check_list/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models + diff --git a/employee_check_list/__manifest__.py b/employee_check_list/__manifest__.py new file mode 100644 index 000000000..722f2d123 --- /dev/null +++ b/employee_check_list/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employee Checklist', + 'version': '10.0.1.0.0', + 'summary': """Manages Employee's Entry & Exit Process""", + 'description': """This module is used to remembering the employee's entry and exit progress.""", + 'category': 'Generic Modules/Human Resources', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'employee_documents_expiry'], + 'data': [ + 'security/ir.model.access.csv', + 'views/employee_form_inherit_view.xml', + 'views/checklist_view.xml', + 'views/settings_view.xml', + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_check_list/__manifest__.py~ b/employee_check_list/__manifest__.py~ new file mode 100644 index 000000000..4934f8f44 --- /dev/null +++ b/employee_check_list/__manifest__.py~ @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employee Checklist', + 'version': '10.0.1.0.0', + 'summary': """Manages Employee's Entry & Exit Process""", + 'description': """This module is used to remembering the employee's entry and exit progress.""", + 'category': "Human Resources", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'employee_documents_expiry'], + 'data': [ + 'security/ir.model.access.csv', + 'views/employee_form_inherit_view.xml', + 'views/checklist_view.xml', + 'views/settings_view.xml', + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_check_list/models/__init__.py b/employee_check_list/models/__init__.py new file mode 100644 index 000000000..d28c4c4c9 --- /dev/null +++ b/employee_check_list/models/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import employee_master_inherit +import settings + + diff --git a/employee_check_list/models/employee_master_inherit.py b/employee_check_list/models/employee_master_inherit.py new file mode 100644 index 000000000..c0e49e7e8 --- /dev/null +++ b/employee_check_list/models/employee_master_inherit.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api + + +class EmployeeMasterInherit(models.Model): + _inherit = 'hr.employee' + + @api.depends('exit_checklist') + def exit_progress(self): + for each in self: + total_len = self.env['employee.checklist'].search_count([('document_type', '=', 'exit')]) + entry_len = len(each.exit_checklist) + if total_len != 0: + each.exit_progress = (entry_len * 100) / total_len + + @api.depends('entry_checklist') + def entry_progress(self): + for each in self: + total_len = self.env['employee.checklist'].search_count([('document_type', '=', 'entry')]) + entry_len = len(each.entry_checklist) + if total_len != 0: + each.entry_progress = (entry_len*100) / total_len + + entry_checklist = fields.Many2many('employee.checklist', 'entry_obj', 'check_hr_rel', 'hr_check_rel', + string='Entry Process', + domain=[('document_type', '=', 'entry')]) + exit_checklist = fields.Many2many('employee.checklist', 'exit_obj', 'exit_hr_rel', 'hr_exit_rel', + string='Exit Process', + domain=[('document_type', '=', 'exit')]) + entry_progress = fields.Float(compute=entry_progress, string='Entry Progress', store=True, default=0.0) + exit_progress = fields.Float(compute=exit_progress, string='Exit Progress', store=True, default=0.0) + maximum_rate = fields.Integer(default=100) + check_list_enable = fields.Boolean(invisible=True, copy=False) + + +class EmployeeDocumentInherit(models.Model): + _inherit = 'hr.employee.document' + + @api.model + def create(self, vals): + result = super(EmployeeDocumentInherit, self).create(vals) + if result.document_name.document_type == 'entry': + result.employee_ref.write({'entry_checklist': [(4, result.document_name.id)]}) + if result.document_name.document_type == 'exit': + result.employee_ref.write({'exit_checklist': [(4, result.document_name.id)]}) + return result + + @api.multi + def unlink(self): + for result in self: + if result.document_name.document_type == 'entry': + result.employee_ref.write({'entry_checklist': [(5, result.document_name.id)]}) + if result.document_name.document_type == 'exit': + result.employee_ref.write({'exit_checklist': [(5, result.document_name.id)]}) + res = super(EmployeeDocumentInherit, self).unlink() + return res + + +class EmployeeChecklistInherit(models.Model): + _inherit = 'employee.checklist' + + entry_obj = fields.Many2many('hr.employee', 'entry_checklist', 'hr_check_rel', 'check_hr_rel', + invisible=1) + exit_obj = fields.Many2many('hr.employee', 'exit_checklist', 'hr_exit_rel', 'exit_hr_rel', + invisible=1) diff --git a/employee_check_list/models/settings.py b/employee_check_list/models/settings.py new file mode 100644 index 000000000..cb2afc17f --- /dev/null +++ b/employee_check_list/models/settings.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields, api + + +class MenuThemes(models.Model): + _name = 'hr.settings' + _inherit = 'res.config.settings' + + enable_checklist = fields.Boolean(string='Enable Checklist Progress in Kanban?') + + @api.multi + def set_enable_checklist(self): + ir_values = self.env['ir.values'] + enable_checklist = self.enable_checklist + ir_values.set_default('hr.settings', 'enable_checklist', enable_checklist) + emp_obj = self.env['hr.employee'].search([]) + for each in emp_obj: + each.write({'check_list_enable': enable_checklist}) + diff --git a/employee_check_list/security/ir.model.access.csv b/employee_check_list/security/ir.model.access.csv new file mode 100644 index 000000000..05f0cf020 --- /dev/null +++ b/employee_check_list/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_hr.settings_manager,hr.settings.manager,model_hr_settings,hr.group_hr_manager,1,1,1,1 diff --git a/employee_check_list/static/description/banner.jpg b/employee_check_list/static/description/banner.jpg new file mode 100644 index 000000000..185536156 Binary files /dev/null and b/employee_check_list/static/description/banner.jpg differ diff --git a/employee_check_list/static/description/cybro_logo.png b/employee_check_list/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/employee_check_list/static/description/cybro_logo.png differ diff --git a/employee_check_list/static/description/entry_checklist.png b/employee_check_list/static/description/entry_checklist.png new file mode 100644 index 000000000..9a492f258 Binary files /dev/null and b/employee_check_list/static/description/entry_checklist.png differ diff --git a/employee_check_list/static/description/exit_checklist.png b/employee_check_list/static/description/exit_checklist.png new file mode 100644 index 000000000..ea95aae3c Binary files /dev/null and b/employee_check_list/static/description/exit_checklist.png differ diff --git a/employee_check_list/static/description/form_view.png b/employee_check_list/static/description/form_view.png new file mode 100644 index 000000000..dddd63a01 Binary files /dev/null and b/employee_check_list/static/description/form_view.png differ diff --git a/employee_check_list/static/description/icon.png b/employee_check_list/static/description/icon.png new file mode 100644 index 000000000..0f20b8400 Binary files /dev/null and b/employee_check_list/static/description/icon.png differ diff --git a/employee_check_list/static/description/index.html b/employee_check_list/static/description/index.html new file mode 100644 index 000000000..baecedc30 --- /dev/null +++ b/employee_check_list/static/description/index.html @@ -0,0 +1,141 @@ +
+
+

Employee Exit/Entry Checklist

+

Manages Employees Entry & Exit Process

+

Cybrosys Technologies

+
+
+

Features:

+
+ Managing entry/exit process.
+ Automatic process on document attachments.
+ Option to enable Gauge widget for employee kanban.
+ Entry/Exit Percentpie in employee form view.
+ Entry Progressbar in employee tree view.
+
+
+
+ +
+
+
+

Overview

+

+A well functioning human resource department will lay down a number procedure and process before an employee during joining/resigning time. It may be submission/Return of a certificate or attending a conference etc. +A person has to undergo all these checklist items before being admitted/resigned. The module simplifies the process by providing you a checklist to mark the proceedings. It will also display the PercentPie of the checklist items completed. + +

+
+
+
+ +
+
+
+

+

Entry/Exit Checklist

+

+

+ + +
+
+ +
+
+
+

+

Employee From View With PercentPie

+

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

+

Employee Tree View With Progressbar

+

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

+

Employee Kanban View with Gauge

+

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

+

Configuration

+

+
+
+
+ +
+
+
+
+ +
+

Need Any Help?

+ +
+ diff --git a/employee_check_list/static/description/index.html~ b/employee_check_list/static/description/index.html~ new file mode 100644 index 000000000..bb6cf0ca6 --- /dev/null +++ b/employee_check_list/static/description/index.html~ @@ -0,0 +1,140 @@ +
+
+

Employee Exit/Entry Checklist

+

Manages Employees Entry & Exit Process

+

Cybrosys Technologies

+
+
+

Features:

+
+ Managing entry/exit process.
+ Automatic process on document attachments.
+ Option to enable Gauge widget for employee kanban.
+ Entry/Exit Percentpie in employee form view.
+ Entry Progressbar in employee tree view.
+
+
+
+ +
+
+
+

Overview

+

+A well functioning human resource department will lay down a number procedure and process before an employee during joining/resigning time. It may be submission/Return of a certificate or attending a conference etc. +A person has to undergo all these checklist items before being admitted/resigned. The module simplifies the process by providing you a checklist to mark the proceedings. It will also display the PercentPie of the checklist items completed. + +

+
+
+
+ +
+
+
+

+

Entry/Exit Checklist

+

+

+ + +
+
+ +
+
+
+

+

Employee From View With PercentPie

+

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

+

Employee Tree View With Progressbar

+

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

+

Employee Kanban View with Gauge

+

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

+

Configuration

+

+
+
+
+ +
+
+
+
+ +
+

Need Any Help?

+ +
diff --git a/employee_check_list/static/description/kanban_view.png b/employee_check_list/static/description/kanban_view.png new file mode 100644 index 000000000..a8fc2bc2b Binary files /dev/null and b/employee_check_list/static/description/kanban_view.png differ diff --git a/employee_check_list/static/description/settings.png b/employee_check_list/static/description/settings.png new file mode 100644 index 000000000..f1360fcfd Binary files /dev/null and b/employee_check_list/static/description/settings.png differ diff --git a/employee_check_list/static/description/tree_view.png b/employee_check_list/static/description/tree_view.png new file mode 100644 index 000000000..26cd0c7af Binary files /dev/null and b/employee_check_list/static/description/tree_view.png differ diff --git a/employee_check_list/views/checklist_view.xml b/employee_check_list/views/checklist_view.xml new file mode 100644 index 000000000..2340943a3 --- /dev/null +++ b/employee_check_list/views/checklist_view.xml @@ -0,0 +1,37 @@ + + + + Entry Checklist + ir.actions.act_window + employee.checklist + form + tree,form + [('document_type', '=', 'entry')] + {"default_document_type":'entry'} + +

+ Click to create a New Entry Checklist +

+
+
+ + + Exit Checklist + ir.actions.act_window + employee.checklist + form + tree,form + [('document_type', '=', 'exit')] + {"default_document_type":'exit'} + +

+ Click to create a New Exit Checklist +

+
+
+ + + +
\ No newline at end of file diff --git a/employee_check_list/views/employee_form_inherit_view.xml b/employee_check_list/views/employee_form_inherit_view.xml new file mode 100644 index 000000000..08327516e --- /dev/null +++ b/employee_check_list/views/employee_form_inherit_view.xml @@ -0,0 +1,62 @@ + + + + hr.employee.form.view + hr.employee + + + +
+ + +
+
+ + + + + + + + + + + + + +
+
+ + + hr.employee.tree.view + hr.employee + + + + + + + + + + hr.employee.kanban.view + hr.employee + + + + + + + + + +
  • + + Entry Progress + +
  • +
    +
    +
    +
    \ No newline at end of file diff --git a/employee_check_list/views/settings_view.xml b/employee_check_list/views/settings_view.xml new file mode 100644 index 000000000..8adcdbf8a --- /dev/null +++ b/employee_check_list/views/settings_view.xml @@ -0,0 +1,33 @@ + + + + + hr.settings.form + hr.settings + +
    +
    +
    + + + + + +
    +
    + + + Hr Settings + hr.settings + form + inline + + + +
    +
    \ No newline at end of file diff --git a/employee_creation_from_user/__init__.py b/employee_creation_from_user/__init__.py new file mode 100644 index 000000000..3d66db91d --- /dev/null +++ b/employee_creation_from_user/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import employee_creation_from_user diff --git a/employee_creation_from_user/__manifest__.py b/employee_creation_from_user/__manifest__.py new file mode 100644 index 000000000..875a63355 --- /dev/null +++ b/employee_creation_from_user/__manifest__.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employees From User', + 'version': '10.0.1.0.0', + 'summary': 'This module automatically creates employee while creating user', + 'description': 'This module helps you to create employees automatically while creating users', + 'category': 'Generic Modules/Human Resources', + 'author': 'Cybrosys Techno Solutions', + 'website': 'http://www.cybrosys.com', + 'company': 'Cybrosys Techno Solutions', + 'depends': ['base', 'hr'], + 'data': ['employee_creation_from_user_view.xml'], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_creation_from_user/__manifest__.py~ b/employee_creation_from_user/__manifest__.py~ new file mode 100644 index 000000000..96ce7137f --- /dev/null +++ b/employee_creation_from_user/__manifest__.py~ @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employees From User', + 'version': '10.0.1.0.0', + 'summary': 'This module automatically creates employee while creating user', + 'description': 'This module helps you to create employees automatically while creating users', + 'category': 'Human Resources', + 'author': 'Cybrosys Techno Solutions', + 'website': 'http://www.cybrosys.com', + 'company': 'Cybrosys Techno Solutions', + 'depends': ['base', 'hr'], + 'data': ['employee_creation_from_user_view.xml'], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_creation_from_user/employee_creation_from_user.py b/employee_creation_from_user/employee_creation_from_user.py new file mode 100644 index 000000000..e5498df15 --- /dev/null +++ b/employee_creation_from_user/employee_creation_from_user.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api, _ + + +class ResUsersInherit(models.Model): + _inherit = 'res.users' + + employee_id = fields.Many2one('hr.employee', + string='Related Employee', ondelete='restrict', auto_join=True, + help='Employee-related data of the user') + + @api.model + def create(self, vals): + result = super(ResUsersInherit, self).create(vals) + result['employee_id'] = self.env['hr.employee'].create({'name': result['name'], + 'user_id': result['id'], + 'address_home_id': result['partner_id'].id}) + return result diff --git a/employee_creation_from_user/employee_creation_from_user.py~ b/employee_creation_from_user/employee_creation_from_user.py~ new file mode 100644 index 000000000..b3297ba78 --- /dev/null +++ b/employee_creation_from_user/employee_creation_from_user.py~ @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api, _ + + +class ResUsersInherit(models.Model): + _inherit = 'res.users' + + employee_id = fields.Many2one('hr.employee', + string='Related Employee', ondelete='restrict', auto_join=True, + help='Partner-related data of the user') + + @api.model + def create(self, vals): + result = super(ResUsersInherit, self).create(vals) + result['employee_id'] = self.env['hr.employee'].create({'name': vals['name'], + 'user_id': result['id'], + 'address_home_id': result['partner_id'].id}) + return result diff --git a/employee_creation_from_user/employee_creation_from_user_view.xml b/employee_creation_from_user/employee_creation_from_user_view.xml new file mode 100644 index 000000000..68c956e80 --- /dev/null +++ b/employee_creation_from_user/employee_creation_from_user_view.xml @@ -0,0 +1,16 @@ + + + + + res.users.form + res.users + + + + + + + + + \ No newline at end of file diff --git a/employee_creation_from_user/static/description/11.png b/employee_creation_from_user/static/description/11.png new file mode 100644 index 000000000..82defadb2 Binary files /dev/null and b/employee_creation_from_user/static/description/11.png differ diff --git a/employee_creation_from_user/static/description/22.png b/employee_creation_from_user/static/description/22.png new file mode 100644 index 000000000..d67db7a86 Binary files /dev/null and b/employee_creation_from_user/static/description/22.png differ diff --git a/employee_creation_from_user/static/description/banner.jpg b/employee_creation_from_user/static/description/banner.jpg new file mode 100644 index 000000000..917ad52d8 Binary files /dev/null and b/employee_creation_from_user/static/description/banner.jpg differ diff --git a/employee_creation_from_user/static/description/cybro_logo.png b/employee_creation_from_user/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/employee_creation_from_user/static/description/cybro_logo.png differ diff --git a/employee_creation_from_user/static/description/icon.png b/employee_creation_from_user/static/description/icon.png new file mode 100644 index 000000000..2fb2b5746 Binary files /dev/null and b/employee_creation_from_user/static/description/icon.png differ diff --git a/employee_creation_from_user/static/description/index.html b/employee_creation_from_user/static/description/index.html new file mode 100644 index 000000000..27488401e --- /dev/null +++ b/employee_creation_from_user/static/description/index.html @@ -0,0 +1,65 @@ +
    +
    +

    Employee From User

    +

    An employee will creates automatically while creating user

    +

    Author : Cybrosys Techno Solutions , www.cybrosys.com

    +
    +
    +
    + ♠This module automatically creates while creating user. +
    +
    +
    + +
    +
    +
    +

    + ☛An employee will creates automatically while creating user. +

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

    Need Any Help?

    + +
    + + diff --git a/employee_creation_from_user/static/description/index.html~ b/employee_creation_from_user/static/description/index.html~ new file mode 100644 index 000000000..88bd2522b --- /dev/null +++ b/employee_creation_from_user/static/description/index.html~ @@ -0,0 +1,65 @@ +
    +
    +

    Employee From User

    +

    An employee will creates automatically while creating user

    +

    Author : Cybrosys Techno Solutions , www.cybrosys.com

    +
    +
    +
    + ♠This Module automatically creates while creating user. +
    +
    +
    + +
    +
    +
    +

    + ☛An employee will creates automatically while creating user. +

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

    Need Any Help?

    + +
    + + diff --git a/employee_documents_expiry/README.md b/employee_documents_expiry/README.md new file mode 100644 index 000000000..bc2b93c7d --- /dev/null +++ b/employee_documents_expiry/README.md @@ -0,0 +1,26 @@ +Employee Documents +------------------ +Supporting Addon for HR, Manages Employee Related Documents + +Overview +-------- +Each and every detail associated with an employee is useful for any organization for better Human resource management. +So the employee documents with such necessary information must be saved and used accordingly. +'Employee Documents' is a useful tool that can help you to store and manage the employee related +documents like certificates, appraisal reports, passport, license etc. +The application also allows you to set an alert message on reaching the expiration/any other +related dates of a document (like an expiration of passport) + +Connect with experts +-------------------- + +If you have any question/queries/additional works on this module, You can drop an email directly to Cybrosys. + +Contacts +-------- + +info - info@cybrosys.com +Cybrosys Odoo - odoo@cybrosys.com +Nilmar Shereef - shereef@cybrosys.in +Jesni Banu - jesni@cybrosys.in + diff --git a/employee_documents_expiry/__init__.py b/employee_documents_expiry/__init__.py new file mode 100644 index 000000000..f0c1cf4f4 --- /dev/null +++ b/employee_documents_expiry/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models diff --git a/employee_documents_expiry/__manifest__.py b/employee_documents_expiry/__manifest__.py new file mode 100644 index 000000000..8092f30fc --- /dev/null +++ b/employee_documents_expiry/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employee Documents', + 'version': '10.0.2.1', + 'summary': """Manages Employee Documents With Expiry Notifications.""", + 'description': """Manages Employee Related Documents with Expiry Notifications.""", + 'category': 'Generic Modules/Human Resources', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'hr'], + 'data': [ + 'security/ir.model.access.csv', + 'views/employee_check_list_view.xml', + 'views/employee_document_view.xml', + ], + 'demo': ['data/data.xml'], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_documents_expiry/__manifest__.py~ b/employee_documents_expiry/__manifest__.py~ new file mode 100644 index 000000000..9aef8c8a3 --- /dev/null +++ b/employee_documents_expiry/__manifest__.py~ @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employee Documents', + 'version': '10.0.2.0', + 'summary': """Manages Employee Documents With Expiry Notifications.""", + 'description': """Manages Employee Related Documents with Expiry Notifications.""", + 'category': 'Generic Modules/Human Resources', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'hr'], + 'data': [ + 'security/ir.model.access.csv', + 'views/employee_check_list_view.xml', + 'views/employee_document_view.xml', + ], + 'demo': ['data/data.xml'], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_documents_expiry/data/data.xml b/employee_documents_expiry/data/data.xml new file mode 100644 index 000000000..ef0581a14 --- /dev/null +++ b/employee_documents_expiry/data/data.xml @@ -0,0 +1,23 @@ + + + + Education Certificate + entry + + + Salary Certificate + entry + + + Experience Certificate + entry + + + Experience Certificate + exit + + + Salary Certificate + exit + + \ No newline at end of file diff --git a/employee_documents_expiry/models/__init__.py b/employee_documents_expiry/models/__init__.py new file mode 100644 index 000000000..217a1d901 --- /dev/null +++ b/employee_documents_expiry/models/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import employee_documents +import employee_entry_exit_check_list diff --git a/employee_documents_expiry/models/employee_documents.py b/employee_documents_expiry/models/employee_documents.py new file mode 100644 index 000000000..4fdab208b --- /dev/null +++ b/employee_documents_expiry/models/employee_documents.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from datetime import datetime,date, timedelta +from odoo import models, fields, api, _ +from odoo.exceptions import Warning + + +class HrEmployeeDocument(models.Model): + _name = 'hr.employee.document' + _description = 'HR Employee Documents' + + def mail_reminder(self): + now = datetime.now() + timedelta(days=1) + date_now = now.date() + match = self.search([]) + for i in match: + if i.expiry_date: + exp_date = fields.Date.from_string(i.expiry_date) - timedelta(days=7) + if date_now >= exp_date: + mail_content = " Hello " + i.employee_ref.name + ",
    Your Document " + i.name + "is going to expire on " + \ + str(i.expiry_date) + ". Please renew it before expiry date" + main_content = { + 'subject': _('Document-%s Expired On %s') % (i.name, i.expiry_date), + 'author_id': self.env.user.partner_id.id, + 'body_html': mail_content, + 'email_to': i.employee_ref.work_email, + } + self.env['mail.mail'].create(main_content).send() + + @api.constrains('expiry_date') + def check_expr_date(self): + for each in self: + exp_date = fields.Date.from_string(each.expiry_date) + if exp_date < date.today(): + raise Warning('Your Document Is Expired.') + + name = fields.Char(string='Document Number', required=True, copy=False) + document_name = fields.Many2one('employee.checklist', string='Document', required=True) + description = fields.Text(string='Description', copy=False) + expiry_date = fields.Date(string='Expiry Date', copy=False) + employee_ref = fields.Many2one('hr.employee', invisible=1, copy=False) + doc_attachment_id = fields.Many2many('ir.attachment', 'doc_attach_rel', 'doc_id', 'attach_id3', string="Attachment", + help='You can attach the copy of your document', copy=False) + issue_date = fields.Date(string='Issue Date', default=fields.datetime.now(), copy=False) + + +class HrEmployee(models.Model): + _inherit = 'hr.employee' + + @api.multi + def _document_count(self): + for each in self: + document_ids = self.env['hr.employee.document'].search([('employee_ref', '=', each.id)]) + each.document_count = len(document_ids) + + @api.multi + def document_view(self): + self.ensure_one() + domain = [ + ('employee_ref', '=', self.id)] + return { + 'name': _('Documents'), + 'domain': domain, + 'res_model': 'hr.employee.document', + 'type': 'ir.actions.act_window', + 'view_id': False, + 'view_mode': 'tree,form', + 'view_type': 'form', + 'help': _('''

    + Click to Create for New Documents +

    '''), + 'limit': 80, + 'context': "{'default_employee_ref': '%s'}" % self.id + } + + document_count = fields.Integer(compute='_document_count', string='# Documents') + + +class HrEmployeeAttachment(models.Model): + _inherit = 'ir.attachment' + + doc_attach_rel = fields.Many2many('hr.employee.document', 'doc_attachment_id', 'attach_id3', 'doc_id', + string="Attachment", invisible=1) diff --git a/employee_documents_expiry/models/employee_entry_exit_check_list.py b/employee_documents_expiry/models/employee_entry_exit_check_list.py new file mode 100644 index 000000000..0a16724fe --- /dev/null +++ b/employee_documents_expiry/models/employee_entry_exit_check_list.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api + + +class EmployeeEntryDocuments(models.Model): + _name = 'employee.checklist' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + _description = "Employee Documents" + + @api.multi + def name_get(self): + result = [] + for each in self: + if each.document_type == 'entry': + name = each.name + '_en' + elif each.document_type == 'exit': + name = each.name + '_ex' + elif each.document_type == 'other': + name = each.name + '_ot' + result.append((each.id, name)) + return result + + name = fields.Char(string='Document Name', copy=False, required=1) + document_type = fields.Selection([('entry', 'Entry Process'), + ('exit', 'Exit Process'), + ('other', 'Other')], string='Checklist Type', required=1) + + diff --git a/employee_documents_expiry/models/employee_entry_exit_check_list.py~ b/employee_documents_expiry/models/employee_entry_exit_check_list.py~ new file mode 100644 index 000000000..6fbd2c51d --- /dev/null +++ b/employee_documents_expiry/models/employee_entry_exit_check_list.py~ @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api + + +class EmployeeEntryDocuments(models.Model): + _name = 'employee.checklist' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + _description = "Employee Documents" + + @api.multi + def name_get(self): + result = [] + for each in self: + if each.document_type == 'entry': + name = each.name + '_en' + elif each.document_type == 'exit': + name = each.name + '_ex' + elif each.document_type == 'other': + name = each.name + '_ot' + result.append((each.id, name)) + return result + + name = fields.Char(string='Document Name', copy=False, required=1) + document_type = fields.Selection([('entry', 'Entry Documents'), + ('exit', 'Exit Documents'), + ('other', 'Other')], string='Checklist Type', required=1) + diff --git a/employee_documents_expiry/security/ir.model.access.csv b/employee_documents_expiry/security/ir.model.access.csv new file mode 100644 index 000000000..145868907 --- /dev/null +++ b/employee_documents_expiry/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_hr_employee_checklist_user,employee.checklist.user,model_employee_checklist,hr.group_hr_user,1,1,1,1 +access_hr_employee_checklist_emp,employee.checklist.emp,model_employee_checklist,base.group_user,1,0,0,0 +"access_hr_employee_document_employee","hr.employee.document_employee","model_hr_employee_document","base.group_user",1,0,0,0 +"access_hr_employee_document_manager","hr.employee.document_manager","model_hr_employee_document","hr.group_hr_manager",1,1,1,1 +"access_hr_employee_document_user","hr.employee.document_user","model_hr_employee_document","hr.group_hr_user",1,1,1,0 + diff --git a/employee_documents_expiry/static/description/banner.jpg b/employee_documents_expiry/static/description/banner.jpg new file mode 100644 index 000000000..931855443 Binary files /dev/null and b/employee_documents_expiry/static/description/banner.jpg differ diff --git a/employee_documents_expiry/static/description/cybro_logo.png b/employee_documents_expiry/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/employee_documents_expiry/static/description/cybro_logo.png differ diff --git a/employee_documents_expiry/static/description/document_form.png b/employee_documents_expiry/static/description/document_form.png new file mode 100644 index 000000000..5c570a339 Binary files /dev/null and b/employee_documents_expiry/static/description/document_form.png differ diff --git a/employee_documents_expiry/static/description/email.png b/employee_documents_expiry/static/description/email.png new file mode 100644 index 000000000..90b70be6c Binary files /dev/null and b/employee_documents_expiry/static/description/email.png differ diff --git a/employee_documents_expiry/static/description/employee_form.png b/employee_documents_expiry/static/description/employee_form.png new file mode 100644 index 000000000..c7ea0e59f Binary files /dev/null and b/employee_documents_expiry/static/description/employee_form.png differ diff --git a/employee_documents_expiry/static/description/icon.png b/employee_documents_expiry/static/description/icon.png new file mode 100644 index 000000000..9aa49d9c9 Binary files /dev/null and b/employee_documents_expiry/static/description/icon.png differ diff --git a/employee_documents_expiry/static/description/index.html b/employee_documents_expiry/static/description/index.html new file mode 100644 index 000000000..948cea538 --- /dev/null +++ b/employee_documents_expiry/static/description/index.html @@ -0,0 +1,102 @@ +
    +
    +

    Employee Documents

    +

    Manages Employee Related Documents

    +

    Cybrosys Technologies

    +
    +
    +

    Features:

    +
    + Managing Documents of Employees.
    + Documents Types.
    + Expiry Date for Documents.
    + Validation for Expiry Date.
    + Mail Notification Based on Expiry Date.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    +Each and every detail associated with an employee is useful for any organization for better Human resource management. + So the employee documents with such necessary information must be saved and used accordingly. + 'Employee Documents' is a useful tool that can help you to store and manage the employee related + documents like certificates, appraisal reports, passport, license etc. +The application also allows you to set an alert message on reaching the expiration/any other + related dates of a document (like an expiration of passport) +

    +
    +
    +
    + +
    +
    +
    +

    +

    Documents Super Button

    +

    +

    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Documents Form

    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Notification Mail for Expiry Doc

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

    Need Any Help?

    + +
    + + + diff --git a/employee_documents_expiry/views/employee_check_list_view.xml b/employee_documents_expiry/views/employee_check_list_view.xml new file mode 100644 index 000000000..eb702bb92 --- /dev/null +++ b/employee_documents_expiry/views/employee_check_list_view.xml @@ -0,0 +1,32 @@ + + + + employee.checklist.form + employee.checklist + +
    + + + + + + +
    + + +
    +
    +
    +
    + + + employee.checklist.tree + employee.checklist + + + + + + + +
    \ No newline at end of file diff --git a/employee_documents_expiry/views/employee_document_view.xml b/employee_documents_expiry/views/employee_document_view.xml new file mode 100644 index 000000000..7695a396d --- /dev/null +++ b/employee_documents_expiry/views/employee_document_view.xml @@ -0,0 +1,66 @@ + + + + HR Employee Data Expiration + 1 + days + -1 + + + + + + + + hr.employee.document.form + hr.employee.document + +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + hr.employee.document.tree + hr.employee.document + + + + + + + + + + + hr.employee.form.view + hr.employee + + +
    + +
    +
    +
    +
    \ No newline at end of file diff --git a/employee_dynamic_fields/__init__.py b/employee_dynamic_fields/__init__.py new file mode 100644 index 000000000..bb896a7d9 --- /dev/null +++ b/employee_dynamic_fields/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from . import models diff --git a/employee_dynamic_fields/__manifest__.py b/employee_dynamic_fields/__manifest__.py new file mode 100644 index 000000000..a3b51557a --- /dev/null +++ b/employee_dynamic_fields/__manifest__.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employee Dynamic Fields', + 'version': '10.0.1.0.0', + 'summary': """Ability To Add Custom Fields From User Level""", + 'description': """Ability to add custom fields in employee master.""", + 'category': 'Generic Modules/Human Resources', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'hr'], + 'data': [ + 'security/ir.model.access.csv', + 'views/employee_fields_view.xml', + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_dynamic_fields/models/__init__.py b/employee_dynamic_fields/models/__init__.py new file mode 100644 index 000000000..8f4a4c563 --- /dev/null +++ b/employee_dynamic_fields/models/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from . import employee_fields + + diff --git a/employee_dynamic_fields/models/employee_fields.py b/employee_dynamic_fields/models/employee_fields.py new file mode 100644 index 000000000..424c7a560 --- /dev/null +++ b/employee_dynamic_fields/models/employee_fields.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +import xml.etree.ElementTree as xee + +from odoo import api, models, fields, _ + + +class EmployeeDynamicFields(models.TransientModel): + _name = 'wizard.dynamic.fields' + _description = 'Dynamic Fields' + _inherit = 'ir.model.fields' + + @api.model + def get_field_types(self): + field_list = sorted((key, key) for key in fields.MetaField.by_type) + field_list.remove(('one2many', 'one2many')) + field_list.remove(('reference', 'reference')) + field_list.remove(('serialized', 'serialized')) + return field_list + + @api.multi + def set_domain(self): + view_id = self.env.ref('hr.view_employee_form') + data1 = str(view_id.arch_base) + doc = xee.fromstring(data1) + field_list = [] + for tag in doc.findall('.//field'): + field_list.append(tag.attrib['name']) + model_id = self.env['ir.model'].sudo().search([('model', '=', 'hr.employee')]) + return [('model_id', '=', model_id.id), ('state', '=', 'base'), ('name', 'in', field_list)] + + @api.multi + def _set_default(self): + model_id = self.env['ir.model'].sudo().search([('model', '=', 'hr.employee')]) + return [('id', '=', model_id.id)] + + @api.multi + def create_fields(self): + self.env['ir.model.fields'].sudo().create({'name': self.name, + 'field_description': self.field_description, + 'model_id': self.model_id.id, + 'ttype': self.ttype, + 'relation': self.ref_model_id.model, + 'required': self.required, + 'selection': self.selection, + 'copy': self.copy, + 'active': True}) + inherit_id = self.env.ref('hr.view_employee_form') + arch_base = _('' + '' + '' + '' + '' + '') % (self.position_field.name, self.position, self.name) + self.env['ir.ui.view'].sudo().create({'name': 'hr.employee.dynamic.fields', + 'type': 'form', + 'model': 'hr.employee', + 'mode': 'extension', + 'inherit_id': inherit_id.id, + 'arch_base': arch_base, + 'active': True}) + return { + 'type': 'ir.actions.client', + 'tag': 'reload', + } + + position_field = fields.Many2one('ir.model.fields', string='Field Name', + domain=set_domain, required=True) + position = fields.Selection([('before', 'Before'), + ('after', 'After')], string='Position', required=True) + model_id = fields.Many2one('ir.model', string='Model', required=True, index=True, ondelete='cascade', + help="The model this field belongs to", domain=_set_default) + ref_model_id = fields.Many2one('ir.model', string='Model', index=True) + rel_field = fields.Many2one('ir.model.fields', string='Related Field') + ttype = fields.Selection(selection='get_field_types', string='Field Type', required=True) diff --git a/employee_dynamic_fields/security/ir.model.access.csv b/employee_dynamic_fields/security/ir.model.access.csv new file mode 100644 index 000000000..37c7f2134 --- /dev/null +++ b/employee_dynamic_fields/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +"access_wizard_dynamic_fields_hr_manager","wizard.dynamic.fields.hr_manager","model_wizard_dynamic_fields","hr.group_hr_manager",1,1,1,1 + diff --git a/employee_dynamic_fields/static/description/banner.jpg b/employee_dynamic_fields/static/description/banner.jpg new file mode 100644 index 000000000..80530826b Binary files /dev/null and b/employee_dynamic_fields/static/description/banner.jpg differ diff --git a/employee_dynamic_fields/static/description/cybro_logo.png b/employee_dynamic_fields/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/employee_dynamic_fields/static/description/cybro_logo.png differ diff --git a/employee_dynamic_fields/static/description/icon.png b/employee_dynamic_fields/static/description/icon.png new file mode 100644 index 000000000..dcec476e6 Binary files /dev/null and b/employee_dynamic_fields/static/description/icon.png differ diff --git a/employee_dynamic_fields/static/description/image1.png b/employee_dynamic_fields/static/description/image1.png new file mode 100644 index 000000000..6e4c6d908 Binary files /dev/null and b/employee_dynamic_fields/static/description/image1.png differ diff --git a/employee_dynamic_fields/static/description/image2.png b/employee_dynamic_fields/static/description/image2.png new file mode 100644 index 000000000..772d86cd1 Binary files /dev/null and b/employee_dynamic_fields/static/description/image2.png differ diff --git a/employee_dynamic_fields/static/description/index.html b/employee_dynamic_fields/static/description/index.html new file mode 100644 index 000000000..6dfec21ef --- /dev/null +++ b/employee_dynamic_fields/static/description/index.html @@ -0,0 +1,83 @@ +
    +
    +

    Employee Dynamic Fields

    +

    Ability To Add Custom Fields From User Level

    +

    Cybrosys Technologies

    +
    +
    +

    Features:

    +
    + Ability to add custom fields in employee master.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    + The module allows the user to add dynamic fields to employee master form. + The user doesn't need any technical/programming skills, + just use the menu-driven approach and simply create and configure new fields. +

    +
    +
    +
    + +
    +
    +
    +

    +

    Dynamic Field Creation

    +

    +

    +
    + Here you can fill the field information to create a new field of employee master. +
    + +
    +
    +
    +
    + +
    +
    +

    Employee Master

    +
    + You can see your field is created in employee master. +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    + + + diff --git a/employee_dynamic_fields/views/employee_fields_view.xml b/employee_dynamic_fields/views/employee_fields_view.xml new file mode 100644 index 000000000..c09f21803 --- /dev/null +++ b/employee_dynamic_fields/views/employee_fields_view.xml @@ -0,0 +1,53 @@ + + + + wizard.dynamic.fields.form + wizard.dynamic.fields + +
    + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + + Create Custom Fields + wizard.dynamic.fields + form + form + + new + + + +
    diff --git a/employee_orientation/README.rst b/employee_orientation/README.rst new file mode 100644 index 000000000..ed271ab76 --- /dev/null +++ b/employee_orientation/README.rst @@ -0,0 +1,23 @@ +Employee Orientation v10 +======================== + +This module developed to manage employee orientation&training programs. + +Installation +============ +Just select it from modules list to install, there is no need to extra installations. + +Usage +===== + +# The system automatically create employee orientation request when employee orientation is confirmed. +# Now when responsible person login in system, he/she will find job allocated as Orientation Checklists Requests and finish it. + +Credits +======= +Developer: Anusha @ cybrosys + + + + + diff --git a/employee_orientation/__init__.py b/employee_orientation/__init__.py new file mode 100644 index 000000000..a8dc6be8e --- /dev/null +++ b/employee_orientation/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +################################################################################### +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2018-TODAY Cybrosys Technologies ().# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import models +from . import wizard diff --git a/employee_orientation/__manifest__.py b/employee_orientation/__manifest__.py new file mode 100644 index 000000000..491f2a04c --- /dev/null +++ b/employee_orientation/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +################################################################################### +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2018-TODAY Cybrosys Technologies ().# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +{ + 'name': "Employee Orientation & Training", + 'version': '10.0.1.0.0', + "category": "Generic Modules/Human Resources", + 'summary': """Employee Orientation/Training Program""", + 'description': """Complete Employee Orientation/Training Program""", + 'author': "Cybrosys Techno Solutions", + 'company': "Cybrosys Techno Solutions", + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'hr'], + 'data': [ + 'security/ir.model.access.csv', + 'wizard/orientation_complete.xml', + 'views/orientation_checklist_line.xml', + 'views/orientation_checklist.xml', + 'views/employee_orientation.xml', + 'views/orientation_checklists_request.xml', + 'views/orientation_checklist_sequence.xml', + 'views/orientation_request_mail_template.xml', + 'views/employee_training.xml', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_orientation/doc/changelog.rst b/employee_orientation/doc/changelog.rst new file mode 100644 index 000000000..9b1251e29 --- /dev/null +++ b/employee_orientation/doc/changelog.rst @@ -0,0 +1,9 @@ +Changelog +========= +* Anusha contact: anusha@cybrosys.in + +`10.0.2.0.0` +----------- + +- Changed : changed openerp to odoo. + diff --git a/employee_orientation/models/__init__.py b/employee_orientation/models/__init__.py new file mode 100644 index 000000000..113fd6a00 --- /dev/null +++ b/employee_orientation/models/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +################################################################################### +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2018-TODAY Cybrosys Technologies ().# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import orientation_checklist_line +from . import orientation_checklist +from . import employee_orientation +from . import orientation_checklist_request +from . import employee_training diff --git a/employee_orientation/models/employee_orientation.py b/employee_orientation/models/employee_orientation.py new file mode 100644 index 000000000..5bf37a203 --- /dev/null +++ b/employee_orientation/models/employee_orientation.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models, _ + + +class Orientation(models.Model): + _name = 'employee.orientation' + _description = "Employee Orientation" + _inherit = ['mail.thread', 'ir.needaction_mixin'] + + name = fields.Char(string='Employee Orientation', readonly=True, default=lambda self: _('New')) + employee_name = fields.Many2one('hr.employee', string='Employee', size=32, required=True) + department = fields.Many2one('hr.department', string='Department', related='employee_name.department_id', required=True) + date = fields.Date(string="Date", default=fields.Datetime.now) + responsible_user = fields.Many2one('res.users', string='Responsible User') + employee_company = fields.Many2one('res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) + parent_id = fields.Many2one('hr.employee', string='Manager', related='employee_name.parent_id') + job_id = fields.Many2one('hr.job', string='Job Title', related='employee_name.job_id', + domain="[('department_id', '=', department)]") + orientation_id = fields.Many2one('orientation.checklist', string='Orientation Checklist', + domain="[('checklist_department','=', department)]", required=True) + note_id = fields.Text('Description') + orientation_request = fields.One2many('orientation.request', 'request_orientation', string='Orientation Request') + state = fields.Selection([ + ('draft', 'Draft'), + ('confirm', 'Confirmed'), + ('cancel', 'Canceled'), + ('complete', 'Completed'), + ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='draft') + + @api.multi + def confirm_orientation(self): + self.write({'state': 'confirm'}) + for values in self.orientation_id.checklist_line_id: + self.env['orientation.request'].create({ + 'request_name': values.line_name, + 'request_orientation': self.id, + 'partner_id': values.responsible_user.id, + 'request_date': self.date, + 'employee_id': self.employee_name.id, + }) + + @api.multi + def cancel_orientation(self): + for request in self.orientation_request: + request.state = 'cancel' + self.write({'state': 'cancel'}) + + @api.multi + def complete_orientation(self): + force_complete = False + for request in self.orientation_request: + if request.state == 'new': + force_complete = True + if force_complete: + return { + 'name': 'Complete Orientation', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'orientation.force.complete', + 'type': 'ir.actions.act_window', + 'context': {'default_orientation_id': self.id}, + 'target': 'new', + } + self.write({'state': 'complete'}) + + @api.model + def create(self, vals): + if vals.get('name', 'New') == 'New': + vals['name'] = self.env['ir.sequence'].next_by_code('employee.orientation') or 'New' + result = super(Orientation, self).create(vals) + return result diff --git a/employee_orientation/models/employee_training.py b/employee_orientation/models/employee_training.py new file mode 100644 index 000000000..400a158bf --- /dev/null +++ b/employee_orientation/models/employee_training.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models, _ + + +class EmployeeTraining(models.Model): + _name = 'employee.training' + _rec_name = 'program_name' + _description = "Employee Training" + _inherit = ['mail.thread', 'ir.needaction_mixin'] + + program_name = fields.Char(string='Training Program', required=True) + program_department = fields.Many2one('hr.department', string='Department', required=True) + program_convener = fields.Many2one('res.users', string='Responsible User', size=32, required=True) + training_id = fields.One2many('hr.employee', string='Employee Details', compute="employee_details") + note_id = fields.Text('Description') + date_from = fields.Date(string="Date From") + date_to = fields.Date(string="Date To") + user_id = fields.Many2one('res.users', string='users', default=lambda self: self.env.user) + company_id = fields.Many2one('res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) + state = fields.Selection([ + ('new', 'New'), + ('confirm', 'Confirmed'), + ('cancel', 'Canceled'), + ('complete', 'Completed'), + ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='new') + + @api.onchange('program_department') + def employee_details(self): + data = self.env['hr.employee'].search( + [('department_id', '=', self.program_department.id)]) + self.training_id = data + + @api.multi + def complete_event(self): + self.write({'state': 'complete'}) + + @api.multi + def confirm_event(self): + self.write({'state': 'confirm'}) + + @api.multi + def cancel_event(self): + self.write({'state': 'cancel'}) + + @api.multi + def confirm_send_mail(self): + self.ensure_one() + ir_model_data = self.env['ir.model.data'] + try: + template_id = ir_model_data.get_object_reference('employee_orientation', 'orientation_training_mailer')[1] + except ValueError: + template_id = False + try: + compose_form_id = ir_model_data.get_object_reference('mail', 'email_compose_message_wizard_form')[1] + except ValueError: + compose_form_id = False + ctx = dict(self.env.context or {}) + ctx.update({ + 'default_model': 'employee.training', + 'default_res_id': self.ids[0], + 'default_use_template': bool(template_id), + 'default_template_id': template_id, + 'default_composition_mode': 'comment', + }) + + return { + 'name': _('Compose Email'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form_id, 'form')], + 'view_id': compose_form_id, + 'target': 'new', + 'context': ctx, + } diff --git a/employee_orientation/models/orientation_checklist.py b/employee_orientation/models/orientation_checklist.py new file mode 100644 index 000000000..1e5753926 --- /dev/null +++ b/employee_orientation/models/orientation_checklist.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields, _ + + +class OrientationChecklist(models.Model): + _name = 'orientation.checklist' + _description = "Checklist" + _rec_name = 'checklist_name' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + + checklist_name = fields.Char(string='Name', required=True) + checklist_department = fields.Many2one('hr.department', string='Department', required=True) + active = fields.Boolean(string='Active', default=True, + help="Set active to false to hide the Orientation Checklist without removing it.") + checklist_line_id = fields.Many2many('checklist.line', 'checklist_line_rel', String="Checklist") + + + + + diff --git a/employee_orientation/models/orientation_checklist_line.py b/employee_orientation/models/orientation_checklist_line.py new file mode 100644 index 000000000..f8cc2c082 --- /dev/null +++ b/employee_orientation/models/orientation_checklist_line.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields + + +class ChecklistLine(models.Model): + _name = 'checklist.line' + _rec_name = 'line_name' + + line_name = fields.Char(string='Name', required=True) + responsible_user = fields.Many2one('res.users', string='Responsible User', required=True) diff --git a/employee_orientation/models/orientation_checklist_request.py b/employee_orientation/models/orientation_checklist_request.py new file mode 100644 index 000000000..2ae699bb6 --- /dev/null +++ b/employee_orientation/models/orientation_checklist_request.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields, api +from odoo.tools.translate import _ + + +class OrientationChecklistRequest(models.Model): + _name = 'orientation.request' + _description = "Employee Orientation Request" + _rec_name = 'request_name' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + + request_name = fields.Char(string='Name') + request_orientation = fields.Many2one('employee.orientation', string='Employee Orientation') + employee_company = fields.Many2one('res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) + partner_id = fields.Many2one('res.users', string='Responsible User') + request_date = fields.Date(string="Date") + employee_id = fields.Many2one('hr.employee', string='Employee') + request_expected_date = fields.Date(string="Expected Date") + attachment_id_1 = fields.Many2many('ir.attachment', 'orientation_rel_1', string="Attachment") + note_id = fields.Text('Description') + user_id = fields.Many2one('res.users', string='users', default=lambda self: self.env.user) + company_id = fields.Many2one('res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) + state = fields.Selection([ + ('new', 'New'), + ('cancel', 'Cancel'), + ('complete', 'Completed'), + ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='new') + + @api.multi + def confirm_send_mail(self): + self.ensure_one() + ir_model_data = self.env['ir.model.data'] + try: + template_id = ir_model_data.get_object_reference('employee_orientation', 'orientation_request_mailer')[1] + except ValueError: + template_id = False + try: + compose_form_id = ir_model_data.get_object_reference('mail', 'email_compose_message_wizard_form')[1] + except ValueError: + compose_form_id = False + ctx = dict(self.env.context or {}) + ctx.update({ + 'default_model': 'orientation.request', + 'default_res_id': self.ids[0], + 'default_use_template': bool(template_id), + 'default_template_id': template_id, + 'default_composition_mode': 'comment', + }) + + return { + 'name': _('Compose Email'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form_id, 'form')], + 'view_id': compose_form_id, + 'target': 'new', + 'context': ctx, + } + + @api.multi + def confirm_request(self): + self.write({'state': "complete"}) + + @api.multi + def cancel_request(self): + self.write({'state': "cancel"}) diff --git a/employee_orientation/security/ir.model.access.csv b/employee_orientation/security/ir.model.access.csv new file mode 100644 index 000000000..1a3d3134c --- /dev/null +++ b/employee_orientation/security/ir.model.access.csv @@ -0,0 +1,18 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_user_orientation_request,orientation.request,model_orientation_request,hr.group_hr_user,1,1,1,1 +access_manager_orientation_request,orientation.request,model_orientation_request,base.group_user,1,1,0,0 +access_user_checklist_line,checklist.line,model_checklist_line,hr.group_hr_user,1,0,0,0 +access_manager_checklist_line,checklist.line,model_checklist_line,hr.group_hr_manager,1,1,1,1 +access_user_employee_orientation,employee.orientation,model_employee_orientation,hr.group_hr_user,1,1,1,1 +access_manager_employee_orientation_request,orientation.checklist,model_orientation_checklist,hr.group_hr_user,1,1,1,1 +access_user_employee_training,employee.training,model_employee_training,hr.group_hr_user,1,1,1,1 +access_manager_employee_training,employee.training,model_employee_training,base.group_user,1,1,0,0 + + + + + + + + + diff --git a/employee_orientation/static/description/banner.jpg b/employee_orientation/static/description/banner.jpg new file mode 100644 index 000000000..067ede9fb Binary files /dev/null and b/employee_orientation/static/description/banner.jpg differ diff --git a/employee_orientation/static/description/cybro_logo.png b/employee_orientation/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/employee_orientation/static/description/cybro_logo.png differ diff --git a/employee_orientation/static/description/hr_orientation_1.png b/employee_orientation/static/description/hr_orientation_1.png new file mode 100644 index 000000000..e375839a9 Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_1.png differ diff --git a/employee_orientation/static/description/hr_orientation_10.png b/employee_orientation/static/description/hr_orientation_10.png new file mode 100644 index 000000000..743282f1d Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_10.png differ diff --git a/employee_orientation/static/description/hr_orientation_11.png b/employee_orientation/static/description/hr_orientation_11.png new file mode 100644 index 000000000..ffc196c5c Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_11.png differ diff --git a/employee_orientation/static/description/hr_orientation_12.png b/employee_orientation/static/description/hr_orientation_12.png new file mode 100644 index 000000000..c2651e81a Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_12.png differ diff --git a/employee_orientation/static/description/hr_orientation_13.png b/employee_orientation/static/description/hr_orientation_13.png new file mode 100644 index 000000000..ed1019dd3 Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_13.png differ diff --git a/employee_orientation/static/description/hr_orientation_2.png b/employee_orientation/static/description/hr_orientation_2.png new file mode 100644 index 000000000..9933f04b7 Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_2.png differ diff --git a/employee_orientation/static/description/hr_orientation_3.png b/employee_orientation/static/description/hr_orientation_3.png new file mode 100644 index 000000000..20ad10e6d Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_3.png differ diff --git a/employee_orientation/static/description/hr_orientation_4.png b/employee_orientation/static/description/hr_orientation_4.png new file mode 100644 index 000000000..51f32e194 Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_4.png differ diff --git a/employee_orientation/static/description/hr_orientation_5.png b/employee_orientation/static/description/hr_orientation_5.png new file mode 100644 index 000000000..daf06ed33 Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_5.png differ diff --git a/employee_orientation/static/description/hr_orientation_6.png b/employee_orientation/static/description/hr_orientation_6.png new file mode 100644 index 000000000..567fd4ed3 Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_6.png differ diff --git a/employee_orientation/static/description/hr_orientation_7.png b/employee_orientation/static/description/hr_orientation_7.png new file mode 100644 index 000000000..3d9c9882b Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_7.png differ diff --git a/employee_orientation/static/description/hr_orientation_8.png b/employee_orientation/static/description/hr_orientation_8.png new file mode 100644 index 000000000..0658c57ed Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_8.png differ diff --git a/employee_orientation/static/description/hr_orientation_9.png b/employee_orientation/static/description/hr_orientation_9.png new file mode 100644 index 000000000..2253f5e6a Binary files /dev/null and b/employee_orientation/static/description/hr_orientation_9.png differ diff --git a/employee_orientation/static/description/icon.png b/employee_orientation/static/description/icon.png new file mode 100644 index 000000000..ce3b03d64 Binary files /dev/null and b/employee_orientation/static/description/icon.png differ diff --git a/employee_orientation/static/description/index.html b/employee_orientation/static/description/index.html new file mode 100644 index 000000000..dfee3fd04 --- /dev/null +++ b/employee_orientation/static/description/index.html @@ -0,0 +1,161 @@ +
    +
    +

    Employee Orientation & Training

    +

    Manage Employee Orientation And Training Programs

    +

    Cybrosys Technologies

    +
    +
    +

    Major Features:

    +
    + Makes the Employee Orientation Program easier.
    + Systematical Workflow.
    + Allows to Create Employee Training Programs.
    + Email Notification for each Responsible person.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    + Employee orientation/training is the process by which an employee acquires the necessary skills, + knowledge, behaviors, and contacts to effectively transition into a new organization.It can enhance + the overall satisfaction of employees and can encourage a positive attitude about the employer. + Employees view companies that offer meaningful benefits as more caring and engaged with their needs. + This may help reduce turnover and increase productivity +

    +
    +
    +
    + +
    +
    +

    Configuration

    +
    +

    You can configure employee orientation programs for each department from + Employees -> Configuration -> Orientation Program

    +
    +

    Orientation Checklist

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

    Orientation Checklist Line

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

    Employee Orientation

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

    + On confirming employee orientation, creates orientation lines from corresponding orientation checklist. +

    +
    + +
    +
    +
    +
    + +
    +
    +

    Orientation Request

    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Email Template

    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Employee Training

    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Email Template

    +
    +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    + + diff --git a/employee_orientation/views/employee_orientation.xml b/employee_orientation/views/employee_orientation.xml new file mode 100644 index 000000000..625054c85 --- /dev/null +++ b/employee_orientation/views/employee_orientation.xml @@ -0,0 +1,112 @@ + + + + + employee.orientation.tree + employee.orientation + + + + + + + + + + + + + employee.orientation.form + employee.orientation + +
    +
    +
    + +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    + +
    +
    + + employee.orientation.search + employee.orientation + + + + + + + + + + + + + Employee Orientation + ir.actions.act_window + employee.orientation + form + tree,form + + [] + {} + +

    + Create Employee Orientation. +

    +
    +
    + +
    +
    diff --git a/employee_orientation/views/employee_training.xml b/employee_orientation/views/employee_training.xml new file mode 100644 index 000000000..fdd77589a --- /dev/null +++ b/employee_orientation/views/employee_training.xml @@ -0,0 +1,91 @@ + + + + + employee.training.tree + employee.training + + + + + + + + + + + employee.training.form + employee.training + +
    +
    +
    + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + + employee.training.search + employee.training + + + + + + + + + + + + Employee Training Program + ir.actions.act_window + employee.training + form + tree,form + + [] + {} + +

    + Create Employee Training Program. +

    +
    +
    + + +
    +
    diff --git a/employee_orientation/views/orientation_checklist.xml b/employee_orientation/views/orientation_checklist.xml new file mode 100644 index 000000000..dc4523716 --- /dev/null +++ b/employee_orientation/views/orientation_checklist.xml @@ -0,0 +1,87 @@ + + + + + orientation.checklist.tree + orientation.checklist + + + + + + + + + + + orientation.checklist.form + orientation.checklist + + +
    + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + + + orientation.checklist.search + orientation.checklist + + + + + + + + + + + + + + Orientation Checklist + ir.actions.act_window + orientation.checklist + form + tree,form + + [] + {'search_default_active': True} + +

    + Create Orientation Checklists. +

    +
    +
    + + +
    +
    diff --git a/employee_orientation/views/orientation_checklist_line.xml b/employee_orientation/views/orientation_checklist_line.xml new file mode 100644 index 000000000..2c3b01a62 --- /dev/null +++ b/employee_orientation/views/orientation_checklist_line.xml @@ -0,0 +1,85 @@ + + + + + checklist.line.tree + checklist.line + + + + + + + + + + checklist.line.form + checklist.line + + +
    + + + + + + +
    +
    +
    + + checklist.line.search + checklist.line + + + + + + + + + + + + + + Orientation Checklist Line + ir.actions.act_window + checklist.line + form + tree,form + + [] + {} + +

    + Create Orientation Checklists Lines. +

    +
    +
    + + + + + + + +
    +
    diff --git a/employee_orientation/views/orientation_checklist_sequence.xml b/employee_orientation/views/orientation_checklist_sequence.xml new file mode 100644 index 000000000..17685ffe4 --- /dev/null +++ b/employee_orientation/views/orientation_checklist_sequence.xml @@ -0,0 +1,15 @@ + + + + + + + Employee Orientation + employee.orientation + OR + 3 + + + + + \ No newline at end of file diff --git a/employee_orientation/views/orientation_checklists_request.xml b/employee_orientation/views/orientation_checklists_request.xml new file mode 100644 index 000000000..15c003bc9 --- /dev/null +++ b/employee_orientation/views/orientation_checklists_request.xml @@ -0,0 +1,84 @@ + + + + + orientation.request.tree + orientation.request + + + + + + + + + + + orientation.request.form + orientation.request + +
    +
    +
    + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + + orientation.request.search + orientation.request + + + + + + + + + + + + Orientation Request + ir.actions.act_window + orientation.request + form + tree,form + + [] + {} + +

    + Create Orientation Requests. +

    +
    +
    + +
    +
    diff --git a/employee_orientation/views/orientation_request_mail_template.xml b/employee_orientation/views/orientation_request_mail_template.xml new file mode 100644 index 000000000..dcb5e79c1 --- /dev/null +++ b/employee_orientation/views/orientation_request_mail_template.xml @@ -0,0 +1,90 @@ + + + + + Employee Orientation Request + ${(object.user_id.email or object.company_id.email)|safe} + ${(object.partner_id.email)} + Employee Orientation Request + + + +

    Hello ${object.partner_id.name},

    +

    Your are request to conduct orientation program listed below.

    +

    Check Line: ${object.request_name}

    +

    Employee: ${object.employee_id.name}

    + %if object.request_expected_date: +

    Expected Date: ${object.request_expected_date}

    + % endif +
    +

    Thank you!

    +
    +
    +

    + ${object.company_id.name}

    +
    +
    + + ${object.company_id.partner_id.sudo().with_context(show_address=True, html_format=True).name_get()[0][1] | safe} + + % if object.company_id.phone: +
    + Phone:  ${object.company_id.phone} +
    + % endif + % if object.company_id.website: + + %endif +

    +
    + + ]]> +
    +
    + + Employee Training program + ${(object.user_id.email or object.company_id.email)} + ${(object.program_convener.email)|safe} + Employee Training Request + + + +

    Hello ${object.program_convener.name},

    +

    Your are request to conduct ${object.program_name} Training program for ${object.program_department.name} department + % if object.from_date and object.to_date: + from ${object.from_date} to ${object.to_date} + % endif + .

    +
    +

    Thank you!

    +
    +
    +

    + ${object.company_id.name}

    +
    +
    + + ${object.company_id.partner_id.sudo().with_context(show_address=True, html_format=True).name_get()[0][1] | safe} + + % if object.company_id.phone: +
    + Phone:  ${object.company_id.phone} +
    + % endif + % if object.company_id.website: + + %endif +

    +
    + + ]]> +
    +
    +
    +
    \ No newline at end of file diff --git a/employee_orientation/wizard/__init__.py b/employee_orientation/wizard/__init__.py new file mode 100644 index 000000000..d55a4e1cc --- /dev/null +++ b/employee_orientation/wizard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import orientation_complete diff --git a/employee_orientation/wizard/orientation_complete.py b/employee_orientation/wizard/orientation_complete.py new file mode 100644 index 000000000..09de84dfa --- /dev/null +++ b/employee_orientation/wizard/orientation_complete.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models, _ + + +class OrientationForceComplete(models.TransientModel): + _name = 'orientation.force.complete' + + name = fields.Char() + orientation_id = fields.Many2one('employee.orientation', string='Orientation') + orientation_lines = fields.One2many('orientation.request', string='Orientation Lines', compute='pending_lines') + + @api.onchange('orientation_id') + def pending_lines(self): + pending = [] + for data in self.orientation_id.orientation_request: + if data.state == 'new': + pending.append(data.id) + self.update({'orientation_lines': pending}) + + @api.multi + def force_complete(self): + for line in self.orientation_lines: + if line.state != 'cancel': + line.state = 'complete' + self.orientation_id.write({'state': 'complete'}) + diff --git a/employee_orientation/wizard/orientation_complete.xml b/employee_orientation/wizard/orientation_complete.xml new file mode 100644 index 000000000..8dfb0de35 --- /dev/null +++ b/employee_orientation/wizard/orientation_complete.xml @@ -0,0 +1,23 @@ + + + + + orientation.force.complete.form + orientation.force.complete + +
    +

    + Please make sure that orientations programs are already done. +

    + +
    +
    +
    \ No newline at end of file diff --git a/employee_stages/__init__.py b/employee_stages/__init__.py new file mode 100644 index 000000000..7c71921f5 --- /dev/null +++ b/employee_stages/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu(jesni@cybrosys.in) +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models + diff --git a/employee_stages/__manifest__.py b/employee_stages/__manifest__.py new file mode 100644 index 000000000..e2812fb59 --- /dev/null +++ b/employee_stages/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu(jesni@cybrosys.in) +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employee Stages', + 'version': '10.0.1.0.0', + 'summary': """Manages Employee Stages""", + 'description': """This module is used to tracking the employee's different stages.""", + 'category': "Generic Modules/Human Resources", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'hr'], + 'data': [ + 'security/ir.model.access.csv', + 'views/employee_stages_view.xml', + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} + + diff --git a/employee_stages/models/__init__.py b/employee_stages/models/__init__.py new file mode 100644 index 000000000..24545a3c9 --- /dev/null +++ b/employee_stages/models/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu(jesni@cybrosys.in) +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import employee_stages + diff --git a/employee_stages/models/employee_stages.py b/employee_stages/models/employee_stages.py new file mode 100644 index 000000000..d47c42336 --- /dev/null +++ b/employee_stages/models/employee_stages.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu(jesni@cybrosys.in) +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from datetime import date +from odoo import models, fields, api + +emp_stages = [('joined', 'Slap On'), + ('grounding', 'Grounding'), + ('test_period', 'Test Period'), + ('employment', 'Employment'), + ('notice_period', 'Notice Period'), + ('relieved', 'Resigned'), + ('terminate', 'Terminated')] + + +class EmployeeFormInherit(models.Model): + _inherit = 'hr.employee' + + @api.model + def create(self, vals): + result = super(EmployeeFormInherit, self).create(vals) + result.stages_history.sudo().create({'start_date': date.today(), + 'employee_id': result.id, + 'state': 'joined'}) + return result + + @api.multi + def start_grounding(self): + self.state = 'grounding' + self.stages_history.sudo().create({'start_date': date.today(), + 'employee_id': self.id, + 'state': 'grounding'}) + + @api.multi + def set_as_employee(self): + self.state = 'employment' + stage_obj = self.stages_history.search([('employee_id', '=', self.id), + ('state', '=', 'test_period')]) + if stage_obj: + stage_obj.sudo().write({'end_date': date.today()}) + self.stages_history.sudo().create({'start_date': date.today(), + 'employee_id': self.id, + 'state': 'employment'}) + + @api.multi + def start_notice_period(self): + self.state = 'notice_period' + stage_obj = self.stages_history.search([('employee_id', '=', self.id), + ('state', '=', 'employment')]) + if stage_obj: + stage_obj.sudo().write({'end_date': date.today()}) + self.stages_history.sudo().create({'start_date': date.today(), + 'employee_id': self.id, + 'state': 'notice_period'}) + + @api.multi + def relived(self): + self.state = 'relieved' + self.active = False + stage_obj = self.stages_history.search([('employee_id', '=', self.id), + ('state', '=', 'notice_period')]) + if stage_obj: + stage_obj.sudo().write({'end_date': date.today()}) + self.stages_history.sudo().create({'end_date': date.today(), + 'employee_id': self.id, + 'state': 'relieved'}) + + @api.multi + def start_test_period(self): + self.state = 'test_period' + self.stages_history.search([('employee_id', '=', self.id), + ('state', '=', 'grounding')]).sudo().write({'end_date': date.today()}) + self.stages_history.sudo().create({'start_date': date.today(), + 'employee_id': self.id, + 'state': 'test_period'}) + + @api.multi + def terminate(self): + self.state = 'terminate' + self.active = False + stage_obj = self.stages_history.search([('employee_id', '=', self.id), + ('state', '=', 'employment')]) + + if stage_obj: + stage_obj.sudo().write({'end_date': date.today()}) + else: + self.stages_history.search([('employee_id', '=', self.id), + ('state', '=', 'grounding')]).sudo().write({'end_date': date.today()}) + self.stages_history.sudo().create({'end_date': date.today(), + 'employee_id': self.id, + 'state': 'terminate'}) + + state = fields.Selection(emp_stages, string='Status', default='joined', track_visibility='always', copy=False, + help="Employee Stages.\nSlap On: Joined\nGrounding: Training\nTest period : Probation") + stages_history = fields.One2many('hr.employee.status.history', 'employee_id', string='Stage History', + help='It shows the duration and history of each stages') + + +class EmployeeStageHistory(models.Model): + _name = 'hr.employee.status.history' + _description = 'Status History' + + @api.depends('end_date') + def get_duration(self): + for each in self: + if each.end_date and each.start_date: + duration = fields.Date.from_string(each.end_date) - fields.Date.from_string(each.start_date) + each.duration = duration.days + + start_date = fields.Date(string='Start Date') + end_date = fields.Date(string='End Date') + duration = fields.Integer(compute=get_duration, string='Duration(days)') + state = fields.Selection(emp_stages, string='Stage') + employee_id = fields.Many2one('hr.employee', invisible=1) + + +class WizardEmployee(models.TransientModel): + _name = 'wizard.employee.stage' + + @api.multi + def set_as_employee(self): + context = self._context + employee_obj = self.env['hr.employee'].search([('id', '=', context.get('employee_id'))]) + if self.related_user: + employee_obj.user_id = self.related_user + employee_obj.set_as_employee() + + related_user = fields.Many2one('res.users', string="Related User") + diff --git a/employee_stages/security/ir.model.access.csv b/employee_stages/security/ir.model.access.csv new file mode 100644 index 000000000..fb8ce590e --- /dev/null +++ b/employee_stages/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_wizard_employee_stage_manager,wizard.employee.stage.manager,model_wizard_employee_stage,hr.group_hr_manager,1,1,1,1 +access_wizard_employee_stage_hr_user,wizard.employee.stage.user,model_wizard_employee_stage,hr.group_hr_user,1,1,1,0 +access_hr_employee_status_history_manager,hr.employee.status.history.manager,model_hr_employee_status_history,hr.group_hr_manager,1,1,1,1 +access_hr_employee_status_history_hr_user,hr.employee.status.history.user,model_hr_employee_status_history,hr.group_hr_user,1,1,1,0 + + diff --git a/employee_stages/static/description/banner.jpg b/employee_stages/static/description/banner.jpg new file mode 100644 index 000000000..f0e59e5d5 Binary files /dev/null and b/employee_stages/static/description/banner.jpg differ diff --git a/employee_stages/static/description/cybro_logo.png b/employee_stages/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/employee_stages/static/description/cybro_logo.png differ diff --git a/employee_stages/static/description/filter.png b/employee_stages/static/description/filter.png new file mode 100644 index 000000000..c4982b897 Binary files /dev/null and b/employee_stages/static/description/filter.png differ diff --git a/employee_stages/static/description/groupby.png b/employee_stages/static/description/groupby.png new file mode 100644 index 000000000..20b0b3cf7 Binary files /dev/null and b/employee_stages/static/description/groupby.png differ diff --git a/employee_stages/static/description/icon.png b/employee_stages/static/description/icon.png new file mode 100644 index 000000000..7ca95a03f Binary files /dev/null and b/employee_stages/static/description/icon.png differ diff --git a/employee_stages/static/description/index.html b/employee_stages/static/description/index.html new file mode 100644 index 000000000..2e61151ff --- /dev/null +++ b/employee_stages/static/description/index.html @@ -0,0 +1,175 @@ +
    +
    +

    Employee Stages

    +

    Manages Employee Stages

    +

    Cybrosys Technologies

    +
    +
    +

    Features:

    +
    + Managing employee's different stages.
    + Added employee's current stage in tree view.
    + Added employee's current stage in kanban view.
    + Added group by stage in search view.
    + Added Employee filter in search view.
    + Added default search for employees in search bar.
    + Automatically recording the stage history.
    + Computing the duration of each stage.
    + Option to set 'Related User' while converting to the employee.
    + Automatically inactive the employee while terminating or relieving the employee.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    + Every employee may undergo different stages during his term in a company. + It may be probation, training, employment etc. The stages may vary according to the organisation. + It is important to track such stages systematically to assess the performance indices of + an employee. So here we are providing + a new module which will facilitate the management of different stages of an employee. +

    +
    +
    +
    + +
    +
    +
    +

    +

    Employee Stages

    +

    +

    +
    + Here we can see different stages of employee, buttons to change the stages and overall history. +
    + +
    +
    +
    +
    + +
    + Status History tab tracking the Start date, End date and Duration of each stages. +
    +
    +
    + +
    + When an employee's state is reached to 'Resigned' stage then the system will automatically + inactive this employee +
    +
    +
    + +
    +
    +
    +

    +

    Option to Add Related User

    +

    +
    +
    +
    + +
    + We have an option to add 'Related User' when we set to 'Employment' stage. +
    +
    +
    + +
    +
    +
    +

    +

    Kanban View

    +

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

    +

    Tree View

    +

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

    +

    Search Bar

    +

    +
    +
    +
    + +
    + In employees view we shows only the users which are in 'Employment' stage. +
    +
    +
    + +
    +
    +
    +

    +

    Search View

    +

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

    Need Any Help?

    + +
    + diff --git a/employee_stages/static/description/kanban.png b/employee_stages/static/description/kanban.png new file mode 100644 index 000000000..090edf6e1 Binary files /dev/null and b/employee_stages/static/description/kanban.png differ diff --git a/employee_stages/static/description/status1.png b/employee_stages/static/description/status1.png new file mode 100644 index 000000000..a2850ec01 Binary files /dev/null and b/employee_stages/static/description/status1.png differ diff --git a/employee_stages/static/description/status2.png b/employee_stages/static/description/status2.png new file mode 100644 index 000000000..9783c818e Binary files /dev/null and b/employee_stages/static/description/status2.png differ diff --git a/employee_stages/static/description/status3.png b/employee_stages/static/description/status3.png new file mode 100644 index 000000000..3ee31fc95 Binary files /dev/null and b/employee_stages/static/description/status3.png differ diff --git a/employee_stages/static/description/status5.png b/employee_stages/static/description/status5.png new file mode 100644 index 000000000..92a4415f7 Binary files /dev/null and b/employee_stages/static/description/status5.png differ diff --git a/employee_stages/static/description/status6.png b/employee_stages/static/description/status6.png new file mode 100644 index 000000000..568e68559 Binary files /dev/null and b/employee_stages/static/description/status6.png differ diff --git a/employee_stages/static/description/tree.png b/employee_stages/static/description/tree.png new file mode 100644 index 000000000..ee529a830 Binary files /dev/null and b/employee_stages/static/description/tree.png differ diff --git a/employee_stages/views/employee_stages_view.xml b/employee_stages/views/employee_stages_view.xml new file mode 100644 index 000000000..bed5b62b3 --- /dev/null +++ b/employee_stages/views/employee_stages_view.xml @@ -0,0 +1,120 @@ + + + + wizard.employee.form + wizard.employee.stage + +
    + + + +
    +
    +
    +
    +
    + + + Set as Employee + wizard.employee.stage + form + form + + new + + + + hr.employee.form.view + hr.employee + + + +
    +
    +
    + + + + + + + + + + + + +
    +
    + + + hr.employee.tree.view + hr.employee + + + + + + + + + + hr.employee.search.view + hr.employee + + + + + + + + + + + + + + hr.employee.kanban.view + hr.employee + + + + + + +
  • +
    +
    +
    + + + Employees + hr.employee + form + kanban,tree,form + [] + {"search_default_employee":1} + + + +

    + Click to add a new employee. +

    + With just a quick glance on the Odoo employee screen, you + can easily find all the information you need for each person; + contact data, job position, availability, etc. +

    +
    +
    +
    diff --git a/employee_vehicle_request/__init__.py b/employee_vehicle_request/__init__.py new file mode 100644 index 000000000..f0c1cf4f4 --- /dev/null +++ b/employee_vehicle_request/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models diff --git a/employee_vehicle_request/__manifest__.py b/employee_vehicle_request/__manifest__.py new file mode 100644 index 000000000..f7d5d4b8d --- /dev/null +++ b/employee_vehicle_request/__manifest__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Employee Vehicle Request', + 'version': '10.0.1.0.0', + 'summary': """Manage Vehicle Requests From Employee""", + 'description': """This module is used for manage vehicle requests from employee. + This module also checking the vehicle availability at the requested time slot.""", + 'category': "Generic Modules/Human Resources", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'hr', 'fleet'], + 'data': [ + 'data/data.xml', + 'security/security.xml', + 'security/ir.model.access.csv', + 'views/employee_fleet_view.xml', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'demo': [], + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/employee_vehicle_request/data/data.xml b/employee_vehicle_request/data/data.xml new file mode 100644 index 000000000..0fe28c0af --- /dev/null +++ b/employee_vehicle_request/data/data.xml @@ -0,0 +1,15 @@ + + + + + User can only see his/her vehicle + + + + + + + [] + + + \ No newline at end of file diff --git a/employee_vehicle_request/models/__init__.py b/employee_vehicle_request/models/__init__.py new file mode 100644 index 000000000..4de95416a --- /dev/null +++ b/employee_vehicle_request/models/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import employee_fleet diff --git a/employee_vehicle_request/models/employee_fleet.py b/employee_vehicle_request/models/employee_fleet.py new file mode 100644 index 000000000..953ccedc9 --- /dev/null +++ b/employee_vehicle_request/models/employee_fleet.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from datetime import datetime +from odoo import models, fields, api, _ +from odoo.exceptions import Warning + + +class FleetReservedTime(models.Model): + _name = "fleet.reserved" + _description = "Reserved Time" + + employee = fields.Many2one('hr.employee', string='Employee') + date_from = fields.Datetime(string='Reserved Date From') + date_to = fields.Datetime(string='Reserved Date To') + reserved_obj = fields.Many2one('fleet.vehicle') + + +class FleetVehicleInherit(models.Model): + _inherit = 'fleet.vehicle' + + check_availability = fields.Boolean(default=True, copy=False) + reserved_time = fields.One2many('fleet.reserved', 'reserved_obj', String='Reserved Time', readonly=1, + ondelete='cascade') + + +class EmployeeFleet(models.Model): + _name = 'employee.fleet' + _description = 'Employee Vehicle Request' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + + @api.model + def create(self, vals): + vals['name'] = self.env['ir.sequence'].next_by_code('employee.fleet') + return super(EmployeeFleet, self).create(vals) + + @api.multi + def send(self): + fleet_obj = self.env['fleet.vehicle'].search([]) + check_availability = 0 + for i in fleet_obj: + for each in i.reserved_time: + if each.date_from <= self.date_from <= each.date_to: + check_availability = 1 + elif self.date_from < each.date_from: + if each.date_from <= self.date_to <= each.date_to: + check_availability = 1 + elif self.date_to > each.date_to: + check_availability = 1 + else: + check_availability = 0 + else: + check_availability = 0 + if check_availability == 0: + reserved_id = self.fleet.reserved_time.create({'employee': self.employee.id, + 'date_from': self.date_from, + 'date_to': self.date_to, + 'reserved_obj': self.fleet.id, + }) + self.write({'reserved_fleet_id': reserved_id.id}) + self.state = 'waiting' + else: + raise Warning('Sorry This vehicle is already requested by another employee') + + @api.multi + def approve(self): + self.fleet.fleet_status = True + self.state = 'confirm' + mail_content = _('Hi %s,
    Your vehicle request for the reference %s is approved.') % \ + (self.employee.name, self.name) + main_content = { + 'subject': _('%s: Approved') % self.name, + 'author_id': self.env.user.partner_id.id, + 'body_html': mail_content, + 'email_to': self.employee.work_email, + } + mail_id = self.env['mail.mail'].create(main_content) + mail_id.mail_message_id.body = mail_content + mail_id.send() + if self.employee.user_id: + mail_id.mail_message_id.write({'needaction_partner_ids': [(4, self.employee.user_id.partner_id.id)]}) + mail_id.mail_message_id.write({'partner_ids': [(4, self.employee.user_id.partner_id.id)]}) + + @api.multi + def reject(self): + self.reserved_fleet_id.unlink() + self.state = 'reject' + mail_content = _('Hi %s,
    Sorry, Your vehicle request for the reference %s is Rejected.') % \ + (self.employee.name, self.name) + + main_content = { + 'subject': _('%s: Approved') % self.name, + 'author_id': self.env.user.partner_id.id, + 'body_html': mail_content, + 'email_to': self.employee.work_email, + } + mail_id = self.env['mail.mail'].create(main_content) + mail_id.mail_message_id.body = mail_content + mail_id.send() + if self.employee.user_id: + mail_id.mail_message_id.write({'needaction_partner_ids': [(4, self.employee.user_id.partner_id.id)]}) + mail_id.mail_message_id.write({'partner_ids': [(4, self.employee.user_id.partner_id.id)]}) + + @api.multi + def cancel(self): + if self.reserved_fleet_id: + self.reserved_fleet_id.unlink() + self.state = 'cancel' + + @api.multi + def returned(self): + self.reserved_fleet_id.unlink() + self.returned_date = fields.datetime.now() + self.state = 'return' + + @api.constrains('date_rom', 'date_to') + def onchange_date_to(self): + for each in self: + if each.date_from > each.date_to: + raise Warning('Date To must be greater than Date From') + + @api.onchange('date_from', 'date_to') + def check_availability(self): + self.fleet = '' + fleet_obj = self.env['fleet.vehicle'].search([]) + for i in fleet_obj: + for each in i.reserved_time: + if each.date_from <= self.date_from <= each.date_to: + i.write({'check_availability': False}) + elif self.date_from < each.date_from: + if each.date_from <= self.date_to <= each.date_to: + i.write({'check_availability': False}) + elif self.date_to > each.date_to: + i.write({'check_availability': False}) + else: + i.write({'check_availability': True}) + else: + i.write({'check_availability': True}) + + reserved_fleet_id = fields.Many2one('fleet.reserved', invisible=1, copy=False) + name = fields.Char(string='Request Number', copy=False) + employee = fields.Many2one('hr.employee', string='Employee', required=1, readonly=True, + states={'draft': [('readonly', False)]}) + req_date = fields.Date(string='Requested Date', default=datetime.now(), required=1, readonly=True, + states={'draft': [('readonly', False)]}, help="Requested Date") + fleet = fields.Many2one('fleet.vehicle', string='Vehicle', required=1, readonly=True, + states={'draft': [('readonly', False)]}) + date_from = fields.Datetime(string='From', required=1, readonly=True, + states={'draft': [('readonly', False)]}) + date_to = fields.Datetime(string='To', required=1, readonly=True, + states={'draft': [('readonly', False)]}) + returned_date = fields.Datetime(string='Returned Date', readonly=1) + purpose = fields.Text(string='Purpose', required=1, readonly=True, + states={'draft': [('readonly', False)]}, help="Purpose") + state = fields.Selection([('draft', 'Draft'), ('waiting', 'Waiting for Approval'), ('cancel', 'Cancel'), + ('confirm', 'Approved'), ('reject', 'Rejected'), ('return', 'Returned')], + string="State", default="draft") + diff --git a/employee_vehicle_request/security/ir.model.access.csv b/employee_vehicle_request/security/ir.model.access.csv new file mode 100644 index 000000000..6401ebdc3 --- /dev/null +++ b/employee_vehicle_request/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_fleet_reserved_employee,access.fleet.reserved.employee,model_fleet_reserved,base.group_user,1,1,1,0 +access_fleet_reserved_hr,access.fleet.reserved.hr,model_fleet_reserved,hr.group_hr_manager,1,1,1,1 +access_fleet_reserved_hr_user,access.fleet.reserved.hr.user,model_fleet_reserved,hr.group_hr_user,1,1,1,0 +access_employee_fleet_employee,access.employee.fleet.employee,model_employee_fleet,base.group_user,1,1,1,0 +access_employee_fleet_hr,access.employee.fleet.hr,model_employee_fleet,hr.group_hr_manager,1,1,1,1 +access_employee_fleet_hr_user,access.employee.fleet.hr.user,model_employee_fleet,hr.group_hr_user,1,1,1,0 diff --git a/employee_vehicle_request/security/security.xml b/employee_vehicle_request/security/security.xml new file mode 100644 index 000000000..cc4ef8001 --- /dev/null +++ b/employee_vehicle_request/security/security.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/employee_vehicle_request/static/description/banner.jpg b/employee_vehicle_request/static/description/banner.jpg new file mode 100644 index 000000000..47f8fbf0b Binary files /dev/null and b/employee_vehicle_request/static/description/banner.jpg differ diff --git a/employee_vehicle_request/static/description/cybro_logo.png b/employee_vehicle_request/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/employee_vehicle_request/static/description/cybro_logo.png differ diff --git a/employee_vehicle_request/static/description/icon.png b/employee_vehicle_request/static/description/icon.png new file mode 100644 index 000000000..24f9b6b08 Binary files /dev/null and b/employee_vehicle_request/static/description/icon.png differ diff --git a/employee_vehicle_request/static/description/index.html b/employee_vehicle_request/static/description/index.html new file mode 100644 index 000000000..26571494c --- /dev/null +++ b/employee_vehicle_request/static/description/index.html @@ -0,0 +1,118 @@ +
    +
    +

    Employee Vehicle Request

    +

    This Module Helps You To Manage Vehicle Requests From Employee

    +

    Cybrosys Technologies

    +
    +
    +

    Features:

    +
    + Employee can request for any vehicle.
    + Checking availability of vehicles.
    + Validation for send request.
    + Validation for requested dates.
    + Advanced search view.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    + This module is used to manage vehicle requests from each employee. According to this module + two employees can't request the same vehicle at same time. Because this module will check + the vehicle availability. Also this module gives the validation for send request and requested dates. +

    +
    +
    +
    + +
    +
    +

    Vehicle Request

    +
    +

    +

    Employee -> Vehicle Request -> Vehicle Request

    +

    +

    +
    + +
    + +
    +
    + ☛ Here any employee can request available vehicle for a time period. + He should mention the time period and purpose. Then he can send this request to hr manager. Here also + module checking the availability of vehicle. +
    +
    +
    + +
    +
    +

    Approval

    +
    +
    + +
    +
    +
    +
    +
    +

    + Here Hr Manager can approve the vehicle request. Or she can refuse the request. Also Employee + can cancel this request from this stage before approval or rejection. +

    +

    +
    +
    +
    + +
    +
    +

    Validation Messages

    +
    +
    + +
    + ☛ Requested Period Validation +
    +
    +
    + +
    + ☛Checking the availability of vehicle +
    +
    +
    + +
    +

    Need Any Help?

    + +
    + + + diff --git a/employee_vehicle_request/static/description/index.html~ b/employee_vehicle_request/static/description/index.html~ new file mode 100644 index 000000000..65882a633 --- /dev/null +++ b/employee_vehicle_request/static/description/index.html~ @@ -0,0 +1,118 @@ +
    +
    +

    Employee Vehicle Request

    +

    This Module Helps You To Manage Vehicle Requests From Employee

    +

    Cybrosys Technologies

    +
    +
    +

    Features:

    +
    + Employee can request for any vehicle.
    + Checking availability of vehicles.
    + Validation for Send Request.
    + Validation for Requested Dates.
    + Advanced Search View.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    + This module is used to manage vehicle requests from each employee. According to this module + two employees can't request the same vehicle at same time. Because this module will check + the vehicle availability. Also this module gives the validation for send request and requested dates. +

    +
    +
    +
    + +
    +
    +

    Vehicle Request

    +
    +

    +

    Employee -> Vehicle Request -> Vehicle Request

    +

    +

    +
    + +
    + +
    +
    + ☛ Here any employee can request available vehicle for a time period. + He should mention the time period and purpose. Then he can send this request to hr manager. Here also + module checking the availability of vehicle. +
    +
    +
    + +
    +
    +

    Approval

    +
    +
    + +
    +
    +
    +
    +
    +

    + Here Hr Manager can approve the vehicle request. Or she can refuse the request. Also Employee + can cancel this request from this stage before approval or rejection. +

    +

    +
    +
    +
    + +
    +
    +

    Validation Messages

    +
    +
    + +
    + ☛ Requested Period Validation +
    +
    +
    + +
    + ☛Checking the availability of vehicle +
    +
    +
    + +
    +

    Need Any Help?

    + +
    + + + diff --git a/employee_vehicle_request/static/description/validation1.png b/employee_vehicle_request/static/description/validation1.png new file mode 100644 index 000000000..f985476be Binary files /dev/null and b/employee_vehicle_request/static/description/validation1.png differ diff --git a/employee_vehicle_request/static/description/validation2.png b/employee_vehicle_request/static/description/validation2.png new file mode 100644 index 000000000..4eb86c19b Binary files /dev/null and b/employee_vehicle_request/static/description/validation2.png differ diff --git a/employee_vehicle_request/static/description/vehicle1.png b/employee_vehicle_request/static/description/vehicle1.png new file mode 100644 index 000000000..200536378 Binary files /dev/null and b/employee_vehicle_request/static/description/vehicle1.png differ diff --git a/employee_vehicle_request/static/description/vehicle2.png b/employee_vehicle_request/static/description/vehicle2.png new file mode 100644 index 000000000..8bccb2424 Binary files /dev/null and b/employee_vehicle_request/static/description/vehicle2.png differ diff --git a/employee_vehicle_request/views/employee_fleet_view.xml b/employee_vehicle_request/views/employee_fleet_view.xml new file mode 100644 index 000000000..1d465f395 --- /dev/null +++ b/employee_vehicle_request/views/employee_fleet_view.xml @@ -0,0 +1,117 @@ + + + + + Vehicle Request Code + employee.fleet + + VR + + + + fleet.vehicle.form.inherit.view + fleet.vehicle + + + + + + + + + + + employee.fleet.form + employee.fleet + +
    +
    +
    + +

    + +

    + + + + + + + + + + + + + +
    +
    + + +
    +
    +
    +
    + + + employee.fleet.tree + employee.fleet + + + + + + + + + + + + + + employee.fleet.search + employee.fleet + + + + + + + + + + + + + + + + + + + + Vehicle Request + ir.actions.act_window + employee.fleet + form + tree,form + + +

    + Click to create a New Vehicle Request. +

    +
    +
    + + + +
    +
    \ No newline at end of file diff --git a/event_catering/README.rst b/event_catering/README.rst new file mode 100644 index 000000000..03cc4e5ce --- /dev/null +++ b/event_catering/README.rst @@ -0,0 +1,24 @@ +================== +Event Catering v10 +================== +Event Catering attaches catering service to Event Management module thus extending the scope of the Event Management Module. +When you install this module, a new service 'Catering' will be available in event management. + +Features +======== +* Automatically creates from event order. +* Catering manager can update the state of the event order. +* Single click for completing a work. + +Contributors +============ + +* Avinash Nk + + +Maintainer +========== + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com diff --git a/event_catering/__init__.py b/event_catering/__init__.py new file mode 100644 index 000000000..18b219312 --- /dev/null +++ b/event_catering/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import models diff --git a/event_catering/__manifest__.py b/event_catering/__manifest__.py new file mode 100644 index 000000000..01acd659a --- /dev/null +++ b/event_catering/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +{ + 'name': 'Event Catering Service', + 'version': '10.0.1.0.0', + 'summary': """Catering Service for Event Management Module.""", + 'description': """Catering Service for Event Management Module.""", + "category": "Industry", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['event_management'], + 'data': ['security/catering_security.xml', + 'security/ir.model.access.csv', + 'views/catering_service.xml', + 'views/event_form.xml', + 'data/catering_service.xml', + ], + 'demo': [ + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'application': False, +} diff --git a/event_catering/data/catering_service.xml b/event_catering/data/catering_service.xml new file mode 100644 index 000000000..d02352581 --- /dev/null +++ b/event_catering/data/catering_service.xml @@ -0,0 +1,22 @@ + + + + + + Catering Service + catering.order.sequence + %(day)s/%(month)s/%(year)s + CAT- + 1 + 2 + + + + Catering Service + service + + + + + + diff --git a/event_catering/models/__init__.py b/event_catering/models/__init__.py new file mode 100644 index 000000000..eeb1c026c --- /dev/null +++ b/event_catering/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import catering_service diff --git a/event_catering/models/catering_service.py b/event_catering/models/catering_service.py new file mode 100644 index 000000000..70fb97ece --- /dev/null +++ b/event_catering/models/catering_service.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from odoo import models, fields, api, _ +from odoo.exceptions import UserError + + +class EventManagementInherit(models.Model): + _inherit = 'event.management' + + catering_on = fields.Boolean(string="Catering Active", default=False) + catering_id = fields.Many2one('event.management.catering', string="Catering Id") + catering_pending = fields.Integer(string='Catering Pending', compute='compute_catering_pending') + catering_done = fields.Integer(string='Catering Done', compute='compute_catering_done') + + @api.multi + def compute_catering_pending(self): + for order in self.catering_id: + pending = 0 + for lines in order.catering_works: + if lines.work_done is False: + pending += 1 + self.catering_pending = pending + + @api.multi + def compute_catering_done(self): + for order in self.catering_id: + done = 0 + for lines in order.catering_works: + if lines.work_done is True: + done += 1 + self.catering_done = done + + @api.multi + def event_confirm(self): + catering_service = self.env['event.management.catering'] + catering_line = self.service_line.search([('service', '=', 'catering'), ('event_id', '=', self.id)]) + if len(catering_line) > 0: + self.catering_on = True + sequence_code = 'catering.order.sequence' + name = self.env['ir.sequence'].next_by_code(sequence_code) + event = self.id + event_type = self.type_of_event.id + start_date = catering_line.date_from + end_date = catering_line.date_to + catering_id = catering_line.id + data = { + 'name': name, + 'start_date': start_date, + 'end_date': end_date, + 'parent_event': event, + 'event_type': event_type, + 'catering_id': catering_id, + } + catering_map = catering_service.create(data) + self.catering_id = catering_map.id + super(EventManagementInherit, self).event_confirm() + + @api.multi + def action_view_catering_service(self): + """This function returns an action that display existing catering service + of the event.""" + action = self.env.ref('event_catering.event_catering_action').read()[0] + action['views'] = [(self.env.ref('event_catering.event_catering_form_view').id, 'form')] + action['res_id'] = self.catering_id.id + if self.catering_id.id is not False: + return action + + +class EventService(models.Model): + _inherit = 'event.service.line' + + service = fields.Selection(selection_add=[('catering', 'Catering')]) + + +class EventManagementCatering(models.Model): + _name = 'event.management.catering' + + name = fields.Char(string="Name", readonly=True) + date = fields.Date(string="Date", default=fields.Date.today, readonly=True) + start_date = fields.Datetime(string="Start date", readonly=True) + end_date = fields.Datetime(string="End date", readonly=True) + catering_works = fields.One2many('event.catering.works', 'catering_id', string="Catering Works") + state = fields.Selection([('open', 'Open'), ('done', 'Done')], string="State", default="open") + note = fields.Text(string="Terms and conditions") + price_subtotal = fields.Float(string='Total', compute='sub_total_update', readonly=True, store=True) + parent_event = fields.Many2one('event.management', string="Event", readonly=True) + catering_id = fields.Integer(string="Catering Id") + currency_id = fields.Many2one('res.currency', readonly=True, + default=lambda self: self.env.user.company_id.currency_id) + event_type = fields.Many2one('event.management.type', string="Event Type", readonly=True) + + @api.multi + @api.depends('catering_works') + def sub_total_update(self): + total = 0 + for items in self.catering_works: + total += items.quantity * items.amount + self.price_subtotal = total + + @api.multi + def catering_done(self): + for items in self.catering_works: + if items.work_done is False: + raise UserError(_("Catering works are pending")) + related_product = self.env.ref('event_catering.catering_service_product').id + for items in self.sudo().parent_event.service_line: + if items.id == self.sudo().catering_id: + items.sudo().write({'amount': self.price_subtotal, 'state': 'done', 'related_product': related_product}) + self.state = "done" + + +class EventCateringWorks(models.Model): + _name = 'event.catering.works' + + service = fields.Many2one('product.product', string="Services", required=True) + quantity = fields.Float(string="Quantity", default=1) + amount = fields.Float(string="Amount") + sub_total = fields.Float(string="Sub Total", compute="sub_total_computation", readonly=True) + currency_id = fields.Many2one('res.currency', readonly=True, + default=lambda self: self.env.user.company_id.currency_id) + catering_id = fields.Many2one('event.management.catering', string="Catering Id") + work_done = fields.Boolean(string="Work done", default=False) + + @api.onchange('service') + def onchange_service(self): + self.amount = self.service.lst_price + + @api.one + @api.depends('quantity', 'amount') + def sub_total_computation(self): + self.sub_total = self.quantity * self.amount + + @api.multi + def work_completed(self): + if self.catering_id.state == "open": + self.work_done = False + + @api.multi + def not_completed(self): + if self.catering_id.state == "open": + self.work_done = True diff --git a/event_catering/security/catering_security.xml b/event_catering/security/catering_security.xml new file mode 100644 index 000000000..475ce9344 --- /dev/null +++ b/event_catering/security/catering_security.xml @@ -0,0 +1,15 @@ + + + + + + Catering Manager + + + + + + + + + \ No newline at end of file diff --git a/event_catering/security/ir.model.access.csv b/event_catering/security/ir.model.access.csv new file mode 100644 index 000000000..4b10bc33b --- /dev/null +++ b/event_catering/security/ir.model.access.csv @@ -0,0 +1,8 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +event_management_catering_id,event_management_catering,model_event_management_catering,event_management.group_event_manager,1,1,1,1 +event_catering_works_id,event_catering_works,model_event_catering_works,event_management.group_event_manager,1,1,1,1 + +event_management_catering_id1,event_management_catering1,model_event_management_catering,event_catering.group_catering_manager,1,1,1,1 +event_catering_works_id1,event_catering_works1,model_event_catering_works,event_catering.group_catering_manager,1,1,1,1 +event_management_type_id1,event_management_type1,event_management.model_event_management_type,event_catering.group_catering_manager,1,0,0,0 + diff --git a/event_catering/static/description/banner.jpg b/event_catering/static/description/banner.jpg new file mode 100644 index 000000000..29a47b8f8 Binary files /dev/null and b/event_catering/static/description/banner.jpg differ diff --git a/event_catering/static/description/cybro_logo.png b/event_catering/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/event_catering/static/description/cybro_logo.png differ diff --git a/event_catering/static/description/event_catering.png b/event_catering/static/description/event_catering.png new file mode 100644 index 000000000..30b04f5ee Binary files /dev/null and b/event_catering/static/description/event_catering.png differ diff --git a/event_catering/static/description/event_catering_form.png b/event_catering/static/description/event_catering_form.png new file mode 100644 index 000000000..b7d0b4732 Binary files /dev/null and b/event_catering/static/description/event_catering_form.png differ diff --git a/event_catering/static/description/icon.png b/event_catering/static/description/icon.png new file mode 100644 index 000000000..b4c4fdba5 Binary files /dev/null and b/event_catering/static/description/icon.png differ diff --git a/event_catering/static/description/index.html b/event_catering/static/description/index.html new file mode 100644 index 000000000..7d85c92c0 --- /dev/null +++ b/event_catering/static/description/index.html @@ -0,0 +1,75 @@ +
    +
    +
    +

    Event Catering

    +

    Catering service for Event management module.

    +

    Manage all works related to catering.

    +

    Cybrosys Technologies

    +
    +
    +

    Major Features:

    +
      +
    •    Automatically creates from event order.
    • +
    •    Catering manager can update the state of the event order.
    • +
    •    Single click for completing a work.
    • +
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    Event Catering attaches catering service to Event Management module thus extending the scope of the Event Management Module. When you install this module, a new service 'Catering' will be available in event management.

    +
    +
    +
    + +
    +
    +
    +

    Event Catering

    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    Event Catering Form View

    +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    diff --git a/event_catering/static/img/catering_product-image.jpeg b/event_catering/static/img/catering_product-image.jpeg new file mode 100644 index 000000000..8563d90ea Binary files /dev/null and b/event_catering/static/img/catering_product-image.jpeg differ diff --git a/event_catering/views/catering_service.xml b/event_catering/views/catering_service.xml new file mode 100644 index 000000000..c3a880536 --- /dev/null +++ b/event_catering/views/catering_service.xml @@ -0,0 +1,169 @@ + + + + + + + + event_catering_tree_view.tree + event.management.catering + + + + + + + + + + + + + + + event_catering_kanban_view.kanban + event.management.catering + + + + + +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + event_catering_form_view.form + event.management.catering + +
    +
    +
    + +

    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    diff --git a/event_management/README.rst b/event_management/README.rst new file mode 100644 index 000000000..98f45c677 --- /dev/null +++ b/event_management/README.rst @@ -0,0 +1,32 @@ +==================== +Event Management v10 +==================== +Event management is a core module which can manage any type of events. +The user can selectively download and install different service modules to extend the scope of this module. +The new service will be automatically get attached to this core Event management module. +It is different from Odoo's event module. +Here you can manage different types of events and allocate services to different users. + +Note: Presently we have released the service “Event Catering” under this module. New services are being developed by our team. + +Features +======== +* Event order creation. +* Automatically creates service orders. +* Allocate the services to different users. +* Integrated with Accounting module. +* Simple Workflow. +* Attractive Design. + +Contributors +============ + +* Avinash Nk + + +Maintainer +========== + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com \ No newline at end of file diff --git a/event_management/__init__.py b/event_management/__init__.py new file mode 100644 index 000000000..18b219312 --- /dev/null +++ b/event_management/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import models diff --git a/event_management/__manifest__.py b/event_management/__manifest__.py new file mode 100644 index 000000000..0e52a0d14 --- /dev/null +++ b/event_management/__manifest__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +{ + 'name': 'Event Management', + 'version': '10.0.1.0.0', + 'summary': """Core Module for Managing Different Types Of Events.""", + 'description': """Core Module for Managing Different Types Of Events""", + "category": "Industry", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['product', 'account'], + 'data': ['security/event_security.xml', + 'security/ir.model.access.csv', + 'views/event_management_view.xml', + 'views/event_type_view.xml', + 'views/dashboard.xml', + 'data/event_management.xml', + ], + 'demo': [ + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'application': True, +} diff --git a/event_management/data/event_management.xml b/event_management/data/event_management.xml new file mode 100644 index 000000000..f9edf8ad5 --- /dev/null +++ b/event_management/data/event_management.xml @@ -0,0 +1,40 @@ + + + + + + Wedding + + + + Birthday + + + + Family Events + + + + Press Conference + + + + Seminars + + + + Conferences + + + + + Event Order + event.order.sequence + %(day)s/%(month)s/%(year)s + EVE- + 1 + 2 + + + + diff --git a/event_management/models/__init__.py b/event_management/models/__init__.py new file mode 100644 index 000000000..cd3e0d0ff --- /dev/null +++ b/event_management/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import event_management diff --git a/event_management/models/event_management.py b/event_management/models/event_management.py new file mode 100644 index 000000000..ae78b9170 --- /dev/null +++ b/event_management/models/event_management.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from odoo import models, fields, api, _ +from odoo.exceptions import UserError, ValidationError + + +class EventManagement(models.Model): + _name = 'event.management' + + name = fields.Char(string="Name", readonly=True) + type_of_event = fields.Many2one('event.management.type', string="Type", required=True) + partner_id = fields.Many2one('res.partner', string="Customer", required=True) + date = fields.Date(string="Date", default=fields.Date.today, required=True) + start_date = fields.Datetime(string="Start date", default=lambda self: fields.datetime.now(), required=True) + end_date = fields.Datetime(string="End date", required=True) + service_line = fields.One2many('event.service.line', 'event_id', string="Services") + state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('invoice', 'Invoiced'), + ('close', 'Close'), ('cancel', 'Canceled')], string="State", default="draft") + note = fields.Text('Terms and conditions') + price_subtotal = fields.Float(string='Total', compute='sub_total_update', readonly=True, store=True) + image = fields.Binary("Image", attachment=True, + help="This field holds the image used as image for the event, limited to 1080x720px.") + currency_id = fields.Many2one('res.currency', readonly=True, + default=lambda self: self.env.user.company_id.currency_id) + invoice_count = fields.Integer(string='# of Invoices') + invoice_ids = fields.Many2many("account.invoice", string='Invoices', copy=False) + pending_invoice = fields.Boolean(string="Invoice Pending", compute='pending_invoice_find') + + @api.multi + @api.depends('service_line', 'service_line.state') + def pending_invoice_find(self): + pending = 0 + for lines in self.service_line: + if lines.invoiced is False and lines.state == "done": + pending = 1 + if pending == 1: + self.pending_invoice = True + else: + self.pending_invoice = False + + @api.multi + @api.depends('service_line', 'service_line.amount') + def sub_total_update(self): + total = 0 + for items in self.service_line: + total += items.amount + self.price_subtotal = total + + @api.model + def create(self, values): + start_date = values['start_date'] + end_date = values['end_date'] + if start_date >= end_date: + raise UserError(_('Start date must be less than End date')) + sequence_code = 'event.order.sequence' + sequence_number = self.env['ir.sequence'].next_by_code(sequence_code) + values['name'] = sequence_number + return super(EventManagement, self).create(values) + + @api.multi + def event_confirm(self): + self.state = "confirm" + + @api.multi + def event_cancel(self): + self.state = "cancel" + + @api.multi + def event_close(self): + pending = 0 + for lines in self.service_line: + if lines.invoiced is False: + pending = 1 + if pending == 1: + raise ValidationError(_('You can close an event only when all services is Done and Invoiced')) + else: + self.state = "close" + + @api.multi + def action_view_invoice_event(self): + invoices = self.mapped('invoice_ids') + action = self.env.ref('account.action_invoice_tree1').read()[0] + if len(invoices) > 1: + action['domain'] = [('id', 'in', invoices.ids)] + elif len(invoices) == 1: + action['views'] = [(self.env.ref('account.invoice_form').id, 'form')] + action['res_id'] = invoices.ids[0] + else: + action = {'type': 'ir.actions.act_window_close'} + return action + + @api.multi + def event_invoice_create(self): + product_line = [] + for lines in self.service_line: + if lines.invoiced is False and lines.state == "done": + product_line.append({'product_id': lines.related_product, 'price_unit': lines.amount}) + lines.invoiced = True + if len(product_line) > 0: + journal_id = self.env['account.invoice'].default_get(['journal_id'])['journal_id'] + company_id = self.env.user.company_id.id + inv_obj = self.env['account.invoice'] + inv_line_obj = self.env['account.invoice.line'] + partner = self.partner_id + inv_data = { + 'name': partner.name, + 'reference': partner.name, + 'account_id': partner.property_account_payable_id.id, + 'partner_id': partner.id, + 'currency_id': self.currency_id.id, + 'journal_id': journal_id, + 'origin': self.name, + 'company_id': company_id, + } + inv_id = inv_obj.create(inv_data) + for records in product_line: + product_id = records['product_id'] + price_unit = records['price_unit'] + if product_id.property_account_income_id.id: + income_account = product_id.property_account_income_id.id + elif product_id.categ_id.property_account_income_categ_id.id: + income_account = product_id.categ_id.property_account_income_categ_id.id + else: + raise UserError( + _('Please define income account for this product: "%s" (id:%d).') % (product_id.name, + product_id.id)) + inv_line_data = { + 'name': self.name, + 'account_id': income_account, + 'price_unit': price_unit, + 'quantity': 1, + 'product_id': product_id.id, + 'invoice_id': inv_id.id, + 'uom_id': product_id.uom_id.id, + } + inv_line_obj.create(inv_line_data) + imd = self.env['ir.model.data'] + action = imd.xmlid_to_object('account.action_invoice_tree1') + list_view_id = imd.xmlid_to_res_id('account.invoice_tree') + form_view_id = imd.xmlid_to_res_id('account.invoice_form') + result = { + 'name': action.name, + 'help': action.help, + 'type': 'ir.actions.act_window', + 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], + [False, 'calendar'], [False, 'pivot']], + 'target': action.target, + 'context': action.context, + 'res_model': 'account.invoice', + } + if len(inv_id) > 1: + result['domain'] = "[('id','in',%s)]" % inv_id.ids + elif len(inv_id) == 1: + result['views'] = [(form_view_id, 'form')] + result['res_id'] = inv_id.ids[0] + else: + result = {'type': 'ir.actions.act_window_close'} + self.state = "invoice" + all_invoice_ids = self.invoice_ids.ids + all_invoice_ids.append(inv_id.id) + self.update({'invoice_ids': all_invoice_ids, 'invoice_count': self.invoice_count + 1}) + return result + + +class EventServiceLine(models.Model): + _name = 'event.service.line' + + service = fields.Selection([('none', 'None')], string="Services", required=True) + event_id = fields.Many2one('event.management', string="Event") + date_from = fields.Datetime(string="Date from", required=True) + date_to = fields.Datetime(string="Date to", required=True) + amount = fields.Float(string="Amount", readonly=True) + state = fields.Selection([('done', 'Done'), ('pending', 'Pending')], string="State", default="pending", + readonly=True) + currency_id = fields.Many2one('res.currency', readonly=True, + default=lambda self: self.env.user.company_id.currency_id) + invoiced = fields.Boolean(string="Invoiced") + related_product = fields.Many2one('product.product', string="Related Product") + + _sql_constraints = [('event_supplier_unique', 'unique(event_id, service)', + 'Duplication Of Service In The Service Lines Is not Allowed')] + + @api.multi + @api.constrains('date_from', 'date_to') + def _check_date_to_date_from(self): + if self.date_to < self.date_from: + raise ValidationError(_('"Date to" cannot be set before "Date from".\n\n' + 'Check the "Date from" and "Date to" of the "%s" service' % self.service)) + + +class EventManagementType(models.Model): + _name = 'event.management.type' + + name = fields.Char(string="Name") + image = fields.Binary("Image", attachment=True, + help="This field holds the image used as image for the event, limited to 1080x720px.") + event_count = fields.Integer(string="# of Events", compute='event_count_calculation') + + @api.multi + def event_count_calculation(self): + for records in self: + events = self.env['event.management'].search([('type_of_event', '=', records.id)]) + records.event_count = len(events) diff --git a/event_management/security/event_security.xml b/event_management/security/event_security.xml new file mode 100644 index 000000000..1635d1bf5 --- /dev/null +++ b/event_management/security/event_security.xml @@ -0,0 +1,17 @@ + + + + + + Event Management + 19 + + + + Event Manager + + + + + + \ No newline at end of file diff --git a/event_management/security/ir.model.access.csv b/event_management/security/ir.model.access.csv new file mode 100644 index 000000000..a3607ac6f --- /dev/null +++ b/event_management/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +event_management_id,event_management,model_event_management,event_management.group_event_manager,1,1,1,1 +event_service_line_id,event_service_line,model_event_service_line,event_management.group_event_manager,1,1,1,1 +event_management_type_id,event_management_type,model_event_management_type,event_management.group_event_manager,1,1,1,1 + diff --git a/event_management/static/description/banner.jpg b/event_management/static/description/banner.jpg new file mode 100644 index 000000000..fde2857f5 Binary files /dev/null and b/event_management/static/description/banner.jpg differ diff --git a/event_management/static/description/cybro_logo.png b/event_management/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/event_management/static/description/cybro_logo.png differ diff --git a/event_management/static/description/event_dashboard.png b/event_management/static/description/event_dashboard.png new file mode 100644 index 000000000..a7f6c4792 Binary files /dev/null and b/event_management/static/description/event_dashboard.png differ diff --git a/event_management/static/description/event_order.png b/event_management/static/description/event_order.png new file mode 100644 index 000000000..3f6dfd306 Binary files /dev/null and b/event_management/static/description/event_order.png differ diff --git a/event_management/static/description/event_order_creation.gif b/event_management/static/description/event_order_creation.gif new file mode 100644 index 000000000..903a6220e Binary files /dev/null and b/event_management/static/description/event_order_creation.gif differ diff --git a/event_management/static/description/event_order_form.png b/event_management/static/description/event_order_form.png new file mode 100644 index 000000000..1a844c37a Binary files /dev/null and b/event_management/static/description/event_order_form.png differ diff --git a/event_management/static/description/event_type.png b/event_management/static/description/event_type.png new file mode 100644 index 000000000..bd476e739 Binary files /dev/null and b/event_management/static/description/event_type.png differ diff --git a/event_management/static/description/icon.png b/event_management/static/description/icon.png new file mode 100644 index 000000000..3c0a67266 Binary files /dev/null and b/event_management/static/description/icon.png differ diff --git a/event_management/static/description/index.html b/event_management/static/description/index.html new file mode 100644 index 000000000..fdb98122d --- /dev/null +++ b/event_management/static/description/index.html @@ -0,0 +1,117 @@ +
    +
    +
    +

    Event Management

    +

    Manage different types of events.

    +

    Core Module for Event Management.

    +

    Cybrosys Technologies

    +
    +
    +

    Major Features:

    +
      +
    •    Event order creation.
    • +
    •    Automatically creates service orders.
    • +
    •    Allocate the services to different users.
    • +
    •    Integrated with Accounting module.
    • +
    •    Simple Workflow.
    • +
    •    Attractive Design.
    • +
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    Event management is a core module which can manage any type of events. The user can selectively download and install different service modules to extend the scope of this module. The new service will be automatically get attached to this core Event management module. It is different from Odoo's event module. Here you can manage different types of events and allocate services to different users.

    +

    Note: Presently we have released the service 'Event Catering' under this module. New services are being developed by our team.

    +
    +
    +
    + +
    +
    +
    +

    Event Dashboard

    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    Event Order View

    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    Event Order Form View

    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    Event Type

    +
    + +
    +
    +
    +
    +
    +
    +
    +

    Event Services

    +

    +

    After installing a new service, you will get an option to select the service in the event order.

    +

    +

    +

    Creating an Event Order

    +

    +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    diff --git a/event_management/static/img/event_type_image1.jpg b/event_management/static/img/event_type_image1.jpg new file mode 100644 index 000000000..208cf6045 Binary files /dev/null and b/event_management/static/img/event_type_image1.jpg differ diff --git a/event_management/static/img/event_type_image2.jpeg b/event_management/static/img/event_type_image2.jpeg new file mode 100644 index 000000000..c74b7c25f Binary files /dev/null and b/event_management/static/img/event_type_image2.jpeg differ diff --git a/event_management/static/img/event_type_image3.jpeg b/event_management/static/img/event_type_image3.jpeg new file mode 100644 index 000000000..c63d5de66 Binary files /dev/null and b/event_management/static/img/event_type_image3.jpeg differ diff --git a/event_management/static/img/event_type_image4.jpeg b/event_management/static/img/event_type_image4.jpeg new file mode 100644 index 000000000..e60d88943 Binary files /dev/null and b/event_management/static/img/event_type_image4.jpeg differ diff --git a/event_management/static/img/event_type_image5.jpeg b/event_management/static/img/event_type_image5.jpeg new file mode 100644 index 000000000..777a7eeba Binary files /dev/null and b/event_management/static/img/event_type_image5.jpeg differ diff --git a/event_management/static/img/event_type_image6.jpeg b/event_management/static/img/event_type_image6.jpeg new file mode 100644 index 000000000..686b70056 Binary files /dev/null and b/event_management/static/img/event_type_image6.jpeg differ diff --git a/event_management/static/src/css/event_dashboard.css b/event_management/static/src/css/event_dashboard.css new file mode 100644 index 000000000..f7461404d --- /dev/null +++ b/event_management/static/src/css/event_dashboard.css @@ -0,0 +1,12 @@ +.style_event { + text-align: center; + flex: none !important; + background: none !important; + box-shadow: none !important; +} +.style_event_type { + text-align: center; + flex: none !important; + background: none !important; + box-shadow: none !important; +} diff --git a/event_management/views/dashboard.xml b/event_management/views/dashboard.xml new file mode 100644 index 000000000..8f183b9c7 --- /dev/null +++ b/event_management/views/dashboard.xml @@ -0,0 +1,62 @@ + + + + + event_management_kanban.dashboard + event.management.type + kanban + + + + + + +
    +
    +
    +

    +
    +
    + +
    +
    + +
    +
    + + Total Orders : + + + + +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + Dashboard + event.management.type + form + kanban,form + {} + + + +
    +
    \ No newline at end of file diff --git a/event_management/views/event_management_view.xml b/event_management/views/event_management_view.xml new file mode 100644 index 000000000..7f8d8899b --- /dev/null +++ b/event_management/views/event_management_view.xml @@ -0,0 +1,206 @@ + + + + + + + + event_management_tree_view.tree + event.management + + + + + + + + + + + + + + + + + event_management_kanban_view.kanban + event.management + + + + + +
    + + +
    + + + +
    +
    +
    + +
    +
    +
    +
    + + + + + + + + + + event_management_form_view.form + event.management + +
    +
    +
    + +
    + +
    +

    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + event_management_view.search + event.management + + + + + + + + + + + + + + + + + + event_management_view.calendar + event.management + + + + + + + + + + + + + event_management_view.graph + event.management + + + + + + + + + + + + Event Management + event.management + ir.actions.act_window + form + kanban,tree,form,calendar,graph + +

    + Click to add an event order. +

    + Here you can create and manage your events. +

    +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/event_management/views/event_type_view.xml b/event_management/views/event_type_view.xml new file mode 100644 index 000000000..0931b9edf --- /dev/null +++ b/event_management/views/event_type_view.xml @@ -0,0 +1,52 @@ + + + + + + event_type_tree_view.tree + event.management.type + + + + + + + + + event_type_form_view.form + event.management.type + +
    + +
    + +
    +

    + +

    +
    +
    +
    +
    + + + Event type + event.management.type + ir.actions.act_window + form + tree,form + +

    + Click to add an event type. +

    + Here you can create different types of events. +

    +
    +
    + + + + +
    +
    \ No newline at end of file diff --git a/event_management_mail/README.rst b/event_management_mail/README.rst new file mode 100644 index 000000000..2f4f0e5c1 --- /dev/null +++ b/event_management_mail/README.rst @@ -0,0 +1,23 @@ +======================== +Event Mail v10 +======================== +Event mail adds the functionality to send email notification to the customer at the time of event order confirmation. + +Features +======== +* Customize your own templates for mail. +* Default template for order confirmation. +* Send notification email to customer when an event order is confirmed. + +Contributors +======= + +* Avinash Nk + + +Maintainer +======= + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com \ No newline at end of file diff --git a/event_management_mail/__init__.py b/event_management_mail/__init__.py new file mode 100644 index 000000000..18b219312 --- /dev/null +++ b/event_management_mail/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import models diff --git a/event_management_mail/__manifest__.py b/event_management_mail/__manifest__.py new file mode 100644 index 000000000..1ffcd9de7 --- /dev/null +++ b/event_management_mail/__manifest__.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +{ + 'name': 'Event Mail', + 'version': '10.0.1.0.0', + 'summary': """Send Email Notification to the Customer at the Time of Event Order Confirmation.""", + 'description': """Send Email Notification to the Customer at the Time of Event Order Confirmation.""", + "category": "Tools", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['event_management'], + 'data': ['data/event_mail_template.xml', + 'views/event_mail.xml', + ], + 'demo': [ + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'application': False, +} diff --git a/event_management_mail/data/event_mail_template.xml b/event_management_mail/data/event_mail_template.xml new file mode 100644 index 000000000..790650def --- /dev/null +++ b/event_management_mail/data/event_mail_template.xml @@ -0,0 +1,113 @@ + + + + + + + + Event Confirmation - Send by Email + ${(object.create_uid.email and '%s <%s>' % (object.create_uid.name, object.create_uid.email) or '')|safe} + ${object.create_uid.company_id.name} Event Confirmation (Ref ${object.name or 'n/a'}) + ${object.partner_id.id} + + ${object.create_uid.email|safe} + + Event_${(object.name or '').replace('/','_')}} + ${object.partner_id.lang} + Dear ${object.partner_id.name} +% if object.partner_id.parent_id: + (${object.partner_id.parent_id.name}) +% endif +,

    +

    Your event order is confirmed.(${object.name})

    +

    Thank you,

    +% if object.create_uid and object.create_uid.signature: + ${object.create_uid.signature | safe} +% endif +]]>
    +
    + + + + Event Confirmation Email + ${object.subject} + + + + + % set record = ctx.get('record') + % set company = record and record.company_id or user.company_id + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    + + Event ${object.record_name} + + + ${company.name} +
    +
    + + + + +
    + ${object.body | safe} +
    +
    + + + + + +
    + ${company.name}
    + ${company.phone or ''} +
    + % if company.email: + ${company.email}
    + % endif + % if company.website: + + ${company.website} + + % endif +
    +
    + Powered by Odoo. +
    + + + ]]>
    +
    + +
    +
    diff --git a/event_management_mail/models/__init__.py b/event_management_mail/models/__init__.py new file mode 100644 index 000000000..e6aa2471f --- /dev/null +++ b/event_management_mail/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import event_mail diff --git a/event_management_mail/models/event_mail.py b/event_management_mail/models/event_mail.py new file mode 100644 index 000000000..f0fbe6a35 --- /dev/null +++ b/event_management_mail/models/event_mail.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from odoo import models, fields, api, _ + + +class EventManagementMail(models.Model): + _inherit = 'event.management' + + sent = fields.Boolean(string="Sent", copy=False, help="It indicates that the mail has been sent.") + + @api.multi + def send_confirmation_mail(self): + """ Open a window to compose an email, with the event mail template + message loaded by default + """ + self.ensure_one() + template = self.env.ref('event_management_mail.email_template_event', False) + compose_form = self.env.ref('mail.email_compose_message_wizard_form', False) + ctx = dict( + default_model='event.management', + default_res_id=self.id, + default_use_template=bool(template), + default_template_id=template and template.id or False, + default_composition_mode='comment', + mark_invoice_as_sent=True, + custom_layout="event_management_mail.mail_template_event_confirmation" + ) + return { + 'name': _('Compose Email'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form.id, 'form')], + 'view_id': compose_form.id, + 'target': 'new', + 'context': ctx, + } + + @api.model + def message_get_reply_to(self, res_ids, default=None): + event = self.sudo().browse(res_ids) + reply_to = event.create_uid.email + event.write({'sent': True}) + return {res_ids[0]: reply_to} diff --git a/event_management_mail/static/description/banner.jpg b/event_management_mail/static/description/banner.jpg new file mode 100644 index 000000000..9c85bb0d0 Binary files /dev/null and b/event_management_mail/static/description/banner.jpg differ diff --git a/event_management_mail/static/description/cybro_logo.png b/event_management_mail/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/event_management_mail/static/description/cybro_logo.png differ diff --git a/event_management_mail/static/description/event_mail_button.png b/event_management_mail/static/description/event_mail_button.png new file mode 100644 index 000000000..f3bd0662f Binary files /dev/null and b/event_management_mail/static/description/event_mail_button.png differ diff --git a/event_management_mail/static/description/event_mail_wizard.png b/event_management_mail/static/description/event_mail_wizard.png new file mode 100644 index 000000000..9816a36d2 Binary files /dev/null and b/event_management_mail/static/description/event_mail_wizard.png differ diff --git a/event_management_mail/static/description/icon.png b/event_management_mail/static/description/icon.png new file mode 100644 index 000000000..362705d06 Binary files /dev/null and b/event_management_mail/static/description/icon.png differ diff --git a/event_management_mail/static/description/index.html b/event_management_mail/static/description/index.html new file mode 100644 index 000000000..70241bf0e --- /dev/null +++ b/event_management_mail/static/description/index.html @@ -0,0 +1,74 @@ +
    +
    +
    +

    Event Mail

    +

    Email Notification for customers at the time of event order confirmation.

    +

    Cybrosys Technologies

    +
    +
    +

    Major Features:

    +
      +
    •    Customize your own templates for mail.
    • +
    •    Default template for order confirmation.
    • +
    •    Send notification email to customer when an event order is confirmed.
    • +
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    Event mail adds the functionality to send email notification to the customer at the time of event order confirmation.

    +
    +
    +
    + +
    +
    +
    +

    Mail Button

    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    Mail Wizard

    +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    diff --git a/event_management_mail/static/src/img/icon.png b/event_management_mail/static/src/img/icon.png new file mode 100644 index 000000000..362705d06 Binary files /dev/null and b/event_management_mail/static/src/img/icon.png differ diff --git a/event_management_mail/views/event_mail.xml b/event_management_mail/views/event_mail.xml new file mode 100644 index 000000000..4c38f0ee4 --- /dev/null +++ b/event_management_mail/views/event_mail.xml @@ -0,0 +1,21 @@ + + + + + event_management_form_view_mail.form + event.management + + +
    +
    + + + + + + +
    + +
    diff --git a/event_management_report/README.rst b/event_management_report/README.rst new file mode 100644 index 000000000..157b24367 --- /dev/null +++ b/event_management_report/README.rst @@ -0,0 +1,26 @@ +=========================== +Event Management Report v10 +=========================== + +Event Management report is a supporting module of Event_management module. +The module helps the user to generate reports of Events. +The user can generate filtered reports and export it to XLS and PDF format. + +Features +======== +* Filtration based on Event type. +* Filtration based on Event state. +* Both PDF and XLS report. + +Contributors +============ + +* Avinash Nk + + +Maintainer +========== + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com diff --git a/event_management_report/__init__.py b/event_management_report/__init__.py new file mode 100644 index 000000000..0a866707d --- /dev/null +++ b/event_management_report/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import models +from . import report diff --git a/event_management_report/__manifest__.py b/event_management_report/__manifest__.py new file mode 100644 index 000000000..ab8ef1ad1 --- /dev/null +++ b/event_management_report/__manifest__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +{ + 'name': 'Event Management Report', + 'version': '10.0.1.0.0', + 'summary': """Generates XLS and PDF Reports of Events in Event Management Module""", + 'description': """Generates XLS and PDF Reports of Events in Event Management Module""", + "category": "Tools", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['event_management', 'report_xlsx'], + 'data': ['views/event_report_wizard.xml', + 'report/event_report_pdf.xml', + 'report/event_reports.xml', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'application': False, +} diff --git a/event_management_report/models/__init__.py b/event_management_report/models/__init__.py new file mode 100644 index 000000000..3dcb3a098 --- /dev/null +++ b/event_management_report/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import event_report_wizard diff --git a/event_management_report/models/event_report_wizard.py b/event_management_report/models/event_report_wizard.py new file mode 100644 index 000000000..9f1fb27d2 --- /dev/null +++ b/event_management_report/models/event_report_wizard.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from odoo import models, fields, api + + +class EventManagement(models.TransientModel): + _name = 'event.management.report' + + event_type = fields.Many2many('event.management.type', 'event_type_rel', 'report_id', 'type_id', string="Type", + required=True) + event_state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('invoice', 'Invoiced'), + ('close', 'Close'), ('cancel', 'Canceled')], string="State") + + @api.multi + def pdf_report(self): + type_select = self.event_type.ids + state_select = self.event_state + wizard_data = {"type_select": type_select, "state_select": state_select} + return self.env['report'].get_action(self, 'event_management_report.event_report_template', data=wizard_data) + + @api.multi + def xls_report(self): + type_select = self.event_type.ids + state_select = self.event_state + wizard_data = {"type_select": type_select, "state_select": state_select} + return {'type': 'ir.actions.report.xml', + 'report_name': 'event_management_report.event_report.xlsx', + 'report_type': 'xlsx', + 'datas': wizard_data, + 'name': 'Event Report'} diff --git a/event_management_report/report/__init__.py b/event_management_report/report/__init__.py new file mode 100644 index 000000000..7423bf3bf --- /dev/null +++ b/event_management_report/report/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from . import event_report_parser +from . import event_report_xlsx diff --git a/event_management_report/report/event_report_parser.py b/event_management_report/report/event_report_parser.py new file mode 100644 index 000000000..ff44d0cf9 --- /dev/null +++ b/event_management_report/report/event_report_parser.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from odoo import models, api + + +class EventReportParser(models.AbstractModel): + _name = 'report.event_management_report.event_report_template' + + @api.model + def render_html(self, docids, data): + filtered_events = self.filtered_records(data) + docargs = { + 'docs': filtered_events, + 'model': self, + 'data': data, + } + return self.env['report'].render('event_management_report.event_report_template', docargs) + + @api.multi + def filtered_records(self, data): + total_events = self.env['event.management'] + type_select = data['type_select'] + state_select = data['state_select'] + domain = [('type_of_event', 'in', type_select)] + if state_select: + domain.append(('state', '=', state_select)) + filtered_events = total_events.search(domain) + return filtered_events diff --git a/event_management_report/report/event_report_pdf.xml b/event_management_report/report/event_report_pdf.xml new file mode 100644 index 000000000..4e9dfba86 --- /dev/null +++ b/event_management_report/report/event_report_pdf.xml @@ -0,0 +1,67 @@ + + + + + + diff --git a/event_management_report/report/event_report_xlsx.py b/event_management_report/report/event_report_xlsx.py new file mode 100644 index 000000000..8e7022581 --- /dev/null +++ b/event_management_report/report/event_report_xlsx.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Avinash Nk() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +from odoo.addons.report_xlsx.report.report_xlsx import ReportXlsx + + +class EventReportXlsx(ReportXlsx): + def generate_xlsx_report(self, workbook, data, obj): + parser_obj = self.env['report.event_management_report.event_report_template'] + filtered_records = parser_obj.filtered_records(data) + sheet = workbook.add_worksheet() + format1 = workbook.add_format({'font_size': 16, 'align': 'center', 'bg_color': '#D3D3D3', 'bold': True}) + format1.set_font_color('#000080') + format2 = workbook.add_format({'font_size': 10, 'bold': True}) + format3 = workbook.add_format({'font_size': 10}) + format1.set_align('center') + format2.set_align('center') + sheet.merge_range('A01:B01', "Name", format2) + sheet.merge_range('C01:D01', "Type", format2) + sheet.merge_range('E01:F01', "Customer", format2) + sheet.merge_range('G01:H01', "Date", format2) + sheet.merge_range('I01:J01', "Start Date", format2) + sheet.merge_range('K01:L01', "End Date", format2) + sheet.merge_range('M01:N01', "State", format2) + row_number = 1 + col_number = 0 + for records in filtered_records: + sheet.merge_range(row_number, col_number, row_number, col_number+1, records.name, format3) + sheet.merge_range(row_number, col_number+2, row_number, col_number+3, records.type_of_event.name, format3) + sheet.merge_range(row_number, col_number+4, row_number, col_number+5, records.partner_id.name, format3) + sheet.merge_range(row_number, col_number+6, row_number, col_number+7, records.date, format3) + sheet.merge_range(row_number, col_number+8, row_number, col_number+9, records.start_date, format3) + sheet.merge_range(row_number, col_number+10, row_number, col_number+11, records.end_date, format3) + sheet.merge_range(row_number, col_number+12, row_number, col_number+13, records.state, format3) + row_number += 1 + + +EventReportXlsx('report.event_management_report.event_report.xlsx', 'event.management') diff --git a/event_management_report/report/event_reports.xml b/event_management_report/report/event_reports.xml new file mode 100644 index 000000000..8b1dc737c --- /dev/null +++ b/event_management_report/report/event_reports.xml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/event_management_report/static/description/banner.jpg b/event_management_report/static/description/banner.jpg new file mode 100644 index 000000000..2d627fa08 Binary files /dev/null and b/event_management_report/static/description/banner.jpg differ diff --git a/event_management_report/static/description/cybro_logo.png b/event_management_report/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/event_management_report/static/description/cybro_logo.png differ diff --git a/event_management_report/static/description/event_report_pdf.png b/event_management_report/static/description/event_report_pdf.png new file mode 100644 index 000000000..6bc4aa023 Binary files /dev/null and b/event_management_report/static/description/event_report_pdf.png differ diff --git a/event_management_report/static/description/event_report_wizard.png b/event_management_report/static/description/event_report_wizard.png new file mode 100644 index 000000000..2e2ca492f Binary files /dev/null and b/event_management_report/static/description/event_report_wizard.png differ diff --git a/event_management_report/static/description/event_report_xls.png b/event_management_report/static/description/event_report_xls.png new file mode 100644 index 000000000..fc5a45c5b Binary files /dev/null and b/event_management_report/static/description/event_report_xls.png differ diff --git a/event_management_report/static/description/icon.png b/event_management_report/static/description/icon.png new file mode 100644 index 000000000..21967b20e Binary files /dev/null and b/event_management_report/static/description/icon.png differ diff --git a/event_management_report/static/description/index.html b/event_management_report/static/description/index.html new file mode 100644 index 000000000..dfc89ad34 --- /dev/null +++ b/event_management_report/static/description/index.html @@ -0,0 +1,85 @@ +
    +
    +
    +

    Event Management Report

    +

    PDF and XLS Report of Events.

    +

    Cybrosys Technologies

    +
    +
    +

    Major Features:

    +
      +
    •    Filtration based on Event type.
    • +
    •    Filtration based on Event state.
    • +
    •    Both PDF and XLS report.
    • +
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    Event Management report is a supporting module of Event_management module. The module helps the user to generate reports of Events. The user can generate filtered reports and export it to XLS and PDF format.

    +
    +
    +
    + +
    +
    +
    +

    Report Wizard

    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    PDF Report

    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    XLS Report

    +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    diff --git a/event_management_report/views/event_report_wizard.xml b/event_management_report/views/event_report_wizard.xml new file mode 100644 index 000000000..0383f8cf1 --- /dev/null +++ b/event_management_report/views/event_report_wizard.xml @@ -0,0 +1,44 @@ + + + + + + event_report_form_view.form + event.management.report + +
    + + + + + + + + + + +
    +
    +
    +
    +
    + + + Event Report + event.management.report + ir.actions.act_window + form + form + new + + + + + +
    +
    \ No newline at end of file diff --git a/export_stockinfo_xls/README.rst b/export_stockinfo_xls/README.rst new file mode 100644 index 000000000..42206e376 --- /dev/null +++ b/export_stockinfo_xls/README.rst @@ -0,0 +1,17 @@ +================================= +Export Product Stock in Excel v10 +================================= +This module helps you to take current stock report for all products in each warehouse. + +Installation +============ +Just select it from available modules to install it, +there is no need to extra installations. + +Credits +======= +Developer: Jesni Banu @ cybrosys, jesni@cybrosys.in +Developer: Nilmar Shereef @ cybrosys, shereef@cybrosys.in + + + diff --git a/export_stockinfo_xls/__init__.py b/export_stockinfo_xls/__init__.py new file mode 100644 index 000000000..a1de6567d --- /dev/null +++ b/export_stockinfo_xls/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import report +import models + diff --git a/export_stockinfo_xls/__manifest__.py b/export_stockinfo_xls/__manifest__.py new file mode 100644 index 000000000..dfb82e018 --- /dev/null +++ b/export_stockinfo_xls/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Export Product Stock in Excel', + 'version': '10.0.2.0.0', + 'summary': "Current Stock Report for all Products in each Warehouse", + 'category': 'Warehouse', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': 'http://www.cybrosys.com', + 'depends': [ + 'base', + 'stock', + 'sale', + 'purchase', + 'report_xlsx' + ], + 'data': [ + 'views/wizard_view.xml', + ], + 'images': ['static/description/banner.jpg'], + 'license': "AGPL-3", + 'installable': True, + 'auto_install': False, +} diff --git a/export_stockinfo_xls/doc/changelog.rst b/export_stockinfo_xls/doc/changelog.rst new file mode 100644 index 000000000..c19d031ca --- /dev/null +++ b/export_stockinfo_xls/doc/changelog.rst @@ -0,0 +1,12 @@ +Changelog +========= +`10.0.2.0.0` +------------ +- Total sold & Total purchased counts corrected. +- Added name for sheet. + + +`9.0.2.0.0` +----------- +- Total sold & Total purchased counts corrected. +- Added name for sheet. diff --git a/export_stockinfo_xls/models/__init__.py b/export_stockinfo_xls/models/__init__.py new file mode 100644 index 000000000..6da829ae1 --- /dev/null +++ b/export_stockinfo_xls/models/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import res_partner +import wizard + diff --git a/export_stockinfo_xls/models/res_partner.py b/export_stockinfo_xls/models/res_partner.py new file mode 100644 index 000000000..bf50be517 --- /dev/null +++ b/export_stockinfo_xls/models/res_partner.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields + + +class Partner(models.Model): + _inherit = 'res.partner' + + supplier_id = fields.Many2many('wizard.stock.history', 'supp_wiz_rel', 'wiz', 'supp', invisible=True) + + +class Category(models.Model): + _inherit = 'product.category' + + obj = fields.Many2many('wizard.stock.history', 'categ_wiz_rel', 'wiz', 'categ', invisible=True) + + +class Warehouse(models.Model): + _inherit = 'stock.warehouse' + + obj = fields.Many2many('wizard.stock.history', 'wh_wiz_rel', 'wiz', 'wh', invisible=True) + + + + + diff --git a/export_stockinfo_xls/models/wizard.py b/export_stockinfo_xls/models/wizard.py new file mode 100644 index 000000000..04c2dfc6f --- /dev/null +++ b/export_stockinfo_xls/models/wizard.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api + + +class StockReport(models.TransientModel): + _name = "wizard.stock.history" + _description = "Current Stock History" + + warehouse = fields.Many2many('stock.warehouse', 'wh_wiz_rel', 'wh', 'wiz', string='Warehouse', required=True) + category = fields.Many2many('product.category', 'categ_wiz_rel', 'categ', 'wiz', string='Warehouse') + + @api.multi + def export_xls(self): + context = self._context + datas = {'ids': context.get('active_ids', [])} + datas['model'] = 'product.product' + datas['form'] = self.read()[0] + for field in datas['form'].keys(): + if isinstance(datas['form'][field], tuple): + datas['form'][field] = datas['form'][field][0] + if context.get('xls_export'): + return {'type': 'ir.actions.report.xml', + 'report_name': 'export_stockinfo_xls.stock_report_xls.xlsx', + 'datas': datas, + 'name': 'Current Stock' + } diff --git a/export_stockinfo_xls/report/__init__.py b/export_stockinfo_xls/report/__init__.py new file mode 100644 index 000000000..5e629d6ae --- /dev/null +++ b/export_stockinfo_xls/report/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import current_stock_xls + + diff --git a/export_stockinfo_xls/report/current_stock_xls.py b/export_stockinfo_xls/report/current_stock_xls.py new file mode 100644 index 000000000..4e4e6850a --- /dev/null +++ b/export_stockinfo_xls/report/current_stock_xls.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Jesni Banu() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import datetime +from odoo.addons.report_xlsx.report.report_xlsx import ReportXlsx + + +class StockReportXls(ReportXlsx): + + def get_warehouse(self, data): + if data.get('form', False) and data['form'].get('warehouse', False): + l1 = [] + l2 = [] + obj = self.env['stock.warehouse'].search([('id', 'in', data['form']['warehouse'])]) + for j in obj: + l1.append(j.name) + l2.append(j.id) + return l1, l2 + + def get_category(self, data): + if data.get('form', False) and data['form'].get('category', False): + l2 = [] + obj = self.env['product.category'].search([('id', 'in', data['form']['category'])]) + for j in obj: + l2.append(j.id) + return l2 + return '' + + def get_lines(self, data, warehouse): + lines = [] + categ = self.get_category(data) + if categ: + stock_history = self.env['product.product'].search([('categ_id', 'in', categ)]) + else: + stock_history = self.env['product.product'].search([]) + for obj in stock_history: + sale_value = 0 + purchase_value = 0 + product = self.env['product.product'].browse(obj.id) + sale_obj = self.env['sale.order.line'].search([('order_id.state', 'in', ('sale', 'done')), + ('product_id', '=', product.id), + ('order_id.warehouse_id', '=', warehouse)]) + for i in sale_obj: + sale_value = sale_value + i.product_uom_qty + purchase_obj = self.env['purchase.order.line'].search([('order_id.state', 'in', ('purchase', 'done')), + ('product_id', '=', product.id), + ('order_id.picking_type_id', '=', warehouse)]) + for i in purchase_obj: + purchase_value = purchase_value + i.product_qty + available_qty = product.with_context({'warehouse': warehouse}).virtual_available + \ + product.with_context({'warehouse': warehouse}).outgoing_qty - \ + product.with_context({'warehouse': warehouse}).incoming_qty + value = available_qty * product.standard_price + vals = { + 'sku': product.default_code, + 'name': product.name, + 'category': product.categ_id.name, + 'cost_price': product.standard_price, + 'available': available_qty, + 'virtual': product.with_context({'warehouse': warehouse}).virtual_available, + 'incoming': product.with_context({'warehouse': warehouse}).incoming_qty, + 'outgoing': product.with_context({'warehouse': warehouse}).outgoing_qty, + 'net_on_hand': product.with_context({'warehouse': warehouse}).qty_available, + 'total_value': value, + 'sale_value': sale_value, + 'purchase_value': purchase_value, + } + lines.append(vals) + return lines + + def generate_xlsx_report(self, workbook, data, lines): + get_warehouse = self.get_warehouse(data) + count = len(get_warehouse[0]) * 11 + 6 + sheet = workbook.add_worksheet('Stock Info') + format1 = workbook.add_format({'font_size': 14, 'bottom': True, 'right': True, 'left': True, 'top': True, 'align': 'vcenter', 'bold': True}) + format11 = workbook.add_format({'font_size': 12, 'align': 'center', 'right': True, 'left': True, 'bottom': True, 'top': True, 'bold': True}) + format21 = workbook.add_format({'font_size': 10, 'align': 'center', 'right': True, 'left': True,'bottom': True, 'top': True, 'bold': True}) + format3 = workbook.add_format({'bottom': True, 'top': True, 'font_size': 12}) + font_size_8 = workbook.add_format({'bottom': True, 'top': True, 'right': True, 'left': True, 'font_size': 8}) + red_mark = workbook.add_format({'bottom': True, 'top': True, 'right': True, 'left': True, 'font_size': 8, + 'bg_color': 'red'}) + justify = workbook.add_format({'bottom': True, 'top': True, 'right': True, 'left': True, 'font_size': 12}) + format3.set_align('center') + font_size_8.set_align('center') + justify.set_align('justify') + format1.set_align('center') + red_mark.set_align('center') + sheet.merge_range('A3:G3', 'Report Date: ' + str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M %p")), format1) + sheet.merge_range(2, 7, 2, count, 'Warehouses', format1) + sheet.merge_range('A4:G4', 'Product Information', format11) + w_col_no = 6 + w_col_no1 = 7 + for i in get_warehouse[0]: + w_col_no = w_col_no + 11 + sheet.merge_range(3, w_col_no1, 3, w_col_no, i, format11) + w_col_no1 = w_col_no1 + 11 + sheet.write(4, 0, 'SKU', format21) + sheet.merge_range(4, 1, 4, 3, 'Name', format21) + sheet.merge_range(4, 4, 4, 5, 'Category', format21) + sheet.write(4, 6, 'Cost Price', format21) + p_col_no1 = 7 + for i in get_warehouse[0]: + sheet.write(4, p_col_no1, 'Available', format21) + sheet.write(4, p_col_no1 + 1, 'Virtual', format21) + sheet.write(4, p_col_no1 + 2, 'Incoming', format21) + sheet.write(4, p_col_no1 + 3, 'Outgoing', format21) + sheet.merge_range(4, p_col_no1 + 4, 4, p_col_no1 + 5, 'Net On Hand', format21) + sheet.merge_range(4, p_col_no1 + 6, 4, p_col_no1 + 7, 'Total Sold', format21) + sheet.merge_range(4, p_col_no1 + 8, 4, p_col_no1 + 9, 'Total Purchased', format21) + sheet.write(4, p_col_no1 + 10, 'Valuation', format21) + p_col_no1 = p_col_no1 + 11 + prod_row = 5 + prod_col = 0 + for i in get_warehouse[1]: + get_line = self.get_lines(data, i) + for each in get_line: + sheet.write(prod_row, prod_col, each['sku'], font_size_8) + sheet.merge_range(prod_row, prod_col + 1, prod_row, prod_col + 3, each['name'], font_size_8) + sheet.merge_range(prod_row, prod_col + 4, prod_row, prod_col + 5, each['category'], font_size_8) + sheet.write(prod_row, prod_col + 6, each['cost_price'], font_size_8) + prod_row = prod_row + 1 + break + prod_row = 5 + prod_col = 7 + for i in get_warehouse[1]: + get_line = self.get_lines(data, i) + for each in get_line: + if each['available'] < 0: + sheet.write(prod_row, prod_col, each['available'], red_mark) + else: + sheet.write(prod_row, prod_col, each['available'], font_size_8) + if each['virtual'] < 0: + sheet.write(prod_row, prod_col + 1, each['virtual'], red_mark) + else: + sheet.write(prod_row, prod_col + 1, each['virtual'], font_size_8) + if each['incoming'] < 0: + sheet.write(prod_row, prod_col + 2, each['incoming'], red_mark) + else: + sheet.write(prod_row, prod_col + 2, each['incoming'], font_size_8) + if each['outgoing'] < 0: + sheet.write(prod_row, prod_col + 3, each['outgoing'], red_mark) + else: + sheet.write(prod_row, prod_col + 3, each['outgoing'], font_size_8) + if each['net_on_hand'] < 0: + sheet.merge_range(prod_row, prod_col + 4, prod_row, prod_col + 5, each['net_on_hand'], red_mark) + else: + sheet.merge_range(prod_row, prod_col + 4, prod_row, prod_col + 5, each['net_on_hand'], font_size_8) + if each['sale_value'] < 0: + sheet.merge_range(prod_row, prod_col + 6, prod_row, prod_col + 7, each['sale_value'], red_mark) + else: + sheet.merge_range(prod_row, prod_col + 6, prod_row, prod_col + 7, each['sale_value'], font_size_8) + if each['purchase_value'] < 0: + sheet.merge_range(prod_row, prod_col + 8, prod_row, prod_col + 9, each['purchase_value'], red_mark) + else: + sheet.merge_range(prod_row, prod_col + 8, prod_row, prod_col + 9, each['purchase_value'], font_size_8) + if each['total_value'] < 0: + sheet.write(prod_row, prod_col + 10, each['total_value'], red_mark) + else: + sheet.write(prod_row, prod_col + 10, each['total_value'], font_size_8) + prod_row = prod_row + 1 + prod_row = 5 + prod_col = prod_col + 11 + +StockReportXls('report.export_stockinfo_xls.stock_report_xls.xlsx', 'product.product') diff --git a/export_stockinfo_xls/static/description/banner.jpg b/export_stockinfo_xls/static/description/banner.jpg new file mode 100644 index 000000000..5dfdf2c2b Binary files /dev/null and b/export_stockinfo_xls/static/description/banner.jpg differ diff --git a/export_stockinfo_xls/static/description/cybro_logo.png b/export_stockinfo_xls/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/export_stockinfo_xls/static/description/cybro_logo.png differ diff --git a/export_stockinfo_xls/static/description/icon.png b/export_stockinfo_xls/static/description/icon.png new file mode 100644 index 000000000..a14eba82a Binary files /dev/null and b/export_stockinfo_xls/static/description/icon.png differ diff --git a/export_stockinfo_xls/static/description/image1.png b/export_stockinfo_xls/static/description/image1.png new file mode 100644 index 000000000..21561b631 Binary files /dev/null and b/export_stockinfo_xls/static/description/image1.png differ diff --git a/export_stockinfo_xls/static/description/image2.png b/export_stockinfo_xls/static/description/image2.png new file mode 100644 index 000000000..33ad12b3d Binary files /dev/null and b/export_stockinfo_xls/static/description/image2.png differ diff --git a/export_stockinfo_xls/static/description/image3.png b/export_stockinfo_xls/static/description/image3.png new file mode 100644 index 000000000..2e69296e0 Binary files /dev/null and b/export_stockinfo_xls/static/description/image3.png differ diff --git a/export_stockinfo_xls/static/description/index.html b/export_stockinfo_xls/static/description/index.html new file mode 100644 index 000000000..9076cdc95 --- /dev/null +++ b/export_stockinfo_xls/static/description/index.html @@ -0,0 +1,88 @@ +
    +
    +

    Current Stock XLS

    +

    Current Stock Report for all Products in each Warehouse

    +

    Cybrosys Technologies

    +
    +
    +
    + This module helps to print Current Stock Report for all Products in each Warehouse with XLS. +
    +
    +
    +
    + ☛ Installation : To install this module, you need also the report_xlsx module. +
    +
    +
    +
    +
    + +
    +
    +
    +

    + Go to Inventory -> Reports -> Current stock in Excel. Now a wizard will appear on your screen. + Please enter the warehouses which you want to take the report. You can also select category for products(It is Optional). + Then Click "Export Product with Stock Info" button. Then You will get the corresponding report in XLS. +

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

    + Per warehouse you can get Available Qty, Virtual Qty, Incoming Qty, Outgoing Qty, Net On Hand Qty, + Total Sold & Total Purchased Qty. You can get your stock valuation details too. In below screen-shot you + can see stock details of 2 warehouse exported in single spreadsheet. Negative stock will be highlighted + in "red" cells. +

    +
    +
    +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    + + + diff --git a/export_stockinfo_xls/views/wizard_view.xml b/export_stockinfo_xls/views/wizard_view.xml new file mode 100644 index 000000000..1f71bb463 --- /dev/null +++ b/export_stockinfo_xls/views/wizard_view.xml @@ -0,0 +1,50 @@ + + + + + wizard.stock.history.form + wizard.stock.history + +
    + + + + + + + + + + + + +
    +
    +
    +
    +
    + + Export product stock in Excel + wizard.stock.history + form + form + + new + + + +
    +
    \ No newline at end of file diff --git a/filter_aged_partners/README.rst b/filter_aged_partners/README.rst new file mode 100644 index 000000000..42bd4f6cb --- /dev/null +++ b/filter_aged_partners/README.rst @@ -0,0 +1,39 @@ +Aged Partner Balance with Partner Filter v10 +============================================ + +Aged Partner report with Partner Filter +You can generate aged partner report from wizard with partner filter + +Depends +======= +[account] addon Odoo + +Tech +==== +* [Python] - Models +* [XML] - Odoo views + +Installation +============ +- www.odoo.com/documentation/10.0/setup/install.html +- Install our custom addon + +License +======= +GNU LESSER GENERAL PUBLIC LICENSE, Version 3 (LGPLv3) +(http://www.gnu.org/licenses/agpl.html) + +Bug Tracker +=========== +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Authors +------- +* Sreejith P + +Maintainer +---------- + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit https://www.cybrosys.com. diff --git a/filter_aged_partners/__init__.py b/filter_aged_partners/__init__.py new file mode 100644 index 000000000..a0fdc10fe --- /dev/null +++ b/filter_aged_partners/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import models diff --git a/filter_aged_partners/__manifest__.py b/filter_aged_partners/__manifest__.py new file mode 100644 index 000000000..ee11e2c92 --- /dev/null +++ b/filter_aged_partners/__manifest__.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +################################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Sreejith P() +# +# This program is free software: you can modify +# it under the terms of the GNU Affero General Public License (AGPL) as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# 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 for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +################################################################################### +{ + 'name': 'Aged Partner Balance with Partner Filter', + 'version': '10.0.1.0.0', + 'summary': """Partner Wise on Aged Partner Balance""", + 'category': 'Accounting', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'depends': ['base', 'account'], + 'data': ['views/filter_aged_partners.xml'], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/filter_aged_partners/models/__init__.py b/filter_aged_partners/models/__init__.py new file mode 100644 index 000000000..3701a2f07 --- /dev/null +++ b/filter_aged_partners/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import filter_aged_partners diff --git a/filter_aged_partners/models/filter_aged_partners.py b/filter_aged_partners/models/filter_aged_partners.py new file mode 100644 index 000000000..13b7785e7 --- /dev/null +++ b/filter_aged_partners/models/filter_aged_partners.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +import time +from datetime import datetime +from dateutil.relativedelta import relativedelta + +from odoo import fields, models, _ +from odoo.exceptions import UserError +from odoo.tools import float_is_zero + + +class FilterAgedPartner(models.TransientModel): + _inherit ='account.aged.trial.balance' + + customer = fields.Many2many('res.partner', 'name', string='Customers') + + def _print_report(self, data): + res = {} + data = self.pre_print_report(data) + data['form'].update(self.read(['period_length'])[0]) + period_length = data['form']['period_length'] + if period_length <= 0: + raise UserError(_('You must set a period length greater than 0.')) + if not data['form']['date_from']: + raise UserError(_('You must set a start date.')) + + start = datetime.strptime(data['form']['date_from'], "%Y-%m-%d") + + for i in range(5)[::-1]: + stop = start - relativedelta(days=period_length - 1) + res[str(i)] = { + 'name': (i != 0 and (str((5 - (i + 1)) * period_length) + '-' + str((5 - i) * period_length)) or ( + '+' + str(4 * period_length))), + 'stop': start.strftime('%Y-%m-%d'), + 'start': (i != 0 and stop.strftime('%Y-%m-%d') or False), + } + start = stop - relativedelta(days=1) + data['form'].update(res) + data['form'].update({'customer': self.customer.ids}) + return self.env['report'].with_context(landscape=True).get_action(self, 'account.report_agedpartnerbalance', + data=data) + + +class FilterAgedCustomer(models .AbstractModel): + _inherit = 'report.account.report_agedpartnerbalance' + + def _get_partner_move_lines(self, account_type, date_from, target_move, period_length,customer): + periods = {} + start = datetime.strptime(date_from, "%Y-%m-%d") + for i in range(5)[::-1]: + stop = start - relativedelta(days=period_length) + periods[str(i)] = { + 'name': (i != 0 and (str((5-(i+1)) * period_length) + '-' + str((5-i) * period_length)) or ('+'+str(4 * period_length))), + 'stop': start.strftime('%Y-%m-%d'), + 'start': (i != 0 and stop.strftime('%Y-%m-%d') or False), + } + start = stop - relativedelta(days=1) + + res = [] + total = [] + cr = self.env.cr + user_company = self.env.user.company_id.id + move_state = ['draft', 'posted'] + if target_move == 'posted': + move_state = ['posted'] + arg_list = (tuple(move_state), tuple(account_type)) + reconciliation_clause = '(l.reconciled IS FALSE)' + cr.execute('SELECT debit_move_id, credit_move_id FROM account_partial_reconcile where create_date > %s', (date_from,)) + reconciled_after_date = [] + for row in cr.fetchall(): + reconciled_after_date += [row[0], row[1]] + if reconciled_after_date: + reconciliation_clause = '(l.reconciled IS FALSE OR l.id IN %s)' + arg_list += (tuple(reconciled_after_date),) + arg_list += (date_from, user_company) + query = ''' + SELECT DISTINCT l.partner_id, UPPER(res_partner.name) + FROM account_move_line AS l left join res_partner on l.partner_id = res_partner.id, account_account, account_move am + WHERE (l.account_id = account_account.id) + AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND ''' + reconciliation_clause + ''' + AND (l.date <= %s) + AND l.company_id = %s + ORDER BY UPPER(res_partner.name)''' + cr.execute(query, arg_list) + partners = cr.dictfetchall() + if customer: + for ptnr in partners[:]: + if ptnr['partner_id'] not in customer: + partners.remove(ptnr) + + for i in range(7): + total.append(0) + + # Build a string like (1,2,3) for easy use in SQL query + partner_ids = [partner['partner_id'] for partner in partners if partner['partner_id']] + lines = dict((partner['partner_id'] or False, []) for partner in partners) + if not partner_ids: + return [], [], [] + + # This dictionary will store the not due amount of all partners + undue_amounts = {} + query = '''SELECT l.id + FROM account_move_line AS l, account_account, account_move am + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND (COALESCE(l.date_maturity,l.date) > %s)\ + AND ((l.partner_id IN %s) OR (l.partner_id IS NULL)) + AND (l.date <= %s) + AND l.company_id = %s''' + cr.execute(query, (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from, user_company)) + aml_ids = cr.fetchall() + aml_ids = aml_ids and [x[0] for x in aml_ids] or [] + for line in self.env['account.move.line'].browse(aml_ids): + partner_id = line.partner_id.id or False + if partner_id not in undue_amounts: + undue_amounts[partner_id] = 0.0 + line_amount = line.balance + if line.balance == 0: + continue + for partial_line in line.matched_debit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount += partial_line.amount + for partial_line in line.matched_credit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount -= partial_line.amount + if not self.env.user.company_id.currency_id.is_zero(line_amount): + undue_amounts[partner_id] += line_amount + lines[partner_id].append({ + 'line': line, + 'amount': line_amount, + 'period': 6, + }) + + # Use one query per period and store results in history (a list variable) + # Each history will contain: history[1] = {'': } + history = [] + for i in range(5): + args_list = (tuple(move_state), tuple(account_type), tuple(partner_ids),) + dates_query = '(COALESCE(l.date_maturity,l.date)' + + if periods[str(i)]['start'] and periods[str(i)]['stop']: + dates_query += ' BETWEEN %s AND %s)' + args_list += (periods[str(i)]['start'], periods[str(i)]['stop']) + elif periods[str(i)]['start']: + dates_query += ' >= %s)' + args_list += (periods[str(i)]['start'],) + else: + dates_query += ' <= %s)' + args_list += (periods[str(i)]['stop'],) + args_list += (date_from, user_company) + + query = '''SELECT l.id + FROM account_move_line AS l, account_account, account_move am + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND ((l.partner_id IN %s) OR (l.partner_id IS NULL)) + AND ''' + dates_query + ''' + AND (l.date <= %s) + AND l.company_id = %s''' + cr.execute(query, args_list) + partners_amount = {} + aml_ids = cr.fetchall() + aml_ids = aml_ids and [x[0] for x in aml_ids] or [] + for line in self.env['account.move.line'].browse(aml_ids): + partner_id = line.partner_id.id or False + if partner_id not in partners_amount: + partners_amount[partner_id] = 0.0 + line_amount = line.balance + if line.balance == 0: + continue + for partial_line in line.matched_debit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount += partial_line.amount + for partial_line in line.matched_credit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount -= partial_line.amount + + if not self.env.user.company_id.currency_id.is_zero(line_amount): + partners_amount[partner_id] += line_amount + lines[partner_id].append({ + 'line': line, + 'amount': line_amount, + 'period': i + 1, + }) + history.append(partners_amount) + + for partner in partners: + if partner['partner_id'] is None: + partner['partner_id'] = False + at_least_one_amount = False + values = {} + undue_amt = 0.0 + if partner['partner_id'] in undue_amounts: # Making sure this partner actually was found by the query + undue_amt = undue_amounts[partner['partner_id']] + + total[6] = total[6] + undue_amt + values['direction'] = undue_amt + if not float_is_zero(values['direction'], precision_rounding=self.env.user.company_id.currency_id.rounding): + at_least_one_amount = True + + for i in range(5): + during = False + if partner['partner_id'] in history[i]: + during = [history[i][partner['partner_id']]] + # Adding counter + total[(i)] = total[(i)] + (during and during[0] or 0) + values[str(i)] = during and during[0] or 0.0 + if not float_is_zero(values[str(i)], precision_rounding=self.env.user.company_id.currency_id.rounding): + at_least_one_amount = True + values['total'] = sum([values['direction']] + [values[str(i)] for i in range(5)]) + ## Add for total + total[(i + 1)] += values['total'] + values['partner_id'] = partner['partner_id'] + if partner['partner_id']: + browsed_partner = self.env['res.partner'].browse(partner['partner_id']) + values['name'] = browsed_partner.name and len(browsed_partner.name) >= 45 and browsed_partner.name[0:40] + '...' or browsed_partner.name + values['trust'] = browsed_partner.trust + else: + values['name'] = _('Unknown Partner') + values['trust'] = False + + if at_least_one_amount: + res.append(values) + + return res, total, lines + + def render_html(self, docids, data=None): + if not data.get('form') or not self.env.context.get('active_model') or not self.env.context.get('active_id'): + raise UserError(_("Form content is missing, this report cannot be printed.")) + + total = [] + model = self.env.context.get('active_model') + docs = self.env[model].browse(self.env.context.get('active_id')) + + target_move = data['form'].get('target_move', 'all') + date_from = data['form'].get('date_from', time.strftime('%Y-%m-%d')) + + if data['form']['result_selection'] == 'customer': + account_type = ['receivable'] + elif data['form']['result_selection'] == 'supplier': + account_type = ['payable'] + else: + account_type = ['payable', 'receivable'] + + movelines, total, dummy = self._get_partner_move_lines(account_type, date_from, target_move, + data['form']['period_length'], data['form']['customer']) + + + + docargs = { + 'doc_ids': self.ids, + 'doc_model': model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'get_partner_lines': movelines, + 'get_direction': total, + } + return self.env['report'].render('account.report_agedpartnerbalance', docargs) diff --git a/filter_aged_partners/static/description/aged_partnerwizard.png b/filter_aged_partners/static/description/aged_partnerwizard.png new file mode 100644 index 000000000..1e29880c5 Binary files /dev/null and b/filter_aged_partners/static/description/aged_partnerwizard.png differ diff --git a/filter_aged_partners/static/description/banner.jpg b/filter_aged_partners/static/description/banner.jpg new file mode 100644 index 000000000..0db23975e Binary files /dev/null and b/filter_aged_partners/static/description/banner.jpg differ diff --git a/filter_aged_partners/static/description/cybro_logo.png b/filter_aged_partners/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/filter_aged_partners/static/description/cybro_logo.png differ diff --git a/filter_aged_partners/static/description/icon.png b/filter_aged_partners/static/description/icon.png new file mode 100644 index 000000000..a4633bb75 Binary files /dev/null and b/filter_aged_partners/static/description/icon.png differ diff --git a/filter_aged_partners/static/description/index.html b/filter_aged_partners/static/description/index.html new file mode 100644 index 000000000..c6a24f93b --- /dev/null +++ b/filter_aged_partners/static/description/index.html @@ -0,0 +1,78 @@ +
    +
    +

    Aged Partner report with Partner Filter

    +

    +

    Cybrosys Technologies

    +
    +
    +
    + Use Partner Filtration on Aged Partner Balance.
    +
    +
    +
    +
    +
    +
    +

    Overview

    +

    + This Cybrosys's module allows you to easily check Partners Aging, Currently we can't take individual aging report. By using this modules we can take aging report of one or more customers. +

    +
    +
    +
    +
    +
    +
    You can generate aged partner report from wizard with partner filter
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    This will open partner ledger report wizard with the selected partner.
    +
    You can add or remove partner from wizard in case of fault selection
    +
    +
    +
    +
    + +
    +
    +
    + + +
    +
    +
    + +
    +

    Need Any Help?

    + +
    diff --git a/filter_aged_partners/static/description/partnerfilter.png b/filter_aged_partners/static/description/partnerfilter.png new file mode 100644 index 000000000..5810f417a Binary files /dev/null and b/filter_aged_partners/static/description/partnerfilter.png differ diff --git a/filter_aged_partners/static/description/pdfreport.png b/filter_aged_partners/static/description/pdfreport.png new file mode 100644 index 000000000..47e007809 Binary files /dev/null and b/filter_aged_partners/static/description/pdfreport.png differ diff --git a/filter_aged_partners/views/filter_aged_partners.xml b/filter_aged_partners/views/filter_aged_partners.xml new file mode 100644 index 000000000..63e66f4a7 --- /dev/null +++ b/filter_aged_partners/views/filter_aged_partners.xml @@ -0,0 +1,15 @@ + + + + + partner.filter.form + account.aged.trial.balance + + + + + + + + + diff --git a/fleet_car_workshop/README.rst b/fleet_car_workshop/README.rst new file mode 100644 index 000000000..a72f187e2 --- /dev/null +++ b/fleet_car_workshop/README.rst @@ -0,0 +1,18 @@ +Car Workshop v10 +================ +Car Workshop Management helps to manage automobile workshop with +great ease. Keep track of everything, like vehicle owner details, +Works assigned, Bill details of service provided, etc. + +Features +======== +* User Friendly Interface. +* Effective Time management. +* Separate Journal Configuration. +* Integrated with Accounting. +* High Scalability. + + .. note:: + + # Its Working Domain Based on Project App. + # Mapped Fleet for Easy Method. diff --git a/fleet_car_workshop/__init__.py b/fleet_car_workshop/__init__.py new file mode 100644 index 000000000..9e0710ae3 --- /dev/null +++ b/fleet_car_workshop/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models + diff --git a/fleet_car_workshop/__manifest__.py b/fleet_car_workshop/__manifest__.py new file mode 100644 index 000000000..de55dc7ec --- /dev/null +++ b/fleet_car_workshop/__manifest__.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Car Workshop', + 'version': '10.0.1.0.0', + 'summary': 'Complete Vehicle Workshop Operations & Reports', + 'description': 'Vehicle workshop operations & Its reports', + 'category': 'Industries', + 'author': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'company': 'Cybrosys Techno Solutions', + 'depends': [ + 'base', + 'fleet', + 'account_accountant', + ], + 'data': [ + 'views/worksheet_views.xml', + 'views/car_dashboard.xml', + 'views/timesheet_view.xml', + 'views/worksheet_stages.xml', + 'views/vehicle.xml', + 'views/report.xml', + 'views/config_setting.xml', + 'views/workshop_data.xml', + 'security/workshop_security.xml', + 'security/ir.model.access.csv', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': True, +} diff --git a/fleet_car_workshop/__manifest__.py~ b/fleet_car_workshop/__manifest__.py~ new file mode 100644 index 000000000..de55dc7ec --- /dev/null +++ b/fleet_car_workshop/__manifest__.py~ @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Car Workshop', + 'version': '10.0.1.0.0', + 'summary': 'Complete Vehicle Workshop Operations & Reports', + 'description': 'Vehicle workshop operations & Its reports', + 'category': 'Industries', + 'author': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'company': 'Cybrosys Techno Solutions', + 'depends': [ + 'base', + 'fleet', + 'account_accountant', + ], + 'data': [ + 'views/worksheet_views.xml', + 'views/car_dashboard.xml', + 'views/timesheet_view.xml', + 'views/worksheet_stages.xml', + 'views/vehicle.xml', + 'views/report.xml', + 'views/config_setting.xml', + 'views/workshop_data.xml', + 'security/workshop_security.xml', + 'security/ir.model.access.csv', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': True, +} diff --git a/fleet_car_workshop/models/__init__.py b/fleet_car_workshop/models/__init__.py new file mode 100644 index 000000000..b020ac10b --- /dev/null +++ b/fleet_car_workshop/models/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import car_workshop +import timesheet +import dashboard +import config diff --git a/fleet_car_workshop/models/car_workshop.py b/fleet_car_workshop/models/car_workshop.py new file mode 100644 index 000000000..2a3c99e14 --- /dev/null +++ b/fleet_car_workshop/models/car_workshop.py @@ -0,0 +1,374 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from datetime import date +from dateutil.relativedelta import relativedelta +from odoo.exceptions import UserError +from odoo import models, api, fields, _ + + +class CarWorkshop(models.Model): + _name = 'car.workshop' + _description = "Car Workshop" + _inherit = ['mail.thread'] + + def _get_default_partner(self): + if 'default_vehicle_id' in self.env.context: + default_vehicle_id = self.env['car.car'].browse(self.env.context['default_vehicle_id']) + return default_vehicle_id.exists().partner_id + + name = fields.Char(string='Title', track_visibility='onchange', required=True) + vehicle_id = fields.Many2one('car.car', string='Vehicle', + default=lambda self: self.env.context.get('default_vehicle_id'), track_visibility='onchange') + user_id = fields.Many2one('res.users', string='Assigned to', select=True, default=lambda self: self.env.uid) + active = fields.Boolean(string='Active', default=True) + partner_id = fields.Many2one('res.partner', string='Customer',default=_get_default_partner) + priority = fields.Selection([('0', 'Normal'), ('1', 'High')], 'Priority', select=True, default='0') + description = fields.Html(string='Description') + sequence = fields.Integer(string='Sequence', select=True,default=10, help="Gives the sequence order when displaying a list of tasks.") + tag_ids = fields.Many2many('worksheet.tags', string='Tags') + kanban_state = fields.Selection( + [('normal', 'In Progress'), ('done', 'Ready for next stage'), ('blocked', 'Blocked')], 'Kanban State', + help="A task's kanban state indicates special situations affecting it:\n" + " * Normal is the default situation\n" + " * Blocked indicates something is preventing the progress of this task\n" + " * Ready for next stage indicates the task is ready to be pulled to the next stage", + required=True, track_visibility='onchange',default='normal', copy=False) + create_date = fields.Datetime(string='Create Date', readonly=True, select=True) + write_date = fields.Datetime(string='Last Modification Date', readonly=True, select=True) + date_start = fields.Datetime(string='Starting Date', default=fields.datetime.now(),select=True, copy=False) + date_end = fields.Datetime(string='Ending Date', select=True, copy=False) + date_assign = fields.Datetime(string='Assigning Date', select=True, copy=False, readonly=True) + date_deadline = fields.Datetime(string='Deadline', select=True, copy=False) + progress = fields.Integer(string="Working Time Progress(%)", copy=False, readonly=True) + date_last_stage_update = fields.Datetime(string='Last Stage Update', select=True, default=fields.datetime.now(),copy=False, readonly=True) + id = fields.Integer('ID', readonly=True) + company_id = fields.Many2many('res.company', string='Company Name', default=lambda self: self.env['res.company']._company_default_get('car.workshop')) + color = fields.Integer(string='Color Index') + stage_id = fields.Many2one('worksheet.stages', string='Stage', track_visibility='onchange', copy=False) + state = fields.Selection([ + ('waiting', 'Ready'), + ('workshop_create_invoices', 'Invoiced'), + ('cancel', 'Invoice Canceled'), + ], string='Status', readonly=True, default='waiting', track_visibility='onchange', select=True) + attachment_ids = fields.One2many('ir.attachment', 'res_id', domain=lambda self: [('res_model', '=', self._name)], + auto_join=True, string='Attachments') + displayed_image_id = fields.Many2one('ir.attachment', + domain="[('res_model', '=', 'car.workshop'), ('res_id', '=', id)," + "\ ('mimetype', 'ilike', 'image')]", + string='Displayed Image') + planned_works = fields.One2many('planned.work', 'work_id', string='Planned/Ordered Works') + works_done = fields.One2many('planned.work', 'work_id', string='Work Done', domain=[('completed', '=', True)]) + materials_used = fields.One2many('material.used', 'material_id', string='Materials Used') + remaining_hour = fields.Float(string='Remaining Hour', readonly=True, compute="hours_left") + effective_hour = fields.Float(string='Hours Spent', readonly=True, compute="hours_spent") + amount_total = fields.Float(string='Total Amount', readonly=True, compute="amount_total1") + + def _get_default_stages(self, cr, uid, context=None): + """ Gives default stage_id """ + if context is None: + context = {} + default_vehicle_id = context.get('default_vehicle_id') + if not default_vehicle_id: + return False + return self.find_stage(cr, uid, [], default_vehicle_id, [('fold', '=', False)], context=context) + + _defaults = { + 'stage_id': _get_default_stages, + } + + @api.depends('planned_works.work_cost', 'materials_used.price') + def amount_total1(self): + for records in self: + for hour in records: + amount_totall = 0.0 + for line in hour.planned_works: + amount_totall += line.work_cost + for line2 in hour.materials_used: + amount_totall += line2.price + records.amount_total = amount_totall + + @api.multi + def cancel(self): + self.state = 'cancel' + + @api.multi + def workshop_create_invoices(self): + + self.state = 'workshop_create_invoices' + inv_obj = self.env['account.invoice'] + inv_line_obj = self.env['account.invoice.line'] + customer = self.partner_id + if not customer.name: + raise UserError( + _( + 'Please select a Customer.')) + + company_id = self.env['res.users'].browse(1).company_id + currency_value = company_id.currency_id.id + self.ensure_one() + ir_values = self.env['ir.values'] + journal_id = ir_values.get_default('workshop.config.setting', 'invoice_journal_type') + if not journal_id: + journal_id = 1 + + inv_data = { + 'name': customer.name, + 'reference': customer.name, + 'account_id': customer.property_account_payable_id.id, + 'partner_id': customer.id, + 'currency_id': currency_value, + 'journal_id': journal_id, + 'origin': self.name, + 'company_id': company_id.id, + } + inv_id = inv_obj.create(inv_data) + for records in self.planned_works: + if records.planned_work.id : + income_account = records.planned_work.property_account_income_id.id + if not income_account: + raise UserError(_('There is no income account defined for this product: "%s".') % + (records.planned_work.name,)) + + inv_line_data = { + 'name': records.planned_work.name, + 'account_id': income_account, + 'price_unit': records.work_cost, + 'quantity': 1, + 'product_id': records.planned_work.id, + 'invoice_id': inv_id.id, + } + inv_line_obj.create(inv_line_data) + + for records in self.materials_used: + if records.material.id : + income_account = records.material.property_account_income_id.id + if not income_account: + raise UserError(_('There is no income account defined for this product: "%s".') % + (records.material.name,)) + + inv_line_data = { + 'name': records.material.name, + 'account_id': records.material.property_account_income_id.id, + 'price_unit': records.price, + 'quantity': records.amount, + 'product_id': records.material.id, + 'invoice_id': inv_id.id, + } + inv_line_obj.create(inv_line_data) + + imd = self.env['ir.model.data'] + action = imd.xmlid_to_object('account.action_invoice_tree1') + list_view_id = imd.xmlid_to_res_id('account.invoice_tree') + form_view_id = imd.xmlid_to_res_id('account.invoice_form') + + result = { + 'name': action.name, + 'help': action.help, + 'type': 'ir.actions.act_window', + 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], + [False, 'calendar'], [False, 'pivot']], + 'target': action.target, + 'context': action.context, + 'res_model': 'account.invoice', + } + if len(inv_id) > 1: + result['domain'] = "[('id','in',%s)]" % inv_id.ids + elif len(inv_id) == 1: + result['views'] = [(form_view_id, 'form')] + result['res_id'] = inv_id.ids[0] + else: + result = {'type': 'ir.actions.act_window_close'} + invoiced_records = self.env['car.workshop'] + + total = 0 + for rows in invoiced_records: + invoiced_date = rows.date + invoiced_date = invoiced_date[0:10] + if invoiced_date == str(date.today()): + total = total + rows.price_subtotal + return result + + @api.depends('works_done.duration') + def hours_spent(self): + for hour in self: + effective_hour = 0.0 + for line in hour.works_done: + effective_hour += line.duration + self.effective_hour = effective_hour + + @api.depends('planned_works.time_spent') + def hours_left(self): + for hour in self: + remaining_hour = 0.0 + for line in hour.planned_works: + remaining_hour += line.time_spent + self.remaining_hour = remaining_hour-self.effective_hour + + def process_demo_scheduler_queue(self): + obj = self.env['car.workshop'] + obj1 = obj.search([]) + now = fields.Datetime.from_string(fields.Datetime.now()) + for obj2 in obj1: + obj3 = obj2 + if obj3.stage_id.name != 'Done' and obj3.stage_id.name != 'Cancelled' and obj3.stage_id.name != 'Verified': + end_date = fields.Datetime.from_string(obj3.date_deadline) + start_date = fields.Datetime.from_string(obj3.date_assign) + if obj3.date_deadline and obj3.date_assign and end_date > start_date: + if now < end_date: + diff1 = relativedelta(end_date, start_date) + if diff1.days == 0: + total_hr = int(diff1.minutes) + else: + total_hr = int(diff1.days) * 24 * 60 + int(diff1.minutes) + diff2 = relativedelta(now, start_date) + if diff2.days == 0: + current_hr = int(diff2.minutes) + else: + current_hr = int(diff2.days) * 24 * 60 + int(diff2.minutes) + if total_hr != 0: + obj3.progress = ((current_hr * 100) / total_hr) + else: + obj3.progress = 100 + else: + obj3.progress = 100 + else: + obj3.progress = 0 + + + @api.model + def _track_subtype(self, init_values): + record = self.browse() + if 'kanban_state' in init_values and record.kanban_state == 'blocked': + return 'fleet_car_workshop.mt_task_blocked' + elif 'kanban_state' in init_values and record.kanban_state == 'done': + return 'fleet_car_workshop.mt_task_ready' + elif 'user_id' in init_values and record.user_id: # assigned -> new + return 'fleet_car_workshop.mt_task_new' + elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence <= 1: # start stage -> new + return 'fleet_car_workshop.mt_task_new' + elif 'stage_id' in init_values: + return 'fleet_car_workshop.mt_task_stage' + return super(CarWorkshop, self)._track_subtype(init_values) + + @api.model + def create(self, vals): + # context: no_log, because subtype already handle this + context = dict(self.env.context, mail_create_nolog=True) + + # for default stage + if vals.get('vehicle_id') and not context.get('default_vehicle_id'): + context['default_vehicle_id'] = vals.get('vehicle_id') + # user_id change: update date_assign + if vals.get('user_id'): + vals['date_assign'] = fields.Datetime.now() + task = super(CarWorkshop, self.with_context(context)).create(vals) + return task + + @api.multi + def write(self, vals): + now = fields.Datetime.now() + # stage change: update date_last_stage_update + if 'stage_id' in vals: + vals['date_last_stage_update'] = now + # reset kanban state when changing stage + if 'kanban_state' not in vals: + vals['kanban_state'] = 'normal' + # user_id change: update date_assign + if vals.get('user_id'): + vals['date_assign'] = now + + result = super(CarWorkshop, self).write(vals) + + return result + + def _read_group_stages(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None): + if context is None: + context = {} + stage_obj = self.pool.get('worksheet.stages') + order = stage_obj._order + access_rights_uid = access_rights_uid or uid + if read_group_order == 'stage_id desc': + order = '%s desc' % order + if 'default_vehicle_id' in context: + search_domain = ['|', ('vehicle_ids', '=', context['default_vehicle_id']), ('id', 'in', ids)] + else: + search_domain = [('id', 'in', ids)] + stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context) + result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context) + result.sort(lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) + + fold = {} + for stage in stage_obj.browse(cr, access_rights_uid, stage_ids, context=context): + fold[stage.id] = stage.fold or False + return result, fold + + _group_by_full = { + 'stage_id': _read_group_stages, + } + + @api.cr_uid_ids_context + def onchange_vehicle(self, cr, uid, id, vehicle_id, context=None): + values = {} + if vehicle_id: + vehicle = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context) + if vehicle.exists(): + values['partner_id'] = vehicle.partner_id.id + values['stage_id'] = self.find_stage(cr, uid, [], vehicle_id, [('fold', '=', False)], context=context) + else: + values['stage_id'] = False + return {'value': values} + + def _get_default_vehicle(self, cr, uid, context=None): + if context is None: + context = {} + if 'default_vehicle_id' in context: + vehicle = self.pool.get('car.car').browse(cr, uid, context['default_vehicle_id'], context=context) + if vehicle and vehicle.partner_id: + return vehicle.partner_id.id + return False + + def find_stage(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None): + """ Override of the base.stage method + Parameter of the stage search taken from the lead: + - section_id: if set, stages must belong to this section or + be a default stage; if not set, stages must be default + stages + """ + if isinstance(cases, (int, long)): + cases = self.browse(cr, uid, cases, context=context) + section_ids = [] + if section_id: + section_ids.append(section_id) + for task in cases: + if task.vehicle_id: + section_ids.append(task.vehicle_id.id) + search_domain = [] + if section_ids: + search_domain = [('|')] * (len(section_ids) - 1) + for section_id in section_ids: + search_domain.append(('vehicle_ids', '=', section_id)) + search_domain += list(domain) + stage_ids = self.pool.get('worksheet.stages').search(cr, uid, search_domain, order=order, context=context) + if stage_ids: + return stage_ids[0] + return False diff --git a/fleet_car_workshop/models/config.py b/fleet_car_workshop/models/config.py new file mode 100644 index 000000000..f82709a90 --- /dev/null +++ b/fleet_car_workshop/models/config.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo.tools.translate import _ +from odoo import fields, models, api + + +class WorkshopSetting(models.Model): + _name = "workshop.config.setting" + + invoice_journal_type = fields.Many2one('account.journal', string="Car Workshop Journal") + + @api.multi + def execute(self): + return self.env['ir.values'].sudo().set_default( + 'workshop.config.setting', 'invoice_journal_type', self.invoice_journal_type.id) + + def cancel(self, cr, uid, ids, context=None): + act_window = self.pool['ir.actions.act_window'] + action_ids = act_window.search(cr, uid, [('res_model', '=', self._name)]) + if action_ids: + return act_window.read(cr, uid, action_ids[0], [], context=context) + return {} + + +class WorksheetTags(models.Model): + _name = "worksheet.tags" + _description = "Tags of vehicles's tasks, issues..." + + name = fields.Char('Name', required=True) + color = fields.Integer('Color Index') + + _sql_constraints = [ + ('name_uniq', 'unique (name)', "Tag name already exists !"), + ] + + +class WorksheetStages(models.Model): + _name = 'worksheet.stages' + _description = 'worksheet Stage' + _order = 'sequence' + + name = fields.Char(string='Stage Name', required=True) + description = fields.Text(string='Description', translate=True) + sequence = fields.Integer(string='Sequence') + vehicle_ids = fields.Many2many('car.car', 'worksheet_type_rel', 'type_id', 'vehicle_id', string='Vechicles') + fold = fields.Boolean('Folded in Tasks Pipeline', + help='This stage is folded in the kanban view when ' + 'there are no records in that stage to display.') + + def _get_default_vehicle_ids(self, cr, uid, ctx=None): + if ctx is None: + ctx = {} + default_vehicle_id = ctx.get('default_vehicle_id') + return [default_vehicle_id] if default_vehicle_id else None + + _defaults = { + 'sequence': 1, + 'vehicle_ids': _get_default_vehicle_ids, + } + _order = 'sequence' + + +class Services(models.Model): + _inherit = 'product.template' + + type = fields.Selection([('consu', _('Consumable')), ('service', _('Service')), ('product', _('Stockable Product'))], 'Product Type', required=True, + help="A consumable is a product for which you don't manage stock," + " a service is a non-material product provided by a company or an individual.") + + _defaults = { + 'type': 'service', + + } diff --git a/fleet_car_workshop/models/dashboard.py b/fleet_car_workshop/models/dashboard.py new file mode 100644 index 000000000..7b592c4e0 --- /dev/null +++ b/fleet_car_workshop/models/dashboard.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo.osv import osv +from odoo.tools.translate import _ +from odoo import fields, api + + +class CarVehicle(osv.osv): + _name = 'car.car' + _description = "Vechicles" + _inherit = ['mail.thread'] + + def _get_visibility_selection_id(self, cr, uid, context=None): + return [('portal', _('Customer Works: visible in portal if the customer is a follower')), + ('employees', _('All Employees Work: all employees can access')), + ('followers', _('Private Work: followers only'))] + + _visibility_selections = lambda self, *args, **kwargs: self._get_visibility_selection_id(*args, **kwargs) + + def _compute_attached_docs_count(self): + Attachment = self.env['ir.attachment'] + for vehicle in self: + vehicle.doc_count = Attachment.search_count([ + '|', + '&', + ('res_model', '=', 'car.car'), ('res_id', '=', vehicle.id), + '&', + ('res_model', '=', 'car.worksheet'), ('res_id', 'in', vehicle.task_ids.ids) + ]) + + def _compute_task_count(self): + for vehicle in self: + vehicle.task_count = len(vehicle.task_ids) + + def attachment_tree_views(self): + self.ensure_one() + domain = [ + '|', + '&', ('res_model', '=', 'car.car'), ('res_id', 'in', self.ids), + '&', ('res_model', '=', 'car.workshop'), ('res_id', 'in', self.task_ids.ids)] + + return { + 'name': _('Attachments'), + 'domain': domain, + 'res_model': 'ir.attachment', + 'type': 'ir.actions.act_window', + 'view_id': False, + 'view_mode': 'kanban,tree,form', + 'view_type': 'form', + 'help': _('''

    + Documents are attached to the tasks and issues of your Worksheet.

    + Send messages or log internal notes with attachments to link + documents to your Worksheet. +

    '''), + 'limit': 80, + 'context': "{'default_res_model': '%s','default_res_id': %d}" % (self._name, self.id) + } + + active = fields.Boolean('Active',default=True) + name = fields.Many2one('fleet.vehicle', string='Vehicle Name', track_visibility='onchange', required=True) + sequence = fields.Integer('Sequence', help="Gives the sequence order when displaying a list of Projects.") + + label_tasks = fields.Char(string='Use Tasks as', help="Gives label to Work on kanban view.", default="Task") + worksheet = fields.One2many('car.workshop', 'vehicle_id', string="Task Activities") + + type_ids = fields.Many2many('worksheet.stages', 'car_workshop_type_rel', + 'vehicle_id', 'type_id', string='Worksheet Stages', + states={'close': [('readonly', True)], 'cancelled': [('readonly', True)]}) + task_count = fields.Integer(compute=_compute_task_count, type='integer', string="Tasks", ) + task_ids = fields.One2many('car.workshop', 'vehicle_id', + domain=['|', ('stage_id.fold', '=', False), ('stage_id', '=', False)]) + doc_count = fields.Integer(compute=_compute_attached_docs_count, string="Number of documents attached") + color = fields.Integer(string='Color Index') + partner_id = fields.Many2one('res.partner', string='Customer') + state = fields.Selection([('draft', 'New'), + ('open', 'In Progress'), + ('cancelled', 'Cancelled'), + ('pending', 'Pending'), + ('close', 'Closed')], string='Status', required=True, + track_visibility='onchange',default='open', copy=False) + + date_start = fields.Date(string='Start Date') + date = fields.Date(string='Expiration Date', select=True, track_visibility='onchange') + use_tasks = fields.Boolean(string='Tasks', default=True) + image_medium = fields.Binary(string="Logo (medium)") + + @api.onchange('name') + def on_change_vehicle(self): + self.image_medium = self.name.image_medium diff --git a/fleet_car_workshop/models/dashboard.py~ b/fleet_car_workshop/models/dashboard.py~ new file mode 100644 index 000000000..3d6b20a02 --- /dev/null +++ b/fleet_car_workshop/models/dashboard.py~ @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo.osv import osv +from odoo.tools.translate import _ +from odoo import fields, api + + +class CarVehicle(osv.osv): + _name = 'car.car' + _description = "Vechicles" + _inherit = ['mail.thread'] + + def _get_visibility_selection_id(self, cr, uid, context=None): + return [('portal', _('Customer Works: visible in portal if the customer is a follower')), + ('employees', _('All Employees Work: all employees can access')), + ('followers', _('Private Work: followers only'))] + + _visibility_selections = lambda self, *args, **kwargs: self._get_visibility_selection_id(*args, **kwargs) + + def _compute_attached_docs_count(self): + Attachment = self.env['ir.attachment'] + for vehicle in self: + vehicle.doc_count = Attachment.search_count([ + '|', + '&', + ('res_model', '=', 'car.car'), ('res_id', '=', vehicle.id), + '&', + ('res_model', '=', 'car.worksheet'), ('res_id', 'in', vehicle.task_ids.ids) + ]) + + def _compute_task_count(self): + for vehicle in self: + vehicle.task_count = len(vehicle.task_ids) + + def attachment_tree_views(self): + self.ensure_one() + domain = [ + '|', + '&', ('res_model', '=', 'car.car'), ('res_id', 'in', self.ids), + '&', ('res_model', '=', 'car.workshop'), ('res_id', 'in', self.task_ids.ids)] + + return { + 'name': _('Attachments'), + 'domain': domain, + 'res_model': 'ir.attachment', + 'type': 'ir.actions.act_window', + 'view_id': False, + 'view_mode': 'kanban,tree,form', + 'view_type': 'form', + 'help': _('''

    + Documents are attached to the tasks and issues of your Worksheet.

    + Send messages or log internal notes with attachments to link + documents to your Worksheet. +

    '''), + 'limit': 80, + 'context': "{'default_res_model': '%s','default_res_id': %d}" % (self._name, self.id) + } + + active = fields.Boolean('Active',default=True) + name = fields.Many2one('fleet.vehicle', string='Vehicle Name', track_visibility='onchange', required=True) + sequence = fields.Integer('Sequence', help="Gives the sequence order when displaying a list of Projects.") + + label_tasks = fields.Char(string='Use Tasks as', help="Gives label to Work on kanban view.", default="Task") + worksheet = fields.One2many('car.workshop', 'vehicle_id', string="Task Activities") + + type_ids = fields.Many2many('worksheet.stages', 'car_workshop_type_rel', + 'vehicle_id', 'type_id', string='Worksheet Stages', + states={'close': [('readonly', True)], 'cancelled': [('readonly', True)]}) + task_count = fields.Integer(compute=_compute_task_count, type='integer', string="Tasks", ) + task_ids = fields.One2many('car.workshop', 'vehicle_id', + domain=['|', ('stage_id.fold', '=', False), ('stage_id', '=', False)]) + doc_count = fields.Integer(compute=_compute_attached_docs_count, string="Number of documents attached") + color = fields.Integer(string='Color Index') + partner_id = fields.Many2one('res.partner', string='Customer') + state = fields.Selection([('draft', 'New'), + ('open', 'In Progress'), + ('cancelled', 'Cancelled'), + ('pending', 'Pending'), + ('close', 'Closed')], string='Status', required=True, + track_visibility='onchange',default='open', copy=False) + + date_start = fields.Date(string='Start Date') + date = fields.Date(string='Expiration Date', select=True, track_visibility='onchange'), + use_tasks = fields.Boolean(string='Tasks', default=True) + image_medium = fields.Binary(string="Logo (medium)") + + @api.onchange('name') + def on_change_vehicle(self): + self.image_medium = self.name.image_medium diff --git a/fleet_car_workshop/models/timesheet.py b/fleet_car_workshop/models/timesheet.py new file mode 100644 index 000000000..19c26e2b9 --- /dev/null +++ b/fleet_car_workshop/models/timesheet.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nilmar Shereef() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import fields, models, api + + +class PlannedWork (models.Model): + _name = 'planned.work' + + planned_work = fields.Many2one('product.template', string='Planned work', domain=[('type', '=', 'service')]) + time_spent = fields.Float(string='Estimated Time') + work_date = fields.Datetime(string='Date') # Date of work planned:planned date + responsible = fields.Many2one('res.users', string='Responsible') + work_id = fields.Many2one('car.workshop', string="Work id") + work_cost = fields.Float(string="Service Cost") + completed = fields.Boolean(string="Completed") + duration = fields.Float(string='Duration') + work_date2 = fields.Datetime(string='Date') # Date of work completed/done:completed date + + @api.onchange('planned_work') + def get_price(self): + self.work_cost = self.planned_work.lst_price + + +class MaterialUsed (models.Model): + _name = 'material.used' + + material = fields.Many2one('product.template', string='Products') + amount = fields.Integer(string='Quantity') + price = fields.Float(string='Unit Price') + material_id = fields.Many2one('car.workshop') + _defaults = { + 'amount': 1, } + + @api.onchange('material') + def get_price(self): + self.price = self.material.lst_price diff --git a/fleet_car_workshop/security/ir.model.access.csv b/fleet_car_workshop/security/ir.model.access.csv new file mode 100644 index 000000000..5f3868aa3 --- /dev/null +++ b/fleet_car_workshop/security/ir.model.access.csv @@ -0,0 +1,22 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink + + + + + + +access_car_car_user,car.car.user,fleet_car_workshop.model_car_car,fleet.fleet_group_user,1,0,0,0 +access_car_workshop_user,car.workshop.user,fleet_car_workshop.model_car_workshop,fleet.fleet_group_user,1,0,0,0 +access_worksheet_tags_all_user,car.car_tags_all,fleet_car_workshop.model_worksheet_tags,fleet.fleet_group_user,1,0,0,0 +access_worksheet_stages_user,worksheet.stages.user,fleet_car_workshop.model_worksheet_stages,fleet.fleet_group_user,1,0,0,0 +access_service_product_user,car.car.products.user,fleet_car_workshop.model_product_template,fleet.fleet_group_user,0,0,0,0 +access_material_used_user,material.used.user,fleet_car_workshop.model_material_used,fleet.fleet_group_user,1,0,0,0 +access_planned_work_user,planned.work.user,fleet_car_workshop.model_planned_work,fleet.fleet_group_user,1,0,0,0 + +access_car_car_manager,car.car.manager,fleet_car_workshop.model_car_car,fleet.fleet_group_manager,1,1,1,1 +access_car_workshop_manager,car.workshop.manager,fleet_car_workshop.model_car_workshop,fleet.fleet_group_manager,1,1,1,1 +access_worksheet_tags_all_manager,car.car_tags_all.manager,fleet_car_workshop.model_worksheet_tags,fleet.fleet_group_manager,1,1,1,1 +access_worksheet_stages_manager,worksheet.stages.manager,fleet_car_workshop.model_worksheet_stages,fleet.fleet_group_manager,1,1,1,1 +access_service_product_manager,car.car.products.manager,fleet_car_workshop.model_product_template,fleet.fleet_group_manager,1,1,1,1 +access_material_used_manager,material.used.manager,fleet_car_workshop.model_material_used,fleet.fleet_group_manager,1,1,1,1 +access_planned_work_manager,planned.work.manager,fleet_car_workshop.model_planned_work,fleet.fleet_group_manager,1,1,1,1 \ No newline at end of file diff --git a/fleet_car_workshop/security/workshop_security.xml b/fleet_car_workshop/security/workshop_security.xml new file mode 100644 index 000000000..961bc0884 --- /dev/null +++ b/fleet_car_workshop/security/workshop_security.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + Manager has all rights on vehicle + + + + + diff --git a/fleet_car_workshop/static/description/1.png b/fleet_car_workshop/static/description/1.png new file mode 100644 index 000000000..37fcbd1f8 Binary files /dev/null and b/fleet_car_workshop/static/description/1.png differ diff --git a/fleet_car_workshop/static/description/10.png b/fleet_car_workshop/static/description/10.png new file mode 100644 index 000000000..120f03120 Binary files /dev/null and b/fleet_car_workshop/static/description/10.png differ diff --git a/fleet_car_workshop/static/description/2.png b/fleet_car_workshop/static/description/2.png new file mode 100644 index 000000000..fe6cc7d47 Binary files /dev/null and b/fleet_car_workshop/static/description/2.png differ diff --git a/fleet_car_workshop/static/description/4.png b/fleet_car_workshop/static/description/4.png new file mode 100644 index 000000000..2c85d2295 Binary files /dev/null and b/fleet_car_workshop/static/description/4.png differ diff --git a/fleet_car_workshop/static/description/5.png b/fleet_car_workshop/static/description/5.png new file mode 100644 index 000000000..33db91bc4 Binary files /dev/null and b/fleet_car_workshop/static/description/5.png differ diff --git a/fleet_car_workshop/static/description/7.png b/fleet_car_workshop/static/description/7.png new file mode 100644 index 000000000..119d302bd Binary files /dev/null and b/fleet_car_workshop/static/description/7.png differ diff --git a/fleet_car_workshop/static/description/8.png b/fleet_car_workshop/static/description/8.png new file mode 100644 index 000000000..9b7656ffb Binary files /dev/null and b/fleet_car_workshop/static/description/8.png differ diff --git a/fleet_car_workshop/static/description/9.png b/fleet_car_workshop/static/description/9.png new file mode 100644 index 000000000..a7b6f8b38 Binary files /dev/null and b/fleet_car_workshop/static/description/9.png differ diff --git a/fleet_car_workshop/static/description/banner.jpg b/fleet_car_workshop/static/description/banner.jpg new file mode 100644 index 000000000..e1a0fbdb1 Binary files /dev/null and b/fleet_car_workshop/static/description/banner.jpg differ diff --git a/fleet_car_workshop/static/description/cybro_logo.png b/fleet_car_workshop/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/fleet_car_workshop/static/description/cybro_logo.png differ diff --git a/fleet_car_workshop/static/description/icon.png b/fleet_car_workshop/static/description/icon.png new file mode 100644 index 000000000..a17017510 Binary files /dev/null and b/fleet_car_workshop/static/description/icon.png differ diff --git a/fleet_car_workshop/static/description/index.html b/fleet_car_workshop/static/description/index.html new file mode 100644 index 000000000..e918e4631 --- /dev/null +++ b/fleet_car_workshop/static/description/index.html @@ -0,0 +1,179 @@ +
    +
    +

    Car Workshop Management

    +

    +

    Cybrosys Technologies

    + + +

    +Car Workshop Management is Cybrosys Generic Module to manage automobile workshop with +great ease. Keep track of everything, like vehicle owner details, + Works assigned, Bill details of service provided,etc..
    Some other features are as below: +

    +
      +
    •    User Friendly Interface.
    • +
    •    Effective Time management.
    • +
    •    Separate Journal Configuration..
    • +
    •    Integrated with Accounting.
    • +
    •    High Scalability.
    • +
    +
    +
    + +
    +
    +
    +

    Dashboard/All Vehicles

    +

    Whole Workshop Analysis

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

    All works

    +
    +

    +

    Goto Car Workshop -->Search -->Worksheet

    +

    Organise all the works according to their Status. Works/Tasks assigned works using the kanban view and + control deadlines in the calendar view.Each Work may have it's own stages. +

    +
    +
    +

    Kanban

    + + +
    +
    +

    Calendar

    + +
    +
    +
    + +
    +
    +
    +

    Worksheet View

    +

    All details related to a work/task

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

    Timesheet

    +
    +

    +

    Goto Car Workshop >Search >Worksheet >Timesheet

    +

    +

    * In timesheet ,Planned work is the sub works related to main Work. By ticking + 'Completed' that work will be automatically updated to Work done.

    +

    * Work done is the details of completed works.

    +

    * Hour spent is time taken for completed work(Work Done).

    +

    * Remaining Hour is total time left(Difference between Total Time and Hour Spent).

    +

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

    Report

    +

    Tabular Details of Vehicles

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

    Settings

    +

    Configure Preferred journal for Invoicing

    +
    +
    +

    +

    Goto Car Workshop >Configuration >Settings

    +

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

    Separate Journal

    +

    Invoices from the car workshop will be saved to Separate journal.

    +
    +
    +

    +

    Goto Car Workshop >Search >Worksheet >Create Invoices

    +

    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    You Looking for a free Documentation of this Application.?

    +

    Give a Request Mail to:    odoo@cybrosys.com

    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    + + + diff --git a/fleet_car_workshop/static/src/css/vehicles.css b/fleet_car_workshop/static/src/css/vehicles.css new file mode 100644 index 000000000..c6e6d31c5 --- /dev/null +++ b/fleet_car_workshop/static/src/css/vehicles.css @@ -0,0 +1,40 @@ + +.oe_kanban_project_avatars img { + width: 30px; + border-radius: 2px; + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); +} +.oe_form_gantt_avatars:after { + font-family: "mnmliconsRegular" !important; + font-size: 21px; + font-weight: 300 !important; + content: "y"; + top: 3px; + position: relative; +} + +.openerp .oe_kanban_view .oe_kanban_project { + width: 250px; + min-height: 160px !important; + cursor: default; +} + +.openerp .oe_percent strong:after { + content: "%"; +} + +.openerp .oe_margin_top_8 { + margin-top: 8px; +} +.openerp .oe_kanban_project .oe_kanban_project_list .col-md-6 a{ + margin-left: 5px; +} + +/* Kanban status as label in project stage form view */ +.openerp label.oe_project_kanban_legend { + min-width: inherit !important; + margin-top: 6px; + margin-right: 8px; +} diff --git a/fleet_car_workshop/static/src/less/car_dashboard.less b/fleet_car_workshop/static/src/less/car_dashboard.less new file mode 100644 index 000000000..36c48bb9c --- /dev/null +++ b/fleet_car_workshop/static/src/less/car_dashboard.less @@ -0,0 +1,98 @@ +.o_kanban_view.o_kanban_dashboard.o_project_kanban { + + .o_kanban_record { + .o-flex-display(); + position: relative; + } + + .o_project_kanban_main { + .o-flex(0, 0, auto); + padding: @odoo-horizontal-padding; + width: 70%; // for IE11 overflow issue + + // give space for manage section at the bottom + margin-bottom: @odoo-horizontal-padding/2 + 19px; + + .o_kanban_card_content { + font-size: 12px; + .o_primary { + font-size: larger; + } + } + + .o_project_kanban_manage { + .o-position-absolute(@bottom: 0, @left: 0); + padding: @odoo-horizontal-padding/2 @odoo-horizontal-padding; + } + .o_kanban_card_manage_pane .o_kanban_card_manage_title { + margin: 0; + } + } + + .o_project_kanban_boxes { + width: 30%; + .o-flex(0, 0, auto); + + .o-flex-display(); + .o-flex-flow(column, nowrap); + + > a:hover { + text-decoration: none; + } + + .o_value { + font-size: x-large; + color: white; + display: block; + } + .o_label { + color: white; + } + .o_needaction{ + position: absolute; + top: 5px; + right: 5px; + color: white; + font-size: small; + opacity: 0.5; + &:hover{ + opacity:1; + } + &::before { + content: "\f086"; + font: normal normal normal 14px/1 FontAwesome; + } + } + + .o_project_kanban_box { + position: relative; + text-align: center; + padding: 15px 0 15px 0; + .o-flex(1, 1, auto); + .o-flex-display(); + .o-align-items(center); + .o-flex-flow(column, nowrap); + .o-justify-content(center); + } + .o_project_kanban_box:nth-child(even) { + background-color: grey; + } + .o_project_kanban_box:nth-child(odd) { + background-color: @odoo-brand-optional; + } + } +} + +.o_kanban_task_cover_image { + .o-columns(200px, 4); + > img { + cursor: pointer; + margin-bottom: 1em; + border: 1px solid transparent; + + &.o_selected { + border-color: @odoo-brand-secondary; + box-shadow: 0px 0px 2px 2px @odoo-brand-secondary; + } + } +} diff --git a/fleet_car_workshop/views/car_dashboard.xml b/fleet_car_workshop/views/car_dashboard.xml new file mode 100644 index 000000000..f277c56dc --- /dev/null +++ b/fleet_car_workshop/views/car_dashboard.xml @@ -0,0 +1,189 @@ + + + car.car.form + car.car + +
    +
    + +
    + +
    + + + + + +
    + +
    +

    + +

    +
    +
    + +
    +
    +
    + + + + + + + + +
    +
    + + +
    +
    +
    +
    + + + car.car.select + car.car + + + + + + + + + + + + + + + + + + car.car.kanban + car.car + + + + + + + + + + + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + Settings +
    + +
    +
    +
      +
    +
    +
    + More +
    +
    + + +
    +
    +
    +
    +
    +
    + + + car.car.tree + car.car + child_ids + + + + + + + + + + + Vehicles + car.car + form + [] + kanban,form + + {'search_default_Current': 1} + +

    + Create a new project. +

    +

    + Organize your activities (plan tasks, track issues, invoice timesheets) for internal, personal or customer projects. +

    +
    +
    + + + Vehicles + car.car + form + [] + tree,form + + {'search_default_Current': 1} + +

    + Create a new vehicle. +

    +
    +
    + + + +
    \ No newline at end of file diff --git a/fleet_car_workshop/views/config_setting.xml b/fleet_car_workshop/views/config_setting.xml new file mode 100644 index 000000000..84652438e --- /dev/null +++ b/fleet_car_workshop/views/config_setting.xml @@ -0,0 +1,32 @@ + + + workshop settings + workshop.config.setting + +
    +
    +
    + +
    + + +
    +
    +
    +
    + + + Settings + ir.actions.act_window + workshop.config.setting + + form + inline + + + + +
    \ No newline at end of file diff --git a/fleet_car_workshop/views/report.xml b/fleet_car_workshop/views/report.xml new file mode 100644 index 000000000..06bbdb98a --- /dev/null +++ b/fleet_car_workshop/views/report.xml @@ -0,0 +1,15 @@ + + + Worksheets + car.workshop + pivot,graph + +

    + Odoo's car workshop management allows you to manage the pipeline of your work efficiently. You can track progress, discuss on works, attach documents, etc. +

    +
    +
    + + + +
    \ No newline at end of file diff --git a/fleet_car_workshop/views/timesheet_view.xml b/fleet_car_workshop/views/timesheet_view.xml new file mode 100644 index 000000000..9732a2298 --- /dev/null +++ b/fleet_car_workshop/views/timesheet_view.xml @@ -0,0 +1,53 @@ + + + + planned.work.form + planned.work + +
    + + + + + + + + + + + +
    +
    +
    + + + material.used.form + material.used + +
    + + + + + + + + + +
    +
    +
    + + + material.used.tree + material.used + + + + + + + + +
    +
    \ No newline at end of file diff --git a/fleet_car_workshop/views/vehicle.xml b/fleet_car_workshop/views/vehicle.xml new file mode 100644 index 000000000..f5aff98c8 --- /dev/null +++ b/fleet_car_workshop/views/vehicle.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/fleet_car_workshop/views/worksheet_stages.xml b/fleet_car_workshop/views/worksheet_stages.xml new file mode 100644 index 000000000..b3ed90bb5 --- /dev/null +++ b/fleet_car_workshop/views/worksheet_stages.xml @@ -0,0 +1,90 @@ + + + + worksheet.stages.form + worksheet.stages + +
    + + + + + + + + + + +

    + You can also add a description to help your co-workers understand the meaning and purpose of the stage. +

    + +
    + + + +
    +
    +
    + + + worksheet.stages.tree + worksheet.stages + + + + + + + + + + + + Stages + worksheet.stages + form + + + + Tags + worksheet.tags + +
    + + + +
    +
    +
    + + + Tags + worksheet.tags + form + +

    + Click to add a new tag. +

    +
    +
    + + + Service-Products + ir.actions.act_window + product.template + kanban,tree,form + form + {"search_default_services":'service'} + +

    + Click to define a new product. +

    +
    +
    + + + + +
    +
    diff --git a/fleet_car_workshop/views/worksheet_views.xml b/fleet_car_workshop/views/worksheet_views.xml new file mode 100644 index 000000000..47090c72a --- /dev/null +++ b/fleet_car_workshop/views/worksheet_views.xml @@ -0,0 +1,285 @@ + + + + Demo scheduler + + 1 + minutes + -1 + + + + + + + worksheet.form.view + car.workshop + +
    +
    +
    + +
    + + + +
    +

    + + +

    +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + + + + + + car.workshop.kanban + car.workshop + + + + + + + + + + + + + + + +
    + + +
    +
    + +
    +
    + +
    +
    + + oe_kanban_text_red + +
    +
    + + +
    +
    + +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + + + worksheet.tree.view + car.workshop + + + + + + + + + + + + + + worksheet.calender.view + car.workshop + + + + + + + + + + + car.workshop.pivot + car.workshop + + + + + + + + + + car.workshop.graph + car.workshop + + + + + + + + + + Worksheets + car.workshop + {'search_default_vehicle_id': active_id} + kanban,tree,form,calendar,pivot,graph + +

    + Odoo's car workshop management allows you to manage the pipeline of your work efficiently. You can track progress, discuss on works, attach documents, etc. +

    +
    +
    + + + car.workshop.search.form + car.workshop + + + + + + + + + + + + + + + + + + + + + + + + + + + + Worksheets + car.workshop + kanban,tree,form,calendar,pivot,graph + +

    + Odoo's car workshop management allows you to manage the pipeline of your work efficiently. You can track progress, discuss on works, attach documents, etc. +

    +
    +
    + + + + + + + \ No newline at end of file diff --git a/fleet_car_workshop/views/workshop_data.xml b/fleet_car_workshop/views/workshop_data.xml new file mode 100644 index 000000000..248025506 --- /dev/null +++ b/fleet_car_workshop/views/workshop_data.xml @@ -0,0 +1,77 @@ + + + + + + Car + car.car + + + + Car Worksheet + car.workshop + + + + + + + Task Opened + car.workshop + + + Task opened + + + Task Blocked + car.workshop + + Task blocked + + + Task Ready + car.workshop + + Task ready for Next Stage + + + Stage Changed + car.workshop + + Stage changed + + + + Task Opened + 10 + car.car + + + vehicle_id + + + Task Blocked + 11 + car.car + + + vehicle_id + + + Task Ready + 12 + car.car + + + vehicle_id + + + Task Stage Changed + 13 + car.car + + + vehicle_id + + + \ No newline at end of file diff --git a/fleet_rental/README.rst b/fleet_rental/README.rst new file mode 100644 index 000000000..2ab264d43 --- /dev/null +++ b/fleet_rental/README.rst @@ -0,0 +1,24 @@ +Fleet Rental Management v10 +=========================== +This module will helps you to give the vehicles for Rent. + +Features +======== + +* Multiple Plans for Rental Contract(Days/Weeks/Months/Years). +* Integrated with Accounting Module. +* Automatically Create Recurring Invoices. +* Sending email for confirmation, first payment and recurrent invoices. +* Check List Facility. +* Separate Tree view for Checklist. +* Damage Checking Facility. +* Billing Facility for Damages/Check Lists. +* Contract Payment Validations. +* Detailed Fleet Rental Analysis Report. +* Access Rights From Multiple Level. + +Credits +======= +Developer: Nilmar Shereef @ cybrosys, shereef@cybrosys.in +Developer: Jesni Banu @ cybrosys, jesni@cybrosys.in +Developer: Avinash NK @ cybrosys, avinash@cybrosys.in diff --git a/fleet_rental/__init__.py b/fleet_rental/__init__.py new file mode 100644 index 000000000..76afd6b4c --- /dev/null +++ b/fleet_rental/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## +import models +import reports + diff --git a/fleet_rental/__manifest__.py b/fleet_rental/__manifest__.py new file mode 100644 index 000000000..aca4b9e0d --- /dev/null +++ b/fleet_rental/__manifest__.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## + +{ + 'name': 'Fleet Rental Management', + 'version': '10.0.3.1.0', + 'summary': """This module will helps you to give the vehicles for Rent.""", + 'description': "Module Helps You To Manage Rental Contracts", + 'category': "Industries", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "http://www.cybrosys.com", + 'depends': ['base', 'account', 'fleet', 'mail'], + 'data': ['security/rental_security.xml', + 'security/ir.model.access.csv', + 'views/car_rental_view.xml', + 'views/checklist_view.xml', + 'views/car_tools_view.xml', + 'reports/rental_report.xml', + 'data/fleet_rental_data.xml', + ], + 'demo': [ + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'application': True, +} diff --git a/fleet_rental/__manifest__.py~ b/fleet_rental/__manifest__.py~ new file mode 100644 index 000000000..af8f03b29 --- /dev/null +++ b/fleet_rental/__manifest__.py~ @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## + +{ + 'name': 'Fleet Rental Management', + 'version': '10.0.3.0.0', + 'summary': """This module will helps you to give the vehicles for Rent.""", + 'description': "Module Helps You To Manage Rental Contracts", + 'category': "Industries", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "http://www.cybrosys.com", + 'depends': ['base', 'account', 'fleet', 'mail'], + 'data': ['security/rental_security.xml', + 'security/ir.model.access.csv', + 'views/car_rental_view.xml', + 'views/checklist_view.xml', + 'views/car_tools_view.xml', + 'reports/rental_report.xml', + 'data/fleet_rental_data.xml', + ], + 'demo': [ + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'application': True, +} diff --git a/fleet_rental/data/fleet_rental_data.xml b/fleet_rental/data/fleet_rental_data.xml new file mode 100644 index 000000000..e68b334af --- /dev/null +++ b/fleet_rental/data/fleet_rental_data.xml @@ -0,0 +1,758 @@ + + + + + Fleet Rental Service + service + + + + In shop + 1 + + + + Active + 2 + + + + Inactive + 3 + + + + Sold + 4 + + + + Rent + 3 + + + + User can only see his/her vehicle + + + + + + + [] + + + + + iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABHNCSVQICAgIfAhkiAAAAF96VFh0 +UmF3IHByb2ZpbGUgdHlwZSBBUFAxAAAImeNKT81LLcpMVigoyk/LzEnlUgADYxMuE0sTS6NEAwMD +CwMIMDQwMDYEkkZAtjlUKNEABZiYm6UBoblZspkpiM8FAE+6FWgbLdiMAAAgAElEQVR4nOy9ebQd +x3kf+Kvq7rvf+1asBEiQBAHuokhKokyQFLiYki3JUiLJSywfy0kc2c4Z2Y493o8zJ1GOk+NJ4jlj +j8exfEZOvESSY8uxFMtaQIoiAXAVKQIQse/b2++7++2qb/6opav7Lu89EKQewP4OLrq7ul93VXV9 +3/f7lqoGUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRS +SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkop +pZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU +UkoppZRSSiklh9j3ugIpXRoREXvhhRf8kZERPj09zWu1WmbNmjW3ZzKZO4Ig2Mo538w5X+d53gTn +vMI5L3iel+WcB5xzHwDnnDMiAikSQohQStkVQrSklHUhxIIQYlpKea7b7Z5otVqvNZvN71Sr1WNj +Y2PdyclJefr0afGe97xHMMboe90nKa2cUgFwhdCuXbv8XC4X1Gq1TLFY3FAoFB7K5XL3+L5/M+f8 +2mw2uyaTyRQ8z7N/wxiLbZP7/YiIevbNVkqJTqeDTqdT63a75zudzrFOp7NvcXFxb6PReN7zvKlS +qdRptVrdnTt3hpet8Sm9YZQKgFVKRMS/+tWv5oMgyGez2W2VSuUD2Wz23iAItudyuQ1BEPiMMZgf +sDJGv4T6xPZd4RCGIRqNRrfdbp9st9uv1uv1Z+r1+lc9zzvV7Xabjz32WJMxJi9rhVK6LJQKgFVE +n/vc57w1a9aUAUyOjo6+P5/PP5rL5e7M5XLXZDIZ7jK6u09EfRn+cgkBl/ndMvNsc2x+QgjU63XR +bDaPNxqN5+r1+lc6nc43Pc+bnZqaWvzYxz4mLkvFUnrdlAqAVUBPPfXUGIAN5XL5RwqFwsOFQuH2 +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 + + + + diff --git a/fleet_rental/data/fleet_rental_data.xml~ b/fleet_rental/data/fleet_rental_data.xml~ new file mode 100644 index 000000000..85af91409 --- /dev/null +++ b/fleet_rental/data/fleet_rental_data.xml~ @@ -0,0 +1,738 @@ + + + + + Fleet Rental Service + service + + + + Rent + 3 + + + + User can only see his/her vehicle + + + + + + + [] + + + + + iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABHNCSVQICAgIfAhkiAAAAF96VFh0 +UmF3IHByb2ZpbGUgdHlwZSBBUFAxAAAImeNKT81LLcpMVigoyk/LzEnlUgADYxMuE0sTS6NEAwMD +CwMIMDQwMDYEkkZAtjlUKNEABZiYm6UBoblZspkpiM8FAE+6FWgbLdiMAAAgAElEQVR4nOy9ebQd +x3kf+Kvq7rvf+1asBEiQBAHuokhKokyQFLiYki3JUiLJSywfy0kc2c4Z2Y493o8zJ1GOk+NJ4jlj +j8exfEZOvESSY8uxFMtaQIoiAXAVKQIQse/b2++7++2qb/6opav7Lu89EKQewP4OLrq7ul93VXV9 +3/f7lqoGUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRS +SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkop +pZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU +UkoppZRSSiklh9j3ugIpXRoREXvhhRf8kZERPj09zWu1WmbNmjW3ZzKZO4Ig2Mo538w5X+d53gTn +vMI5L3iel+WcB5xzHwDnnDMiAikSQohQStkVQrSklHUhxIIQYlpKea7b7Z5otVqvNZvN71Sr1WNj +Y2PdyclJefr0afGe97xHMMboe90nKa2cUgFwhdCuXbv8XC4X1Gq1TLFY3FAoFB7K5XL3+L5/M+f8 +2mw2uyaTyRQ8z7N/wxiLbZP7/YiIevbNVkqJTqeDTqdT63a75zudzrFOp7NvcXFxb6PReN7zvKlS +qdRptVrdnTt3hpet8Sm9YZQKgFVKRMS/+tWv5oMgyGez2W2VSuUD2Wz23iAItudyuQ1BEPiMMZgf +sDJGv4T6xPZd4RCGIRqNRrfdbp9st9uv1uv1Z+r1+lc9zzvV7Xabjz32WJMxJi9rhVK6LJQKgFVE +n/vc57w1a9aUAUyOjo6+P5/PP5rL5e7M5XLXZDIZ7jK6u09EfRn+cgkBl/ndMvNsc2x+QgjU63XR +bDaPNxqN5+r1+lc6nc43Pc+bnZqaWvzYxz4mLkvFUnrdlAqAVUBPPfXUGIAN5XL5RwqFwsOFQuH2 +XC434nleX+2+nOOlypdL/Zi/X3m/YyKClBKtVgu1Wm2q0Wi8uLi4+JVOp/OlbDY79cADD8y9rsql +9LopFQDfI9q9e3e+2WxuHB8f/2A+n/9gsVi8K5/Pj3LOl4T0l6LtVyoIBjH+sPP9/Adm3/xarRaq +1eqFer2+p1qt/nW32/1muVw+/+53v7u5ogqmdFkoFQBvMn3ta1+bGBkZeXuxWPynpVJpRz6f3+T7 +/lCmX462Xw6DL1cILMX8g64ZhAr6CQMpJer1OhYXFw8uLCz8Q71e/zPG2KFHH310ZlmVTOmyUCoA +3iT65je/ublSqXywWCz+aKlUels2my1xzu35lWr9NwryL0WXYhIMiywQETqdDhYWFuaq1erTtVrt +z4noqZ07d56+3HVPqZdSAfAG065du7ZOTk7+k2Kx+MPFYnFrJpMJhmn5lTL9G83wS9FKkIC73w8d +dLtdLC4utubn519aXFz8s3a7/eXv//7vP/ZG1DslRakAeINo9+7dWwuFwicqlcqPlEqlLb7vc2Aw +w19Oe385lLzHcmD/UrRSv8CgrZQSi4uLYm5u7jsLCwt/2ul0/iYVBG8MpQLgMtMzzzxzXblc/kSp +VPq4y/hAb/jO3S53fxi9WWhgucJiKeZ39/shAiEEarVaODs7+51qtfqZMAz/5pFHHjnzuiqfUoxS +AXCZaO/evZVcLveT5XL5n5fL5e2+7wfm3DDGvxSm/17D/kE0TDBcChIwuQZhGGJubq69sLDwbLVa +/UPG2N/u3Lmz9ka04a1Gq3MkXWH04osvfqBcLv9CuVy+L5vN5k35pTB+v+PlnhtGK4X4b8RzLsU3 +4GYddrtdzM/PV2dnZ79cq9X+4NFHH33qkiqZkqVUALwO2r1799bR0dFfLJfLP1ooFEaY5pp+zH6p +Gn8ljHg57Pjl0OWo03IQwSCh0Gw2aWZm5sLCwsLvN5vNP33sscdOrqwFKRlKBcAlEBHxffv2/VSx +WPzFSqWyzfM8T0rZw+jL0frfCzg/iCm/l3VZCg30K6tWq93p6em9jUbjdx988MEvvpn1vlooFQAr +pFdeeWV7Npv99XK5/JFcLlcAejX9pcD+y0VvNAp4M+q9lDngXtvpdDAzMzM/Pz//B4uLi3/4+OOP +n3pDKniVUioAlklExF977bUfzWazv1Yul2/2PM8zTqqltP5KbPxl1uV1nb9UutzpxkkaNJ/APTcM +DUxNTT3TbDb/zYMPPvj111WRtxClAmAZdODAgQnO+a+USqWfyefzReh+czX+G6n1l5NsY6jbDdHq +hGi1u2h3Q3S6At2uQDcUCIWEEAJCEoSUmpkAxlTdPM7hcQbP8+B7DIHvIQg8ZAIf2cBHLhsgnw3g ++17Pcy9nvsKloAGdUUhTU1Mz8/Pz/yYMwz9JIwVLUyoAlqD9+/ffl8vl/nW5XH7Y9/3AtfUvxeZf +Di01086UdUOBWqONerONerODZrOLZruLUMqeOqlju2fusqw6kCQQCCDA9zny2QD5XAbFXAbFQhal +QhaZwO+5x+tBPivxCbghQykl5ubmmrOzs39RrVb//aOPPnpw2Q99C1IqAAYQEXmHDx/+4Uwm89vF +YnEr55y7kP9yav7lZtBJSVhYbGKh1sRivYXFRhudrgBYr/9BPzleH2bqA7DkqycCwREJSagdnejR +vpnAQ7mQRbmYx0gph5FyAZwnhc/KEcJKkYB5P0SExcVFMT09/Vyj0fjVHTt2fJOlS5b1pVQA9CEi +yh08ePAXCoXCLxUKhXFTnpyqu1SYr99x4jkDy2zsOxSYXahjrtrE/GIDtUbHQnbGODh37s+4c24A +w8WKGSxnJ6oS1S06L0mJCLWR+hRBGgaUalsuZDFSzmNspIjxkSICf/C6Bivto2EoILnfbrcxNTV1 +ulqt/srZs2f/e7oQSS+lAiBBR48eXSel/O1SqfSJTCaTM1oFGGzzr1TrLydFdnquhum5GmYX6lhs +dgAoAcQ1EzOmhBHjDK6m556C6JnARzYTION7CAKOwPPh+9rG5zymoVX+vfILCEEIhURXKN9BJxTo +dJQ/odXuQAi9shcBRFL/vbTMrwSFhNRmSLmQxfhIEZOjJUyOl4f200r7bJApYMpMFuHU1FR1bm7u +3xHRH+zYsWNx4EPegpQKAIcOHTp0q+d5ny4Wiz8YBIG19/tp/mGQfykapNUarQ4uzFQxNauYH5rB +uWV2o+G5NegL+QyK+RwK+QCFbAa5bIBMkHTSsSFHibo5/yep2xVotjtotruoNztoNNtotDqa8cma +Da5AkNrZCCJMjpexZqyE9ZMjyOcyl8VHMMwpaN6f9gu0Zmdn/2hubu533vve955b9oOuckoFgKZj +x47dB+B3SqXSDs55LMRn5u2/XuYfpO3nqw2cnVrAhZkqFhttBe0ZA/c4ACUEGONgnMH3PVSKeZSL +OZQKGZTy2SH1YLFNnzPx+vU96CMMjL+ACLVmG/VGG4v1Nqr1BrpdkRAECgkIISyDVgo5rJusYMOa +EYxWij11X2l/DhICRvgYIbCwsNCdnZ39wsLCwm8++uijR5f1kKuc3vICgIjY0aNHd3qe9+8LhcI9 +nucxIurL9IMEwDKf07OdqzZw+vwczk7No9kWWtsbTa+2nHNwj2O0UsRoKYdKMY9CLkCSuRn62fdL +kHvJUBdZ0k+QwAkOgqnWW1ioNTG/WIcIJWBQgPk5qKCQDbBx7SiuWT+G8ZGSqtLr7NtBP0PValXO +zMx8udls/soDDzywf9kPuUrpLS0AiIgdP378cc75f8jn83d4noek5l9umG/A/Xv2iZQn/+TZGZy+ +MIdmRwBQ2j7S9OpXzCv7eaxSQKWYUzdyPfjJsF5PmO9yEPXdHSgUtB9gsdHGXLWO2Wod9UZLmwRG +EKh9KQRAQD4bYNP6MVy7ceKSEMFSYUJrhmiq1WqYmZn5eqPR+Fc7dux4eWX9cXXRW1YAEBE7ceLE +exljv5vP529drsZfamAOC101Wx0cPzOD42dnsFhvWw3PnB/nDKOVAiZGShgfKSKb8fVLMhqeJfj9 +EjT/iqmfEBiSq2DaDUK7E2J2oY6ZhTrmq/UYEjD7UpsHlVIO122cxPWb1iCXDZbtXE32+VKIAADq +9TpmZmaeqNVqn3rwwQdfudSeudLpLSkAiIgdO3bsUd/3/2M+n78dGMz4K9H8w5j/+JlpHDk5hQuz +i8rG9zyl8TkH556F+WvGSpgcLSLwvChzhzHL+7FXljyGc/x63mxfcyBZmBQK1LNPZp+AbhhiZqGO +i7OLShAQgaSAFJF5IKUAScL6yQpu2LwWWzatWVGEZakcgQFC4OuNRuNTO3bs2Lfc7rma6C0nAIiI +nTp1agcR/ad8Pn8306PJwP3Xy/zJ7ex8HYdOXMDhU1Mg7dDj3NMa3wP3GMqlPNaNVbBuoozA14xv +nhfT8KYO0T6QZM0kIrgEMoKMsWi/9yKnRrCMT86+ORETBN0QF+cWcX6misVa0zELFPNLIUBSgoNw +43XrsG3LBoyNFF/XexgmBGq1Gk1PT3+53W5/6v777z+y4r66wuktJwCOHz/+dgC/l8/n7+ca9w9i +fmBwUk2S+g28g8cv4LVj5zFbbShm5xzMU1Df83wEgYcNa0axfqKCQi6jY/pmcEfaP9q49RjM6AnW +HFTjJdtkL0uADooxuCnvRQSx62yZ1r6NNi7MVnF2agHdbidifm0OGEEwMVrE9us3YNv1G9RzVuAk +HGYOmDwFIkKtVhOzs7Ofm5+f/+W32pJjbykBcP78+esbjcbvFYvF9+kv5PY4/C4H888vNrDv0Fm8 +dvw8CEzDfQP11f74aAnXrB3B5GjJMrxlcoYI/icQAIPmpb7w36nTkpVeslk9xPr+YdIZmHyA0vwR +KiD9T+UGTM3VcG5qAdPzi4BGAlIIGzmQQoADuPnGDbjlxk0YrRQuixBwHYNEhIWFhc7s7OwfEdFv +vOtd76qurGeuXOqd1nWVEhGVpqamPl0oFP6x53mBCfUtN9Y/4J52a/ZPnpvFc985jiOnp0HQzj3G +wbgP5itbf9OGCWzZOIFyMR+D+8SUHiUW1/6xZ2qBYHiKtO4lABIEIgYi97zS2Oan0nYT5xM/DDmn +ftT3mqiOrlCImyqmfrqByOcyKBdz4B7DYrMNIRXksHWFyiG4ML2A+YU6shkflVIeLi0lCIYlHJmo +TyaT8Yjo9kaj0f7MZz7zlllq7C2BAIgoOHr06K9mMplfy+Vy+STzrzTOP8jr/Mprp/Dya6dRa3Z1 +WM9TWt9XWr9cLmDzujFsnKyoe9tnRR7+GAro4+CL8VSSz/o56zG8bEADbduN4rYyqc+d4rUkdWxM +B3Ir6SIlipsFBJydnsep87Oo1VuQIoQUMjILtJOwXMjibTdfizu2X7usqEz0vMH+AJMxKITA1NTU +/Pz8/M/t2LHjz5fbXVcyXfUCgIj4sWPH/kkmk/m9bDY7JqW0zN9PCACD7cxBjN9qd/H8q8fxysHT +kMTAfQX11c8HOMfkWBnXbRjHRKVgtT5z4L7id1cYAP1eT6Shk2zX/7q4UFhCQiQDDINP9ynTngdH +EMX8AgN8AQaaqGKJ2YUGTpyfxczcovYDiNhWhgKcAXfdfC3uvv0GGy4cJgiWcgy6GYPdbhcXL148 +Va1Wf+KBBx54ok+Tryq6qgUAEbGTJ08+zBj7w3w+vzWZ2+8m+rgmgLt17hXbt17+hTqefeUovnv8 +ogrv+ZHW554P5nnYsGYE128YR7GQjTQ/XASAWMgvIg33KTqkATzsONpjhb18vnLjf0CgMVbVHkHQ +c30SCWhfgCMIDDKo1Vs4fm4W56bnQUIzvhCQYaj9Amp7y40b8Y47bsS49qOsRAi4TkDpZCgyxtBq +tXDx4sXd7Xb7p77v+77vuyvoqiuOrmoBcP78+etbrdYf53K59wDgwzT/MOg/SIOcm5rHnm8fxbGz +s8qz7/sK9vsemNb+m9eP4fqN48hlAjDONdMDAOvV+K7jz32+3Sr1GqFpBrLe9vi15qAXGQxBATGY +31Pct4wxl8GZ1voMZvp9LEzomgSOCRA3BdSv2e7g+LlZnDo/6wiBEDIUgBQQoUIFN167Fu9621Zs +WDu2bAQ3zBRwwoPh9PT0fyOiT13NTsGr1glIRPkLFy78Vi6X+zDnPEgyvrsPLO3xT3qTT56bwTef +O4QT5+eUk8/zAM38xJXm37x+HDdcM4FMEACMaYedYnrLHo7mdx1qErAOPonIgSdJLXghHYeetA4+ +x9kn4+X2Jyl+3OcX/Q1BQt2LED9PZPpE1S9WB7jX6OsAy+uuELLXmPP653sc5UIOQhLm6y17H0C1 +wWxn5mqYr9ZRKeUxUi7Y+y4nQpB0BrrbIAg4EW1rNBqzn/nMZ/YuebMrlK5KBEBE/PDhwz+Zz+f/ +cxAEZeP0S2r+pOd/wL16tkdPTeGp5w/i3GxNT9ZRHn5PQ37u+9i0fhw3bZpQS2XphTriTr+Eo891 +uiHhOwPiyjJ2nhzGiq51TRb3+kFlsdZrTd3rPY9fyxJlfU0DFr8+5r2IQZe4WUCkJhJ1uiEOn57C +qfNzgAyV5tdIgKSACEOQELhm3Rh23LMd129eu2xHrmsO9MsREELg/PnzU41G48fvv//+f+h7oyuc +rjoBQGqCz7s8z/uTXC53i2v3L5Xw0+dedmv2j5y8iF3PfhcXZuvgnmZ+z4fne2CeD+772LhuDNs2 +TSCXDQDmwH7Gncy+aBtjcvf5iLSj6zOLzlHP30balHru2SME+kkFt2rxIlueZHQzOcksTmQcgYb5 +k4LDFQK29ZRMHNJwXBJanS4OnZrC2YtzICEgRAgKlUlAQgsFKbFx7QgeeuctuGHzuhW/26QAMM7i +VquF8+fPP9loND7x0EMPHevfYVcu9a7keOVThTH2C0EQ3CSEGAj1lwof9WP+o6cu4ht7DuDszCI8 +zwcxD5JxeNyD5Mr+Hx8p4bp1owgCH5L0M11/uPGSW2+5OXC0uKPRo3q4AoH6CIXesl5+J+f6/hST +TclzCXdFxNxk910BEQkE0w/mbyjZKwCxqOH2WLUqCHxcu34czXYXU3NVEOOQjPSWA0xCAjh5dhZP +7N0Pzhi2bFprn208/PG2MNsf/fICGFNrCGQyGYyOjt4npfwXRPTrjDE5uPeuPLqqBACphTw/kc/n +f5AxFsv0M/surSRufOrcLL6x9wBOXVwA9zxIbdN7zINgatWeSiGHa9ePIZ/LQhCzDAAiqyVBWjUS +WT0YS6yJaXwayPiRnd3vbxM2dnQUZ/6kIOjjBEwKBJfRnSimZm4WEwymezkiRrNmAKPYPQGAxSQa +xQRWPpfB5vXjqLe6WKw3QIwgwEDgkNq3IqEmXe3aux+PeR42bZiwz+0nBNxzyWO3vFQqZZvN5k8/ +/fTTzwL4Hz03uYLpqhEAGvq/I5PJfDIIgqKBcEBc6y8nXJQUABdnqvjGngM4dnYOnHtK80Brfsb1 +5B4Pm9aNYbxSgIQa1IKicJ++IVwIQEQAc5nZaP7Irpf6pOy5xjEBSF/nCgxdboQG7LGpx2CKxfId +WG8SkRkiZjaMHjE21KImiAQBtwJDCcKYEDHPjPkGkvVV27FyHpvWjeHA8TYkI4B7yn7nHFJIgHFI +SBw+cQE+53jvQ3dhzXgl0bb4u++HAlyFIaWE53kYHR0da7fbv/jkk0++dDWZAleNAJiZmSkR0c8G +QXBjEvr3c/LZTLceZ1lcANQaLXx9z34cOH4B3PMAcACK6QU4PK5g6DVrR7FxogxBLrPoZ7lIV/9n +9HaMqZPa3jkXpfBG5dI9dv4u7iyMEAKQ5P3+gqBHM8dsfUcAJBGAw+zueR4TFuQIh6gcIKefKLaJ +6s2wcbKCaqON42enQWAg5kEgEgIEBkHAq4dOI5v18YM770Exn+3bTtvePijAbDnn1hQoFovvCMPw +J3bt2vXpnTt3hkNveoXQVSEAtNf/g7lc7kOMMd+Fe8Ns/z73ie0TEb6xez9ePHAazPPAmAfiTA02 +Y/szD+OlIjauqUBqlmHE4tqMkbJpmdHaDCpzn1kt7kJ6o/ljjE+ktbwJubmMTz1/70L/mFBIMtkA +SjK/KWMszrycJcqY1uaMaWHAwBlZocgYOQLBFQbOM5ICgKxVAAKwcbKCucUGZhdqas1BxkHgWgio +CkkAz75yBMVcFj+w8+6YwB80Bvr5AtztyMhIpt1u/2wYhk8CeGJoB14hdFUIgLm5uWuCIPiZIAhK +g6C/S4Ocfkno/8SzB/DUi0cgwcC1rQnmgRz4zzjHhsky8tmM0v5qPEaMr43liAmVFo2YNWJkG9eH +inEb5rbxd+fYFQDuBB8L+x0ecv0JTot1W+NMbk71C+XF7H5j71stb5g9ruk5i8pcxufOMeA4DGFM +kAT3O4f5bAbrJ0YwvdAAMQ/EJCRT70cyrnIlwCAl8MSe/aiU8tjxjluGjoFhKMCU+76P0dHRyW63 ++8l9+/Y9f9ttt13xnx674gUAEflHjx79yUwmc7cQgg2b1ruU08/sExFeee0Unnz2IDqhBPcDMMat +5udc+QCIcWyaqGD9RBlqZT8Nkw3zOwa+tjQtc0r9zMi2p1jCj9lGCTYR47vCIDIT+pgCQEwwxIXA +YATAEgeRxifdQhqKADhUmceUxjfMz2P7kd2vBIZzPxeqGBlqHYOqeP1EGVMLdZydmrfvQm01QpMM +EgyhCLFrzz6MjZRw27bNSyKBQREBQOULZLNZXigUfmBmZuaHAPzZwE68QuiKFgCkVve52ff9H/M8 +L5+U4EtBfn2PHs1/fmoeu/bsx3S1Ce75TrjJA2Mc4GrVnowfYO1YyTKdM1sflvlhIH8C6iPO3C6T +xzL8EJVFWXjx8zFTwFWWVvAMQgE9vWFqHvWj6kyHWSNRFtn8hvEpJgw4jzQ9t4gA1jyIBIFGBQBE +wjwA4EQHnLYQw9qxMs7N1iBDabU/Ma7CsxA2UnNhtopde1/FmokK1k6MxFo8bHz0QwGcc5TL5XKz +2fzkrl27vr5z587zw3p0tdMVLQAAZMMw/GfZbPZGd5bfckN//TS/lBJf370Pr52YBnOW52KcQzAO +j+koAPcwOVbERDmvvf2AAvjaijUAQKOBJNNbOK+3gkil3PbR+tJx/AnHNDBCwAoXVxCoYhc5aySS +sK9jpJlb193tM9cnwKC0fIQOEGdusy8ZGNeMrss4M36ASADwmENR+wiof7IQAEAlCWKiUsCa0RJO +X5izzK9MAQFiRiAwSGLYd/A0nhjfh4/+wLtj4yDpLxoUEjQ/IkIQBCiVSvd2Op2PEtHvX8m5AVes +ACA1zfdOzvkHAQTDsvv6IYFBmWBPPvtdfOulY5Dg4Nrjz5in4/pcDyoPHvewdrSIkJTdD+7wjKt5 +GYGkhpBJIUAE0RcB9IH8RHFkQP2Z3ipL0z6nzFX//fg/npMY9VfkoIucdqY8BvuBCPIjYmwjGLzE +PmMA51oIGBRh0IYjXEDk1M00Wr2vyZEiTk0tKMjPVF4AMQ6hfTaRMxXYtWcfNq4dw/333uy0rTdH +ICkcXCFg9ovFYq5er//k7t27/xbAiT7deUXQFSsAAGQA/FQQBJuI+i/w0Y9cxjdb8zt2+iKefO41 +ZfcHHgAGxjikXsCT6cw/Boa1I0WMlXMq28/arVBal5ldgvp8nuPZN8wN0hN24swvEkwvCPrz3L2h +wKQvQD8exhEYtTl+vIQdoO9i7H0N+ymy/61JYP0CbvjP9QswR8sTpIX/pJOnAC5JfacQZH0GrlkR +mR1OnoCMqjleyWO8UsSF2Sqk66hlIQgaERAHgSHsdrFr76vYvHES126cXKIPIkoqEiklgiBAuVy+ +bWpq6mNE9H9eqSjgihQARMRPnz59h+d5jxNRAPRq+eWG/YwgEELgG7v34/i5eXDf1xBSh/7AwJkH +MK6+0weO8XJep/oSGLGe+xr4b7W00ewgh7EB4QgAl/ml1vguWuhx/pl9IA73TQHcsmHQ3zkRU/6u +T4CcrS5nkTDglmHdEGC0byMBMB85dcwAUva/5K5PwNk3zzJ1caAPETA+UsC5mUWl8cFBkNoc0JmC +zGQKMhw+cQFP7NmHj3/4wdhY6Uf9zEUXCeRyuWw2m/3R3bt3fw5XKAq4IgUAgKDb7X48k8lY7W9o +OU6/JEkp8dTzr+Hpbx+D0GCWiMNjDMIyv7btGUcpl8FYKWc9/y5yjqX1IhICMY2eYHBBCilISjr8 +qAfuS0pCfeeZmvHdFhIhwfQ0QAboAU6mHRGxhGee6QsN6mEw2l2jARhTQGl7ax4YuE8yMgEYA5cq +YsDJERggSK59AY5j0NYRtiMxVsohmw1Qb4oI9pMxBZgS5tqAEQQ8sXcfbtqyHve9fVsM7qu2DncK +usgxCAIUCoXbFhYWPkRE/xdjrH/XrmK64gSAtv23e573GBH5Sdh/KZ7/6bkqvvn8QbS6Ep7vQYDp +DD9PL+LBNazk8MBQKeaQCXwIaeQCRU5/GB2pjpTWVzA+mjdPEO68fOkwPnQOAFFMcJC5j623elJS +GNg2xhuMAWdAFNn4pj/MVda1aZk/oYUReeuNp54BkKbMJv1ov4Bk+rPkkQngMQLjDBIETsYxqP0B +UpsDVvszbY4Yf4Xaz/hqodBqox0xu9X63KIAkx/QbHfxxJ59uGXrJoxWijEbfxD1CykTEYrFYqbR +aHxkz549XwBwxS0pfsUJAKhFTD7KOb+xn+3fj5JS3hARaeh/APuOXgD3fK3Vlc6SADyoVX0FGDgY +wDjKhSxCqeGvTvqhSB0m4HrkxTfMLhxoL6RjEsBEAqB9BJEQccN9sPeO2uMKgjgl2iz7XhS7ltm9 +6NoY0lEcGHcIGt+ANn9iDj04JgAZJyED54DQgkFoJMC10OA2ehDPIuyNDKgOqhTUBCwAitlNNIYx +CECbB3q1YTC8tP84nty7Dx945N4Ygkw6/JLkjjXjCygUCt4YwVcAACAASURBVPfOzc09CuCzQzp3 +VdIVJwBOnz59Hef8cSIKBiVyJIXBMMffkRPn8a0XDyMUBI8rT7/x9nPmQXIO0hEA4wMoFzIQ5uaS +DCYGtNNPajigPP5ak2t7XwmBuAkgSTM+krkBFPm7HFMgZu875yOKa3xKXtxDSyHXCGLYXAeyTY68 +9VJqr706lsYPANcngMgnQNw6CBUaMFmDDB454UI4SIO5IVfdsUQo5TNgDAgpgvtGCEidJCQBHRZU +gveJ3fvwtlu24Lpr1gxt/aDQsSkvFAq5RqPxj3bt2vWlnTt3Ti/RmauKrigBQETeiRMnHuKc3wzE +mX0lKb9mG4Yhnnj2NTXF1w9sNplSOZ6G/goBmKFcyWWQ1/Af2gmmEICKBSotLUHErAAwUD+y9RMC +wPHymzI4yCHS+HEL3jHL9XEvvB9e0NM7gzregQVKJNmMR63RjSAwleK6UOtkiwY4Z5CWqaUVBpwz +kCnnaukze86YBAwq5Ko4X7G3lpD5jI9CLoPZxRCgSACQSRGGkyaszYOjZy7iyb378PEPP2SbupwU +4X4oIJfL3R+G4e24wuYIXFEC4OzZs6NE9CEiKq/E5gcScFlr1/2HT+OZbx+1jjlY/eapccw4iJTX +nxgHJ45cJlCxf3LuywCzoEXknZfW5pcysu2N9ok7+iKUYJ18iLQ+kLD5gR5e7Q8AaMAFfS5OmBM9 +pE0H09WxhCJr/0fXWKeauafODxBCCQGj1TmMY5DUnAsOcNJZhNBmAFcCRcKI4aimzKl7LpeBrDZh +1l4k4xCEygtQx1oYaNT15N79eNddN2Hb9RtjpuJSYyo57nK53Hi9Xv/I888//+y9997bGPrHq4iu +GAGgQ3+3c87fDvSX1IOSfdxj8wvDEE8+dxAX5uvgnsr1F0x9uBOMwcb8GVPf7COlofJZX+lAA/1d +z7D+xeF85PlX2X4UEwpu2I8o0vKm6tLhdusDcNs0VBLEGt+vsGe396rECaPx+92TEDnplBSwsXxz +KeMACYUjOFMOQyUAtJYnZRJ4OrvS48o5aN6viSgArjBQHZcLPGduhXH6cesUFBoRCNKmAICzU3N4 +6rn92Hb9xlgkoJ/9b8655w0KyGazLJvN7my1WhsBHO77x6uQrhgBAMATQvwgY2wj0N/Wd8uT5DK/ +lBIHjpzBnpePKijvKwbnyl0FgoL+2noFN5YsMWQCD2E06V85/0htSaOA+Aq7ZGP8RjAox18iv9/4 +CwyTu8LAtiHRpoGQvafxS3TtEO0fkzrxs6zf8x00EDGq7S5tKpB1CioHIbN+ABMGFFJlC6rZvlEy +EXPuZ+8N1dlBEFhhqxKwFNNLmNWVDSrQwoEYhEYBD73zNmzdsiFq2wBzsp85AKjchlwud3Oz2XyY +iI5cKSHBK0YAnDx5cjNj7AEiYq7XFhjM9IMoDEN86/mDOD/XUNrfuK0103vabiRi8BiDJA6Q0lK+ +5yG0HKru5y7tZSfvAPHYvnTTfuPJPhHcR4+jrz/zu+ZMvxauAPo7+73Mn3xIfxQRh+TMuZJ0VMDJ +7de+AGm0uXElqC5WCEELVskYPEbgxNQ6DIgnGzGKtyHwtHYHbFRGMkcYaweg1JEBgnoHZy7O4VvP +H8CN161f1jgaggJ4EATvfe655/4KwMySN1oFdEUIACLi586du6Pb7W5zy4dp+6TEdrX/6fMz2PPK +cRteg4aKOp8NZoEJBg4Qjw1qj6tBBiK7jqXjD4tB/1hev3Q1fjzrz4b4LOyPa+SVMX9PZww6kbzd +EPg/WNOb66IeciIFmmITe0woj0m9zgIgOYEJPX2YoPwA+lriGh2QzinQUQBuF16Lnu15XAlUqYQv +EQPpEKPV/oxp84Drd6KOv/ncAbzvPXdj7cRI38SyYSFBs+/7PoIgeGe9Xt+AK0QA8KUvWRXkdzqd +H5BSjgO9jL+U9z9p+z/9wiEcPTsHIQgET8/zZ85UUq0htJ2oNLdifMYZhCSERBASCAkIJSEUpLfK +yZcsC6WC/kISupIgpFTH+j7GMRhKqU0Gc44QRQeciIKEI2CSkQX90/fq/zNOSbLPG3xNn3snyoRb +N1f4SYIgiZB0u6SEkFKVSwlBEkIogdiVEqGUCIXaCrMvyPmpfusKafswJHWOMfWuYj/oHADrE4jy +BKR+v6EkHDx2Dt967kBsvAwbU4PGXzabvYZz/r7Pfe5zV8RHd64IBHDixIlrANwDICZxkxJ4OU7A +breLPa8cg5ASpFtPEmrmHymbX+HSKPTHtIUAPYBCUqjBhMRimX8SkcffHFNvvj9RfJqvW99krk5y +Yk9fGojfh5QPQxDDYH/yHCVq6Xj9WOyyXiRgQ4KSwLjqE4+zyCwwjkK4vgCFAqSDLMzzhHRRn9bw +Uq0zAEcQSKi04CgiIPH0i9/Fhx9/V0/cvx+zuwlDblk2m4Xv+w9u3rz5MwBmh/TwqqBVLwCIyLtw +4cLtrVbrBlM2yE5zp2+6ZeYnhMDulw7h+X2nwHzfzuNXVyuGN45AzrXXGAAnbsN+Us/u0zWxtq6C +/sxhdlimT2pM41eTGt8bT3/M32bqH2vfwE4a8lfL/ZsV3M89309QkLsT+QUAJ1RIkTOPjHNPqMxK +KSQ8xlVEwIYA1VwB6TgDOdeRBlsN0rkW2qwzJhmUIAAYBCmtHyE7k2nJ8czzr2Hvtw/iXXdtiy0r +lxxP/ciMSd/3kclk7pVSrkcqAC4LsXa7/R4hxJj7NV8gjgbcrSGX+Q383/PyUYRSghHBg8oVN2wP +HfYT2n70SA0YomjGX1tI+OBWmzkzU63HP4oAuGVOudX8CQdgouHL0/zLcQREd7R/M8jXJRPX9jC/ +u9On0rZO/XwEipgjGJj2/CvHHikhwAAySUKkcwO049CsHMS1Q8/em7R5YBCVee82tdo4Ap3EIDj7 +UoKExJ6XlADol/Fn9l1F0+9cEATr6/X6A0T0XbbKpwmvegEwNTU1SUT3LgX3lyIpJWbmqnhh/ykI +UvnnkEpLKDef8eSpNQBIO4c4mRCgGmjNUCLnQkTDpkabwGh+zfwm3i91fj9RjOGt1x8JxbpcqB6j +oZg+vks9pfFKDDMBXEHS1/SIymOviex/NlUHjFmHnhIG0dwBGx7UIVp3sRHGTUgwWpOgFQoIbT9Z +JyCY7e/IPGNWKJjcDPXOJHa/+F385Ecexki5sOwxNsAMeOCJJ574MwCreuHQVS0AiIjNzs5uAXBD +crpmP62fNAGS2n/vy0dx8MQUvCCj9Ib2CAMcITF4FvKrwWfy/Zme+AMQGm0BnxvEYJjYDHs3l9/4 +Achh/ggVAJG339zDtiPWCYlOYYmLo8Yvt1ftjfozv8vUg0wBV3oMMA/MOdt1vUjChPRU90q7nLpC +ACZJSE8S4lGegGQELnT83cxfBtBohwiFDQHY6lj4rywGCBZFZIRODTbobN+hM3j25UN4bMfb+joC +k8jARQFm63kegiC4p1wul5EKgNdFrN1u3ymEWBsrXKH2N/b/C/tPWA1hwh/MWKga/pOO/ytkoOxE +RjqYzBmaXYlCTtu1rvaGSfRJaH6K2/7GwSedARofZgnYn2xqv9l8fS/s2xPOnhx0agCQcAtZHCmw +xCV9nISxXIEYyKAoa1DDecZNdzOdH0CQIjIFGGMqdIgoIROQaHRC3efMOFgA6eRmuD8YR6AOCwJ2 +gZbnXj6ER++/U7V0BSjAJd/3r5dSbgVwblk3+B7RqhYAx48fz3DO75NSZjzPWzL8B0TaNZn5t1hr +4NsHTimtbhQEMe1g0lkopBxPYMzGkhkjPeVXCYpaJ8SYzMCCdIYYY5PV/Ij5BAwMhUECWjs6aDze +juSOZapEmwdA9SguzxLXLWFRDIL+Fq30kRSUeEY/ZGAgv6lf7DZk0QADAxNqjQAjSD29ZJgks5Yg +qe8vmOiMvl+9Haop1Pq9Wz8AmUiMdgKakCDT2l+S9vuocOyzLx9Cq91FPpeBizwH5QK41zgThLL1 +ev3+Xbt27V7NXxFatQJAw//Jer2+/VI0vrsvhMCL+47jwPGLKvMvAHS6GYjUDD4PTNvjLNJYpL3V +kgAuAelhsSXUWgAwzGBsP4MC4gt5GEFAzvwA9/p+bDnUBDCaW5cP6hkyZ+16ftFzkezPHo1N8RsT +Icp66kcy6vO+0ixqaUwI6PApM6YCTJYfwIRZK5CBZDQtmKQudzIBzT1rza615221zU8Yza/zFsDs +wisCKl+AdLbmdw6ewkv7juLdd2/vCfstlzKZDHzfv3t8fDwLIBUAl0Asn89vWFhYuAa4NNhvBqUQ +Ai8dOKkSf3zFjB6Ys3gni7YKwyskACjNL6P5ZfV2F8LRxhHiYBbWC6N5EI8GkNb8/XxnRrOSgRUD +mM2Nq9vd5Dre7gWOyRChiuQNYncfcA0lynsqETs30IlJSoOrattWK6Y3Qo0pJyDJSCCopCwdEhSk +nIBklgtT7a+3ulGURSqGJu3ti8wwppOEIpNMkEmsUiFEKQkvfOcI3n339ph2XwkxxuB53m2+72cB +1Ff0x28irWYBgEajsS0Mw/WDvvLrUj94ZuB/t9vFq4fPQoBAgoF80opRp56SdhSpFSOUDUlqAClv +M7c2f60VotbsIp9RqwZb3UaRzW9+Qmu22Dp++jFx/lAnojZE9jlLMCX1MDviDNpHcAwUJwkY3vfv +rbAaxPjO3w4UDkBkd6l+73FmklnwQz+ToqXEGADS04PtHALrMFR91ex0UW11rfB14T8R2e8DqMxE +sz4gs0KAAGsGSEl4af/RHuZfaoZgMhrged4N3W73OqzifIDVLABYq9V6G4As0F8CD0sIcpN/Ls4s +4MDRCxoBKE3PmJqDLjTwNBYoDGKmCP6bgQhtIsw3Q2R8D8aRFoWanCQfJCAoHO3vSAPXjZhE3gDs +bEOnQDfeLVPHzD1BduWMpLvP+SN3G9/te02CAciWUXSOeq6AlSJ29WRK3ItZIWZmCQq9VoBZAISE +Zn49SYiTVMJRC4CFegddzcEWAZhxILVmJ7JmAFHCHCBtBmik8MqBE5ieq2JyrDIUBfTzDRg/gO/7 +uVqtdicRfXu1zg5czQKgCOCmYRf0s8uSL0NKif2Hz+Di7CK4n7ExfjVrzHzFU0l9T/8phypmUmeb +aSHAGSAhsdDqYryU0Q9kMcaO7Hx3qm/E/KqORuA4rEmR2w4u05ttrJms76e0I/5yoTiG2PyIM2X8 +omhrYQ5DT8XIrWAE6e25nvvrMkKE+R1hpYqVM9CmAOtbMcP8zDEdoMrnGx1lglloL9VtKYL2doKW +WZ5NKgewSgnWEQX9wdfzMwvYf+gUHnznbU63LT3eXAqCAJzz2z//+c9zIFpFbjXRqhUA7XZ7Ugix +HkAsLXM5lEQAB49fADMr/HrqR+AqJCiVM1ClpjLLsUQqQcjmfBtGkMBcvY21pSyyvpk3EPGIFQKA +DkEpTaP+Mc0vMlFfLMn0cf2hTIGtEwU8tG0COU/5HyYKPso5HyQlTsw20AkFiID1lSwCD6g2Q0zX +OxoiR30VSkLgKaFUyHhYW8rg1FwLC22B+WYXpxc6OLfYRr0tE7a9Kxzcirv7DjKwp6VFD8zR/gYF +QTv4mJETzAnbmqo7UYN2N8RcvW1DvLD2vhsFUO9DaBQndI6G1BO0AP3xFy8EF2oFqNeOnMGD77xt +RX4ANyeAcw7P87bv2LEjC2BVrhK0KgUAEfFmsznR6XTW6ONLuQdMAtDR0zNgnCkBoF80MQ7maVsQ +BA+RYwg6/Edch5tAWusou7PRIcw1ulhTzsLYmuqZCrJHpoTj9UcU+2dOm0iptj5Mz2JMTyBHkxM+ +dNsa/NT9W+Bxjn1nZvFrX3hRRSeMo4FxqzoN0zJAlZsKxXcQQXN1D849XDdZwJpyFg9t3YhXzlWx +58SC8ycMDFL7/2KV1U/TX05Ivj9yH2+W63AarxcXNTkajAhkj5Vw5eajLIwwW2+j0QntzUn3g5AE +UrOxrANQIQAZJQGBgXseIEKlGIQHxiUgBQ4eO3vJTkDHCb1FCJFDKgBWRkQ0LqWcXGqqr742tm8z +7aREGIY4cW5OMT9XTA+Pg3sMYJ5VLcLVZiTtBCAGNQ+ApFnaWl031+hgopiJ9Jxmfji2pzSwmEy6 +sLHJKQHpHQZwGJOSTTVIQQoUA/VxDQC4ecMo1o0UcXqxE90H5DC71q7QBvYgh5+9Vt1CADg608TR +qTr2HpnGu29cg597YAv+67OnsdDsRn1vPXVO3Q2iSj6GjEM0koxRM01evwEFMhICuu+Nx8Yuw04K +kRnkpZ4tHQegMzFLSuWc1T/GCNAhRXBPL0SgQhCMMxw+cd6p9tJKqN/Y5JxvApBf8o+/R7Rq1wNo +Nps3SCkrg7z+S5GJAMwt1HHq3CygbTuYD31wT00v1d/8Y5wrOAilGVRoiKy2iE/0Icw2Opipd+yc +dglp4aSQZvUfMx+faXuT7Ey0KCMN0RRVfe++1yBKJ5YgfPGlk+gIZeR6nOPDb98E6WUg/RxkkAUF +OZCfUT9zHGSjYz+IzttfoK/NgLwMiEfXSM/H00em8dlnDuHj79iIh26aUH0DFrURUf2JUXRs2kGq +fyVJ7RMhy5DRAqqItLQO5Zn1A6ReN8GskyAkYbbWwmytrd+V+Xt9XyntWgt2/QX9PlUugafevx4L +0CaiGicejp+Zxly1tmIE6o5Xz/NGp6enr1vRDd5EWrUIQIdP+nL9MGGQRAAnz81gsdGBp5f9BjMv +m4Fpqa9uxwEvmmcOiuLLTCqoSWBg0lMImxhm612Ucr6jsSIFaiE+lGayZq4TOXA1X9Q4dY+sR/hH +d63Hu68fh2fsSgDzrS7+/LlTePVkA//wygm8/+4bAAIeu/0a/Pdvn8O5hgTsbEWj7d2wWwJuxxyH +iYChMU08T8FjHmK+GeL3vrYP77t9M37psa34zNPHMdsK4TryEOsDx8QxJpZ5HoueF8uxJ2NHKyZn +OgdA+QyMJaSgw2ytbTwK+j1IG2WJvq1g5mNo5uQAI+58rYSBPA4mmVYUCgFU602cOjONsUppSVOg +XzRAhwJZq9XaAuCZvn/4PabVKgDyxgHokulk1xub3DdkEMDZi/P2hSonoIZ7WusTY2CepwWC9jkz +paWYhFoOnBMgdeiQq4R/YgxzzS4qDeV4i8ag4+1Hj4Wt2mGuQ1RAMINLQfxPf+gW3HnNuNP26D7b +15bwo388p1Yw1mLK4ww/++D1+M3/dVglNmhmYJwptWjjhH0EADk4nFj8WAtBAgAvUOipy/DlV0/j +hRNT+NTDt2DXoWnsOjQdMx/ICJRkvzDD4No+d3rHrM4gjSkgTIKQK5A1dAfDYrONuXrLIglTXUkE +EtJOyCIpI2cu0+9ZrTYK4tx579x+Co7pNOHT52dwx83XLWu89YsS6BT2VYsAVqsJUBZCjCULh0nh +ftJXSompuZp+8VzbkWrLPeUPYNx8Blxbl0xZncp8ZhqKJpa+ghrXoRCYqbf1eW0KGAiLaCXg+PoA +ZsksdR8FiU3WIOl18gRuv2bUtiXZ2ko+QDkD7Ni+0SlluHfLJH7i3g3W50CIFsGUzJgR+pPZnKkf +9AczGHN++loW/a36mIYSiBRkIP0sztU6+K2/eQHrCj5+/2Nvx/+2cyvWlQNIrZNJ+zFkFFxR7Qfp +JdfUNaZ/DIy3tjtgs/ZUf2qTSioBPVtrIxTO9SR1eM/J6rNjxkBzFVViXKMMrsaG53H11WItEJj+ +IMy5i3NLjjV3TPY7p/0Aq5JWKwIoCCHKy0n+SU4HNlsTApyeq6lYvtbwxLWkBwDY1ScVHIxuCisU +GLPxZQblGDTZA4yA2XqIQtDGmlIWD28bQ+DxXo4l4Ma1Reu0M6nHR2caavqqcW3pvP3tawqRgdDf +CMLO7WtRyWd6yn/sHddh/Ugef7T3FOZadkKzqgSPHIB2LaQYKkAUbbDIQLdWqgaTQRLcV9BZcPzZ +s0fwzOGz+M0P3oPv+9g9+KX/8RJOzrWiAIDUIN3E742JFsEOWP2uE3tIRohAWU7mGqXt5+otzNRa +tn0kpUZuFPkX9BPUGOFgTCoNr/uccb0MnEF/LBon4ByMGC7MzMe0e3L6b3J6cJL09Wt7TqwSWq0C +IC+EKA2ajz0IhrnHBgHMLNS1Rjdf+WWRw8fR+mBQOQJ6PTpmyhBt1RdslYOQG9gOgdlaC//hQ9vx +0C3rTdKwru8KWkwRGxprHEBvmr+mf/GeW3vKjKfgkW3r8Mi2tTgyXY+FHpM36kqBY7ON6KFOZWLM +Z4vJvcTuEBEgQhw8N4uHb7sO/+kjd+OpwxdRa4c4O9fEYifE2bkGap0QZ+aaAFgiw5FBqtlSNs7P +TG2Jaf+CKSO0ugp52aiKti3sx1SdMCKg3yW3sgWMafufGJjQqE+bBqRBMeNqReHp2arT/OHjbsiE +oYl+hauBVq0AkFIWk4WDbP9+10kpIYRAdbGlIR0DOGnHn2Zq820/Hg0WArNCANCwEXqsMQZBFFuO +igOYzAH33TgJomiCUU/NrH08QCqw+OB3y5dDWp87f8KwdbK0pBC6bf3I8h6wAhotZPGBOzcPPD9f +b+NCtYlTc3VUW10cvrCICwtNHDhXRbXVhZGGkiKMoICJcvDNLLZRb6m4f5R+La2JYdcXYFzN4iT9 +frVQMKYgaYegyvvQyNDjIMHBpFIQcwv1pZi7xxfQ59woVimtVgGQlVIW+p3otwKQ2Xe3Zr9ab1ko +z5gF75oRzdco7LIgkcplPGIo7Q8wyEAxv/rgpZRAwKSeZ64Eivv5Kl0RtSy4kMhmTJcbR53TLpeL +L4GSgmMlAOTNpNFiFqPFLLZviPMFATg7V8P+M/P47vkFfGP/OVystqKTxDBfb2G20XImVDEQhM0D +MMKPMQ5GetEA4gATivFFBOzADBrwwFgI++J0PgBjDAuLUf5OPzNgKRNAl5dfd6e9QbRaBUBARPl+ +9n5SEg+SvlJ7fmvNjn6ZGtZpB5AZF+BmRSBjCnBri4PxSKMzwPpMWWSPAgKP3XYNwDlCAnwdtnKR +QEdI/Owf/T0+cO9W/NA7t+u6At0whOcZoyHiWFcG9KDuuJqPTIVYR/Xe53IJA+rZ6a1L8nSPUBtU +GQI2jpawcbSER27bhJ995Fa8fGIGX993Bt84cBZn55qYq3egZhMaga9iBmp6sHE6MB1hNL4PBf8Z +OTklTH3yPXq/KkuUdAQATDk+F3WUwVbREQI91e+DEnRZD5pdLbSaBUAu2dHDYJhL5m+EEGh1uupT +1ebFW9Nff/jTanz7x7DOMWWE6nIFF4nUNwSIKXh6/3Uj+LnH3wahpxMzBsCLrAsAePq7Z/DqhTp+ +fcs6W8dvfOc4fu0vn0Y+w/G5n/8g1o6ULCKwHnNTJd0mUxZZL5Flb3yZyd65FMZ3mZwQJSMRkTN3 +Xp0zn/D2ufqyj+c80LTDrpxM1CM3ovcZZfkZtAUw3HHtJO64dhKfet+d+Pqrp/D5vUfwNy+c1NeQ +AXCAdSM6tpTeV7M5nYxCfW9r93NuO5HZzuRgnodmu2PrvpKx5+5LKVdtJuBqFgCBOXCTe5aipCnQ +6YRR7Jcpxw/Xy8uQigmpPHOmPVDcjARoLaP2lVyQ6gMiKkEAPg/xr3/oDnDPs2vMCwYEIMBj8JXy +wbVrRvHpH74f168dtQwQZAKUJ9bg5vVljJbyEbNTlPlnGMam+CPhIHRW0FVTZB1hYO7Xb8wO6Uoj +ZFSuPCGUQHfIwtYmrbbrLHLg6+4zi20MpyhiE3a7YIwhk83A5zz2AVEAePDWzXjwls348fvP4lf/ +ci8OX1yENvdhjThGUDM0ZSQYSAl6ZRaQDQGq6uo1oe1YYFY5EIBON1rMZyVCwB2vnuclwzWrhlar +APCIyF8J4wP9/QChXl+OafHPPD1UNBqIqU99GC0HZG7MoJL8uT6nBtSHb1+DTWtGYppaEhAKoCUJ +WQ4EHNi8poLr1lScBSyBB7Zvwte2b7LrBtiPWur6R1o3jgoMGXDCmEED0bJZjkcjAjDmvnByEtx7 +OWQY185pEEKZVDY6gBiU9jyuIbQiV2DYe5gA/4D31mi18NLhk7hh/SQ2TI5D+r59rsoGBHzO4HGO +e25Yh6/86gfwH7/0In7/a/vBDTRzYD9n5p3puoJZ5lcAwYwDaF+A2rHJYbpt3TAcGAZcipxxuFr5 +bNVWjBNR32+rJV/GIIqEgQSDF/kANBSMMHYEPMHUKrTMwEhnYDHiIE7W/vSpi5/eeTPAmMozFyoj +hakpoGBgaAmgozVjwJVmNJ+1svU0bUIEq3XagQOdh/SUIwRMawCKafJLJUmEdquFVquJMAx1Xxj7 +WTGJ53nIZnPIZLOxj2q66djtVgudTtv6ZZLEGMO5uUX8ya5XUG208dmf/yi8TgetdgvdThehiKbS +57MZlAp5FHI5/Kv3342MB/znv9+vFxGN7qcWDuUgJvTqQcyaAcochFUKcBg+2lfnqM8s/kH2/6By +AKv2O4GrVQB4QK89tdwwoEu+75l0EGuTM8Pz+p3HZucpKwHMmAH6UtKaHxwgSfj+7RNYN1aCEBIi +DNHpdtDtdOB5HvKFInzftzCSA+joRSl9Fq16Y5g9xvh9tkvSJTC50co2RZYrp5hLQki8fPIcnjp0 +Esdm6/pRhErgYzQfAETI+T4+cvc2jI2OIJfLg3M1D0F0Q51FKfHSkZN45uAptLv6o9yEaKvf8Vip +iA/cuw03rRuDDLt47uBJfHHPfrx2blYlEpExdzju3boBv/zRnRgtl3BuuopK3sdiW8TeLyMOxoUO +5+kRQM44MEJCO2zdMWGYn3EG7i+dLNtvnLq00olsbyatVgEAqCzZ1y05Mz5HWyjtr2LDep8pNADo +hT8Am0MfCQEdS9a2pDUTSOA9N68BGEO73cbRc1PYd2IK/983vo1P7Lwd73vXbSh4RbWuveMsMwlE +g8xySuy7ZZeL1ACV6Ha66HTaCIWA73kIggyCTAbuCEw1dAAAIABJREFU59cY5/jasQt4brYL+EXt +WQfOhAJY0MtvhXXs/+qL+PkHbse169cgl8uDMeD41Cw8khgt5vD/fGs/prt6Nr9ZqJNg86RVneoA +LmAiw/Eb778Hn/7iXpxZDEHMA5GvXH76bw49exySPYmPPnAnfua9d+GbB7+CLnlod0S0hDvTUQHm +TIqyil3tcGbCgw4CAKwJQIwhE/ixvruUWalYpasBAat3LoCEXkr5UvwA7t/kMkFC8zOrgZh29DGm +vdmIYviMpHIawSJDbWczgEJcv7aiphtXF/E7f/UMvv/uG1EeHce/+9KrePnoWQghohx/KOYPXW3v +/Nyw3Rv5k6QWSGm3O5it1fHVA0fxmT3fwVf2HcF0dRHtdhthGKovJ0MJgJ++/22oTIzCGxsDHxkH +q4zCGx2HNzYOPjYBb2wC5/0C/u2Tr+DYuYtot9tYaLRwdHoev/bFp/Ds8fO4dcs14OURsMoYWGUM +vDwGVhoFSqOg0ihQGgErVcByRZyuh/iLvQdx7TXrwUsj8Eqj8EoVeMUReIUyeHEEXmkcz56Yx82b +12HPa6fwKz90D7pdaZld+XsjYW/hPyNw5cZVJowJDzNzHtY8gDYX8tlgReMvOQ41rdplwVerAAil +lJ2kU29YxtWgsnw+o1+mCQXpgaLVmWJ0cphcfW6KMeU0gkUCWmOAAJIYK2ZBUuK/Pvkqqh1ACgHy +M5hcM44Xjl1Ep92GFNFMFSLS686TjTT2qHwY7Xj5fyQlRLeLVrOB3UdP4WtHz+CvTs3i6ZrAX56Y +xhcPnsTXDx5Hq9mA6HZVbj0Rxot5/Nxd18PzPbCMB54NwHMZ8GwWXjYDlsuDj4ygXqjg/957EM1O +B6WMh4dvvg43bN6AJ05M4/13XA8WZMCCLFgmA5bNgGUCsEwGPJMBy2QBP4MG81FjWZysCTx+1/Vg +XgB4Ppjv620A5nlgmQzmu8DsYhN/t/cAfvCerfjAXRvBoLM8oSI9hvlNUg+3sJ9HSJ8IZlUjwHEY +MjN+sgPHYL9xN2Csdnr+aJXQqhUAnPNmvxMrRQSlfMZ+U868dLOyj3L+8yiu7uSQqzlDKoZsBhVZ +zlWCIhQSTenhYgs4O1/HPdeOoZLPI+DAc4dOac+5o4EBtAXQEYSuBELzIzNDsD9CuBw/IQmNVhOf +f/k1nG008dG3bccHb70B/sg4vu+Gzfipe2+D53v4zPP70Gg1Eeq6c87w7k2T+OU7NiLn8WhtAJ+D +PA74nmLiUhlnWQZ/ve8oRvMZPHnsDM60BH7k3u24c9Mk7lhTVKPN06E2zgCPgbj6BuNiV6DalRCe +h4YEHrllEwAJ7psFOgxsZ2DMw/VrKrhh/Rh++8cfg+QePvHw7QBpRauTMEj7bOwsQGcMWKvOU55/ +iwqMomAqIbBczC1rnC3hBGz1nFgltFp9ACGAhtup/Tp4kCBw7bSRUh4MC44Z4Hj9NRoA1yklXIeK +mJ7GSlBOP1ICQ92Ag4OQ9TkOnpnCP77vJuy84zr81uefxScfvgX/a/8FfPa5BfwYEe679Ya+NnxL +Ar7xR5i22DY57VtmZy1FRIQw7GL/uSn83fkF/PANGxCGId69fgxfOL+AOyaK6IoQAQOenK7h1pPn +sGPrFnDOUQw4fAY8eu0Eto0V8KXTc/jOfBMBgHsminhg/Qi2lPM2YuFpRvvInTfhQ3dstfkR/8fD +d+D3nz+CJ0/NocvULEJIoBOGaHQE2lKtXUA+x01rK7h5/Rhu31jB/pkWjCd1bTmPdcUs3nZNBf9s +xzZ4vo8tG9egGUrkcwEYCXDm6/erviBEejEXzrgW8CzSAtKZAeKMDxPuJDCMlou23O3PYX3dB7mm +HwZZIXUYYzWg16ZfzsQMcy1jDCOlnOvYdQJkpMJ8JkIA0vPTVdgQMOvTUcSlXLkLBWOoNTs4fn4G +hcDDnVvW4rd+6G785hdfxlzIAS+L87UuFGro38CukSe6Xm+kn1jqeQj/8/QM2MgI9s43sLPZRNkP +cG2GIU8SrWYLXz4/Bz46hr8+PYP7tmyCH2TgAQh0uvT1lQL+5W2FmNAyVgacUKZaNyFa6osIKGQD +/OqOm/G/S4kT83VwRqi2Qhybq9kbERFuXTuCLWNFgDH83b98HK9dWAARcOvGMfVVZu3PE0RohkAr +1GsISICTCsMyE/8nqZGf8Qfw6EvP2qFpkYAb9bFhQGC0UugZU/2o3xh1yhbfgNd6WWjVCgDO+aIQ +w52n/QRBMlljrFLQ7ztacNIyNmC/Pgsdw+aMQzKlNRi3n6t0OFT5DOZqTbS6Ar/7pRfwyG2bsWnN +CDZOlDE/LxAKiUoxbxfRGNoGU6dozF12EpJwarGOuSCDyUoRJxYX8T+PncH7Nq3FHUUPr87Mo95s +4iRxeJUyLtaAIws13JzNR59I71MxZv9TDlShGT8koCsploPgMWVW+R7HtskyfK4crvddOxFHQRTt +ZwMfd14zEXeXaOZvC6ApyCZQAQR4ZGf3cWgMLx0mN/1s/MDGESgjmz/KnFQXToyWoqhIn05YyhzV +5xeGXvQ9pNUqANqMsfmkJF1qXkC/lzExWoRZ2ddo24jjCCCpnX0qS04tAa6+Jc8I8Lj6GIUZNeR5 +4AAuLjTQJoZFyuKl8w3sm2nhYhNYN1pCwAjb9TTb5cJ4AzQsFF1hhw2/N+H4Yg2/fddNKGez+Mq5 +aXzh8Em8ungC6wpZvFxr44SUuGmigk/esAkz7Q6OTM9g+5pJhBIQOgeCDxECBg10CWhrH4chbqIt ++h2YdUnMnB4zZyfWVwlTyEQOCYSOBBqCdJKVQhz1Vkdrf6YW9tTpjnb9P4RqOriMO/lg+13CJAG5 +6dMTY/GJfEuNuwHjNf002Aqp7fv+XKcTTcQwNMwEYIzFkls455gcK+n9mB6xG8XXagR6AMChvkjD +OYi4nSDCoJa2YowgPY4T01WMj5bx//7zR3DLhlG02y38l6cO4q/2zyJgISDV8lUr8bJaNAAgBjpe +J0kiTDeaYN0OmjLEg6N5vP3OG/CHx8/jxZABlRyOSIlPjhRQgkAxYHi524UkQkOovsx7cSEQY0pS +zFgXSjMnSRDQDRXz+gzIegwBV/t2aQYWtd+QgfuRaaEyK+thtLQ46QjHYrMFQGt00vn+kmvhL8E8 +rtcYlEooSLUoiUIADoogPSmJK9Ni7URFndHPcrMdXeqnoMyWcz59yS/vDabVKgA6nPMZYKBEtUw+ +KLXUbNeOl+1sQMVRepEJRgCkchJ5anDalX+hBoVaLoArOKkdSWrQcLx4Yhr/9IYN2DxZRKNex3/Z +9SpemWphy3geJ+YW8fTRi3js7dsH+gCGkcsILiq4VJKScKLexO7TZzDi+/A9Hx3uYSKXwWl4+K2R +DP54vomT1Squ8whHa01MN9Va+6EEal31Qc2cZlpAwfyOBFqOJrb1J7IREBM9MQtzdtD7hQz33ZrZ +hZxFwiaUhI6IpxHbd6/LpudrGgFoz75UTAypbmiOmTC2PGxikwn0kF73wUhgzhjWT47a57n1TdY/ +2ZaE3+DcMl/Vm06rVQC0fd+f7sf0w8yApFBgjGH9ZAWlQha1dmi/OUdW0it1SyTBSTn+1DepuV4x +iiATU0sJDCwI8NzpKj7eaePVY2fwhT2vYXJiFL/x/rtwZLqGzz53HFs3ToB53uv25MdQAS5RGDAG +PxPgszM1INShskwGmZERMA/Y0+xgJgzxt802vjY9jzqA90yM2U/4hQQsdmmoJ0tKCSkEumEXIhQI +hbAoTEqVLi2EGBwuk7LvOSIVoZEyLmU452i0Ozg/u4h146M4OTUPz3MQgHXs6bkATNo5XpEJ4Mwa +JChTkAMQqt2lQhYb1kZr0y5nPYp+x5zzVACskFq5XO4CKWIriQIYMoOvVMhi42QFh87M6kFhFoSE +FfbqKzNmwUtmk0MkcXAi7SgEGONqKjH5CJmHwxfm8fevnMCxhTb+9MP343N7D+IndtyKF05O4b6t +G4FlOAGXS+TsrFgYeByj5SKCTAEZj+PxcgEPjZbAmMQvnZzCl9sh1hTyeNfkOL6xUENAEpVcoKbH +LuP2Qki02y00Gw20mk2cqS6i3u1iutXBHevW4MDULBZbLVyoNdDoRLPrIKETjoCZegvVVkdFA4RG +DHpK5EytiYVGy3gAASLkPI4b141h/6lp3H/ztRgvl8C4B+4xlf+vPg+sfLtShW4Zk3YxRwKDp8O9 +rh/D7ehr1o2hUlreVP4hUQAKguDYMt/Um06rVgBUKpWLZ8+enSOi8UEmANDrmXXLzW/TuhEcPjOr +GFtrA2tcQn9mGgDpBa0ZFBzkXOcDWEeAOcfAgwAvnZrHB96xHV985STyvod9Jy6gde+NuGVdBVvX +T/TUzWjCUESZoe7cQJuTnmiXW47ENXaGm722tzM557i+VMI63sbPr5vERODBl138t4tzuLaQw+Z8 +gAkifHRyDOtzAf5ioYYtpXxfe9dV0GZXCIG5eh1/e/AInrw4i0UJJTwkYUdb4OD/396bB1lynHdi +v8ys9/q9vq/pnp6e6bkHBDAYAAOMQUIECGHDkilpFbIU0kq2bAX1h6xweL0OWl47FA7HMuQN74qy +vI6VaG2IS5khWQIFiZQE8VqRhCCSAkiAxDU4CAwwB+bqnqtn+nzvVWb6j+/LrHzVVfXqdc8MZrSd +EdWvKjOruo78ft+ZX15dxCxNyIA1ioncwGoNo8FA0ANUa0T4UsPGltZZFBpioBeVPtCkIEN6yfbh +Oo5dXEA0NIbhkRG8MzsPoRSre2zQAwAjoHz0J23JqsQimTbM784vOQZgZmpsDbfPGm9FKoAQ4srI +yMjJtV/l1ii3KgCsVKvVRSHEmTQAOP1SKZonFH6UtPjvJrZs3zoCKY7Dhfxa5vChUdDSQoCsd5LB +iwaNIt2QXUYQEloAUlXw3Kmr+KUf2o83J4ew0Ijx5oUl/O7fvob/4uGDQCoGwFqLxmoDS4sLWF1d +YQu1bCMyH7MerIYcPodrS9fTYE8ATwiaN4/g+L7hIVzSlzEIi8WFRXxzbhY/0Bb/6uB+vHRtCW9d +uYqrS3X8UL2O7169hoPDw7A2eYY8SYC+CfB7bxzDK7GB2jqNHkW5XEyzibu2juHgDolPvzcHAZVM +BtIGJjawsYHRnAo8NrBGU722sC0NaS32DNZhNOVXmBnsRV0JPLJvCl999ThG61Uc3jaI/+XPvgup +IkDQYp9WW47kJEGfFnYJwROANJAmyVJE4jpzcSkxs22sHXyRbwswgQqTYlhnrLWbbsAui7HWLiul +Tmut7wGQfqm5JQQBR1wzU6NwHn2AVvqlkc06v1vWipVBIdjiD1qjXknBPIJWm1FCwFYiaC3x+3/3 +Bn718YP4/PeO4e5dU7hv9xT2TI606bvWUiTe8tIS/uV/eA6vXlqEjCQGaxUM1yqcrVwCSmCsp4KB +auQBpy9SGK/RfIaKlJjqrflBuLO/rw0YpOBcBAwsbj+KIkRRBRNCYHF5GS/PzeKPri3in+7aicUG +cHH+Gr4+ewFHpAJqNexTCpGK2hYxz+J0Oo4Rxy1orfHRndsx3YjRUG5ICfRZg0cmR1AB0CeBq7Gm +xTrYoLert4ooqqBSqXrAAntO9o4OFqp5WmvsGevD0sICnnj2NRghoCLl5+9LR/wWgBSU9ydG4GWx +gJVBLIP1tgA3E3TX9JY2vb+T2pkeo6z/n6rVaq3CE9/HcqsCAKy1S1EUvRfHNK+c3HLtOhbQTvBh +CTnkzm2jGBvqxeWlFgTI7088PnQLWsBoAg1iG6Qc8EcnVVLR1GGeTixqPfjO6au4542T+OlDO1CJ +KpBKYXHhmr8vL/bHLfzJS2/j9VaE6rYdEJFEQwqcB+upESUtmRNslBIMCtYCy3Ei2i8sgzRYC6vP +87MCE5FCVQhMVyuoSYktlQoGIoWRahWj9V5Mj45ipq8P//qtNzArIsjBIeyqVNCKW7jWbOFCtYpP +X5iDgsA/u+tuD57WUkagZpNmCvrvYwyajQbmFhcw32wCUuFuKWmZbQv0K4nxnipWrs7jahyjsrSC +cX4nlxstLLQ03rhmsKu/D/dsm0S9t46oUilFZDqOsbq6gmPvncXvfuV5vLcUQ1T7YaWChOHwDgVp +WOfnTMBe2LKWvDyCJEEBx829NRBjw33Ys2OibXo0gDVjLYvo3XfncXi8v7+/UfhQ72O5JQFACGGs +tQu1Wu3UyspKpmgVWvyLPAFSSgz117F7ehxX3jrLYaKG7QHau5J8uKgVQUAQWaCdcdCpB4ZDUqXs +geg1+PTz7+GpV9/Dga2D6KtIbOnvcQ+CC0urmFtZxbuLTSz29CEaHYeq1yEiCRmx1KEUzV6L2FjF +S5gLJQIwSH4dB7MALQMqgGuxhrUGczoG4hjWaNhmE1hZhb1wEb9mDA5OTeG/2nsAn1q8hkVNcQ+t +VguXrUU0NISTcQv/4/g46pWK97PHrRZWVpbx3uVLuLq62vae/+7KPF5sNmnWHidAAWiVZcQtjGuN +YWtwcqWBFVnxmdUAWm7dtmKIxhn8mm7hrqmtqPf2olKpQtJ6ev67OoIyWiOOW2isruLC5Sv47b9+ +FmebElFPH5SiOQACEkIbkvIkIAwnYJESsBoSAaGz1c8FgiVSocWeHVswPNi3htFkgUHe+OT+bwPY +lADWUZYGBgbemZubW1FK1UMpII26aR0tQF8opRDHMfZsH8NLb51LLP/WUmgox4pasGFQ0Op8FBNA +JkEjQFFkLDNIaynMVwFK1iGiCBfjJi6cWwYtmM3uJKUgKhFkTxVycBiVvl7IWg8ZqxSJ/DJSkErR +vhIQkfJLVQl2a0EKCOXSmfMxR9A4YHBGTVq/yMLGyWA2q4t46uo8dvX1Y8/gIH69ugV/unAVvzc7 +i8eGhvGKsbi3rw8/39+PrdUemjsQtxDHLawsL+PdK5fxby/MoaV4OTBjIFQENTSEWr2X3J2cktty +xI6JNa40VnFZG2BYoCoi6mNocQ+rWf9fXsK/ee0kfuzCFfzo/l2o1eqoVCpQHlASIGq1Wmg1G/j2 +m8fxxPNvY0H00DsVEawAZMzSk+QvFSfxBMK5Ea1zBAuKE9CSzT2JcVBIgb0zk2tAKG0UzSP6wB6w +0t/f/wo2AWBdZXlgYOBitVp9x1p7MEvUciXLOps2lO3buYXqnWQgyPHHgi5dW/h8vMQdFBkCXV8N +C0hyBVrOLwglIEQNsqdG5wtAKFpkU0QUMyCiCLIaMaGTq4oInlaigeT7lGgjfqh2IHDEn6xzwJGK +vLQ5AZgkUdf6FwHbX8MJC/zl+bP4x8ZgoLcXvzo4hGb/IM43GvgXo2O03qG1aKyuoNVqodloYHV1 +BX97+RK+ZizEtmnUajWaH6FB/7dSIeKTgjP7GDKnGDby6RhGk0huIIDYEOEzQEAb6EoVsVL4i4uX +8MzZ7+GDW4Zw95YR7BwZIrsAgEYc4+3zl/DmuYt49sQsrrQAVRtAVKnR7D9LxjyK/oNn8Ion/4gQ +KCVYQnBGYB5TDKLutR3YtdUTfKc5AHmSgFLq3ZGRkVNCiFs2I9CtDAArxpgFpdSxOI4PZnH/LMIH +EimgDQB2TGDX9BBOzi7QtFC/DC0NBD9ZCPCzAqWV0EJAWAPLxi3rLEvMgSk+gIjeyioRrVLEsZnL +i0i2ifUORISQ5Iai1cqBiLm8AwhH/Iq8D5DktrIOKNwiJs5D4ZLbSU5zZulehawiGh3G38VNXDx3 +Gj8xNILRWg1SKowIgYUmqajaaBitcX5lBd9buIbvmRjLff2ojI5C9Q1CVhRJ8JqlC9DrEw4RAke6 +FRJCViAVEbzUBsbn1zMQEeUOlNUIUf8ApKxgfnEBX7y0gL86fQl2tQEbx7DasL6uIKIqZH0IUV8V +QkWQbi0GQ/cjFIn5gg240tlTpCR7AAikhBQUEWhTGwBYi13Toziwe8qPnSzu70oH8f+t1dXVxXWO +/5tSbmUAQL1ev1qtVo81m81OL3qNcca7w5SClBLVSoQDMxM4dd7lBjBM9AwGPhrcwmUMsoISYlg2 +xknFS2WD7YQSLAnIRCyXkmMIQNxGscFQJZxcKuLeXrwPRXwZSASO8wdcH8KdC39dnwqbE3KC7z0x +XwJRvRdicgJv9Mzj1StXsPVSC9u8xZ4knktGY14A89Uq1GAfov4B9NTrkD11TpfNxMaZdozl2XdQ +JFQ7ABIm4cTse6EVFQzZT/g9G0mZlmVUgahLkpTqvVCrTdhmCzbWDACWgUYCgrm6oYAhSidCVn5r +kunA0rn92AhI6pLgwCDncHDjBywiUMMdO7eiXutxD9CmBoSlaEyyq/qNKIoyE9vcKuVWBgAL4NrA +wMCr8/Pz3g6Q5xHIsx47KUBKiQM7J/H1777tCd8tHw32DEAbWPYN+yQhlmfDCQUIJmzmwo7QDAOG +kYDLSyeYaTuVQATeA0/0El6dgPPxK3A7cXm3YrEbzLTACd2PS+IrFdkmfEpzNnRYAeKSAgAUVL0P +Mqoi6h/C5cYyLrZalJiTXhREFEFEVdSrVchqhdJ48UIpRli/Top3lXE+FcOvxxrF0oACwMsHKdD8 +CWtgpeB5F4Kz9jqubVg3rxDwRT2wWkO0NNsKNMBggNjALfMrLb9rQmoIa8hQq+g9CAiI2EJ67s4e +IGMgbTL70zqvCg+hD+zdtsb6v2Zw5lj+3QZgtbe39ztjY2O3rAcAuIUBQAhhrbVLAwMD5yuVyrvW +2rs7cf88O0AURWi1Ynxg9yR2bh3BexcW2AtAKoCbMWZ9bsDAPSjIWm6lgbEEAoZdhVY6/zvZA6QT +CyStQeinEnL6KykEW/YDqUC2SwOQkm0E0nN9AhMmfrYLwMKvcJMQvvTLkgFM95TrivsriEhB1npg +dZ/P+8cvi+6LLfBeHxKk33sgEbwAF69ywutucl8LSEXvEcxqDdlR4NQYJnZr+d1Zkii086wIA6to +aW7LOr1f09EKP8HHSkBYAWmpHwX4SQhoCC0Y5Nl/z55dtyYERU9aKI79FF4NAHZMjeCufdOeyYQL +nriSRfwZ4/LdgYGBd3ELJwQFbmEA4LJUqVSuKKVe11rfHSKtI/wi7g8kEoAQAv19Ndy5ZxKnL1wj +91kQCEREryGtgrCGrfmK7GrMI6QiyVYKyyKt5SnCSIyCTHCCid3ZCpwo7wN3VKJCSEEegMSq3x7V +56MDnUgL+NTmgsVsKCICH8QognkInCab30gibaReW7uE6wa4I3z2glgbzJQUrBIA1tLUW6dj03vz ++dTgBBM4WwXP0oOVMNJQ7g6F9jZWjawl0d4aTXWRhIhNIhWx6w9wKwKRZOW9PJanBIOlGHYFO/CH +6wOLu/dtw2B/b5sHIK/kWP6dAfCoUuqSEKJgYbX3v3QzXf39KKZer1/u6el5JRSv8lA3LGF4sIuK +k1Lizr1TnNrbshRgaBlpo3mA0ECQhgaHlBSoI10bZwaWTHjS/Q+4hJWOa7MrkA1SjkFDgLgh6xNu +EFsWY8Ecy3NutykQ97NIJAgGASsd10+kDW+cdBxQyHZCdGpDsEEF7R54rL+OhbsngHPusPrCNgnn +qQADjnL9Zbv3wqlBwoGeW6AzAUxvU3E35O0hFPEohUv/7bL98mvlwCrBNhHJsRQCglOGaTho9N/b +e4YE7tm/w4+VcAyFpUjvd+NTKfXC+Pj4LRsC7MqtDgAAsDA2NvYKKKY6E22zXINA8uF8WKwQuHvv +FO7eOwkyAroVYwwFiBgDYTRZkmEhoQkcrFvNx1mWaYAneeUtfPZZR2eSxU0lk6QijmNZ94uECHgJ +FEfUEgGxkPwKFy7sJQUwzYQAA/jr+nMlT4FO3kzgvgg2ByJciODdnIIEP2jHtt0nVdsErAQZJ4VM +7oVwwxG5YBema2MDKchDQkRNqpGKOGuv5AVDAy+Iuy/JLlGX+VcK0f7tONCLMotQQJDz/LgxcHD/ +FO7eP+3HSjiG/DvJEf3DMQngTH9//3dwC/v/XbmlAYDFp6V6vX5JKfVyiLBZ0gCANcehN8DtH9y3 +jY1HTjQEYAgE2I5Hk0JsWGegoCmvXTiGBYubPDDdQHbHITF68T5iYuHR5wlI+udmd6MDBw5MYrpz +HDrNseF/qN6ntvKJMJMtFC7CbQ0oGOfWE+3/w980PMgwRfs0X0JaBhC2F7j34J818XC4BVpIaghB +h415/E6lS/rB71d5cLVQQtIS5Up6gicgoKhPQfM6WQI0ftq34JwABw/syCT+ojGWNSallK9UKpWz +uIVXBHLllgYALisDAwMXenp6Xu5WDXDFqQFRFEFKiUMHtmH7xGCiBhji9MIwkbNrUFpL+w4ERLJy +kIST5EPx36JN0rZoPxZOlQiIHIG4Dvh4dRESm3epUX/BB+T/dpTbTvwkNbjjpJ0AKwGf9CZlsnZh +cNHA95kCARbTHTBxa3K/NlQL+JJeCkLirnSgCUGg64hfoO2RnHQluS84R4MSZNgjLEm4vrTw3J6+ +J6l3EpYkPUsq+o6JIdx3x8wa8T9dyor/27dvn7vV9X/g9gAAALg6MjLyLICTaXErXHG2DAhIKTE6 +3I979m+DjwOwhsR/VgOk5cEiHbFTbLmzLEuXV85HEpJh0OmixOGSffYY8gB2lMlirgyNmI5CWCd1 +dc6qzpwyuRiflpLu2+rcJR2h+T85m/UkzARrc68JIFl+2Pd1D02kzGZTis0Pz+P7cLcjmfRD1KTL +BJZ7JwUIsC0gMasIJN/LAx0AIcjAK4WAdN/ZsrrnpQCLQx/YgS2jg7kBP8Ba63/OODzZ19f3DdzC +i4GE5ZYHgJQa8GKeCpBOGRWcDyCxAzgQuPfAdowP1UlHBAKub2iBCVCwCXET+lVIiNlJACSWwuvC +zuaVlqQT4kMbR1tTieQwtXNji7cErvdkrONW7Zpz2uCoTQ0IjhHUC7cYibMTWChrGXitl7gkE7tk +l6+TBmAtxgf7cP+dOyCVLDT+uZIed+GYVEproDZQAAAgAElEQVS9VK/Xz+AWd/+5cqu7AV1ZHhkZ +OV+r1Z5bXFz8SWOMDIOCnFvQHQPtH89xXaUUTQ7SGjNTo7jvwDS+8f132ViUZAkidUBD0Cwgijoj +1zu5Dw1gJbkGXSCeYZGT/p8kqd0xVOHuwfmnyVlvvVsKZBOwLEdzMj4Sjw1gyWMNQ5Fwvh/o57CS ++JVKhAHROQWZeyvPGoP/R2vcJQT+qVLoK3GuO79lLf5Ca/xFi9xyPjm/FfwewVOu2V8IDTdZCIlu +4oUGWFqiXfhIo7hNIKFoTMDndJCg2ARug5EQQjOh0yWEdrYdC9jYq3nWSQBwIeDA/XfuwM6pLZ5B +pMcPgDWcPs2I+NhEUfTN6enpM7eD+A/cBhJAUBZGR0dfBHA0S/QqYwcIQ4OllLj/AzswPlAnY58F +RbGxW9CpBs6S7Os8xxEMFNbbAJTjQtZ4l6ATUd1gS6JSAG8HtAQqALvNecfysV+2nK/jLPpW0oX+ +u0qECSFQB9DbYavz9riUmBACP6MUxkue684fFAL/dRTRzXkjYXLPgKX7tiCgc7dviYgtN/pnDYUf +AQqt9odkxJNSeGOrsvCuQK+igRK3eOnB2uRbht+P/f5UB4wN13H4rp1QUaL7l9X/0+NQCPHa0NDQ +3+M2sP67clsAgFMDhoaGZqMoes4YY8sYBLO8AYkqAOzcNob77txOnMVqz/mhWR0AG5BMDMoqaylM +mEVIJSUUD1YvarKI6sRQpwlLAJ6iNcXNC5YInCRseR0t6yjG/WoDaxNDW3IdEwBD92XUWkzwfgvA +RWtRdubKogNaR+jG+mdhswXc9F8nESD4Hm7FHsttgtk9hRcbyOC9CSnYmMeASgGPXiKQDmg5oMvF +cDiid98Ghr+l0/9hcfjOXdi9nbl/gfW/yPDHY9BGUfRcf3//SdwG1n9XbhcVAKDY6ouDg4N/e/ny +5Z80xmwNRX9H4KGRJkRyd+zUAKMJBA7fuQNvnpjF7OWlQDTkwCCjAa0gKgoCpPuJyJBLDAbGaIr2 +4zQTtAkvutKgtkQICMR8ln1tG/FbDvThc8CTayxzSsHEoynoxsI9L7DeYPNBCDyjDU5Yi++67DnG +4k4p8FNK4cECg5imlwpOrEPvh4nMMvelSrQTPksNApZyByDEMBKLQmnAifG0gIdL9hn478Hx/6zv +W7fcu1NFjOEMw27SF1gqsdg2PogH797px0Q4+y89dtxvmvADAJir1+tfGRsbu3y7iP/AbSIBBGVx +bGzsHQDfyfoIaf0sLKFhJ/zg0xPDOHznDh5osXcHOrFRWgcE5B6URpO6ANE28Gj1rMRlKFkfda4p +H18ANzjJ4AjmjMKxQ6cOGLJU0wYIzfXCiddEQMLL192Vi9bipDV4Usd43mj8rJL435TCTyiJN7TF +/9Fs4TldPI7pkel5DKfwTohFQGhwghDj7zdBSvfMgYjOEpYA2BPDXF6AJ/64X3rnZJRl958l8HRu +PmGt/3bOuAvBIMASwAN37cT2raOIVNQm+mfp/1k6f7hJKb8zODj4GoBm91/j/Su3DQAwqi6Pjo6e +7+vr+4YxZllrnekNSEcGpj8ohYgqrw48cNcMDuwY5wklOgkNNpoHkjMKBsesRypWB4SwiMDWZpP4 +nZ0+mkw+Yo7JIrKfiJKan25Tv4aJ3fLcd8uqiDHdU//3tcHHG02c1RZDVuDfVKv4+SjCvVLiY1GE +xyWl9P7NRhNzOTYVAJwXAEz8liYX8XsXnCDEGwPcr3HPyEKCUw+SSX4sUTAwgg17LGVIsA2AXbIK +7LkRFlJoSB2GeLvcAGwPMMm3uWPnJI7cs7vNJhQ+aXoKcJbOb4wBj8HlarX6N9u2bTuNDSllN7/c +NgDARQNYnpiYeAHA80VRgVkhwmvsAOz2Ge7vxeG7Z1BRgvX/hHNAx8T9vUGJNmmcROAGItsAwDEB +AKQwbLByeq6ba8DiqzHkaWAOKTznt34OfGILYI6vLWxsmOAcYZUvf9yM8b+vNrHI536iWsH2FEB+ +RElPpJ9v5nuzbABcDqigNURMxO/uz2kE0C5jkOHFO91zc7QeS1QOFBV4VWHH7d07ZK9KKFVJa33w +Fv1qzkwUQ8Sa33UMwKAiBP6Te3ZhaLAPkYraokSzCL8o6IfVzxeGhoa+BVrWfhMAblRhKWBxYmLi +XK1W+6oxZsVJAaE0EMzJXiMFhHEBURRR6LqSuP8D23Hkru1wo5W4kubBykZBYwMRkolZMvEb+lUs +7pNXga3UmuuMI3x3HXgi8JtxYrM7Jv3V/VrNxG819e3Cgf+mNniy1fJ6eGQsahkGbw038A3OFqkB +hiQQ63R/Q0RvjeapxpTfH9p4YyD8c9M7c88pWF/3gOpMJdqSmM8qlYSEcqoCS2JgoidOr9slNgPA +BXtZAFbjyD07cd+dM1BSIlIqiVDMMALSY7aPq3DMWWtXenp6vrJr164TuE18/2G5rQCASxMEAn8H +4NU8O8BaW0BCJC6ohGaUJarAkYMz2DExRMkodAyhNVuNNWBishFoDamZo2gNERueR+BAI9FdHWcC +kujCRBIIPAcMCNZFqrn71snyWFZbLx24OhgDxLoU/Tcs8K+XV9mWYHGflHhISZzKIPB3Ys0iPBDl +SRhO+DAG0JokARNs2tI9OxsHA4Rzz1kGt1A9Ek7vDwEByTuToj2gR/J1pSGVLQFo9uQ4VY6lOhiN +HZNDeOjQHkRKIQoSj3ocDCRHIFvsT421o6Ojo18FsHy7cX/g9gQAC2B527Zt56rV6l+HtgC3GEee +SkCD1iYxAVHk5weQQXAERw5uRzUSrL8S0VsT8yCn1NvWaoiYOI2EEztpcComdOUkCVgoDuxxxC5N +oqfCJPqviJkgjGUxmrmkG8zaesJxlu2yGsC/XFrBvOYBbQx+phqhHwKt1PnL1uKvVpuU+DM22KGy +feIAmPgdIGm+L+slGMHtro9gkJCGA3UMuf3gAQBtICAhAjBNgag39CWiv0uHTvehKZMQg7c1FhUh +8cF79mB6yxCiKIIKI/8C679ldStL5E9JnMvVavWpmZmZk7gNuT9wGwIAo+wKgGtTU1Nfs9a+miWe +5dkC0hGCijmBMwweuXsXjty5w1vgBRM+4hjCxJC6BaljwLZIfI+1lxBIDHXqAuv/bHFW7N92BC75 ++jKciuy4pfvVvEQW57+zllUAR1TakHjdobwWx3i50fLXGofA3ZHCudjlyU/KCy2NKzoBmA9H+Z5i +G2sY5rbGEb4O1RU+1jYxwPH3SLwsCdeWro8LwXZ9nFTlJm3ZxJrvpDLL30DqGCJuUVCXoW8GnuL9 +0D07ceTgbv7eKlkEJhgPebp/lpoJ4NUtW7Z8EcDC7eT6C8ttBwBBWdm2bdv5arX6ea31Ulm3YNom +IKVEpEgXVKwKfPDQbuzfMcYcjkHA8CCL2S6gLakAlo6VG7TaJnPNOcKQvAbaD2oXg06D2hG9YSlA +w2qOSGQuKhyhO11as9htLBCbjh/xiUWKFCBJxuI/rRJRr+i1EsReJTFmAWs0Hq5G2B+pnKuyAdBx +ef+unBpgELoyhYsP0AYi1h4UnHog+Zp+1p6l4CzvDjSajH4MroJdshQMpSFj7d8T5Q7UiTpgLA7M +bMEH79sDKQUvlSYhIdkdmW/xzxtXWuulWq32hZmZmRO4Tbk/cHsFAvkiaOWgFQAL09PTXzt+/PiP +aq0fd6J9GBjkrP5pT0Ao7gkhoaSCliTCT4wO4oOHduHytWVcXmqQpT52ef4EoMm4Z3kaLqXqFrQE +lbAuSobDXAWEVTBsuIKwsC7PIDhePrawSkFAw9KwJPHV5RV0k+rY3pfM86fgnQGZL6YbAG82WvT8 +QgDC4LEeWrxTG4NWyo04rST+3egAzmmNmVziD4KX2CVp2X/vPROhgdM40Z9By6k+FgyiBJwu/sGp +ALBk+XcAIjz4JuK939fE7Q3/WqMZTA1GB2v40KE9mBgdJOJXyXOFsf9rLf6ZhA+tNaSU3x0fH/8i +gMXblfsDt7cEAAArU1NTc/V6/U+NMZfTakBaCgASO0AY9uk8AsnCmgJ37JzEhw7tQgSwOEyiJXQM +NNk1GMfJAIxjSMeV2YWoLCBZgpCawMUHu3iDIW8sKku28rv2kPsLd2xZAmHi+Mq1/MzTJ1oxGjEv +gRZrjFhgUkmcaGm81Whha4aOXxEoJH4AGJSSjJVxIraDVQcXSi20gYiNV3cE2wGkZq6vE8+KNWDb +CRL9nomdAnoSAymMhdQatkU2GunUgLgFEceAbkG0YhirEQngQ4f24M49W6GkYqu/bBP/PSMAc3/O +L5ilWvJ2uVarfW7Hjh3v4Tbm/sBtKgEAbVJAz759+54+evTolxuNxj8RQkTFUoBt0/US149BRUWB +GAg8dM8uXF1cxbdePknc01m8pYSJWwQiQlBgeix81hwBWt0XWsNlvRDWwlgDydF8RksoBRgtaa6P +YpeTUwsA8htCwk+S47z1EqC05Jq4+qcvXcNLKw3s6qmg4WV6gZoUeKPRYvsCGSKlNvjM1SU8t9LE +h6oR9lZoCJyPScSmKYzuLWdbGA2AV1aaFI8AFp35nmUYnxBwf2ENZQ/mNsUcloCD1CQHHGCpgEAO +XBeoPjEZZqUmdckwAFv22oDXSRRG40P37cHD9+5hkFdQUnHeAOHV/2y9P5v7NxqNuFKpfGX37t1f +AVn+b1vuD9zGAAB4EFgaGBio9vf3P3n16tXHtNbTeWGdPhmHp5EQCIggFbuorLKwIsKH79+NxZUG +XnrrPAwHpbgYdcuZdYUUQIWcBi4aSGhSAqQArS0oKGwVMDCCBqE1FkoYGCMhoWGgeFkvInySgknM +hxU8Y1DChplzYXF3rQcfHahjUEnE/HgCQCQF3lptkjGOH3pbNcJDtSr+s74atkUKP2i08BtzVzEY +SfTzNObEx8fvzoGKtVAQWNAa7zVjIuyw3akC7AEh4GM1gLm+MC5AyHhpRzrbQGAAdAFZRPDOmq85 +MCsGWvwbt4BWi4y0XGfZXnP4wDQeObwPSvES6UpSurCU0BPOU0j0ft0m8gei/2x/f//nhoeHL+E2 +5/7AbQ4AXJoAVvbv3//iyy+//O/jOP41rXWvc++snTBkIaF4Ka210oCSClaBdHZr0d/biw/fvxer +zRbePHWZ8tppnuzlmKXLZAsnAWgiQgHibgIw7NKyUFDQyRJ2QlEufEHLV1khHHvnrDqK3VK8LJgy +vNJNkk/rn28dxliOyD4uJBETPS76AdzNNgAA+PWzV7C/J8I/nxh2y3nkF0vP0rIWX5lfwucuLfAJ +hkKbjbNzwMcFCDg3pnMNWu/SbI98dB4S3a72OMNeTBF9iDVsTCqY1TGpATFvrPtDG9y5cwKPHt6H +/noPlCK9XwqVfDTRbvWHI3xNxJ82ADq3X6VS+cyePXu+A2DldvT7p8ttDwCCFhBZqdVqlS1btjx1 +5syZHwLwj0LjTnoikDEGUsg1xG+tJQORsLDWpekVmBwdwCP370Oj9QO8e27e90esYUULtsWTVpxo +ISzaxoag8GDKnQ8ACtInyQCtrotkBqDlhJkAYKEhLBsCJSBiC7++lSGsKNLWG1onyTEEcGo1maqu +LTAqgP9+yyBGVXfmoF8cH8STc1eJ63MkpFuizK+75zwcrP8724bQxp8jtOVgq8TeIVi0F8YwcTuD +XgzRagG6ResGMucnF22LvCctg93bhvGRw3sxOT6EilKIIkXcn8QrL/63if4pj1EW9zfGPDs2NvaF +vr6+a+iAlbdLue0BgEsLwMqePXtOz8/P/8HS0tJBrfWkEAJa6zYAEBz91zZbMGi3FhCQUCqiyFVr +oVSEmalRPPrAfujn38Kp2WvBKjPhbfDA4n13afJ7K4C5NAEFZfcRLC2zjMAr4BgGBwFhBKxkSjeS +1xCI6fqSpICGyWdEY1KSX55FkjMrTcy2NCYrCi1rMS4ECk7PLYvePSr8hCcYF44Lb+0no53w8Q/O +kCe9WsAuQq29i9AGoj9Z+LUX+62OgaYGWmzwc5yfgWLn5CB++MgB7Jgag5LCc39ajYgSiYS2DUf8 +ANZw/FTQz2xfX9//u2/fvndxG8b855Xb3QsAoC04aOXw4cNfj6Lo32utl+I4Tn9E3qdlq0MQCLPw +UjyAoHBRpRBFFCewd/s4PvLAPsooHMewugXETc+FbKvFA7EJtJpA3IJt0kC1Ma11Fw5w0XJ1bDHX +pBe7uQfCJSYxgIwNeRk0z3jTFrJFYclF5e7eamJ5j+l//cWlawAos5HWdo0rMF10OliA64RmNx6H +REvtnoPuS8Yk5ifPovn5OBJQx7TWH3tToGkOgXAcn417aLWAJuv6rRa/d2cDaMLGLUAb7NgygI8c +OYC92ycQKYVqpULRfjzfQ3JWFucBCo1+Wmsv/odjhsfQUqVS+YPDhw9/GWT4u20SfnQq/1AkAAgh +zPHjxxvj4+PV4eHhP7t48eJhrfWPSilFHMdtM75cHkFiotJzba8SCJrIQ0FCEYy1tMilBfbPTMJa +i2defBfvzS6w/atFYj8sL4QZJUzGsATgpqRaS3G/MvKWf0pkoejYgkRp6+IVBCcLoVTa4DXzBATn +IRSJES6jPNhfJ4ABnPMeX75wDT81OoDJagTD4dN55ffPXMZwReFnJ4bWNhpN4j5zfQrlTSb7uFBm +Lx0E+9DsHvSuQwZCE8O2kuhLOBCIY6DVJJ1fawJXHbNaoDEzOYTHHjyAAzNb6LtJBSkpuMvb+w1Y +gkpEf/f8BdzfWmu/OTg4+DlQpt/b3vAXlmJn761dRHobHh42999/vxgbG1u5fPnybKvVegTAYDrX +m/MGCJGdAdZNFiJDEeWeM85gCIvRoX4M99dwbXEZ8wsrcE4lyy5G2EA1EO72ABK4rLfSJ/PeQfdj +nHrAxxAcXsxXMMH9cYQcAPzE1Aj6coyASgjExuD1xdVkngGAv7+yiAcG+3BipYkPDveiN8MG8Otv +n8OzlxfxMxPD2BoYDgGgoS3+6txl9uOzROLnNiTGPpJWgjkOxrDEY1l3T+IkrI79SsDQJOZ7i7+X +rlqAcfsxhDbYPTWKx4/sx/4ZSu0VSYlqxNwfbm3I5N0BSKJDA+Of1nGbtMjc/0ytVvuNXbt2vfTU +U08tHzx40H++4HK3bbndAKDwxT/zzDM4cuSI3rVrl9q6devZixcvLsVx/JAQohbme0/AwBH5WhCg +fyYAYX0MgYH1iSOGB3oxOtSL5eUGLs0vAiDR1jpjoAVxfAAkBiS/ggneiwnWBsecbJQz7AoIcpW5 +eieucKScgMWPT43mAgAAHBqo441rK5hbaZLn0FisGoOvzM2jZQweHOrDCMcDLGuDb15exL/4wVmc +XWniN/Zvw6HB+pprNozFX525xEQNT/R+co4X9V2kX2jddxF9xuv65MZzxB8nxB+32NLfpDrDAUCa +AOCOmS14/MgB7JoeRyTI4FfhoC4JUuf8O+OB4+P713B/3Ub8cRzPVyqVf3XnnXf+5dmzZ5d/+Id/ +OEv0v63B4FZUATb0In/u537OPvvss82ZmZlodHT0C3Nzcwe01h8D0JO2+NNxkg7KuQrX3opAxEbB +WGtEkoht59Qoaj0V1HoivHTsHIntSPzwAOfzY5VAWAMoC1MxkFb5UFkhFRnCJFvOlYRVoBBkYWmF +XGMo/6Cle7SCPQO2nBnnE3dsw7995zz+9uI1MvxoAr+55Sb+p6OnMFxRaGmLJa1hBbCr3oPfuWcG +AwVzAUSL6MEb+NwzMmdNvAEuJJhVBj9vwLDxz/n3ycUn2WYCHZN+71QCR/wxBTfdu38Kjx7eRyG+ +PLc/kson+PSZ1tm7AlhS55CAgNYamic1OZ2fOX9DSvnEyMjI50+ePNn8/Oc/X0b0Lxq7t6TR8FaR +ADaComlVANeuXTP33nuvHR8fN8vLy8ebzeYBAHvCyMA2KQDM/S3J7u3qgGS3nvSpvkmnp9++ehU7 +JkcgYHF27gpF8lnLAjwX5tg0Fm0iAXBfz/09Zw/85W6mIODnzMNavy8A/NiOsUIJwJWHRvtx/1Av +YIGllsZyM/bBN43YoK4EPrp1GP/D3in859tG0VOQFLRhDP765AUyXDodPzRgmoTTQ8c+LBhGe8Of +4+I2jonIOZjHxhTWiybr/07nj1tAK0YE4IOHduDxI3dgdLAPkSQXXzWqIIoogSst1MLLtTHxtxn9 +4jjh/rpd9+ftmaGhod+q1+unP/e5z61+4hOf2Kjof0tKCu+nBLDeF9HxvCeffBJzc3PN3/zN34yG +h4dPaK0/2Ww2Z7TW+7OyB4dSgDOohSAgIWGEoZlkUEAEtGKNCiLE1mCgrwf/6KE7MNDXg+8cPYkr +Sy2AJ/oIo4FIAzYC5RiIQGvSRWQAixSEjWC1BJSGUArE/iWgON6eXBPkNgxX1zWCEuR1wVsODNRx +YIBE+veWG/g/3ziN/3LXBA4O96HeTSyABbnhfOhDoP8715qP3wdJO5rm6ZOf30kBcaLza0f8LtpP +A5pUATfDb6S/Bw8dnMEH79lN3F5SbEdVRX5FZtL72c5j2y3+4VRxx/3juJUckwrwdq1W+y0Ab//R +H/3R6ic+8Yksn396HHbD4cNz31fJ4P2QANaDgmXQs63PyZMncejQITs5OSmFEOcbjcZ5rfXDQoh+ +f0KbJJBcBGtsAokFifoH54NWrZFCYNvEMEYG61heaeDK1aXAGGgTzu50dwuKV3cBM4LtA4Zj5J3X +AGwzcNKCtWQMNMm1PrprAn2V7rF8qBLhO7Pz+LHt4xiodDcUmtrgqXfPt4nz0Jp9/TFETMY/yW49 +q2P22xMAkFWfdXxn7W/SseA2oVs8vZcAYs+2ETz2wH7cf8cORJKMfVEUoaoiyu4kACUFz/BzNhJK +7tKW2GONtT8R/5vN5mylUvlfBwYGnn7rrbcaTz75pD558qQbBKXHXxflfZUKbhYAdPNy1lj3M9rS +/WSqjwQgvvzlL9upqSns3LlTWWvfsdY2ATwohKgBaeOfCOl8DQj4NWcECfdSuqAhZyykUN2RwV5M +TwwDsJi7eI3cjdYwEbvYebB0QAc+tbe18IZCN3/eAJSeBwnxO+CwgDAGP7F3G3q7JGAAaBmLvzt7 +CXeNDGCo2h2ANLXBU2+f8Qk3wdZ9Gxj7rOPunEehnfB1YOFnXT92INHynB9xDGUtjty1A489sB87 +p0aJ+JWEihQqUnnVTEmRBPrwwiuFxB/o/rzNCyF+q9Vqfe773/9+85Of/GT8wgsvpB/djbWssYjU +8XrH/U0rNxoAunmgor7pNom1L0wi46OcOXPGTkxMiL6+PhXH8TGlVAXAvQAqabcgcexAGsgCAQ8S +ggNLRCIJgKzO9VoVe6fH0NsbYWlxFQtLq3ReODkmiA2gY5OI0QCSOfMcRstZdoWLt2fbAAzwT+7e +CVWQEyCvKCHwpXdn8dj0WNcA0qMk/vy1E5ydyCS+febmzj9P4bls3XeEnwqcEtrF+bf4N0nBtm1s +AB+5fw8efWAfBuo9nvhDzk/E3x7ll0X8pO+zfz/W3u3HRr/lOI5/v9lsfubEiRPLTzzxROuFF15w +4nl6rJVhUOlyvWjhupYbBQDXA/W6kQDy6sTly5fx9ttvm927d8tKpWKUUm9FUTQA4G4AKiRyy2Ye +IRIDXh4IkCpA0WWWT5TcJq2AFRZbx4cwNT4IAeDCpQVonWTA8ZzfIEiWmXB1uIAan2AjCaVNwICM +alJK7Bzuh7YWsSm/PX/uCv7Du+cw0deD6YF6d+eevoTvnppjfT5m7h8n03I5nj8heIrgE2z0s57Y +W+RN0ElcP2Kax3/4wDQefXA/7tg5yRZ+QQDAnF9IkroiJdqJ3+YTv3fztRN/U2v9x3Ecf+r48eMX +P/vZzza+/e1vJ86c8uNuveM6r9xwILgRFy/7YN20pV9umba2flNTU/KXfumXenbu3FkZGxvbMTw8 +/D9Xq9WfiaJIumQgtEiE8gtFugQhWZ4DK5wRETDWINYG2hoYbaGtQaw1rAVaOoaxFq8eO4uX3z6L +4+euAFBARUJIRZmAhAIiCSsVRKQAqQD+34jYICjbNyEFIHjugODoQMnjRSa2CYDBTQi42YOhumMD +jpmYo1gl4WXRvfvUOmOam/1n4BcrscbbL7xEYAxgNSyHIbtpuoLVA8FeApr4o3m9A43d20Zw34Fp +3LNvGhGH8kYyghBARUXet6+k9Gsx+ps38MQfTuqxKSu/SVx+ptVq/dni4uJvvvHGGyeefvrp1b/5 +m78J/f22xH6ntry6Mm3d9Om6XG8JYCPE3wlFCzl9h00uLi7iwoULGB8fVysrK4u1Wu2ter0+AeAO +wEkAYSRf+222H5OO6YlHSFYJiBjJSE8ZZxRb7ieG+7F7egz1aoTl5RUsLjUC0T/IAOy4O+fUF23c +PiQswGXipc1yckyeVcf1PjkH584DSw2Jhd60X1szkbp8e8bQPAYftGMSq73T48N9NyefObyNEx1f +sIQg4hZn8IkDL0CMLUN1fPDgTjz24AHsmhpLOD7P6KsomtMvpSAQsG5AFHP+kPjjOIZNAn0Qx/FT +V65c+a3vfe97x7/73e82v/rVrzqLf6exV2a/G/WgU7khksD1AoBOokrRC8kk2Jzj9G9X+5cuXRLL +y8totVpyZWXl6sDAwFu1Wm1SCLEfSEDApRAvpQ5AEKdsAw6RcCZqhpQS1YrCzOQIpieH0VORWFhY +xWqjmQTJIMmYazUlvrTsW6cpBDoBA+tm4wEu8SXWgARb550hzsXdm4CY2xKO6mQevptzz1mPyW3n +fPfu3MRHL9iFJ2Jn0NMk8gd6vm3FbYTvYv6HeiM8cMd2PPbAPty9dxt6eypQMuH2FRVxgI8DWAry +STws2Qa/UOwPOX9g8f/S3NzcJ5955pm333jjDf3888/rlZWVbplLFqPKGvNlAaIMHV23slEAWO8N +p+uuC5fP+W2rm52dFcYY0dfXJ9977yrmQaYAAByqSURBVL35gYGBH/T29o4rpfZba0XaLdj+iYIE +EnQIDw8eC4LzBcUQCE4Yolgq6O/twe5tY5ieGEKPklhcbiRAwKmsfDCQJs+AsCEYsBjtgMPbDBwh +2yTgJuT41rKrLiD4cAuz8LjzHLHHMZ0Ta7hFUkgyIJ3fcuiuZZ3ethn2Aqu/bnkJYrgvwv0HpvGR ++/fhvjt2YKivTtl7JEVeUgov6UV+AZ685dQTIImhsmtz96fFfrL8x9Ba25WVlS/Ozc198ktf+tIP +jh07Zp9++mm9srJSNO7S4zRrvHYay+kRlXWc7p9VrhsQXA8A6KYtD/WA7JcVHm+E+MN62Wg0xNWr +VxFFkTx9+vSV4eHhN3t7eweVUgesTWJrrU0IXKSIv+2hWAWgrgn3d4kn3bGQPBuR1YLBvhr2bB/H +jskR9PVEWG20sLi84mfTkceAbAlCk4TgZtVZJwFoVhFccI0xcGsUeCLmKboiprh8G1jZE2kgqaO+ +Lb5+nIAJz74LLfqJf5+CdShxqnP5tfwqS9aH+xpMDNVx/4FpPHaYCH9koJeTdrjEHSTuK5Gk8JJC +QAkJ5+wQAn6mZcj5/eIw7RN6QuKPl5eX/+Ldd9/9v770pS+9ferUKXv06FHdbDbTY61ofHYavyjR +J+866XNvaNnIP1gP8ee1d/OSywBFWBzx22AfADAxMSHvvPPOSk9Pj3j00Ud3HDp06Ff7+vp+tlKp +1JxhULrYcl5FJjQMyjYDIWe2D4yDZORnkZQHqrEWMefjN5YMhprF1SuLK3j75Bzefu8ijp+9AuvQ +Q0kISEAKNvqRIdAKNvxJSXMDhIRg16Rrc8BkXXrx8PWI8DgVURgGLoEMnT7FF3NcGEBYyg3o7BYw +zp6huY/1ocx7pkewb/s4PrBzEkMDvbTwp5JM2CzaC6ASKQ+8zs1Hob18n0Ab8aez+KQDfRzxt1qt +1eXl5T999dVXf+9rX/vaqbNnz5o333xTw8sRSaY2YE3GHxts6bqifaTqkWpLH98IA2JuWS8AdDqv +SMzJIuDQ5SJTx2miTwf9ZPVJ72cduw+tHnjgARVFkXzkkUcmH3744V8cGhr6pSiKBsJU4Yq9A245 +aSGTZaXa048lQGDdBBRjYQUTPBvmjDXQhtKCOSAwbFHX1uDYqQs4fuYiTpyfx+yVRXpsDgEWzhsg +hPcCQPCxAB8zMFggmd8g4OcQr8HKYGxakMfAUuouN+uQYhQohbdwQUtsdXeLfFivjhCATIz2Y/fU +KPZOj2LPji2IVGIwbSd8m+TtY2FKBoRP0zSsJ3wgZ/GOUN/3AT8x4jheuHr16mefe+65P/z6179+ +fnZ2Vp8+fdoRepq4846z9l0xBX1YXmk7LrpWEUBklXWDwHoAoBvOn0f4Zdo6EXQnKSEEkizg8OcM +Dw+rLVu2qP7+frlv377+n/qpn/rpiYmJ/7ZarY4l7kHpXYQeBISADPZDNyG53tqlAZpQLJjjs5vK +GljAA4OTCGABbQ2WG00cP3sFp85fxunz8zh/ZREWTPRsW6D/6VyEwqcrg3C57/nVyCDWITMZVODy +E6AgHwE4QnftPnzZGlg4Lk9j3FqLraP9mJkYxsy2UeyaHkNfT8XH57uIPSWVN+jR9AaVxPILCqsS +kJ7r0/8VSIv8awJ8UoRvjEGz2bw0Ozv7u1/4whf+/K233lo8ffp0fOXKlSzC54f1dSJ1jIz+Fmuv +0wkwykoH3QDBukDgRgJAWV0or72I6IvaO3H9zLbBwUE1MDAg+vr6VK1Wi37lV37l8X379v2zWq22 +W0op2qSBNlBolwbKAoGxTPQsTlvYoI6mEXupQFsYGDRbMd6bm8fZ2as4e+kazl+8hmsrTR6piYRA +T+RSX7pjmtVIpX1NvLbiZie6rj5dmCaVxDgJwXA3jcHeGqbGBjG1ZRA7JoYxPTmMaqTIBcpivoRb +jVmkCJ8kFy8JlCD8Ijdfivjt6urq8ePHj//fv/M7v/M3y8vL+vjx4xqUVzmP4xdJA2WJfSOqQbfq +QZm23NItAGyE+N1vWeLfKIEXbWnpwG1q69atcmFhQYyOjopf/uVfvu/ee+/9b4aGhh6KoqjiFhFV +7jcHBPyKs4BXCdx/MIZo1NC84YToQehA0b0s3gI82K2vA8BufYOl1QbOX1zA3JUFXLi8hEtXF3Hp +6gpWWy1AiAQYYANpwL050f4V/BC0wTEjFgQsNAQEapUIo4O92DLShy3D/ZgYG8Dk6CD6e6ucaRk+ +557ycfrw7lQn+gtYInxOyUaT95I5Fm5OhLuvtK6fJn5n8KMw3xhxHLcWFhaee/nll//dpz/96Zdn +Z2d1T0+PWVhYCIk/i8t3s6HLdqT2kVN/00DgegFAJ4K3GXVZ/cL9rON0vH86XiDdN31++jpZ7Wpk +ZASVSkU0m03x0z/90zsff/zxnx0bG/vJer0+GK4krIKowRAI0gZCIAECCwBsH/BAAJCNwBsLWSqw +DgyI+zrJwEkQISCQOmGx0mjg8rUVzC8sY2GpQdtyA8uNFlYaLaw2mmi2DFqx8cDiuG8lkqhWItSq +CvVaFb21CgZ6ezDQ24PB/l4MD/RgZKAP9VoFkvV3BAQvOTTacXDBHF1KlRjxBAXxgIOuXKL0Nj3f +Cg9EobhfNKPPc/84xsrKyrXLly//5Te+8Y0nn3rqqZOtVsteuXLFop3zh8SWBwAoaHPnIXXcDQDk +1Ymcfsg57lSfW7oBgKy+RXUh4WcRNFLHZTh8EcGX6RMSfsd+Q0ND4urVq+K+++7r+9jHPvaj+/bt ++1i9Xp+Iokh6NUCpTGlgrZcgGwjogKIKibiJkE3AiS2Mlwxs0JYkuKDzLBgUmJos27SttcFISs7N +Kj51mk24dnLv9MfVEecO8u2JRLx3xO3ddu5d0D9PzrPt7yFN+HnE3ybuJ6G9ZmVlZe6dd975zB/8 +wR989cUXX1z0j72W+LOIuBOxd5IIOgFAFsCgoL9I1adL2brcUgYAivoUcf50ex4IFBF/XkRgUV3I ++cucXwgC9Xpduuiwj3/84/c/9NBDPz8+Pv5AFEV1T/QsDUgl2wyEzvpeBAQAAhsBfW9Hm4a/ZULw +VMuM3wOCI3AfwQh4QKF/ZjNz/7tz1wQ/ISB6kE5Ode7FunkH/KIYNFwWHloJKZQMhLsNuHwKntsD +Xsene1pL+H7LInw2AMZxvHL58uUXnnvuuSc+9alPfX9lZcU9sUZ5ET/dL7Ts57V1Oh8F/w8F+0jV +I9WWdVy2zZcygUDrBYA08Yf1Zbl1ZjRfxr7bVM5+VlvWFgX7EoCM49j3f/HFFy/Mzc0d3bJly/Lg +4OBOIUSvyywL5tzhgHUPnJ92m8YIO7uov3CEFgQUMauU7NengCIXIkAitQSJ5EoR4EgWtR2BKikR +cb0EcW4lqD50xykpKMWWP1aQzkXHEk6kBJQgIx9N1gkMe97Sz/8biYEPEAnRQwTD3RF6DtcPxHwX +2BPHsQvswerq6qW33nrrTz/72c/+f3/yJ39ynL9ZyESKxkxe+HjWMVL76eOsMZ9X8tq7ucaGy0Yk +gDLcP+tFZXH6PAAAij9Smtt36lv0gcvYF/zA+vjHP/7QkSNH/vH4+Pi9URTV0ipB1paWCACkuG+y +H6oITqoH4PV9CM4/HEgArlAEI53vVAQgI5JRJFICYUxyT76LQMD5pVMgAgkh6S/brgG4KdYiQ8Sn ++zQB52/n+KGen5mzn0Bg9eLFiy8///zzT/32b//2c8jmxEV6ehbHzms3qXaU6JvuU1Y9QKodGb/I +Oe5U31Y6SQDr5f7hb5HBTab6hESngraQe6eJUQV9FPKlgHRbkcQQIVtC8H2fffbZ8+fPn39jcHDw +6uDg4JRSqt9a60zY7aJrIBEgFNfXlNQ3tixuizANGb3GxG2WSAkuQYnjyC7sOAGe1CYCgBLS14sU +UCXXA5/H6bdcolQ43z0DgUxAAxY+pRk9PtFDnkvP+/TTMfwh149ju7CwcO7o0aN//sd//Md//sQT +TxzLGBtZDOF6bgh+kWpzH1IG+2Ffm+oXlvQ11ltKSQ/XQ0wJj9fD/fO4chY45KkE6XZH0OF1VcG5 +Rft5UoDffvEXf/GuRx999LHp6ekjvb29w6FRUORIA0KIzFwDRN9pTtz+um2qyiUkEUE9eQjyP2/a +GCh5CfK84rIm+Xvy5gbbJjHArv2vRPRoA8FQXfKcP4PjpwN9lpeX50+fPv3db33rW3/7h3/4h68h +IZQ0987TzbP2w7q0sVCn+qXPyeL8oeSR1a+sfQCp4+suBXTD4bPasoAgCwQ6IWlZsT1Plytq62RH +KAKXPMJf80wTExP1X/iFX7j/wQcf/MiWLVvu7OnpqXcCgjZ1IA0EKRBoN9Kt/TRpUEh/lFwzRIci +RMEoyiB219CedTlbInJEnykFpAi/0WisXLhw4fXvfe97z3zmM5/5/rVr11aQLU53Ms5liflFxJxu +T+9ntZVRJ8J77qQipPeDL9D2m/0xCsr1BIBuuX9IWAj280S5PHDI4vpZAJB1nW6MQGVsBOLee+8d +/ehHP3rvwYMHH56cnNwfRVElEwiEhFRyjbidBQZANhB0AoV0SRYlK1PaVjYovmqbXt+Z8JGh7+cR +fhzHrdnZ2bePHj3690899dRLr7322iUUc9JOOn4R4ecRuKvLkgbyJIoiQEDGvXUrBSCnLl2uOwDk +jboszoiMuiJxupMe10kCyAOAoutkXausJJAr1Rw6dGjLj//4jx+65557jmzZsmVfFEXRGgkgRxpo +I/4OQCDooP0DpY7bi0WCuXklW31I2y1CT4fpQPjIEPnTRB+qAHEcxxcuXDj26quvPv/FL37xlVde +eWUOxcRS1i3XSQLI2zoBQCfw6ARInYi/CADS+yhRD+D6A0AeCHQDAEVi/PUGgCL1YkMA4PYPHjy4 +5Ud+5Ec+cOjQocNbt27d61SDNYTPUoHPGZBlHxAc3psHBqF0ACbGDB9/2dJG8Nb6/5/F5df8pgAg +j+MjddxoNFbOnTt37NVXX33x61//+usvv/zyBXcHHbYiAOgkpt8MAMiyUXQCgLxjBMdZ+yhRD6Ac +kee15XF/91sEAGVE7U6EG24qdW7a2t8JAIpUjaz7Q0afomfGXXfdNfKhD31ozwMPPHBo+/bt+/v7 ++0eygMC5C6VwhsK1IJCWCKy1NEUYa7n/eonflTyu73+N8fdQtIVcP0vvX1xcvHzmzJm3v//977/y +7W9/+/jrr79+GfnEkCYioBynLSL4IgDQqevogr5FANCNJJB+ZmT85tWlS25btwBQxP3db9F+GeLq +BACdCLwIHLLOT7flHW8EAHz9zMxM38GDByc+/OEPH9q9e/e+iYmJnVJKkVYD1ngKIHIBASiWBvxH +CuryRoSXHFKliNuXIfyQ6APit3Nzcyfffffdt7/1rW+98tprr104derUIjoTQzcAUEbk1xltRUTe +CSDKSACdQAAd9tFhHyXqbxgApNuKxOc8YssT8TuBQLcAkfW/yoCAe8asZ0o/9xpQrFar1b179w4+ +8sgjuw4ePHhg69atu8fGxrbk2QTagoekTADB2wqKQaBbSaCTYc/9WuMCkdZa9vN0/kuXLl04f/78 +8ddff/0Hzz777Iljx45dW1paaiKf2LPqTFDfLfGXEfnzCLyorZOKkHdfRSCQfnZktGXto0T9DQUA +t1nkc8ssnXsjEkBWfTcSQJFE0AnEigDAFZk6BgA5Ojrau2fPnv6HH354/759+3bt2LFjZnBwcCwL +AIrVgXY1IE8acICRLuFcAn+c9YuE0F19Lufn/WvXrl06c+bMyWPHjp14+umn356bm7t27ty5lfDf +IyFqd5wHAJ2IpxPHX68EkCcVdCsBZIFC+llEThuC36J9lKi/KQCQVZ+nBpQBgCJiz2sPiV6k+tws +CSBPKgrfnxoeHu6ZnJysP/LIIzvvuOOOndPT0zuGh4e39fT0qCwQaE9H1o3bML+UdesBWDthhwm+ +0Wjo+fn5M2fOnDn9gx/84OQ3v/nNk7Ozs8vz8/MNEMEAnbndjZYANNYSZhoMOqkC6fZuAKAI0Dq9 +C3TYR4n6TQDIuG5ZAEBG/UYBoE1a6O3trfT19VXvuOOOocOHD+/ctWvX1vHx8amJiYmpSqVS6WQc +zPotW7rV+VutVmtubu7cxYsXz504ceL8Sy+9dOKNN964urS01FxeXqb10tcO4I0CgGvbBIC1+yhR +/74BQBbhdwsA3QBB3rkbUQGKQCD9zFnHeX2y3ikAyGq1GtXrdbVz586+e+65Z+vMzMyWycnJ8bGx +sbHBwcGxvr6+gY1KAWW4/9LS0sK1a9cuXbp06dLs7OzFkydPzh09enT2/Pnzi/Pz87rZbLq0W0D2 +AO1E+J2Os4h/IypAFsF2S/jrAYA8FeAfDAC4ksUluwGAdFuRDaCoPev8Igkgbz8k/usBAOn9ovcb +1kn2IIjh4WG1d+/ekZmZmaGJiYmhkZGRgYGBgf7e3t6+gYGB3mq1Wq/Vaj1KqWqlUqlIKZUxRoIu +YowxutVqtbTWzdXV1Uaz2VxZWFhYXl5eXlpYWFi8cuXKwtzc3NV33nln/tSpU/Pz8/PaUOl2gKYH +d7qtGwAIQaAIAPIkgDwbQJ6OX8YG0AlsygCAU2/Sz33bAEBWXR6x5IndWQCgUvtpos7i9Fn1ndyA +7noo2C+yA6Sf2/Xp9L6K3m/6m2R9oyL2Xsz6k5I7WHLa0nVZhJ3VljegTao9DwCQ2tdB36z9Iokg +S4zPInaLfBXBorMXIA+Y8sAA6Py+NgQAUV5DwYU6DaSwT1bf9DXC47wPLpC8JBnsu6JSbUXilEFn +QpOpfun9dH+NYgBw17NBW/g/0v8PwbNktYXXt6n+QPsHlxl1ZUr6OdP17n9nAYAI7jnNzVxdej+8 +ZpoYUHCcBRhZHLUIAIpE8SzgyTovfI6888P3kH5n6RJ+2zLfrtvvCyAfALol9DL90+cidX54XOb8 +9IdJA0M4mNKElR7c7johVw+P3fOlP0pauskDAJM6tqm6LFAyOW3I6IvUMxXVd1vKcJW8AV3EsbKI +ogzBFxFlHuEXceFOYNCJc3dDeHnP3E0peu+d+q8p3UoAZf7ZRoEg74MXtYdEj1Qd0C4ZZHGktHhu +sZbwRYm28Frp9pBDh8d5KkB431l90//DHeddq+xAyzov7zul/6+ry+L+6WuFfcPrpwksBLJO3LlT +XR7nLtMvr283W9Z7KFu67V+qXG8ASJcs7hWWrIHbCQCKOGLWwE9fS6T202pDFrGn64B8w6azfmfV +h/cZqg3hM4T7OuPcrOfOOy7bFpaigZZuy+prM9qy9tPfNastj3CywL8bALCp36L9Mu1lib/M82SB +3w0r6wGAvBvL4ghl1IiwOFHe7YeliMg7AUCa6NP7abHcEXcopod14f/qpAJk9bWptvC3U13Z4071 +nUoeEHQCgTxiz6tLf5M8gilLXJ2AoBMApMGiGwAo05YFbFlFZPQr+01KlyIAKINAWYSeBQRF58uM +OnfN8MW5flkAkSaU9MdPi9yuPm2ISxN7WoQvIuqyAJC+500AaG+7WQDQCQyyCDlvP4/oi+67k/Ey +LJ2O80rHfutVAfLAIYv4O4mlNufYvYjQEJcm6LTun94Pzw/vL/2btQ+0E30oDQDtRJ0FAOk+yGlP +33NefRmCv9kqQFZdJwDIq88jmnR7JwDIIrKyANAJFPJUiKx7SRN4+h7TYz9dyhJ9WTDILNfLBpAG +hJCYykgDWX0cwaVfbnhNiUQ/DgHDfYCQ67vjcD9LxA+PdU47Un07cfoyXD6P2PNAIqtvmfpuS7cD +L4+489rz2vKIP32crktz4Cw7QN5xkXEwzeGR0yfr/rKeJ68f0E4PZYFgXaUTAORx+qy2NFd1del+ +WdcLCTFNhO4Fp4ksvHbWfYRAEF4rbAuvFwYDhfWdRPxOHL4bUb+Iy2+U469XAtiIRNCJ83cChiwQ +CPc7SQBZXDkLIIp09U6gUBZcsoAg/W6y3kvWu0nX512vY7mRXoA0ELj9NLED+YMzJHJHwDLV5iLz +0upACA5ZIn76PvJAKO9erycAFO2XOc6ruxGlE9F3Ou60vxEAyGors3UiamS0hdGGYZtBuXtJt3d6 +PzekdDNoyg66vIHeiUjyCK5oHkFWe1GIblFbWU6fd+95z1b0TvLqyh7n1a2nT1jKDLzrBQSdQCBs +60Q43UoGRQReti2Py3dSBzo9W947QUZbp7rcslEAyGpL9yuKge8EBOn6tB7eaZJR0fmdCD/rnlDQ +J68t67dov8xxXl2ZtvWUbkXNjUoEZQGgqK0MQBRJAlncvROR551f5p7Sz5t2g5eVDG4YABT1zxuw +ecRQhosWceBu++RJD3nttsP/Sj9TGLFXBACuj9vP+n/pNnec9b+z6rOON1ryCFgge2CG921zjtNt +BmufN31t18fktIf/I9xETr07p2wwTxniLuqTdYyM9qxnQkZ9unRF/MD6Bsp6JYEsIirDSddL/Os9 +t+he8zh8uB8SuCzol+4T7rvj9P8LP3AWQGT9j3TJa+uGq6QJOuvaaQIH2oncZPRP76f75/UL/1+a +aMpw4/USejfnpvfT95jVXvS86dI18QM3zwiYrgt/kdovc800t0ZGfR6Ro0RbOjgpDxzS10KHtvR+ +p7a8ujJtN6N0OyCLBnMnzpdFLGFbEREVGebS1yxD4On/W4bjl30uZLTdsLLeAbQRKSDrN2zPI9Jw +P0tyyOvT6TjvfxTdU9GzdEPgnY7z6sq03YyyEQDodJzXVpaYygJEWQLOOy7qU3RPnZ4l79myyrqB +4kYAQFZ7J66YVd9JHAfaA33SInh4rpMU0jp6+lqd7rWT+N+pPev/dtOn2/YbXToNvPWAQLqurGSQ +1Z7VlqVKuOO84LP0eW7Mpa9Vhut3AoGiPnnlpgNAp3M7DeZQDUDOr3uotEXfEXJY0sTbDXfP6pN3 +z1n3mHdu0TXy2rtp66bPjShlVbZu2jpxvDSBCRQTWCfpoBspIfxNW+hD4HD9wriUIjAI29P3VFRX +pq1j2ejgWS+H6sT98/bLEHin9rzrdgKkovvOO866l6xyo8T8jX7fjQyu9QzabgmhWzUhDzTcflkA +KNOedY9lRP0y9WXbO5brxT3WAwTr0ZU3IoqXaSvzvzv1K3vcqb5s+406F7hxAFDUXpbIOx2X0ae7 +JeL1qB5F52Ud59V10166XE/xcT3i6nqBoYyuXRYEis7rpi3reL31Zds7lfcTAMqc3y3n6wYM1tNW +ltDz9jdK6BtVq7ou11t/3IjO2g1xdbvfqa3b9m7riurLtpft836W6zGAuwGF9dR1275eMCh73Km+ +2z5dlRs1oMpet1vddyNE/H4DQKe2jfS9lUs3g7Zbu8H7CQDrae+mbT39ui43epBdrwG/UdXhetR1 +arve4vx/jABQpv96OOj1Ao+N9CnTtpG+6yo3a5DdKCDIq79euvhGxfL/GDl+p3IjJYKyfa637aFT +fae2jfTdULnZg+56EsT1JOaNEvGNJvTbDRzWM4CvN4GslxivF2iUbV9v3+tS3o+BdaMIwPWxGf0F +sl+u6HBti7VBRxvp5/pmlSIbxE0fGBssRfdf5vmLSnoS0Xr72Zx7yRor4Zi6Uca69+Ub3yqc5Wb4 +um80573ZLtXbqVzPwX2jOerNMMzdMoCuOne56eVm+76vB7H9QyPY612u94C/Hte73sbJG33+Ztks +m2WzbJbNslk2y2bZLJtls2yWzbJZNstm2SybZbNsls2yWTbLZtksm2WzbJbNslk2y2bZLJtls2yW +zbJZNstm2SybZbO48v8DggJUjj9y5wwAAAAASUVORK5CYII= + + + + \ No newline at end of file diff --git a/fleet_rental/doc/changelog.rst b/fleet_rental/doc/changelog.rst new file mode 100644 index 000000000..f393a607c --- /dev/null +++ b/fleet_rental/doc/changelog.rst @@ -0,0 +1,47 @@ +Changelog +========= +* Nilmar Shereef contact: shereef@cybrosys.in +* Jesni Banu contact: jesni@cybrosys.in + +`10.0.2.0.0` +------------ +- Pre Invoices Feature Added: Contract may be past record. +- Smart Buttons: Related invoices in Rental Contracts. +- Image of Vehicle in Rental Contract. +- Date Validations in rental record. +- Pending Invoice validations added. +- Reporting on Rental Management. + +`9.0.2.0.0` +----------- +- Pre Invoices Feature Added: Contract may be past record. +- Smart Buttons: Related invoices in Rental Contracts. +- Image of Vehicle in Rental Contract. +- Date Validations in rental record. +- Pending Invoice validations added. +- Reporting on Rental Management. +- Coloured Tree View for Rentals. + +`9.0.3.0.0` +----------- +- Changed Menus: accessories/tools. +- Security changed. +- Checking list invoicing changed. +- Field changed in recurrent invoice line. +- Company Image added. + +- Added xml data for vehicle stage. + +`10.0.3.0.0` +------------ +- Changed Menus: accessories/tools. +- Security changed. +- Checking list invoicing changed. +- Due date of invoice added in recurrent invoice line. +- Company Image added to "Fleet Rental Module Logo". + +- Added xml data for vehicle stage. + +`10.0.3.1.0` +------------ +- Colour Widget Dependecy Removed. diff --git a/fleet_rental/doc/changelog.rst~ b/fleet_rental/doc/changelog.rst~ new file mode 100644 index 000000000..9bc8add5f --- /dev/null +++ b/fleet_rental/doc/changelog.rst~ @@ -0,0 +1,43 @@ +Changelog +========= +* Nilmar Shereef contact: shereef@cybrosys.in +* Jesni Banu contact: jesni@cybrosys.in + +`10.0.2.0.0` +------------ +- Pre Invoices Feature Added: Contract may be past record. +- Smart Buttons: Related invoices in Rental Contracts. +- Image of Vehicle in Rental Contract. +- Date Validations in rental record. +- Pending Invoice validations added. +- Reporting on Rental Management. + +`9.0.2.0.0` +----------- +- Pre Invoices Feature Added: Contract may be past record. +- Smart Buttons: Related invoices in Rental Contracts. +- Image of Vehicle in Rental Contract. +- Date Validations in rental record. +- Pending Invoice validations added. +- Reporting on Rental Management. +- Coloured Tree View for Rentals. + +`9.0.3.0.0` +----------- +- Changed Menus: accessories/tools. +- Security changed. +- Checking list invoicing changed. +- Field changed in recurrent invoice line. +- Company Image added. + +- Added xml data for vehicle stage. + +`10.0.3.0.0` +------------ +- Changed Menus: accessories/tools. +- Security changed. +- Checking list invoicing changed. +- Due date of invoice added in recurrent invoice line. +- Company Image added to "Fleet Rental Module Logo". + +- Added xml data for vehicle stage. diff --git a/fleet_rental/models/__init__.py b/fleet_rental/models/__init__.py new file mode 100644 index 000000000..b4c2922d4 --- /dev/null +++ b/fleet_rental/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## +import car_rental +import fleet + + diff --git a/fleet_rental/models/car_rental.py b/fleet_rental/models/car_rental.py new file mode 100644 index 000000000..3dfbdfcc9 --- /dev/null +++ b/fleet_rental/models/car_rental.py @@ -0,0 +1,626 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## +from datetime import datetime, date, timedelta +from odoo import models, fields, api, _ +from odoo.exceptions import UserError, Warning + + +class CarRentalContract(models.Model): + _name = 'car.rental.contract' + _description = 'Fleet Rental Management' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + + @api.onchange('rent_start_date', 'rent_end_date') + def check_availability(self): + self.vehicle_id = '' + fleet_obj = self.env['fleet.vehicle'].search([]) + for i in fleet_obj: + for each in i.rental_reserved_time: + if each.date_from <= self.rent_start_date <= each.date_to: + i.write({'rental_check_availability': False}) + elif self.rent_start_date < each.date_from: + if each.date_from <= self.rent_end_date <= each.date_to: + i.write({'rental_check_availability': False}) + elif self.rent_end_date > each.date_to: + i.write({'rental_check_availability': False}) + else: + i.write({'rental_check_availability': True}) + else: + i.write({'rental_check_availability': True}) + + image = fields.Binary(related='vehicle_id.image', string="Image of Vehicle") + reserved_fleet_id = fields.Many2one('rental.fleet.reserved', invisible=True, copy=False) + image_medium = fields.Binary(related='vehicle_id.image_medium', string="Logo (medium)") + image_small = fields.Binary(related='vehicle_id.image_small', string="Logo (small)") + name = fields.Char(string="Name", default="Draft Contract", readonly=True, copy=False) + customer_id = fields.Many2one('res.partner', required=True, string='Customer', help="Customer") + vehicle_id = fields.Many2one('fleet.vehicle', string="Vehicle", required=True, help="Vehicle", + readonly=True, + states={'draft': [('readonly', False)]} + ) + car_brand = fields.Many2one('fleet.vehicle.model.brand', string="Fleet Brand", size=50, + related='vehicle_id.model_id.brand_id', store=True, readonly=True) + car_color = fields.Char(string="Fleet Color", size=50, related='vehicle_id.color', store=True, copy=False, + default='#FFFFFF', readonly=True) + cost = fields.Float(string="Rent Cost", help="This fields is to determine the cost of rent", required=True) + rent_start_date = fields.Date(string="Rent Start Date", required=True, default=datetime.today(), + help="Start date of contract", track_visibility='onchange') + rent_end_date = fields.Date(string="Rent End Date", required=True, help="End date of contract", + track_visibility='onchange') + state = fields.Selection([('draft', 'Draft'), ('reserved', 'Reserved'), ('running', 'Running'), ('cancel', 'Cancel'), + ('checking', 'Checking'), ('invoice', 'Invoice'), ('done', 'Done')], string="State", + default="draft", copy=False, track_visibility='onchange') + notes = fields.Text(string="Details & Notes") + cost_generated = fields.Float(string='Recurring Cost', + help="Costs paid at regular intervals, depending on the cost frequency") + cost_frequency = fields.Selection([('no', 'No'), ('daily', 'Daily'), ('weekly', 'Weekly'), ('monthly', 'Monthly'), + ('yearly', 'Yearly')], string="Recurring Cost Frequency", + help='Frequency of the recurring cost', required=True) + journal_type = fields.Many2one('account.journal', 'Journal', + default=lambda self: self.env['account.journal'].search([('id', '=', 1)])) + account_type = fields.Many2one('account.account', 'Account', + default=lambda self: self.env['account.account'].search([('id', '=', 17)])) + recurring_line = fields.One2many('fleet.rental.line', 'rental_number', readonly=True, help="Recurring Invoices", + copy=False) + first_payment = fields.Float(string='First Payment', + help="Transaction/Office/Contract charge amount, must paid by customer side other " + "than recurrent payments", + track_visibility='onchange', + required=True) + first_payment_inv = fields.Many2one('account.invoice', copy=False) + first_invoice_created = fields.Boolean(string="First Invoice Created", invisible=True, copy=False) + attachment_ids = fields.Many2many('ir.attachment', 'car_rent_checklist_ir_attachments_rel', + 'rental_id', 'attachment_id', string="Attachments", + help="Images of the vehicle before contract/any attachments") + checklist_line = fields.One2many('car.rental.checklist', 'checklist_number', string="Checklist", + help="Facilities/Accessories, That should verify when closing the contract.", + states={'invoice': [('readonly', True)], + 'done': [('readonly', True)], + 'cancel': [('readonly', True)]}) + total = fields.Float(string="Total (Accessories/Tools)", readonly=True, copy=False) + tools_missing_cost = fields.Float(string="Missing Cost", readonly=True, copy=False, + help='This is the total amount of missing tools/accessories') + damage_cost = fields.Float(string="Damage Cost", copy=False) + damage_cost_sub = fields.Float(string="Damage Cost", readonly=True, copy=False) + total_cost = fields.Float(string="Total", readonly=True, copy=False) + invoice_count = fields.Integer(compute='_invoice_count', string='# Invoice', copy=False) + check_verify = fields.Boolean(compute='check_action_verify', copy=False) + sales_person = fields.Many2one('res.users', string='Sales Person', default=lambda self: self.env.uid, + track_visibility='always') + + @api.multi + def action_run(self): + self.state = 'running' + + @api.multi + @api.depends('checklist_line.checklist_active') + def check_action_verify(self): + flag = 0 + for each in self: + for i in each.checklist_line: + if i.checklist_active: + continue + else: + flag = 1 + if flag == 1: + each.check_verify = False + else: + each.check_verify = True + + @api.constrains('rent_start_date', 'rent_end_date') + def validate_dates(self): + if self.rent_end_date < self.rent_start_date: + raise Warning("Please select the valid end date.") + + @api.multi + def set_to_done(self): + invoice_ids = self.env['account.invoice'].search([('origin', '=', self.name)]) + f = 0 + for each in invoice_ids: + if each.state != 'paid': + f = 1 + break + if f == 0: + self.state = 'done' + else: + raise UserError("Some Invoices are pending") + + @api.multi + def _invoice_count(self): + invoice_ids = self.env['account.invoice'].search([('origin', '=', self.name)]) + self.invoice_count = len(invoice_ids) + + @api.constrains('state') + def state_changer(self): + if self.state == "running": + state_id = self.env.ref('fleet_rental.vehicle_state_rent').id + self.vehicle_id.write({'state_id': state_id}) + elif self.state == "cancel": + state_id = self.env.ref('fleet.vehicle_state_active').id + self.vehicle_id.write({'state_id': state_id}) + elif self.state == "invoice": + self.rent_end_date = fields.datetime.now() + state_id = self.env.ref('fleet.vehicle_state_active').id + self.vehicle_id.write({'state_id': state_id}) + + @api.constrains('checklist_line', 'damage_cost') + def total_updater(self): + total = 0.0 + tools_missing_cost = 0.0 + for records in self.checklist_line: + total += records.price + if not records.checklist_active: + tools_missing_cost += records.price + self.total = total + self.tools_missing_cost = tools_missing_cost + self.damage_cost_sub = self.damage_cost + self.total_cost = tools_missing_cost + self.damage_cost + + @api.multi + def fleet_scheduler1(self, rent_date): + inv_obj = self.env['account.invoice'] + inv_line_obj = self.env['account.invoice.line'] + recurring_obj = self.env['fleet.rental.line'] + start_date = datetime.strptime(self.rent_start_date, '%Y-%m-%d').date() + end_date = datetime.strptime(self.rent_end_date, '%Y-%m-%d').date() + supplier = self.customer_id + inv_data = { + 'name': supplier.name, + 'reference': supplier.name, + 'account_id': supplier.property_account_payable_id.id, + 'partner_id': supplier.id, + 'currency_id': self.account_type.company_id.currency_id.id, + 'journal_id': self.journal_type.id, + 'origin': self.name, + 'company_id': self.account_type.company_id.id, + 'date_due': self.rent_end_date, + } + inv_id = inv_obj.create(inv_data) + product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) + if product_id.property_account_income_id.id: + income_account = product_id.property_account_income_id + elif product_id.categ_id.property_account_income_categ_id.id: + income_account = product_id.categ_id.property_account_income_categ_id + else: + raise UserError( + _('Please define income account for this product: "%s" (id:%d).') % (product_id.name, + product_id.id)) + recurring_data = { + 'name': self.vehicle_id.name, + 'date_today': rent_date, + 'account_info': income_account.name, + 'rental_number': self.id, + 'recurring_amount': self.cost_generated, + 'invoice_number': inv_id.id, + 'invoice_ref': inv_id.id, + } + recurring_obj.create(recurring_data) + inv_line_data = { + 'name': self.vehicle_id.name, + 'account_id': income_account.id, + 'price_unit': self.cost_generated, + 'quantity': 1, + 'product_id': product_id.id, + 'invoice_id': inv_id.id, + } + inv_line_obj.create(inv_line_data) + mail_content = _( + '

    Reminder Recurrent Payment!


    Hi %s,
    This is to remind you that the ' + 'recurrent payment for the ' + 'rental contract has to be done.' + 'Please make the payment at the earliest.' + '

    ' + 'Please find the details below:

    ' + '' + '' + '' + '
    Contract Ref %s
    Amount %s
    Due Date %s
    Responsible Person %s, %s
    ') % \ + (self.customer_id.name, self.name, inv_id.amount_total, inv_id.date_due, + inv_id.user_id.name, + inv_id.user_id.mobile) + main_content = { + 'subject': "Reminder Recurrent Payment!", + 'author_id': self.env.user.partner_id.id, + 'body_html': mail_content, + 'email_to': self.customer_id.email, + } + self.env['mail.mail'].create(main_content).send() + + @api.model + def fleet_scheduler(self): + inv_obj = self.env['account.invoice'] + inv_line_obj = self.env['account.invoice.line'] + recurring_obj = self.env['fleet.rental.line'] + today = date.today() + for records in self.search([]): + start_date = datetime.strptime(records.rent_start_date, '%Y-%m-%d').date() + end_date = datetime.strptime(records.rent_end_date, '%Y-%m-%d').date() + if end_date >= date.today(): + temp = 0 + if records.cost_frequency == 'daily': + temp = 1 + elif records.cost_frequency == 'weekly': + week_days = (date.today() - start_date).days + if week_days % 7 == 0 and week_days != 0: + temp = 1 + elif records.cost_frequency == 'monthly': + if start_date.day == date.today().day and start_date != date.today(): + temp = 1 + elif records.cost_frequency == 'yearly': + if start_date.day == date.today().day and start_date.month == date.today().month and \ + start_date != date.today(): + temp = 1 + if temp == 1 and records.cost_frequency != "no" and records.state == "running": + supplier = records.customer_id + inv_data = { + 'name': supplier.name, + 'reference': supplier.name, + 'account_id': supplier.property_account_payable_id.id, + 'partner_id': supplier.id, + 'currency_id': records.account_type.company_id.currency_id.id, + 'journal_id': records.journal_type.id, + 'origin': records.name, + 'company_id': records.account_type.company_id.id, + 'date_due': self.rent_end_date, + } + inv_id = inv_obj.create(inv_data) + product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) + if product_id.property_account_income_id.id: + income_account = product_id.property_account_income_id + elif product_id.categ_id.property_account_income_categ_id.id: + income_account = product_id.categ_id.property_account_income_categ_id + else: + raise UserError( + _('Please define income account for this product: "%s" (id:%d).') % (product_id.name, + product_id.id)) + recurring_data = { + 'name': records.vehicle_id.name, + 'date_today': today, + 'account_info': income_account.name, + 'rental_number': records.id, + 'recurring_amount': records.cost_generated, + 'invoice_number': inv_id.id, + 'invoice_ref': inv_id.id, + } + recurring_obj.create(recurring_data) + inv_line_data = { + 'name': records.vehicle_id.name, + 'account_id': income_account.id, + 'price_unit': records.cost_generated, + 'quantity': 1, + 'product_id': product_id.id, + 'invoice_id': inv_id.id, + + } + inv_line_obj.create(inv_line_data) + mail_content = _( + '

    Reminder Recurrent Payment!


    Hi %s,
    This is to remind you that the ' + 'recurrent payment for the ' + 'rental contract has to be done.' + 'Please make the payment at the earliest.' + '

    ' + 'Please find the details below:

    ' + '
    ' + '' + '' + '
    Contract Ref %s
    Amount %s
    Due Date %s
    Responsible Person %s, %s
    ') % \ + (self.customer_id.name, self.name, inv_id.amount_total, inv_id.date_due, + inv_id.user_id.name, + inv_id.user_id.mobile) + main_content = { + 'subject': "Reminder Recurrent Payment!", + 'author_id': self.env.user.partner_id.id, + 'body_html': mail_content, + 'email_to': self.customer_id.email, + } + self.env['mail.mail'].create(main_content).send() + else: + if self.state == 'running': + records.state = "checking" + + @api.multi + def action_verify(self): + self.state = "invoice" + self.reserved_fleet_id.unlink() + self.rent_end_date = fields.datetime.now() + if self.total_cost != 0: + inv_obj = self.env['account.invoice'] + inv_line_obj = self.env['account.invoice.line'] + supplier = self.customer_id + inv_data = { + 'name': supplier.name, + 'reference': supplier.name, + 'account_id': supplier.property_account_payable_id.id, + 'partner_id': supplier.id, + 'currency_id': self.account_type.company_id.currency_id.id, + 'journal_id': self.journal_type.id, + 'origin': self.name, + 'company_id': self.account_type.company_id.id, + 'date_due': self.rent_end_date, + } + inv_id = inv_obj.create(inv_data) + product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) + if product_id.property_account_income_id.id: + income_account = product_id.property_account_income_id + elif product_id.categ_id.property_account_income_categ_id.id: + income_account = product_id.categ_id.property_account_income_categ_id + else: + raise UserError( + _('Please define income account for this product: "%s" (id:%d).') % (product_id.name, + product_id.id)) + inv_line_data = { + 'name': "Damage/Tools missing cost", + 'account_id': income_account.id, + 'price_unit': self.total_cost, + 'quantity': 1, + 'product_id': product_id.id, + 'invoice_id': inv_id.id, + } + inv_line_obj.create(inv_line_data) + imd = self.env['ir.model.data'] + action = imd.xmlid_to_object('account.action_invoice_tree1') + list_view_id = imd.xmlid_to_res_id('account.invoice_tree') + form_view_id = imd.xmlid_to_res_id('account.invoice_form') + result = { + 'name': action.name, + 'help': action.help, + 'type': 'ir.actions.act_window', + 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], + [False, 'calendar'], [False, 'pivot']], + 'target': action.target, + 'context': action.context, + 'res_model': 'account.invoice', + } + if len(inv_id) > 1: + result['domain'] = "[('id','in',%s)]" % inv_id.ids + elif len(inv_id) == 1: + result['views'] = [(form_view_id, 'form')] + result['res_id'] = inv_id.ids[0] + else: + result = {'type': 'ir.actions.act_window_close'} + return result + + @api.multi + def action_confirm(self): + check_availability = 0 + for each in self.vehicle_id.rental_reserved_time: + if each.date_from <= self.rent_start_date <= each.date_to: + check_availability = 1 + elif self.rent_start_date < each.date_from: + if each.date_from <= self.rent_end_date <= each.date_to: + check_availability = 1 + elif self.rent_end_date > each.date_to: + check_availability = 1 + else: + check_availability = 0 + else: + check_availability = 0 + if check_availability == 0: + reserved_id = self.vehicle_id.rental_reserved_time.create({'customer_id': self.customer_id.id, + 'date_from': self.rent_start_date, + 'date_to': self.rent_end_date, + 'reserved_obj': self.vehicle_id.id + }) + self.write({'reserved_fleet_id': reserved_id.id}) + else: + raise Warning('Sorry This vehicle is already booked by another customer') + self.state = "reserved" + sequence_code = 'car.rental.sequence' + order_date = self.create_date + order_date = order_date[0:10] + self.name = self.env['ir.sequence'] \ + .with_context(ir_sequence_date=order_date).next_by_code(sequence_code) + mail_content = _('

    Order Confirmed!


    Hi %s,
    This is to notify that your rental contract has ' + 'been confirmed.

    ' + 'Please find the details below:

    ' + '
    ' + '' + '
    Reference Number %s
    Time Range %s to %s
    Vehicle %s
    Point Of Contact %s , %s
    ') % \ + (self.customer_id.name, self.name, self.rent_start_date, self.rent_end_date, + self.vehicle_id.name, self.sales_person.name, self.sales_person.mobile) + main_content = { + 'subject': _('Confirmed: %s - %s') % + (self.name, self.vehicle_id.name), + 'author_id': self.env.user.partner_id.id, + 'body_html': mail_content, + 'email_to': self.customer_id.email, + } + self.env['mail.mail'].create(main_content).send() + + @api.multi + def action_cancel(self): + self.state = "cancel" + if self.reserved_fleet_id: + self.reserved_fleet_id.unlink() + + @api.multi + def force_checking(self): + self.state = "checking" + + @api.multi + def action_view_invoice(self): + inv_obj = self.env['account.invoice'].search([('origin', '=', self.name)]) + inv_ids = [] + for each in inv_obj: + inv_ids.append(each.id) + view_id = self.env.ref('account.invoice_form').id + if inv_ids: + if len(inv_ids) <= 1: + value = { + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'account.invoice', + 'view_id': view_id, + 'type': 'ir.actions.act_window', + 'name': _('Invoice'), + 'res_id': inv_ids and inv_ids[0] + } + else: + value = { + 'domain': str([('id', 'in', inv_ids)]), + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'account.invoice', + 'view_id': False, + 'type': 'ir.actions.act_window', + 'name': _('Invoice'), + 'res_id': inv_ids + } + + return value + + @api.multi + def action_invoice_create(self): + for each in self: + rent_date = datetime.strptime(each.rent_start_date, "%Y-%m-%d").date() + if each.cost_frequency != 'no' and rent_date < date.today(): + rental_days = (date.today() - rent_date).days + if each.cost_frequency == 'weekly': + rental_days = int(rental_days / 7) + if each.cost_frequency == 'monthly': + rental_days = int(rental_days / 30) + for each1 in range(0, rental_days + 1): + if rent_date > datetime.strptime(each.rent_end_date, "%Y-%m-%d").date(): + break + each.fleet_scheduler1(rent_date) + if each.cost_frequency == 'daily': + rent_date = rent_date + timedelta(days=1) + if each.cost_frequency == 'weekly': + rent_date = rent_date + timedelta(days=7) + if each.cost_frequency == 'monthly': + rent_date = rent_date + timedelta(days=30) + + if self.first_payment != 0: + self.first_invoice_created = True + inv_obj = self.env['account.invoice'] + inv_line_obj = self.env['account.invoice.line'] + supplier = self.customer_id + inv_data = { + 'name': supplier.name, + 'reference': supplier.name, + 'account_id': supplier.property_account_payable_id.id, + 'partner_id': supplier.id, + 'currency_id': self.account_type.company_id.currency_id.id, + 'journal_id': self.journal_type.id, + 'origin': self.name, + 'company_id': self.account_type.company_id.id, + 'date_due': self.rent_end_date, + } + inv_id = inv_obj.create(inv_data) + self.first_payment_inv = inv_id.id + product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) + if product_id.property_account_income_id.id: + income_account = product_id.property_account_income_id.id + elif product_id.categ_id.property_account_income_categ_id.id: + income_account = product_id.categ_id.property_account_income_categ_id.id + else: + raise UserError( + _('Please define income account for this product: "%s" (id:%d).') % (product_id.name, + product_id.id)) + inv_line_data = { + 'name': self.vehicle_id.name, + 'account_id': income_account, + 'price_unit': self.first_payment, + 'quantity': 1, + 'product_id': product_id.id, + 'invoice_id': inv_id.id, + } + inv_line_obj.create(inv_line_data) + inv_id.action_invoice_open() + mail_content = _( + '

    First Payment Received!


    Hi %s,
    This is to notify that your first payment has ' + 'been received.

    ' + 'Please find the details below:

    ' + '
    ' + '
    Invoice Number %s
    Date %s
    Amount %s
    ') % \ + (self.customer_id.name, inv_id.number, inv_id.date_invoice, inv_id.amount_total) + main_content = { + 'subject': _('Payment Received: %s') % inv_id.number, + 'author_id': self.env.user.partner_id.id, + 'body_html': mail_content, + 'email_to': self.customer_id.email, + } + self.env['mail.mail'].create(main_content).send() + imd = self.env['ir.model.data'] + action = imd.xmlid_to_object('account.action_invoice_tree1') + list_view_id = imd.xmlid_to_res_id('account.invoice_tree') + form_view_id = imd.xmlid_to_res_id('account.invoice_form') + result = { + 'name': action.name, + 'help': action.help, + 'type': 'ir.actions.act_window', + 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], + [False, 'calendar'], [False, 'pivot']], + 'target': action.target, + 'context': action.context, + 'res_model': 'account.invoice', + } + if len(inv_id) > 1: + result['domain'] = "[('id','in',%s)]" % inv_id.ids + elif len(inv_id) == 1: + result['views'] = [(form_view_id, 'form')] + result['res_id'] = inv_id.ids[0] + else: + result = {'type': 'ir.actions.act_window_close'} + return result + else: + raise Warning("Please enter advance amount to make first payment") + + +class FleetRentalLine(models.Model): + _name = 'fleet.rental.line' + + name = fields.Char('Description') + date_today = fields.Date('Date') + account_info = fields.Char('Account') + recurring_amount = fields.Float('Amount') + rental_number = fields.Many2one('car.rental.contract', string='Rental Number') + payment_info = fields.Char(compute='paid_info', string='Payment Stage', default='draft') + invoice_number = fields.Integer(string='Invoice ID') + invoice_ref = fields.Many2one('account.invoice', string='Invoice Ref') + date_due = fields.Date(string='Due Date', related='invoice_ref.date_due') + + @api.multi + @api.depends('payment_info') + def paid_info(self): + for each in self: + if self.env['account.invoice'].browse(each.invoice_number): + each.payment_info = self.env['account.invoice'].browse(each.invoice_number).state + else: + each.payment_info = 'Record Deleted' + + +class CarRentalChecklist(models.Model): + _name = 'car.rental.checklist' + + name = fields.Many2one('car.tools', string="Name") + checklist_active = fields.Boolean(string="Available", default=True) + checklist_number = fields.Many2one('car.rental.contract', string="Checklist Number") + price = fields.Float(string="Price") + + @api.onchange('name') + def onchange_name(self): + self.price = self.name.price + + +class CarTools(models.Model): + _name = 'car.tools' + + name = fields.Char(string="Name") + price = fields.Float(string="Price") diff --git a/fleet_rental/models/fleet.py b/fleet_rental/models/fleet.py new file mode 100644 index 000000000..28f20c1ca --- /dev/null +++ b/fleet_rental/models/fleet.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## +from odoo import models, fields + + +class FleetReservedTime(models.Model): + _name = "rental.fleet.reserved" + _description = "Reserved Time" + + customer_id = fields.Many2one('res.partner', string='Customer') + date_from = fields.Date(string='Reserved Date From') + date_to = fields.Date(string='Reserved Date To') + reserved_obj = fields.Many2one('fleet.vehicle') + + +class EmployeeFleet(models.Model): + _inherit = 'fleet.vehicle' + + rental_check_availability = fields.Boolean(default=True, copy=False) + color = fields.Char(string='Color', default='#FFFFFF') + rental_reserved_time = fields.One2many('rental.fleet.reserved', 'reserved_obj', String='Reserved Time', readonly=1, + ondelete='cascade') + fuel_type = fields.Selection([('gasoline', 'Gasoline'), + ('diesel', 'Diesel'), + ('electric', 'Electric'), + ('hybrid', 'Hybrid'), + ('petrol', 'Petrol')], + 'Fuel Type', help='Fuel Used by the vehicle') + + _sql_constraints = [('vin_sn_unique', 'unique (vin_sn)', "Chassis Number already exists !"), + ('license_plate_unique', 'unique (license_plate)', "License plate already exists !")] diff --git a/fleet_rental/reports/__init__.py b/fleet_rental/reports/__init__.py new file mode 100644 index 000000000..bc68c5e7f --- /dev/null +++ b/fleet_rental/reports/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## +import rental_report + diff --git a/fleet_rental/reports/rental_report.py b/fleet_rental/reports/rental_report.py new file mode 100644 index 000000000..0d7202a12 --- /dev/null +++ b/fleet_rental/reports/rental_report.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Cybrosys() +# you can modify it under the terms of the GNU AGPL (v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 AGPL (AGPL v3) for more details. +# +############################################################################## +from odoo import models, fields, tools + + +class FleetRentalReport(models.Model): + _name = "report.fleet.rental" + _description = "Fleet Rental Analysis" + _auto = False + + name = fields.Char(string="Name") + customer_id = fields.Many2one('res.partner') + vehicle_id = fields.Many2one('fleet.vehicle') + car_brand = fields.Char(string="Car Brand") + car_color = fields.Char(string="Car Color") + cost = fields.Float(string="Rent Cost") + rent_start_date = fields.Date(string="Rent Start Date") + rent_end_date = fields.Date(string="Rent End Date") + state = fields.Selection([('draft', 'Draft'), ('running', 'Running'), ('cancel', 'Cancel'), + ('checking', 'Checking'), ('done', 'Done')], string="State") + cost_frequency = fields.Selection([('no', 'No'), ('daily', 'Daily'), ('weekly', 'Weekly'), ('monthly', 'Monthly'), + ('yearly', 'Yearly')], string="Recurring Cost Frequency") + total = fields.Float(string="Total(Tools)") + tools_missing_cost = fields.Float(string="Tools missing cost") + damage_cost = fields.Float(string="Damage cost") + damage_cost_sub = fields.Float(string="Damage cost") + total_cost = fields.Float(string="Total cost") + + _order = 'name desc' + + def _select(self): + select_str = """ + SELECT + (select 1 ) AS nbr, + t.id as id, + t.name as name, + t.car_brand as car_brand, + t.customer_id as customer_id, + t.vehicle_id as vehicle_id, + t.car_color as car_color, + t.cost as cost, + t.rent_start_date as rent_start_date, + t.rent_end_date as rent_end_date, + t.state as state, + t.cost_frequency as cost_frequency, + t.total as total, + t.tools_missing_cost as tools_missing_cost, + t.damage_cost as damage_cost, + t.damage_cost_sub as damage_cost_sub, + t.total_cost as total_cost + """ + return select_str + + def _group_by(self): + group_by_str = """ + GROUP BY + t.id, + name, + car_brand, + customer_id, + vehicle_id, + car_color, + cost, + rent_start_date, + rent_end_date, + state, + cost_frequency, + total, + tools_missing_cost, + damage_cost, + damage_cost_sub, + total_cost + """ + return group_by_str + + def init(self): + tools.sql.drop_view_if_exists(self._cr, 'report_fleet_rental') + self._cr.execute(""" + CREATE view report_fleet_rental as + %s + FROM car_rental_contract t + %s + """ % (self._select(), self._group_by())) diff --git a/fleet_rental/reports/rental_report.xml b/fleet_rental/reports/rental_report.xml new file mode 100644 index 000000000..17ee96ee3 --- /dev/null +++ b/fleet_rental/reports/rental_report.xml @@ -0,0 +1,25 @@ + + + + + report.fleet.rental.pivot + report.fleet.rental + + + + + + + + + Fleet Rental Analysis + report.fleet.rental + form + pivot + {'group_by_no_leaf':1,'group_by':[]} + This report allows you to analyse the performance of your Fleet Rental. + + + + + \ No newline at end of file diff --git a/fleet_rental/security/ir.model.access.csv b/fleet_rental/security/ir.model.access.csv new file mode 100644 index 000000000..0af30bfe7 --- /dev/null +++ b/fleet_rental/security/ir.model.access.csv @@ -0,0 +1,29 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +fleet_car_rental_contract_access_right_user,fleet_car_rental_contract_access_right,model_car_rental_contract,rental_group_user,1,1,1,0 +fleet_car_rental_contract_access_right_manager,fleet_car_rental_contract_access_right1,model_car_rental_contract,fleet.fleet_group_manager,1,1,1,1 +fleet_fleet_rental_line_access_right_user,fleet_fleet_rental_line_access_right,model_fleet_rental_line,rental_group_user,1,1,1,0 +fleet_fleet_rental_line_access_right_manager,fleet_fleet_rental_line_access_right1,model_fleet_rental_line,fleet.fleet_group_manager,1,1,1,1 +fleet_car_rental_checklist_access_right_user,fleet_car_rental_checklist_access_right,model_car_rental_checklist,rental_group_user,1,1,1,0 +fleet_car_rental_checklist_access_right_manager,fleet_car_rental_checklist_access_right1,model_car_rental_checklist,fleet.fleet_group_manager,1,1,1,1 +fleet_car_tools_access_right_user,fleet_car_tools_access_right,model_car_tools,rental_group_user,1,1,1,0 +fleet_car_tools_contract_access_right_manager,fleet_car_tools_access_right1,model_car_tools,fleet.fleet_group_manager,1,1,1,1 +fleet_report_fleet_rental_access_right_user,fleet_report_fleet_rental_access_right,model_report_fleet_rental,rental_group_user,1,1,1,0 +fleet_report_fleet_rental_access_right_manager,fleet_report_fleet_rental_access_right1,model_report_fleet_rental,fleet.fleet_group_manager,1,1,1,1 +fleet_cron_right_user,fleet_vehicle_access_right1,base.model_ir_cron,rental_group_user,1,1,1,0 +fleet_cron_right_user1,fleet_vehicle_access_right11,base.model_ir_cron,fleet.fleet_group_manager,1,1,1,0 +fleet_vehicle_model_access_right_user,fleet_vehicle_model_access_right,fleet.model_fleet_vehicle_model,rental_group_user,1,1,1,0 +fleet_vehicle_model_brand_access_right_user,fleet_vehicle_model_brand_access_right,fleet.model_fleet_vehicle_model_brand,rental_group_user,1,1,1,0 +fleet_vehicle_access_right_user,fleet_vehicle_access_right,fleet.model_fleet_vehicle,rental_group_user,1,1,1,0 +fleet_vehicle_log_fuel_access_right_rental_user,fleet_vehicle_log_fuel_access_right_rental_user,fleet.model_fleet_vehicle_log_fuel,rental_group_user,1,1,1,1 +fleet_vehicle_odometer_access_right_rental_user,fleet_vehicle_odometer_access_right_rental_user,fleet.model_fleet_vehicle_odometer,rental_group_user,1,1,1,1 +fleet_vehicle_log_services_access_right_rental_user,fleet_vehicle_log_services_access_right_rental_user,fleet.model_fleet_vehicle_log_services,fleet.fleet_group_manager,1,1,1,1 +fleet_rental_fleet_reserved_access_right_user,fleet_rental_fleet_reserved_access_right,model_rental_fleet_reserved,rental_group_user,1,1,1,0 +fleet_rental_fleet_reserved_access_right_manager,fleet_rental_fleet_reserved_access_right1,model_rental_fleet_reserved,fleet.fleet_group_manager,1,1,1,1 + + + + + + + + diff --git a/fleet_rental/security/rental_security.xml b/fleet_rental/security/rental_security.xml new file mode 100644 index 000000000..8c2247b31 --- /dev/null +++ b/fleet_rental/security/rental_security.xml @@ -0,0 +1,18 @@ + + + + + Rental User + + + + + + Manager + + + + + + diff --git a/fleet_rental/static/description/banner.jpg b/fleet_rental/static/description/banner.jpg new file mode 100644 index 000000000..5e6b5642c Binary files /dev/null and b/fleet_rental/static/description/banner.jpg differ diff --git a/fleet_rental/static/description/check_list_form.png b/fleet_rental/static/description/check_list_form.png new file mode 100644 index 000000000..e52026090 Binary files /dev/null and b/fleet_rental/static/description/check_list_form.png differ diff --git a/fleet_rental/static/description/check_list_tree.png b/fleet_rental/static/description/check_list_tree.png new file mode 100644 index 000000000..febc4704b Binary files /dev/null and b/fleet_rental/static/description/check_list_tree.png differ diff --git a/fleet_rental/static/description/checklist_contract.png b/fleet_rental/static/description/checklist_contract.png new file mode 100644 index 000000000..ead008916 Binary files /dev/null and b/fleet_rental/static/description/checklist_contract.png differ diff --git a/fleet_rental/static/description/contract_menu.png b/fleet_rental/static/description/contract_menu.png new file mode 100644 index 000000000..cb80cbea7 Binary files /dev/null and b/fleet_rental/static/description/contract_menu.png differ diff --git a/fleet_rental/static/description/cybro_logo.png b/fleet_rental/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/fleet_rental/static/description/cybro_logo.png differ diff --git a/fleet_rental/static/description/email1.png b/fleet_rental/static/description/email1.png new file mode 100644 index 000000000..9fbd5896f Binary files /dev/null and b/fleet_rental/static/description/email1.png differ diff --git a/fleet_rental/static/description/email2.png b/fleet_rental/static/description/email2.png new file mode 100644 index 000000000..6cd54feec Binary files /dev/null and b/fleet_rental/static/description/email2.png differ diff --git a/fleet_rental/static/description/email3.png b/fleet_rental/static/description/email3.png new file mode 100644 index 000000000..5ccaecafd Binary files /dev/null and b/fleet_rental/static/description/email3.png differ diff --git a/fleet_rental/static/description/icon.png b/fleet_rental/static/description/icon.png new file mode 100644 index 000000000..da2ab45be Binary files /dev/null and b/fleet_rental/static/description/icon.png differ diff --git a/fleet_rental/static/description/index.html b/fleet_rental/static/description/index.html new file mode 100644 index 000000000..9a50c8ce6 --- /dev/null +++ b/fleet_rental/static/description/index.html @@ -0,0 +1,234 @@ +
    +
    +

    Fleet/Vehicle Rental Management

    +

    This module helps with an opportunity to give the vehicles like car,van,bike,jeep etc.. for Rent.

    +

    Cybrosys Technologies

    +
    +
    +

    Features:

    +
    + Multiple Plans for Rental Contract(Days/Weeks/Months/Years).
    + Integrated with Accounting Module.
    + Automatically Create Recurring Invoices.
    + Sending email for confirmation, first payment and recurrent invoices.
    + Check List Facility.
    + Separate Tree view for Checklist.
    + Damage Checking Facility.
    + Billing Facility for Damages/Check Lists.
    + Contract Payment Validations.
    + Detailed Fleet Rental Analysis Report.
    + Access Rights From Multiple Level.
    + Flexible for further customization.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    + This module is an application for Vehicle Rental System which helps in managing the rental of vehicles like car,van,bike, jeep etc... + It manages fleet/vehicle property by extending the basic fleet module of Odoo. + Currently fleet module does not have any connection with accounting module. But in this module, + we integrate the module with accounting also. +

    +
    +
    +
    + +
    +
    +

    Fleet Rental Management

    +
    +

    +

    Fleet Rental -> Rental Management

    +

    +

    +
    + +
    + +
    +
    + ☛ When you install the module, an extra menu named Rental Management is created + under the Fleet Menu. Also "Fleet" menu is replaced as "Fleet Rental". Here you can see different color + codes according to each state. This helps you in finding out contracts easily. +
    +
    +
    +
    +

    +

    Fleet Rental -> Rental Management -> Rental Contract

    +

    +

    +
    + +
    +
    + ☛ This is the Rental Contract form. You can see the Recurring lines created according to + the Recurring cost. And also you can see all the invoices related to this contract from the smart + button "Invoices". +
    +
    +
    +
    + +
    +
    +

    Checklist

    +
    +
    + +
    + ☛ Checklist Tab in Rental Contract Form. +
    +
    +
    +
    +

    + Here you can add the list of tools given with the vehicle. + When the vehicle is returned back, the checklist can be validated and helps you to identify the + tools that are not returned. The price of unreturned tools will be added to the missing tool cost. + The renter have to pay that amount and you can also add damage cost if any. Check the damages by + using the images of vehicle uploaded before the contract. +

    +

    +
    +
    +
    + +
    +
    +

    Checklist Easy Access

    +
    +
    + +
    + ☛ No need to open all rental contract to see the checklist. +
    +
    +
    + +
    +
    + + You can also create invoice against the checklist from here. + The checklists are those which are in the checking state, + that means the ones ready for checking the operation. + If there is any damage or any missing tool, then you can charge all that from customer. +
    +
    +
    +
    + +
    +
    +

    Email Notifications

    +
    +
    + + ☛The system will send email notification to notify the confirmation of contract.
    + ☛The system will notify the first payment through email.
    + ☛The system will remind all recurrent invoices through email.
    + Note:- You should configure outgoing and incoming e-mail settings from your odoo for email service. +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +

    Contract Payment Validations

    +
    +
    + +
    +
    + ☛ + Here you can see you have 4 invoices and this contract is in 'Invoice' state. + So you can set this contract to done only if all the invoices are in 'paid' state. + Otherwise it will raise a warning as follow. + + +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Fleet Rental Analysis Report

    +
    +
    + +
    + ☛ + You can also analyse all your fleet rentals from Fleet Rental -> Reports -> Fleet Rental Analysis. + +
    +
    +
    + +
    +
    +

    Access Rights

    +
    + ☛Fleet Manager :- Fleet manager has the complete access across the fleet rental management
    + ☛Fleet Rental User :- Fleet rental user can read, write and create the records. +
    +
    +
    + +
    +
    You Looking for a Documentation of this Application.?
    +
    Give a Request Mail to:    odoo@cybrosys.com
    +
    + +
    +

    Need Any Help?

    + +
    + + + diff --git a/fleet_rental/static/description/menu_items.png b/fleet_rental/static/description/menu_items.png new file mode 100644 index 000000000..c80ff0a07 Binary files /dev/null and b/fleet_rental/static/description/menu_items.png differ diff --git a/fleet_rental/static/description/rental_inv.png b/fleet_rental/static/description/rental_inv.png new file mode 100644 index 000000000..def84f9bb Binary files /dev/null and b/fleet_rental/static/description/rental_inv.png differ diff --git a/fleet_rental/static/description/rental_validation.png b/fleet_rental/static/description/rental_validation.png new file mode 100644 index 000000000..665b0acbe Binary files /dev/null and b/fleet_rental/static/description/rental_validation.png differ diff --git a/fleet_rental/static/description/report.png b/fleet_rental/static/description/report.png new file mode 100644 index 000000000..f6a4d8ff3 Binary files /dev/null and b/fleet_rental/static/description/report.png differ diff --git a/fleet_rental/views/car_rental_view.xml b/fleet_rental/views/car_rental_view.xml new file mode 100644 index 000000000..97d0e6cbc --- /dev/null +++ b/fleet_rental/views/car_rental_view.xml @@ -0,0 +1,216 @@ + + + + + Car Rental Sequence + car.rental.sequence + RENT/%(range_year)s/ + + + + 4 + + + + + + Fleet scheduler + + 1 + days + -1 + + + + + + + fleet.vehicle.form.inherit.view + fleet.vehicle + + + + + + + + + + + + + + car.contract.result.form + car.rental.contract + form + +
    +
    +
    + +
    + +
    + +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + +
    +
    +
    +
    +
    + + + +
    +
    + + +
    + +
    +
    + + + car_contract_tree_view.tree + car.rental.contract + tree + + + + + + + + + + + + + + + + + Rental Contract + car.rental.contract + form + tree,form + + + + + +
    +
    diff --git a/fleet_rental/views/car_rental_view.xml~ b/fleet_rental/views/car_rental_view.xml~ new file mode 100644 index 000000000..0d55ca69b --- /dev/null +++ b/fleet_rental/views/car_rental_view.xml~ @@ -0,0 +1,216 @@ + + + + + Car Rental Sequence + car.rental.sequence + RENT/%(range_year)s/ + + + + 4 + + + + + + Fleet scheduler + + 1 + days + -1 + + + + + + + fleet.vehicle.form.inherit.view + fleet.vehicle + + + + + + + + + + + + + + car.contract.result.form + car.rental.contract + form + +
    +
    +
    + +
    + +
    + +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + +
    +
    +
    +
    +
    + + + +
    +
    + + +
    + +
    +
    + + + car_contract_tree_view.tree + car.rental.contract + tree + + + + + + + + + + + + + + + + + Rental Contract + car.rental.contract + form + tree,form + + + + + +
    +
    diff --git a/fleet_rental/views/car_tools_view.xml b/fleet_rental/views/car_tools_view.xml new file mode 100644 index 000000000..5e1caaaad --- /dev/null +++ b/fleet_rental/views/car_tools_view.xml @@ -0,0 +1,46 @@ + + + + + car_rental_contract_tools_form_view.form + car.tools + form + +
    + + + + + + + + + + + +
    +
    + + + car_rental_contract_tools_tree_view.tree + car.tools + tree + + + + + + + + + + Accessories/Tools + car.tools + form + tree,form + + + +
    +
    diff --git a/fleet_rental/views/checklist_view.xml b/fleet_rental/views/checklist_view.xml new file mode 100644 index 000000000..76bb8751c --- /dev/null +++ b/fleet_rental/views/checklist_view.xml @@ -0,0 +1,91 @@ + + + + + car_rental_contract_checklist_form_view.form + car.rental.contract + form + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + +
    +
    +
    +
    + +
    +
    + + + car_rental_contract_checklist_tree_view.tree + car.rental.contract + tree + + + + + + + + + + + Checklist + car.rental.contract + form + tree,form + [('state', 'in', ('running', 'checking'))] + + + + + + form + + + + + + + tree + + + + + +
    +
    diff --git a/front_office_management/README.rst b/front_office_management/README.rst new file mode 100644 index 000000000..a1f8e2bc6 --- /dev/null +++ b/front_office_management/README.rst @@ -0,0 +1,22 @@ +=========================== +Front Office Management v10 +=========================== + +Helps You To Manage Front Office Operations. + +Installation +============ + +Just install the module. + +Configuration +============= + +Nothing to configure. + +Credits +======= +Anusha P P @ cybrosys, anusha@cybrosys.in +Niyas Raphy @ cybrosys, niyas@cybrosys.in + + diff --git a/front_office_management/__init__.py b/front_office_management/__init__.py new file mode 100644 index 000000000..d5097b4df --- /dev/null +++ b/front_office_management/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Anusha P P() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +import models diff --git a/front_office_management/__manifest__.py b/front_office_management/__manifest__.py new file mode 100644 index 000000000..2acf71ff8 --- /dev/null +++ b/front_office_management/__manifest__.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Anusha P P() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +{ + 'name': "Front Office Management", + 'version': '10.0.1.0.0', + 'summary': """Manage Front Office Operations:Visitors, Devices Carrying Register, Actions""", + 'description': """Helps You To Manage Front Office Operations""", + 'author': "Cybrosys Techno Solutions", + 'maintainer': 'Cybrosys Techno Solutions', + 'company': "Cybrosys Techno Solutions", + 'website': "https://www.cybrosys.com", + 'category': 'Industries', + 'depends': ['base', 'hr'], + 'data': [ + 'views/fo_visit.xml', + 'views/fo_visitor.xml', + 'views/fo_property_counter.xml', + 'report/report.xml', + 'report/fo_property_label.xml', + 'report/fo_visitor_label.xml', + 'report/visitors_report.xml', + 'security/fo_security.xml', + 'security/ir.model.access.csv', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, +} diff --git a/front_office_management/models/__init__.py b/front_office_management/models/__init__.py new file mode 100644 index 000000000..2b4b9505d --- /dev/null +++ b/front_office_management/models/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Anusha P P() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +import fo_visitor +import fo_property_counter +import fo_visit + + + + + + diff --git a/front_office_management/models/fo_property_counter.py b/front_office_management/models/fo_property_counter.py new file mode 100644 index 000000000..d55d774eb --- /dev/null +++ b/front_office_management/models/fo_property_counter.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Maintainer: Cybrosys Technologies () +############################################################################## + + +from odoo import models, fields, api,_ +from odoo.exceptions import UserError + + +class VisitDetails(models.Model): + _name = 'fo.property.counter' + _inherit = ['mail.thread', 'ir.needaction_mixin'] + _rec_name = 'employee' + _description = 'Property Details' + + employee = fields.Many2one('hr.employee', string="Employee", required=True) + date = fields.Date(string="Date", required=True) + visitor_belongings = fields.One2many('fo.belongings', 'belongings_id_fov_employee', string="Personal Belongings", + copy=False) + state = fields.Selection([ + ('draft', 'Draft'), + ('prop_in', 'Taken In'), + ('prop_out', 'Taken out'), + ('cancel', 'Cancelled'), + ], track_visibility='onchange', default='draft', + help='If the employee taken the belongings to the company change state to ""Taken In""' + 'when he/she leave office change the state to ""Taken out""') + + @api.one + def action_cancel(self): + self.state = "cancel" + + @api.one + def action_prop_in(self): + count = 0 + number = 0 + for data in self.visitor_belongings: + if not data.property_count: + raise UserError(_('Please Add the Count.')) + if data.permission == '1': + count += 1 + number = data.number + if number == count: + raise UserError(_('No property can be taken in.')) + else: + self.state = 'prop_in' + + @api.multi + def action_prop_out(self): + self.state = "prop_out" + + + + + diff --git a/front_office_management/models/fo_visit.py b/front_office_management/models/fo_visit.py new file mode 100644 index 000000000..828dc6238 --- /dev/null +++ b/front_office_management/models/fo_visit.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Maintainer: Cybrosys Technologies () +############################################################################## + +import datetime +from odoo import models, fields, api, _ + + +class VisitDetails(models.Model): + _name = 'fo.visit' + _inherit = ['mail.thread'] + _description = 'Visit' + + name = fields.Char(string="sequence", default=lambda self: _('New')) + visitor = fields.Many2one("fo.visitor", string='Visitor') + phone = fields.Char(string="Phone", required=True) + email = fields.Char(string="Email", required=True) + reason = fields.Many2many('fo.purpose', string='Purpose Of Visit', required=True, + help='Enter the reason for visit') + visitor_belongings = fields.One2many('fo.belongings', 'belongings_id_fov_visitor', string="Personal Belongings", + help='Add the belongings details here.') + check_in_date = fields.Datetime(string="Check In Time", help='Visitor check in time automatically' + ' fills when he checked in to the office.') + check_out_date = fields.Datetime(string="Check Out Time", help='Visitor check out time automatically ' + 'fills when he checked out from the office.') + visiting_person = fields.Many2one('hr.employee', string="Meeting With") + department = fields.Many2one('hr.department', string="Department") + state = fields.Selection([ + ('draft', 'Draft'), + ('check_in', 'Checked In'), + ('check_out', 'Checked Out'), + ('cancel', 'Cancelled'), + ], track_visibility='onchange', default='draft') + + @api.model + def create(self, vals): + if vals: + vals['name'] = self.env['ir.sequence'].next_by_code('fo.visit') or _('New') + result = super(VisitDetails, self).create(vals) + return result + + @api.one + def action_cancel(self): + self.state = "cancel" + + @api.one + def action_check_in(self): + self.state = "check_in" + self.check_in_date = datetime.datetime.now() + + @api.multi + def action_check_out(self): + self.state = "check_out" + self.check_out_date = datetime.datetime.now() + + @api.onchange('visitor') + def visitor_details(self): + if self.visitor: + if self.visitor.phone: + self.phone = self.visitor.phone + if self.visitor.email: + self.email = self.visitor.email + + @api.onchange('visiting_person') + def get_emplyee_dpt(self): + if self.visiting_person: + self.department = self.visiting_person.department_id + + +class PersonalBelongings(models.Model): + _name = 'fo.belongings' + + property_name = fields.Char(string="Property", help='Employee belongings name') + property_count = fields.Char(string="Count", help='Count of property') + number = fields.Integer(compute='get_number', store=True, string="Sl") + belongings_id_fov_visitor = fields.Many2one('fo.visit', string="Belongings") + belongings_id_fov_employee = fields.Many2one('fo.property.counter', string="Belongings") + permission = fields.Selection([ + ('0', 'Allowed'), + ('1', 'Not Allowed'), + ('2', 'Allowed With Permission'), + ], 'Permission', required=True, index=True, default='0', track_visibility='onchange') + + @api.multi + @api.depends('belongings_id_fov_visitor', 'belongings_id_fov_employee') + def get_number(self): + for visit in self.mapped('belongings_id_fov_visitor'): + number = 1 + for line in visit.visitor_belongings: + line.number = number + number += 1 + for visit in self.mapped('belongings_id_fov_employee'): + number = 1 + for line in visit.visitor_belongings: + line.number = number + number += 1 + + +class VisitPurpose(models.Model): + _name = 'fo.purpose' + + name = fields.Char(string='Purpose', required=True, help='Meeting purpose in short term.eg:Meeting.') + description = fields.Text(string='Description Of Purpose', help='Description for the Purpose.') + + + + + + diff --git a/front_office_management/models/fo_visitor.py b/front_office_management/models/fo_visitor.py new file mode 100644 index 000000000..280e8738d --- /dev/null +++ b/front_office_management/models/fo_visitor.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Maintainer: Cybrosys Technologies () +############################################################################## + +from odoo import models, fields, api + + +class VisitorDetails(models.Model): + _name = 'fo.visitor' + + name = fields.Char(string="Visitor", required=True) + visitor_image = fields.Binary(string='Image', attachment=True) + street = fields.Char(string="Street") + street2 = fields.Char(string="Street2") + zip = fields.Char(change_default=True) + city = fields.Char() + state_id = fields.Many2one("res.country.state", string='State', ondelete='restrict') + country_id = fields.Many2one('res.country', string='Country', ondelete='restrict') + phone = fields.Char(string="Phone", required=True) + email = fields.Char(string="Email", required=True) + id_proof = fields.Many2one('id.proof', string="ID Proof") + id_proof_no = fields.Char(string="ID Number", help='Id proof number') + company_info = fields.Many2one('res.partner', string="Company", help='Visiting persons company details') + visit_count = fields.Integer(compute='_no_visit_count', string='# Visits') + + _sql_constraints = [ + ('field_uniq_email_and_id_proof', 'unique (email,id_proof)', "Please give the correct data !"), + ] + + @api.multi + def _no_visit_count(self): + data = self.env['fo.visit'].search([('visitor', '=', self.ids), ('state', '!=', 'cancel')]).ids + self.visit_count = len(data) + + +class VisitorProof(models.Model): + _name = 'id.proof' + _rec_name = 'id_proof' + + id_proof = fields.Char(string="Name") + code = fields.Char(string="Code") + + + + + + + + diff --git a/front_office_management/report/fo_property_label.xml b/front_office_management/report/fo_property_label.xml new file mode 100644 index 000000000..f866b9b4b --- /dev/null +++ b/front_office_management/report/fo_property_label.xml @@ -0,0 +1,57 @@ + + + + + + \ No newline at end of file diff --git a/front_office_management/report/fo_visitor_label.xml b/front_office_management/report/fo_visitor_label.xml new file mode 100644 index 000000000..f50b50784 --- /dev/null +++ b/front_office_management/report/fo_visitor_label.xml @@ -0,0 +1,67 @@ + + + + + + \ No newline at end of file diff --git a/front_office_management/report/report.xml b/front_office_management/report/report.xml new file mode 100644 index 000000000..ec1f6c250 --- /dev/null +++ b/front_office_management/report/report.xml @@ -0,0 +1,30 @@ + + + + + + + + + \ No newline at end of file diff --git a/front_office_management/report/visitors_report.xml b/front_office_management/report/visitors_report.xml new file mode 100644 index 000000000..55adf0e90 --- /dev/null +++ b/front_office_management/report/visitors_report.xml @@ -0,0 +1,63 @@ + + + + + + \ No newline at end of file diff --git a/front_office_management/security/fo_security.xml b/front_office_management/security/fo_security.xml new file mode 100644 index 000000000..2c68920bf --- /dev/null +++ b/front_office_management/security/fo_security.xml @@ -0,0 +1,15 @@ + + + + + Reception + 0 + + + + + Receptionist + + + + \ No newline at end of file diff --git a/front_office_management/security/ir.model.access.csv b/front_office_management/security/ir.model.access.csv new file mode 100644 index 000000000..9caaabf7f --- /dev/null +++ b/front_office_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_fo_visit_receptionist,fo.visit,model_fo_visit,front_office_management.group_receptionist,1,1,1,1 +access_fo_visitor_receptionist,fo_visitor,model_fo_visitor,front_office_management.group_receptionist,1,1,1,1 +access_fo_belongings_receptionist,fo.belongings,model_fo_belongings,front_office_management.group_receptionist,1,1,1,1 +access_id_proof_receptionist,id.proof,model_id_proof,front_office_management.group_receptionist,1,1,1,1 +access_fo_property_counter_receptionist,fo.property.counter,model_fo_property_counter,front_office_management.group_receptionist,1,1,1,1 +access_fo_purpose_receptionist,fo.purpose,model_fo_purpose,front_office_management.group_receptionist,1,1,1,1 + + + + + + + diff --git a/front_office_management/static/description/banner.jpg b/front_office_management/static/description/banner.jpg new file mode 100644 index 000000000..e9b673984 Binary files /dev/null and b/front_office_management/static/description/banner.jpg differ diff --git a/front_office_management/static/description/belongings.png b/front_office_management/static/description/belongings.png new file mode 100644 index 000000000..acbbfadf1 Binary files /dev/null and b/front_office_management/static/description/belongings.png differ diff --git a/front_office_management/static/description/cybro_logo.png b/front_office_management/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/front_office_management/static/description/cybro_logo.png differ diff --git a/front_office_management/static/description/icon.png b/front_office_management/static/description/icon.png new file mode 100644 index 000000000..8b7ae409c Binary files /dev/null and b/front_office_management/static/description/icon.png differ diff --git a/front_office_management/static/description/index.html b/front_office_management/static/description/index.html new file mode 100644 index 000000000..b2fb5a2fa --- /dev/null +++ b/front_office_management/static/description/index.html @@ -0,0 +1,185 @@ +
    +
    +

    Front Office Management

    +

    Manages Visitors and Employee Belongings

    +

    Cybrosys Technologies

    +
    +
    +

    Features:

    +
    + Manage visitors.
    + Issue Visitor Pass.
    + Keep Check in, Check out Details of Visitors.
    + Manage Visitor Belongings.
    + Print Report Of visitor.
    + Manage Employee Belongings.
    + Print Property Label.
    +
    +
    +
    + +
    +
    +
    +

    Overview

    +

    + This app will help you to manage the visitors coming to your office by issuing entry passes and handling their belongings. + The app can also manage the belongings of your employees. +

    +
    +
    +
    + +
    +
    +
    +

    +

    Visitors

    +

    +

    +
    + Create visitors. +
    + +
    +
    +
    +
    + +
    +
    +
    +

    +

    Visits

    +

    +
    +
    + Add visiting details. +
    + +
    +
    +
    +
    + +
    +
    +
    +

    +

    Visitor Pass

    +

    +
    +
    + Go to Visitor Management -> Visits -> Print -> Visitor Pass +
    + +
    +
    +
    +
    + +
    +
    +
    +

    +

    Visitor Report

    +

    +
    +
    + Go to Visitor Management -> Visits -> Print -> Visitors Report +
    + +
    +
    +
    +
    + +
    +
    +
    +

    +

    Today's Visits

    +

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

    +

    Employee Belongings

    +

    +
    +
    + Here you can specify the field 'Permission' with the values of Allowed,Not Allowed and Allowed with permission. +
    + +
    +
    +
    +
    + +
    +
    +
    +

    +

    Property Label

    +

    +
    +
    + Print the properties name that are not allowed to enter to the office. +
    + +
    +
    +
    +
    + +
    +
    +
    +

    +

    Receptionist

    +

    +
    +
    + We can set 'Receptionist' access from users form. +
    + +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    + diff --git a/front_office_management/static/description/label.png b/front_office_management/static/description/label.png new file mode 100644 index 000000000..9de50b5ef Binary files /dev/null and b/front_office_management/static/description/label.png differ diff --git a/front_office_management/static/description/pass.png b/front_office_management/static/description/pass.png new file mode 100644 index 000000000..eaeec483b Binary files /dev/null and b/front_office_management/static/description/pass.png differ diff --git a/front_office_management/static/description/report.png b/front_office_management/static/description/report.png new file mode 100644 index 000000000..b444c6cf6 Binary files /dev/null and b/front_office_management/static/description/report.png differ diff --git a/front_office_management/static/description/todays.png b/front_office_management/static/description/todays.png new file mode 100644 index 000000000..810412900 Binary files /dev/null and b/front_office_management/static/description/todays.png differ diff --git a/front_office_management/static/description/user.png b/front_office_management/static/description/user.png new file mode 100644 index 000000000..d807f163e Binary files /dev/null and b/front_office_management/static/description/user.png differ diff --git a/front_office_management/static/description/visit.png b/front_office_management/static/description/visit.png new file mode 100644 index 000000000..339627c96 Binary files /dev/null and b/front_office_management/static/description/visit.png differ diff --git a/front_office_management/static/description/visitor.png b/front_office_management/static/description/visitor.png new file mode 100644 index 000000000..ebb9d0219 Binary files /dev/null and b/front_office_management/static/description/visitor.png differ diff --git a/front_office_management/views/fo_property_counter.xml b/front_office_management/views/fo_property_counter.xml new file mode 100644 index 000000000..ec5804e3d --- /dev/null +++ b/front_office_management/views/fo_property_counter.xml @@ -0,0 +1,112 @@ + + + + + Property Counter + fo.property.counter + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    + + + Property Counter + fo.property.counter + + + + + + + + + + + Property Counter + fo.property.counter + search + + + + + + + + + + + + + + + + + + Property Counter + fo.property.counter + form + tree,form + +

    Record Personal Belongings. +

    +
    +
    + + + +
    +
    \ No newline at end of file diff --git a/front_office_management/views/fo_visit.xml b/front_office_management/views/fo_visit.xml new file mode 100644 index 000000000..7dd78a291 --- /dev/null +++ b/front_office_management/views/fo_visit.xml @@ -0,0 +1,208 @@ + + + + + Visits + fo.visit + +
    +
    +
    + +
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    + +
    +
    + + + Visits + fo.visit + + + + + + + + + + + + Visits + fo.visit + search + + + + + + + + + + + + + + + + + + Visits + fo.visit + form + tree,form + +

    Create Visits. +

    +

    + The check in time will be automatically filled when the visitor check in to the office. +

    +

    + The check out time automatically filled when the visitor check out from office. +

    +
    +
    + + + Today's Visits + fo.visit + form + tree,form + [('check_in_date', '>=',((context_today()-datetime.timedelta(days=0)).strftime('%Y-%m-%d 00:00:00'))), + ('check_in_date', '<=',((context_today()-datetime.timedelta(days=0)).strftime('%Y-%m-%d 23:59:59')))] + + + + + Visits + fo.visit + VID + 3 + + + + + Belongings + fo.belongings + +
    + + + + + + + + + + + +
    +
    + + + ID Proof + id.proof + +
    + + + + + + + + + + + +
    +
    + + + + + Visiting Purpose + fo.purpose + +
    + + + + + + + + + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/front_office_management/views/fo_visitor.xml b/front_office_management/views/fo_visitor.xml new file mode 100644 index 000000000..73ab42e14 --- /dev/null +++ b/front_office_management/views/fo_visitor.xml @@ -0,0 +1,138 @@ + + + + + Visitors + fo.visitor + +
    + +
    + +
    + +
    +

    +

    + + + +
    + +
    + +
    + + + + + + + + + + +
    + +
    +
    + + + fo.visitor.kanban + fo.visitor + + + + +
    +
    + +
    +
    + +
      +
    • Name :
    • +
    • Phone:
    • +
    +
    +
    +
    +
    +
    +
    +
    +
    + + Visitors + fo.visitor + search + + + + + + + + + + + + + + + + + + + Visitors + fo.visitor + tree + + + + + + + + + + + Visitors + ir.actions.act_window + fo.visitor + kanban,tree,form + form + + +

    + Click to Create New Visitor. +

    +
    +
    + + + + + + + +
    +
    \ No newline at end of file diff --git a/game_sudoku/README.rst b/game_sudoku/README.rst new file mode 100644 index 000000000..06082ea2b --- /dev/null +++ b/game_sudoku/README.rst @@ -0,0 +1,20 @@ +Odoo Games - Sudoku v10 +======================= + The classic Sudoku game involves a grid of 81 squares. The grid is divided into nine blocks, +each containing nine squares. + The rules of the game are simple: +Each of the nine blocks has to contain all the numbers 1-9 within its squares. Each number can +only appear once in a row, column or box. + You can select the squares by clicking. Enter the numbers. + +Space button is use to erase the entry. + +Features +======== + +* We can play SUDOKU Game. +* Play only By the approval of HR Manager. + +Credits +======= +Nikhil Krishnan @ cybrosys, nikhil@cybrosys.in \ No newline at end of file diff --git a/game_sudoku/__init__.py b/game_sudoku/__init__.py new file mode 100644 index 000000000..db6e2e68e --- /dev/null +++ b/game_sudoku/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +import models diff --git a/game_sudoku/__manifest__.py b/game_sudoku/__manifest__.py new file mode 100644 index 000000000..097112bae --- /dev/null +++ b/game_sudoku/__manifest__.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +{ + 'name': 'Odoo Games - Sudoku', + 'version': '10.0.1.0.0', + 'summary': """Sudoku Game.""", + 'description': """We can play SUDOKU.""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': 'http://www.cybrosys.com', + 'category': '', + 'depends': ['base', 'hr'], + 'license': 'LGPL-3', + 'data': [ + 'security/security_data.xml', + 'security/ir.model.access.csv', + 'views/game_approve_sequence.xml', + 'views/game_template.xml', + 'views/main_menu.xml', + 'views/sudoku_menu.xml', + ], + 'demo': [], + 'qweb': [ + "static/src/xml/sudoku.xml", + "static/src/xml/game.xml", + ], + 'images': ['static/description/banner.jpg'], + 'installable': True, + 'auto_install': False, +} diff --git a/game_sudoku/models/__init__.py b/game_sudoku/models/__init__.py new file mode 100644 index 000000000..b2afdd8b7 --- /dev/null +++ b/game_sudoku/models/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +import game + diff --git a/game_sudoku/models/game.py b/game_sudoku/models/game.py new file mode 100644 index 000000000..8b8f50f04 --- /dev/null +++ b/game_sudoku/models/game.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from datetime import datetime +from odoo import models, fields, api + + +class EntertainmentGames(models.Model): + _name = 'employee.game.approve' + _inherit = ['ir.needaction_mixin'] + _order = 'sequence desc' + + name = fields.Char(string='Name', related='employee_id.name') + approve_datetime = fields.Datetime(string='Datetime', readonly=1) + employee_id = fields.Many2one('hr.employee', string='Employee', required=True) + user_id = fields.Many2one('res.users', string='User') + department_id = fields.Many2one('hr.department', string='Department', related='employee_id.department_id') + game_user = fields.Boolean(string='Is Game User') + state = fields.Selection([ + ('draft', 'Requested'), + ('approve', 'Approved'), + ('cancel', 'Cancelled'), + ], string='Status', readonly=True, copy=False, default='draft') + sequence = fields.Integer('Sequence') + + @api.model + def _needaction_domain_get(self): + return [('state', '=', 'draft')] + + def create_employee_game_approve(self, empl_id, user): + rec = self.search([('employee_id', '=', empl_id)]) + if rec: + seq = self.env['ir.sequence'].next_by_code('employee.game') + rec.write({'sequence': seq, 'state': 'draft', 'approve_datetime': datetime.now()}) + else: + vals = { + 'employee_id': empl_id, + 'user_id': user, + 'approve_datetime': datetime.now(), + 'sequence': self.env['ir.sequence'].next_by_code('employee.game') + } + self.create(vals) + + def approve(self): + group_game_approve = self.env.ref('game_sudoku.odoo_gamer_group', False) + group_game_approve.write({'users': [(4, self.user_id.id)]}) + + group_game_req = self.env.ref('game_sudoku.odoo_gamer_approve_req', False) + group_game_req.write({'users': [(3, self.user_id.id)]}) + + return self.write({'game_user': True, 'state': 'approve'}) + + def cancel(self): + group_game_approve = self.env.ref('game_sudoku.odoo_gamer_group', False) + group_game_approve.write({'users': [(3, self.user_id.id)]}) + + group_game_req = self.env.ref('game_sudoku.odoo_gamer_approve_req', False) + group_game_req.write({'users': [(4, self.user_id.id)]}) + + return self.write({'game_user': False, 'state': 'cancel'}) diff --git a/game_sudoku/security/ir.model.access.csv b/game_sudoku/security/ir.model.access.csv new file mode 100644 index 000000000..e4a1c9915 --- /dev/null +++ b/game_sudoku/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink + +access_game_gamer,employee.game.approve.user,game_sudoku.model_employee_game_approve,base.group_user,1,1,1,0 +access_game_gamer_manager,employee.game.approve.manager,game_sudoku.model_employee_game_approve,hr.group_hr_manager,1,1,1,1 diff --git a/game_sudoku/security/security_data.xml b/game_sudoku/security/security_data.xml new file mode 100644 index 000000000..5a6b4f142 --- /dev/null +++ b/game_sudoku/security/security_data.xml @@ -0,0 +1,26 @@ + + + + + Game + 10 + + + + + Odoo Gamer + + + + + Odoo Game Request + + + + + + + + + + diff --git a/game_sudoku/static/description/Game Request.png b/game_sudoku/static/description/Game Request.png new file mode 100644 index 000000000..f98af56af Binary files /dev/null and b/game_sudoku/static/description/Game Request.png differ diff --git a/game_sudoku/static/description/Just wait for approval.png b/game_sudoku/static/description/Just wait for approval.png new file mode 100644 index 000000000..410f2f4ec Binary files /dev/null and b/game_sudoku/static/description/Just wait for approval.png differ diff --git a/game_sudoku/static/description/Level.png b/game_sudoku/static/description/Level.png new file mode 100644 index 000000000..512e1ee5d Binary files /dev/null and b/game_sudoku/static/description/Level.png differ diff --git a/game_sudoku/static/description/May i play.png b/game_sudoku/static/description/May i play.png new file mode 100644 index 000000000..df84a5e2a Binary files /dev/null and b/game_sudoku/static/description/May i play.png differ diff --git a/game_sudoku/static/description/Sudoku.png b/game_sudoku/static/description/Sudoku.png new file mode 100644 index 000000000..f88651465 Binary files /dev/null and b/game_sudoku/static/description/Sudoku.png differ diff --git a/game_sudoku/static/description/banner.jpg b/game_sudoku/static/description/banner.jpg new file mode 100644 index 000000000..0fd479eb1 Binary files /dev/null and b/game_sudoku/static/description/banner.jpg differ diff --git a/game_sudoku/static/description/color code.png b/game_sudoku/static/description/color code.png new file mode 100644 index 000000000..d0e8465d0 Binary files /dev/null and b/game_sudoku/static/description/color code.png differ diff --git a/game_sudoku/static/description/cybro_logo.png b/game_sudoku/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/game_sudoku/static/description/cybro_logo.png differ diff --git a/game_sudoku/static/description/icon.png b/game_sudoku/static/description/icon.png new file mode 100644 index 000000000..e34faf824 Binary files /dev/null and b/game_sudoku/static/description/icon.png differ diff --git a/game_sudoku/static/description/index.html b/game_sudoku/static/description/index.html new file mode 100644 index 000000000..ba975e9d9 --- /dev/null +++ b/game_sudoku/static/description/index.html @@ -0,0 +1,192 @@ +
    +
    +

    Odoo Games - Sudoku

    +

    Brain-Teaser game.!!

    +

    Cybrosys Technologies

    +
    +

    Features:

    +
      +
    •    We can play SUDOKU.
    • +
    •    Play only By the approval of HR Manager.
    • + +
    +
    +
    +
    + +
    +
    +

    How to start the game.?

    +
    +
    +
    + +
    +
    +
    +

    + To start playing the game, user should click the button () + for send a request. +

    +
    +
    +

    + Wait for the approval of HR manager. +

    +
    + +
    +

    + A record is generated. And from the record the HR manager can give approval to play the game. +

    +
    +
    +
    +
    + +
    +
    +

    Admin, please check with the user form to enable the option " Odoo Game Request".

    +
    +
    +
    + +
    +
    +
    +
    + Admin can directly give the permission to play the game. Just enable "Odoo Gamer" +

    Ps:- if we directly give permission to play game, don't forget to remove Odoo Game Request"

    +
    +
    +
    + +
    +
    +

    Approve the game request by HR Manager

    +
    +
    +
    + +
    +
    +
    +

    + HR managers can see this request from the menu "Game Request" under Game. +

    +

    + We can see 2 buttons here. +

    + 1.This icon( ) for approve the request +

    +

    + 2. This icon () for avoid/cancel the request +

    +

    +

    + We can easily identify the states of the request by color. + +

      +
    • Red is in draft state.
    • +
    +
      +
    • Green is in approve state.
    • +
    +
      +
    • Grey is in cancel state.
    • +
    +

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

    SUDOKU

    +
    + Click on the "New Game" button to start the game. +
    +
    +
    +
    + +
    +
    +
    +
    + Select your level of game. +
    +
    +
    +
    + +
    +
    +
    +
    + Let's play..!! +

    + The classic Sudoku game involves a grid of 81 squares. + The grid is divided into nine blocks, each containing nine squares. +

    The rules of the game are simple:

    + each of the nine blocks should contain all the numbers 1-9 within its squares. + Each number can appear only once in a row, column or box. +

    +

    You can select the squares by clicking. Read the numbers from key boards.

    +

    Space button can be used to erase the entry.

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

    WON the game

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

    Need Any Help?

    + +
    diff --git a/game_sudoku/static/description/sudoku 1.png b/game_sudoku/static/description/sudoku 1.png new file mode 100644 index 000000000..79a109806 Binary files /dev/null and b/game_sudoku/static/description/sudoku 1.png differ diff --git a/game_sudoku/static/description/user group.png b/game_sudoku/static/description/user group.png new file mode 100644 index 000000000..7a642d908 Binary files /dev/null and b/game_sudoku/static/description/user group.png differ diff --git a/game_sudoku/static/description/won.png b/game_sudoku/static/description/won.png new file mode 100644 index 000000000..a6beedf63 Binary files /dev/null and b/game_sudoku/static/description/won.png differ diff --git a/game_sudoku/static/src/css/sudoku.css b/game_sudoku/static/src/css/sudoku.css new file mode 100644 index 000000000..8e060911f --- /dev/null +++ b/game_sudoku/static/src/css/sudoku.css @@ -0,0 +1,283 @@ + +.o_entertainment_games_req_footer{ + display:none; +} +.sudokupage +{ + height: 650px; + width:100%; + background-color: #CDD5F4; +} +.sudokupage1 +{ + height: auto; + width:25%; + float: left; + margin-top: 250px; +} +.sudokupage2 +{ + height: 650px; + width:55%; + float: left; + background-color: #CDD5F4; +} +.sudokupage2 h3 +{ + color: red; + font-size: 28px; +} +.sudokupage2 h4 +{ + color: red; + font-size: 20px; +} +.sudokupage3 +{ + height: auto; + width:20%; + float:right; + background-color: #CDD5F4; +} + +.sudokunewbutton { + border-radius: 4px; + background-color: #4CAF50; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} + +.sudokulevelbutton { + border-radius: 3px; + background-color: #4CAF50; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} +.sudokulevelbuttonreset { + border-radius: 3px; + display: none; + background-color: #4CAF50; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} +.sudokulevelbuttoncheck { + border-radius: 3px; + display: none; + background-color: #4CAF50; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} +.sudokulevelbuttoncheckback { + border-radius: 3px; + display: none; + background-color: #4CAF50; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} +.sudokulevelbuttonsolve { + border-radius: 3px; + display: none; + background-color: #4CAF50; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} +.sudokulevelbutton1 { + border-radius: 3px; + background-color: #00b3b3; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} +.sudokulevelbutton2 { + border-radius: 3px; + background-color: #00b3b3; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} +.sudokulevelbutton3 { + border-radius: 3px; + background-color: #00b3b3; + border: none; + color: #FFFFFF; + text-align: center; + font-size: 22px; + padding: 15px; + width: 170px; + height:55px; + transition: all 0.5s; + cursor: pointer; + margin: 5px; +} + +.sudokulevelselection { + display: none; + position: fixed; + z-index: 1; + padding-top: 100px; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + + +.sudokulevelselection-content { + position: relative; + background-color: #fefefe; + margin: auto; + padding: 0; + border: 1px solid #888; + width: 80%; + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19); + -webkit-animation-name: animatetop; + -webkit-animation-duration: 0.4s; + animation-name: animatetop; + animation-duration: 0.4s +} + +@-webkit-keyframes animatetop { + from {top:-300px; opacity:0} + to {top:0; opacity:1} +} + +@keyframes animatetop { + from {top:-300px; opacity:0} + to {top:0; opacity:1} +} + + +.sudokulevelselectionclose { + color: white; + float: right; + font-size: 28px; + font-weight: bold; +} + +.sudokulevelselection:hover, +.sudokulevelselection:focus { + color: #000; + text-decoration: none; + cursor: pointer; +} + +.sudokulevelselection-header { + padding: 2px 16px; + background-color: #5cb85c; + color: white; +} + +.sudokulevelselection-body {padding: 2px 16px;} + +.sudokulevelselection-footer { + padding: 2px 16px; + background-color: #5cb85c; + color: white; +} + +table.sudoright td {width: 50px; height:80px; +font-weight: bold; +text-align: center +} +table.sudoright { +margin-top: 120px; +} +table.sudoku td {width: 55px; height:55px; +border-width: 1px; +border-style: solid; +border-color: black; +font-weight: bold; +text-align: center +} +table.sudoku { +border-width: 3px; +border-style: solid; +border-color:black; +} +table.sudoku td[id^=cell_0] {border-bottom-width: 3px;border-bottom-style: double;} +table.sudoku td[id^=cell_1] {border-bottom-width: 3px;border-bottom-style: double;} +table.sudoku td[id^=cell_2] {border-bottom-width: 3px} +table.sudoku td[id^=cell_3] {border-bottom-width: 3px;border-bottom-style: double;} +table.sudoku td[id^=cell_4] {border-bottom-width: 3px;border-bottom-style: double;} +table.sudoku td[id^=cell_5] {border-bottom-width: 3px} +table.sudoku td[id^=cell_6] {border-bottom-width: 3px;border-bottom-style: double;} +table.sudoku td[id^=cell_7] {border-bottom-width: 3px;border-bottom-style: double;} +table.sudoku td[id$=_0] {border-right-width: 3px;border-right-style: double;} +table.sudoku td[id$=_1] {border-right-width: 3px;border-right-style: double;} +table.sudoku td[id$=_2] {border-right-width: 3px} +table.sudoku td[id$=_3] {border-right-width: 3px;border-right-style: double;} +table.sudoku td[id$=_4] {border-right-width: 3px;border-right-style: double;} +table.sudoku td[id$=_5] {border-right-width: 3px} +table.sudoku td[id$=_6] {border-right-width: 3px;border-right-style: double;} +table.sudoku td[id$=_7] {border-right-width: 3px;border-right-style: double;} +td.selected {background-color: rgb(100%, 70%, 0%)} +td.tofill {color: blue;background-color: #f2ffde } +td.filled {color: blue;background-color: #c0ff96} +td.green{color:green;background-color: #fff} +td.red{color:red;background-color:#FC9E9E;border-color: red;border-width: 1.5px} +td.notfill {color: green;font-style:bold;background-color: #cac5c3;} \ No newline at end of file diff --git a/game_sudoku/static/src/img/application-switcher-bg.jpg b/game_sudoku/static/src/img/application-switcher-bg.jpg new file mode 100644 index 000000000..b42f07885 Binary files /dev/null and b/game_sudoku/static/src/img/application-switcher-bg.jpg differ diff --git a/game_sudoku/static/src/js/game.js b/game_sudoku/static/src/js/game.js new file mode 100644 index 000000000..8af1ad333 --- /dev/null +++ b/game_sudoku/static/src/js/game.js @@ -0,0 +1,49 @@ +odoo.define('game_sudoku.models_entertainment_game', function (require) { +"use strict"; + +var core = require('web.core'); +var Model = require('web.Model'); +var Widget = require('web.Widget'); + +var QWeb = core.qweb; +var _t = core._t; + +var MyGame = Widget.extend({ + events: { + "click .o_entertainment_games_log_in_icon": function() { + this.$('.o_entertainment_games_log_in_icon').attr("disabled", "disabled"); + this.$('.o_entertainment_games_req_footer').css('display', 'block'); + this.game_request(); + }, + }, + game_request: function(){ + new Model("employee.game.approve") + .call("create_employee_game_approve", [1, this.employee.id, this.user]) + }, + + start: function () { + var self = this; + + var hr_employee = new Model('hr.employee'); + hr_employee.query(['attendance_state', 'name']) + .filter([['user_id', '=', self.session.uid]]) + .all() + .then(function (res) { + if (_.isEmpty(res) ) { + self.$('.o_hr_attendance_employee').append(_t("Error : Could not find employee linked to user")); + return; + } + self.employee = res[0]; + self.user = self.session.uid + self.$el.html(QWeb.render("EntertainmentGamesMainMenu", {widget: self})); + }); + + return this._super.apply(this, arguments); + }, +}); + +core.action_registry.add('entertainment_games_my_game', MyGame); + +return MyGame; + +}); \ No newline at end of file diff --git a/game_sudoku/static/src/js/sudoku.js b/game_sudoku/static/src/js/sudoku.js new file mode 100644 index 000000000..582a9f399 --- /dev/null +++ b/game_sudoku/static/src/js/sudoku.js @@ -0,0 +1,1004 @@ +var maxAttempts=100; +var globb; +var check = 0 +var selected_cell_id; +var current_cell = null; +var sudokuboard = new Array(9); +var orginalboard = new Array(9); +var board = new Array(9); +Puzzle=new Array(9); +maxAttempts=100; +var thisCol; +var thisRow; +var subMat; +var time=0; +var checkit=0; + +odoo.define('game_sudoku.models_sudoku_game', function (require) { +"use strict"; + +var core = require('web.core'); +var Model = require('web.Model'); +var Widget = require('web.Widget'); + +var QWeb = core.qweb; +var _t = core._t; + +var Sudoku = Widget.extend({ + events: { + "click .sudokunewbutton": function() { + $('.sudokulevelselection').css('display', 'block'); + }, + "click .sudokulevelbutton1": function() { + this.newgame(); + this.level(45); + checkit = 1; + $('.sudokulevelselection').css('display', 'none'); + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttoncheckback').css('display', 'none'); + $('.sudokulevelbuttonreset').css('display', 'block'); + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttonsolve').css('display', 'block'); + }, + "click .sudokulevelbutton2": function() { + this.newgame(); + this.level(35); + checkit = 1; + $('.sudokulevelselection').css('display', 'none'); + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttoncheckback').css('display', 'none'); + $('.sudokulevelbuttonreset').css('display', 'block'); + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttonsolve').css('display', 'block'); + }, + "click .sudokulevelbutton3": function() { + this.newgame(); + this.level(25); + checkit = 1; + $('.sudokulevelselection').css('display', 'none'); + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttoncheckback').css('display', 'none'); + $('.sudokulevelbuttonreset').css('display', 'block'); + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttonsolve').css('display', 'block'); + }, + "click .sudokulevelselectionclose": function() { + $('.sudokulevelselection').css('display', 'none'); + }, + "click .sudokulevelbuttonreset": function() { + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttoncheckback').css('display', 'none'); + this.rese(); + }, + "click .sudokulevelbuttoncheck": function() { + this.check(); + $('.sudokulevelbuttoncheck').css('display', 'none'); + $('.sudokulevelbuttoncheckback').css('display', 'block'); + }, + "click .sudokulevelbuttoncheckback": function() { + this.checkback(); + $('.sudokulevelbuttoncheck').css('display', 'block'); + $('.sudokulevelbuttoncheckback').css('display', 'none'); + }, + "click .sudokulevelbuttonsolve": function() { + this.show_lost(); + this.solve(); + }, + "click #cell_0_0": function() { + var cell = document.getElementById('cell_0_0'); + var cell_id = "#cell_0_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_1": function() { + + var cell = document.getElementById('cell_0_1'); + var cell_id = "#cell_0_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_2": function() { + + var cell = document.getElementById('cell_0_2'); + var cell_id = "#cell_0_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_3": function() { + + var cell = document.getElementById('cell_0_3'); + var cell_id = "#cell_0_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_4": function() { + + var cell = document.getElementById('cell_0_4'); + var cell_id = "#cell_0_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_5": function() { + + var cell = document.getElementById('cell_0_5'); + var cell_id = "#cell_0_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_6": function() { + + var cell = document.getElementById('cell_0_6'); + var cell_id = "#cell_0_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_7": function() { + + var cell = document.getElementById('cell_0_7'); + var cell_id = "#cell_0_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_0_8": function() { + + var cell = document.getElementById('cell_0_8'); + var cell_id = "#cell_0_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_0": function() { + + var cell = document.getElementById('cell_1_0'); + var cell_id = "#cell_1_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_1": function() { + + var cell = document.getElementById('cell_1_1'); + var cell_id = "#cell_1_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_2": function() { + + var cell = document.getElementById('cell_1_2'); + var cell_id = "#cell_1_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_3": function() { + + var cell = document.getElementById('cell_1_3'); + var cell_id = "#cell_1_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_4": function() { + + var cell = document.getElementById('cell_1_4'); + var cell_id = "#cell_1_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_5": function() { + + var cell = document.getElementById('cell_1_5'); + var cell_id = "#cell_1_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_6": function() { + + var cell = document.getElementById('cell_1_6'); + var cell_id = "#cell_1_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_7": function() { + + var cell = document.getElementById('cell_1_7'); + var cell_id = "#cell_1_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_1_8": function() { + + var cell = document.getElementById('cell_1_8'); + var cell_id = "#cell_1_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_0": function() { + + var cell = document.getElementById('cell_2_0'); + var cell_id = "#cell_2_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_1": function() { + + var cell = document.getElementById('cell_2_1'); + var cell_id = "#cell_2_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_2": function() { + + var cell = document.getElementById('cell_2_2'); + var cell_id = "#cell_2_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_3": function() { + + var cell = document.getElementById('cell_2_3'); + var cell_id = "#cell_2_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_4": function() { + + var cell = document.getElementById('cell_2_4'); + var cell_id = "#cell_2_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_5": function() { + + var cell = document.getElementById('cell_2_5'); + var cell_id = "#cell_2_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_6": function() { + + var cell = document.getElementById('cell_2_6'); + var cell_id = "#cell_2_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_7": function() { + + var cell = document.getElementById('cell_2_7'); + var cell_id = "#cell_2_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_2_8": function() { + + var cell = document.getElementById('cell_2_8'); + var cell_id = "#cell_2_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_0": function() { + + var cell = document.getElementById('cell_3_0'); + var cell_id = "#cell_3_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_1": function() { + + var cell = document.getElementById('cell_3_1'); + var cell_id = "#cell_3_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_2": function() { + + var cell = document.getElementById('cell_3_2'); + var cell_id = "#cell_3_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_3": function() { + + var cell = document.getElementById('cell_3_3'); + var cell_id = "#cell_3_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_4": function() { + + var cell = document.getElementById('cell_3_4'); + var cell_id = "#cell_3_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_5": function() { + + var cell = document.getElementById('cell_3_5'); + var cell_id = "#cell_3_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_6": function() { + + var cell = document.getElementById('cell_3_6'); + var cell_id = "#cell_3_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_7": function() { + + var cell = document.getElementById('cell_3_7'); + var cell_id = "#cell_3_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_3_8": function() { + + var cell = document.getElementById('cell_3_8'); + var cell_id = "#cell_3_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_0": function() { + + var cell = document.getElementById('cell_4_0'); + var cell_id = "#cell_4_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_1": function() { + + var cell = document.getElementById('cell_4_1'); + var cell_id = "#cell_4_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_2": function() { + + var cell = document.getElementById('cell_4_2'); + var cell_id = "#cell_4_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_3": function() { + + var cell = document.getElementById('cell_4_3'); + var cell_id = "#cell_4_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_4": function() { + + var cell = document.getElementById('cell_4_4'); + var cell_id = "#cell_4_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_5": function() { + + var cell = document.getElementById('cell_4_5'); + var cell_id = "#cell_4_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_6": function() { + + var cell = document.getElementById('cell_4_6'); + var cell_id = "#cell_4_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_7": function() { + + var cell = document.getElementById('cell_4_7'); + var cell_id = "#cell_4_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_4_8": function() { + + var cell = document.getElementById('cell_4_8'); + var cell_id = "#cell_4_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_0": function() { + + var cell = document.getElementById('cell_5_0'); + var cell_id = "#cell_5_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_1": function() { + + var cell = document.getElementById('cell_5_1'); + var cell_id = "#cell_5_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_2": function() { + + var cell = document.getElementById('cell_5_2'); + var cell_id = "#cell_5_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_3": function() { + + var cell = document.getElementById('cell_5_3'); + var cell_id = "#cell_5_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_4": function() { + + var cell = document.getElementById('cell_5_4'); + var cell_id = "#cell_5_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_5": function() { + + var cell = document.getElementById('cell_5_5'); + var cell_id = "#cell_5_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_6": function() { + + var cell = document.getElementById('cell_5_6'); + var cell_id = "#cell_5_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_7": function() { + + var cell = document.getElementById('cell_5_7'); + var cell_id = "#cell_5_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_5_8": function() { + + var cell = document.getElementById('cell_5_8'); + var cell_id = "#cell_5_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_0": function() { + + var cell = document.getElementById('cell_6_0'); + var cell_id = "#cell_6_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_1": function() { + + var cell = document.getElementById('cell_6_1'); + var cell_id = "#cell_6_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_2": function() { + + var cell = document.getElementById('cell_6_2'); + var cell_id = "#cell_6_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_3": function() { + + var cell = document.getElementById('cell_6_3'); + var cell_id = "#cell_6_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_4": function() { + + var cell = document.getElementById('cell_6_4'); + var cell_id = "#cell_6_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_5": function() { + + var cell = document.getElementById('cell_6_5'); + var cell_id = "#cell_6_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_6": function() { + + var cell = document.getElementById('cell_6_6'); + var cell_id = "#cell_6_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_7": function() { + + var cell = document.getElementById('cell_6_7'); + var cell_id = "#cell_6_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_6_8": function() { + + var cell = document.getElementById('cell_6_8'); + var cell_id = "#cell_6_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_0": function() { + + var cell = document.getElementById('cell_7_0'); + var cell_id = "#cell_7_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_1": function() { + + var cell = document.getElementById('cell_7_1'); + var cell_id = "#cell_7_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_2": function() { + + var cell = document.getElementById('cell_7_2'); + var cell_id = "#cell_7_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_3": function() { + + var cell = document.getElementById('cell_7_3'); + var cell_id = "#cell_7_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_4": function() { + + var cell = document.getElementById('cell_7_4'); + var cell_id = "#cell_7_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_5": function() { + + var cell = document.getElementById('cell_7_5'); + var cell_id = "#cell_7_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_6": function() { + + var cell = document.getElementById('cell_7_6'); + var cell_id = "#cell_7_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_7": function() { + + var cell = document.getElementById('cell_7_7'); + var cell_id = "#cell_7_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_7_8": function() { + + var cell = document.getElementById('cell_7_8'); + var cell_id = "#cell_7_8"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_0": function() { + + var cell = document.getElementById('cell_8_0'); + var cell_id = "#cell_8_0"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_1": function() { + + var cell = document.getElementById('cell_8_1'); + var cell_id = "#cell_8_1"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_2": function() { + + var cell = document.getElementById('cell_8_2'); + var cell_id = "#cell_8_2"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_3": function() { + + var cell = document.getElementById('cell_8_3'); + var cell_id = "#cell_8_3"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_4": function() { + + var cell = document.getElementById('cell_8_4'); + var cell_id = "#cell_8_4"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_5": function() { + + var cell = document.getElementById('cell_8_5'); + var cell_id = "#cell_8_5"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_6": function() { + + var cell = document.getElementById('cell_8_6'); + var cell_id = "#cell_8_6"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_7": function() { + + var cell = document.getElementById('cell_8_7'); + var cell_id = "#cell_8_7"; + this.selectCell(cell, cell_id) + }, + "click #cell_8_8": function() { + + var cell = document.getElementById('cell_8_8'); + var cell_id = "#cell_8_8"; + this.selectCell(cell, cell_id) + }, + + }, + + valid: function (k,l,r1){ + + var k1= (Math.floor(k/3))*3; + var k2=k1+3; + var l1= (Math.floor(l/3))*3; + var l2=l1+3; + for (var i=k1;i= 1 && key_no <= 9) + { + console.log("key + selected_cell_id",key, selected_cell_id); + var chk = globb.valid(rr,cc,key); + if (chk==1) + { + $(selected_cell_id).text(key); + sudokuboard[rr][cc]=key; + $(selected_cell_id).addClass('filled').removeClass('selected'); + if(globb.isfull(rr, cc)) + { + globb.show_wow() + setTimeout(function() { + globb.check(); + }, 10000); + } + } + else + alert("Cannot enter "+key+".Because this number twice in the same row or same column or same box."); + } + } + }, + + initialize:function() + { + document.onkeypress = this.keyPress; + }, + +selectCell: function(cell, cell_id) + { + if (checkit) + { + for (var rows = 0; rows <=8; rows++) + { + for (var cols=0; cols <= 8; cols++) + { + var cells=document.getElementById('cell_' + rows + '_' + cols) + if (cells.className == 'selected') + { + var v= sudokuboard[rows][cols]; + if (v==0){ + cells.className = 'tofill'; + } + else{ + if (sudokuboard[rows][cols] == board[rows][cols]) + { + cells.className = 'notfill'; + } + else + cells.className = 'filled'; + } + } + } + } + + var row = cell_id.charAt(6); + var col = cell_id.charAt(8); + + if (parseInt(cell.innerHTML)) + { + if (board[row][col] != 0){ + cell.className='notfill'; + } + else{ + cell.className='selected'; + } + + } + else{ + cell.className='selected'; + } + current_cell = this; + globb = this; + selected_cell_id = cell_id + } + }, + + level: function(lvl) + { + for (var i = 1; i <=lvl;) + { + var k=this.rand(); + var l=this.rand(); + if (sudokuboard[k][l] == 0) + { + var x = Puzzle[k][l]; + var random="cell_"+k+"_"+l; + $("#cell_"+k+"_"+l).text(x); + sudokuboard[k][l]=x; + board[k][l]=x; + i++; + } + } + for (var row = 0; row <=8; row++) + { + for (var col=0; col <= 8; col++) + { + var cell = document.getElementById('cell_' + row + '_' + col); + var self = this; + var cell_id = "#cell_" + row + "_" + col + var cell_idd = "cell_" + row + "_" + col + if (!parseInt(cell.innerHTML)) + { + cell.className='tofill'; + } + else + { + cell.className='notfill'; + } + } + } + this.rese(); + }, + + newgame: function() + { + $(".sudo").text("SUDOKU"); + this.problem(); + for (var row = 0; row <=8; row++) + { + sudokuboard[row]=new Array(9); + orginalboard[row]=new Array(9); + board[row]=new Array(9); + for (var col=0; col <= 8; col++) + { + $("#cell_"+row+"_"+col).text(""); + + sudokuboard[row][col]=0; + orginalboard[row][col]=0; + board[row][col]=0; + } + } + }, + + validd:function (randVal,thisRow,thisCol,subMat) + { + for(var i=0;i<9;i++) + { + if(thisRow[i]==randVal) + { + return 1; + } + else if (thisCol[i]==randVal) + { + return 1; + } + else if(subMat[i]==randVal) + { + return 1; + } + else + { + continue; + } + } + return 0; + }, + + rand: function() + { + var r1=Math.floor(Math.random() * 10); + r1=(r1+r1+1)%9 + return r1; + }, + + checkback: function() + { + for (var row = 0; row <=8; row++) + { + for (var col=0; col <= 8; col++) + { + var cell=document.getElementById('cell_' + row + '_' + col) + var cell_id = '#cell_' + row + '_' + col + var v= sudokuboard[row][col]; + if (v==0){ + $("#cell_"+row+"_"+col).text(""); + cell.className = 'tofill'; + } + else{ + $("#cell_"+row+"_"+col).text(v); + console.log("receckkkkk",sudokuboard[row][col] ) + if (sudokuboard[row][col] == board[row][col]) + { + cell.className = 'notfill'; + } + else + cell.className = 'filled'; + + } + + } + } + }, + + show_wow: function() { + var class_to_add = 'o_wow_thumbs'; + var $body = $('body'); + $body.addClass(class_to_add); + setTimeout(function() { + $body.removeClass(class_to_add); + }, 10000); + }, + + show_lost: function() { + var class_to_add = 'o_lost_thumbs'; + var $body = $('body'); + $body.addClass(class_to_add); + setTimeout(function() { + $body.removeClass(class_to_add); + }, 10000); + }, + + check: function() + { + for (var row = 0; row <=8; row++) + { + for (var col=0; col <= 8; col++) + { + var cell = document.getElementById('cell_' + row + '_' + col); + if (Puzzle[row][col]==sudokuboard[row][col]) + cell.className='green'; + else + cell.className='red'; + } + } + }, + + solve: function() + { + + for (var row = 0; row <=8; row++) + { + for (var col=0; col <= 8; col++) + { + var val=Puzzle[row][col]; + $("#cell_"+row+"_"+col).text(val); + sudokuboard[row][col]=val; + } + } + + }, + + rese: function() + { + this.initialize(); + for (var row = 0; row <=8; row++) + { + for (var col=0; col <= 8; col++) + { + sudokuboard[row][col]=board[row][col]; + var cell=document.getElementById('cell_' + row + '_' + col) + var cell_id = '#cell_' + row + '_' + col + var cell_idd = 'cell_' + row + '_' + col + var v= board[row][col]; + if (v==0) + $("#cell_"+row+"_"+col).text(""); + else{ + $("#cell_"+row+"_"+col).text(v); + } + if (!parseInt(cell.innerHTML)) + { + cell.className = 'tofill'; + } + else + cell.className = 'notfill'; + } + + } + }, + + isfull:function (rr, cc) + { + for (var row = 0; row <=8; row++) + { + for (var col=0; col <= 8; col++) + { + if (!(row == rr && col == cc)){ + var cell = document.getElementById('cell_' + row + '_' + col); + console.log("isfullllllllllllllllllll",cell, cell.innerHTML); + if (!parseInt(cell.innerHTML)) + { + return false; + } + } + } + } + return true; + }, + + problem: function(){ + + var count=101; + while(count>maxAttempts) + { + for(var m=0;m<9;m++) + { + Puzzle[m]=new Array(9); + for(var n=0;n<9;n++) + { + Puzzle[m][n]=0; + } + } + for(var row=0;row<9;row++) + { + for(var col=0;col<9;col++) + { + thisRow=Puzzle[row]; + thisCol=new Array(); + for(var row1=0;row1<9;row1++) + { + thisCol.push(Puzzle[row1][col]); + } + var subRow=parseInt(row/3); + var subCol=parseInt(col/3); + var subMat=new Array(); + for(var subR=0;subR<3;subR++) + { + for(var subC=0;subC<3;subC++) + { + subMat.push(Puzzle[(subRow*3)+subR][(subCol*3)+subC]); + } + } + var randVal=0; + count=0; + while(this.validd(randVal,thisRow,thisCol,subMat)) + { + randVal=this.rand(); + if (randVal==0) + randVal=9; + count+=1; + if(count>maxAttempts) + { + break; + } + } + Puzzle[row][col]=randVal; + if(count>maxAttempts) + { + break; + } + + + } + if(count>maxAttempts) + { + break; + } + } + + } + }, + +start: function () { + var self = this; + var hr_employee = new Model('hr.employee'); + hr_employee.query(['attendance_state', 'name']) + .filter([['user_id', '=', self.session.uid]]) + .all() + .then(function (res) { + if (_.isEmpty(res) ) { + self.$('.o_hr_attendance_employee').append(_t("Error : Could not find employee linked to user")); + return; + } + self.employee = res[0]; + self.user = self.session.uid + self.$el.html(QWeb.render("EntertainmentGamesSudoku", {widget: self})); + }); + + return this._super.apply(this, arguments); + }, +}); +core.action_registry.add('entertainment_games_sudoku', Sudoku); + +return Sudoku; + +}); diff --git a/game_sudoku/static/src/less/games.less b/game_sudoku/static/src/less/games.less new file mode 100644 index 000000000..30c0a71e5 --- /dev/null +++ b/game_sudoku/static/src/less/games.less @@ -0,0 +1,119 @@ +.o_entertainment_games_log_in_icon { + font-size: 15em; + cursor: pointer; + margin: 20px 0px 20px 0px; + padding: 0px 15px 0px 15px; + border-radius: 10%; + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.6); +} + +.o_entertainment_games_kiosk_mode_container { + .o-flex-display(); + .o-flex-flow(column, nowrap); + .o-justify-content(center); + .o-align-items(center); + + @media (min-width: @screen-xs-max) { + background: url("../img/application-switcher-bg.jpg") no-repeat center center fixed; + background-size: cover; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } +} + +/************** MIXINS for ANIMATIONS *************/ +.o-display-marked(@content, @top, @left, @color) { + position: absolute; + top: @top; + left: @left; + font-size: 150px; + font-family: "FontAwesome"; + content: @content; + color: @color; + animation: markAnim ease-in-out 10s; + animation-iteration-count: 5; + transform-origin: 50% 50%; + animation-fill-mode:forwards; /*when the spec is finished*/ + -webkit-animation: markAnim ease-in-out 10s; + -webkit-animation-iteration-count: 1; + -webkit-transform-origin: 50% 50%; + -webkit-animation-fill-mode:forwards; /*Chrome 16+, Safari 4+*/ + -moz-animation: markAnim ease-in-out 10s; + -moz-animation-iteration-count: 1; + -moz-transform-origin: 50% 50%; + -moz-animation-fill-mode:forwards; /*FF 5+*/ + -o-animation: markAnim ease-in-out 10s; + -o-animation-iteration-count: 1; + -o-transform-origin: 50% 50%; + -o-animation-fill-mode:forwards; /*Not implemented yet*/ + -ms-animation: markAnim ease-in-out 10s; + -ms-animation-iteration-count: 1; + -ms-transform-origin: 50% 50%; + -ms-animation-fill-mode:forwards; /*IE 10+*/ + + @media (max-width: 992px) { + left: 40%; + font-size: 30vw; + } +} + +.o_wow_thumbs:after { + .o-display-marked("You Won \A \f164 \00a0 - \f118", 20%, 40%, #21b799); + white-space: pre; +} +.o_lost_thumbs:after { + .o-display-marked("You Lost \A \f165 \00a0 - \f119", 20%, 40%, #b73720); + white-space: pre; +} + + +.o_entertainment_games_kiosk_mode { + width: 100%; + text-align: center; + position: relative; + background-color: #fff; + padding: 2em; + + h1 { + margin: 0 0 2rem 0; + } + + .message_demo_barcodes { + font-size: 0.9em; + margin: 0; + } + + img { + overflow:hidden; // prevent margins colapsing with h1 + margin-top: 3rem; + width: 200px; + } + + p { + text-align: left; + margin: 3rem 0; + } + + > button { + font-size: 1.2em; + margin-bottom: 2rem; + width: 100%; + } + + > button:last-child { + margin-bottom: 0; + } + + @media (min-width: @screen-xs-max) { + flex: 0 0 auto; + width: 550px; + border-radius: 10px; + background-color: rgba(255,255,255,0.8); + box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.6); + font-size: 1.2em; + padding: 3em; + } +} \ No newline at end of file diff --git a/game_sudoku/static/src/xml/game.xml b/game_sudoku/static/src/xml/game.xml new file mode 100644 index 000000000..453a4e638 --- /dev/null +++ b/game_sudoku/static/src/xml/game.xml @@ -0,0 +1,20 @@ + + diff --git a/game_sudoku/static/src/xml/sudoku.xml b/game_sudoku/static/src/xml/sudoku.xml new file mode 100644 index 000000000..eda232f0a --- /dev/null +++ b/game_sudoku/static/src/xml/sudoku.xml @@ -0,0 +1,161 @@ + + diff --git a/game_sudoku/views/game_approve_sequence.xml b/game_sudoku/views/game_approve_sequence.xml new file mode 100644 index 000000000..52371cfed --- /dev/null +++ b/game_sudoku/views/game_approve_sequence.xml @@ -0,0 +1,9 @@ + + + + + Game Approve + employee.game + + + \ No newline at end of file diff --git a/game_sudoku/views/game_template.xml b/game_sudoku/views/game_template.xml new file mode 100644 index 000000000..6f976770a --- /dev/null +++ b/game_sudoku/views/game_template.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/game_sudoku/views/main_menu.xml b/game_sudoku/views/main_menu.xml new file mode 100644 index 000000000..c0e88d404 --- /dev/null +++ b/game_sudoku/views/main_menu.xml @@ -0,0 +1,49 @@ + + + + + Game Approval + entertainment_games_my_game + main + + + + employee.game.approve.tree + employee.game.approve + + + + + + + + + + + + + {'readonly': [('state', 'in', ('sent','revised','done','cancel'))]} + + + + {'readonly': [('state', 'in', ('sent','revised','done','cancel'))]} + + + + {'readonly': [('state', 'in', ('sent','revised','done','cancel'))]} + + + + {'readonly': [('state', 'in', ('sent','revised','done','cancel'))]} + + + + + + sale.order.tree + sale.order + + + + + + + + + \ No newline at end of file diff --git a/hr_recruitment_validations/__init__.py b/hr_recruitment_validations/__init__.py new file mode 100644 index 000000000..427d284cf --- /dev/null +++ b/hr_recruitment_validations/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2016-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models diff --git a/hr_recruitment_validations/__manifest__.py b/hr_recruitment_validations/__manifest__.py new file mode 100644 index 000000000..331aeb62d --- /dev/null +++ b/hr_recruitment_validations/__manifest__.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2016-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Advanced HR Recruitment', + 'version': '10.0.1.0.0', + 'summary': 'Creates validations In HR Recruitment Workflow' + '(Eg: An application stage cannot be moved to its previous one)', + 'description': """ Once Application stage is set as Contract signed then Users cannot change its value + """, + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'category': 'Generic Modules/Human Resources', + 'website': 'https://www.cybrosys.com', + 'depends': [ + 'base', + 'hr_recruitment' + ], + 'data': ['views/hr_form_extend.xml'], + 'images': ['static/description/banner.jpg'], + 'installable': True, + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, +} diff --git a/hr_recruitment_validations/__manifest__.py~ b/hr_recruitment_validations/__manifest__.py~ new file mode 100644 index 000000000..2662fb981 --- /dev/null +++ b/hr_recruitment_validations/__manifest__.py~ @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2016-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Advanced HR Recruitment', + 'version': '10.0.1.0.0', + 'summary': 'Creates validations In HR Recruitment Workflow' + '(Eg: An application stage cannot be moved to its previous one)', + 'description': """ Once Application stage is set as Contract signed then Users cannot change its value + """, + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'category': 'Human Resources', + 'website': 'https://www.cybrosys.com', + 'depends': [ + 'base', + 'hr_recruitment' + ], + 'data': ['views/hr_form_extend.xml'], + 'images': ['static/description/banner.jpg'], + 'installable': True, + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, +} diff --git a/hr_recruitment_validations/models/__init__.py b/hr_recruitment_validations/models/__init__.py new file mode 100644 index 000000000..811755b32 --- /dev/null +++ b/hr_recruitment_validations/models/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2016-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import hr_form_validations diff --git a/hr_recruitment_validations/models/hr_form_validations.py b/hr_recruitment_validations/models/hr_form_validations.py new file mode 100644 index 000000000..426dd10e3 --- /dev/null +++ b/hr_recruitment_validations/models/hr_form_validations.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2016-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technologies() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +from odoo import models, fields, api, _ +from odoo.exceptions import UserError + + +class AddValidationHr(models.Model): + _inherit = 'hr.applicant' + + stage_check = fields.Char(related='stage_id.name') + + @api.multi + def write(self, data): + res = super(AddValidationHr, self).write(data) + if data['stage_id'] and data['last_stage_id']: + if data['last_stage_id'] > data['stage_id']: + raise UserError(_("Invalid movement!!!")) + return res diff --git a/hr_recruitment_validations/static/description/banner.jpg b/hr_recruitment_validations/static/description/banner.jpg new file mode 100644 index 000000000..c9c925532 Binary files /dev/null and b/hr_recruitment_validations/static/description/banner.jpg differ diff --git a/hr_recruitment_validations/static/description/cybro_logo.png b/hr_recruitment_validations/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/hr_recruitment_validations/static/description/cybro_logo.png differ diff --git a/hr_recruitment_validations/static/description/hr_recruitment.png b/hr_recruitment_validations/static/description/hr_recruitment.png new file mode 100644 index 000000000..57d51a3e7 Binary files /dev/null and b/hr_recruitment_validations/static/description/hr_recruitment.png differ diff --git a/hr_recruitment_validations/static/description/hr_recruitment_2.png b/hr_recruitment_validations/static/description/hr_recruitment_2.png new file mode 100644 index 000000000..d4bfa7708 Binary files /dev/null and b/hr_recruitment_validations/static/description/hr_recruitment_2.png differ diff --git a/hr_recruitment_validations/static/description/icon.png b/hr_recruitment_validations/static/description/icon.png new file mode 100644 index 000000000..b342dc883 Binary files /dev/null and b/hr_recruitment_validations/static/description/icon.png differ diff --git a/hr_recruitment_validations/static/description/index.html b/hr_recruitment_validations/static/description/index.html new file mode 100644 index 000000000..975684808 --- /dev/null +++ b/hr_recruitment_validations/static/description/index.html @@ -0,0 +1,78 @@ +
    +
    +

    Advanced HR Recruitment

    +

    Creates validations In HR Recruitment Workflow

    +

    Author : Cybrosys Techno Solutions , www.cybrosys.com

    +
    +

    Features:

    +
      +
    •    Once application stage is set to contract signed, then changing the stage option is disabled.
    • +
    •    An applicant cannot be refused after contract is signed.
    • +
    •    An applicant cannot be moved to a previous stage.
    • +
    +
    +
    +
    + +
    +
    +

    Application Form

    +
    +
    +
    + +
    +
    +
    +

    + An application stage cannot be moved to its previous one +

    +
    + +
    +
    +
    + +
    +
    +

    Contract Signed Stage

    +
    +
    +
    + +
    +
    +
    +

    + Refuse Button and stage changing options are disabled +

    +
    +
    +
    +
    + +
    +

    Need Any Help?

    + +
    diff --git a/hr_recruitment_validations/views/hr_form_extend.xml b/hr_recruitment_validations/views/hr_form_extend.xml new file mode 100644 index 000000000..b5afddeb7 --- /dev/null +++ b/hr_recruitment_validations/views/hr_form_extend.xml @@ -0,0 +1,24 @@ + + + + + Jobs - Recruitment Form + hr.applicant + + + + + + +
    + +
    +

    Need Any Help?

    + +
    diff --git a/hrms_dashboard/static/src/css/hrms_dashboard.css b/hrms_dashboard/static/src/css/hrms_dashboard.css new file mode 100644 index 000000000..2cbceda5a --- /dev/null +++ b/hrms_dashboard/static/src/css/hrms_dashboard.css @@ -0,0 +1,575 @@ +.o_dashboards{ + padding-top :15px; + background-color: #f8faff !important; +} +.social-box { + min-height: 160px; + margin-bottom: 1.5rem; + text-align: center; + background: #fff; } + .social-box i { + display: block; + margin: -1px -1px 0; + font-size: 40px; + line-height: 90px; + background: #e9ecef; } + .social-box .chart-wrapper { + height: 90px; + margin: -90px 0 0; } + .social-box .chart-wrapper canvas { + width: 100% !important; + height: 90px !important; } + .social-box ul { + padding: 10px 0; + list-style: none; } + .social-box ul li { + display: block; + float: left; + width: 50%; + padding-top: 10px; + font-size: 18px; } + .social-box ul li:first-child { + border-right: 1px solid #c2cfd6; } + .social-box ul li strong { + display: block; + font-size: 20px; } + .social-box ul li span { + font-size: 18px; + font-weight: 500; + color: #949CA0; + text-transform: uppercase; } + .social-box.facebook i { + color: #fff; + background: #3b5998; } + .social-box.twitter i { + color: #fff; + background: #00aced; } + .social-box.linkedin i { + color: #fff; + background: #4875b4; } + .social-box.google-plus i { + color: #fff; + background: #d34836; } + + +.content { + float: left; + padding: 0 20px; + width: 100%; } + +.card { + padding-top: 0px; + padding: 14px; + margin-bottom: 1.5rem; + border-radius: 10px; + box-shadow: 2px 14px 32px 5px rgba(0, 0, 0, 0.02), 0 3px 13px 0px rgba(0, 0, 0, 0.16); + background-color: #fff; + transition: transform 0.2s ease, box-shadow 0.2s ease; + will-change: transform, box-shadow; +} +.card:hover{ + transform: translateY(-5px) translateZ(0); + box-shadow: 0 16px 32px 0 rgba(62,57,107,0.28), 0 0 0 transparent; +} + .card h4 { + font-size: 1.1rem; } + .card .user-header .media img { + border: 5px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + -webkit-border-radius: 50%; } + .card .card-header .card-actions button { + display: block; + float: left; + width: 50px; + padding: .75rem 0; + margin: 0 !important; + color: #fff; + outline: 0; + text-align: center; + background: transparent; + border: 0; + border-left: 1px solid rgba(120, 130, 140, 0.4); } + .card .card-footer { + padding: 0.65rem 1.25rem; + background-color: #f0f3f5; + border-top: 1px solid #c2cfd6; } + .card .card-footer ul li { + display: table-cell; + padding: 0 1rem; + text-align: center; } + +.breadcrumbs { + margin-top: 0; } + +/* Tabs */ +.nav-tabs a.active { + color: #555; + cursor: default; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; } +.nav-tabs .dropdown .dropdown-menu { + top: 100% !important; } + +.custom-tab .nav-tabs > a.active, .custom-tab .nav-tabs > .active > a:focus, .custom-tab .nav-tabs > li.active > a:hover { + border-color: transparent transparent; + color: #ff2e44; + position: relative; } + +.custom-tab .nav-tabs > a.active > a:after, .custom-tab .nav-tabs > li.active > a:focus:after, .custom-tab .nav-tabs > li.active > a:hover:after { + background: #ff2e44; + bottom: -1px; + content: ""; + height: 2px; + left: 0; + position: absolute; + right: 0; + width: 100%; + z-index: 999; } + +.card .card-header .card-actions { + float: right; } + .card .card-header .card-actions [class*="btn"] { + border-left: 1px solid rgba(120, 130, 140, 0.4); + color: #878787; + display: inline-block; + font-size: 16px; + float: left; + padding: 0 7px; + width: inherit; + text-align: center; } +.left-top-card-body { + display: block; + float: left; + position: relative; +} +.left-bottom-card-body{ + display: block; + float: left; + position: relative; +} +.social-buttons .card-body p button { + padding-top: 0; + padding-left: 0; + padding-bottom: 0; } +.social-buttons .only-icon .card-body p button { + padding: 0; } +.social-buttons .social i { + padding: 0 10px; + width: inherit !important; } +.social-buttons .only-text p button { + padding: 0 .5rem; } + +.buttons button { + margin: 2px 0; } + +/* Ribons */ +.corner-ribon { + text-align: center; + width: 71px; + height: 71px; + position: absolute; + right: 0; + top: 0; + font-size: 20px; } + +.corner-ribon i { + padding: 10px 0 0 35px; + color: #fff; } + +/*.black-ribon {*/ + /*background: url("../../images/twitter_corner_black.png") no-repeat; }*/ + +/*.blue-ribon {*/ + /*background: url("../../images/twitter_corner_blue.png") no-repeat; }*/ + +.twt-feed .wtt-mark { + color: rgba(255, 255, 255, 0.15); + font-size: 160px; + position: absolute; + top: 10px; + left: 40%; } + +.twt-feed { + -webkit-border-radius: 4px 4px 0 0; + color: #FFFFFF; + padding: 40px 10px 10px; + position: relative; + min-height: 170px; } + +.weather-category { + padding: 15px 0; + color: #74829C; } + .weather-category ul li { + width: 32%; + text-align: center; + border-right: 1px solid #e6e6e6; + display: inline-block; } + +.twt-feed.blue-bg { + background: #58C9F3; } + +.twt-category { + display: inline-block; + margin-bottom: 11px; + margin-top: 10px; + width: 100%; } + .twt-category ul li { + color: #bdbdbd; + font-size: 13px; } + +.twt-footer { + padding: 12px 15px; } + +.twt-footer, .twt-footer a { + color: #d2d2d2; } + +/* Button Reset */ +.btn, .button { + display: inline-block; + font-weight: 400; + text-align: center; + white-space: nowrap; + vertical-align: middle; + transition: all .15s ease-in-out; + border-radius: 0; + cursor: pointer; } + +/* Icons */ +.icon-section { + margin: 0 0 3em; + clear: both; + overflow: hidden; } + +.icon-container { + width: 240px; + padding: .7em 0; + float: left; + position: relative; + text-align: left; } + +.icon-container [class^="ti-"], +.icon-container [class*=" ti-"] { + color: #000; + position: absolute; + margin-top: 3px; + transition: .3s; } + +.icon-container:hover [class^="ti-"], +.icon-container:hover [class*=" ti-"] { + font-size: 2.2em; + margin-top: -5px; } + +.icon-container:hover .icon-name { + color: #000; } + +.icon-name { + color: #aaa; + margin-left: 35px; + font-size: 14px; + transition: .3s; } + +.icon-container:hover .icon-name { + margin-left: 45px; } + +.fontawesome-icon-list .page-header { + border-bottom: 1px solid #C9CDD7; + padding-bottom: 9px; + margin: 30px 0px 27px 0px; } +.fontawesome-icon-list h2 { + margin-top: 0; + font-size: 20px; + font-weight: 300; } +.fontawesome-icon-list i { + font-style: italic; + padding-right: 10px; } + +.social-box i { + line-height: 110px; } +.social-box ul { + display: inline-block; + margin: 7px 0 0; + padding: 10px; + width: 100%; } + .social-box ul li { + color: #949CA0; + font-size: 14px; + font-weight: 700; + padding: 0 10px 0 0; + text-align: right; } + .social-box ul li:last-child { + padding-left: 10px; + padding-right: 0; + text-align: left; } + .social-box ul li span { + font-size: 14px; } + +.login-logo { + text-align: center; + margin-bottom: 15px; } + .login-logo span { + color: #ffffff; + font-size: 24px; } + +.login-content { + max-width: 540px; + margin: 8vh auto; } + +.login-form { + background: #ffffff; + padding: 30px 30px 20px; + border-radius: 2px; } + +.login-form h4 { + color: #878787; + text-align: center; + margin-bottom: 50px; } + +.login-form .checkbox { + color: #878787; } + +.login-form .checkbox label { + text-transform: none; } + +.login-form .btn { + width: 100%; + text-transform: uppercase; + font-size: 14px; + padding: 15px; + border: 0px; } + +.login-form label { + color: #878787; + text-transform: uppercase; } + +.login-form label a { + color: #ff2e44; } + +.social-login-content { + margin: 0px -30px; + border-top: 1px solid #e7e7e7; + border-bottom: 1px solid #e7e7e7; + padding: 30px 0px; + background: #fcfcfc; } + +.social-button { + padding: 0 30px; } + .social-button .facebook { + background: #3b5998; + color: #fff; } + .social-button .facebook:hover { + background: #344e86; } + .social-button .twitter { + background: #00aced; + color: #fff; } + .social-button .twitter:hover { + background: #0099d4; } + +.social-button i { + padding: 19px; } + +.register-link a { + color: #ff2e44; } + +.cpu-load { + width: 100%; + height: 272px; + font-size: 14px; + line-height: 1.2em; } + +.cpu-load-data-content { + font-size: 18px; + font-weight: 400; + line-height: 40px; } + +.cpu-load-data { + margin-bottom: 30px; } + +.cpu-load-data li { + display: inline-block; + width: 32.5%; + text-align: center; + border-right: 1px solid #e7e7e7; } + +.cpu-load-data li:last-child { + border-right: 0px; } + +.nestable-cart { + overflow: hidden; } + +/* Forms */ +.input-group-addon { + background-color: transparent; + border-left: 0; } + +.input-group-addon, .input-group-btn { + white-space: nowrap; + vertical-align: middle; } + +.input-group-addon { + padding: .5rem .75rem; + margin-bottom: 0; + font-size: 1rem; + font-weight: 400; + line-height: 1.25; + color: #495057; + text-align: center; + background-color: #e9ecef; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: .25rem; } + +.flotTip { + background: #252525; + border: 1px solid #252525; + padding: 5px 15px; + color: #ffffff; } + +.flot-container { + box-sizing: border-box; + width: 100%; + height: 275px; + padding: 20px 15px 15px; + margin: 15px auto 30px; + background: transparent; } + +.flot-pie-container { + height: 275px; } + +.flotBar-container { + height: 275px; } + +.flot-line { + width: 100%; + height: 100%; + font-size: 14px; + line-height: 1.2em; } + +.legend table { + border-spacing: 5px; } + +#chart1, +#flotBar, +#flotCurve { + width: 100%; + height: 275px; } + +.morris-hover { + position: absolute; + z-index: 1; } + +.morris-hover.morris-default-style .morris-hover-row-label { + font-weight: bold; + margin: 0.25em 0; } + +.morris-hover.morris-default-style .morris-hover-point { + white-space: nowrap; + margin: 0.1em 0; } + +.morris-hover.morris-default-style { + border-radius: 2px; + padding: 10px 12px; + color: #666; + background: rgba(0, 0, 0, 0.7); + border: none; + color: #fff !important; } + +.morris-hover-point { + color: rgba(255, 255, 255, 0.8) !important; } + +#morris-bar-chart { + height: 285px; } + +.map, .vmap { + width: 100%; + height: 400px; } + +.btn-toolbar { + float: left !important; } + .btn-toolbar .btn-outline-secondary:not([disabled]):not(.disabled):active, + .btn-toolbar .btn-outline-secondary:not([disabled]):not(.disabled).active, + .btn-toolbar .show > .btn-outline-secondary.dropdown-toggle { + background-color: #212529; + border-color: #212529; + -webkit-box-shadow: none; + box-shadow: none; + color: #fff; } + .btn-toolbar .btn-outline-secondary:hover { + background-color: #212529; + border-color: #212529; + color: #fff; } + +/* Widget One +---------------------------*/ +.dib { + display: inline-block; } + +.stat-widget-one .stat-icon { + vertical-align: top; + margin: auto; + width: 100%; + color: #01c490; +} +.stat-widget-one { + background-color: white; + text-align: center; +} + +.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; } + +.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; } + +.bg-flat-color-1 { + background: #20a8d8; } + +.bg-flat-color-2 { + background: #63c2de; } + +.bg-flat-color-3 { + background: #ffc107; } + +.bg-flat-color-4 { + background: #f86c6b; } + +.bg-flat-color-5 { + background: #4dbd74; } + +.mb-0{ + font-size: 20px; + position: relative; + text-align: center; +} +.mb-0 .dash-title { + font-size: 20px; + text-align: center; + color: rgba(255, 255, 255, 0.81); +} +.hr_birthday { + font-size: 28px; + text-align: center; + padding: 20px 0; + color: #00438b; + font-weight: 600; +} +body .text-color { + color: #00438b; +} \ No newline at end of file diff --git a/hrms_dashboard/static/src/js/hrms_dashboard.js b/hrms_dashboard/static/src/js/hrms_dashboard.js new file mode 100644 index 000000000..af73f656f --- /dev/null +++ b/hrms_dashboard/static/src/js/hrms_dashboard.js @@ -0,0 +1,223 @@ +odoo.define('hrms_dashboard.Dashboard', function (require) { +"use strict"; + +var ajax = require('web.ajax'); +var ControlPanelMixin = require('web.ControlPanelMixin'); +var core = require('web.core'); +var Dialog = require('web.Dialog'); +var Model = require('web.Model'); +var session = require('web.session'); +var utils = require('web.utils'); +var web_client = require('web.web_client'); +var Widget = require('web.Widget'); +var session = require('web.session'); +var _t = core._t; +var QWeb = core.qweb; + +var HrDashboard = Widget.extend(ControlPanelMixin, { + template: "hrms_dashboard.HrDashboardMain", + events: { + 'click .hr_leave_request_approve': 'leaves_to_approve', + 'click .hr_leave_allocations_approve': 'leave_allocations_to_approve', + 'click .hr_timesheet_approve': 'timesheets_to_approve', + 'click .hr_job_application_approve': 'job_applications_to_approve', + 'click .hr_payslip':'hr_payslip', + 'click .hr_contract':'hr_contract', + 'click .hr_employee':'hr_employee', + 'click .leaves_request_month':'leaves_request_month', + 'click .leaves_request':'leaves_request' + }, + + init: function(parent, context) { + this._super(parent, context); + this.login_employee = true; + this.employee_birthday = []; + this._super(parent,context); + + }, + + start: function() { + var self = this; + for(var i in self.breadcrumbs){ + self.breadcrumbs[i].title = "Dashboard"; + } + self.update_control_panel({breadcrumbs: self.breadcrumbs}, {clear: true}); + var hr_emp = new Model('hr.employee'); + var model = new Model('hr.employee').call('get_user_employee_details').then(function(result){ + + this.login_employee = result[0]; + $('.o_hr_dashboard').html(QWeb.render('ManagerDashboard', {widget: this})); + $('.o_hr_dashboard').prepend(QWeb.render('LoginEmployeeDetails', {widget: this})); + /*need to check user access levels*/ + session.user_has_group('hr.group_hr_manager').then(function(has_group){ + if(has_group == false){ + $('.employee_dashboard_main').css("display", "none"); + } + }); + }); + var today = new Date().toJSON().slice(0,10).replace(/-/g,'/'); + var employee = new Model('hr.employee').query(['name', 'birthday','image']).filter([['birthday', '!=', false]]) + .order_by('birthday').all().then(function(res){ + for (var i = 0; i < res.length; i++) { + var bday_dt = new Date(res[i]['birthday']); + var bday_month = bday_dt.getMonth(); + var bday_day = bday_dt.getDate(); + var today_dt = new Date( today); + var today_month = today_dt.getMonth(); + var today_day = today_dt.getDate(); + var day = new Date(); + var next_day = new Date(day.setDate(day.getDate() + 7)); + var next_week = next_day.toJSON().slice(0,10).replace(/-/g,'/'); + var bday_date = bday_dt.toJSON().slice(0,10).replace(/-/g,'/');; + if (bday_month == today_month && bday_day >= today_day && next_week >= bday_date){ + self.employee_birthday.push(res[i]); + var flag = 1; + } + } + if (flag !=1){ + self.employee_birthday = false; + } + $('.o_hr_birthday_reminder').html(QWeb.render('BirthdayEventDashboard', {widget: self})); + }); + return this._super().then(function() { + self.$el.parent().addClass('oe_background_grey'); + }); + }, + + hr_payslip: function(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + this.do_action({ + name: _t("Employee Payslips"), + type: 'ir.actions.act_window', + res_model: 'hr.payslip', + view_mode: 'tree,form,calendar', + view_type: 'form', + views: [[false, 'list'],[false, 'form']], + target: 'current' + }) + }, + + hr_contract: function(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + this.do_action({ + name: _t("Contracts"), + type: 'ir.actions.act_window', + res_model: 'hr.contract', + view_mode: 'tree,form,calendar', + view_type: 'form', + views: [[false, 'list'],[false, 'form']], + target: 'current' + }) + }, + + leaves_request_month: function(e) { + var self = this; + e.stopPropagation(); + e.preventDefault(); + var date = new Date(); + var firstDay = new Date(date.getFullYear(), date.getMonth(), 1); + var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0); + var fday = firstDay.toJSON().slice(0,10).replace(/-/g,'-'); + var lday = lastDay.toJSON().slice(0,10).replace(/-/g,'-'); + this.do_action({ + name: _t("Leave Request"), + type: 'ir.actions.act_window', + res_model: 'hr.holidays', + view_mode: 'tree,form,calendar', + view_type: 'form', + views: [[false, 'list'],[false, 'form']], + domain: [['date_from','>', fday],['state','=','confirm'],['date_from','<', lday]], + target: 'current' + }) + }, + + leaves_request: function(e) { + var self = this; + e.stopPropagation(); + e.preventDefault(); + this.do_action({ + name: _t("Leave Request"), + type: 'ir.actions.act_window', + res_model: 'hr.holidays', + view_mode: 'tree,form,calendar', + view_type: 'form', + views: [[false, 'list'],[false, 'form']], + domain: [['type','=','add']], + target: 'current' + }) + }, + leaves_to_approve: function(e) { + var self = this; + e.stopPropagation(); + e.preventDefault(); + this.do_action({ + name: _t("Leave Request"), + type: 'ir.actions.act_window', + res_model: 'hr.holidays', + view_mode: 'tree,form,calendar', + view_type: 'form', + views: [[false, 'list'],[false, 'form']], + context: {'search_default_approve': true}, + domain: [['type','=','remove'],], + target: 'current' + }) + }, + leave_allocations_to_approve: function(e) { + var self = this; + e.stopPropagation(); + e.preventDefault(); + this.do_action({ + name: _t("Leave Allocation Request"), + type: 'ir.actions.act_window', + res_model: 'hr.holidays', + view_mode: 'tree,form,calendar', + view_type: 'form', + views: [[false, 'list'],[false, 'form']], + context: {'search_default_approve': true}, + domain: [['type','=','add'],], + target: 'current' + }) + }, + + timesheets_to_approve: function(e) { + var self = this; + e.stopPropagation(); + e.preventDefault(); + this.do_action({ + name: _t("Timesheets"), + type: 'ir.actions.act_window', + res_model: 'hr_timesheet_sheet.sheet', + view_mode: 'tree,form', + view_type: 'form', + views: [[false, 'list'],[false, 'form']], + context: {'search_default_to_approve': true}, + target: 'current' + }) + }, + job_applications_to_approve: function(event){ + var self = this; + event.stopPropagation(); + event.preventDefault(); + this.do_action({ + name: _t("Applications"), + type: 'ir.actions.act_window', + res_model: 'hr.applicant', + view_mode: 'tree,kanban,form,pivot,graph,calendar', + view_type: 'form', + views: [[false, 'list'],[false, 'kanban'],[false, 'form'], + [false, 'pivot'],[false, 'graph'],[false, 'calendar']], + context: {}, + target: 'current' + }) + }, +}); + +core.action_registry.add('hr_dashboard', HrDashboard); + +return HrDashboard; + +}); diff --git a/hrms_dashboard/static/src/xml/hrms_dashboard.xml b/hrms_dashboard/static/src/xml/hrms_dashboard.xml new file mode 100644 index 000000000..e55b29680 --- /dev/null +++ b/hrms_dashboard/static/src/xml/hrms_dashboard.xml @@ -0,0 +1,155 @@ + + + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +

    +

    + +

    +

    Leave Request

    +
    +
    +
    +
    +
    +
    +

    +

    +

    +

    This Month

    +
    +
    +
    +
    +
    +
    +

    +

    +

    +

    To Approve

    +
    +
    +
    +
    +
    +
    +
    +

    +

    +

    +

    Leave Allocations

    +
    +
    +
    +
    +
    +
    +

    +

    +

    +

    Job Applications

    +
    +
    +
    +
    +
    + + + +
    +
    + Upcoming Birthdays +
    +
    +
    + +
    +
    +
    +
    + + + +
    +

    +

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

    +

    +
    +
    + +
    +
    +
    +
    +
    +
    +
    Payslips
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    Timesheets
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    Contracts
    +
    +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/hrms_dashboard/views/dashboard_views.xml b/hrms_dashboard/views/dashboard_views.xml new file mode 100644 index 000000000..f18ac8478 --- /dev/null +++ b/hrms_dashboard/views/dashboard_views.xml @@ -0,0 +1,20 @@ + + + + Dashboard + hr_dashboard + + + + + + + diff --git a/mrp_production_draft/__init__.py b/mrp_production_draft/__init__.py new file mode 100644 index 000000000..4cd9270a1 --- /dev/null +++ b/mrp_production_draft/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Maintainer: Cybrosys Technologies () +############################################################################## +import models diff --git a/mrp_production_draft/__manifest__.py b/mrp_production_draft/__manifest__.py new file mode 100644 index 000000000..7bef4a508 --- /dev/null +++ b/mrp_production_draft/__manifest__.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: fasluca() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Draft Manufacturing Order', + 'version': '10.0.1.0', + 'summary': 'Draft State in Manufacturing Order', + 'description': """ + This module provides a draft state for manufacturing order instead of default first stage 'confirmed'. + """, + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://cybrosys.com/", + 'category': 'Manufacturing', + 'depends': ['mrp'], + 'data': [ + 'views/mrp_production_view.xml', + ], + 'demo': [], + 'images': ['static/description/banner.gif'], + 'license': 'LGPL-3', + 'installable': True, + 'application': False +} diff --git a/mrp_production_draft/__manifest__.py~ b/mrp_production_draft/__manifest__.py~ new file mode 100644 index 000000000..5b0ff2b94 --- /dev/null +++ b/mrp_production_draft/__manifest__.py~ @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: fasluca() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +{ + 'name': 'Draft Manufacturing Order', + 'version': '10.0.1.0', + 'summary': 'Draft State in Manufacturing Order', + 'description': """ + This module provides a draft state for manufacturing order instead of default first stage 'confirmed'. + """, + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://cybrosys.com/", + 'category': 'Manufacturing', + 'depends': ['mrp'], + 'data': [ + 'views/mrp_production_view.xml', + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'application': False +} diff --git a/mrp_production_draft/models/__init__.py b/mrp_production_draft/models/__init__.py new file mode 100644 index 000000000..150459d9e --- /dev/null +++ b/mrp_production_draft/models/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Maintainer: Cybrosys Technologies () +############################################################################## +import mrp_production diff --git a/mrp_production_draft/models/mrp_production.py b/mrp_production_draft/models/mrp_production.py new file mode 100644 index 000000000..e8d81e612 --- /dev/null +++ b/mrp_production_draft/models/mrp_production.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2009-TODAY Cybrosys Technologies(). +# Author: fasluca() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import api, models, fields, _ +from odoo.exceptions import UserError + +from odoo.addons.mrp.models.mrp_production import MrpProduction as mp + + +class MrpProduction(models.Model): + _inherit = 'mrp.production' + + state = fields.Selection([ + ('draft', 'Draft'), + ('confirmed', 'Confirmed'), + ('planned', 'Planned'), + ('progress', 'In Progress'), + ('done', 'Done'), + ('cancel', 'Cancelled')], string='State', + copy=False, default='draft', track_visibility='onchange') + + _sql_constraints = [ + ('name_uniq', 'check(1=1)', 'Reference must be unique per Company!'), + ] + + @api.model + def create(self, values): + production = super(mp, self).create(values) + return production + + @api.multi + def unlink(self): + if any(production.state not in ['draft', 'cancel'] for production in self): + raise UserError(_('Cannot delete a manufacturing order not in draft or cancel state')) + return super(mp, self).unlink() + + @api.multi + def action_confirm(self): + if not self.name or self.name == _('New'): + self.name = self.env['ir.sequence'].next_by_code('mrp.production') or _('New') + if not self.procurement_group_id: + self.procurement_group_id = self.env["procurement.group"].create({'name': self.name}).id + self._generate_moves() + self.state = 'confirmed' diff --git a/mrp_production_draft/static/description/MO_default.png b/mrp_production_draft/static/description/MO_default.png new file mode 100644 index 000000000..062b417ab Binary files /dev/null and b/mrp_production_draft/static/description/MO_default.png differ diff --git a/mrp_production_draft/static/description/MO_new.png b/mrp_production_draft/static/description/MO_new.png new file mode 100644 index 000000000..a0a5f0435 Binary files /dev/null and b/mrp_production_draft/static/description/MO_new.png differ diff --git a/mrp_production_draft/static/description/banner.gif b/mrp_production_draft/static/description/banner.gif new file mode 100644 index 000000000..f4f53468a Binary files /dev/null and b/mrp_production_draft/static/description/banner.gif differ diff --git a/mrp_production_draft/static/description/cybro_logo.png b/mrp_production_draft/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/mrp_production_draft/static/description/cybro_logo.png differ diff --git a/mrp_production_draft/static/description/delete_warning.png b/mrp_production_draft/static/description/delete_warning.png new file mode 100644 index 000000000..0394de602 Binary files /dev/null and b/mrp_production_draft/static/description/delete_warning.png differ diff --git a/mrp_production_draft/static/description/icon.png b/mrp_production_draft/static/description/icon.png new file mode 100644 index 000000000..34fb91887 Binary files /dev/null and b/mrp_production_draft/static/description/icon.png differ diff --git a/mrp_production_draft/static/description/index.html b/mrp_production_draft/static/description/index.html new file mode 100644 index 000000000..3d1991647 --- /dev/null +++ b/mrp_production_draft/static/description/index.html @@ -0,0 +1,95 @@ +
    +
    +

    Draft Manufacturing Order

    +

    Cybrosys Technologies

    +
    +
    + +
    +
    +

    Draft State in Manufacturing Order

    +

    + Provides a new state 'Draft' as default. So that users can manage a manufacturing order more easily. +

    +
    + +
    +

    By Default in Odoo,

    +
    + +
    +
    +
    +
      +
    •    When we create a MO, that directly becomes 'Confirmed'.
    • +
    •    Changing Product Or Any Other Related Details Like Quantity, BoM Is Not Possible After Saving The Manufacturing Order.
    • +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +

    Using this module,

    +
    + +
    +
    +
    +
      +
    •    Newly Created Manufacturing Orders Will Be In 'Draft' State.
    • +
    •    User Can Change The Product, Quantity, etc.. On This State.
    • +
    •    A New Button 'Confirm' Is Added To Confirm The Manufacturing Order.
    • +
    •    Sequence Number Will Not Be Generated Until Confirmation Of Manufacturing Order.
    • +
    +
    +
    +
    + +
    +
    +
    +
      +
    •    User can delete manufacturing order in 'Draft' state.
    • +
    +
    +
    +
    + +
    +
    +
    +
    + +
    + +
    +

    Need Any Help?

    + +
    + diff --git a/mrp_production_draft/views/mrp_production_view.xml b/mrp_production_draft/views/mrp_production_view.xml new file mode 100644 index 000000000..d83557b38 --- /dev/null +++ b/mrp_production_draft/views/mrp_production_view.xml @@ -0,0 +1,54 @@ + + + + + mrp.production.form + mrp.production + + + + + + + + + mrp.production.select + mrp.production + + + + + + + + + + Manufacturing Orders + ir.actions.act_window + mrp.production + form + tree,kanban,form,calendar,pivot,graph + + + {'search_default_todo': True} + +

    + Click to create a manufacturing order. +

    + A manufacturing order, based on a bill of materials, will + consume raw materials and produce finished products. +

    + Manufacturing orders are usually proposed automatically based + on customer requirements or automated rules like the minimum + stock rule. +

    +
    +
    + +
    +
    \ No newline at end of file diff --git a/mrp_secondary_uom/README.rst b/mrp_secondary_uom/README.rst new file mode 100644 index 000000000..1cf9a471e --- /dev/null +++ b/mrp_secondary_uom/README.rst @@ -0,0 +1,30 @@ +======================= +MRP - Secondary UoM v10 +======================= + +This module Manage the Manufacturing process with secondary UoM. + +Installation +============ + +Just select it from available modules to install it, there is no need to extra installations. + +Configuration +============= + +After installing this module, Go to Inventory->Configuration->Setting->Products->Unit of Measures-> +Enable the different units of measure for products (TICK on Some 'products may be sold/purchased in different unit of +measures'). + +Features +======== + +* Allows to manage MRP with Secondary UoM. +* Products to Produce With Secondary UoM. +* Produced Products With Secondary UoM. + +Credits +======= +Developer: Nikhil krishnan @ cybrosys, nikhil@cybrosys.in + + diff --git a/mrp_secondary_uom/__init__.py b/mrp_secondary_uom/__init__.py new file mode 100644 index 000000000..656daadf5 --- /dev/null +++ b/mrp_secondary_uom/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## +import models diff --git a/mrp_secondary_uom/__manifest__.py b/mrp_secondary_uom/__manifest__.py new file mode 100644 index 000000000..3f00168e4 --- /dev/null +++ b/mrp_secondary_uom/__manifest__.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +{ + 'name': 'MRP - Secondary UoM', + 'version': '10.0.1.0', + 'category': 'Manufacturing', + 'summary': 'Secondary UoM in Manufacturing Order', + 'description': """ +Manage the Manufacturing process with secondary UoM +=================================================== +This module allows you to cover planning, ordering, stocks and the manufacturing with a Secondary UoM. It handles the +Products to Produce & Produced Products according to the production with Secondary UoM +----------------------------------------------------------------------------------------- +* Allows to manage MRP with Secondary UoM +* Products to Produce With Secondary UoM +* Produced Products With Secondary UoM +""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "http://www.cybrosys.com", + 'depends': ['mrp'], + 'data': ['views/mrp_sec_uom.xml', + 'data/mrp_sec_uom_round.xml'], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'application': False, +} diff --git a/mrp_secondary_uom/data/mrp_sec_uom_round.xml b/mrp_secondary_uom/data/mrp_sec_uom_round.xml new file mode 100644 index 000000000..2949ee4f0 --- /dev/null +++ b/mrp_secondary_uom/data/mrp_sec_uom_round.xml @@ -0,0 +1,9 @@ + + + + + Secondary UoM Ratio + 10 + + + \ No newline at end of file diff --git a/mrp_secondary_uom/models/__init__.py b/mrp_secondary_uom/models/__init__.py new file mode 100644 index 000000000..b1fd4a670 --- /dev/null +++ b/mrp_secondary_uom/models/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +import mrp_sec_uom +import change_production_qnty diff --git a/mrp_secondary_uom/models/change_production_qnty.py b/mrp_secondary_uom/models/change_production_qnty.py new file mode 100644 index 000000000..4f3072269 --- /dev/null +++ b/mrp_secondary_uom/models/change_production_qnty.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError +import math + + +class ChangeProductionQty(models.TransientModel): + _inherit = 'change.production.qty' + + mrp_sec_qty = fields.Float(string='Product Secondary Qty') + mrp_sec_uom = fields.Many2one('product.uom', string='Secondary Unit') + + @api.model + def default_get(self, fields): + res = super(ChangeProductionQty, self).default_get(fields) + prod_obj = self.env['mrp.production'] + prod = prod_obj.browse(self._context.get('active_id')) + if 'product_qty' in fields: + res.update({'product_qty': prod.product_qty}) + if 'mrp_sec_qty' in fields: + res.update({'mrp_sec_qty': prod.mrp_sec_qty}) + if 'mrp_sec_uom' in fields: + res.update({'mrp_sec_uom': prod.mrp_sec_uom.id}) + return res + + @api.model + def _update_product_to_produce(self, production, qty, ratio, sec_uom): + production_move = production.move_finished_ids.filtered(lambda x:x.product_id.id == production.product_id.id and x.state not in ('done', 'cancel')) + + if production_move: + production_move.write({ + 'product_uom_qty': qty, + 'stock_move_sec_uom': sec_uom.id, + 'ratio_sec_uom': ratio, + }) + else: + production_move = production._generate_finished_moves() + production_move = production.move_finished_ids.filtered(lambda x : x.state not in ('done', 'cancel') and production.product_id.id == x.product_id.id) + production_move.write({ + 'product_uom_qty': qty, + 'stock_move_sec_uom': sec_uom.id, + 'ratio_sec_uom': ratio, + }) + + @api.multi + def change_prod_qty(self): + for wizard in self: + production = wizard.mo_id + produced = sum(production.move_finished_ids.mapped('quantity_done')) + if wizard.product_qty < produced: + raise UserError(_("You have already processed %d. Please input a quantity higher than %d ")%(produced, produced)) + ratio = wizard.mrp_sec_qty/wizard.product_qty + production.write({'product_qty': wizard.product_qty, + 'mrp_sec_qty': wizard.mrp_sec_qty, + 'mrp_sec_uom': wizard.mrp_sec_uom.id, + 'mrp_ratio_sec_uom': ratio + }) + factor = production.product_uom_id._compute_quantity(production.product_qty - production.qty_produced, production.bom_id.product_uom_id) / production.bom_id.product_qty + boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id) + for line, line_data in lines: + production._update_raw_move(line, line_data) + operation_bom_qty = {} + for bom, bom_data in boms: + for operation in bom.routing_id.operation_ids: + operation_bom_qty[operation.id] = bom_data['qty'] + + self._update_product_to_produce(production, production.product_qty - production.qty_produced, + ratio, production.mrp_sec_uom) + moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel')) + moves.do_unreserve() + moves.action_assign() + for wo in production.workorder_ids: + operation = wo.operation_id + if operation_bom_qty.get(operation.id): + cycle_number = math.ceil(operation_bom_qty[operation.id] / operation.workcenter_id.capacity) # TODO: float_round UP + wo.duration_expected = (operation.workcenter_id.time_start + + operation.workcenter_id.time_stop + + cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency) + if production.product_id.tracking == 'serial': + quantity = 1.0 + else: + quantity = wo.qty_production - wo.qty_produced + quantity = quantity if (quantity > 0) else 0 + wo.qty_producing = quantity + if wo.qty_produced < wo.qty_production and wo.state == 'done': + wo.state = 'progress' + # assign moves; last operation receive all unassigned moves + # TODO: following could be put in a function as it is similar as code in _workorders_create + # TODO: only needed when creating new moves + moves_raw = production.move_raw_ids.filtered(lambda move: move.operation_id == operation and move.state not in ('done', 'cancel')) + if wo == production.workorder_ids[-1]: + moves_raw |= production.move_raw_ids.filtered(lambda move: not move.operation_id) + moves_finished = production.move_finished_ids.filtered(lambda move: move.operation_id == operation) #TODO: code does nothing, unless maybe by_products? + moves_raw.mapped('move_lot_ids').write({'workorder_id': wo.id}) + (moves_finished + moves_raw).write({'workorder_id': wo.id}) + if wo.move_raw_ids.filtered(lambda x: x.product_id.tracking != 'none') and not wo.active_move_lot_ids: + wo._generate_lot_ids() + return {} diff --git a/mrp_secondary_uom/models/mrp_sec_uom.py b/mrp_secondary_uom/models/mrp_sec_uom.py new file mode 100644 index 000000000..e99b268d0 --- /dev/null +++ b/mrp_secondary_uom/models/mrp_sec_uom.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +# +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Nikhil krishnan() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +from odoo import models, fields, api +import odoo.addons.decimal_precision as dp + + +class MRPSecUOM(models.Model): + _inherit = 'mrp.production' + + mrp_sec_qty = fields.Float('Secondary Quantity', readonly=True) + mrp_sec_uom = fields.Many2one('product.uom', 'Secondary Unit') + mrp_ratio_sec_uom = fields.Float('Ratio 2ndry Quantity', digits=dp.get_precision('Secondary UoM Ratio')) + + # Over write this fuction for add the new line of code: 'ratio_sec_uom': self.mrp_ratio_sec_uom, + def _generate_finished_moves(self): + move = self.env['stock.move'].create({ + 'name': self.name, + 'date': self.date_planned_start, + 'date_expected': self.date_planned_start, + 'product_id': self.product_id.id, + 'product_uom': self.product_uom_id.id, + 'product_uom_qty': self.product_qty, + 'ratio_sec_uom': self.mrp_ratio_sec_uom, + 'stock_move_sec_uom': self.mrp_sec_uom.id, + 'location_id': self.product_id.property_stock_production.id, + 'location_dest_id': self.location_dest_id.id, + 'move_dest_id': self.procurement_ids and self.procurement_ids[0].move_dest_id.id or False, + 'procurement_id': self.procurement_ids and self.procurement_ids[0].id or False, + 'company_id': self.company_id.id, + 'production_id': self.id, + 'origin': self.name, + 'group_id': self.procurement_group_id.id, + }) + move.action_confirm() + return move + + @api.model + def create(self, vals): + if vals.get('mrp_sec_qty'): + if vals.get('product_qty'): + vals['mrp_ratio_sec_uom'] = float(vals['mrp_sec_qty'])/float(vals['product_qty']) + return super(MRPSecUOM, self).create(vals) + + +class StockMoveSecUOM(models.Model): + _inherit = 'stock.move' + + stock_move_sec_qty_to_produce = fields.Float(string='To Produce (2ndry)', + compute='compute_stock_move_sec_qty_to_produce') + stock_move_sec_uom = fields.Many2one('product.uom', string='2ndry UoM') + stock_move_sec_qty_produced = fields.Float(string='Produced (2ndry)', + compute='compute_stock_move_sec_qty_produced') + ratio_sec_uom = fields.Float(string='Ratio 2ndry Quantity', digits=dp.get_precision('Secondary UoM Ratio')) + + def compute_stock_move_sec_qty_to_produce(self): + for rec in self: + rec.stock_move_sec_qty_to_produce = rec.ratio_sec_uom * rec.product_uom_qty + + def compute_stock_move_sec_qty_produced(self): + for rec in self: + rec.stock_move_sec_qty_produced = rec.ratio_sec_uom * rec.quantity_done + + +class MRPProductProduceSecUOM(models.TransientModel): + _inherit = 'mrp.product.produce' + + product_produce_sec_qty = fields.Float(string='2ndry Quantity') + ratio_sec_uom = fields.Float(string='Ratio 2ndry Quantity', digits=dp.get_precision('Secondary UoM Ratio')) + product_produce_sec_uom = fields.Many2one('product.uom', string='2ndry UoM') + + @api.model + def default_get(self, fields): + res = super(MRPProductProduceSecUOM, self).default_get(fields) + if self._context and self._context.get('active_id'): + production = self.env['mrp.production'].browse(self._context['active_id']) + serial_finished = (production.product_id.tracking == 'serial') + if serial_finished: + sec_qty = production.mrp_ratio_sec_uom + else: + + sec_qty = res['product_qty'] * production.mrp_ratio_sec_uom + + res['product_produce_sec_qty'] = sec_qty + res['product_produce_sec_uom'] = production.mrp_sec_uom.id + res['ratio_sec_uom'] = production.mrp_ratio_sec_uom + return res + + @api.onchange('product_qty', 'product_produce_sec_qty') + def onchange_product_qty(self): + sec_qty = self.product_qty * self.ratio_sec_uom + self.product_produce_sec_qty = sec_qty diff --git a/mrp_secondary_uom/static/description/5.png b/mrp_secondary_uom/static/description/5.png new file mode 100644 index 000000000..b4db1f4b9 Binary files /dev/null and b/mrp_secondary_uom/static/description/5.png differ diff --git a/mrp_secondary_uom/static/description/6.png b/mrp_secondary_uom/static/description/6.png new file mode 100644 index 000000000..a8a01be3f Binary files /dev/null and b/mrp_secondary_uom/static/description/6.png differ diff --git a/mrp_secondary_uom/static/description/Finished Products.png b/mrp_secondary_uom/static/description/Finished Products.png new file mode 100644 index 000000000..2db8a87ce Binary files /dev/null and b/mrp_secondary_uom/static/description/Finished Products.png differ diff --git a/mrp_secondary_uom/static/description/MRP Order.png b/mrp_secondary_uom/static/description/MRP Order.png new file mode 100644 index 000000000..283ed9a9c Binary files /dev/null and b/mrp_secondary_uom/static/description/MRP Order.png differ diff --git a/mrp_secondary_uom/static/description/banner.jpg b/mrp_secondary_uom/static/description/banner.jpg new file mode 100644 index 000000000..626395242 Binary files /dev/null and b/mrp_secondary_uom/static/description/banner.jpg differ diff --git a/mrp_secondary_uom/static/description/change.png b/mrp_secondary_uom/static/description/change.png new file mode 100644 index 000000000..5d44f1a06 Binary files /dev/null and b/mrp_secondary_uom/static/description/change.png differ diff --git a/mrp_secondary_uom/static/description/cybro_logo.png b/mrp_secondary_uom/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/mrp_secondary_uom/static/description/cybro_logo.png differ diff --git a/mrp_secondary_uom/static/description/icon.png b/mrp_secondary_uom/static/description/icon.png new file mode 100644 index 000000000..65c6a9f52 Binary files /dev/null and b/mrp_secondary_uom/static/description/icon.png differ diff --git a/mrp_secondary_uom/static/description/index.html b/mrp_secondary_uom/static/description/index.html new file mode 100644 index 000000000..65bd88804 --- /dev/null +++ b/mrp_secondary_uom/static/description/index.html @@ -0,0 +1,135 @@ +
    +
    +
    +

    MRP - Secondary UoM

    +

    Manage the Manufacturing process with secondary UoM

    +

    Cybrosys Technologies

    +
    +
    +

    Major Features:

    +
      +
    •   Allows to manage MRP with Secondary UoM.
    • +
    •    Products to Produce With Secondary UoM.
    • +
    •    Produced Products With Secondary UoM.
    • +
    +
    +
    +
    + +
    +
    +
    +

    +

    This module allows you to cover planning, ordering, stocks and the manufacturing with a Secondary + UoM. It handles the Products to Produce & Produced Products according to the production with Secondary UoM.

    +

    + +
    +
    +
    + +
    +
    +
    +

    +

    As shown here, When we create a MO with a Primary and Secondary Product Quantities and UOMs. + After saving, Order is in 'Confirmed' state. Same time we can see a record + created in 'Finished Products' with secondary UoM.

    +

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

    +

    We can change the Primary Quantity, Secondary Quantity and Secondary UoM at any time. There + will be an 'Update' Button to handle the same.

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

    +

    When we click on the 'Produce' button, The same window is appear with Secondary + Quantity and UoM.

    +

    If we Produce Partially or completely, It automatically calculate the Secondary quantity with same ratio.

    +

    +
    +
    +
    + +
    +
    +
    +

    +

    Update the Produced Products records.

    +

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

    Need Any Help?

    + +
    + + + + + + + diff --git a/mrp_secondary_uom/static/description/partial production.png b/mrp_secondary_uom/static/description/partial production.png new file mode 100644 index 000000000..80ff5e60b Binary files /dev/null and b/mrp_secondary_uom/static/description/partial production.png differ diff --git a/mrp_secondary_uom/static/description/update.png b/mrp_secondary_uom/static/description/update.png new file mode 100644 index 000000000..e70d17136 Binary files /dev/null and b/mrp_secondary_uom/static/description/update.png differ diff --git a/mrp_secondary_uom/views/mrp_sec_uom.xml b/mrp_secondary_uom/views/mrp_sec_uom.xml new file mode 100644 index 000000000..368ed1faf --- /dev/null +++ b/mrp_secondary_uom/views/mrp_sec_uom.xml @@ -0,0 +1,64 @@ + + + + + mrp.production.uom.form + mrp.production + + + + + + + + + + + + + + + + + + + + + MRP Product Produce + mrp.product.produce + + + + + + + + + + + + + + + + + + + Change Product Qty + change.production.qty + + + + + + + + + + \ No newline at end of file diff --git a/news_letter_name/__init__.py b/news_letter_name/__init__.py new file mode 100644 index 000000000..b0f26a9a6 --- /dev/null +++ b/news_letter_name/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers diff --git a/news_letter_name/__manifest__.py b/news_letter_name/__manifest__.py new file mode 100644 index 000000000..dfa17e31d --- /dev/null +++ b/news_letter_name/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Cybrosys Technologies Pvt. Ltd. +# Copyright (C) 2017-TODAY Cybrosys Technologies(). +# Author: Hilar AK() +# you can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# It is forbidden to publish, distribute, sublicense, or sell copies +# of the Software or modified copies of the Software. +# +# 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 +# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. +# If not, see . +# +############################################################################## + +{ + 'name': "News Letter Subscription With Name", + 'version': '10.0.1.0', + 'summary': """Odoo mailing list subscription With Subscriber Name""", + 'description': """Odoo mailing list subscription With Subscriber Name""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'website': "https://cybrosys.com", + 'category': 'Marketing', + 'depends': ['base', + 'website_mass_mailing', + 'mass_mailing', + ], + 'data': [ + 'views/templates.xml', + ], + 'demo': [], + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'application': False +} \ No newline at end of file diff --git a/news_letter_name/controllers/__init__.py b/news_letter_name/controllers/__init__.py new file mode 100644 index 000000000..b0f26a9a6 --- /dev/null +++ b/news_letter_name/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers diff --git a/news_letter_name/controllers/controllers.py b/news_letter_name/controllers/controllers.py new file mode 100644 index 000000000..a348b67b8 --- /dev/null +++ b/news_letter_name/controllers/controllers.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from odoo.addons.website_mass_mailing.controllers.main import MassMailController +from odoo.http import route, request + + +class MassMailController(MassMailController): + @route('/website_mass_mailing/subscribe', type='json', website=True, auth="public") + def subscribe(self, list_id, email, **post): + """ + Overrided function which treats the inputs when clicks on subscribe button. + :param list_id: + :param email: + :param post: Will contain the Name entered on Input box. + :return: + """ + Contacts = request.env['mail.mass_mailing.contact'].sudo() + name, email = Contacts.get_name_email(email) + + contact_ids = Contacts.search([ + ('list_id', '=', int(list_id)), + ('email', '=', email), + ], limit=1) + if not contact_ids: + # inline add_to_list as we've already called half of it + Contacts.create({'name': post.get('name') or name, 'email': email, 'list_id': int(list_id)}) + elif contact_ids.opt_out: + contact_ids.opt_out = False + # add email to session + request.session['mass_mailing_email'] = email + return True diff --git a/news_letter_name/security/ir.model.access.csv b/news_letter_name/security/ir.model.access.csv new file mode 100644 index 000000000..db8d0c6af --- /dev/null +++ b/news_letter_name/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_news_letter_name_news_letter_name,news_letter_name.news_letter_name,model_news_letter_name_news_letter_name,,1,0,0,0 \ No newline at end of file diff --git a/news_letter_name/static/description/banner.jpg b/news_letter_name/static/description/banner.jpg new file mode 100644 index 000000000..c63285f6d Binary files /dev/null and b/news_letter_name/static/description/banner.jpg differ diff --git a/news_letter_name/static/description/cybro_logo.png b/news_letter_name/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/news_letter_name/static/description/cybro_logo.png differ diff --git a/news_letter_name/static/description/dropped.png b/news_letter_name/static/description/dropped.png new file mode 100644 index 000000000..ec235075c Binary files /dev/null and b/news_letter_name/static/description/dropped.png differ diff --git a/news_letter_name/static/description/icon.png b/news_letter_name/static/description/icon.png new file mode 100644 index 000000000..e3768ea17 Binary files /dev/null and b/news_letter_name/static/description/icon.png differ diff --git a/news_letter_name/static/description/index.html b/news_letter_name/static/description/index.html new file mode 100644 index 000000000..83025e83e --- /dev/null +++ b/news_letter_name/static/description/index.html @@ -0,0 +1,124 @@ +
    +
    +

    News Letter Subscription With Name

    +

    Cybrosys Technologies

    +
    +
    + +
    +
    +

    Subscribe News letters by mentioning subscribers name

    +

    + Easily subscribers can add their name while doing news letters subscription on Odoo. +

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

    Need Any Help?

    + +
    + diff --git a/news_letter_name/static/description/nameonbackend.png b/news_letter_name/static/description/nameonbackend.png new file mode 100644 index 000000000..3d2bc012d Binary files /dev/null and b/news_letter_name/static/description/nameonbackend.png differ diff --git a/news_letter_name/static/description/snippet_subscribe.png b/news_letter_name/static/description/snippet_subscribe.png new file mode 100644 index 000000000..5c9997b61 Binary files /dev/null and b/news_letter_name/static/description/snippet_subscribe.png differ diff --git a/news_letter_name/static/description/subscribe.png b/news_letter_name/static/description/subscribe.png new file mode 100644 index 000000000..d317825e5 Binary files /dev/null and b/news_letter_name/static/description/subscribe.png differ diff --git a/news_letter_name/static/description/thanks.png b/news_letter_name/static/description/thanks.png new file mode 100644 index 000000000..1e0cca811 Binary files /dev/null and b/news_letter_name/static/description/thanks.png differ diff --git a/news_letter_name/static/src/js/news_letter_name.js b/news_letter_name/static/src/js/news_letter_name.js new file mode 100644 index 000000000..6873f623b --- /dev/null +++ b/news_letter_name/static/src/js/news_letter_name.js @@ -0,0 +1,36 @@ +odoo.define('news_letter_name.massmailextend', function (require) { +"use strict"; +var ajax = require('web.ajax'); +var utils = require('web.utils'); +var animation = require('web_editor.snippets.animation'); +require('web_editor.base'); +require('mass_mailing.website_integration'); +//updated onclick function to feed the name from news letter subscribe +animation.registry.subscribe.include({ + on_click: function () { + var self = this; + var $email = this.$target.find(".js_subscribe_email:visible"); + var $name = this.$target.find(".js_subscribe_name:visible"); + + if ($email.length && !$email.val().match(/.+@.+/)) { + this.$target.addClass('has-error'); + return false; + } + this.$target.removeClass('has-error'); + ajax.jsonRpc('/website_mass_mailing/subscribe', 'call', { + 'list_id': this.$target.data('list-id'), + 'email': $email.length ? $email.val() : false, + 'name': $name.length ? $name.val() : false, + }).then(function (subscribe) { + self.$target.find(".js_subscribe_email, .input-group-btn").addClass("hidden"); + self.$target.find(".js_subscribe_name, .input-group-btn").addClass("hidden"); + self.$target.find(".alert").removeClass("hidden"); + self.$target.find('input.js_subscribe_email').attr("disabled", subscribe ? "disabled" : false); + self.$target.find('input.js_subscribe_name').attr("disabled", subscribe ? "disabled" : false); + self.$target.attr("data-subscribe", subscribe ? 'on' : 'off'); + }); + }, + +}); + +}); \ No newline at end of file diff --git a/news_letter_name/views/templates.xml b/news_letter_name/views/templates.xml new file mode 100644 index 000000000..f55953cfd --- /dev/null +++ b/news_letter_name/views/templates.xml @@ -0,0 +1,17 @@ + + +