diff --git a/salon_management/__init__.py b/salon_management/__init__.py
new file mode 100644
index 000000000..dd2853e1a
--- /dev/null
+++ b/salon_management/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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 controllers
diff --git a/salon_management/__manifest__.py b/salon_management/__manifest__.py
new file mode 100644
index 000000000..20fb64a33
--- /dev/null
+++ b/salon_management/__manifest__.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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': 'Beauty Spa Management',
+ 'summary': """Beauty Parlour Management with Online Booking System""",
+ 'version': '10.0.1.0.0',
+ 'author': 'Cybrosys Techno Solutions',
+ 'website': "http://www.cybrosys.com",
+ 'company': 'Cybrosys Techno Solutions',
+ "category": "Industries",
+ 'depends': ['base', 'account', 'mail', 'website'],
+ 'data': ['views/salon_holiday.xml',
+ 'views/salon_data.xml',
+ 'views/salon_management_chair.xml',
+ 'views/salon_management_services.xml',
+ 'views/salon_order_view.xml',
+ 'views/salon_management_dashboard.xml',
+ 'views/booking_backend.xml',
+ 'views/salon_bookings.xml',
+ 'views/salon_email_template.xml',
+ 'views/salon_config.xml',
+ 'views/working_hours.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'demo': [
+ 'views/booking_demo.xml',
+ ],
+ 'images': ['static/description/banner.jpg'],
+ 'license': 'LGPL-3',
+ 'installable': True,
+ 'application': True,
+}
diff --git a/salon_management/controllers/__init__.py b/salon_management/controllers/__init__.py
new file mode 100644
index 000000000..b62b9e7f3
--- /dev/null
+++ b/salon_management/controllers/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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/salon_management/controllers/main.py b/salon_management/controllers/main.py
new file mode 100644
index 000000000..b51eec0a5
--- /dev/null
+++ b/salon_management/controllers/main.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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 json
+from datetime import datetime, date
+from odoo import http
+from odoo.http import request
+
+
+class SalonBookingWeb(http.Controller):
+
+ @http.route('/page/salon_details', csrf=False, type="http", methods=['POST', 'GET'], auth="public", website=True)
+ def salon_details(self, **kwargs):
+
+ name = kwargs['name']
+ date = kwargs['date']
+ time = kwargs['time']
+ phone = kwargs['phone']
+ email = kwargs['email']
+ chair = kwargs['chair']
+ j = 0
+ service_list = []
+ while(j < (int(kwargs['number']))):
+ item = "list_service["+str(j)+"][i]"
+ service_list.append(int(kwargs[item]))
+ j += 1
+ salon_service_obj = request.env['salon.service'].search([('id', 'in', service_list)])
+ dates_time = date+" "+time+":00"
+ date_and_time = datetime.strptime(dates_time, '%m/%d/%Y %H:%M:%S')
+ salon_booking = request.env['salon.booking']
+ booking_data = {
+ 'name': name,
+ 'phone': phone,
+ 'time': date_and_time,
+ 'email': email,
+ 'chair_id': chair,
+ 'services': [(6, 0, [x.id for x in salon_service_obj])],
+ }
+ salon_booking.create(booking_data)
+ return json.dumps({'result': True})
+
+ @http.route('/page/salon_check_date', type='json', auth="public", website=True)
+ def salon_check(self, **kwargs):
+ date_info = kwargs.get('check_date')
+ return date_info
+
+ @http.route('/page/salon_management.salon_booking_thank_you', type='http', auth="public", website=True)
+ def thank_you(self, **post):
+ return request.render('salon_management.salon_booking_thank_you', {})
+
+ @http.route('/page/salon_management.salon_booking_form', type='http', auth="public", website=True)
+ def chair_info(self, **post):
+
+ salon_service_obj = request.env['salon.service'].search([])
+ salon_working_hours_obj = request.env['salon.working.hours'].search([])
+ salon_holiday_obj = request.env['salon.holiday'].search([('holiday', '=', True)])
+ date_check = date.today()
+ if 'x' in post.keys():
+ date_check = post['x']
+ chair_obj = request.env['salon.chair'].search([('active_booking_chairs', '=', True)])
+ order_obj = request.env['salon.order'].search([('chair_id.active_booking_chairs', '=', True),
+ ('stage_id', 'in', [1, 2, 3])])
+ date_check = str(date_check)
+ order_obj = order_obj.search([('start_date_only', '=', date_check)])
+ return request.render('salon_management.salon_booking_form',
+ {'chair_details': chair_obj, 'order_details': order_obj,
+ 'salon_services': salon_service_obj, 'date_search': date_check,
+ 'holiday': salon_holiday_obj,
+ 'working_time': salon_working_hours_obj})
\ No newline at end of file
diff --git a/salon_management/models/__init__.py b/salon_management/models/__init__.py
new file mode 100644
index 000000000..294035f3d
--- /dev/null
+++ b/salon_management/models/__init__.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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 salon_management
+import salon_booking
+import salon_config
+
diff --git a/salon_management/models/salon_booking.py b/salon_management/models/salon_booking.py
new file mode 100644
index 000000000..db0c4a9b8
--- /dev/null
+++ b/salon_management/models/salon_booking.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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
+
+
+class SalonBookingBackend(models.Model):
+ _name = 'salon.booking'
+
+ name = fields.Char(string="Name")
+ state = fields.Selection([('draft', 'Draft'), ('approved', 'Approved'), ('rejected', 'Rejected')], default="draft")
+ time = fields.Datetime(string="Date")
+ phone = fields.Char(string="Phone")
+ email = fields.Char(string="E-Mail")
+ services = fields.Many2many('salon.service', string="Services")
+ chair_id = fields.Many2one('salon.chair', string="Chair")
+ company_id = fields.Many2one('res.company', 'Company',
+ default=lambda self: self.env['res.company'].browse(1))
+ lang = fields.Many2one('res.lang', 'Language',
+ default=lambda self: self.env['res.lang'].browse(1))
+
+ def all_salon_orders(self):
+ if self.time:
+ date_only = str(self.time)[0:10]
+ else:
+ date_only = date.today()
+ all_salon_service_obj = self.env['salon.order'].search([('chair_id', '=', self.chair_id.id),
+ ('start_date_only', '=', date_only)])
+ self.filtered_orders = [(6, 0, [x.id for x in all_salon_service_obj])]
+
+ filtered_orders = fields.Many2many('salon.order', string="Salon Orders", compute="all_salon_orders")
+
+ @api.multi
+ def booking_approve(self):
+ salon_order_obj = self.env['salon.order']
+ salon_service_obj = self.env['salon.order.lines']
+ order_data ={
+ 'customer_name': self.name,
+ 'chair_id': self.chair_id.id,
+ 'start_time': self.time,
+ 'date': date.today(),
+ 'stage_id': 1,
+ 'booking_identifier': True,
+ }
+ order = salon_order_obj.create(order_data)
+ for records in self.services:
+ service_data = {
+ 'service_id': records.id,
+ 'time_taken': records.time_taken,
+ 'price': records.price,
+ 'price_subtotal': records.price,
+ 'salon_order': order.id,
+ }
+ salon_service_obj.create(service_data)
+ template = self.env.ref('salon_management.salon_email_template_approved')
+ self.env['mail.template'].browse(template.id).send_mail(self.id)
+ self.state = "approved"
+
+ @api.multi
+ def booking_reject(self):
+ template = self.env.ref('salon_management.salon_email_template_rejected')
+ self.env['mail.template'].browse(template.id).send_mail(self.id)
+ self.state = "rejected"
+
diff --git a/salon_management/models/salon_config.py b/salon_management/models/salon_config.py
new file mode 100644
index 000000000..1e87fbb91
--- /dev/null
+++ b/salon_management/models/salon_config.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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 SalonWorkingHours(models.Model):
+ _name = 'salon.working.hours'
+
+ name = fields.Char(string="Name")
+ from_time = fields.Float(string="Starting Time")
+ to_time = fields.Float(string="Closing Time")
+
+
+class SalonHoliday(models.Model):
+ _name = 'salon.holiday'
+
+ name = fields.Char(string="Name")
+ holiday = fields.Boolean(string="Holiday")
+
+
+class WorkshopSetting(models.Model):
+ _name = "salon.config.settings"
+
+ @api.model
+ def booking_chairs(self):
+ return self.env['salon.chair'].search([('active_booking_chairs', '=', True)])
+
+ @api.model
+ def holidays(self):
+ return self.env['salon.holiday'].search([('holiday', '=', True)])
+
+ salon_booking_chairs = fields.Many2many('salon.chair', string="Booking Chairs", default=booking_chairs)
+ salon_holidays = fields.Many2many('salon.holiday', string="Holidays", default=holidays)
+
+ @api.multi
+ def execute(self):
+ salon_chair_obj = self.env['salon.chair'].search([])
+ book_chair = []
+ for chairs in self.salon_booking_chairs:
+ book_chair.append(chairs.id)
+ for records in salon_chair_obj:
+ if records.id in book_chair:
+ records.active_booking_chairs = True
+ else:
+ records.active_booking_chairs = False
+
+ salon_holiday_obj = self.env['salon.holiday'].search([])
+ holiday = []
+ for days in self.salon_holidays:
+ holiday.append(days.id)
+ for records in salon_holiday_obj:
+ if records.id in holiday:
+ records.holiday = True
+ else:
+ records.holiday = False
diff --git a/salon_management/models/salon_management.py b/salon_management/models/salon_management.py
new file mode 100644
index 000000000..e0430e792
--- /dev/null
+++ b/salon_management/models/salon_management.py
@@ -0,0 +1,418 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2017-TODAY Cybrosys Technologies().
+# Author: Avinash Nk()
+# 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, datetime, timedelta
+from odoo import models, fields, api
+from odoo.tools.translate import _
+from odoo.exceptions import UserError, ValidationError
+
+
+class PartnerSalon(models.Model):
+ _inherit = 'res.partner'
+
+ partner_salon = fields.Boolean(string="Is a Salon Partner")
+
+
+class SequenceUpdaterSalon(models.Model):
+ _name = 'salon.sequence.updater'
+
+ sequence_salon = fields.Char(string="Salon Sequence")
+
+
+class UserSalon(models.Model):
+ _inherit = 'res.users'
+
+ user_salon_active = fields.Boolean(string="Active Salon Users")
+
+
+class SalonChair(models.Model):
+ _name = 'salon.chair'
+
+ name = fields.Char(string="Chair", required=True,
+ default=lambda self: self.env['salon.sequence.updater'].browse(1).sequence_salon or "Chair-1")
+ number_of_orders = fields.Integer(string="No.of Orders")
+ collection_today = fields.Float(string="Today's Collection")
+ user_of_chair = fields.Many2one('res.users', string="User", readonly=True,
+ help="You can select the user from the Users Tab."
+ "Last user from the Users Tab will be selected as the Current User.")
+ date = fields.Datetime(string="Date", readonly=True)
+ user_line = fields.One2many('salon.chair.user', 'salon_chair', string="Users")
+ total_time_taken_chair = fields.Float(string="Time Reserved(Hrs)")
+ active_booking_chairs = fields.Boolean(string="Active booking chairs")
+ chair_created_user = fields.Integer(string="Salon Chair Created User",
+ default=lambda self: self._uid)
+
+ @api.model
+ def create(self, cr):
+ sequence_code = 'chair.sequence'
+ sequence_number = self.env['ir.sequence'].next_by_code(sequence_code)
+ self.env['salon.sequence.updater'].browse(1).write({'sequence_salon': sequence_number})
+ if 'user_line' in cr.keys():
+ if cr['user_line']:
+ date_changer = []
+ for elements in cr['user_line']:
+ date_changer.append(elements[2]['start_date'])
+ number = 0
+ for elements in cr['user_line']:
+ number += 1
+ if len(cr['user_line']) == number:
+ break
+ elements[2]['end_date'] = date_changer[number]
+ cr['user_of_chair'] = cr['user_line'][len((cr['user_line']))-1][2]['user_id']
+ cr['date'] = cr['user_line'][len((cr['user_line']))-1][2]['start_date']
+ return super(SalonChair, self).create(cr)
+
+ @api.multi
+ def write(self, cr):
+ if 'user_line' in cr.keys():
+ if cr['user_line']:
+ date_changer = []
+ for elements in cr['user_line']:
+ if elements[1] is False:
+ date_changer.append(elements[2]['start_date'])
+ number = 0
+ num = 0
+ for records in self.user_line:
+ if records.end_date is False:
+ records.end_date = date_changer[0]
+ for elements in cr['user_line']:
+ number += 1
+ if elements[2] is not False:
+ num += 1
+ if len(cr['user_line']) == number:
+ break
+ elements[2]['end_date'] = date_changer[num]
+ cr['user_of_chair'] = cr['user_line'][len((cr['user_line']))-1][2]['user_id']
+ cr['date'] = cr['user_line'][len((cr['user_line']))-1][2]['start_date']
+ return super(SalonChair, self).write(cr)
+
+ def collection_today_updater(self, cr, uid, context=None):
+ salon_chair = self.pool.get('salon.chair')
+ for values in self.search(cr, uid, []):
+ chair_obj = salon_chair.browse(cr, uid, values, context=context)
+ invoiced_records = chair_obj.env['salon.order'].search([('stage_id', 'in', [3, 4]),
+ ('chair_id', '=', chair_obj.id)])
+ 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
+ chair_obj.collection_today = total
+
+
+class SalonChairUserLines(models.Model):
+ _name = 'salon.chair.user'
+
+ read_only_checker = fields.Boolean(string="Checker", default=False)
+ user_id = fields.Many2one('res.users', string="User", required=True)
+ start_date = fields.Datetime(string="Start Date", default=date.today(), required=True)
+ end_date = fields.Datetime(string="End Date", readonly=True, default=False)
+ salon_chair = fields.Many2one('salon.chair', string="Chair", required=True, ondelete='cascade',
+ index=True, copy=False)
+
+ @api.model
+ def create(self, cr):
+ chairs = self.env['salon.chair'].search([])
+ all_active_users = []
+ for records in chairs:
+ if records.user_of_chair:
+ all_active_users.append(records.user_of_chair.id)
+ records.user_of_chair.write({'user_salon_active': True})
+ users = self.env['res.users'].search([('id', 'not in', all_active_users)])
+ for records in users:
+ records.write({'user_salon_active': False})
+ cr['read_only_checker'] = True
+ return super(SalonChairUserLines, self).create(cr)
+
+
+class SalonOrder(models.Model):
+ _name = 'salon.order'
+
+ @api.depends('order_line.price_subtotal')
+ def sub_total_update(self):
+ for order in self:
+ amount_untaxed = 0.0
+ for line in order.order_line:
+ amount_untaxed += line.price_subtotal
+ order.price_subtotal = amount_untaxed
+ for order in self:
+ total_time_taken = 0.0
+ for line in order.order_line:
+ total_time_taken += line.time_taken
+ order.time_taken_total = total_time_taken
+ time_takes = total_time_taken
+ hours = int(time_takes)
+ minutes = (time_takes - hours)*60
+ start_time_store = datetime.strptime(self.start_time, "%Y-%m-%d %H:%M:%S")
+ self.write({'end_time': start_time_store + timedelta(hours=hours, minutes=minutes)})
+ if self.end_time:
+ self.write({'end_time_only': str(self.end_time)[11:16]})
+ if self.start_time:
+ salon_start_time = self.start_time
+ salon_start_time_date = salon_start_time[0:10]
+ self.write({'start_date_only': salon_start_time_date})
+ self.write({'start_time_only': str(self.start_time)[11:16]})
+
+ name = fields.Char(string='Salon', required=True, copy=False, readonly=True,
+ default='Draft Salon Order')
+ start_time = fields.Datetime(string="Start time", default=date.today(), required=True)
+ end_time = fields.Datetime(string="End time")
+ date = fields.Datetime(string="Date", required=True, default=date.today())
+ color = fields.Integer(string="Colour", default=6)
+ partner_id = fields.Many2one('res.partner', string="Customer", required=False,
+ help="If the customer is a regular customer, "
+ "then you can add the customer in your database")
+ customer_name = fields.Char(string="Name", required=True)
+ amount = fields.Float(string="Amount")
+ chair_id = fields.Many2one('salon.chair', string="Chair", required=True)
+ price_subtotal = fields.Float(string='Total', compute='sub_total_update', readonly=True, store=True)
+ time_taken_total = fields.Float(string="Total time taken")
+ note = fields.Text('Terms and conditions')
+ order_line = fields.One2many('salon.order.lines', 'salon_order', string="Order Lines")
+ stage_id = fields.Many2one('salon.stages', string="Stages", default=1)
+ inv_stage_identifier = fields.Boolean(string="Stage Identifier")
+ invoice_number = fields.Integer(string="Invoice Number")
+ validation_controller = fields.Boolean(string="Validation controller", default=False)
+ start_date_only = fields.Date(string="Date Only")
+ booking_identifier = fields.Boolean(string="Booking Identifier")
+ start_time_only = fields.Char(string="Start Time Only")
+ end_time_only = fields.Char(string="End Time Only")
+ chair_user = fields.Many2one('res.users', string="Chair User")
+ salon_order_created_user = fields.Integer(string="Salon Order Created User",
+ default=lambda self: self._uid)
+
+ @api.onchange('start_time')
+ def start_date_change(self):
+ salon_start_time = self.start_time
+ salon_start_time_date = salon_start_time[0:10]
+ self.write({'start_date_only': salon_start_time_date})
+
+ @api.multi
+ def action_view_invoice_salon(self):
+ 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': action.type,
+ 'views': [[form_view_id, 'form'], [list_view_id, 'tree'], [False, 'graph'], [False, 'kanban'],
+ [False, 'calendar'], [False, 'pivot']],
+ 'target': action.target,
+ 'context': action.context,
+ 'res_model': action.res_model,
+ 'res_id': self.invoice_number,
+ }
+ return result
+
+ @api.multi
+ def write(self, cr):
+ if 'stage_id' in cr.keys():
+ if self.stage_id.id == 3 and cr['stage_id'] != 4:
+ raise ValidationError(_("You can't perform that move !"))
+ if self.stage_id.id == 1 and cr['stage_id'] not in [2, 5]:
+ raise ValidationError(_("You can't perform that move!"))
+ if self.stage_id.id == 4:
+ raise ValidationError(_("You can't move a salon order from closed stage !"))
+ if self.stage_id.id == 5:
+ raise ValidationError(_("You can't move a salon order from cancel stage !"))
+ if self.stage_id.id == 2 and (cr['stage_id'] == 1 or cr['stage_id'] == 4):
+ raise ValidationError(_("You can't perform that move !"))
+ if self.stage_id.id == 2 and cr['stage_id'] == 3 and self.inv_stage_identifier is False:
+ self.salon_invoice_create()
+ if 'stage_id' in cr.keys() and self.name == "Draft Salon Order":
+ if cr['stage_id'] == 2:
+ self.salon_confirm()
+ return super(SalonOrder, self).write(cr)
+
+ @api.multi
+ def salon_confirm(self):
+ sequence_code = 'salon.order.sequence'
+ order_date = self.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)
+ if self.partner_id:
+ self.partner_id.partner_salon = True
+ self.stage_id = 2
+ self.chair_id.number_of_orders = len(self.env['salon.order'].search([("chair_id", "=", self.chair_id.id),
+ ("stage_id", "in", [2, 3])]))
+ self.chair_id.total_time_taken_chair = self.chair_id.total_time_taken_chair + self.time_taken_total
+ self.chair_user = self.chair_id.user_of_chair
+
+ @api.multi
+ def salon_validate(self):
+ self.validation_controller = True
+
+ @api.multi
+ def salon_close(self):
+ self.stage_id = 4
+ self.chair_id.number_of_orders = len(self.env['salon.order'].search([("chair_id", "=", self.chair_id.id),
+ ("stage_id", "in", [2, 3])]))
+ self.chair_id.total_time_taken_chair = self.chair_id.total_time_taken_chair - self.time_taken_total
+
+ @api.multi
+ def salon_cancel(self):
+ self.stage_id = 5
+ self.chair_id.number_of_orders = len(self.env['salon.order'].search([("chair_id", "=", self.chair_id.id),
+ ("stage_id", "in", [2, 3])]))
+ if self.stage_id.id != 1:
+ self.chair_id.total_time_taken_chair = self.chair_id.total_time_taken_chair - self.time_taken_total
+
+ @api.multi
+ def button_total_update(self):
+ for order in self:
+ amount_untaxed = 0.0
+ for line in order.order_line:
+ amount_untaxed += line.price_subtotal
+ order.price_subtotal = amount_untaxed
+
+ @api.onchange('chair_id')
+ def onchange_chair(self):
+ if 'active_id' in self._context.keys():
+ self.chair_id = self._context['active_id']
+
+ @api.multi
+ def salon_invoice_create(self):
+ inv_obj = self.env['account.invoice']
+ inv_line_obj = self.env['account.invoice.line']
+ if self.partner_id:
+ supplier = self.partner_id
+ else:
+ supplier = self.partner_id.search([("name", "=", "Salon Default Customer")])
+ company_id = self.env['res.users'].browse(1).company_id
+ currency_salon = company_id.currency_id.id
+
+ inv_data = {
+ 'name': supplier.name,
+ 'reference': supplier.name,
+ 'account_id': supplier.property_account_payable_id.id,
+ 'partner_id': supplier.id,
+ 'currency_id': currency_salon,
+ 'journal_id': 1,
+ 'origin': self.name,
+ 'company_id': company_id.id,
+ }
+ inv_id = inv_obj.create(inv_data)
+ self.invoice_number = inv_id
+ product_id = self.env['product.product'].search([("name", "=", "Salon Service")])
+ for records in self.order_line:
+ 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': records.service_id.name,
+ 'account_id': income_account,
+ 'price_unit': records.price,
+ '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'}
+ self.inv_stage_identifier = True
+ self.stage_id = 3
+ invoiced_records = self.env['salon.order'].search([('stage_id', 'in', [3, 4]),
+ ('chair_id', '=', self.chair_id.id)])
+ 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
+ self.chair_id.collection_today = total
+ self.chair_id.number_of_orders = len(self.env['salon.order'].search([("chair_id", "=", self.chair_id.id),
+ ("stage_id", "in", [2, 3])]))
+ return result
+
+ @api.multi
+ def unlink(self):
+ for order in self:
+ if order.stage_id.id == 3 or order.stage_id.id == 4:
+ raise UserError(_("You can't delete an invoiced salon order!"))
+ return super(SalonOrder, self).unlink()
+
+
+class SalonServices(models.Model):
+ _name = 'salon.service'
+
+ name = fields.Char(string="Name")
+ price = fields.Float(string="Price")
+ time_taken = fields.Float(string="Time Taken", help="Approximate time taken for this service in Hours")
+
+
+class SalonOrderLine(models.Model):
+ _name = 'salon.order.lines'
+
+ service_id = fields.Many2one('salon.service', string="Service")
+ price = fields.Float(string="Price")
+ salon_order = fields.Many2one('salon.order', string="Salon Order", required=True, ondelete='cascade',
+ index=True, copy=False)
+ price_subtotal = fields.Float(string='Subtotal')
+ time_taken = fields.Float(string='Time Taken')
+
+ @api.onchange('service_id')
+ def onchange_service(self):
+ self.price = self.service_id.price
+ self.price_subtotal = self.service_id.price
+ self.time_taken = self.service_id.time_taken
+
+ @api.onchange('price')
+ def onchange_price(self):
+ self.price_subtotal = self.price
+
+ @api.onchange('price_subtotal')
+ def onchange_subtotal(self):
+ self.price = self.price_subtotal
+
+
+class SalonStages(models.Model):
+ _name = 'salon.stages'
+
+ name = fields.Char(string="Name", required=True, translate=True)
diff --git a/salon_management/security/ir.model.access.csv b/salon_management/security/ir.model.access.csv
new file mode 100644
index 000000000..9535c0fd6
--- /dev/null
+++ b/salon_management/security/ir.model.access.csv
@@ -0,0 +1,20 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+view_salon_order,view.salon.order,model_salon_order,base.group_user,1,1,1,1
+view_salon_order_lines,view.salon.order.lines,model_salon_order_lines,base.group_user,1,1,1,1
+view_salon_stages,view.salon.stages,model_salon_stages,base.group_user,1,1,1,1
+view_salon_chair,view.salon.chair,model_salon_chair,base.group_user,1,1,1,1
+view_salon_service,view.salon.service,model_salon_service,base.group_user,1,1,1,1
+
+view_salon_order3,view.salon.order3,model_salon_order,base.group_public,1,1,1,1
+view_salon_order_lines3,view.salon.order3.lines,model_salon_order_lines,base.group_public,1,1,1,1
+view_salon_stages3,view.salon.stages3,model_salon_stages,base.group_public,1,1,1,1
+view_salon_chair3,view.salon.chair3,model_salon_chair,base.group_public,1,1,1,1
+view_salon_service3,view.salon.service3,model_salon_service,base.group_public,1,1,1,1
+view_salon_booking3,view.salon.booking3,model_salon_booking,base.group_public,1,1,1,1
+view_salon_working_hours3,view.salon.working.hours3,model_salon_working_hours,base.group_public,1,1,1,1
+view_salon_holiday3,view.salon.holiday3,model_salon_holiday,base.group_public,1,1,1,1
+view_salon_config_settings3,view.salon.config.settings3,model_salon_config_settings,base.group_public,1,1,1,1
+view_res_partner3,view.res.partner3,model_res_partner,base.group_public,1,1,1,1
+view_res_users3,view.res.users3,model_res_users,base.group_public,1,1,1,1
+view_salon_chair_user3,view.salon.chair.user3,model_salon_chair_user,base.group_public,1,1,1,1
+view_salon_sequence_updater3,view.salon.sequence.updater3,model_salon_sequence_updater,base.group_public,1,1,1,1
\ No newline at end of file
diff --git a/salon_management/static/description/banner.jpg b/salon_management/static/description/banner.jpg
new file mode 100644
index 000000000..9cdd77b3b
Binary files /dev/null and b/salon_management/static/description/banner.jpg differ
diff --git a/salon_management/static/description/cybro_logo.png b/salon_management/static/description/cybro_logo.png
new file mode 100644
index 000000000..bb309114c
Binary files /dev/null and b/salon_management/static/description/cybro_logo.png differ
diff --git a/salon_management/static/description/icon.png b/salon_management/static/description/icon.png
new file mode 100644
index 000000000..ddb8bedeb
Binary files /dev/null and b/salon_management/static/description/icon.png differ
diff --git a/salon_management/static/description/index.html b/salon_management/static/description/index.html
new file mode 100644
index 000000000..945f09292
--- /dev/null
+++ b/salon_management/static/description/index.html
@@ -0,0 +1,278 @@
+
+
+
Beauty Spa Management
+
This Module is for Managing the Process's in a Spa
☑Customer Can view the Available chairs and order details
+
☑Different access levels for Users and Administrator
+
☑Track the chair user by date
+
+
+
+
+
+
+
+
+
+ This Spa management system developed by Cybrosys Techno Solutions helps
+ your customers to do the online booking for using the service. This module
+ integrates with other Odoo modules like accounting and website.
+
+
Another advantage of having this Spa management system is your customers
+ who have done the online booking will get the booking information via email.
+ By using an app like this, you can enhance your business.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Go to 'Salon Menu'
+
+ 'Salon Menu' will direct you to the 'Dashboard' of the Salon.
+
+
+ *Note : It will be shown as empty(False) if you have not created chairs
+
+ Dashboard view is shown in the above image. Your customers can book
+ the service in two ways, direct booking and online booking. The pink
+ color chairs are the only ones available for online booking and blue
+ chairs for direct booking.
+
In Dashboard, you get the daily collection of that chair
+ and also the customer will be able to know when will be the chair free,
+ in case if that chair is currently in use. Also you can see the active
+ orders of that chair and if you click on it, that will directly take
+ you to the active orders of that chair.
+
If you want to change the settings of chair, you can just
+ click the settings button in the dashboard.
+
+
+
+
+
+
+
+
+ Sub Menu : Salon -> Chair
+
Here you can create and edit details of each chair.
+ You can assign a user to the chair by adding new user to the users
+ tab in the form view of chair(Check the image shown below).
+ The last added user will be turned to the current user of the chair.
+ Using this tab, you can track which user is active on the Chair on a
+ particular date or time.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sub Menu : Salon -> Services
+
+ List of services provided by the Spa. You can create and edit services here.
+
+
+
+
+
+
+
+
+ Sub Menu : Salon -> Salon Orders
+
+
+ Here you have all the orders in the Spa.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form view of the salon order is shown in the image.
+ You will get the corresponding invoice details of the
+ order by clicking the Invoice button in the upper right
+ side of the form view.
+
+
+
+
+
+
+
+
+
+ Sub Menu : Salon -> Bookings
+
+ Here you can see all the online bookings.
+ You can either approve a booking or reject a booking.
+ In both cases the notification is send to the customer mail address.
+ The approved bookings will be changed to salon orders.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form View of Booking
+
+ Here you can see all the salon orders on the corresponding date.
+ After checking the time available,
+ you can decide to approve/reject the booking accordingly.
+
+
+
+
+
+
+
+
+
+
+
+ Sub Menu : Salon -> Settings
+
+ Here you can assign the chairs for booking purpose.
+ Only the assigned chairs can be booked by a customer through online.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ☛ Online Booking Form
+
+
+
+
+
+
+
+
+
+
+ Here the customer can fill the details. and send the form.
+
+
+
+
+
+
+
+ ☛ Online Booking Chair Details
+
+
+
+
+
+
+
+
+
+
+ Here the customer can check the availability of the chair by date.
+
+
+
+
+
+
You Looking for a free Documentation of this Application.?