[IMP] removed categories in tags , fix
[odoo/odoo.git] / addons / base_calendar / base_calendar.py
index c41917a..b570c2e 100644 (file)
@@ -22,6 +22,7 @@
 from datetime import datetime, timedelta, date
 from dateutil import parser
 from dateutil import rrule
+from dateutil.relativedelta import relativedelta
 from osv import fields, osv
 from service import web_services
 from tools.translate import _
@@ -50,17 +51,19 @@ def get_recurrent_dates(rrulestring, exdate, startdate=None, exrule=None):
 
     if not startdate:
         startdate = datetime.now()
+
     if not exdate:
         exdate = []
-    rset1 = rrule.rrulestr(str(rrulestring), dtstart=startdate, forceset=True)
 
+    rset1 = rrule.rrulestr(str(rrulestring), dtstart=startdate, forceset=True)
     for date in exdate:
         datetime_obj = todate(date)
         rset1._exdate.append(datetime_obj)
+
     if exrule:
         rset1.exrule(rrule.rrulestr(str(exrule), dtstart=startdate))
 
-    return list(rset1._iter())
+    return list(rset1)
 
 def base_calendar_id2real_id(base_calendar_id=None, with_date=False):
     """
@@ -242,13 +245,13 @@ class calendar_attendee(osv.osv):
                     continue
                 else:
                     result[id][name] = self._get_address(attdata.sent_by_uid.name, \
-                                        attdata.sent_by_uid.address_id.email)
+                                        attdata.sent_by_uid.user_email)
 
             if name == 'cn':
                 if attdata.user_id:
                     result[id][name] = attdata.user_id.name
-                elif attdata.partner_address_id:
-                    result[id][name] = attdata.partner_address_id.name or attdata.partner_id.name
+                elif attdata.partner_id:
+                    result[id][name] = attdata.partner_id.name or False
                 else:
                     result[id][name] = attdata.email or ''
 
@@ -321,7 +324,7 @@ class calendar_attendee(osv.osv):
     _columns = {
         'cutype': fields.selection([('individual', 'Individual'), \
                     ('group', 'Group'), ('resource', 'Resource'), \
-                    ('room', 'Room'), ('unknown', '') ], \
+                    ('room', 'Room'), ('unknown', 'Unknown') ], \
                     'Invite Type', help="Specify the type of Invitation"),
         'member': fields.char('Member', size=124,
                     help="Indicate the groups that the attendee belongs to"),
@@ -330,50 +333,49 @@ class calendar_attendee(osv.osv):
                     ('opt-participant', 'Optional Participation'), \
                     ('non-participant', 'For information Purpose')], 'Role', \
                     help='Participation role for the calendar user'),
-        'state': fields.selection([('tentative', 'Tentative'),
-                        ('needs-action', 'Needs Action'),
-                        ('accepted', 'Accepted'),
+        'state': fields.selection([('needs-action', 'Needs Action'),
+                        ('tentative', 'Tentative'),
                         ('declined', 'Declined'),
-                        ('delegated', 'Delegated')], 'State', readonly=True, \
+                        ('accepted', 'Accepted'),
+                        ('delegated', 'Delegated')], 'Status', readonly=True, \
                         help="Status of the attendee's participation"),
         'rsvp':  fields.boolean('Required Reply?',
                     help="Indicats whether the favor of a reply is requested"),
-        'delegated_to': fields.function(_compute_data, method=True, \
+        'delegated_to': fields.function(_compute_data, \
                 string='Delegated To', type="char", size=124, store=True, \
                 multi='delegated_to', help="The users that the original \
 request was delegated to"),
-        'delegated_from': fields.function(_compute_data, method=True, string=\
+        'delegated_from': fields.function(_compute_data, string=\
             'Delegated From', type="char", store=True, size=124, multi='delegated_from'),
         'parent_ids': fields.many2many('calendar.attendee', 'calendar_attendee_parent_rel', \
                                     'attendee_id', 'parent_id', 'Delegrated From'),
         'child_ids': fields.many2many('calendar.attendee', 'calendar_attendee_child_rel', \
                                       'attendee_id', 'child_id', 'Delegrated To'),
-        'sent_by': fields.function(_compute_data, method=True, string='Sent By', \
+        'sent_by': fields.function(_compute_data, string='Sent By', \
                         type="char", multi='sent_by', store=True, size=124, \
                         help="Specify the user that is acting on behalf of the calendar user"),
-        'sent_by_uid': fields.function(_compute_data, method=True, string='Sent By User', \
+        'sent_by_uid': fields.function(_compute_data, string='Sent By User', \
                             type="many2one", relation="res.users", multi='sent_by_uid'),
-        'cn': fields.function(_compute_data, method=True, string='Common name', \
+        'cn': fields.function(_compute_data, string='Common name', \
                             type="char", size=124, multi='cn', store=True),
         'dir': fields.char('URI Reference', size=124, help="Reference to the URI\
 that points to the directory information corresponding to the attendee."),
-        'language': fields.function(_compute_data, method=True, string='Language', \
+        'language': fields.function(_compute_data, string='Language', \
                     type="selection", selection=_lang_get, multi='language', \
                     store=True, help="To specify the language for text values in a\
 property or property parameter."),
         'user_id': fields.many2one('res.users', 'User'),
-        'partner_address_id': fields.many2one('res.partner.address', 'Contact'),
-        'partner_id': fields.related('partner_address_id', 'partner_id', type='many2one', \
-                        relation='res.partner', string='Partner', help="Partner related to contact"),
+        'partner_id': fields.many2one('res.partner', 'Contact'),
         'email': fields.char('Email', size=124, help="Email of Invited Person"),
-        'event_date': fields.function(_compute_data, method=True, string='Event Date', \
+        'event_date': fields.function(_compute_data, string='Event Date', \
                             type="datetime", multi='event_date'),
-        'event_end_date': fields.function(_compute_data, method=True, \
+        'event_end_date': fields.function(_compute_data, \
                             string='Event End Date', type="datetime", \
                             multi='event_end_date'),
         'ref': fields.reference('Event Ref', selection=_links_get, size=128),
         'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
-     }
+    }
+
     _defaults = {
         'state': 'needs-action',
         'role': 'req-participant',
@@ -382,7 +384,7 @@ property or property parameter."),
     }
 
     def copy(self, cr, uid, id, default=None, context=None):
-        raise osv.except_osv(_('Warning!'), _('Can not Duplicate'))
+        raise osv.except_osv(_('Warning!'), _('You cannot duplicate a calendar attendee.'))
 
     def get_ics_file(self, cr, uid, event_obj, context=None):
         """
@@ -411,7 +413,7 @@ property or property parameter."),
         cal = vobject.iCalendar()
         event = cal.add('vevent')
         if not event_obj.date_deadline or not event_obj.date:
-              raise osv.except_osv(_('Warning !'),_("Couldn't Invite because date is not specified!"))     
+            raise osv.except_osv(_('Warning!'),_("First you have to specify the date of the invitation."))
         event.add('created').value = ics_datetime(time.strftime('%Y-%m-%d %H:%M:%S'))
         event.add('dtstart').value = ics_datetime(event_obj.date)
         event.add('dtend').value = ics_datetime(event_obj.date_deadline)
@@ -456,7 +458,7 @@ property or property parameter."),
             trigger.value = delta
             # Compute other details
             valarm.add('DESCRIPTION').value = alarm_data['name'] or 'OpenERP'
-                
+
         for attendee in event_obj.attendee_ids:
             attendee_add = event.add('attendee')
             attendee_add.params['CUTYPE'] = [str(attendee.cutype)]
@@ -480,7 +482,7 @@ property or property parameter."),
             context = {}
 
         company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.name
