[MERGE]: merging from same branch
bzr revid: mga@tinyerp.com-20091204103053-irl080te2jmzdye1
This commit is contained in:
@@ -144,6 +144,7 @@ class account_bank_statement(osv.osv):
|
||||
}
|
||||
|
||||
def button_confirm(self, cr, uid, ids, context=None):
|
||||
context = context or {}
|
||||
done = []
|
||||
res_currency_obj = self.pool.get('res.currency')
|
||||
res_users_obj = self.pool.get('res.users')
|
||||
@@ -176,6 +177,8 @@ class account_bank_statement(osv.osv):
|
||||
# In line we get reconcile_id on bank.ste.rec.
|
||||
# in bank stat.rec we get line_new_ids on bank.stat.rec.line
|
||||
for move in st.line_ids:
|
||||
context.update({'date':move.date})
|
||||
|
||||
move_id = account_move_obj.create(cr, uid, {
|
||||
'journal_id': st.journal_id.id,
|
||||
'period_id': st.period_id.id,
|
||||
|
||||
@@ -189,20 +189,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_res_partner_filter" model="ir.ui.view">
|
||||
<field name="name">res.partner.select</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="type">search</field>
|
||||
<field name="inherit_id" ref="base.view_res_partner_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Partner">
|
||||
<field name="address" mode="tree,form" select="1">
|
||||
<field name="job_ids" select="1" string="Contacts" />
|
||||
</field>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- don't display the categories, since it is displayed in an other tab-->
|
||||
<record model="ir.ui.view" id="view_partner_form_inherit2">
|
||||
<field name="name">res.partner.form</field>
|
||||
@@ -363,7 +350,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Contact">
|
||||
<field name="job_ids" select='1'/>
|
||||
</search>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import calendar
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
{
|
||||
"name" : "CalDAV",
|
||||
"version" : "1.0",
|
||||
"depends" : [
|
||||
"base",
|
||||
],
|
||||
'description': """
|
||||
To develop a full featured caldav system that support:
|
||||
- access through webdav (based on xrg code)
|
||||
- alerts (create requests)
|
||||
- recurring events (*)
|
||||
- invitations to others people (exactly like sunbird)
|
||||
- availabilities of users/calendars
|
||||
- full day events""",
|
||||
"author" : "Tiny",
|
||||
"init_xml" : [],
|
||||
|
||||
"update_xml" : [
|
||||
'security/ir.model.access.csv'
|
||||
],
|
||||
"installable" : True,
|
||||
"active" : False,
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,325 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
||||
# $Id$
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
from time import strftime
|
||||
import time
|
||||
import base64
|
||||
import vobject
|
||||
from dateutil.rrule import *
|
||||
from dateutil import parser
|
||||
from datetime import datetime
|
||||
from time import strftime
|
||||
from pytz import timezone
|
||||
|
||||
# O-1 Optional and can come only once
|
||||
# O-n Optional and can come more than once
|
||||
# R-1 Required and can come only once
|
||||
# R-n Required and can come more than once
|
||||
|
||||
class CalDAV(object):
|
||||
__attribute__= {
|
||||
}
|
||||
|
||||
def ical_items(self):
|
||||
return self.__attribute__.items()
|
||||
|
||||
def ical_set(self, name, value, type):
|
||||
if name in self.__attribute__ and self.__attribute__[name]:
|
||||
self.__attribute__[name][type] = value
|
||||
return True
|
||||
|
||||
def ical_get(self, name, type):
|
||||
if self.__attribute__.get(name):
|
||||
val = self.__attribute__.get(name).get(type, None)
|
||||
valtype = self.__attribute__.get(name).get('type', None)
|
||||
if type == 'value':
|
||||
if valtype and valtype=='datetime' and val:
|
||||
val = val.strftime('%Y-%m-%d %H:%M:%S')
|
||||
if valtype and valtype=='integer' and val:
|
||||
val = int(val)
|
||||
return val
|
||||
else:
|
||||
return self.__attribute__.get(name, None)
|
||||
|
||||
def export_ical(self):
|
||||
pass
|
||||
|
||||
def import_ical(self, cr, uid, ical_data):
|
||||
parsedCal = vobject.readOne(ical_data)
|
||||
for child in parsedCal.getChildren():
|
||||
for cal_data in child.getChildren():
|
||||
if cal_data.name.lower() == 'attendee':
|
||||
# This is possible only if Attendee does not inherit osv_memory
|
||||
attendee = Attendee()
|
||||
attendee.import_ical(cr, uid, cal_data)
|
||||
if cal_data.name.lower() in self.__attribute__:
|
||||
self.ical_set(cal_data.name.lower(), cal_data.value, 'value')
|
||||
return True
|
||||
|
||||
class Calendar(CalDAV, osv.osv_memory):
|
||||
_name = 'caldav.calendar'
|
||||
__attribute__ = {
|
||||
'prodid' : None, # Use: R-1, Type: TEXT, Specifies the identifier for the product that created the iCalendar object.
|
||||
'version' : None, # Use: R-1, Type: TEXT, Specifies the identifier corresponding to the highest version number
|
||||
# or the minimum and maximum range of the iCalendar specification
|
||||
# that is required in order to interpret the iCalendar object.
|
||||
'calscale' : None, # Use: O-1, Type: TEXT, Defines the calendar scale used for the calendar information specified in the iCalendar object.
|
||||
'method' : None, # Use: O-1, Type: TEXT, Defines the iCalendar object method associated with the calendar object.
|
||||
'vevent' : None, # Use: O-n, Type: Collection of Event class
|
||||
'vtodo' : None, # Use: O-n, Type: Collection of ToDo class
|
||||
'vjournal': None, # Use: O-n, Type: Collection of Journal class
|
||||
'vfreebusy': None, # Use: O-n, Type: Collection of FreeBusy class
|
||||
'vtimezone': None, # Use: O-n, Type: Collection of Timezone class
|
||||
|
||||
}
|
||||
|
||||
def import_ical(self, cr, uid, ical_data):
|
||||
# Write openobject data from ical_data
|
||||
ical = vobject.readOne(ical_data)
|
||||
for child in ical.getChildren():
|
||||
child_name = child.name.lower()
|
||||
if child_name == 'vevent':
|
||||
for event in child.getChildren():
|
||||
if event.name.lower() =="attendee":
|
||||
attendee = Attendee()
|
||||
attendee.import_ical(cr, uid, event)
|
||||
if event.name.lower() =="valarm":
|
||||
alarm = Alarm()
|
||||
alarm.import_ical(cr, uid, event)
|
||||
elif child_name == "vtimezone":
|
||||
timezone = Timezone()
|
||||
timezone.import_ical(cr, uid, child)
|
||||
return True
|
||||
|
||||
def export_ical(self, cr, uid, ids):
|
||||
# Read openobject data in ical format
|
||||
ical = vobject.iCalendar()
|
||||
datas = self.browse(cr, uid, ids)
|
||||
|
||||
vcal = ical.add('vcalendar')
|
||||
for name, value in self.ical_items():
|
||||
if not value:
|
||||
continue
|
||||
if name == 'vevent':
|
||||
for event in value:
|
||||
vevent = event.ical_read()
|
||||
vcal.add(vevent)
|
||||
elif name == 'vtodo':
|
||||
for todo in value:
|
||||
vtodo = todo.ical_read()
|
||||
vcal.add(vtodo)
|
||||
elif name == 'vjournal':
|
||||
for journal in value:
|
||||
vjournal = journal.ical_read()
|
||||
vcal.add(vjournal)
|
||||
elif name == 'vfreebusy':
|
||||
for freebusy in value:
|
||||
vfreebusy = freebusy.ical_read()
|
||||
vcal.add(vfreebusy)
|
||||
elif name == 'vtimezone':
|
||||
for timezone in value:
|
||||
vtimezone = timezone.ical_read()
|
||||
vcal.add(vtimezone)
|
||||
else:
|
||||
vcal.add(name).value = value
|
||||
s = ical.serialize()
|
||||
return s
|
||||
|
||||
def ical_write(self, data):
|
||||
ical = vobject.readOne(data)
|
||||
for child in ical.getChildren():
|
||||
child_name = child.name.lower()
|
||||
child_value = child.value
|
||||
if child_name == 'vevent':
|
||||
vevents = []
|
||||
for event in child.getChildren():
|
||||
vevent = Event()
|
||||
vevent.ical_write(event.serialize())
|
||||
vevents.append(vevent)
|
||||
self.ical_set(child_name, vevents)
|
||||
else:
|
||||
self.ical_set(child_name, child_value)
|
||||
return True
|
||||
|
||||
Calendar()
|
||||
|
||||
class Event(CalDAV, osv.osv_memory):
|
||||
_name = 'caldav.event'
|
||||
__attribute__ = {
|
||||
'class' : None, # Use: O-1, Type: TEXT, Defines the access classification for a calendar component like "PUBLIC" / "PRIVATE" / "CONFIDENTIAL"
|
||||
'created' : None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the calendar information was created by the calendar user agent in the calendar store.
|
||||
'description' : None, # Use: O-1, Type: TEXT, Provides a more complete description of the calendar component, than that provided by the "SUMMARY" property.
|
||||
'dtstart' : None, # Use: O-1, Type: DATE-TIME, Specifies when the calendar component begins.
|
||||
'geo' : None, # Use: O-1, Type: FLOAT, Specifies information related to the global position for the activity specified by a calendar component.
|
||||
'last-mod' : None, # Use: O-1, Type: DATE-TIME Specifies the date and time that the information associated with the calendar component was last revised in the calendar store.
|
||||
'location' : None, # Use: O-1, Type: TEXT Defines the intended venue for the activity defined by a calendar component.
|
||||
'organizer' : None, # Use: O-1, Type: CAL-ADDRESS, Defines the organizer for a calendar component.
|
||||
'priority' : None, # Use: O-1, Type: INTEGER, Defines the relative priority for a calendar component.
|
||||
'dtstamp' : None, # Use: O-1, Type: DATE-TIME, Indicates the date/time that the instance of the iCalendar object was created.
|
||||
'seq' : None, # Use: O-1, Type: INTEGER, Defines the revision sequence number of the calendar component within a sequence of revision.
|
||||
'status' : None, # Use: O-1, Type: TEXT, Defines the overall status or confirmation for the calendar component.
|
||||
'summary' : None, # Use: O-1, Type: TEXT, Defines a short summary or subject for the calendar component.
|
||||
'transp' : None, # Use: O-1, Type: TEXT, Defines whether an event is transparent or not to busy time searches.
|
||||
'uid' : None, # Use: O-1, Type: TEXT, Defines the persistent, globally unique identifier for the calendar component.
|
||||
'url' : None, # Use: O-1, Type: URL, Defines a Uniform Resource Locator (URL) associated with the iCalendar object.
|
||||
'recurid' : None,
|
||||
'attach' : None, # Use: O-n, Type: BINARY, Provides the capability to associate a document object with a calendar component.
|
||||
'attendee' : None, # Use: O-n, Type: CAL-ADDRESS, Defines an "Attendee" within a calendar component.
|
||||
'categories' : None, # Use: O-n, Type: TEXT, Defines the categories for a calendar component.
|
||||
'comment' : None, # Use: O-n, Type: TEXT, Specifies non-processing information intended to provide a comment to the calendar user.
|
||||
'contact' : None, # Use: O-n, Type: TEXT, Used to represent contact information or alternately a reference to contact information associated with the calendar component.
|
||||
'exdate' : None, # Use: O-n, Type: DATE-TIME, Defines the list of date/time exceptions for a recurring calendar component.
|
||||
'exrule' : None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for an exception to a recurrence set.
|
||||
'rstatus' : None,
|
||||
'related' : None, # Use: O-n, Specify the relationship of the alarm trigger with respect to the start or end of the calendar component.
|
||||
# like A trigger set 5 minutes after the end of the event or to-do.---> TRIGGER;RELATED=END:PT5M
|
||||
'resources' : None, # Use: O-n, Type: TEXT, Defines the equipment or resources anticipated for an activity specified by a calendar entity like RESOURCES:EASEL,PROJECTOR,VCR, LANGUAGE=fr:1 raton-laveur
|
||||
'rdate' : None, # Use: O-n, Type: DATE-TIME, Defines the list of date/times for a recurrence set.
|
||||
'rrule' : None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for recurring events, to-dos, or time zone definitions.
|
||||
'x-prop' : None,
|
||||
'duration' : None, # Use: O-1, Type: DURATION, Specifies a positive duration of time.
|
||||
'dtend' : None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that a calendar component ends.
|
||||
}
|
||||
|
||||
def get_recurrent_dates(self, rrulestring, exdate, startdate=None):
|
||||
todate = parser.parse
|
||||
if not startdate:
|
||||
startdate = datetime.now()
|
||||
else:
|
||||
startdate = todate(startdate)
|
||||
rset1 = rrulestr(rrulestring, dtstart=startdate, forceset=True)
|
||||
for date in exdate:
|
||||
datetime_obj = datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
|
||||
# datetime_obj_utc = datetime_obj.replace(tzinfo=timezone('UTC'))
|
||||
rset1._exdate.append(datetime_obj)
|
||||
re_dates = rset1._iter()
|
||||
recurrent_dates = map(lambda x:x.strftime('%Y-%m-%d %H:%M:%S'), re_dates)
|
||||
return recurrent_dates
|
||||
|
||||
def search(self, cr, uid, args, offset=0, limit=None, order=None,
|
||||
context=None, count=False):
|
||||
# put logic for recurrent event
|
||||
# example : 123-20091111170822
|
||||
pass
|
||||
|
||||
def create(self, cr, uid, vals, context={}):
|
||||
# put logic for recurrent event
|
||||
# example : 123-20091111170822
|
||||
pass
|
||||
|
||||
def write(self, cr, uid, ids, vals, context={}):
|
||||
# put logic for recurrent event
|
||||
# # example : 123-20091111170822
|
||||
pass
|
||||
|
||||
Event()
|
||||
|
||||
class ToDo(CalDAV):
|
||||
__attribute__ = {
|
||||
}
|
||||
|
||||
class Journal(CalDAV):
|
||||
__attribute__ = {
|
||||
}
|
||||
|
||||
class FreeBusy(CalDAV):
|
||||
__attribute__ = {
|
||||
'contact' : None, # Use: O-1, Type: Text, Represent contact information or alternately a reference to contact information associated with the calendar component.
|
||||
'dtstart' : None, # Use: O-1, Type: DATE-TIME, Specifies when the calendar component begins.
|
||||
'dtend' : None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that a calendar component ends.
|
||||
'duration' : None, # Use: O-1, Type: DURATION, Specifies a positive duration of time.
|
||||
'dtstamp' : None, # Use: O-1, Type: DATE-TIME, Indicates the date/time that the instance of the iCalendar object was created.
|
||||
'organizer' : None, # Use: O-1, Type: CAL-ADDRESS, Defines the organizer for a calendar component.
|
||||
'uid' : None, # Use: O-1, Type: Text, Defines the persistent, globally unique identifier for the calendar component.
|
||||
'url' : None, # Use: O-1, Type: URL, Defines a Uniform Resource Locator (URL) associated with the iCalendar object.
|
||||
'attendee' : None, # Use: O-n, Type: CAL-ADDRESS, Defines an "Attendee" within a calendar component.
|
||||
'comment' : None, # Use: O-n, Type: TEXT, Specifies non-processing information intended to provide a comment to the calendar user.
|
||||
'freebusy' : None, # Use: O-n, Type: PERIOD, Defines one or more free or busy time intervals.
|
||||
'rstatus' : None,
|
||||
'X-prop' : None,
|
||||
}
|
||||
|
||||
class Timezone(CalDAV):
|
||||
__attribute__ = {
|
||||
'tzid' : None, # Use: R-1, Type: Text, Specifies the text value that uniquely identifies the "VTIMEZONE" calendar component.
|
||||
'last-mod' : None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the information associated with the calendar component was last revised in the calendar store.
|
||||
'tzurl' : None, # Use: O-1, Type: URI, Provides a means for a VTIMEZONE component to point to a network location that can be used to retrieve an up-to-date version of itself.
|
||||
'standardc' : # Use: R-n,
|
||||
{'tzprop' : None, }, # Use: R-1,
|
||||
'daylightc' : # Use: R-n, Type: Text,
|
||||
{'tzprop' : None, }, # Use: R-1,
|
||||
'x-prop' : None, # Use: O-n, Type: Text,
|
||||
}
|
||||
def import_ical(self, cr, uid, ical_data):
|
||||
for val in ical_data.getChildren():
|
||||
if self.__attribute__.has_key(val.name.lower()):
|
||||
self.__attribute__[val.name] = val.value
|
||||
|
||||
class Alarm(CalDAV):
|
||||
__attribute__ = {
|
||||
|
||||
'action' : None, # Use: R-1, Type: Text, defines the action to be invoked when an alarm is triggered LIKE "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
|
||||
'description' : None, # Type: Text, Provides a more complete description of the calendar component, than that provided by the "SUMMARY" property. Use:- R-1 for DISPLAY,Use:- R-1 for EMAIL,Use:- R-1 for PROCEDURE
|
||||
'summary' : None, # Use: R-1, Type: Text Which contains the text to be used as the message subject. Use for EMAIL
|
||||
'attendee' : None, # Use: R-n, Type: CAL-ADDRESS, Contain the email address of attendees to receive the message. It can also include one or more. Use for EMAIL
|
||||
'trigger' : None, # Use: R-1, Type: DURATION, The "TRIGGER" property specifies a duration prior to the start of an event or a to-do. The "TRIGGER" edge may be explicitly set to be relative to the "START" or "END" of the event or to-do with the "RELATED" parameter of the "TRIGGER" property. The "TRIGGER" property value type can alternatively be set to an absolute calendar date and time of day value. Use for all action like AUDIO, DISPLAY, EMAIL and PROCEDURE
|
||||
'duration' : None, # Type: DURATION, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
|
||||
'repeat' : None, # Type: INTEGER, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
|
||||
'attach' : None, # Use:- O-n : which MUST point to a sound resource, which is rendered when the alarm is triggered for AUDIO, Use:- O-n : which are intended to be sent as message attachments for EMAIL, Use:- R-1:which MUST point to a procedure resource, which is invoked when the alarm is triggered for PROCEDURE.
|
||||
'x-prop' : None,
|
||||
}
|
||||
|
||||
def import_ical(self, cr, uid, ical_data):
|
||||
for val in ical_data.getChildren():
|
||||
if self.__attribute__.has_key(val.name.lower()):
|
||||
self.__attribute__[val.name] = val.value
|
||||
|
||||
class Attendee(CalDAV):
|
||||
# Also inherit osv_memory
|
||||
_name = 'caldav.attendee'
|
||||
__attribute__ = {
|
||||
'cutype' : None, # Use: 0-1 Specify the type of calendar user specified by the property like "INDIVIDUAL"/"GROUP"/"RESOURCE"/"ROOM"/"UNKNOWN".
|
||||
'member' : None, # Use: 0-1 Specify the group or list membership of the calendar user specified by the property.
|
||||
'role' : None, # Use: 0-1 Specify the participation role for the calendar user specified by the property like "CHAIR"/"REQ-PARTICIPANT"/"OPT-PARTICIPANT"/"NON-PARTICIPANT"
|
||||
'partstat' : None, # Use: 0-1 Specify the participation status for the calendar user specified by the property. like use for VEVENT :- "NEEDS-ACTION"/"ACCEPTED"/"DECLINED"/"TENTATIVE"/"DELEGATED", use for VTODO :-"NEEDS-ACTION"/"ACCEPTED"/"DECLINED"/"TENTATIVE"/"DELEGATED"/"COMPLETED"/"IN-PROCESS" and use for VJOURNAL :- "NEEDS-ACTION"/"ACCEPTED"/"DECLINED".
|
||||
'rsvp' : None, # Use: 0-1 Specify whether there is an expectation of a favor of a reply from the calendar user specified by the property value like TRUE / FALSE.
|
||||
'delegated-to' : None, # Use: 0-1 Specify the calendar users to whom the calendar user specified by the property has delegated participation.
|
||||
'delegated-from' : None, # Use: 0-1 Specify the calendar users that have delegated their participation to the calendar user specified by the property.
|
||||
'sent-by' : None, # Use: 0-1 Specify the calendar user that is acting on behalf of the calendar user specified by the property.
|
||||
'cn' : None, # Use: 0-1 Specify the common name to be associated with the calendar user specified by the property.
|
||||
'dir' : None, # Use: 0-1 Specify reference to a directory entry associated with the calendar user specified by the property.
|
||||
'language' : None, # Use: 0-1 Specify the language for text values in a property or property parameter.
|
||||
}
|
||||
|
||||
def import_ical(self, cr, uid, ical_data):
|
||||
if ical_data.value:
|
||||
self.__attribute__['sent-by'] = ical_data.value
|
||||
for key, val in ical_data.params.items():
|
||||
if self.__attribute__.has_key(key.lower()):
|
||||
if type(val) == type([]):
|
||||
self.__attribute__[key] = val[0]
|
||||
else:
|
||||
self.__attribute__[key] = val
|
||||
return
|
||||
|
||||
Attendee()
|
||||
@@ -0,0 +1,3 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"caldav_calendar_all","caldav.calendar","model_caldav_calendar",,1,1,1,1
|
||||
"caldav_event_all","caldav.event","model_caldav_event",,1,1,1,1
|
||||
|
@@ -21,6 +21,7 @@
|
||||
|
||||
import crm
|
||||
import crm_segmentation
|
||||
import crm_calendar
|
||||
|
||||
import report
|
||||
import wizard
|
||||
|
||||
@@ -44,7 +44,9 @@ The CRM module has a email gateway for the synchronisation interface
|
||||
between mails and Open ERP.""",
|
||||
'author': 'Tiny',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['base'],
|
||||
'depends': ['base',
|
||||
'caldav'
|
||||
],
|
||||
'init_xml': ['crm_data.xml'],
|
||||
'update_xml': [
|
||||
'crm_wizard.xml',
|
||||
|
||||
@@ -1099,5 +1099,46 @@ class crm_email_add_cc_wizard(osv.osv_memory):
|
||||
|
||||
crm_email_add_cc_wizard()
|
||||
|
||||
|
||||
class crm_calendar_config_wizard(osv.osv_memory):
|
||||
_name = 'crm.calendar.config_wizard'
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64),
|
||||
'caldav': fields.boolean('Caldav Properties View', help="Manages the fields required for Caldav Properties.")
|
||||
}
|
||||
|
||||
def action_create(self, cr, uid, ids, context=None):
|
||||
res = self.read(cr, uid, ids)[0]
|
||||
idref = {}
|
||||
if res['caldav']:
|
||||
for fname in ('view', 'wizard'):
|
||||
try:
|
||||
fp = tools.file_open(os.path.join('crm', 'crm_caldav_' + fname + '.xml'))
|
||||
except IOError, e:
|
||||
fp = None
|
||||
if fp:
|
||||
tools.convert_xml_import(cr, 'crm', fp, idref, 'init', noupdate=True)
|
||||
cr.commit()
|
||||
|
||||
return {
|
||||
'view_type': 'form',
|
||||
"view_mode": 'form',
|
||||
'res_model': 'ir.actions.configuration.wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
return {
|
||||
'view_type': 'form',
|
||||
"view_mode": 'form',
|
||||
'res_model': 'ir.actions.configuration.wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
crm_calendar_config_wizard()
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="caldav_attendee_form_view" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.attendee</field>
|
||||
<field name="model">caldav.attendee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Atendee details">
|
||||
<field name="cutype" select="1"/>
|
||||
<field name="member"/>
|
||||
<field name="role" select="1"/>
|
||||
<field name="partstat"/>
|
||||
<field name="rsvp"/>
|
||||
<field name="delegated_to" select="1"/>
|
||||
<field name="delegated_from" select="1"/>
|
||||
<field name="sent_by"/>
|
||||
<field name="cn" select="1"/>
|
||||
<field name="dir"/>
|
||||
<field name="language"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_attendee_tree_view" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.attendee</field>
|
||||
<field name="model">caldav.attendee</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Atendee details">
|
||||
<field name="cutype" select="1"/>
|
||||
<field name="member"/>
|
||||
<field name="role" select="1"/>
|
||||
<field name="partstat"/>
|
||||
<field name="rsvp"/>
|
||||
<field name="delegated_to" select="1"/>
|
||||
<field name="delegated_from" select="1"/>
|
||||
<field name="sent_by"/>
|
||||
<field name="cn" select="1"/>
|
||||
<field name="dir"/>
|
||||
<field name="language"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_crm_case_view" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.form</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="crm.crm_case-view"/>
|
||||
<field name="arch" type="xml">
|
||||
<notebook position="inside">
|
||||
<page string="CalDav Properties">
|
||||
<field name="class"/>
|
||||
<field name="transparent"/>
|
||||
<field name="caldav_url" widget="url"/>
|
||||
<newline/>
|
||||
<separator string="Event Location" colspan="4"/>
|
||||
<field name="location" colspan="4" nolabel="1"/>
|
||||
<separator string="Freebusy Value" colspan="4"/>
|
||||
<field name="freebusy" colspan="4" nolabel="1"/>
|
||||
<separator string="Attendee Details" colspan="4"/>
|
||||
<field name="attendee" colspan="4" nolabel="1"/>
|
||||
<separator string="RRule Details" colspan="4"/>
|
||||
<field name="rrule" colspan="4" nolabel="1"/>
|
||||
<separator string="Recurrenet Dates" colspan="4"/>
|
||||
<field name="rdates" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Attendee">
|
||||
<separator string="Attendee" colspan="4"/>
|
||||
<field name="attendees" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_crm_case_view1" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.form1</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="crm.crm_case-view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="categ_id" position="replace">
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_crm_case_view2" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.tree1</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_tree-view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="id" position="replace">
|
||||
<field name="id" widget="char"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,12 @@
|
||||
<openerp>
|
||||
<data>
|
||||
<wizard string="Import ICS File" model="crm.case"
|
||||
name="caldav.crm.import" id="wizard_crm_cal_import" multi="True"
|
||||
/>
|
||||
|
||||
<wizard string="Export ICS File" model="crm.case" name="caldav.crm.export"
|
||||
id="wizard_crm_cal_export" multi="True"
|
||||
/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,299 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
||||
# $Id$
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
from time import strftime
|
||||
import time
|
||||
import base64
|
||||
import vobject
|
||||
from dateutil.rrule import *
|
||||
from dateutil import parser
|
||||
from datetime import datetime
|
||||
from time import strftime
|
||||
from pytz import timezone
|
||||
import tools
|
||||
|
||||
class crm_section(osv.osv):
|
||||
_name = 'crm.case.section'
|
||||
_inherit = 'crm.case.section'
|
||||
_description = 'Cases Section'
|
||||
|
||||
def export_cal(self, cr, uid, ids, context={}):
|
||||
# Set all property of CalDAV
|
||||
self.export_ical()
|
||||
|
||||
def import_cal(self, cr, uid, ids, context={}):
|
||||
self.import_ical(cr, uid)
|
||||
# get all property of CalDAV
|
||||
crm_section()
|
||||
|
||||
class caldav_attendee(osv.osv):
|
||||
_name = 'caldav.attendee'
|
||||
_description = 'Attendee information'
|
||||
_rec_name = 'cutype'
|
||||
|
||||
__attribute__ = {
|
||||
'cutype' : {'field':'cutype', 'type':'text'}, # Use: 0-1 Specify the type of calendar user specified by the property like "INDIVIDUAL"/"GROUP"/"RESOURCE"/"ROOM"/"UNKNOWN".
|
||||
'member' : {'field':'member', 'type':'text'}, # Use: 0-1 Specify the group or list membership of the calendar user specified by the property.
|
||||
'role' : {'field':'role', 'type':'text'}, # Use: 0-1 Specify the participation role for the calendar user specified by the property like "CHAIR"/"REQ-PARTICIPANT"/"OPT-PARTICIPANT"/"NON-PARTICIPANT"
|
||||
'partstat' : {'field':'partstat', 'type':'text'}, # Use: 0-1 Specify the participation status for the calendar user specified by the property. like use for VEVENT :- "NEEDS-ACTION"/"ACCEPTED"/"DECLINED"/"TENTATIVE"/"DELEGATED", use for VTODO :-"NEEDS-ACTION"/"ACCEPTED"/"DECLINED"/"TENTATIVE"/"DELEGATED"/"COMPLETED"/"IN-PROCESS" and use for VJOURNAL :- "NEEDS-ACTION"/"ACCEPTED"/"DECLINED".
|
||||
'rsvp' : {'field':'rsvp', 'type':'boolean'}, # Use: 0-1 Specify whether there is an expectation of a favor of a reply from the calendar user specified by the property value like TRUE / FALSE.
|
||||
'delegated-to' : {'field':'delegated_to', 'type':'char'}, # Use: 0-1 Specify the calendar users to whom the calendar user specified by the property has delegated participation.
|
||||
'delegated-from' : {'field':'delegated_from', 'type':'char'}, # Use: 0-1 Specify the calendar users that have delegated their participation to the calendar user specified by the property.
|
||||
'sent-by' : {'field':'sent_by', 'type':'text'}, # Use: 0-1 Specify the calendar user that is acting on behalf of the calendar user specified by the property.
|
||||
'cn' : {'field':'cn', 'type':'text'}, # Use: 0-1 Specify the common name to be associated with the calendar user specified by the property.
|
||||
'dir' : {'field':'dir', 'type':'text'}, # Use: 0-1 Specify reference to a directory entry associated with the calendar user specified by the property.
|
||||
'language' : {'field':'language', 'type':'text'}, # Use: 0-1 Specify the language for text values in a property or property parameter.
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'cutype' : fields.selection([('INDIVIDUAL', 'INDIVIDUAL'), ('GROUP', 'GROUP'), \
|
||||
('RESOURCE', 'RESOURCE'), ('ROOM', 'ROOM'), ('UNKNOWN', 'UNKNOWN') ], 'CUTYPE'),
|
||||
'member' : fields.char('Member', size=124),
|
||||
'role' : fields.selection([('CHAIR', 'CHAIR'), ('REQ-PARTICIPANT', 'REQ-PARTICIPANT'), \
|
||||
('OPT-PARTICIPANT', 'OPT-PARTICIPANT'), ('NON-PARTICIPANT', 'NON-PARTICIPANT')], 'ROLE'),
|
||||
'partstat' : fields.selection([('NEEDS-ACTION', 'NEEDS-ACTION'), ('ACCEPTED', 'ACCEPTED'), \
|
||||
('DECLINED', 'DECLINED'), ('TENTATIVE', 'TENTATIVE'), ('DELEGATED', 'DELEGATED')], 'PARTSTAT'),
|
||||
'rsvp' : fields.boolean('RSVP'),
|
||||
'delegated_to' : fields.char('DELEGATED-TO', size=124),
|
||||
'delegated_from' : fields.char('DELEGATED-FROM', size=124),
|
||||
'sent_by' : fields.char('SENT-BY', size=124),
|
||||
'cn' : fields.char('CN', size=124),
|
||||
'dir' : fields.char('DIR', size=124),
|
||||
'language' : fields.char('LANGUAGE', size=124),
|
||||
}
|
||||
|
||||
caldav_attendee()
|
||||
|
||||
class crm_case(osv.osv):
|
||||
_name = 'crm.case'
|
||||
_inherit = 'crm.case'
|
||||
_description = 'Cases'
|
||||
|
||||
__attribute__ = {
|
||||
'class' : {'field':'class', 'type':'text'},
|
||||
'created' : {'field':'create_date', 'type':'datetime'}, # keep none for now
|
||||
'description' : {'field':'description', 'type':'text'},
|
||||
'dtstart' : {'field':'date', 'type':'datetime'},
|
||||
#'last-mod' : {'field':'write_date', 'type':'datetime'},
|
||||
'location' : {'field':'location', 'type':'text'},
|
||||
'organizer' : {'field':'partner_id', 'sub-field':'name', 'type':'many2one'},
|
||||
'priority' : {'field':'priority', 'type':'int'},
|
||||
'dtstamp' : {'field':'date', 'type':'datetime'},
|
||||
'seq' : None,
|
||||
'status' : {'field':'state', 'type':'selection', 'mapping' : {'TENTATIVE' : 'draft', \
|
||||
'CONFIRMED' : 'open' , 'CANCELLED' : 'cancel'}},
|
||||
'summary' : {'field':'name', 'type':'text'},
|
||||
'transp' : {'field':'transparent', 'type':'text'},
|
||||
'uid' : {'field':'id', 'type':'text'},
|
||||
'url' : {'field':'caldav_url', 'type':'text'},
|
||||
'recurid' : None,
|
||||
# 'attach' : {'field':'attachment_ids', 'sub-field':'datas', 'type':'list'},
|
||||
'attendee' : {'field':'attendees', 'type':'text'},
|
||||
# 'categories' : {'field':'categ_id', 'sub-field':'name'},
|
||||
# 'categories' : {'field':None , 'sub-field':'name', 'type':'text'}, # keep none for now
|
||||
'comment' : None,
|
||||
'contact' : None,
|
||||
'exdate' : None,
|
||||
'exrule' : None,
|
||||
'rstatus' : None,
|
||||
'related' : None,
|
||||
'resources' : None,
|
||||
'rdate' : None,
|
||||
'rrule' : {'field':'rrule', 'type':'text'},
|
||||
'x-openobject-id' : {'field':'id', 'type':'text'},
|
||||
'x-openobject-model' : {'value':_name, 'type':'text'},
|
||||
# 'duration' : {'field':'duration'},
|
||||
'dtend' : {'field':'date_closed', 'type':'datetime'},
|
||||
}
|
||||
|
||||
def _get_location(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for case in self.browse(cr, uid, ids):
|
||||
if case.partner_address_id:
|
||||
add = case.partner_address_id
|
||||
st = add.street and add.street+',\n' or ''
|
||||
st2 = add.street2 and add.street2+',\n' or ''
|
||||
ct = add.city and add.city+',\n' or ''
|
||||
zip = add.zip and add.zip or ''
|
||||
country = add.country_id and add.country_id.name+',\n' or ''
|
||||
res[case.id] = st + st2+ ct + country + zip
|
||||
else:
|
||||
res[case.id] = ''
|
||||
return res
|
||||
|
||||
def _get_rdates(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
context.update({'read':True})
|
||||
for case in self.read(cr, uid, ids, ['date', 'rrule'], context=context):
|
||||
if case['rrule']:
|
||||
rule = case['rrule'].split('\n')[0]
|
||||
exdate = case['rrule'].split('\n')[1:]
|
||||
event_obj = self.pool.get('caldav.event')
|
||||
res[case['id']] = str(event_obj.get_recurrent_dates(str(rule), exdate, case['date']))
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'categ_id': fields.many2many('crm.case.categ', 'crm_category_rel', 'case_id', 'category_id', 'Categories'),
|
||||
'class' : fields.selection([('PUBLIC', 'PUBLIC'), ('PRIVATE', 'PRIVATE'), \
|
||||
('CONFIDENTIAL', 'CONFIDENTIAL')], 'Class'),
|
||||
'location' : fields.function(_get_location, method=True, store = True, string='Location', type='text'),
|
||||
'freebusy' : fields.text('FreeBusy'),
|
||||
'transparent' : fields.selection([('OPAQUE', 'OPAQUE'), ('TRANSPARENT', 'TRANSPARENT')], 'Trensparent'),
|
||||
'caldav_url' : fields.char('Caldav URL', size=34),
|
||||
# 'attachment_ids' : function ("one2many from ir.attachemnt"),
|
||||
'attendee' : fields.text('Attendee'), #TODO : display dynamic view from text value
|
||||
'rrule' : fields.text('Recurrent Rule'),
|
||||
'rdates' : fields.function(_get_rdates, method=True, string='Recurrent Dates', \
|
||||
store=True, type='text'),
|
||||
'attendees': fields.many2many('caldav.attendee', 'crm_attendee_rel', 'case_id', 'attendee_id', 'Attendees'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'caldav_url': lambda *a: 'http://localhost:8080',
|
||||
'class': lambda *a: 'PUBLIC',
|
||||
'transparent': lambda *a: 'OPAQUE',
|
||||
}
|
||||
|
||||
def export_cal(self, cr, uid, ids, context={}):
|
||||
crm_data = self.read(cr, uid, ids, [])
|
||||
ical = vobject.iCalendar()
|
||||
event_obj = self.pool.get('caldav.event')
|
||||
for crm in crm_data:
|
||||
ical.add('vevent')
|
||||
vevent = ical.vevent
|
||||
for key, val in self.__attribute__.items():
|
||||
if val == None or key == 'rrule':
|
||||
continue
|
||||
if val.has_key('field') and val.has_key('sub-field') and crm[val['field']] and crm[val['field']]:
|
||||
vevent.add(key).value = crm[val['field']][1]
|
||||
elif val.has_key('field') and crm[val['field']]:
|
||||
if val['type'] == "text":
|
||||
vevent.add(key).value = str(crm[val['field']])
|
||||
elif val['type'] == 'datetime' and crm[val['field']]:
|
||||
vevent.add(key).value = datetime.strptime(crm[val['field']], "%Y-%m-%d %H:%M:%S")
|
||||
if crm[self.__attribute__['rrule']['field']]:
|
||||
startdate = datetime.strptime(crm['date'], "%Y-%m-%d %H:%M:%S")
|
||||
if not startdate:
|
||||
startdate = datetime.now()
|
||||
rset1 = rrulestr(str(crm[event_obj.__attribute__['rrule']['field']]), dtstart=startdate, forceset=True)
|
||||
vevent.rruleset = rset1
|
||||
|
||||
return ical.serialize().replace(vobject.icalendar.CRLF, vobject.icalendar.LF).strip()
|
||||
|
||||
def import_cal(self, cr, uid, ids, data, context={}):
|
||||
file_content = base64.decodestring(data['form']['file_path'])
|
||||
event_obj = self.pool.get('caldav.event')
|
||||
event_obj.__attribute__.update(self.__attribute__)
|
||||
event_obj.import_ical(cr, uid, file_content)
|
||||
vals = {}
|
||||
for map_dict in event_obj.__attribute__:
|
||||
map_val = event_obj.ical_get(map_dict, 'value')
|
||||
field = event_obj.ical_get(map_dict, 'field')
|
||||
field_type = event_obj.ical_get(map_dict, 'type')
|
||||
if field and map_val:
|
||||
if field_type == 'selection':
|
||||
mapping =event_obj.__attribute__[map_dict].get('mapping', False)
|
||||
if mapping:
|
||||
map_val = mapping[map_val]
|
||||
if field_type == 'many2one':
|
||||
# TODO: Map field value to many2one object
|
||||
continue # For now
|
||||
vals[field] = map_val
|
||||
# TODO: Select proper section
|
||||
section_id = self.pool.get('crm.case.section').search(cr, uid, [])[0]
|
||||
vals.update({'section_id' : section_id})
|
||||
vals.pop('id')
|
||||
vals.pop('create_date')
|
||||
case_id = self.create(cr, uid, vals)
|
||||
return
|
||||
|
||||
def search(self, cr, uid, args, offset=0, limit=None, order=None,
|
||||
context=None, count=False):
|
||||
res = super(crm_case, self).search(cr, uid, args, offset,
|
||||
limit, order, context, count)
|
||||
return res
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
res = super(crm_case, self).write(cr, uid, ids, vals, context=context)
|
||||
return res
|
||||
|
||||
def browse(self, cr, uid, select, context=None, list_class=None, fields_process={}):
|
||||
select = map(lambda x:int(str(x).split('-')[0]), select)
|
||||
return super(crm_case, self).browse(cr, uid, select, context, list_class, fields_process)
|
||||
|
||||
def read(self, cr, uid, ids, fields=None, context={},
|
||||
load='_classic_read'):
|
||||
""" logic for recurrent event
|
||||
example : 123-20091111170822"""
|
||||
if context and context.has_key('read'):
|
||||
return super(crm_case, self).read(cr, uid, ids, fields=fields, context=context, load=load)
|
||||
ids = map(lambda x:int(str(x).split('-')[0]), ids)
|
||||
res = super(crm_case, self).read(cr, uid, ids, fields=fields, context=context, load=load)
|
||||
result = res + []
|
||||
read_ids = ",".join([str(x) for x in ids])
|
||||
cr.execute('select id,rrule,rdates from crm_case where id in (%s)' % read_ids)
|
||||
rrules = filter(lambda x: not x['rrule']==None, cr.dictfetchall())
|
||||
rdates = []
|
||||
for data in rrules:
|
||||
if data['rrule'] and data['rdates']: # delete 2nd condition at last
|
||||
rdates = eval(data['rdates'])
|
||||
for res_temp in res:
|
||||
if res_temp['id'] == data['id']:
|
||||
val = res_temp
|
||||
if rdates:
|
||||
result.remove(val)
|
||||
|
||||
for rdate in rdates:
|
||||
import re
|
||||
idval = (re.compile('\d')).findall(rdate)
|
||||
val['date'] = rdate
|
||||
id = str(val['id']).split('-')[0]
|
||||
val['id'] = id + '-' + ''.join(idval)
|
||||
val1 = val.copy()
|
||||
result += [val1]
|
||||
return result
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
#TODO: Change RRULE
|
||||
for id in ids:
|
||||
if len(str(id).split('-')) > 1:
|
||||
date_new = time.strftime("%Y-%m-%d %H:%M:%S", time.strptime(str(str(id).split('-')[1]), "%Y%m%d%H%M%S"))
|
||||
for record in self.read(cr, uid, [str(id).split('-')[0]], ['date', 'rdates', 'rrule']):
|
||||
if record['date'] == date_new:
|
||||
self.write(cr, uid, [int(str(id).split('-')[0])], {'rrule' : record['rrule'] +"\n" + str(date_new)})
|
||||
else:
|
||||
return super(crm_case, self).unlink(cr, uid, ids)
|
||||
crm_case()
|
||||
|
||||
|
||||
class ir_attachment(osv.osv):
|
||||
_name = 'ir.attachment'
|
||||
_inherit = 'ir.attachment'
|
||||
|
||||
def search_count(self, cr, user, args, context=None):
|
||||
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)
|
||||
|
||||
ir_attachment()
|
||||
@@ -36,7 +36,7 @@ class crm_segmentation(osv.osv):
|
||||
'description': fields.text('Description'),
|
||||
'categ_id': fields.many2one('res.partner.category', 'Partner Category', required=True, help='The partner category that will be added to partners that match the segmentation criterions after computation.'),
|
||||
'exclusif': fields.boolean('Exclusive', help='Check if the category is limited to partners that match the segmentation criterions. If checked, remove the category from partners that doesn\'t match segmentation criterions'),
|
||||
'state': fields.selection([('not running','Not Running'),('running','Running')], 'Execution State', readonly=True),
|
||||
'state': fields.selection([('not running','Not Running'),('running','Running')], 'Execution Status', readonly=True),
|
||||
'partner_id': fields.integer('Max Partner ID processed'),
|
||||
'segmentation_line': fields.one2many('crm.segmentation.line', 'segmentation_id', 'Criteria', required=True),
|
||||
'som_interval': fields.integer('Days per Periode', help="A period is the average number of days between two cycle of sale or purchase for this segmentation. It's mainly used to detect if a partner has not purchased or buy for a too long time, so we suppose that his state of mind has decreased because he probably bought goods to another supplier. Use this functionality for recurring businesses."),
|
||||
|
||||
@@ -706,5 +706,42 @@
|
||||
</record>
|
||||
<menuitem id="crm_email_gateway_server_menu" name="Email Gateway Server" parent="next_id_51" action="crm_email_gateway_server_act" />
|
||||
|
||||
<!-- Caldav configartion view -->
|
||||
|
||||
<record id="view_config_crm_caldav_menu" model="ir.ui.view">
|
||||
<field name="name">Configure Menu for Caldav Properites</field>
|
||||
<field name="model">crm.calendar.config_wizard</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Configure view for Caldav Properites">
|
||||
<separator colspan="4" string=""/>
|
||||
<label colspan="4" align="0.0" string="This will provide a detailed view for caldav properties configuration"/>
|
||||
<newline/>
|
||||
<field name="caldav"/>
|
||||
<separator colspan="4" string=""/>
|
||||
<group col="4" colspan="4">
|
||||
<button icon="gtk-cancel" name="action_cancel" type="object" special="cancel" string="Cancel"/>
|
||||
<button icon="gtk-go-forward" name="action_create" string="Next" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_config_crm_caldav_menu" model="ir.actions.act_window">
|
||||
<field name="name">Configure Menu for Caldav Properites</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">crm.calendar.config_wizard</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<!-- register configuration wizard -->
|
||||
<record id="config_wizard_step_cam_caldav_menu" model="ir.actions.todo">
|
||||
<field name="name">Configure Menu for Caldav Properites</field>
|
||||
<field name="note">This Configuration step use to provide a detailed view for caldav properties configuration</field>
|
||||
<field name="action_id" ref="action_view_config_crm_caldav_menu"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -23,6 +23,8 @@ import crm_wizard
|
||||
import wizard_crm_send_email
|
||||
import wizard_crm_new_send_email
|
||||
import wizard_fetch_mail
|
||||
import wizard_cal_export
|
||||
import wizard_cal_import
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import tools
|
||||
import wizard
|
||||
import os
|
||||
import mx.DateTime
|
||||
import base64
|
||||
import pooler
|
||||
import vobject
|
||||
|
||||
|
||||
class crm_cal_export_wizard(wizard.interface):
|
||||
form1 = '''<?xml version="1.0"?>
|
||||
<form string="Export ICS">
|
||||
<separator string="Save ICS file"/>
|
||||
<field name="file_path" colspan="4" width="300" nolabel="1"/>
|
||||
</form>'''
|
||||
|
||||
form1_fields = {
|
||||
'file_path': {
|
||||
'string': 'Select ICS file',
|
||||
'type': 'binary',
|
||||
'required' : True,
|
||||
'filters' : '*.ics'
|
||||
}
|
||||
}
|
||||
|
||||
def _process_export_ics(self, cr, uid, data, context):
|
||||
case_obj = pooler.get_pool(cr.dbname).get('crm.case')
|
||||
calendar = case_obj.export_cal(cr, uid, data['ids'], context)
|
||||
return {'file_path': base64.encodestring(calendar)}
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [_process_export_ics],
|
||||
'result': {'type': 'form', 'arch':form1, 'fields':form1_fields, 'state': [('end', '_Cancel', 'gtk-cancel'), ('end', 'Ok', 'gtk-ok')]}
|
||||
},
|
||||
}
|
||||
|
||||
crm_cal_export_wizard('caldav.crm.export')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import tools
|
||||
import wizard
|
||||
import os
|
||||
import mx.DateTime
|
||||
import base64
|
||||
import pooler
|
||||
import vobject
|
||||
|
||||
|
||||
class crm_cal_import_wizard(wizard.interface):
|
||||
form1 = '''<?xml version="1.0"?>
|
||||
<form string="Import ICS">
|
||||
<separator string="Select ICS file"/>
|
||||
<field name="file_path" colspan="4" width="300" nolabel="1"/>
|
||||
</form>'''
|
||||
|
||||
form1_fields = {
|
||||
'file_path': {
|
||||
'string': 'Select ICS file',
|
||||
'type': 'binary',
|
||||
'required' : True,
|
||||
'filters' : '*.ics'
|
||||
}
|
||||
}
|
||||
|
||||
def _process_import_ics(self, cr, uid, data, context=None):
|
||||
case_obj = pooler.get_pool(cr.dbname).get('crm.case')
|
||||
case_obj.import_cal(cr, uid, data['ids'], data, context)
|
||||
return {}
|
||||
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {'type': 'form', 'arch':form1, 'fields':form1_fields, 'state': [('end', '_Cancel', 'gtk-cancel'), ('open', '_Import', 'gtk-ok')]}
|
||||
},
|
||||
'open': {
|
||||
'actions': [],
|
||||
'result': {'type': 'action', 'action':_process_import_ics, 'state':'end'}
|
||||
}
|
||||
}
|
||||
|
||||
crm_cal_import_wizard('caldav.crm.import')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -46,7 +46,7 @@ email_send_form = '''<?xml version="1.0"?>
|
||||
<field name="doc2" />
|
||||
<newline/>
|
||||
<field name="doc3" />
|
||||
<separator colspan="4" string="State of Case"/>
|
||||
<separator colspan="4" string="Set case state to"/>
|
||||
<newline/>
|
||||
<field name="state" />
|
||||
</form>'''
|
||||
@@ -81,7 +81,7 @@ def _mass_mail_send(self, cr, uid, data, context):
|
||||
emails = filter(None, emails)
|
||||
body = data['form']['text']
|
||||
if not case.user_id.address_id.email:
|
||||
raise wizard.except_wizard(_('Warning!'),("Please specify user's email address"))
|
||||
raise wizard.except_wizard(_('Warning!'),_("Please specify user's email address !"))
|
||||
if case.user_id.signature:
|
||||
body += '\n\n%s' % (case.user_id.signature)
|
||||
case_pool._history(cr, uid, [case], _('Send'), history=True, email=False, details=body)
|
||||
@@ -103,10 +103,8 @@ def _mass_mail_send(self, cr, uid, data, context):
|
||||
elif data['form']['state'] == 'pending':
|
||||
case_pool.case_pending(cr, uid, data['ids'])
|
||||
cr.commit()
|
||||
raise wizard.except_wizard(_('Message!'),("Email Successfully Sent..!!"))
|
||||
|
||||
else:
|
||||
raise wizard.except_wizard(_('Warning!'),("Email is not sent Successfully"))
|
||||
raise wizard.except_wizard(_('Warning!'),_("Email not sent !"))
|
||||
return {}
|
||||
|
||||
def _get_info(self, cr, uid, data, context):
|
||||
@@ -114,11 +112,11 @@ def _get_info(self, cr, uid, data, context):
|
||||
return {}
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
case = pool.get('crm.case').browse(cr,uid,data['ids'])[0]
|
||||
if not case.email_from:
|
||||
raise wizard.except_wizard(_('Error'),_('You must put a Partner eMail to use this action!'))
|
||||
#if not case.email_from:
|
||||
# raise wizard.except_wizard(_('Error'),_('You must put a Partner eMail to use this action!'))
|
||||
if not case.user_id:
|
||||
raise wizard.except_wizard(_('Error'),_('You must define a responsible user for this case in order to use this action!'))
|
||||
return {'to': case.email_from,'subject': '['+str(case.id)+'] '+case.name,'cc': case.email_cc or ''}
|
||||
return {'to': case.email_from,'subject': case.name,'cc': case.email_cc or ''}
|
||||
|
||||
class wizard_send_mail(wizard.interface):
|
||||
states = {
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
<field name="partner_mobile"/>
|
||||
<field name="email_from" string="Prospect Email"/>
|
||||
<newline/>
|
||||
<group colspan="2" col="4">
|
||||
<label string="Partner:" colspan="1" align="1.0"/>
|
||||
<field name="partner_id" nolabel="1" colspan="2"/>
|
||||
<button string="Convert to Partner"
|
||||
icon="terp-partner" name="%(wizard_crm_partner_create)d"
|
||||
type="action" attrs="{'invisible':[('partner_id','!=',False)]}"
|
||||
/>
|
||||
</group>
|
||||
<label string="Partner:" colspan="1" align="1.0"/>
|
||||
<group colspan="2" col="2">
|
||||
<field name="partner_id" nolabel="1" colspan="1"/>
|
||||
<button string="Convert to Partner"
|
||||
icon="terp-partner" name="%(wizard_crm_partner_create)d"
|
||||
type="action" attrs="{'invisible':[('partner_id','!=',False)]}"
|
||||
/>
|
||||
</group>
|
||||
<field name="partner_address_id" string="Contact" on_change="onchange_partner_address_id(partner_address_id, email_from)"/>
|
||||
|
||||
<field name="priority" string="Priority"/>
|
||||
@@ -116,9 +116,9 @@
|
||||
<field name="email"/>
|
||||
<field name="canal_id"/>
|
||||
<button
|
||||
string="Add a CC"
|
||||
name="%(crm.action_view_crm_email_add_cc_wizard)d"
|
||||
icon="gtk-add" type="action"/>
|
||||
string="Add a CC"
|
||||
name="%(crm.action_view_crm_email_add_cc_wizard)d"
|
||||
icon="gtk-add" type="action"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<field name="description" colspan="4" nolabel="1"/>
|
||||
@@ -173,7 +173,7 @@
|
||||
</record>
|
||||
|
||||
|
||||
<record id="view_crm_case_leads_filter" model="ir.ui.view">
|
||||
<record id="view_crm_case_leads_filter" model="ir.ui.view">
|
||||
<field name="name">crm.case.leads.select</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="type">search</field>
|
||||
@@ -181,27 +181,27 @@
|
||||
<search string="Search Prospects">
|
||||
<group col="3" colspan="1">
|
||||
<filter icon="gtk-home" string=" Today "
|
||||
separator="1"
|
||||
domain="[('date::date','=',time.strftime('%%Y-%%m-%%d'))]"
|
||||
help="Todays's Prospects"
|
||||
separator="1"
|
||||
domain="[('date::date','=',time.strftime('%%Y-%%m-%%d'))]"
|
||||
help="Todays's Prospects"
|
||||
/>
|
||||
<filter icon="gtk-media-rewind" string=" 7 Days "
|
||||
separator="1" help="Prospects during last 7 days"
|
||||
domain="[('date::date','<', time.strftime('%%Y-%%m-%%d')), ('date::date','>=',(datetime.date.today()-datetime.timedelta(days=7)).strftime('%%Y-%%m-%%d'))]"
|
||||
separator="1" help="Prospects during last 7 days"
|
||||
domain="[('date::date','<', time.strftime('%%Y-%%m-%%d')), ('date::date','>=',(datetime.date.today()-datetime.timedelta(days=7)).strftime('%%Y-%%m-%%d'))]"
|
||||
/>
|
||||
</group>
|
||||
<separator orientation="vertical"/>
|
||||
<group col="4" colspan="2">
|
||||
<field name="name" select="1"/>
|
||||
<field name="user_id" select="1" widget="selection">
|
||||
<filter icon="terp-partner"
|
||||
domain="[('user_id','=',uid)]" help="My Prospects"
|
||||
default="1"
|
||||
/>
|
||||
<filter icon="terp-crm"
|
||||
domain="[('user_id','child_of',[uid])]"
|
||||
help="My department's Prospects"
|
||||
/>
|
||||
<filter icon="terp-partner"
|
||||
domain="[('user_id','=',uid)]" help="My Prospects"
|
||||
default="1"
|
||||
/>
|
||||
<filter icon="terp-crm"
|
||||
domain="[('user_id','child_of',[uid])]"
|
||||
help="My department's Prospects"
|
||||
/>
|
||||
</field>
|
||||
<field name="state" select="1">
|
||||
<filter icon="gtk-new" domain="[('state','=','draft')]" help="Draft Prospects"/>
|
||||
|
||||
Reference in New Issue
Block a user