from odoo import models, fields, api,_ from odoo.exceptions import UserError, ValidationError,Warning from psycopg2 import sql, DatabaseError from pytz import timezone from werkzeug import utils import os.path from google.oauth2 import service_account from googleapiclient.discovery import build from datetime import datetime, timedelta import json # IF YOU MODIFY THE SCOPE DELETE THE TOKEN.TXT FILE SCOPES = ['https://www.googleapis.com/auth/calendar'] SERVICE_ACCOUNT_FILE = '/usr/lib/python3/dist-packages/odoo/kalachakra_module/kalachakra/models/creds.json' # You should make it an environment variable SUBJECT = 'kalachakra-srv@kalachakra-351613.iam.gserviceaccount.com' class EventTagCategory(models.Model): _inherit = "event.tag.category" _description = 'Event tag category' calendar_id=fields.Char('google calendar id') class KalachakraEvent(models.Model): _inherit = "event.event" _description = 'Event' calendar_id=fields.Char('calendar id') calendar_event_id=fields.Char('event id') free_participation=fields.Boolean('Free participation') participation_product_id=fields.Many2one('product.product',string='participation product') participation_standard_price=fields.Monetary('Standard Price',currency_field='currency_id') participation_member_price=fields.Monetary('Member price',currency_field='currency_id') participation_super_member_price=fields.Monetary('Super member price',currency_field='currency_id') subscription_product_id=fields.Many2one('product.product',string='subscription product') subscription_standard_price=fields.Monetary('Standard Price',currency_field='currency_id') subscription_member_price=fields.Monetary('Member price',currency_field='currency_id') subscription_super_member_price=fields.Monetary('Super member price',currency_field='currency_id') recurring_event=fields.Boolean('Recurring event') recurring_event_newsletter_id=fields.Many2one('mailing.list',string='Recurring event Newsletter') online_event=fields.Boolean('Online event') online_link=fields.Char('link') online_id=fields.Char('id') online_password=fields.Char('password') duration=fields.Integer('duration', compute="_compute_duration") frequency=fields.Selection(string='Frequency',selection=[('daily', 'Daily'), ('weekly', 'Weekly')]) weekly_day=fields.Selection(string='Weekly day',selection=[('monday', 'Monday'),('tuesday', 'Tuesday'),('wednesday', 'Wednesday'),('thursday', 'Thursday'),('friday', 'Friday'),('saturday', 'Saturday'),('sunday', 'Sunday') ]) end_generation_date=fields.Datetime('End generation date') generated_events=fields.Boolean('generated_ events', compute='_compute_generated_events') #for event generated from a parent event parent_event_id=fields.Many2one('event.event',string='parent event', readonly=True) def _compute_generated_events(self): for rec in self: rec.generated_events=False evt=rec.env['event.event'].search([('parent_event_id','=', int(rec.id))]) if evt:rec.generated_events=True def remove_generated_events(self): evt=self.env['event.event'].search([('parent_event_id','=', int(self.id))]) if evt: for e in evt: e.remove_event_from_google_agenda() e.unlink() def generate_events(self): for rec in self: if rec.duration>1 :raise Warning('action cancelled: the duration f the event is more than 1 days !') if rec.end_generation_date100:raise Warning('action cancelled: the duration f the event is more than 100 days !') if rec.frequency=='daily':d=1 if rec.frequency=='weekly':d=7 start_date_event=rec.date_begin+timedelta(days=d) end_date_event=rec.date_end+timedelta(days=d) while start_date_event<=rec.end_generation_date: if not start_date_event.weekday() in (5,6): #avant de dupliquer l'événement on regarde si celui-ci n'a pas déjà été crée ! evt=self.env['event.event'].search([('date_begin','=',start_date_event),('parent_event_id','=', int(self.id))]) if evt: raise Warning('action cancelled: event already generated with this date :'+ str(start_date_event)) dup=self._create_event(rec,start_date_event,end_date_event) dup.add_event_to_google_agenda() end_date_event=end_date_event+timedelta(days=d) start_date_event=start_date_event+timedelta(days=d) def _create_event(self,rec,start_date_event,end_date_event): vals={} vals['name']=rec.name vals['date_begin']=start_date_event vals['date_end']=end_date_event vals['description']=rec.description vals['tag_ids']=rec.tag_ids vals['event_logo']=rec.event_logo vals['is_published']=True vals['free_participation']=rec.free_participation vals['participation_product_id']=rec.participation_product_id vals['participation_standard_price']=rec.participation_standard_price vals['participation_member_price']=rec.participation_member_price vals['participation_super_member_price']=rec.participation_super_member_price vals['subscription_product_id']=rec.subscription_product_id vals['subscription_standard_price']=rec.subscription_standard_price vals['subscription_member_price']=rec.subscription_member_price vals['subscription_super_member_price']=rec.subscription_super_member_price vals['recurring_event']=rec.recurring_event vals['recurring_event_newsletter_id']=rec.recurring_event_newsletter_id vals['online_event']=rec.online_event vals['online_link']=rec.online_link vals['online_id']=rec.online_id vals['online_password']=rec.online_password vals['parent_event_id']=rec.id vals['cover_properties']=rec.cover_properties ev=self.env['event.event'].create(vals) return ev def _compute_duration(self): for rec in self: duration = rec.date_end-rec.date_begin rec.duration = duration.days 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') 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.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)] @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 ) media_link_ids=fields.One2many( 'event.media.link', 'event_id', string='Media links' ) def add_event_to_google_agenda(self): credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES) delegated_credentials = credentials.with_subject(SUBJECT) service = build('calendar', 'v3', credentials=delegated_credentials) start=self.date_begin.astimezone(timezone('Europe/Paris')) end=self.date_end.astimezone(timezone('Europe/Paris')) start=start.isoformat() end=end.isoformat() diff_date=self.date_end-self.date_begin if diff_date.days>0: date_param=self.date_begin.strftime('%Y-%m-%d')+'-'+self.date_end.strftime('%Y-%m-%d')+'-'+str(self.id) else: date_param=self.date_begin.strftime('%Y-%m-%d')+'-'+str(self.id) name_param=self.name.replace(' ','-') name_param=name_param.replace('\'','-') description='Click here to register' #str(self.date_begin.year())+'-'+str(self.date_begin.month())+'-'+self.date_begin.day() body={"summary": self.name, "description": description, "start": {"dateTime": start, "timeZone": 'Europe/Paris'}, "end": {"dateTime": end, "timeZone": 'Europe/Paris'}, } #recherche de l'id calendar lié à l'étiquette de l'événément calendar_find=False for tag in self.tag_ids: if tag.category_id.calendar_id: calendar_find=True event = service.events().insert(calendarId=tag.category_id.calendar_id, body=body).execute() self.calendar_event_id=event['id'] self.calendar_id=tag.category_id.calendar_id if not calendar_find: raise Warning('operation cancelled: no calendar id find, please selected a label wih category with a calendar_id') def remove_event_from_google_agenda(self): credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES) delegated_credentials = credentials.with_subject(SUBJECT) service = build('calendar', 'v3', credentials=delegated_credentials) event = service.events().get(calendarId=self.calendar_id, eventId=self.calendar_event_id).execute() #raise Warning(json.dumps(event, indent = 4) ) if event['status'] != "cancelled" : service.events().delete(calendarId=self.calendar_id, eventId=self.calendar_event_id).execute() self.calendar_event_id=False self.calendar_id=False