-        email_message_obj = self.pool.get('email.message')
+        mail_message = self.pool.get('mail.message')
         for att in self.browse(cr, uid, ids, context=context):
             sign = att.sent_by_uid and att.sent_by_uid.signature or ''
             sign = '<br>'.join(sign and sign.split('\n') or [])
@@ -507,15 +509,15 @@ property or property parameter."),
                 body = html_invitation % body_vals
                 if mail_to and email_from:
                     attach = self.get_ics_file(cr, uid, res_obj, context=context)
-                    email_message_obj.email_send(
+                    mail_message.schedule_with_attach(cr, uid,
                         email_from,
                         mail_to,
                         sub,
                         body,
-                        model='calendar.attendee',
-                        attach=attach and [('invitation.ics', attach)] or None,
-                        subtype='html',
-                        reply_to=email_from
+                        attachments=attach and {'invitation.ics': attach} or None,
+                        content_subtype='html',
+                        reply_to=email_from,
+                        context=context
                     )
             return True
 
@@ -533,7 +535,7 @@ property or property parameter."),
             return {'value': {'email': ''}}
         usr_obj = self.pool.get('res.users')
         user = usr_obj.browse(cr, uid, user_id, *args)
-        return {'value': {'email': user.address_id.email, 'availability':user.availability}}
+        return {'value': {'email': user.user_email, 'availability':user.availability}}
 
     def do_tentative(self, cr, uid, ids, context=None, *args):
         """ Makes event invitation as Tentative
@@ -676,7 +678,7 @@ true, it will allow you to hide the event alarm information without removing it.
                     new_res_alarm = alarm_ids[0]
                 cr.execute('UPDATE %s ' % model_obj._table + \
                             ' SET base_calendar_alarm_id=%s, alarm_id=%s ' \
-                            ' WHERE id=%s', 
+                            ' WHERE id=%s',
                             (cal_alarm.id, new_res_alarm, data.id))
 
             self.do_alarm_unlink(cr, uid, [data.id], model)
@@ -765,7 +767,7 @@ class calendar_alarm(osv.osv):
                     ('run', 'Run'),
                     ('stop', 'Stop'),
                     ('done', 'Done'),
-                ], 'State', select=True, readonly=True),
+                ], 'Status', select=True, readonly=True),
      }
 
     _defaults = {
@@ -808,12 +810,10 @@ class calendar_alarm(osv.osv):
         @param use_new_cursor: False or the dbname
         @param context: A standard dictionary for contextual values
         """
-        return True # XXX FIXME REMOVE THIS AFTER FIXING get_recurrent_dates!!
         if context is None:
             context = {}
-        email_message_obj = self.pool.get('email.message')
+        mail_message = self.pool.get('mail.message')
         current_datetime = datetime.now()
-        request_obj = self.pool.get('res.request')
         alarm_ids = self.search(cr, uid, [('state', '!=', 'done')], context=context)
 
         mail_to = []
@@ -853,26 +853,28 @@ class calendar_alarm(osv.osv):
                 ref = alarm.model_id.model + ',' + str(alarm.res_id)
 
                 # search for alreay sent requests
-                if request_obj.search(cr, uid, [('trigger_date', '=', r_date), ('ref_doc1', '=', ref)], context=context):
-                    continue
-
-                if alarm.action == 'display':
-                    value = {
-                       'name': alarm.name,
-                       'act_from': alarm.user_id.id,
-                       'act_to': alarm.user_id.id,
-                       'body': alarm.description,
-                       'trigger_date': r_date,
-                       'ref_doc1': ref
-                    }
-                    request_id = request_obj.create(cr, uid, value)
-                    request_ids = [request_id]
-                    for attendee in res_obj.attendee_ids:
-                        if attendee.user_id:
-                            value['act_to'] = attendee.user_id.id
-                            request_id = request_obj.create(cr, uid, value)
-                            request_ids.append(request_id)
-                    request_obj.request_send(cr, uid, request_ids)
+                #if request_obj.search(cr, uid, [('trigger_date', '=', r_date), ('ref_doc1', '=', ref)], context=context):
+                    #continue
+
+                # Deactivated because of the removing of res.request
+                # TODO: when cleaning calendar module, re-add this in a new mechanism
+                #if alarm.action == 'display':
+                    #value = {
+                       #'name': alarm.name,
+                       #'act_from': alarm.user_id.id,
+                       #'act_to': alarm.user_id.id,
+                       #'body': alarm.description,
+                       #'trigger_date': r_date,
+                       #'ref_doc1': ref
+                    #}
+                    #request_id = request_obj.create(cr, uid, value)
+                    #request_ids = [request_id]
+                    #for attendee in res_obj.attendee_ids:
+                        #if attendee.user_id:
+                            #value['act_to'] = attendee.user_id.id
+                            #request_id = request_obj.create(cr, uid, value)
+                            #request_ids.append(request_id)
+                    #request_obj.request_send(cr, uid, request_ids)
 
                 if alarm.action == 'email':
                     sub = '[Openobject Reminder] %s' % (alarm.name)
@@ -889,16 +891,16 @@ From:
 
 """  % (alarm.name, alarm.trigger_date, alarm.description, \
                         alarm.user_id.name, alarm.user_id.signature)
-                    mail_to = [alarm.user_id.address_id.email]
+                    mail_to = [alarm.user_id.user_email]
                     for att in alarm.attendee_ids:
-                        mail_to.append(att.user_id.address_id.email)
+                        mail_to.append(att.user_id.user_email)
                     if mail_to:
-                        email_message_obj.email_send(
+                        mail_message.schedule_with_attach(cr, uid,
                             tools.config.get('email_from', False),
                             mail_to,
                             sub,
                             body,
-                            model='calendar.alarm'
+                            context=context
                         )
             if next_trigger_date:
                 update_vals.update({'trigger_date': next_trigger_date})
@@ -918,22 +920,6 @@ class calendar_event(osv.osv):
     def _tz_get(self, cr, uid, context=None):
         return [(x.lower(), x) for x in pytz.all_timezones]
 
-    def onchange_allday(self, cr, uid, ids, allday, context=None):
-        """Sets duration as 24 Hours if event is selected for all day
-        @param self: The object pointer
-        @param cr: the current row, from the database cursor,
-        @param uid: the current user’s ID for security checks,
-        @param ids: List of calendar event’s IDs.
-        @param allday: Value of allday boolean
-        @param context: A standard dictionary for contextual values
-        """
-        if not allday or not ids:
-            return {}
-        value = {
-                 'duration': 24
-                 }
-        return {'value': value}
-
     def onchange_dates(self, cr, uid, ids, start_date, duration=False, end_date=False, allday=False, context=None):
         """Returns duration and/or end date based on values passed
         @param self: The object pointer
@@ -955,11 +941,19 @@ class calendar_event(osv.osv):
             duration = 1.00
             value['duration'] = duration
 
+        start = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S")
         if allday: # For all day event
-            value = {'duration': 24}
             duration = 24.0
+            value['duration'] = duration
+            # change start_date's time to 00:00:00 in the user's timezone
+            user = self.pool.get('res.users').browse(cr, uid, uid)
+            tz = pytz.timezone(user.context_tz) if user.context_tz else pytz.utc
+            start = pytz.utc.localize(start).astimezone(tz)     # convert start in user's timezone
+            start = start.replace(hour=0, minute=0, second=0)   # change start's time to 00:00:00
+            start = start.astimezone(pytz.utc)                  # convert start back to utc
+            start_date = start.strftime("%Y-%m-%d %H:%M:%S")
+            value['date'] = start_date
 
-        start = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S")
         if end_date and not duration:
             end = datetime.strptime(end_date, "%Y-%m-%d %H:%M:%S")
             diff = end - start
@@ -970,7 +964,7 @@ class calendar_event(osv.osv):
             value['date_deadline'] = end.strftime("%Y-%m-%d %H:%M:%S")
         elif end_date and duration and not allday:
             # we have both, keep them synchronized:
-            # set duration based on end_date (arbitrary decision: this avoid 
+            # set duration based on end_date (arbitrary decision: this avoid
             # getting dates like 06:31:48 instead of 06:32:00)
             end = datetime.strptime(end_date, "%Y-%m-%d %H:%M:%S")
             diff = end - start
@@ -992,85 +986,6 @@ class calendar_event(osv.osv):
             self.unlink(cr, uid, r_ids, context=context)
         return True
 
-    def _set_rrulestring(self, cr, uid, id, name, value, arg, context=None):
-        """
-        Sets values of fields that defines event recurrence from the value of rrule string
-        @param self: The object pointer
-        @param cr: the current row, from the database cursor,
-        @param id: List of calendar event's ids.
-        @param context: A standard dictionary for contextual values
-        @return: dictionary of rrule value.
-        """
-        if context is None:
-            context = {}
-        cr.execute("UPDATE %s set freq='None',interval=0,count=0,end_date=Null,\
-                    mo=False,tu=False,we=False,th=False,fr=False,sa=False,su=False,\
-                    day=0,select1='date',month_list=Null ,byday=Null where id=%%s" % (self._table), (id,))
-
-        if not value:
-            cr.execute("UPDATE %s set rrule_type='none' where id=%%s" % self._table,(id,))
-            return True
-        val = {}
-        for part in value.split(';'):
-            if part.lower().__contains__('freq') and len(value.split(';')) <=2:
-                rrule_type = part.lower()[5:]
-                break
-            else:
-                rrule_type = 'custom'
-                break
-        ans = value.split(';')
-        for i in ans:
-            val[i.split('=')[0].lower()] = i.split('=')[1].lower()
-        if not val.get('interval'):
-            rrule_type = 'custom'
-        elif int(val.get('interval')) > 1: #If interval is other than 1 rule is custom
-            rrule_type = 'custom'
-
-        qry = "UPDATE \"%s\" set rrule_type=%%s " % self._table
-        qry_args = [ rrule_type, ]
-        new_val = val.copy()
-        for k, v in val.items():
-            if  val['freq'] == 'weekly' and val.get('byday'):
-                for day in val['byday'].split(','):
-                    new_val[day] = True
-                val.pop('byday')
-
-            if val.get('until'):
-                until = parser.parse(''.join((re.compile('\d')).findall(val.get('until'))))
-                new_val['end_date'] = until.strftime('%Y-%m-%d')
-                val.pop('until')
-                new_val.pop('until')
-
-            if val.get('bymonthday'):
-                new_val['day'] = val.get('bymonthday')
-                val.pop('bymonthday')
-                new_val['select1'] = 'date'
-                new_val.pop('bymonthday')
-
-            if val.get('byday'):
-                d = val.get('byday')
-                if '-' in d:
-                    new_val['byday'] = d[:2]
-                    new_val['week_list'] = d[2:4].upper()
-                else:
-                    new_val['byday'] = d[:1]
-                    new_val['week_list'] = d[1:3].upper()
-                new_val['select1'] = 'day'
-
-            if val.get('bymonth'):
-                new_val['month_list'] = val.get('bymonth')
-                val.pop('bymonth')
-                new_val.pop('bymonth')
-
-        for k, v in new_val.items():
-            qry += ", %s=%%s" % k
-            qry_args.append(v)
-
-        qry = qry + " where id=%s"
-        qry_args.append(id)
-        cr.execute(qry, qry_args)
-        return True
-
     def _get_rulestring(self, cr, uid, ids, name, arg, context=None):
         """
         Gets Recurrence rule string according to value type RECUR of iCalendar from the values given.
@@ -1080,64 +995,66 @@ class calendar_event(osv.osv):
         @param context: A standard dictionary for contextual values
         @return: dictionary of rrule value.
         """
+
         result = {}
-        for datas in self.read(cr, uid, ids, context=context):
-            event = datas['id']
-            if datas.get('rrule_type'):
-                if datas.get('rrule_type') == 'none':
-                    result[event] = False
-                    cr.execute("UPDATE %s set exrule=Null where id=%%s" % self._table,( event,))
-                if datas.get('rrule_type') :
-                    if datas.get('interval', 0) < 0:
-                        raise osv.except_osv(_('Warning!'), _('Interval can not be Negative'))
-                    if datas.get('count', 0) < 0:
-                        raise osv.except_osv(_('Warning!'), _('Count can not be Negative'))
-                    rrule_custom = self.compute_rule_string(cr, uid, datas, \
-                                                         context=context)
-                    result[event] = rrule_custom
-                else:
-                    result[event] = self.compute_rule_string(cr, uid, {'freq': datas.get('rrule_type').upper(), 'interval': 1}, context=context)
+        if not isinstance(ids, list):
+            ids = [ids]
 
-        for id, myrule in result.items():
-            #Remove the events generated from recurrent event
-            if not myrule:
-                self.unlink_events(cr, uid, [id], context=context)
+        for datas in self.read(cr, uid, ids, ['id','byday','recurrency', 'month_list','end_date', 'rrule_type', 'select1', 'interval', 'count', 'end_type', 'mo', 'tu', 'we', 'th', 'fr', 'sa', 'su', 'exrule', 'day', 'week_list' ], context=context):
+            event = datas['id']
+            if datas.get('interval', 0) < 0:
+                raise osv.except_osv(_('Warning!'), _('Interval cannot be negative.'))
+            if datas.get('count', 0) < 0:
+                raise osv.except_osv(_('Warning!'), _('Count cannot be negative.'))
+            if datas['recurrency']:
+                result[event] = self.compute_rule_string(datas)
+            else:
+                result[event] = ""
         return result
 
+    def _rrule_write(self, obj, cr, uid, ids, field_name, field_value, args, context=None):
+        data = self._get_empty_rrule_data()
+        if field_value:
+            data['recurrency'] = True
+            for event in self.browse(cr, uid, ids, context=context):
+                rdate = rule_date or event.date
+                update_data = self._parse_rrule(field_value, dict(data), rdate)
+                data.update(update_data)
+                super(calendar_event, obj).write(cr, uid, ids, data, context=context)
+        return True
+
+
     _columns = {
-        'id': fields.integer('ID'),
+        'id': fields.integer('ID', readonly=True),
         'sequence': fields.integer('Sequence'),
         'name': fields.char('Description', size=64, required=False, states={'done': [('readonly', True)]}),
-        'date': fields.datetime('Date', states={'done': [('readonly', True)]}),
-        'date_deadline': fields.datetime('Deadline', states={'done': [('readonly', True)]}),
+        'date': fields.datetime('Date', states={'done': [('readonly', True)]}, required=True,),
+        'date_deadline': fields.datetime('Deadline', states={'done': [('readonly', True)]}, required=True,),
         'create_date': fields.datetime('Created', readonly=True),
         'duration': fields.float('Duration', states={'done': [('readonly', True)]}),
         'description': fields.text('Description', states={'done': [('readonly', True)]}),
         'class': fields.selection([('public', 'Public'), ('private', 'Private'), \
-             ('confidential', 'Confidential')], 'Mark as', states={'done': [('readonly', True)]}),
+             ('confidential', 'Public for Employees')], 'Privacy', states={'done': [('readonly', True)]}),
         'location': fields.char('Location', size=264, help="Location of Event", states={'done': [('readonly', True)]}),
         'show_as': fields.selection([('free', 'Free'), ('busy', 'Busy')], \
-                                                'Show as', states={'done': [('readonly', True)]}),
+                                                'Show Time as', states={'done': [('readonly', True)]}),
         'base_calendar_url': fields.char('Caldav URL', size=264),
         'state': fields.selection([('tentative', 'Tentative'),
+                        ('cancelled', 'Cancelled'),
                         ('confirmed', 'Confirmed'),
-                        ('cancelled', 'Cancelled')], 'State', readonly=True),
+                        ], 'Status', readonly=True),
         'exdate': fields.text('Exception Date/Times', help="This property \
 defines the list of date/time exceptions for a recurring calendar component."),
         'exrule': fields.char('Exception Rule', size=352, help="Defines a \
 rule or repeating pattern of time to exclude from the recurring rule."),
