| @ -1,3 +1,4 @@ | |||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| from . import kalachakra | |||||
| from . import kalachakra | |||||
| from . import booking | |||||
| @ -0,0 +1,401 @@ | |||||
| from odoo import fields, http, _ | |||||
| from odoo.http import request | |||||
| import werkzeug | |||||
| from odoo.tools import format_datetime, format_date, is_html_empty | |||||
| from odoo.exceptions import UserError,AccessError, MissingError,Warning | |||||
| from odoo.addons.website_event.controllers.main import WebsiteEventController | |||||
| from odoo.addons.auth_signup.controllers.main import AuthSignupHome | |||||
| from odoo.addons.sale.controllers.portal import CustomerPortal | |||||
| from odoo.addons.portal.controllers.portal import pager as portal_pager, get_records_pager | |||||
| import json | |||||
| import binascii | |||||
| from odoo.addons.payment.controllers.portal import PaymentProcessing | |||||
| from odoo.addons.portal.controllers.mail import _message_post_helper | |||||
| from odoo.osv import expression | |||||
| class booking(WebsiteEventController,AuthSignupHome): | |||||
| @http.route(['/booking/registration/options'], type='http', auth='user', website=True, sitemap=False,csrf=False) | |||||
| def bookingregistration_options(self,event_id,*args,**kw): | |||||
| data={} | |||||
| #contact lié à l'utilisateur | |||||
| userid=request.env.context.get('uid') | |||||
| user=request.env['res.users'].search([('id','=',int(userid))]) | |||||
| partner=request.env['res.partner'].sudo().search([('id','=',int(user.partner_id))]) | |||||
| request.session['partner_id']=int(partner.id) | |||||
| #si le pays n'est pas renseigné, on le renseigne avec France | |||||
| #c'est indispensable pour pouvoir régléer le devis | |||||
| if not partner.country_id: | |||||
| country=request.env['res.country'].search([('name','=','France')]) | |||||
| partner.country_id=country.id | |||||
| data['partner']=partner | |||||
| #évenement | |||||
| request.session['event_id']=int(event_id) | |||||
| event=request.env['event.event'].sudo().search([('id','=',int(event_id))]) | |||||
| data['event']=event | |||||
| #status | |||||
| # category_ids=partner.category_id | |||||
| # data['status']='standard' | |||||
| # if category_ids: | |||||
| # for c in category_ids: | |||||
| # category=request.env['event.partner_category'].sudo().search([('partner_category_id','=',c.id)]) | |||||
| # #category=request.env['res.partner.category'].search([('id','=',c.id)]) | |||||
| # if category:data['status']=category.status | |||||
| data['status']=partner.member_status | |||||
| if data['status']=='not member':data['status']='standard' | |||||
| #prix | |||||
| data['price']='' | |||||
| if data['status']=='standard':data['price']=event.booking_price | |||||
| if data['status']=='member':data['price']=event.booking_member_price | |||||
| if data['status']=='super member':data['price']=event.booking_super_member_price | |||||
| #membership product | |||||
| membership_product=request.env['event.membership_product'].sudo().search([]) | |||||
| if not membership_product: raise Warning('no membership product find') | |||||
| data['membership_product']=membership_product | |||||
| #options | |||||
| data['options']=[] | |||||
| for opt in event.booking_option_ids: | |||||
| if opt.booking_option_id==membership_product.membership_product_id: | |||||
| if data['status']!='member' and data['status']!='super member':data['options'].append(opt) | |||||
| else:data['options'].append(opt) | |||||
| #data['options']=event.booking_option_ids | |||||
| #questions | |||||
| data['questions']=event.question_ids | |||||
| return http.request.render('booking.registration_options_form',data) | |||||
| @http.route(['/booking/registration/questionnaire'], type='http', auth='user', website=True, sitemap=False,csrf=False) | |||||
| def bookingregistration_questionnaire(self,**post): | |||||
| vals={} | |||||
| data={} | |||||
| vals['event_id']=post.get('event_id') | |||||
| vals['name']=post.get('name') | |||||
| vals['phone']=post.get('phone') | |||||
| vals['email']=post.get('email') | |||||
| vals['firstname']=post.get('firstname') | |||||
| vals['age']=post.get('age') | |||||
| vals['gender']=post.get('gender') | |||||
| vals['mobile']=post.get('mobile') | |||||
| request.session['registrant'] = vals | |||||
| request.session['down_payment'] =False | |||||
| if post.get('down_payment')=="false":request.session['down_payment'] = False | |||||
| if post.get('down_payment')=="true":request.session['down_payment'] = True | |||||
| #options | |||||
| if post.get('nb_o')!="0": | |||||
| vals3={} | |||||
| i=1 | |||||
| k=1 | |||||
| while i <= int(post.get('nb_o')): | |||||
| if post.get('o['+str(i)+']'): | |||||
| vals3[k]=post.get('o['+str(i)+']') | |||||
| k=k+1 | |||||
| i=i+1 | |||||
| request.session['options']=vals3 | |||||
| request.session['nb_o']=k-1 | |||||
| else: | |||||
| request.session['options']=None | |||||
| request.session['nb_o']=0 | |||||
| #questions | |||||
| event=request.env['event.event'].sudo().search([('id','=',int(post.get('event_id')))]) | |||||
| data['event']=event | |||||
| data['questions']=False | |||||
| if event.question_ids: | |||||
| data['questions']=event.question_ids | |||||
| #return vals3 | |||||
| return http.request.render('booking.registration_questionnaire_form',data) | |||||
| @http.route(['/booking/payment_choice'], type='http',auth='user', website=True, sitemap=False,csrf=False) | |||||
| def bookinginvoice(self,**post): | |||||
| vals={} | |||||
| vals['event_id']=request.session['event_id'] | |||||
| vals['partner_id']=request.session['partner_id'] | |||||
| vals['name']=request.session['registrant']['name'] | |||||
| vals['phone']=request.session['registrant']['phone'] | |||||
| vals['email']=request.session['registrant']['email'] | |||||
| vals['firstname']=request.session['registrant']['firstname'] | |||||
| vals['age']=request.session['registrant']['age'] | |||||
| vals['gender']=request.session['registrant']['gender'] | |||||
| vals['mobile']=request.session['registrant']['mobile'] | |||||
| vals['medical_concern']=post.get('medical_concern') | |||||
| vals['medical_information']=post.get('medical_information') | |||||
| vals['medical_contact_name']=post.get('medical_contact_name') | |||||
| vals['medical_contact_phone']=post.get('medical_contact_phone') | |||||
| vals['down_payment']=request.session['down_payment'] | |||||
| vals['state']='draft' | |||||
| res=request.env['event.registration'].sudo().create(vals) | |||||
| vals2={} | |||||
| #questionnaire' | |||||
| i=1 | |||||
| vals2['event_registration_id']=res.id | |||||
| #suppression du questionnaire de la personne inscrite | |||||
| request.env['event.registration_questionnaire'].sudo().search([('event_registration_id','=',int(res.id))]).unlink() | |||||
| if post.get('nb_q')!="0": | |||||
| while i < int(post.get('nb_q')): | |||||
| vals2['sequence']=i | |||||
| vals2['question']=post.get('q['+str(i)+']') | |||||
| vals2['answer']=post.get('a['+str(i)+']') | |||||
| #ajout du questionnaire avec les réponses | |||||
| res2=request.env['event.registration_questionnaire'].sudo().create(vals2) | |||||
| res.write({'questionnaire_ids':[(4,res2.id)]}) | |||||
| i=i+1 | |||||
| #options | |||||
| if request.session['nb_o']!=0 : | |||||
| vals3={} | |||||
| i=1 | |||||
| #suppression des options de la personne inscrite | |||||
| request.env['event.registration_option'].sudo().search([('event_registration_id','=',int(res.id))]).unlink() | |||||
| while i <= int(request.session['nb_o']): | |||||
| vals3['booking_option_id']=request.session['options'][i] | |||||
| vals3['event_registration_id']=res.id | |||||
| #ajout des options | |||||
| res3=request.env['event.registration_option'].sudo().create(vals3) | |||||
| res.write({'option_ids':[(4,res3.id)]}) | |||||
| i=i+1 | |||||
| #création du devis | |||||
| order_id=request.env['event.registration'].sudo().action_event_registration_generate_order(res.id) | |||||
| order=request.env['sale.order'].sudo().search([("id","=",int(order_id))]) | |||||
| data={} | |||||
| data['submit_txt']='Pay now' | |||||
| data['success_url']='/booking/payment/success' | |||||
| data['error_url']='/booking/payment/error' | |||||
| data['acquirers'] = list(request.env['payment.acquirer'].search([ | |||||
| ('state', 'in', ['enabled', 'test']), | |||||
| ('company_id', '=', request.env.company.id) | |||||
| ])) | |||||
| userid=request.env.context.get('uid') | |||||
| user=request.env['res.users'].search([('id','=',int(userid))]) | |||||
| partner=request.env['res.partner'].sudo().search([('id','=',int(user.partner_id))]) | |||||
| request.session['partner_id']=int(partner.id) | |||||
| payment_tokens = partner.payment_token_ids | |||||
| payment_tokens |= partner.commercial_partner_id.sudo().payment_token_ids | |||||
| data['payment_tokens']=payment_tokens | |||||
| data['order_id']=order_id | |||||
| return http.request.render('booking.payment_choice_form',data) | |||||
| #return http.request.redirect(order.access_url) | |||||
| @http.route(['/booking/payment/transaction/', | |||||
| '/booking/payment/transaction/<int:so_id>', | |||||
| '/booking/payment/transaction/<int:so_id>/<string:access_token>'], type='json', auth="public", website=True) | |||||
| def booking_payment_transaction(self, acquirer_id,order_id, save_token=False, so_id=None, access_token=None, token=None, **kwargs): | |||||
| """ Json method that creates a payment.transaction, used to create a | |||||
| transaction when the user clicks on 'pay now' button. After having | |||||
| created the transaction, the event continues and the user is redirected | |||||
| to the acquirer website. | |||||
| :param int acquirer_id: id of a payment.acquirer record. If not set the | |||||
| user is redirected to the checkout page | |||||
| """ | |||||
| # Ensure a payment acquirer is selected | |||||
| if not acquirer_id: | |||||
| return False | |||||
| try: | |||||
| acquirer_id = int(acquirer_id) | |||||
| except: | |||||
| return False | |||||
| order_id=order_id | |||||
| order=request.env['sale.order'].search([('id','=',int(order_id))], limit=1) | |||||
| # Ensure there is something to proceed | |||||
| if not order or (order and not order.order_line): | |||||
| return False | |||||
| assert order.partner_id.id != request.website.partner_id.id | |||||
| # Create transaction | |||||
| vals = {'acquirer_id': acquirer_id, | |||||
| 'return_url': '/booking/payment/validate'} | |||||
| if save_token: | |||||
| vals['type'] = 'form_save' | |||||
| if token: | |||||
| vals['payment_token_id'] = int(token) | |||||
| transaction = order._create_payment_transaction(vals) | |||||
| # store the new transaction into the transaction list and if there's an old one, we remove it | |||||
| # until the day the ecommerce supports multiple orders at the same time | |||||
| last_tx_id = request.session.get('__website_sale_last_tx_id') | |||||
| last_tx = request.env['payment.transaction'].browse(last_tx_id).sudo().exists() | |||||
| if last_tx: | |||||
| PaymentProcessing.remove_payment_transaction(last_tx) | |||||
| PaymentProcessing.add_payment_transaction(transaction) | |||||
| request.session['__website_sale_last_tx_id'] = transaction.id | |||||
| request.session['order_id']=order.id | |||||
| return transaction.render_sale_button(order) | |||||
| http.route('/booking/payment/token', type='http', auth='public', website=True, sitemap=False) | |||||
| def booking_payment_token(self, pm_id=None, **kwargs): | |||||
| """ Method that handles payment using saved tokens | |||||
| :param int pm_id: id of the payment.token that we want to use to pay. | |||||
| """ | |||||
| try: | |||||
| pm_id = int(pm_id) | |||||
| except ValueError: | |||||
| return request.redirect('/shop/?error=invalid_token_id') | |||||
| # We retrieve the token the user want to use to pay | |||||
| if not request.env['payment.token'].sudo().search_count([('id', '=', pm_id)]): | |||||
| return request.redirect('/shop/?error=token_not_found') | |||||
| # Create transaction | |||||
| vals = {'payment_token_id': pm_id, 'return_url': '/booking/payment/validate'} | |||||
| tx = order._create_payment_transaction(vals) | |||||
| request.session['transaction_id']=tx.id | |||||
| PaymentProcessing.add_payment_transaction(tx) | |||||
| return request.redirect('booking/payment/process') | |||||
| @http.route(['/booking/payment/process'], type="http", auth="public", website=True, sitemap=False) | |||||
| def booking_payment_status_page(self, **kwargs): | |||||
| # When the customer is redirect to this website page, | |||||
| # we retrieve the payment transaction list from his session | |||||
| tx_ids_list = self.get_payment_transaction_ids() | |||||
| payment_transaction_ids = request.env['payment.transaction'].sudo().browse(tx_ids_list).exists() | |||||
| render_ctx = { | |||||
| 'payment_tx_ids': payment_transaction_ids.ids, | |||||
| } | |||||
| return request.render("payment.payment_process_page", render_ctx) | |||||
| @http.route('/booking/payment/validate', type='http', auth="public", website=True, sitemap=False) | |||||
| def booking_payment_validate(self, transaction_id=None, sale_order_id=None, **post): | |||||
| """ Method that should be called by the server when receiving an update | |||||
| for a transaction. State at this point : | |||||
| - UDPATE ME | |||||
| """ | |||||
| order_id=int(request.session['order_id']) | |||||
| order=request.env['sale.order'].search([('id','=',order_id)]) | |||||
| order.state='sale' | |||||
| request.session['order_id']=None | |||||
| transaction_id=int(request.session['__website_sale_last_tx_id'] ) | |||||
| tx = request.env['payment.transaction'].sudo().browse(transaction_id) | |||||
| PaymentProcessing.remove_payment_transaction(tx) | |||||
| return request.redirect('/booking/payment/confirmation') | |||||
| @http.route(['/booking/payment/confirmation'], type='http', auth="public", website=True, sitemap=False) | |||||
| def booking_payment_confirmation(self, **post): | |||||
| return request.render("booking.thankyou") | |||||
| # class CustomerPortal(CustomerPortal): | |||||
| # #affichage de la page de paiement | |||||
| # @http.route(['/my/quotes', '/my/quotes/page/<int:page>'], type='http', auth="user", website=True) | |||||
| # def portal_my_quotes(self, page=1, date_begin=None, date_end=None, sortby=None, **kw): | |||||
| # values = self._prepare_portal_layout_values() | |||||
| # partner = request.env.user.partner_id | |||||
| # SaleOrder = request.env['sale.order'] | |||||
| # #return str(len(SaleOrder)) | |||||
| # domain = [('partner_id','=',int(partner.id)),('state','in',('draft','sent'))] | |||||
| # searchbar_sortings = { | |||||
| # 'date': {'label': _('Order Date'), 'order': 'date_order desc'}, | |||||
| # 'name': {'label': _('Reference'), 'order': 'name'}, | |||||
| # 'stage': {'label': _('Stage'), 'order': 'state'}, | |||||
| # } | |||||
| # # default sortby order | |||||
| # if not sortby: | |||||
| # sortby = 'date' | |||||
| # sort_order = searchbar_sortings[sortby]['order'] | |||||
| # if date_begin and date_end: | |||||
| # domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)] | |||||
| # # count for pager | |||||
| # quotation_count = SaleOrder.search_count(domain) | |||||
| # # make pager | |||||
| # pager = portal_pager( | |||||
| # url="/my/quotes", | |||||
| # url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby}, | |||||
| # total=quotation_count, | |||||
| # page=page, | |||||
| # step=self._items_per_page | |||||
| # ) | |||||
| # # search the count to display, according to the pager data | |||||
| # quotations = SaleOrder.search(domain, order=sort_order, limit=self._items_per_page, offset=pager['offset']) | |||||
| # request.session['my_quotations_history'] = quotations.ids[:100] | |||||
| # values.update({ | |||||
| # 'date': date_begin, | |||||
| # 'quotations': quotations.sudo(), | |||||
| # 'page_name': 'quote', | |||||
| # 'pager': pager, | |||||
| # 'default_url': '/my/quotes', | |||||
| # 'searchbar_sortings': searchbar_sortings, | |||||
| # 'sortby': sortby, | |||||
| # }) | |||||
| # return request.render("sale.portal_my_quotations", values) | |||||
| @ -0,0 +1,18 @@ | |||||
| from odoo import models, fields, api | |||||
| class DonationDonation(models.Model): | |||||
| _inherit = 'donation.donation' | |||||
| event_registration_id=fields.Many2one( | |||||
| 'event.registration', | |||||
| String='Event registration', | |||||
| index=True, | |||||
| readonly=True, | |||||
| track_visibility='onchange', | |||||
| ) | |||||
| @ -0,0 +1,185 @@ | |||||
| from odoo import models, fields, api | |||||
| from odoo.exceptions import UserError, ValidationError,Warning | |||||
| from psycopg2 import sql, DatabaseError | |||||
| from werkzeug import utils | |||||
| class EventType(models.Model): | |||||
| _inherit = "event.type" | |||||
| _description = 'Event Template' | |||||
| booking_event = fields.Boolean(string="Booking event", tracking=True) | |||||
| booking_option_ids=fields.One2many('booking.option','event_type_id','booking options') | |||||
| booking_questionnaire_id=fields.Many2one( | |||||
| 'booking.questionnaire', | |||||
| String='Questionnaire', | |||||
| index=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='cascade' | |||||
| ) | |||||
| class EventBookingOptions(models.Model): | |||||
| _name='booking.option' | |||||
| _description='booking options for events' | |||||
| booking_option_id=fields.Many2one('product.product',string='booking options',domain="[('booking_option_product','=','True')]") | |||||
| name=fields.Char(related='booking_option_id.name') | |||||
| booking_option_price=fields.Monetary('Price',currency_field='currency_id') | |||||
| booking_option_member_price=fields.Monetary('Member price',currency_field='currency_id') | |||||
| booking_option_super_member_price=fields.Monetary('Super member price',currency_field='currency_id') | |||||
| event_type_id = fields.Many2one( | |||||
| 'event.type', | |||||
| String='Event type', | |||||
| index=True, | |||||
| readonly=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='cascade' | |||||
| ) | |||||
| event_id = fields.Many2one( | |||||
| 'event.event', | |||||
| String='Event', | |||||
| index=True, | |||||
| readonly=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='cascade' | |||||
| ) | |||||
| @api.model | |||||
| def _default_currency(self): | |||||
| company = self.env['res.company']._company_default_get( | |||||
| 'event.event') | |||||
| return company.currency_id | |||||
| currency_id = fields.Many2one( | |||||
| 'res.currency', | |||||
| string='Currency', | |||||
| required=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='restrict', | |||||
| default=_default_currency | |||||
| ) | |||||
| @api.onchange('booking_option_id') | |||||
| def onchange_booking_option(self): | |||||
| #for option in self: | |||||
| if self.booking_option_id: | |||||
| bo= self.env['product.product'].search([('id',"=",int(self.booking_option_id))]) | |||||
| self.booking_option_price= bo.lst_price | |||||
| # class BookingEvent(models.Model): | |||||
| # _inherit = "event.event" | |||||
| # _description = 'Event' | |||||
| # booking_event = fields.Boolean(string="Booking event", tracking=True) | |||||
| # question_ids=fields.One2many( | |||||
| # 'event.question', | |||||
| # 'event_id', | |||||
| # string='Questions' | |||||
| # ) | |||||
| # booking_option_ids=fields.One2many('booking.option','event_id','booking options') | |||||
| # @api.model | |||||
| # def _default_currency(self): | |||||
| # company = self.env['res.company']._company_default_get( | |||||
| # 'event.event') | |||||
| # return company.currency_id | |||||
| # currency_id = fields.Many2one( | |||||
| # 'res.currency', | |||||
| # string='Currency', | |||||
| # required=True, | |||||
| # states={'done': [('readonly', True)]}, | |||||
| # track_visibility='onchange', | |||||
| # ondelete='restrict', | |||||
| # default=_default_currency | |||||
| #) | |||||
| # booking_price=fields.Monetary('Price',currency_field='currency_id') | |||||
| # booking_member_price=fields.Monetary('Member price',currency_field='currency_id') | |||||
| # booking_super_member_price=fields.Monetary('Super member price',currency_field='currency_id') | |||||
| # booking_down_payment=fields.Monetary('Down payment',currency_field='currency_id') | |||||
| # booking_product_id=fields.Many2one('product.product',string='booking product',domain="[('booking_product','=','True')]") | |||||
| # @api.depends('event_type_id') | |||||
| # def _compute_booking_event(self): | |||||
| # self.booking_event=self.event_type_id.booking_event | |||||
| # @api.onchange('event_type_id') | |||||
| # def onchange_state(self): | |||||
| # self.booking_event=self.event_type_id.booking_event | |||||
| # booking_option=self.env['booking.option'].search([('event_type_id','=',int(self.event_type_id))]) | |||||
| # if booking_option: | |||||
| # on supprime les options existantes: | |||||
| # self.booking_option_ids=False | |||||
| # on rappatrie les options du modèle | |||||
| # for option in booking_option: | |||||
| # vals={} | |||||
| # vals['event_id']=self.id | |||||
| # vals['booking_option_id']=option.booking_option_id | |||||
| # vals['booking_option_price']=option.booking_option_price | |||||
| # vals['currency_id']=option.currency_id | |||||
| # self.booking_option_ids = [(0, 0, vals)] | |||||
| # if self.event_type_id.booking_questionnaire_id: | |||||
| # on supprime les question existantes: | |||||
| # self.question_ids=False | |||||
| # questions=self.env['booking.question'].search([('questionnaire_id','=',int(self.event_type_id.booking_questionnaire_id))]) | |||||
| # on rappatrie les question | |||||
| # for question in questions: | |||||
| # vals={} | |||||
| # vals['event_id']=self.id | |||||
| # vals['sequence']=question.sequence | |||||
| # vals['question']=question.question | |||||
| # self.question_ids = [(0, 0, vals)] | |||||
| #super(event, self).write(vals) | |||||
| #self.booking_option_ids=self.event_type_id.booking_option_ids | |||||
| class event_question(models.Model): | |||||
| _name = 'event.question' | |||||
| _description = 'event question' | |||||
| question=fields.Text(string='question') | |||||
| sequence = fields.Integer(string="sequence", default=10) | |||||
| event_id = fields.Many2one( | |||||
| 'event.event', | |||||
| String='Questionnaire', | |||||
| index=True, | |||||
| readonly=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='cascade' | |||||
| ) | |||||
| class event_partner_category(models.Model): | |||||
| _name = 'event.partner_category' | |||||
| _description = 'map partner categories vs member or super-member for pricing' | |||||
| partner_category_id=fields.Many2one( | |||||
| 'res.partner.category', | |||||
| String='Category', | |||||
| index=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='cascade' | |||||
| ) | |||||
| status=fields.Selection(selection=[('member','Member'),('supermember','Super Member')]) | |||||
| class event_membership_product(models.Model): | |||||
| _name = 'event.membership_product' | |||||
| _description = 'membership product' | |||||
| membership_product_id=fields.Many2one('product.product',string='Membership product',domain="[('booking_option_product','=','True')]") | |||||
| @ -0,0 +1,392 @@ | |||||
| from odoo import models, fields, api | |||||
| from odoo.exceptions import UserError, ValidationError, Warning | |||||
| from psycopg2 import sql, DatabaseError | |||||
| from dateutil.relativedelta import relativedelta | |||||
| from datetime import datetime | |||||
| from werkzeug import utils | |||||
| class EventRegistration(models.Model): | |||||
| _inherit = 'event.registration' | |||||
| room_id = fields.Many2one( | |||||
| 'booking.room', | |||||
| String='Room', | |||||
| index=True, | |||||
| group_expand='_read_group_room_ids', | |||||
| track_visibility='onchange', | |||||
| ) | |||||
| booking_event=fields.Boolean(related='event_id.booking_event') | |||||
| event_end=fields.Boolean(related='event_id.stage_id.pipe_end') | |||||
| medical_concern=fields.Selection( | |||||
| [('have medical concern','I have a medical concern to report'), | |||||
| ('have no medical concern','I have no medical concern to report'), | |||||
| ('no answer','I don\'t want to answer')], | |||||
| string='Medical concern', | |||||
| ) | |||||
| medical_information=fields.Char('Medical informations') | |||||
| medical_contact_name=fields.Char('Name and Firstname of the contact') | |||||
| medical_contact_phone=fields.Char('Phone of the contact') | |||||
| questionnaire_ids=fields.One2many( | |||||
| 'event.registration_questionnaire', | |||||
| 'event_registration_id', | |||||
| String='Questionnaire', | |||||
| readonly=True | |||||
| ) | |||||
| option_ids=fields.One2many( | |||||
| 'event.registration_option', | |||||
| 'event_registration_id', | |||||
| String='Options', | |||||
| readonly=True | |||||
| ) | |||||
| donation_ids=fields.One2many( | |||||
| 'donation.donation', | |||||
| 'event_registration_id', | |||||
| String='Donations', | |||||
| readonly=True | |||||
| ) | |||||
| down_payment=fields.Boolean('down payment',default=False) | |||||
| firstname=fields.Char('Firstname') | |||||
| age=fields.Integer('Age') | |||||
| gender=fields.Selection([('male','Male'),('femelle','Femelle')],string='gender') | |||||
| mobile=fields.Char('Mobile') | |||||
| kanban_color=fields.Char('kanban color',compute='_compute_kanban_color') | |||||
| order_id=fields.Many2one('sale.order') | |||||
| order_state=fields.Selection(related='order_id.state') | |||||
| down_payment_order_id=fields.Many2one('sale.order') | |||||
| down_payment_order_state=fields.Selection(related='down_payment_order_id.state') | |||||
| balance_order_id=fields.Many2one('sale.order') | |||||
| balance_order_state=fields.Selection(related='balance_order_id.state') | |||||
| payment_status=fields.Char(string='payment status',compute='_compute_payment_status') | |||||
| def _compute_payment_status(self): | |||||
| for rec in self: | |||||
| rec.payment_status='undefined' | |||||
| if rec.order_id: | |||||
| if rec.order_state in ('draft','sent'):rec.payment_status='not paid' | |||||
| if rec.order_state=='sale':rec.payment_status='paid' | |||||
| if rec.order_state in ('done','cancel'):rec.payment_status=rec.order_state | |||||
| else: | |||||
| if rec.down_payment_order_id and balance_order_state: | |||||
| if rec.down_payment_order_state in ('draft','sent'):rec.payment_status='down payment not paid' | |||||
| if rec.down_payment_order_state=='sale' and rec.balance_payment_order_state=='sale' :rec.payment_status='paid' | |||||
| if rec.down_payment_order_state=='sale' and rec.balance_payment_order_state!='sale':rec.payment_status='down payment paid' | |||||
| def _compute_kanban_color(self): | |||||
| for rec in self: | |||||
| rec.kanban_color='' | |||||
| if rec.gender=='male':rec.kanban_color="d0e0e3" | |||||
| if rec.gender=='femelle':rec.kanban_color="eebbcc" | |||||
| @api.model | |||||
| def _read_group_room_ids(self, stages, domain, order): | |||||
| return self.env['booking.room'].search([]) | |||||
| @api.model_create_multi | |||||
| def create(self, vals_list): | |||||
| registrations = super(EventRegistration, self).create(vals_list) | |||||
| if registrations._check_auto_confirmation(): | |||||
| registrations.sudo().action_confirm() | |||||
| #ajout du questionnaire pour la personne inscrite | |||||
| questions=self.env['event.question'].search([('event_id','=',int(registrations.event_id))]) | |||||
| if questions: | |||||
| for question in questions: | |||||
| vals={} | |||||
| vals['sequence']=question.sequence | |||||
| vals['question']=question.question | |||||
| vals['event_registration_id']=registrations.id | |||||
| res=self.env['event.registration_questionnaire'].create(vals) | |||||
| #ajout des options pour la personne inscrite | |||||
| options=self.env['booking.option'].search([('event_id','=',int(registrations.event_id))]) | |||||
| if options: | |||||
| for option in options: | |||||
| vals={} | |||||
| vals['booking_option_id']=int(option.booking_option_id) | |||||
| vals['booking_option_price']=option.booking_option_price | |||||
| vals['event_registration_id']=int(registrations.id) | |||||
| res=self.env['event.registration_option'].create(vals) | |||||
| return registrations | |||||
| def action_event_registration_order(self): | |||||
| return True | |||||
| def create_donation(self,event_registration_id,partner_id,product_id,price_unit): | |||||
| vals={} | |||||
| vals['partner_id']=int(partner_id) | |||||
| #raise Warning(vals['partner_id']) | |||||
| vals['donation_date']=datetime.now() | |||||
| vals['tax_receipt_option']='annual' | |||||
| #mode de paiement CB par defaut | |||||
| electronic_method=self.env['account.payment.method'].search([('code','=','electronic')],limit=1) | |||||
| if electronic_method: | |||||
| cb_mode=self.env['account.payment.mode'].search([('payment_method_id','=',int(electronic_method.id))],limit=1) | |||||
| if cb_mode: | |||||
| vals['payment_mode_id']=cb_mode.id | |||||
| else: | |||||
| raise Warning('please configure credit card mode') | |||||
| #tant que le devis n'est pas validé (paiment effectué), le don est en brouillon | |||||
| vals['state']='draft' | |||||
| vals['payment_ref']='internet' | |||||
| donation_draft=self.env['donation.donation'].sudo().create(vals) | |||||
| #ajout du don au niveau de l'inscription | |||||
| reg=self.env['event.registration'].search([('id','=',int(event_registration_id))]) | |||||
| if reg: | |||||
| reg.write({'donation_ids':[(4,int(donation_draft.id))]}) | |||||
| vals={} | |||||
| #create line donation | |||||
| vals['donation_id']=donation_draft.id | |||||
| product=self.env['product.product'].search([('id','=',int(product_id))]) | |||||
| vals['product_id']=int(product_id) | |||||
| vals['display_name']=product.name | |||||
| vals['quantity']=1 | |||||
| vals['unit_price']=price_unit | |||||
| vals['tax_receipt_ok']=product.tax_receipt_ok | |||||
| donation_line=self.env['donation.line'].sudo().create(vals) | |||||
| donation_draft.state='done' | |||||
| def action_event_registration_generate_order(self,id_registration=None): | |||||
| #suppression des devis existants | |||||
| if self.order_id: | |||||
| self.env['sale.order'].search([('id','=',int(self.order_id))]).unlink() | |||||
| self.order_id=False | |||||
| if self.down_payment_order_id: | |||||
| self.env['sale.order'].search([('id','=',int(self.down_payment_order_id))]).unlink() | |||||
| self.down_payment_order_id=False | |||||
| if self.balance_order_id: | |||||
| self.env['sale.order'].search([('id','=',int(self.balance_order_id))]).unlink() | |||||
| self.balance_order_id=False | |||||
| #suppression des dons existants | |||||
| self.env['donation.donation'].search([('id','in',self.donation_ids)]).unlink() | |||||
| self.donation_ids=False | |||||
| if id_registration:reg=self.env['event.registration'].search([('id','=',int(id_registration))]) | |||||
| else : reg=self | |||||
| event=self.env['event.event'].search([('id','=',int(reg.event_id))]) | |||||
| selected_registrant_options=self.env['event.registration_option'].search([ | |||||
| ('event_registration_id','=',int(reg.id))]) | |||||
| #controles avant traitement : un produit doit être associé à l'événement | |||||
| if not event.booking_product_id: raise Warning('product missing for event booking') | |||||
| #Prix à appliquer au produit en fonction du statut de l'inscrit | |||||
| status=reg.partner_id.member_status | |||||
| product_price=event.booking_price | |||||
| if status=='not member':product_price=event.booking_price | |||||
| if status=='member':product_price=event.booking_member_price | |||||
| if status=='super member':product_price=event.booking_super_member_price | |||||
| #Prix à appliquer au produit si paiement de l'adhésion | |||||
| membership_option=False | |||||
| membership_product=self.env['event.membership_product'].search([]) | |||||
| if membership_product: | |||||
| if selected_registrant_options: | |||||
| for opt in selected_registrant_options: | |||||
| if opt.booking_option_id==membership_product.id: | |||||
| membership_option=True | |||||
| if status!="super member": | |||||
| product_price=event.booking_member_price | |||||
| #calcul du montant total à régler | |||||
| #création du devis sans accompte | |||||
| if not reg.down_payment: | |||||
| #création du devis | |||||
| vals={} | |||||
| vals['partner_id']=int(reg.partner_id) | |||||
| order=self.env['sale.order'].create(vals) | |||||
| #création des lignes de devis | |||||
| vals={} | |||||
| vals['order_id']=order.id | |||||
| #ajout du produit | |||||
| vals['product_id']=int(event.booking_product_id) | |||||
| vals['product_uom_qty']=1 | |||||
| vals['price_unit']=product_price | |||||
| vals['name']=event.booking_product_id.name | |||||
| order_line=self.env['sale.order.line'].create(vals) | |||||
| #ajout des options | |||||
| vals={} | |||||
| if selected_registrant_options: | |||||
| for option in selected_registrant_options: | |||||
| vals['order_id']=order.id | |||||
| vals['product_id']=int(option.booking_option_id.id) | |||||
| vals['product_uom_qty']=1 | |||||
| prd=self.env['product.product'].search([('id','=',int(option.booking_option_id.id))]) | |||||
| vals['name']=prd.name | |||||
| #prix à appliquer aux options en fonction du statut ou de la présence de l'option d'adhesion | |||||
| event_option=self.env['booking.option'].search(['&',('event_id','=',int(reg.event_id)),('booking_option_id','=',int(option.booking_option_id.id))]) | |||||
| if event_option: | |||||
| if status=="super member":vals['price_unit']=event_option.booking_option_super_member_price | |||||
| if status=="member":vals['price_unit']=event_option.booking_option_member_price | |||||
| if status=="not member" and membership_option: vals['price_unit']=event_option.booking_option_member_price | |||||
| if status=="not member" and not membership_option: vals['price_unit']=event_option.booking_option_price | |||||
| order_line=self.env['sale.order.line'].create(vals) | |||||
| #si l'option est un produit de don on créé un don pour la personne | |||||
| #if prd.donation: self.create_donation(reg.id,reg.partner_id,vals['product_id'],vals['price_unit']) | |||||
| order.message_subscribe(partner_ids=order.partner_id.ids) | |||||
| order.state='sent' | |||||
| reg.order_id=order.id | |||||
| return order.id | |||||
| #2 devis si paiement avec acompte | |||||
| else: | |||||
| #création du 1er devis d'acompte | |||||
| vals={} | |||||
| vals['partner_id']=int(reg.partner_id) | |||||
| order=self.env['sale.order'].create(vals) | |||||
| #création des lignes de devis | |||||
| vals={} | |||||
| vals['order_id']=order.id | |||||
| #ajout du produit | |||||
| vals['product_id']=int(event.booking_product_id) | |||||
| vals['product_uom_qty']=1 | |||||
| vals['price_unit']=event.booking_down_payment | |||||
| vals['name']='Acompte '+event.booking_product_id.name | |||||
| order_line=self.env['sale.order.line'].create(vals) | |||||
| order.message_subscribe(partner_ids=order.partner_id.ids) | |||||
| order.state='sent' | |||||
| reg.down_payment_order_id=order.id | |||||
| #création du 2ème devis de solde + paiement des options | |||||
| vals={} | |||||
| vals['partner_id']=int(reg.partner_id) | |||||
| order2=self.env['sale.order'].create(vals) | |||||
| #création des lignes de devis | |||||
| vals={} | |||||
| vals['order_id']=order2.id | |||||
| #ajout du produit | |||||
| vals['product_id']=int(event.booking_product_id) | |||||
| vals['product_uom_qty']=1 | |||||
| vals['price_unit']=product_price-event.booking_down_payment | |||||
| vals['name']='solde '+event.booking_product_id.name | |||||
| order_line=self.env['sale.order.line'].create(vals) | |||||
| #ajout des options | |||||
| vals={} | |||||
| if selected_registrant_options: | |||||
| for option in selected_registrant_options: | |||||
| vals['order_id']=order2.id | |||||
| vals['product_id']=int(option.booking_option_id.id) | |||||
| vals['product_uom_qty']=1 | |||||
| prd=self.env['product.product'].search([('id','=',int(option.booking_option_id.id))]) | |||||
| vals['name']=prd.name | |||||
| #prix à appliquer aux options en fonction du statut ou de la présence de l'option d'adhesion | |||||
| event_option=self.env['booking.option'].search(['&',('event_id','=',int(reg.event_id)),('booking_option_id','=',int(option.booking_option_id.id))]) | |||||
| if event_option: | |||||
| if status=="super member":vals['price_unit']=event_option.booking_option_super_member_price | |||||
| if status=="member":vals['price_unit']=event_option.booking_option_member_price | |||||
| if status=="not member" and membership_option: vals['price_unit']=event_option.booking_option_member_price | |||||
| if status=="not member" and not membership_option: vals['price_unit']=event_option.booking_option_price | |||||
| order_line=self.env['sale.order.line'].create(vals) | |||||
| order2.message_subscribe(partner_ids=order2.partner_id.ids) | |||||
| order2.state='sent' | |||||
| reg.balance_order_id=order2.id | |||||
| return order.id | |||||
| class EventRegistration_questionnaire(models.Model): | |||||
| _name = 'event.registration_questionnaire' | |||||
| _description = 'event registration questionnaire' | |||||
| sequence = fields.Integer(string="sequence", default=10) | |||||
| question=fields.Text(string='question',readonly=True) | |||||
| answer=fields.Text(string='answer') | |||||
| event_registration_id=fields.Many2one( | |||||
| 'event.registration', | |||||
| String='Event registration', | |||||
| index=True, | |||||
| readonly=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='cascade' | |||||
| ) | |||||
| class EventRegistration_option(models.Model): | |||||
| _name = 'event.registration_option' | |||||
| _description = 'event registration option' | |||||
| booking_option_id=fields.Many2one('product.product',string='booking options',domain="[('booking_option_product','=','True')]") | |||||
| booking_option_price=fields.Monetary('Price',currency_field='currency_id',readonly=True) | |||||
| event_registration_id=fields.Many2one( | |||||
| 'event.registration', | |||||
| String='Event registration', | |||||
| index=True, | |||||
| readonly=True, | |||||
| track_visibility='onchange', | |||||
| ) | |||||
| @api.model | |||||
| def _default_currency(self): | |||||
| company = self.env['res.company']._company_default_get( | |||||
| 'event.event') | |||||
| return company.currency_id | |||||
| currency_id = fields.Many2one( | |||||
| 'res.currency', | |||||
| string='Currency', | |||||
| required=True, | |||||
| states={'done': [('readonly', True)]}, | |||||
| track_visibility='onchange', | |||||
| ondelete='restrict', | |||||
| default=_default_currency | |||||
| ) | |||||
| @ -0,0 +1,14 @@ | |||||
| from odoo import models, fields, api | |||||
| class booking_location(models.Model): | |||||
| _name = 'booking.location' | |||||
| _description = 'booking location' | |||||
| name = fields.Char('name',required=True) | |||||
| description = fields.Text('description') | |||||
| capacity = fields.Integer('max capacity') | |||||
| available_seats = fields.Integer('available seats') | |||||
| @ -0,0 +1,26 @@ | |||||
| from odoo import models, fields, api | |||||
| from odoo.exceptions import UserError, ValidationError | |||||
| from psycopg2 import sql, DatabaseError | |||||
| from werkzeug import utils | |||||
| class ProductTemplate(models.Model): | |||||
| _inherit = "product.template" | |||||
| booking_product = fields.Boolean(string="booking product", tracking=True) | |||||
| booking_option_product = fields.Boolean(string="booking option product", tracking=True) | |||||
| # def _get_special_price(self, combination=False, product_id=False, add_qty=1, pricelist=False, parent_combination=False, only_template=False): | |||||
| # special_price={} | |||||
| # special_price['price_adherent']=100 | |||||
| # special_price['price_soutien']=100 | |||||
| # return special_price | |||||
| @ -0,0 +1,33 @@ | |||||
| from odoo import models, fields, api,_ | |||||
| from odoo.exceptions import UserError, ValidationError,Warning | |||||
| from psycopg2 import sql, DatabaseError | |||||
| class booking_questionnaire(models.Model): | |||||
| _name = 'booking.questionnaire' | |||||
| _description = 'questionnaire pour inscription' | |||||
| name=fields.Char(string='Name') | |||||
| description=fields.Text(string='Description') | |||||
| question_ids = fields.One2many( | |||||
| 'booking.question', | |||||
| 'questionnaire_id', | |||||
| string='Questions' | |||||
| ) | |||||
| class booking_question(models.Model): | |||||
| _name = 'booking.question' | |||||
| _description = 'question' | |||||
| question=fields.Text(string='question') | |||||
| sequence = fields.Integer(string="sequence", default=10) | |||||
| questionnaire_id = fields.Many2one( | |||||
| 'booking.questionnaire', | |||||
| String='Questionnaire', | |||||
| index=True, | |||||
| readonly=True, | |||||
| track_visibility='onchange', | |||||
| ondelete='cascade' | |||||
| ) | |||||
| @ -0,0 +1,46 @@ | |||||
| from odoo import models, fields, api | |||||
| from odoo.exceptions import UserError, ValidationError,Warning | |||||
| class booking_room(models.Model): | |||||
| _name = 'booking.room' | |||||
| _description = 'booking room' | |||||
| name2 = fields.Char('name',required=True) | |||||
| name=fields.Char('room name',compute='_compute_room_name') | |||||
| description = fields.Text('description') | |||||
| capacity = fields.Integer('max capacity') | |||||
| available_seats = fields.Integer('available seats') | |||||
| location_id=fields.Many2one('booking.location', string='location') | |||||
| def _compute_room_name(self): | |||||
| for rec in self: | |||||
| rec.name='' | |||||
| if rec.name2: | |||||
| rec.name=rec.name2+'('+str(rec.capacity)+')' | |||||
| class booking_room_occupation(models.Model): | |||||
| _name = 'booking.room.occupation' | |||||
| _description = 'room occupation' | |||||
| room_id = fields.Many2one('booking.room', string='room') | |||||
| event_id=fields.Many2one('event.event',domain="[('date_begin','>=',context_today().strftime('%Y-%m-%d 00:00:00'))]") | |||||
| event_registration_id = fields.Many2one('event.registration', string='event registration',domain="['&',('event_id', '=', event_id),('room_id', '=', False),('event_id.booking_event', '=', True)]") | |||||
| name=fields.Char(related='event_registration_id.name') | |||||
| date_begin=fields.Datetime(related='event_registration_id.event_id.date_begin') | |||||
| date_end=fields.Datetime(related='event_registration_id.event_id.date_begin') | |||||
| @api.model | |||||
| def create(self,vals): | |||||
| res=super(booking_room_occupation, self).create(vals) | |||||
| #event_reg=self.env['booking.room.occupation'].search([]) | |||||
| event_reg=self.env['event.registration'].search([('id','=',int(res.event_registration_id))]) | |||||
| event_reg.room_id= res.room_id | |||||
| return res | |||||
| @ -0,0 +1,39 @@ | |||||
| from odoo import models, fields, api | |||||
| class SaleOrder(models.Model): | |||||
| _inherit = 'sale.order' | |||||
| def write(self,vals): | |||||
| res = super(SaleOrder, self).write(vals) | |||||
| if self.state=='sale': | |||||
| #on recherche si le devis est lié à une booking inscription | |||||
| event_registration=self.env['event.registration'].search(['|','|',('order_id','=',int(self.id)),('down_payment_order_id','=',int(self.id)),('balance_order_id','=',int(self.id))]) | |||||
| #event_registration=self.env['event.registration'].search([('order_id','=',int(self.id))]) | |||||
| if event_registration: | |||||
| if event_registration.payment_status=='paid': | |||||
| amount=0 | |||||
| for option in event_registration.option_ids: | |||||
| prd=self.env['product.product'].search([('id','=',int(option.booking_option_id)),('donation','=',True)]) | |||||
| if prd: | |||||
| #au niveau de l'événement,on recherche le montant du don en fonction du statut: | |||||
| booking_option=self.env['booking.option'].search([('event_id','=',int(event_registration.event_id)),('booking_option_id','=',int(option.booking_option_id))]) | |||||
| if booking_option: | |||||
| if event_registration.partner_id.member_status=='not member' : amount=booking_option.booking_option_price | |||||
| if event_registration.partner_id.member_status=='member': amount=booking_option.booking_option_member_price | |||||
| if event_registration.partner_id.member_status=='super member': amount=booking_option.booking_option_super_member_price | |||||
| self.env['event.registration'].create_donation(event_registration.id,event_registration.partner_id,option.booking_option_id,amount) | |||||
| @ -0,0 +1,111 @@ | |||||
| odoo.define('booking.main', function (require) { | |||||
| $(document).ready(function() { | |||||
| $('#medical_info').hide() | |||||
| $('#booking_total_price').text( | |||||
| $('#booking_price_product').val()+' €' | |||||
| ); | |||||
| }); | |||||
| $( "#medical_concern" ).change(function() { | |||||
| if (this.value=='have medical concern') | |||||
| { | |||||
| $('#medical_info').show() | |||||
| $("medical_info_div").addClass("s_website_form_required"); | |||||
| $("medical_information").prop('required',true); | |||||
| } | |||||
| else | |||||
| { | |||||
| $('#medical__info').hide() | |||||
| $("medical_info_div").removeClass("s_website_form_required"); | |||||
| $("medical_information").prop('required',false); | |||||
| } | |||||
| }); | |||||
| $( "#back_button2" ).click(function() { | |||||
| history.back() | |||||
| }); | |||||
| $( "#back_button1" ).click(function() { | |||||
| history.back() | |||||
| }); | |||||
| $(":checkbox").change(function() { | |||||
| if(this.value==$("#membership_product").val() && this.checked) | |||||
| { | |||||
| if ($("#status").val()=='standard') {$("#status2").val('member')} | |||||
| } | |||||
| if(this.value==$("#membership_product").val() && this.checked==false) | |||||
| { | |||||
| if ($("#status").val()=='standard'){$("#status2").val('standard')} | |||||
| } | |||||
| //recalcul du prix total | |||||
| if ($("#status2").val()=='standard') | |||||
| { | |||||
| $("#your_status").text('standard') | |||||
| $("#price_of_the_stay").text($("#booking_price").val()+' €') | |||||
| $("#total_price").val($("#booking_price").val()) | |||||
| } | |||||
| if ($("#status2").val()=='member') | |||||
| { | |||||
| $("#your_status").text('member') | |||||
| $("#price_of_the_stay").text($("#booking_member_price").val()+' €') | |||||
| $("#total_price").val($("#booking_member_price").val()) | |||||
| } | |||||
| if ($("#status2").val()=='super member') | |||||
| { | |||||
| $("#your_status").text('super member') | |||||
| $("#price_of_the_stay").text($("#booking_super_member_price").val()+' €') | |||||
| $("#total_price").val($("#booking_super_member_price").val()) | |||||
| } | |||||
| $( ":checkbox" ).each(function( index ) { | |||||
| var l=this.name.length | |||||
| var i=this.name.substring(2,l-1) | |||||
| if (this.value==$("#membership_product").val()) | |||||
| { | |||||
| var option_price_str='#o_standard'+i | |||||
| } | |||||
| else | |||||
| { | |||||
| var option_price_str='#o_'+$("#status2").val()+i | |||||
| } | |||||
| option_price=$(option_price_str).val() | |||||
| total_price=$("#total_price").val() | |||||
| if(this.checked) { | |||||
| $("#total_price").val(parseInt(total_price)+parseInt(option_price)) | |||||
| } | |||||
| }); | |||||
| $("#booking_total_price").text($("#total_price").val()+' €'); | |||||
| }); | |||||
| }); | |||||
| @ -0,0 +1,155 @@ | |||||
| <?xml version="1.0" encoding="utf-8" ?> | |||||
| <odoo> | |||||
| <record model="ir.ui.view" id="partner_category_list"> | |||||
| <field name="name">partner category list</field> | |||||
| <field name="model">event.partner_category</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree> | |||||
| <field name="partner_category_id"/> | |||||
| <field name="status"/> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.ui.view" id="membership_product_list"> | |||||
| <field name="name">Membership product list</field> | |||||
| <field name="model">event.membership_product</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree> | |||||
| <field name="membership_product_id"/> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record id="booking_event_type_view_form" model="ir.ui.view"> | |||||
| <field name="name">event.type.view.form.inherit.booking</field> | |||||
| <field name="model">event.type</field> | |||||
| <field name="inherit_id" ref="event.view_event_type_form" /> | |||||
| <field name="arch" type="xml"> | |||||
| <xpath expr="//div[@class='oe_title']" position="after"> | |||||
| <div class="row o_settings_container" name="event_type_booking"> | |||||
| <div class="col-12 col-lg-8 o_setting_box"> | |||||
| <div class="o_setting_left_pane"> | |||||
| <field name="booking_event"/> | |||||
| </div> | |||||
| <div class="o_setting_right_pane"> | |||||
| <label for="booking_event"/> | |||||
| <div class="row mt16" attrs="{'invisible': [('booking_event', '=', False)]}"> | |||||
| <div class="col-12"> | |||||
| <label for="booking_questionnaire_id"/> | |||||
| <field name="booking_questionnaire_id"/> | |||||
| <field name="booking_option_ids" style="width: 100%;"> | |||||
| <tree string="Options" editable="bottom"> | |||||
| <field name="booking_option_id"/> | |||||
| <field name="booking_option_price" /> | |||||
| <field name="booking_option_member_price" /> | |||||
| <field name="booking_option_super_member_price" /> | |||||
| </tree> | |||||
| </field> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </xpath> | |||||
| </field> | |||||
| </record> | |||||
| <record id="booking_event_view_form" model="ir.ui.view"> | |||||
| <field name="name">event.view.form.inherit.booking</field> | |||||
| <field name="model">event.event</field> | |||||
| <field name="inherit_id" ref="event.view_event_form" /> | |||||
| <field name="arch" type="xml"> | |||||
| <xpath expr="//div[@class='oe_title']" position="after"> | |||||
| <div class="row o_settings_container" name="event_type_booking"> | |||||
| <div class="col-12 col-lg-2 o_setting_box"> | |||||
| <div class="o_setting_left_pane"> | |||||
| <field name="booking_event"/> | |||||
| </div> | |||||
| <div class="o_setting_right_pane"> | |||||
| <label for="booking_event"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </xpath> | |||||
| <xpath expr="//page[@name='tickets']" position="before"> | |||||
| <page string="Prices" name="booking" attrs="{'invisible':[('booking_event','=',False)]}"> | |||||
| <group style="width:25%%"> | |||||
| <field name="booking_product_id" attrs="{'required': [('booking_event','=', True)]}"/> | |||||
| <field name="booking_price" attrs="{'required': [('booking_event','=', True)]}"/> | |||||
| <field name="booking_member_price" attrs="{'required': [('booking_event','=', True)]}"/> | |||||
| <field name="booking_super_member_price" attrs="{'required': [('booking_event','=', True)]}"/> | |||||
| <field name="booking_down_payment" attrs="{'required': [('booking_event','=', True)]}"/> | |||||
| </group> | |||||
| </page> | |||||
| </xpath> | |||||
| <xpath expr="//page[@name='booking']" position="after"> | |||||
| <page string="Options" name="booking_options" attrs="{'invisible':[('booking_event','=',False)]}"> | |||||
| <group style="width:100%%"> | |||||
| <field name="booking_option_ids" style="width: 100%;"> | |||||
| <tree string="Options" editable="bottom"> | |||||
| <field name="booking_option_id"/> | |||||
| <field name="booking_option_price" /> | |||||
| <field name="booking_option_member_price" /> | |||||
| <field name="booking_option_super_member_price" /> | |||||
| </tree> | |||||
| </field> | |||||
| </group> | |||||
| </page> | |||||
| <page string="Questions" name="booking_questions" attrs="{'invisible':[('booking_event','=',False)]}"> | |||||
| <group style="width:100%%"> | |||||
| <field name="question_ids" style="width: 100%;"> | |||||
| <tree string="Questions" editable="bottom"> | |||||
| <field name="sequence" widget="handle"/> | |||||
| <field name="question" /> | |||||
| </tree> | |||||
| </field> | |||||
| </group> | |||||
| </page> | |||||
| </xpath> | |||||
| <xpath expr="//page[@name='tickets']" position="replace"> | |||||
| </xpath> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.actions.act_window" id="partner_category_action"> | |||||
| <field name="name">Partner categories</field> | |||||
| <field name="res_model">event.partner_category</field> | |||||
| <field name="view_mode">tree,form</field> | |||||
| </record> | |||||
| <record model="ir.actions.act_window" id="membership_product_action"> | |||||
| <field name="name">Membership product</field> | |||||
| <field name="res_model">event.membership_product</field> | |||||
| <field name="view_mode">tree,form</field> | |||||
| </record> | |||||
| <menuitem id="booking_title_menu" name ="Booking" | |||||
| parent="event.event_main_menu" groups="event.group_event_user" sequence="99"/> | |||||
| <menuitem id="booking_partner_category_menu" action="partner_category_action" | |||||
| parent="booking_title_menu" groups="event.group_event_user" sequence="2"/> | |||||
| <menuitem id="booking_membership_product__menu" action="membership_product_action" | |||||
| parent="booking_title_menu" groups="event.group_event_user" sequence="3"/> | |||||
| </odoo> | |||||
| @ -0,0 +1,208 @@ | |||||
| <odoo> | |||||
| <record model="ir.actions.act_window" id="action_view_event_registration_questionnaire"> | |||||
| <field name="name">Booking Questionnaire</field> | |||||
| <field name="res_model">event.registration_questionnaire</field> | |||||
| <field name="view_mode">tree,form</field> | |||||
| <field name="context">{'search_default_event_registration_id': active_id}</field> | |||||
| </record> | |||||
| <record id="event_registration_questionnaire_search" model="ir.ui.view"> | |||||
| <field name="name">event_registration_questionnaire.search</field> | |||||
| <field name="model">event.registration_questionnaire</field> | |||||
| <field name="arch" type="xml"> | |||||
| <search string="Search registrant"> | |||||
| <field name="event_registration_id"/> | |||||
| </search> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.actions.act_window" id="action_view_event_registration_option"> | |||||
| <field name="name">Booking Options</field> | |||||
| <field name="res_model">event.registration_option</field> | |||||
| <field name="view_mode">tree,form</field> | |||||
| <field name="context">{'search_default_event_registration_id': active_id}</field> | |||||
| </record> | |||||
| <record id="registration_action_orders" model="ir.actions.act_window"> | |||||
| <field name="name">Sales Orders</field> | |||||
| <field name="type">ir.actions.act_window</field> | |||||
| <field name="res_model">sale.order</field> | |||||
| <field name="view_mode">tree,kanban,form,calendar,pivot,graph,activity</field> | |||||
| <field name="search_view_id" ref="sale.sale_order_view_search_inherit_sale"/> | |||||
| <field name="context">{}</field> | |||||
| <field name="domain">[('state', 'not in', ('draft', 'sent', 'cancel'))]</field> | |||||
| <field name="help" type="html"> | |||||
| <p class="o_view_nocontent_smiling_face"> | |||||
| Create a new quotation, the first step of a new sale! | |||||
| </p><p> | |||||
| Once the quotation is confirmed, it becomes a sales order.<br/> You will be able to create an invoice and collect the payment. | |||||
| </p> | |||||
| </field> | |||||
| </record> | |||||
| <record id="event_registration_option_search" model="ir.ui.view"> | |||||
| <field name="name">event_registration_option.search</field> | |||||
| <field name="model">event.registration_option</field> | |||||
| <field name="arch" type="xml"> | |||||
| <search string="Search registrant"> | |||||
| <field name="event_registration_id"/> | |||||
| </search> | |||||
| </field> | |||||
| </record> | |||||
| <record id="event_registration_view_form" model="ir.ui.view"> | |||||
| <field name="name">event.type.view.form.inherit.booking</field> | |||||
| <field name="model">event.registration</field> | |||||
| <field name="inherit_id" ref="event.view_event_registration_form"/> | |||||
| <field name="arch" type="xml"> | |||||
| <xpath expr="//group[@name='attendee']" position="inside"> | |||||
| <field name="gender"/> | |||||
| <field name="age"/> | |||||
| <field name="medical_concern"/> | |||||
| <field name="medical_information"/> | |||||
| <field name="medical_contact_name"/> | |||||
| <field name="medical_contact_phone"/> | |||||
| <field name="room_id"/> | |||||
| <field name="down_payment"/> | |||||
| </xpath> | |||||
| <xpath expr="//div[@name='button_box']" position="inside"> | |||||
| <button name="%(action_view_event_registration_questionnaire)d" type="action" | |||||
| class="oe_stat_button" icon="fa-question" string="Questionnaire"> | |||||
| </button> | |||||
| </xpath> | |||||
| <xpath expr="//div[@name='button_box']" position="inside"> | |||||
| <button name="%(action_view_event_registration_option)d" type="action" | |||||
| class="oe_stat_button" icon="fa-bed" string="Options"> | |||||
| </button> | |||||
| </xpath> | |||||
| <xpath expr="//button[@name='action_cancel']" position="after"> | |||||
| <button name="action_event_registration_generate_order" type="object" | |||||
| states="open" string="Generate quotation(s)"> | |||||
| </button> | |||||
| </xpath> | |||||
| <xpath expr="//group[@name='event']" position="after"> | |||||
| <group string="Payments" name="payments"> | |||||
| <field name="order_id"/> | |||||
| <field name="down_payment_order_id"/> | |||||
| <field name="balance_order_id"/> | |||||
| </group> | |||||
| </xpath> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.ui.view" id="event_registration_questionnaire_list" > | |||||
| <field name="name">event registration questionnaire List</field> | |||||
| <field name="model">event.registration_questionnaire</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree editable="bottom"> | |||||
| <field name="question"/> | |||||
| <field name="answer"/> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.ui.view" id="event_registration_option_list" > | |||||
| <field name="name">event registration option List</field> | |||||
| <field name="model">event.registration_option</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree editable="bottom"> | |||||
| <field name="booking_option_id"/> | |||||
| <!-- <field name="booking_option_price"/> --> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record id="event_registration_view_kanban" model="ir.ui.view"> | |||||
| <field name="name">booking.event.registration.kanban.inherit</field> | |||||
| <field name="model">event.registration</field> | |||||
| <field name="inherit_id" ref="event.event_registration_view_kanban"/> | |||||
| <field name="arch" type="xml"> | |||||
| <xpath expr="//field[@name='email']" position="after"> | |||||
| <field name="room_id" /> | |||||
| </xpath> | |||||
| <xpath expr="//field[@name='event_ticket_id']" position="after"> | |||||
| <field name="kanban_color" /> | |||||
| </xpath> | |||||
| <xpath expr="//kanban[@class='o_event_attendee_kanban_view']" position="attributes"> | |||||
| <attribute name="default_group_by">room_id</attribute> | |||||
| </xpath> | |||||
| <!-- <xpath expr="/kanban/templates/t[3]/div/div/div/div/div/span" position="replace"> | |||||
| <span attrs="{'invisible': [('partner_id', '=', False)]}">Booked by <field name="partner_id" /> (<field name="gender" />)</span> | |||||
| </xpath> --> | |||||
| <xpath expr="/kanban/templates/t[3]/div" position="replace"> | |||||
| <!-- <attribute name="style">background-color:red</attribute> --> | |||||
| <div t-attf-class="oe_kanban_global_click oe_kanban_color_#{record.kanban_color.raw_value} o_event_registration_kanban container-fluid p-0" t-attf-style="background-color:##{record.kanban_color.raw_value};"> | |||||
| <div class="row h-100"> | |||||
| <div class="col-9 pr-0"> | |||||
| <div class="oe_kanban_content h-100"> | |||||
| <div class="o_kanban_record_body pt-1 pl-2 h-100 d-flex flex-column"> | |||||
| <b class="o_kanban_record_title"><field name="name"/></b> | |||||
| <field name="event_id" invisible="context.get('default_event_id')" /> | |||||
| <span attrs="{'invisible': [('partner_id', '=', False)]}">Booked by <field name="partner_id" /></span> | |||||
| <div id="event_ticket_id" class="o_field_many2manytags o_field_widget d-flex mt-auto"> | |||||
| <t t-if="record.event_ticket_id.raw_value"> | |||||
| <div t-attf-class="badge badge-pill o_tag_color_#{(record.event_ticket_id.raw_value % 11) + 1}" > | |||||
| <b><span class="o_badge_text"><t t-esc="record.event_ticket_id.value"/></span></b> | |||||
| </div> | |||||
| </t> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div id="event_attendees_kanban_icons" class="col-3 pl-0"> | |||||
| <t t-call="event_attendees_kanban_icons_desktop"/> | |||||
| <t t-call="event_attendees_kanban_icons_mobile"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </xpath> | |||||
| </field> | |||||
| </record> | |||||
| <record id="event_registration_view_tree" model="ir.ui.view"> | |||||
| <field name="name">booking.event.registration.tree.inherit</field> | |||||
| <field name="model">event.registration</field> | |||||
| <field name="inherit_id" ref="event.view_event_registration_tree"/> | |||||
| <field name="arch" type="xml"> | |||||
| <xpath expr="//field[@name='event_ticket_id']" position="replace"> | |||||
| <field name="room_id" /> | |||||
| <field name="payment_status" /> | |||||
| </xpath> | |||||
| </field> | |||||
| </record> | |||||
| <record id="view_registration_search" model="ir.ui.view"> | |||||
| <field name="name">event.registration.search.inherit</field> | |||||
| <field name="model">event.registration</field> | |||||
| <field name="inherit_id" ref="event.view_registration_search"/> | |||||
| <field name="arch" type="xml"> | |||||
| <xpath expr="//filter[@name='partner']" position="after"> | |||||
| <filter string="Room" name="room_id" domain="[]" context="{'group_by':'room_id'}"/> | |||||
| </xpath> | |||||
| </field> | |||||
| </record> | |||||
| </odoo> | |||||
| @ -0,0 +1,33 @@ | |||||
| <odoo> | |||||
| <template id="events_list" inherit_id="website_event.events_list"> | |||||
| <xpath expr="//time[@itemprop='startDate']" position="after"> | |||||
| <t t-if="event.booking_event"> | |||||
| <time itemprop="endDate" t-att-datetime="event.date_end"> | |||||
| <span t-field="event.with_context(tz=event.date_tz).date_end" t-options="{'date_only': 'true', 'format': 'long'}"/> | |||||
| </time> | |||||
| <br/> | |||||
| <b><font style="color: rgb(255, 0, 0); font-size: 11px;">Non adhérent : <span t-esc="int(event.booking_price)"/> €</font> | |||||
| <font style="color: rgb(255, 0, 0); font-size: 11px;"> Adhérent et autres : <span t-esc="int(event.booking_member_price)"/> €</font> | |||||
| <br/><font style="color: rgb(255, 0, 0); font-size: 11px;">Soutien et Sangha : <span t-esc="int(event.booking_super_member_price)"/> €</font></b> | |||||
| </t> | |||||
| </xpath> | |||||
| <xpath expr="//time[@itemprop='startDate']" position="replace"> | |||||
| <t t-if="event.booking_event"> | |||||
| <span t-field="event.with_context(tz=event.date_tz).date_begin" t-options="{'date_only': 'true', 'format': 'long'}"/> - | |||||
| </t> | |||||
| <t t-if="not event.booking_event"> | |||||
| <time itemprop="startDate" t-att-datetime="event.date_begin"> | |||||
| <span t-field="event.with_context(tz=event.date_tz).date_begin" t-options="{'date_only': 'true', 'format': 'long'}"/> - | |||||
| <span t-field="event.with_context(tz=event.date_tz).date_begin" t-options="{'time_only': 'true', 'format': 'short'}"/> | |||||
| </time> | |||||
| </t> | |||||
| </xpath> | |||||
| </template> | |||||
| </odoo> | |||||
| @ -0,0 +1,62 @@ | |||||
| <odoo> | |||||
| <!-- on affiche pas les informations de tickets comme le prix ou gratuit --> | |||||
| <!-- <template id="booking.event_sale_registration_template" inherit_id="website_event_sale.registration_template"> | |||||
| <xpath expr="//div[@class='px-2 text-dark mr-2 border-right d-flex align-items-center align-self-stretch']" position="replace"> | |||||
| </xpath> | |||||
| </template> --> | |||||
| <template id="event_registration_template" inherit_id="website_event.registration_template"> | |||||
| <xpath expr="//div[@class='col-lg-4 pt-3 pt-lg-0 pl-2 pl-lg-0']" position="replace"> | |||||
| <t t-if="event.booking_event"> | |||||
| <div class="col-lg-4 pt-3 pt-lg-0 pl-2 pl-lg-0"> | |||||
| <a t-attf-id="#{event.id}" t-attf-href="/booking/registration/options?event_id={{event.id}}" class="btn btn-primary btn-block" data-original-title="" title="" aria-describedby="tooltip34075">Register</a> | |||||
| </div> | |||||
| </t> | |||||
| <t t-if="not event.booking_event"> | |||||
| <div class="col-lg-4 pt-3 pt-lg-0 pl-2 pl-lg-0"> | |||||
| <a t-attf-id="#{event.id}" t-attf-href="/event/registration/step1?event_id={{event.id}}" class="btn btn-primary btn-block" data-original-title="" title="" aria-describedby="tooltip34075">Register</a> | |||||
| </div> | |||||
| <t t-if="event.seats_limited and event.seats_max and event.seats_available <= (event.seats_max * 0.2)"> | |||||
| (only <t t-esc="event.seats_available"/> available) | |||||
| </t> | |||||
| </t> | |||||
| </xpath> | |||||
| <!-- on bloque la qte à 1 --> | |||||
| <xpath expr="//select[@class='w-auto custom-select']" position="replace"> | |||||
| <select t-att-name="'nb_register-%s' % (tickets.id if tickets else 0)" class="w-auto custom-select"> | |||||
| <t t-set="seats_max_ticket" t-value="(not tickets or not tickets.seats_limited or tickets.seats_available > 9) and 10 or tickets.seats_available + 1"/> | |||||
| <t t-set="seats_max_event" t-value="(not event.seats_limited or event.seats_available > 9) and 10 or event.seats_available + 1"/> | |||||
| <t t-set="seats_max" t-value="min(seats_max_ticket, seats_max_event) if tickets else seats_max_event"/> | |||||
| <option t-esc="1"/> | |||||
| </select> | |||||
| </xpath> | |||||
| </template> | |||||
| <template id="booking.event_description_full" inherit_id="website_event.event_description_full"> | |||||
| <xpath expr="//div[@class='o_wevent_sidebar_block'][1]" position="before"> | |||||
| <t t-if="event.booking_event"> | |||||
| <div class="o_wevent_sidebar_block"> | |||||
| <h6 class="o_wevent_sidebar_title">Participation</h6> | |||||
| <h7 t-esc="'Non adhérent : '+str(int(event.booking_price))+' €'"/> | |||||
| <br/> | |||||
| <h7 t-esc="'Adhérent et autres : '+str(int(event.booking_member_price))+' €'"/> | |||||
| <br/> | |||||
| <h7 t-esc="'Soutien et Sangha : '+str(int(event.booking_super_member_price))+' €'"/> | |||||
| </div> | |||||
| </t> | |||||
| </xpath> | |||||
| </template> | |||||
| </odoo> | |||||
| @ -0,0 +1,32 @@ | |||||
| <odoo> | |||||
| <data> | |||||
| <!-- explicit list view definition --> | |||||
| <record model="ir.ui.view" id="location_list"> | |||||
| <field name="name">booking_location list</field> | |||||
| <field name="model">booking.location</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree> | |||||
| <field name="name"/> | |||||
| <field name="description"/> | |||||
| <field name="capacity"/> | |||||
| <field name="available_seats"/> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.actions.act_window" id="location_action"> | |||||
| <field name="name">Locations</field> | |||||
| <field name="res_model">booking.location</field> | |||||
| <field name="view_mode">tree,form</field> | |||||
| </record> | |||||
| <menuitem id="booking_location_menu" action="location_action" | |||||
| parent="booking_title_menu" groups="event.group_event_user" sequence="1"/> | |||||
| <menuitem action="product.product_template_action" id="menu_booking_product_template_action" | |||||
| parent="booking_title_menu" sequence="1"/> | |||||
| </data> | |||||
| </odoo> | |||||
| @ -0,0 +1,38 @@ | |||||
| <?xml version="1.0" encoding="utf-8" ?> | |||||
| <odoo> | |||||
| <record id="product_template_search_view" model="ir.ui.view"> | |||||
| <field name="name">booking.product.template.search</field> | |||||
| <field name="model">product.template</field> | |||||
| <field name="inherit_id" ref="product.product_template_search_view" /> | |||||
| <field name="arch" type="xml"> | |||||
| <filter name="filter_to_purchase" position="after"> | |||||
| <filter | |||||
| name="filter_booking_product" | |||||
| string="Booking products" | |||||
| domain="[('booking_product', '=', True)]" | |||||
| /> | |||||
| <filter | |||||
| name="filter_booking_product_options" | |||||
| string="Booking option products" | |||||
| domain="[('booking_option_product', '=', True)]" | |||||
| /> | |||||
| </filter> | |||||
| </field> | |||||
| </record> | |||||
| <record id="product_template_form_view" model="ir.ui.view"> | |||||
| <field name="name">booking.product.template.form</field> | |||||
| <field name="model">product.template</field> | |||||
| <field name="inherit_id" ref="product.product_template_form_view" /> | |||||
| <field name="arch" type="xml"> | |||||
| <div name="options" position="inside"> | |||||
| <field name="booking_product" /> | |||||
| <label for="booking_product" /> | |||||
| <field name="booking_option_product" /> | |||||
| <label for="booking_option_product" /> | |||||
| </div> | |||||
| </field> | |||||
| </record> | |||||
| </odoo> | |||||
| @ -0,0 +1,57 @@ | |||||
| <odoo> | |||||
| <data> | |||||
| <record model="ir.ui.view" id="questionnaire_list"> | |||||
| <field name="name">booking_questionnaire list</field> | |||||
| <field name="model">booking.questionnaire</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree> | |||||
| <field name="name"/> | |||||
| <field name="description"/> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.ui.view" id="questionnaire_form" > | |||||
| <field name="name">booking_questionnaire Form</field> | |||||
| <field name="model">booking.questionnaire</field> | |||||
| <field name="arch" type="xml"> | |||||
| <form string="questionnaire_form" delete="0" create="0"> | |||||
| <sheet> | |||||
| <group name="questionnaire"> | |||||
| <field name="name"/> | |||||
| <field name="description"/> | |||||
| </group> | |||||
| <group name="questions"> | |||||
| <field name="question_ids"> | |||||
| <tree editable="bottom"> | |||||
| <field name="sequence" widget="handle"/> | |||||
| <field name="question"/> | |||||
| </tree> | |||||
| </field> | |||||
| </group> | |||||
| </sheet> | |||||
| </form> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.actions.act_window" id="questionnaire_action"> | |||||
| <field name="name">questionnaire</field> | |||||
| <field name="res_model">booking.questionnaire</field> | |||||
| <field name="view_mode">tree,form</field> | |||||
| </record> | |||||
| <menuitem name="questionnaire" | |||||
| id="menu_event_questionnaire" | |||||
| sequence="10" | |||||
| parent="event.event_main_menu" | |||||
| action="questionnaire_action" | |||||
| groups="event.group_event_user"/> | |||||
| </data> | |||||
| </odoo> | |||||
| @ -0,0 +1,2 @@ | |||||
| <odoo> | |||||
| </odoo> | |||||
| @ -0,0 +1,101 @@ | |||||
| <odoo> | |||||
| <data> | |||||
| <!-- explicit list view definition --> | |||||
| <record model="ir.ui.view" id="room_list"> | |||||
| <field name="name">booking_room list</field> | |||||
| <field name="model">booking.room</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree> | |||||
| <field name="name"/> | |||||
| <field name="location_id"/> | |||||
| <field name="description"/> | |||||
| <field name="capacity"/> | |||||
| <field name="available_seats"/> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.actions.act_window" id="room_action"> | |||||
| <field name="name">Rooms</field> | |||||
| <field name="res_model">booking.room</field> | |||||
| <field name="view_mode">tree,form</field> | |||||
| </record> | |||||
| <menuitem id="booking_room_menu" action="room_action" | |||||
| parent="booking_title_menu" groups="event.group_event_user" sequence="2"/> | |||||
| <record model="ir.ui.view" id="room_occupation_list"> | |||||
| <field name="name">booking_room_occupation list</field> | |||||
| <field name="model">booking.room.occupation</field> | |||||
| <field name="arch" type="xml"> | |||||
| <tree> | |||||
| <field name="room_id"/> | |||||
| <field name="name"/> | |||||
| <field name="event_id"/> | |||||
| <field name="date_begin"/> | |||||
| <field name="date_end"/> | |||||
| </tree> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.ui.view" id="room_occupation_form" > | |||||
| <field name="name">booking_room_occupation Form</field> | |||||
| <field name="model">booking.room.occupation</field> | |||||
| <field name="arch" type="xml"> | |||||
| <form string=""> | |||||
| <sheet> | |||||
| <group name="main"> | |||||
| <field name="room_id"/> | |||||
| <field name="event_id"/> | |||||
| <field name="event_registration_id"/> | |||||
| </group> | |||||
| </sheet> | |||||
| </form> | |||||
| </field> | |||||
| </record> | |||||
| <record id="view_room_occupation_search" model="ir.ui.view"> | |||||
| <field name="name">room.occupation.search</field> | |||||
| <field name="model">booking.room.occupation</field> | |||||
| <field name="priority">1</field> | |||||
| <field name="arch" type="xml"> | |||||
| <search string="Search Room"> | |||||
| <field string="Room" name="room_id"/> | |||||
| </search> | |||||
| </field> | |||||
| </record> | |||||
| <record model="ir.actions.act_window" id="room_occupation_action"> | |||||
| <field name="name">Rooms occupation</field> | |||||
| <field name="res_model">booking.room.occupation</field> | |||||
| <field name="view_mode">tree,form,pivot</field> | |||||
| </record> | |||||
| <record id="action_registration" model="ir.actions.act_window"> | |||||
| <field name="name">Room occupation</field> | |||||
| <field name="res_model">event.registration</field> | |||||
| <field name="domain"></field> | |||||
| <field name="view_mode">kanban,pivot,graph,tree,form</field> | |||||
| <field name="context">{}</field> | |||||
| <field name="domain">[('booking_event','=',True),('event_end','=',False)]</field> | |||||
| <field name="search_view_id" ref="event.view_registration_search"/> | |||||
| </record> | |||||
| <menuitem id="booking_room_occupation_menu" action="action_registration" | |||||
| parent="booking_title_menu" groups="event.group_event_user" sequence="3"/> | |||||
| </data> | |||||
| </odoo> | |||||
| @ -0,0 +1,319 @@ | |||||
| <odoo> | |||||
| <template id="assets_frontend" name="booking assets" inherit_id="web.assets_frontend"> | |||||
| <xpath expr="." position="inside"> | |||||
| <script type="text/javascript" src="/booking/static/js/booking.js"></script> | |||||
| </xpath> | |||||
| </template> | |||||
| <template id="registration_options_form" name="Registration options form"> | |||||
| <t t-call="website.layout"> | |||||
| <div class="container-fluid"> | |||||
| <h4 style="display: inline">Registering to : </h4><h4 style="display: inline" t-esc="event.name"></h4> | |||||
| <h6>From <span t-field="event.date_begin" t-options='{"format": "dd/mm/yyyy hh:mm"}'/> to <span t-field="event.date_end" t-options='{"format": "dd/MM/yyyy hh:mm"}'/> </h6> | |||||
| <h6> Your status : <span id="your_status" t-esc='status'></span></h6> | |||||
| <h6>Price of the stay : <span id="price_of_the_stay" t-esc="str(int(price))+ ' €'"></span> | |||||
| (standard price : <span t-esc="str(int(int(event.booking_price)))+ ' €'"></span> | |||||
| , member price : <span t-esc="str(int(int(event.booking_member_price)))+ ' €'"></span> | |||||
| , super member price : <span t-esc="str(int(int(event.booking_super_member_price)))+ ' €'"></span>)</h6> | |||||
| <h6>Please select your booking options :</h6> | |||||
| <form action="questionnaire" method="post" class="form js_website_submit_form"> | |||||
| <input type="hidden" id="booking_price_product" name="price_product" t-att-value="int(price)"/> | |||||
| <input type="hidden" id="booking_price" name="booking_price" t-att-value="int(event.booking_price)"/> | |||||
| <input type="hidden" id="booking_member_price" name="booking_member_price" t-att-value="int(event.booking_member_price)"/> | |||||
| <input type="hidden" id="booking_super_member_price" name="booking_super_member_price" t-att-value="int(event.booking_super_member_price)"/> | |||||
| <input type="hidden" id="total_price" name="total_price" t-att-value="int(price)"/> | |||||
| <input type="hidden" name="event_id" t-att-value="event.id"/> | |||||
| <input type="hidden" id="status" name="status" t-att-value="status"/> | |||||
| <input type="hidden" id="status2" name="status2" t-att-value="status"/> | |||||
| <input type="hidden" id="membership_product" name="membership_product" t-att-value="int(membership_product.membership_product_id)"/> | |||||
| <t t-if="options"> | |||||
| <table class='table' width='50%'> | |||||
| <thead> | |||||
| <tr> | |||||
| <th>Selection</th> | |||||
| <th>Option</th> | |||||
| <th>Standard price</th> | |||||
| <th>Member price</th> | |||||
| <th>Super member price</th> | |||||
| </tr> | |||||
| </thead> | |||||
| <t t-set="i" t-value="1"/> | |||||
| <t t-foreach="options" t-as="option"> | |||||
| <tr> | |||||
| <td><input type="checkbox" t-att-name="'o['+str(i)+']'" t-att-value="int(option.booking_option_id)" t-att-id="'o['+str(i)+']'" /></td> | |||||
| <td><span t-field="option.name"/></td> | |||||
| <td><span t-esc="str(int(option.booking_option_price))+' €'"/></td> | |||||
| <td><span t-esc="str(int(option.booking_option_member_price))+' €'"/></td> | |||||
| <td><span t-esc="str(int(option.booking_option_super_member_price))+' €'"/></td> | |||||
| </tr> | |||||
| <input type="hidden" t-att-id="'o_standard'+str(i)" t-att-name="'o_standard['+str(i)+']'" t-att-value="int(option.booking_option_price)"/> | |||||
| <input type="hidden" t-att-id="'o_member'+str(i)" t-att-name="'o_member['+str(i)+']'" t-att-value="int(option.booking_option_member_price)"/> | |||||
| <input type="hidden" t-att-id="'o_super_member'+str(i)" t-att-name="'o_super_member['+str(i)+']'" t-att-value="int(option.booking_option_super_member_price)"/> | |||||
| <t t-set="i" t-value="i+1"/> | |||||
| </t> | |||||
| <input type="hidden" name="nb_o" t-att-value="i-1"/> | |||||
| </table> | |||||
| </t> | |||||
| <t t-if="not options"> | |||||
| <input type="hidden" name="nb_o" value="0"/> | |||||
| </t> | |||||
| <h4>Total Price : <span id="booking_total_price"></span></h4> | |||||
| <span>Do you want to pay only the deposit </span><span style="display:inline" t-esc="'('+str(int(event.booking_down_payment))+' €) ?'"/> | |||||
| <div class="form-group s_website_form_field col-2 s_website_form_custom s_website_form_required" data-type="char" data-name="Field"> | |||||
| <select id="down_payment" name="down_payment" class="form-control s_website_form_input"> | |||||
| <option name="yes" value="true" label="Oui"></option> | |||||
| <option name="no" selected="false" value="false" label="Non"></option> | |||||
| </select> | |||||
| </div> | |||||
| <section class="s_website_form pt16 pb16 o_colored_level"> | |||||
| <h6>Participant :</h6> | |||||
| <div class="form-group s_website_form_field col-4 s_website_form_custom s_website_form_required " data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Name</span> | |||||
| <span class="s_website_form_mark"> *</span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" name="name" t-att-value="partner.name" required="1" id="name" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-4 s_website_form_custom s_website_form_required " data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">First name</span> | |||||
| <span class="s_website_form_mark"> *</span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" name="firstname" t-att-value="partner.firstname" required="1" id="firstname" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-3 s_website_form_custom s_website_form_required" data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Age</span> | |||||
| <span class="s_website_form_mark"> *</span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="number" class="form-control s_website_form_input" name="age" required="1" id="age" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-4 s_website_form_custom s_website_form_required" data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Gender</span> | |||||
| <span class="s_website_form_mark"> *</span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <select id="gender" name="gender" class="form-control s_website_form_input"> | |||||
| <option name="male" value="male" label="Homme"></option> | |||||
| <option name="femelle" value="femelle" label="Femme"></option> | |||||
| </select> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-4 s_website_form_custom " data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Phone</span> | |||||
| <span class="s_website_form_mark"></span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" name="phone" t-att-value="partner.phone" id="phone" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-4 s_website_form_custom" data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Mobile</span> | |||||
| <span class="s_website_form_mark"></span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" name="mobile" t-att-value="partner.mobile" id="mobile" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-5 s_website_form_custom" data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">email</span> | |||||
| <span class="s_website_form_mark"></span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" name="email" readonly="readonly" t-att-value="partner.email" id="email" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <button id="back_button1" type="button" class="btn btn-warning" >back</button> | |||||
| <button type="submit" class="btn btn-primary" >Continue</button> | |||||
| <br/> | |||||
| </section> | |||||
| </form> | |||||
| </div> | |||||
| </t> | |||||
| </template> | |||||
| <template id="registration_questionnaire_form" name="Registration questionnaire form"> | |||||
| <t t-call="website.layout"> | |||||
| <div class="container-fluid"> | |||||
| <h4 t-esc="'Inscription à : '+event.name"></h4> | |||||
| <h6><u>Health quiz</u></h6> | |||||
| <form action="/booking/payment_choice" method="post" class="form js_website_submit_form"> | |||||
| <input type="hidden" name="event_id" t-att-value="event.id"/> | |||||
| <div class="form-group s_website_form_field col-6 s_website_form_custom s_website_form_required" data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Medical concern</span> | |||||
| <span class="s_website_form_mark"> *</span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <select id="medical_concern" name="medical_concern" class="form-control s_website_form_input"> | |||||
| <option name="medical_concern" value="have medical concern" label="J'ai un soucis médical à signaler"></option> | |||||
| <option name="medical_concern" selected="selected" value="have no medical concern" label="Je n'ai pas de soucis médical à signaler"></option> | |||||
| <option name="medical_concern" value="no answer" label="Je ne veux pas répondre"></option> | |||||
| </select> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div id='medical_info'> | |||||
| <div id="medical_info_div" class="form-group s_website_form_field col-6 s_website_form_custom" data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Informations de nature médicale utiles à connaître (allergies, prise de médicaments, contre-indications…)</span> | |||||
| <span class="s_website_form_mark"></span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <textarea class="form-control s_website_form_input" rows="5" name="medical_information" value="" id="medical_information" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-6 s_website_form_custom" data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Name of the medical contact</span> | |||||
| <span class="s_website_form_mark"></span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" name="medical_contact_name" value="" id="medical_contact_name" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="form-group s_website_form_field col-6 s_website_form_custom " data-type="char" data-name="Field"> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px" for="9ois9pkv0wv"> | |||||
| <span class="s_website_form_label_content">Phone of the medical contact</span> | |||||
| <span class="s_website_form_mark"></span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" name="medical_contact_phone" value="" id="medical_contact_phone" style="cursor: auto;"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <br/> | |||||
| <t t-if="questions"> | |||||
| <h6><u>Questionnaire :</u></h6> | |||||
| <t t-set="i" t-value="1"/> | |||||
| <t t-foreach="questions" t-as="question"> | |||||
| <div class="form-group s_website_form_field col-6 s_website_form_custom s_website_form_required "> | |||||
| <div class="row s_col_no_resize s_col_no_bgcolor"> | |||||
| <label class="col-form-label col-sm-auto s_website_form_label" style="width: 200px"> | |||||
| <span class="s_website_form_label_content" t-esc="question.question"></span> | |||||
| </label> | |||||
| <div class="col-sm"> | |||||
| <input type="text" class="form-control s_website_form_input" t-att-name="'a['+str(i)+']'" t-att-id="'#a'+str(question.id)"/> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <input type="hidden" t-att-name="'q['+str(i)+']'" t-att-value="question.question"/> | |||||
| <t t-set="i" t-value="i+1"/> | |||||
| </t> | |||||
| <input type="hidden" name="nb_q" t-att-value="i"/> | |||||
| </t> | |||||
| <t t-if="not questions"> | |||||
| <input type="hidden" name="nb_q" value="0"/> | |||||
| </t> | |||||
| <div class="row"> | |||||
| <div class="col"> | |||||
| <br/> | |||||
| <button id="back_button2" type="button" class="btn btn-warning" >back</button> | |||||
| <button type="submit" class="btn btn-primary" >Continue</button> | |||||
| <br/> | |||||
| </div> | |||||
| </div> | |||||
| </form> | |||||
| </div> | |||||
| </t> | |||||
| </template> | |||||
| <template id="payment_choice_form" name="payment choice form"> | |||||
| <t t-call="website.layout"> | |||||
| <div class="container-fluid"> | |||||
| <div id="payment_method" class="mt-3 col-lg-6"> | |||||
| <h4 class="mb24">Pay with </h4> | |||||
| <t t-call="payment.payment_tokens_list"> | |||||
| <t t-set="mode" t-value="'payment'"/> | |||||
| <t t-set="submit_txt" t-value="submit_txt"/> | |||||
| <t t-set="icon_right" t-value="1"/> | |||||
| <t t-set="icon_class" t-value="'fa-chevron-right'"/> | |||||
| <t t-set="submit_class" t-value="'btn btn-primary fa fa-gift'"/> | |||||
| <t t-set="pms" t-value="tokens"/> | |||||
| <t t-set="acquirers" t-value="acquirers"/> | |||||
| <t t-set="order_id" t-value="order_id"/> | |||||
| <t t-set="form_action" t-value="'/booking/payment/token'"/> | |||||
| <t t-set="prepare_tx_url" t-value="'/booking/payment/transaction/'"/> | |||||
| <t t-set="partner_id" t-value="partner"/> | |||||
| <t t-set="back_button_icon_class" t-value="'fa-chevron-left'"/> | |||||
| <t t-set="back_button_class" t-value="'btn btn-secondary'"/> | |||||
| <t t-set="back_button_link" t-value="'/shop/cart'"/> | |||||
| </t> | |||||
| </div> | |||||
| </div> | |||||
| </t> | |||||
| </template> | |||||
| <template id="thankyou" name="booking form"> | |||||
| <t t-call="website.layout"> | |||||
| <div class="container-fluid"> | |||||
| <h2>Thank you for your registration !</h2> | |||||
| <a href="/" class="ml-4 btn btn-secondary">back Home</a> | |||||
| </div> | |||||
| </t> | |||||
| </template> | |||||
| </odoo> | |||||