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

+

Author : Cybrosys Techno Solutions, www.cybrosys.com

+
+

Major Features

+
    +
  • Online Booking Facility
  • +
  • Accounting Facility
  • +
  • Customer Notification Through Mail
  • +
  • User Interactive Dashboard
  • +
  • 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.?

+

Give a Request Mail to:    odoo@cybrosys.com

+
+ +
+

Need Any Help?

+ +
+ + diff --git a/salon_management/static/description/screenshot_salon_ services.png b/salon_management/static/description/screenshot_salon_ services.png new file mode 100644 index 000000000..1ea1aa39d Binary files /dev/null and b/salon_management/static/description/screenshot_salon_ services.png differ diff --git a/salon_management/static/description/screenshot_salon_booking_forms.png b/salon_management/static/description/screenshot_salon_booking_forms.png new file mode 100644 index 000000000..f7583ed91 Binary files /dev/null and b/salon_management/static/description/screenshot_salon_booking_forms.png differ diff --git a/salon_management/static/description/screenshot_salon_booking_tree.png b/salon_management/static/description/screenshot_salon_booking_tree.png new file mode 100644 index 000000000..1de327a64 Binary files /dev/null and b/salon_management/static/description/screenshot_salon_booking_tree.png differ diff --git a/salon_management/static/description/screenshot_salon_chair.png b/salon_management/static/description/screenshot_salon_chair.png new file mode 100644 index 000000000..82fe9702c Binary files /dev/null and b/salon_management/static/description/screenshot_salon_chair.png differ diff --git a/salon_management/static/description/screenshot_salon_dashboard.png b/salon_management/static/description/screenshot_salon_dashboard.png new file mode 100644 index 000000000..951c455e7 Binary files /dev/null and b/salon_management/static/description/screenshot_salon_dashboard.png differ diff --git a/salon_management/static/description/screenshot_salon_online_1.png b/salon_management/static/description/screenshot_salon_online_1.png new file mode 100644 index 000000000..1a27d2054 Binary files /dev/null and b/salon_management/static/description/screenshot_salon_online_1.png differ diff --git a/salon_management/static/description/screenshot_salon_online_2.png b/salon_management/static/description/screenshot_salon_online_2.png new file mode 100644 index 000000000..8a41e490d Binary files /dev/null and b/salon_management/static/description/screenshot_salon_online_2.png differ diff --git a/salon_management/static/description/screenshot_salon_order_form.png b/salon_management/static/description/screenshot_salon_order_form.png new file mode 100644 index 000000000..cae0f546c Binary files /dev/null and b/salon_management/static/description/screenshot_salon_order_form.png differ diff --git a/salon_management/static/description/screenshot_salon_order_kanban.png b/salon_management/static/description/screenshot_salon_order_kanban.png new file mode 100644 index 000000000..55a05dc6d Binary files /dev/null and b/salon_management/static/description/screenshot_salon_order_kanban.png differ diff --git a/salon_management/static/description/screenshot_salon_settings.png b/salon_management/static/description/screenshot_salon_settings.png new file mode 100644 index 000000000..3975cf769 Binary files /dev/null and b/salon_management/static/description/screenshot_salon_settings.png differ diff --git a/salon_management/static/src/css/salon_dashboard.css b/salon_management/static/src/css/salon_dashboard.css new file mode 100644 index 000000000..6f57a3d56 --- /dev/null +++ b/salon_management/static/src/css/salon_dashboard.css @@ -0,0 +1,57 @@ +.style_chair{ + text-align: center; + color: black; + font-size: 21px; + background: #337ab7; +} +.style_chair_booking{ + text-align: center; + color: black; + font-size: 21px; + background: #a52694; +} +.style_collection{ + color: black !important; + font-size: 12px; + text-align: center; + background: #337ab7 !important; + padding: 2px 0px 2px 3px; +} +.style_collection_booking{ + color: black !important; + font-size: 12px; + text-align: center; + background: #a52694 !important; + padding: 2px 0px 2px 3px; +} +.no_of_people{ + text-align: center; + font-size: 60px; + margin: 0px; + background: #337ab7; + color: white; + border-bottom: 1px solid #fff; + border-top: 1px solid #fff; +} +.no_of_people_booking{ + text-align: center; + font-size: 60px; + margin: 0px; + background: #a52694; + color: white; + border-bottom: 1px solid #fff; + border-top: 1px solid #fff; +} +.button_background{ + background-color: Transparent; + border: transparent; +} + +.chair_box_website{ + text-align: center; + border: 1px solid #666; + padding: 10px 15px; + box-shadow: 7px 8px 5px #888888; + background-color: #337ab7; + color: #fff; +} diff --git a/salon_management/static/src/js/salon_booking.js b/salon_management/static/src/js/salon_booking.js new file mode 100644 index 000000000..9c4bc4911 --- /dev/null +++ b/salon_management/static/src/js/salon_booking.js @@ -0,0 +1,74 @@ +odoo.define('salon_management.website_salon_booking_system', function (require) { +'use strict'; +var ajax = require('web.ajax'); +var base = require('web_editor.base'); +var core = require('web.core'); +var _t = core._t; +$(document).on('click',"#submit_button",function() { + var name = $( "#name" ).val(); + var date = $( "#date" ).val(); + var time = $( "#time" ).val(); + var phone = $( "#phone" ).val(); + var email = $( "#email" ).val(); + var service = $( "#service" ).val(); + var chair = $( "#chair" ).val(); + var list_service = []; + var number = service.length + for (var i=0; i<(service.length); i++){ + var k = {i : service[i]} + list_service.push(k) + } + var time_left_char = time.substring(0, 2) + var time_right_char = time.substring(3, 5) + var time_separator = time.substring(2,3) + if(date != ""){ + if (isNaN(time_left_char) || isNaN(time_right_char) || time_separator != ":"){ + if(time != ""){ + alert("Select a valid Time") + } + } + else{ + var time_left = parseInt(time_left_char) + var time_right = parseInt(time_right_char) + if ((time_left < 24) && (time_right < 60) && (time_left >= 0) && (time_right >= 0)){ + if (name != "" && phone != "" && email != "" && service != "" && chair != ""){ + var booking_record = {'name': name, 'date': date, 'time': time, 'phone': phone, + 'email': email, service, 'list_service':list_service,'chair': chair,'number': number } + $.ajax({ + url: "/page/salon_details", + method: "POST", + dataType: "json", + data: booking_record, + success: function( data ) { + window.location.href = "/page/salon_management.salon_booking_thank_you"; + }, + error: function (error) { + alert('error: ' + error); + } + }); + } + else{ + alert("Fill all the required fields") + } + } + else { + alert("Select a valid time") + } + } + } +}); +$(document).on('click',"#check_button",function() { + var check_date = $( "#check_date" ).val(); + if (check_date != "") + { + var salon_check_date = ajax.jsonRpc("/page/salon_check_date", 'call', {'check_date':check_date }) + .then(function(date_info){ + window.location= "/page/salon_management.salon_booking_form?x=" + date_info + }) + } + else + { + alert("Fill the Field") + } +}); +}); \ No newline at end of file diff --git a/salon_management/static/src/less/salon_dashboard.less b/salon_management/static/src/less/salon_dashboard.less new file mode 100644 index 000000000..cb2db4c9a --- /dev/null +++ b/salon_management/static/src/less/salon_dashboard.less @@ -0,0 +1,16 @@ +@dashboard-bg-color: white; + +.o_kanban_view.o_kanban_dashboard.o_salon_kanban { + @sale-table-spacing: 10px; + + .o_kanban_record { + min-height: 120px; + max-width: 180px !important; + box-shadow: 0px 0px 1px 3px #000 !important; + @media (min-width: @screen-sm-min) { + min-width: 20px; + + } + } + +} \ No newline at end of file diff --git a/salon_management/views/booking_backend.xml b/salon_management/views/booking_backend.xml new file mode 100644 index 000000000..3dc1b74f9 --- /dev/null +++ b/salon_management/views/booking_backend.xml @@ -0,0 +1,61 @@ + + + + + salon_booking_form.form + salon.booking + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + salon_booking_tree.tree + salon.booking + + + + + + + + + + + + Salon Bookings + salon.booking + form + tree,form + + + +
+
\ No newline at end of file diff --git a/salon_management/views/booking_demo.xml b/salon_management/views/booking_demo.xml new file mode 100644 index 000000000..19654cea6 --- /dev/null +++ b/salon_management/views/booking_demo.xml @@ -0,0 +1,12 @@ + + + + + Bookings + /page/salon_management.salon_booking_form + + 80 + + + + \ No newline at end of file diff --git a/salon_management/views/salon_bookings.xml b/salon_management/views/salon_bookings.xml new file mode 100644 index 000000000..65f4db701 --- /dev/null +++ b/salon_management/views/salon_bookings.xml @@ -0,0 +1,234 @@ + + + + + Bookings + /page/salon_management.salon_booking_form + + 80 + + + + + + + \ No newline at end of file diff --git a/salon_management/views/salon_config.xml b/salon_management/views/salon_config.xml new file mode 100644 index 000000000..7aa9b21b4 --- /dev/null +++ b/salon_management/views/salon_config.xml @@ -0,0 +1,37 @@ + + + + salon settings + salon.config.settings + +
+
+
+
+ + + + + + +
+
+
+
+ + + Settings + ir.actions.act_window + salon.config.settings + + form + inline + + + + +
\ No newline at end of file diff --git a/salon_management/views/salon_data.xml b/salon_management/views/salon_data.xml new file mode 100644 index 000000000..807ad2fcf --- /dev/null +++ b/salon_management/views/salon_data.xml @@ -0,0 +1,65 @@ + + + + + user_salon_boolean.view + res.users + + + + + + + + + salon_stages_form.form + salon.stages + +
+ +

+ +

+
+
+
+
+ + Draft + + + + Open + + + + Invoiced + + + + Closed + + + + Cancelled + + + + Salon Default Customer + 1 + + + + Salon Service + 1 + service + + +
+ + + Salon Sequence Updater + Chair-1 + + +
diff --git a/salon_management/views/salon_email_template.xml b/salon_management/views/salon_email_template.xml new file mode 100644 index 000000000..5082d1f19 --- /dev/null +++ b/salon_management/views/salon_email_template.xml @@ -0,0 +1,41 @@ + + + + + Salon e-mail template + ${object.company_id and object.company_id.email or ''} + Congratz ${object.name} + ${object.email|safe} + ${object.lang} + + + + Dear ${(object.name)},

+ Thank you for choosing ${(object.company_id.name)}, your booking was registered!

+ Regards,
+ ${(object.company_id.name)} + ]]> +
+
+ + Salon e-mail template + ${object.company_id and object.company_id.email or ''} + We are Sorry ${object.name} + ${object.email|safe} + ${object.lang} + + + + Dear ${(object.name)},