-        'rrule': fields.function(_get_rulestring, type='char', size=124, method=True, \
-                                    string='Recurrent Rule', store=True, \
-                                    fnct_inv=_set_rrulestring, help='Defines a\
- rule or repeating pattern for recurring events\n\
-e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
-        FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=-1SU'),
+        'rrule': fields.function(_get_rulestring, type='char', size=124, \
+                    fnct_inv=_rrule_write, store=True, string='Recurrent Rule'),
         'rrule_type': fields.selection([('none', ''), ('daily', 'Daily'), \
                             ('weekly', 'Weekly'), ('monthly', 'Monthly'), \
-                            ('yearly', 'Yearly'),], 
+                            ('yearly', 'Yearly'),],
                             'Recurrency', states={'done': [('readonly', True)]},
                             help="Let the event automatically repeat at that interval"),
-        'alarm_id': fields.many2one('res.alarm', 'Alarm', states={'done': [('readonly', True)]},
+        'alarm_id': fields.many2one('res.alarm', 'Reminder', states={'done': [('readonly', True)]},
                         help="Set an alarm at this time, before the event occurs" ),
         'base_calendar_alarm_id': fields.many2one('calendar.alarm', 'Alarm'),
         'recurrent_uid': fields.integer('Recurrent ID'),
@@ -1146,15 +1063,8 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
         'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}),
         'organizer': fields.char("Organizer", size=256, states={'done': [('readonly', True)]}), # Map with Organizer Attribure of VEvent.
         'organizer_id': fields.many2one('res.users', 'Organizer', states={'done': [('readonly', True)]}),
-        'freq': fields.selection([('None', 'No Repeat'),
-                                ('hourly', 'Hours'),
-                                ('daily', 'Days'),
-                                ('weekly', 'Weeks'),
-                                ('monthly', 'Months'),
-                                ('yearly', 'Years'), ], 'Frequency'),
-          
-        'end_type' : fields.selection([('forever', 'Forever'), ('count', 'Fix amout of times'), ('end_date','End date')], 'Way to end reccurency'),
-        'interval': fields.integer('Repeat every', help="Repeat every (Days/Week/Month/Year)"),
+        'end_type' : fields.selection([('count', 'Number of repetitions'), ('end_date','End date')], 'Recurrence Termination'),
+        'interval': fields.integer('Repeat Every', help="Repeat every (Days/Week/Month/Year)"),
         'count': fields.integer('Repeat', help="Repeat x times"),
         'mo': fields.boolean('Mon'),
         'tu': fields.boolean('Tue'),
@@ -1163,7 +1073,7 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
         'fr': fields.boolean('Fri'),
         'sa': fields.boolean('Sat'),
         'su': fields.boolean('Sun'),
-        'select1': fields.selection([('date', 'Date of month'), 
+        'select1': fields.selection([('date', 'Date of month'),
                                     ('day', 'Day of month')], 'Option'),
         'day': fields.integer('Date of month'),
         'week_list': fields.selection([('MO', 'Monday'), ('TU', 'Tuesday'), \
@@ -1180,9 +1090,9 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
         'allday': fields.boolean('All Day', states={'done': [('readonly', True)]}),
         'active': fields.boolean('Active', help="If the active field is set to \
          true, it will allow you to hide the event alarm information without removing it."),
-        'recurrency': fields.boolean('Recurrent', help="Recurrent Meeting"),                                    
-        'edit_all': fields.boolean('Edit All', help="Edit all Occurrences  of recurrent Meeting."),        
+        'recurrency': fields.boolean('Recurrent', help="Recurrent Meeting"),
     }
+
     def default_organizer(self, cr, uid, context=None):
         user_pool = self.pool.get('res.users')
         user = user_pool.browse(cr, uid, uid, context=context)
@@ -1192,350 +1102,337 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
         return res
 
     _defaults = {
-            'end_type' : 'forever',
+            'end_type' : 'count',
+            'count' : 1,
+            'rrule_type' : 'none',
             'state': 'tentative',
             'class': 'public',
             'show_as': 'busy',
-            'freq': 'None',
             'select1': 'date',
             'interval': 1,
             'active': 1,
             'user_id': lambda self, cr, uid, ctx: uid,
             'organizer': default_organizer,
-            'edit_all' : False,
     }
 
-    def onchange_edit_all(self, cr, uid, ids, rrule_type,edit_all, context=None):
-        if not context:
-            context = {}
-    
-        value = {}
-        if edit_all and rrule_type:
-            for id in ids:
-              base_calendar_id2real_id(id)
-        return value              
-
-    def modify_all(self, cr, uid, event_ids, defaults, context=None, *args):
-        """
-        Modifies the recurring event
-        @param cr: the current row, from the database cursor,
-        @param uid: the current user’s ID for security checks,
-        @param event_ids: List of crm meeting’s IDs.
-        @param context: A standard dictionary for contextual values
-        @return: True
-        """
-        for event_id in event_ids:
-            event_id = base_calendar_id2real_id(event_id)
-
-            defaults.pop('id')
-            defaults.update({'table': self._table})
-
-            qry = "UPDATE %(table)s set name = '%(name)s', \
-                            date = '%(date)s', date_deadline = '%(date_deadline)s'"
-            if defaults.get('alarm_id'):
-                qry += ", alarm_id = %(alarm_id)s"
-            if defaults.get('location'):
-                qry += ", location = '%(location)s'"
-            qry += "WHERE id = %s" % (event_id)
-            cr.execute(qry, defaults)
-
-        return True
-
-    def get_recurrent_ids(self, cr, uid, select, base_start_date, base_until_date, limit=100):
+    def get_recurrent_ids(self, cr, uid, select, domain, limit=100, context=None):
         """Gives virtual event ids for recurring events based on value of Recurrence Rule
         This method gives ids of dates that comes between start date and end date of calendar views
         @param self: The object pointer
         @param cr: the current row, from the database cursor,
         @param uid: the current user’s ID for security checks,
-        @param base_start_date: Get Start Date
-        @param base_until_date: Get End Date
         @param limit: The Number of Results to Return """
+        if not context:
+            context = {}
 
-        if not limit:
-            limit = 100
-        if isinstance(select, (str, int, long)):
-            ids = [select]
-        else:
-            ids = select
         result = []
-        recur_dict = []
-        if ids and (base_start_date or base_until_date):
-            cr.execute("select m.id, m.rrule, m.date, m.date_deadline, m.duration, \
-                            m.exdate, m.exrule, m.recurrent_id, m.recurrent_uid from " + self._table + \
-                            " m where m.id = ANY(%s)", (ids,) )
-
-            count = 0
-            for data in cr.dictfetchall():
-                start_date = base_start_date and datetime.strptime(base_start_date[:10]+ ' 00:00:00' , "%Y-%m-%d %H:%M:%S") or False
-                until_date = base_until_date and datetime.strptime(base_until_date[:10]+ ' 23:59:59', "%Y-%m-%d %H:%M:%S") or False
-                if count > limit:
-                    break
-                event_date = datetime.strptime(data['date'], "%Y-%m-%d %H:%M:%S")
+        for data in super(calendar_event, self).read(cr, uid, select, context=context):
+            if not data['rrule']:
+                result.append(data['id'])
+                continue
+            event_date = datetime.strptime(data['date'], "%Y-%m-%d %H:%M:%S")
 #                To check: If the start date is replace by event date .. the event date will be changed by that of calendar code
-                start_date = event_date
-                if not data['rrule']:
-                    if start_date and (event_date < start_date):
-                        continue
-                    if until_date and (event_date > until_date):
-                        continue
-                    idval = real_id2base_calendar_id(data['id'], data['date'])
-                    if not data['recurrent_id']:
-                        result.append(idval)
-                        count += 1
-                    else:
-                        ex_id = real_id2base_calendar_id(data['recurrent_uid'], data['recurrent_id'])
-                        ls = base_calendar_id2real_id(ex_id, with_date=data and data.get('duration', 0) or 0)
-                        if not isinstance(ls, (str, int, long)) and len(ls) >= 2:
-                            if ls[1] == data['recurrent_id']:
-                                result.append(idval)
-                        recur_dict.append(ex_id)
-                else:
-                    exdate = data['exdate'] and data['exdate'].split(',') or []
-                    rrule_str = data['rrule']
-                    new_rrule_str = []
-                    rrule_until_date = False
-                    is_until = False
-                    for rule in rrule_str.split(';'):
-                        name, value = rule.split('=')
-                        if name == "UNTIL":
-                            is_until = True
-                            value = parser.parse(value)
-                            rrule_until_date = parser.parse(value.strftime("%Y-%m-%d"))
-                            if until_date and until_date >= rrule_until_date:
-                                until_date = rrule_until_date
-                            if until_date:
-                                value = until_date.strftime("%Y%m%d%H%M%S")
-                        new_rule = '%s=%s' % (name, value)
-                        new_rrule_str.append(new_rule)
-                    if not is_until and until_date:
-                        value = until_date.strftime("%Y%m%d%H%M%S")
-                        name = "UNTIL"
-                        new_rule = '%s=%s' % (name, value)
-                        new_rrule_str.append(new_rule)
-                    new_rrule_str = ';'.join(new_rrule_str)
-                    rdates = get_recurrent_dates(str(new_rrule_str), exdate, start_date, data['exrule'])
-                    for r_date in rdates:
-                        if start_date and r_date < start_date:
-                            continue
-                        if until_date and r_date > until_date:
-                            continue
-                        idval = real_id2base_calendar_id(data['id'], r_date.strftime("%Y-%m-%d %H:%M:%S"))
-                        result.append(idval)
-                        count += 1
-        if result:
-            ids = list(set(result)-set(recur_dict))
+
+            if not data['rrule']:
+                continue
+
+            exdate = data['exdate'] and data['exdate'].split(',') or []
+            rrule_str = data['rrule']
+            new_rrule_str = []
+            rrule_until_date = False
+            is_until = False
+            for rule in rrule_str.split(';'):
+                name, value = rule.split('=')
+                if name == "UNTIL":
+                    is_until = True
+                    value = parser.parse(value)
+                    rrule_until_date = parser.parse(value.strftime("%Y-%m-%d %H:%M:%S"))
+                    value = value.strftime("%Y%m%d%H%M%S")
+                new_rule = '%s=%s' % (name, value)
+                new_rrule_str.append(new_rule)
+            new_rrule_str = ';'.join(new_rrule_str)
+            rdates = get_recurrent_dates(str(new_rrule_str), exdate, event_date, data['exrule'])
+            for r_date in rdates:
+                ok = True
+                for arg in domain:
+                    if arg[0] in ('date', 'date_deadline'):
+                        if (arg[1]=='='):
+                            ok = ok and r_date.strftime('%Y-%m-%d')==arg[2]
+                        if (arg[1]=='>'):
+                            ok = ok and r_date.strftime('%Y-%m-%d')>arg[2]
+                        if (arg[1]=='<'):
+                            ok = ok and r_date.strftime('%Y-%m-%d')<arg[2]
+                        if (arg[1]=='>='):
+                            ok = ok and r_date.strftime('%Y-%m-%d')>=arg[2]
+                        if (arg[1]=='<='):
+                            ok = ok and r_date.strftime('%Y-%m-%d')<=arg[2]
+                if not ok:
+                    continue
+                idval = real_id2base_calendar_id(data['id'], r_date.strftime("%Y-%m-%d %H:%M:%S"))
+                result.append(idval)
+
         if isinstance(select, (str, int, long)):
             return ids and ids[0] or False
+        else:
+            ids = list(set(result))
         return ids
 
-    def compute_rule_string(self, cr, uid, datas, context=None, *args):
+    def compute_rule_string(self, datas):
         """
         Compute rule string according to value type RECUR of iCalendar from the values given.
         @param self: the object pointer
-        @param cr: the current row, from the database cursor,
-        @param uid: the current user’s ID for security checks,
         @param datas: dictionary of freq and interval value.
-        @param context: A standard dictionary for contextual values
-        @return: String value of the format RECUR of iCalendar
         """
+        def get_week_string(freq, datas):
+            weekdays = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
+            if freq == 'weekly':
+                byday = map(lambda x: x.upper(), filter(lambda x: datas.get(x) and x in weekdays, datas))
+                if byday:
+                    return ';BYDAY=' + ','.join(byday)
+            return ''
 
-        weekdays = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
-        weekstring = ''
-        monthstring = ''
-        yearstring = ''
-        freq=datas.get('rrule_type')
-        if  freq == 'none':
+        def get_month_string(freq, datas):
+            if freq == 'monthly':
+                if datas.get('select1')=='date' and (datas.get('day') < 1 or datas.get('day') > 31):
+                    raise osv.except_osv(_('Error!'), ("Please select a proper day of the month."))
+
+                if datas.get('select1')=='day':
+                    return ';BYDAY=' + datas.get('byday') + datas.get('week_list')
+                elif datas.get('select1')=='date':
+                    return ';BYMONTHDAY=' + str(datas.get('day'))
             return ''
-            
-        interval_srting = datas.get('interval') and (';INTERVAL=' + str(datas.get('interval'))) or ''
 
-        if freq == 'weekly':
-            byday = map(lambda x: x.upper(), filter(lambda x: datas.get(x) and x in weekdays, datas))
-            if byday:
-                weekstring = ';BYDAY=' + ','.join(byday)
+        def get_end_date(datas):
+            if datas.get('end_date'):
+                datas['end_date_new'] = ''.join((re.compile('\d')).findall(datas.get('end_date'))) + 'T235959Z'
+
+            return (datas.get('end_type') == 'count' and (';COUNT=' + str(datas.get('count'))) or '') +\
+                             ((datas.get('end_date_new') and datas.get('end_type') == 'end_date' and (';UNTIL=' + datas.get('end_date_new'))) or '')
 
-        elif freq == 'monthly':
-            if datas.get('select1')=='date' and (datas.get('day') < 1 or datas.get('day') > 31):
-                raise osv.except_osv(_('Error!'), ("Please select proper Day of month"))
-            if datas.get('select1')=='day':
-                monthstring = ';BYDAY=' + datas.get('byday') + datas.get('week_list')
-            elif datas.get('select1')=='date':
-                monthstring = ';BYMONTHDAY=' + str(datas.get('day'))
+        freq=datas.get('rrule_type')
+        if freq == 'none':
+            return ''
 
-       
-        if datas.get('end_date'):
-            datas['end_date'] = ''.join((re.compile('\d')).findall(datas.get('end_date'))) + 'T235959Z'
-        enddate = (datas.get('count') and (';COUNT=' + str(datas.get('count'))) or '') +\
-                             ((datas.get('end_date') and (';UNTIL=' + datas.get('end_date'))) or '')
+        interval_srting = datas.get('interval') and (';INTERVAL=' + str(datas.get('interval'))) or ''
 
-        rrule_string = 'FREQ=' + freq.upper() + weekstring + interval_srting \
-                            + enddate + monthstring + yearstring
+        return 'FREQ=' + freq.upper() + get_week_string(freq, datas) + interval_srting + get_end_date(datas) + get_month_string(freq, datas)
+
+    def _get_empty_rrule_data(self):
+        return  {
+            'byday' : False,
+            'recurrency' : False,
+            'end_date' : False,
+            'rrule_type' : False,
+            'select1' : False,
+            'interval' : 0,
+            'count' : False,
+            'end_type' : False,
+            'mo' : False,
+            'tu' : False,
+            'we' : False,
+            'th' : False,
+            'fr' : False,
+            'sa' : False,
+            'su' : False,
+            'exrule' : False,
+            'day' : False,
+            'week_list' : False
+        }
+
+    #def _write_rrule(self, cr, uid, ids, field_value, rule_date=False, context=None):
+    #    data = self._get_empty_rrule_data()
+    #
+    #    if field_value:
+    #        data['recurrency'] = True
+    #        for event in self.browse(cr, uid, ids, context=context):
+    #            rdate = rule_date or event.date
+    #            update_data = self._parse_rrule(field_value, dict(data), rdate)
+    #            data.update(update_data)
+    #            #parse_rrule
+    #            self.write(cr, uid, event.id, data, context=context)
+
+
+    def _parse_rrule(self, rule, data, date_start):
+        day_list = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
+        rrule_type = ['yearly', 'monthly', 'weekly', 'daily']
+        r = rrule.rrulestr(rule, dtstart=datetime.strptime(date_start, "%Y-%m-%d %H:%M:%S"))
+
+        if r._freq > 0 and r._freq < 4:
+            data['rrule_type'] = rrule_type[r._freq]
+
+        data['count'] = r._count
+        data['interval'] = r._interval
+        data['end_date'] = r._until and r._until.strftime("%Y-%m-%d %H:%M:%S")
+        #repeat weekly
+        if r._byweekday:
+            for i in xrange(0,7):
+                if i in r._byweekday:
+                    data[day_list[i]] = True
+            data['rrule_type'] = 'weekly'
+        #repeat monthly bynweekday ((weekday, weeknumber), )
+        if r._bynweekday:
+            data['week_list'] = day_list[r._bynweekday[0][0]].upper()
+            data['byday'] = r._bynweekday[0][1]
+            data['select1'] = 'day'
+            data['rrule_type'] = 'monthly'
+
+        if r._bymonthday:
+            data['day'] = r._bymonthday[0]
+            data['select1'] = 'date'
+            data['rrule_type'] = 'monthly'
+
+        #yearly but for openerp it's monthly, take same information as monthly but interval is 12 times
+        if r._bymonth:
+            data['interval'] = data['interval'] * 12
+
+        #FIXEME handle forever case
+        #end of recurrence
+        #in case of repeat for ever that we do not support right now
+        if not (data.get('count') or data.get('end_date')):
+            data['count'] = 100
+        if data.get('count'):
+            data['end_type'] = 'count'
+        else:
+            data['end_type'] = 'end_date'
+        return data
 
-        return rrule_string
+    def remove_virtual_id(self, ids):
+        if isinstance(ids, (str, int, long)):
+            return base_calendar_id2real_id(ids)
 
-    def search(self, cr, uid, args, offset=0, limit=100, order=None,
-            context=None, count=False):
-        """
-        Overrides orm search method.
-        @param cr: the current row, from the database cursor,
-        @param user: the current user’s ID for security checks,
-        @param args: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...].
-        @param offset: The Number of Results to Pass
-        @param limit: The Number of Results to Return
-        @param context: A standard dictionary for contextual values
-        @param count: If its True the method returns number of records instead of ids
-        @return: List of id
-        """
+        if isinstance(ids, (list, tuple)):
+            res = []
+            for id in ids:
+                res.append(base_calendar_id2real_id(id))
+            return res
+
+    def search(self, cr, uid, args, offset=0, limit=0, order=None, context=None, count=False):
+        context = context or {}
         args_without_date = []
-        start_date = False
-        until_date = False
+        filter_date = []
 
         for arg in args:
-            if arg[0] not in ('date', unicode('date'), 'date_deadline', unicode('date_deadline')):
+            if arg[0] == "id":
+                new_id = self.remove_virtual_id(arg[2])
+                new_arg = (arg[0], arg[1], new_id)
+                args_without_date.append(new_arg)
+            elif arg[0] not in ('date', unicode('date'), 'date_deadline', unicode('date_deadline')):
                 args_without_date.append(arg)
             else:
-                if arg[1] in ('>', '>='):
-                    if start_date:
-                        continue
-                    start_date = arg[2]
-                elif arg[1] in ('<', '<='):
-                    if until_date:
-                        continue
-                    until_date = arg[2]
+                if context.get('virtual_id', True):
+                    args_without_date.append('|')
+                args_without_date.append(arg)
+                if context.get('virtual_id', True):
+                    args_without_date.append(('recurrency','=',1))
+                filter_date.append(arg)
+
         res = super(calendar_event, self).search(cr, uid, args_without_date, \
-                                 offset, limit, order, context, count)
+                                 0, 0, order, context, count=False)
+        if context.get('virtual_id', True):
+            res = self.get_recurrent_ids(cr, uid, res, args, limit, context=context)
+
+        if count:
+            return len(res)
+        elif limit:
+            return res[offset:offset+limit]
+        else:
+            return res
 
-        res = self.get_recurrent_ids(cr, uid, res, start_date, until_date, limit)
-        return res
-    
-
-    def get_edit_all(self, cr, uid, id, vals=None):
-        """
-            return true if we have to edit all meeting from the same recurrent
-            or only on occurency
-        """
-        meeting = self.read(cr,uid, id, ['edit_all', 'recurrency'] )
-        if(vals and 'edit_all' in vals): #we jsut check edit_all
-            return vals['edit_all']
-        else: #it's a recurrent event and edit_all is already check
-            return meeting['recurrency'] and meeting['edit_all'] 
+    def _get_data(self, cr, uid, id, context=None):
+        res = self.read(cr, uid, [id],['date', 'date_deadline'])
+        return res[0]
 
+    def need_to_update(self, event_id, vals):
+        split_id = str(event_id).split("-")
+        if len(split_id) < 2:
+            return False
+        else:
+            date_start = vals.get('date', '')
+            try:
+                date_start = datetime.strptime(date_start, '%Y-%m-%d %H:%M:%S').strftime("%Y%m%d%H%M%S")
+                return date_start == split_id[1]
+            except Exception:
+                return True
 
-        
 
     def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True):
-        """
-        Overrides orm write method.
-        @param self: the object pointer
-        @param cr: the current row, from the database cursor,
-        @param uid: the current user’s ID for security checks,
-        @param ids: List of crm meeting's ids
-        @param vals: Dictionary of field value.
-        @param context: A standard dictionary for contextual values
-        @return: True
-        """
-        if context is None:
-            context = {}
+        context = context or {}
         if isinstance(ids, (str, int, long)):
-            select = [ids]
-        else:
-            select = ids
-        new_ids = []
+            ids = [ids]
         res = False
-        for event_id in select:
-            real_event_id = base_calendar_id2real_id(event_id)
-            
-
-            if(self.get_edit_all(cr, uid, event_id, vals=vals)):
-                event_id = real_event_id
-            
-            
-            if len(str(event_id).split('-')) > 1:
-                data = self.read(cr, uid, event_id, ['date', 'date_deadline', \
-                                                    'rrule', 'duration', 'exdate'])
-                if data.get('rrule'):
-                    data.update(vals)
-                    data.update({
-                        'recurrent_uid': real_event_id,
-                        'recurrent_id': data.get('date'),
-                        'rrule_type': 'none',
-                        'rrule': '',
-                        'edit_all': False,
-                        'recurrency' : False,
-                        })
-                    
-                    new_id = self.copy(cr, uid, real_event_id, default=data, context=context)
-                    
-                    date_new = event_id.split('-')[1]
-                    date_new = time.strftime("%Y%m%dT%H%M%S", \
-                                 time.strptime(date_new, "%Y%m%d%H%M%S"))
-                    exdate = (data['exdate'] and (data['exdate'] + ',')  or '') + date_new
-                    res = self.write(cr, uid, [real_event_id], {'exdate': exdate})
-                    
-                    context.update({'active_id': new_id, 'active_ids': [new_id]})
-                    continue
-            if not real_event_id in new_ids:
-                new_ids.append(real_event_id)
 
-        if vals.get('vtimezone', '').startswith('/freeassociation.sourceforge.net/tzfile/'):
-            vals['vtimezone'] = vals['vtimezone'][40:]
+        # Special write of complex IDS
+        for event_id in ids[:]:
+            if len(str(event_id).split('-')) == 1:
+                continue
+            ids.remove(event_id)
+            real_event_id = base_calendar_id2real_id(event_id)
+            if not vals.get('recurrency', True):
+                ids.append(real_event_id)
+                continue
 
-        updated_vals = self.onchange_dates(cr, uid, new_ids,
-            vals.get('date', False),
-            vals.get('duration', False),
-            vals.get('date_deadline', False),
-            vals.get('allday', False),
-            context=context)
-        vals.update(updated_vals.get('value', {}))
+            #if edit one instance of a reccurrent id
+            data = self.read(cr, uid, event_id, ['date', 'date_deadline', \
+                                                'rrule', 'duration', 'exdate'])
+            if data.get('rrule'):
+                data.update(vals)
+                data.update({
+                    'recurrent_uid': real_event_id,
+                    'recurrent_id': data.get('date'),
+                    'rrule_type': 'none',
+                    'rrule': '',
+                    'recurrency' : False,
+                    })
+
+                new_id = self.copy(cr, uid, real_event_id, default=data, context=context)
+
+                date_new = event_id.split('-')[1]
+                date_new = time.strftime("%Y%m%dT%H%M%S", \
+                             time.strptime(date_new, "%Y%m%d%H%M%S"))
+                exdate = (data['exdate'] and (data['exdate'] + ',')  or '') + date_new
+                res = self.write(cr, uid, [real_event_id], {'exdate': exdate})
+
+                context.update({'active_id': new_id, 'active_ids': [new_id]})
+                continue
 
-        if not 'edit_all' in vals:
-            vals['edit_all'] = False
+        if vals.get('vtimezone', '') and vals.get('vtimezone', '').startswith('/freeassociation.sourceforge.net/tzfile/'):
+            vals['vtimezone'] = vals['vtimezone'][40:]
 
-        if new_ids:
-            res = super(calendar_event, self).write(cr, uid, new_ids, vals, context=context)
+        res = super(calendar_event, self).write(cr, uid, ids, vals, context=context)
 
         if ('alarm_id' in vals or 'base_calendar_alarm_id' in vals)\
                 or ('date' in vals or 'duration' in vals or 'date_deadline' in vals):
-            # change alarm details
             alarm_obj = self.pool.get('res.alarm')
-            alarm_obj.do_alarm_create(cr, uid, new_ids, self._name, 'date', context=context)
-        return res
+            alarm_obj.do_alarm_create(cr, uid, ids, self._name, 'date', context=context)
+        return res or True and False
 
-    def browse(self, cr, uid, ids, context=None, list_class=None, fields_process=None):
-        """
-        Overrides orm browse method.
-        @param self: the object pointer
-        @param cr: the current row, from the database cursor,
-        @param uid: the current user’s ID for security checks,
-        @param ids: List of crm meeting's ids
-        @param context: A standard dictionary for contextual values
-        @return: the object list.
-        """
-        if isinstance(ids, (str, int, long)):
-            select = [ids]
-        else:
-            select = ids
-        select = map(lambda x: base_calendar_id2real_id(x), select)
-        res = super(calendar_event, self).browse(cr, uid, select, context, \
-                                                    list_class, fields_process)
-        if isinstance(ids, (str, int, long)):
-            return res and res[0] or False
+    def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
+        if not context:
+            context = {}
 
+        if 'date' in groupby:
+            raise osv.except_osv(_('Warning!'), _('Group by date is not supported, use the calendar view instead.'))
+        virtual_id = context.get('virtual_id', True)
+        context.update({'virtual_id': False})
+        res = super(calendar_event, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
+        for re in res:
+            #remove the count, since the value is not consistent with the result of the search when expand the group
+            for groupname in groupby:
+                if re.get(groupname + "_count"):
+                    del re[groupname + "_count"]
+            re.get('__context', {}).update({'virtual_id' : virtual_id})
         return res
 
     def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
-        """
-        Overrides orm Read method.Read List of fields for calendar event.
-        @param cr: the current row, from the database cursor,
-        @param user: the current user’s ID for security checks,
-        @param ids: List of calendar event's id.
-        @param fields: List of fields.
-        @param context: A standard dictionary for contextual values
-        @return: List of Dictionary of form [{‘name_of_the_field’: value, ...}, ...]
-        """
         # FIXME This whole id mangling has to go!
         if context is None:
             context = {}
+        fields2 = fields and fields[:] or None
+
+        EXTRAFIELDS = ('class','user_id','duration')
+        for f in EXTRAFIELDS:
+            if fields and (f not in fields):
+                fields2.append(f)
 
         if isinstance(ids, (str, int, long)):
             select = [ids]
@@ -1543,17 +1440,14 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
             select = ids
         select = map(lambda x: (x, base_calendar_id2real_id(x)), select)
         result = []
-        if fields and 'date' not in fields:
-            fields.append('date')
-        if fields and 'duration' not in fields:
-            fields.append('duration')
 
+        real_data = super(calendar_event, self).read(cr, uid,
+                    [real_id for base_calendar_id, real_id in select],
+                    fields=fields2, context=context, load=load)
+        real_data = dict(zip([x['id'] for x in real_data], real_data))
 
         for base_calendar_id, real_id in select:
-            #REVET: Revision ID: olt@tinyerp.com-20100924131709-cqsd1ut234ni6txn
-            res = super(calendar_event, self).read(cr, uid, real_id, fields=fields, context=context, load=load)
-            if not res :
-                continue
+            res = real_data[real_id].copy()
             ls = base_calendar_id2real_id(base_calendar_id, with_date=res and res.get('duration', 0) or 0)
             if not isinstance(ls, (str, int, long)) and len(ls) >= 2:
                 res['date'] = ls[1]
@@ -1561,85 +1455,77 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
             res['id'] = base_calendar_id
 
             result.append(res)
+
+        for r in result:
+            if r['user_id']:
+                user_id = type(r['user_id']) in (tuple,list) and r['user_id'][0] or r['user_id']
+                if user_id==uid:
+                    continue
+            if r['class']=='private':
+                for f in r.keys():
+                    if f not in ('id','date','date_deadline','duration','user_id','state'):
+                        r[f] = False
+                    if f=='name':
+                        r[f] = _('Busy')
+
+        for r in result:
+            for k in EXTRAFIELDS:
+                if (k in r) and ((not fields) or (k not in fields)):
+                    del r[k]
         if isinstance(ids, (str, int, long)):
             return result and result[0] or False
         return result
 
     def copy(self, cr, uid, id, default=None, context=None):
-        """
-        Duplicate record on specified id.
-        @param self: the object pointer.
-        @param cr: the current row, from the database cursor,
-        @param id: id of record from which we duplicated.
-        @param context: A standard dictionary for contextual values
-        @return: Duplicate record id.
-        """
         if context is None:
             context = {}
+
         res = super(calendar_event, self).copy(cr, uid, base_calendar_id2real_id(id), default, context)
         alarm_obj = self.pool.get('res.alarm')
         alarm_obj.do_alarm_create(cr, uid, [res], self._name, 'date', context=context)
-
         return res
 
     def unlink(self, cr, uid, ids, context=None):
-        """
-        Deletes records specified in ids.
-        @param self: the object pointer.
-        @param cr: the current row, from the database cursor,
-        @param id: List of calendar event's id.
-        @param context: A standard dictionary for contextual values
-        @return: True
-        """
+        if not isinstance(ids, list):
+            ids = [ids]
         res = False
-        for event_datas in self.read(cr, uid, ids, ['date', 'rrule', 'exdate'], context=context):
-            event_id = event_datas['id']
-            
-            if self.get_edit_all(cr, uid, event_id, vals=None):
-                event_id = base_calendar_id2real_id(event_id)
-            
-            if isinstance(event_id, (int, long)):
-                res = super(calendar_event, self).unlink(cr, uid, event_id, context=context)
-                self.pool.get('res.alarm').do_alarm_unlink(cr, uid, [event_id], self._name)
-                self.unlink_events(cr, uid, [event_id], context=context)
-            else:
-                str_event, date_new = event_id.split('-')
-                event_id = int(str_event)
-                if event_datas['rrule']:
-                    # Remove one of the recurrent event
-                    date_new = time.strftime("%Y%m%dT%H%M%S", \
-                                 time.strptime(date_new, "%Y%m%d%H%M%S"))
-                    exdate = (event_datas['exdate'] and (event_datas['exdate'] + ',')  or '') + date_new
-                    res = self.write(cr, uid, [event_id], {'exdate': exdate})
-                else:
-                    res = super(calendar_event, self).unlink(cr, uid, [event_id], context=context)
-                    self.pool.get('res.alarm').do_alarm_unlink(cr, uid, [event_id], self._name)
-                    self.unlink_events(cr, uid, [event_id], context=context)
+        attendee_obj=self.pool.get('calendar.attendee')
+        for event_id in ids[:]:
+            if len(str(event_id).split('-')) == 1:
+                continue
+
+            real_event_id = base_calendar_id2real_id(event_id)
+            data = self.read(cr, uid, real_event_id, ['exdate'], context=context)
+            date_new = event_id.split('-')[1]
+            date_new = time.strftime("%Y%m%dT%H%M%S", \
+                         time.strptime(date_new, "%Y%m%d%H%M%S"))
+            exdate = (data['exdate'] and (data['exdate'] + ',')  or '') + date_new
+            self.write(cr, uid, [real_event_id], {'exdate': exdate})
+            ids.remove(event_id)
+        for event in self.browse(cr, uid, ids, context=context):
+            if event.attendee_ids:
+                attendee_obj.unlink(cr, uid, [x.id for x in event.attendee_ids], context=context)
+
+        res = super(calendar_event, self).unlink(cr, uid, ids, context=context)
+        self.pool.get('res.alarm').do_alarm_unlink(cr, uid, ids, self._name)
+        self.unlink_events(cr, uid, ids, context=context)
         return res
 
+
     def create(self, cr, uid, vals, context=None):
-        """
-        Create new record.
-        @param self: the object pointer
-        @param cr: the current row, from the database cursor,
-        @param uid: the current user’s ID for security checks,
-        @param vals: dictionary of every field value.
-        @param context: A standard dictionary for contextual values
-        @return: new created record id.
-        """
         if context is None:
             context = {}
 
         if vals.get('vtimezone', '') and vals.get('vtimezone', '').startswith('/freeassociation.sourceforge.net/tzfile/'):
             vals['vtimezone'] = vals['vtimezone'][40:]
 
-        updated_vals = self.onchange_dates(cr, uid, [],
-            vals.get('date', False),
-            vals.get('duration', False),
-            vals.get('date_deadline', False),
-            vals.get('allday', False),
-            context=context)
-        vals.update(updated_vals.get('value', {}))
+        #updated_vals = self.onchange_dates(cr, uid, [],
+        #    vals.get('date', False),
+        #    vals.get('duration', False),
+        #    vals.get('date_deadline', False),
+        #    vals.get('allday', False),
+        #    context=context)
+        #vals.update(updated_vals.get('value', {}))
 
         res = super(calendar_event, self).create(cr, uid, vals, context)
         alarm_obj = self.pool.get('res.alarm')
@@ -1715,12 +1601,12 @@ class calendar_todo(osv.osv):
         @param args: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...].
         @param context: A standard dictionary for contextual values
         """
-        
+
         assert name == 'date'
         return self.write(cr, uid, id, { 'date_start': value }, context=context)
 
     _columns = {
-        'date': fields.function(_get_date, method=True, fnct_inv=_set_date, \
+        'date': fields.function(_get_date, fnct_inv=_set_date, \
                             string='Duration', store=True, type='datetime'),
         'duration': fields.integer('Duration'),
     }
@@ -1735,21 +1621,14 @@ class ir_attachment(osv.osv):
     _inherit = 'ir.attachment'
 
     def search_count(self, cr, user, args, context=None):
-        """
-        @param self: The object pointer
-        @param cr: the current row, from the database cursor,
-        @param user: the current user’s ID for security checks,
-        @param args: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...].
-        @param context: A standard dictionary for contextual values
-        """
+        new_args = []
+        for domain_item in args:
+            if isinstance(domain_item, (list, tuple)) and len(domain_item) == 3 and domain_item[0] == 'res_id':
+                new_args.append((domain_item[0], domain_item[1], base_calendar_id2real_id(domain_item[2])))
+            else:
+                new_args.append(domain_item)
+        return super(ir_attachment, self).search_count(cr, user, new_args, context)
 
-        args1 = []
-        for arg in args:
-            args1.append(map(lambda x:str(x).split('-')[0], arg))
-        return super(ir_attachment, self).search_count(cr, user, args1, context)
-        
-        
-    
     def create(self, cr, uid, vals, context=None):
         if context:
             id = context.get('default_res_id', False)
@@ -1758,21 +1637,12 @@ class ir_attachment(osv.osv):
 
     def search(self, cr, uid, args, offset=0, limit=None, order=None,
             context=None, count=False):
-        """
-        @param self: The object pointer
-        @param cr: the current row, from the database cursor,
-        @param uid: the current user’s ID for security checks,
-        @param args: list of tuples of form [(‘name_of_the_field’, ‘operator’, value), ...].
-        @param offset: The Number of Results to pass,
-        @param limit: The Number of Results to Return,
-        @param context: A standard dictionary for contextual values
-        """
-
-        new_args = args
-        for i, arg in enumerate(new_args):
-            if arg[0] == 'res_id':
-                new_args[i] = (arg[0], arg[1], base_calendar_id2real_id(arg[2]))
-
+        new_args = []
+        for domain_item in args:
+            if isinstance(domain_item, (list, tuple)) and len(domain_item) == 3 and domain_item[0] == 'res_id':
+                new_args.append((domain_item[0], domain_item[1], base_calendar_id2real_id(domain_item[2])))
+            else:
+                new_args.append(domain_item)
         return super(ir_attachment, self).search(cr, uid, new_args, offset=offset,
                             limit=limit, order=order, context=context, count=False)
 ir_attachment()
@@ -1918,7 +1788,7 @@ class res_users(osv.osv):
     _columns = {
             'availability': fields.function(_get_user_avail_fun, type='selection', \
                     selection=[('free', 'Free'), ('busy', 'Busy')], \
-                    string='Free/Busy', method=True),
+                    string='Free/Busy'),
     }
 
 res_users()