diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml
index e1122e07674..f6b41f318ed 100644
--- a/addons/account_voucher/voucher_payment_receipt_view.xml
+++ b/addons/account_voucher/voucher_payment_receipt_view.xml
@@ -182,9 +182,6 @@
-
diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index df5aaa4287d..c4c719c5008 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -477,7 +477,7 @@ property or property parameter."),
@param context: A standard dictionary for contextual values
@return: True
"""
- if not context:
+ if context is None:
context = {}
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.name
@@ -555,7 +555,7 @@ property or property parameter."),
@param context: A standard dictionary for contextual values
@return: True
"""
- if not context:
+ if context is None:
context = {}
for vals in self.browse(cr, uid, ids, context=context):
@@ -575,7 +575,7 @@ property or property parameter."),
@param ids: List of calendar attendee’s IDs
@param *args: Get Tupple value
@param context: A standard dictionary for contextual values """
- if not context:
+ if context is None:
context = {}
return self.write(cr, uid, ids, {'state': 'declined'}, context)
@@ -587,7 +587,7 @@ property or property parameter."),
@param vals: Get Values
@param context: A standard dictionary for contextual values """
- if not context:
+ if context is None:
context = {}
if not vals.get("email") and vals.get("cn"):
cnval = vals.get("cn").split(':')
@@ -641,7 +641,7 @@ true, it will allow you to hide the event alarm information without removing it.
@param context: A standard dictionary for contextual values
@return: True
"""
- if not context:
+ if context is None:
context = {}
alarm_obj = self.pool.get('calendar.alarm')
res_alarm_obj = self.pool.get('res.alarm')
@@ -713,7 +713,7 @@ true, it will allow you to hide the event alarm information without removing it.
@param model: Model name for which alarm is to be cleared.
@return: True
"""
- if not context:
+ if context is None:
context = {}
alarm_obj = self.pool.get('calendar.alarm')
ir_obj = self.pool.get('ir.model')
@@ -781,7 +781,7 @@ class calendar_alarm(osv.osv):
@param context: A standard dictionary for contextual values
@return: new record id for calendar_alarm.
"""
- if not context:
+ if context is None:
context = {}
event_date = vals.get('event_date', False)
if event_date:
@@ -808,7 +808,7 @@ class calendar_alarm(osv.osv):
@param context: A standard dictionary for contextual values
"""
return True # XXX FIXME REMOVE THIS AFTER FIXING get_recurrent_dates!!
- if not context:
+ if context is None:
context = {}
current_datetime = datetime.now()
request_obj = self.pool.get('res.request')
@@ -943,8 +943,9 @@ class calendar_event(osv.osv):
@param end_date: Ending Datee
@param context: A standard dictionary for contextual values
"""
- if not context:
+ if context is None:
context = {}
+
value = {}
if not start_date:
return value
@@ -967,6 +968,14 @@ class calendar_event(osv.osv):
elif not end_date:
end = start + timedelta(hours=duration)
value['date_deadline'] = end.strftime("%Y-%m-%d %H:%M:%S")
+ elif end_date and duration:
+ # we have both, keep them synchronized:
+ # 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
+ duration = float(diff.days)* 24 + (float(diff.seconds) / 3600)
+ value['duration'] = round(duration, 2)
return {'value': value}
@@ -975,7 +984,7 @@ class calendar_event(osv.osv):
This function deletes event which are linked with the event with recurrent_uid
(Removes the events which refers to the same UID value)
"""
- if not context:
+ if context is None:
context = {}
for event_id in ids:
cr.execute("select id from %s where recurrent_uid=%%s" % (self._table), (event_id,))
@@ -992,7 +1001,7 @@ class calendar_event(osv.osv):
@param context: A standard dictionary for contextual values
@return: dictionary of rrule value.
"""
- if not context:
+ 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,\
@@ -1203,7 +1212,7 @@ true, it will allow you to hide the event alarm information without removing it.
@param context: A standard dictionary for contextual values
@return: Dictionary value which open Crm Meeting form.
"""
- if not context:
+ if context is None:
context = {}
data_obj = self.pool.get('ir.model.data')
@@ -1448,7 +1457,7 @@ true, it will allow you to hide the event alarm information without removing it.
@param context: A standard dictionary for contextual values
@return: True
"""
- if not context:
+ if context is None:
context = {}
if isinstance(ids, (str, int, long)):
select = [ids]
@@ -1477,14 +1486,23 @@ true, it will allow you to hide the event alarm information without removing it.
if vals.get('vtimezone', '').startswith('/freeassociation.sourceforge.net/tzfile/'):
vals['vtimezone'] = vals['vtimezone'][40:]
+
+ 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 new_ids:
res = super(calendar_event, self).write(cr, uid, new_ids, vals, context=context)
- if (vals.has_key('alarm_id') or vals.has_key('base_calendar_alarm_id'))\
- or (vals.has_key('date') or vals.has_key('duration') or vals.has_key('date_deadline')):
+
+ 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)
+ alarm_obj.do_alarm_create(cr, uid, new_ids, self._name, 'date', context=context)
return res
def browse(self, cr, uid, ids, context=None, list_class=None, fields_process=None):
@@ -1520,7 +1538,7 @@ true, it will allow you to hide the event alarm information without removing it.
@return: List of Dictionary of form [{‘name_of_the_field’: value, ...}, ...]
"""
# FIXME This whole id mangling has to go!
- if not context:
+ if context is None:
context = {}
if isinstance(ids, (str, int, long)):
@@ -1558,7 +1576,7 @@ true, it will allow you to hide the event alarm information without removing it.
@param context: A standard dictionary for contextual values
@return: Duplicate record id.
"""
- if not context:
+ 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')
@@ -1607,10 +1625,12 @@ true, it will allow you to hide the event alarm information without removing it.
@param context: A standard dictionary for contextual values
@return: new created record id.
"""
- if not context:
+ if context is None:
context = {}
+
if vals.get('vtimezone', '') and vals.get('vtimezone', '').startswith('/freeassociation.sourceforge.net/tzfile/'):
vals['vtimezone'] = vals['vtimezone'][40:]
+
res = super(calendar_event, self).create(cr, uid, vals, context)
alarm_obj = self.pool.get('res.alarm')
alarm_obj.do_alarm_create(cr, uid, [res], self._name, 'date', context=context)
@@ -1770,7 +1790,7 @@ class ir_values(osv.osv):
@param uid: the current user’s ID for security checks,
@param model: Get The Model
"""
- if not context:
+ if context is None:
context = {}
new_model = []
for data in models:
@@ -1798,7 +1818,7 @@ class ir_model(osv.osv):
@param context: A standard dictionary for contextual values
"""
new_ids = isinstance(ids, (str, int, long)) and [ids] or ids
- if not context:
+ if context is None:
context = {}
data = super(ir_model, self).read(cr, uid, new_ids, fields=fields, \
context=context, load=load)
diff --git a/addons/pad/LICENSE b/addons/pad/LICENSE
new file mode 100644
index 00000000000..cff5dae3a7b
--- /dev/null
+++ b/addons/pad/LICENSE
@@ -0,0 +1,15 @@
+OpenERP, Open Source Management Solution
+Copyright © 2010 OpenERP SA ().
+
+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 Lice
+along with this program. If not, see .
\ No newline at end of file
diff --git a/addons/pad/__init__.py b/addons/pad/__init__.py
new file mode 100644
index 00000000000..6a60bdb9799
--- /dev/null
+++ b/addons/pad/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+import company_pad
diff --git a/addons/pad/__openerp__.py b/addons/pad/__openerp__.py
new file mode 100644
index 00000000000..4b5e3ca959e
--- /dev/null
+++ b/addons/pad/__openerp__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': 'Enhanced support for (Ether)Pad attachments',
+ 'version': '1.0',
+ 'category': 'Generic Modules/Others',
+ 'description': """
+Adds enhanced support for (Ether)Pad attachments in the web client, lets the
+company customize which Pad installation should be used to link to new pads
+(by default, pad.openerp.com)
+ """,
+ 'author': 'OpenERP SA',
+ 'website': 'http://openerp.com',
+ 'depends': ['base'],
+ 'update_xml': [
+ 'company_pad.xml'
+ ],
+ 'installable': True,
+ 'active': False,
+ 'web': True,
+}
diff --git a/addons/pad/company_pad.py b/addons/pad/company_pad.py
new file mode 100644
index 00000000000..1e687704eac
--- /dev/null
+++ b/addons/pad/company_pad.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from osv import fields, osv
+
+class company_pad(osv.osv):
+ _inherit = 'res.company'
+ _columns = {
+ 'pad_index': fields.char('Pad root URL', size=64, required=True,
+ help="The root URL of the company's pad "
+ "instance"),
+ }
+ _defaults = {
+ 'pad_index': 'http://pad.openerp.com'
+ }
+
+company_pad()
diff --git a/addons/pad/company_pad.xml b/addons/pad/company_pad.xml
new file mode 100644
index 00000000000..754776715d7
--- /dev/null
+++ b/addons/pad/company_pad.xml
@@ -0,0 +1,16 @@
+
+
+
+ res.company.form.pad
+ res.company
+ form
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/pad/web/__init__.py b/addons/pad/web/__init__.py
new file mode 100644
index 00000000000..95542e91e3e
--- /dev/null
+++ b/addons/pad/web/__init__.py
@@ -0,0 +1,2 @@
+import controllers
+import editors
diff --git a/addons/pad/web/controllers.py b/addons/pad/web/controllers.py
new file mode 100644
index 00000000000..faa5d0ad54b
--- /dev/null
+++ b/addons/pad/web/controllers.py
@@ -0,0 +1,34 @@
+import urlparse
+
+import cherrypy
+
+from openobject.tools import expose
+
+import openerp.controllers
+from openerp.utils import rpc, TinyDict
+
+class Piratepad(openerp.controllers.SecuredController):
+ _cp_path = "/piratepad"
+
+ def get_root(self):
+ return rpc.RPCProxy('res.company').read(
+ [rpc.session.company_id], ['pad_index'])[0]['pad_index']
+
+ def make_url(self, pad_name):
+ return urlparse.urljoin(
+ self.get_root(), '-'.join(pad_name.split())
+ )
+
+ @expose('json', methods=('POST',))
+ def link(self, pad_name):
+ params, data = TinyDict.split(cherrypy.session['params'])
+ ctx = dict(rpc.session.context,
+ default_res_model=params.model, default_res_id=params.id,
+ active_id=False, active_ids=[])
+
+ pad_link = self.make_url(pad_name)
+ attachment_id = rpc.RPCProxy('ir.attachment').create({
+ 'name': pad_name,
+ 'url': pad_link,
+ }, ctx)
+ return {'id': attachment_id, 'name': pad_name, 'url': pad_link}
diff --git a/addons/pad/web/editors.py b/addons/pad/web/editors.py
new file mode 100644
index 00000000000..62ff426a623
--- /dev/null
+++ b/addons/pad/web/editors.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+import openobject.templating
+
+class SidebarTemplateEditor(openobject.templating.TemplateEditor):
+ templates = ['/openerp/widgets/templates/sidebar.mako']
+ ADD_ATTACHMENT_BUTTON = u'id="add-attachment"'
+ BINARY_ATTACHMENTS_FORM = u'
+
+ ''' + output[form_insertion_point:]
diff --git a/addons/profile_tools/installer.py b/addons/profile_tools/installer.py
index 6ea024aebbe..fac23e8299d 100644
--- a/addons/profile_tools/installer.py
+++ b/addons/profile_tools/installer.py
@@ -31,6 +31,11 @@ class misc_tools_installer(osv.osv_memory):
'idea':fields.boolean('Ideas Box',help='Promote ideas of the employees, votes and discussion on best ideas.'),
'share':fields.boolean('Share Data / Portals',help='This module allows you to easily give restricted access of any filtered list of objects to any customer or supplier.' \
'Just click on the share icon to give access to your customers on their project\'s tasks, support requests, invoices, etc.'),
+ 'pad': fields.boolean('Native pad integration',
+ help="This module creates a tighter integration between a Pad "
+ "instance of your choosing and your OpenERP Web Client by "
+ "letting you easily link pads to OpenERP objects via "
+ "OpenERP attachments."),
}
_defaults = {
}
diff --git a/addons/profile_tools/misc_tools_installer.xml b/addons/profile_tools/misc_tools_installer.xml
index d81936756a6..b3d343d8c30 100644
--- a/addons/profile_tools/misc_tools_installer.xml
+++ b/addons/profile_tools/misc_tools_installer.xml
@@ -30,6 +30,7 @@
+