+ Thank you for choosing ${(object.company_id.name)}, but your booking was rejected!
+ there is no seats available for the time you chosen.
+ better luck next time.

+ Regards,
+ ${(object.company_id.name)} + ]]> +
+
+
+
\ No newline at end of file diff --git a/salon_management/views/salon_holiday.xml b/salon_management/views/salon_holiday.xml new file mode 100644 index 000000000..5c004428a --- /dev/null +++ b/salon_management/views/salon_holiday.xml @@ -0,0 +1,27 @@ + + + + + Sunday + True + + + Monday + + + Tuesday + + + Wednesday + + + Thursday + + + Friday + + + Saturday + + + \ No newline at end of file diff --git a/salon_management/views/salon_management_chair.xml b/salon_management/views/salon_management_chair.xml new file mode 100644 index 000000000..b98d6641f --- /dev/null +++ b/salon_management/views/salon_management_chair.xml @@ -0,0 +1,91 @@ + + + + + Chair Sequence + chair.sequence + Chair- + 2 + 1 + 1 + + + + + Collection Today + + + 1 + days + -1 + + + + + + salon_chair_form.form + salon.chair + +
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + salon_chair_tree.tree + salon.chair + + + + + + + + + Dashboard + salon.chair + form + kanban,form + {} + + + Chair + salon.chair + form + tree,form + + + + + +
+
\ No newline at end of file diff --git a/salon_management/views/salon_management_dashboard.xml b/salon_management/views/salon_management_dashboard.xml new file mode 100644 index 000000000..03555f396 --- /dev/null +++ b/salon_management/views/salon_management_dashboard.xml @@ -0,0 +1,96 @@ + + + + + salon_management_kanban.dashboard + salon.chair + kanban + + + + + + + +
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+
+ + Today's Collection : + + + + +
+
+
+
+ + Today's Collection : + + + + +
+
+
+
+ + Free After (Hours) : + + + + +
+
+
+
+ + Reserved For Booking + +
+
+
+
+
+
+
+
+ +
+
\ No newline at end of file diff --git a/salon_management/views/salon_management_services.xml b/salon_management/views/salon_management_services.xml new file mode 100644 index 000000000..d87cfdb34 --- /dev/null +++ b/salon_management/views/salon_management_services.xml @@ -0,0 +1,38 @@ + + + + + salon_service_form.form + salon.service + +
+ + + + + + + +
+
+
+ + salon_service_tree.tree + salon.service + + + + + + + + + + Services + salon.service + form + tree,form + + +
+
\ No newline at end of file diff --git a/salon_management/views/salon_order_view.xml b/salon_management/views/salon_order_view.xml new file mode 100644 index 000000000..c03e0ecc7 --- /dev/null +++ b/salon_management/views/salon_order_view.xml @@ -0,0 +1,221 @@ + + + + + partner_salon_boolean.view + res.partner + + + + + + + + + Salon Order Sequence + salon.order.sequence + SALON/%(range_year)s/ + + + + 4 + + + salon_order_tree.tree + salon.order + + + + + + + + + + + + + + salon_order_kanban.kanban + salon.order + + + + + +
+ +
+
+ +
+
+ Customer : + +
+ Chair : + +
+
+
+ Amount : + +
+ +
+ Date : + +
+
+
+
+
+
+
+
+
+ + salon_order_form.form + salon.order + +
+
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+ +
+
+
+
+
+ + + + + +
+ + + + + + + + Salon + salon.order + form + kanban,tree,form + + + Salon Orders + salon.order + form + kanban,tree,form + [('chair_id', '=', active_id)] + + + + \ No newline at end of file diff --git a/salon_management/views/working_hours.xml b/salon_management/views/working_hours.xml new file mode 100644 index 000000000..eae08314f --- /dev/null +++ b/salon_management/views/working_hours.xml @@ -0,0 +1,68 @@ + + + + + salon_working_form.form + salon.working.hours + +
+ +

+ +

+ + + + + + + + +
+
+
+
+ + salon_working_tree.tree + salon.working.hours + + + + + + + + +
+ + Working Hours + salon.working.hours + form + tree,form + + + + + Sunday + + + Monday + + + Tuesday + + + Wednesday + + + Thursday + + + Friday + + + Saturday + + +
\ No newline at end of file