diff --git a/addons/audittrail/i18n/el.po b/addons/audittrail/i18n/el.po
index 6abb75f9b34..bc7c28dcb83 100644
--- a/addons/audittrail/i18n/el.po
+++ b/addons/audittrail/i18n/el.po
@@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-24 02:58+0000\n"
+"PO-Revision-Date: 2010-06-24 21:17+0000\n"
"Last-Translator: Panayiotis Konstantinidis \n"
"Language-Team: Greek \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: audittrail
@@ -159,153 +159,157 @@ msgid ""
" Subscribe Rules for read, write, create and delete on objects and check "
"logs"
msgstr ""
+"Επιστρέπει στον Διαχειριστή να ακολουθεί τα ίχνη κάθε λειτουργίας του χρήστη "
+"σε όλα τα αντικείμενα του συστήματος.\n"
+" Εισάγεται κανόνες για ανάγνωση, εγγραφή, δημιουργία και διαγραφή στα "
+"αντικείμενα και τα ημερολόγια ελέγχου."
#. module: audittrail
#: field:audittrail.log,timestamp:0
msgid "Date"
-msgstr ""
+msgstr "Ημερομηνία"
#. module: audittrail
#: field:audittrail.log,user_id:0
msgid "User"
-msgstr ""
+msgstr "Χρήστης"
#. module: audittrail
#: view:audittrail.log:0
msgid "Old Value Text : "
-msgstr ""
+msgstr "Παλιά τιμή κειμένου: "
#. module: audittrail
#: constraint:ir.ui.view:0
msgid "Invalid XML for View Architecture!"
-msgstr ""
+msgstr "Λανθασμένο XML για αρχιτεκτονική όψης!"
#. module: audittrail
#: field:audittrail.log,name:0
msgid "Name"
-msgstr ""
+msgstr "Όνομα"
#. module: audittrail
#: field:audittrail.log,line_ids:0
msgid "Log lines"
-msgstr ""
+msgstr "Γραμμές ημερολογίου"
#. module: audittrail
#: model:ir.ui.menu,name:audittrail.menu_action_audittrail_rule_tree_sub
msgid "Subscribed Rules"
-msgstr ""
+msgstr "Εγγεγραμμένοι Κανόνες"
#. module: audittrail
#: field:audittrail.log.line,field_id:0
msgid "Fields"
-msgstr ""
+msgstr "Πεδία"
#. module: audittrail
#: view:audittrail.rule:0
msgid "AuditTrail Rules"
-msgstr ""
+msgstr "Κανόνες διαδρομής ελέγχου"
#. module: audittrail
#: model:ir.model,name:audittrail.model_audittrail_rule
msgid "audittrail.rule"
-msgstr ""
+msgstr "ελεγκτική ιχνηλάτηση.κανόνες"
#. module: audittrail
#: view:audittrail.rule:0
msgid "UnSubscribe"
-msgstr ""
+msgstr "Διαγραφείτε"
#. module: audittrail
#: field:audittrail.rule,log_write:0
msgid "Log writes"
-msgstr ""
+msgstr "Εγγραφές ημερολογίου"
#. module: audittrail
#: model:ir.model,name:audittrail.model_audittrail_log
msgid "audittrail.log"
-msgstr ""
+msgstr "ελεγκτική ιχνηλάτηση.ημερολόγιο"
#. module: audittrail
#: field:audittrail.log.line,field_description:0
msgid "Field Description"
-msgstr ""
+msgstr "Περιγραφή πεδίου"
#. module: audittrail
#: selection:audittrail.log,method:0
msgid "Delete"
-msgstr ""
+msgstr "Διαγραφή"
#. module: audittrail
#: wizard_button:audittrail.view.log,init,open:0
msgid "Open Logs"
-msgstr ""
+msgstr "Άνοιγμα ημερολογίων"
#. module: audittrail
#: field:audittrail.log.line,new_value_text:0
msgid "New value Text"
-msgstr ""
+msgstr "Νέα τιμή κειμένου"
#. module: audittrail
#: field:audittrail.rule,name:0
msgid "Rule Name"
-msgstr ""
+msgstr "Όνομα Κανόνα"
#. module: audittrail
#: field:audittrail.rule,log_read:0
msgid "Log reads"
-msgstr ""
+msgstr "Αναγνώσεις ημερολογίων"
#. module: audittrail
#: model:ir.ui.menu,name:audittrail.menu_action_audittrail_log_tree
msgid "Logs"
-msgstr ""
+msgstr "Αρχεία καταγραφής"
#. module: audittrail
#: field:audittrail.log.line,new_value:0
msgid "New Value"
-msgstr ""
+msgstr "Νέα τιμή"
#. module: audittrail
#: model:ir.ui.menu,name:audittrail.menu_action_log_tree2
msgid "View Logs"
-msgstr ""
+msgstr "Δείτε τα αρχεία καταγραφής"
#. module: audittrail
#: field:audittrail.rule,log_create:0
msgid "Log creates"
-msgstr ""
+msgstr "Δημιουργία αρχείων καταγραφής"
#. module: audittrail
#: view:audittrail.log:0
msgid "AuditTrail Logs"
-msgstr ""
+msgstr "παρακολούθηση της πόρειας των αρχείων καταγραφής"
#. module: audittrail
#: model:ir.ui.menu,name:audittrail.menu_action_audittrail_rule_tree
msgid "Rules"
-msgstr ""
+msgstr "Κανόνες"
#. module: audittrail
#: view:audittrail.log:0
msgid "New Value : "
-msgstr ""
+msgstr "Νέα τιμή : "
#. module: audittrail
#: field:audittrail.rule,user_id:0
msgid "Users"
-msgstr ""
+msgstr "Χρήστες"
#. module: audittrail
#: field:audittrail.log.line,old_value_text:0
msgid "Old value Text"
-msgstr ""
+msgstr "Παλιά τιμή κειμένου"
#. module: audittrail
#: wizard_button:audittrail.view.log,init,end:0
msgid "Cancel"
-msgstr ""
+msgstr "Ακύρωση"
#. module: audittrail
#: field:audittrail.rule,log_unlink:0
msgid "Log deletes"
-msgstr ""
+msgstr "Διαγραφή αρχείων καταγραφής"
diff --git a/addons/audittrail/i18n/es.po b/addons/audittrail/i18n/es.po
index d2537ed39b8..dda9f7880f3 100644
--- a/addons/audittrail/i18n/es.po
+++ b/addons/audittrail/i18n/es.po
@@ -7,14 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-11-17 08:59+0000\n"
-"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
-"\n"
+"PO-Revision-Date: 2010-06-27 21:04+0000\n"
+"Last-Translator: Borja López Soilán (Pexego) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-22 04:16+0000\n"
+"X-Launchpad-Export-Date: 2010-06-28 03:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: audittrail
@@ -83,7 +82,7 @@ msgstr "Ver registro"
#. module: audittrail
#: model:ir.model,name:audittrail.model_audittrail_log_line
msgid "audittrail.log.line"
-msgstr "audittrail.registro.linea"
+msgstr "auditoria.registro.linea"
#. module: audittrail
#: field:audittrail.log,method:0
@@ -212,7 +211,7 @@ msgstr "Reglas de auditoría"
#. module: audittrail
#: model:ir.model,name:audittrail.model_audittrail_rule
msgid "audittrail.rule"
-msgstr "audittrail.regla"
+msgstr "auditoria.regla"
#. module: audittrail
#: view:audittrail.rule:0
@@ -227,7 +226,7 @@ msgstr "Registrar escrituras"
#. module: audittrail
#: model:ir.model,name:audittrail.model_audittrail_log
msgid "audittrail.log"
-msgstr "audittrail.registro"
+msgstr "auditoria.registro"
#. module: audittrail
#: field:audittrail.log.line,field_description:0
diff --git a/addons/base_action_rule/__openerp__.py b/addons/base_action_rule/__openerp__.py
index ab1ae6c965b..cdb62316d15 100644
--- a/addons/base_action_rule/__openerp__.py
+++ b/addons/base_action_rule/__openerp__.py
@@ -27,7 +27,9 @@
'author': 'Tiny',
'website': 'http://www.openerp.com',
'depends': ['base'],
- 'init_xml': [],
+ 'init_xml': [
+ 'base_action_rule_data.xml'
+ ],
'update_xml': [
'base_action_rule_view.xml',
'security/ir.model.access.csv',
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index a1213dd7542..405c3155619 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -19,14 +19,16 @@
#
##############################################################################
-import time
-import mx.DateTime
-import re
-
-import tools
+from datetime import datetime
from osv import fields, osv, orm
from osv.orm import except_orm
+from osv.osv import osv_pool
from tools.translate import _
+import mx.DateTime
+import pooler
+import re
+import time
+import tools
class base_action_rule(osv.osv):
""" Base Action Rules """
@@ -93,23 +95,23 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
'trg_state_to': fields.selection(_state_get, 'Button Pressed', size=16),
'act_method': fields.char('Call Object Method', size=64),
- 'act_user_id': fields.many2one('res.users', 'Set responsible to'),
- 'act_state': fields.selection(_state_get, 'Set state to', size=16),
- 'act_email_cc': fields.char('Add watchers (Cc)', size=250, help="\
+ 'act_user_id': fields.many2one('res.users', 'Set Responsible to'),
+ 'act_state': fields.selection(_state_get, 'Set State to', size=16),
+ 'act_email_cc': fields.char('Add Watchers (Cc)', size=250, help="\
These people will receive a copy of the future communication between partner \
and users by email"),
'act_remind_partner': fields.boolean('Remind Partner', help="Check \
this if you want the rule to send a reminder by email to the partner."),
- 'act_remind_user': fields.boolean('Remind responsible', help="Check \
+ 'act_remind_user': fields.boolean('Remind Responsible', help="Check \
this if you want the rule to send a reminder by email to the user."),
'act_reply_to': fields.char('Reply-To', size=64),
- 'act_remind_attach': fields.boolean('Remind with attachment', help="Check this if you want that all documents attached to the object be attached to the reminder email sent."),
- 'act_mail_to_user': fields.boolean('Mail to responsible', help="Check\
+ 'act_remind_attach': fields.boolean('Remind with Attachment', help="Check this if you want that all documents attached to the object be attached to the reminder email sent."),
+ 'act_mail_to_user': fields.boolean('Mail to Responsible', help="Check\
this if you want the rule to send an email to the responsible person."),
- 'act_mail_to_watchers': fields.boolean('Mail to watchers (CC)',
+ 'act_mail_to_watchers': fields.boolean('Mail to Watchers (CC)',
help="Check this if you want \
the rule to mark CC(mail to any other person defined in actions)."),
- 'act_mail_to_email': fields.char('Mail to these emails', size=128, \
+ 'act_mail_to_email': fields.char('Mail to these Emails', size=128, \
help="Email-id of the persons whom mail is to be sent"),
'act_mail_body': fields.text('Mail body', help="Content of mail"),
'regex_name': fields.char('Regular Expression on Model Name', size=128),
@@ -132,6 +134,71 @@ the rule to mark CC(mail to any other person defined in actions)."),
_order = 'sequence'
+ def pre_action(self, cr, uid, ids, model, context=None):
+ # Searching for action rules
+ cr.execute("SELECT model.model, rule.id FROM base_action_rule rule LEFT JOIN ir_model model on (model.id = rule.name)")
+ res = cr.fetchall()
+ # Check if any rule matching with current object
+ for obj_name, rule_id in res:
+ if not (model == obj_name):
+ continue
+ else:
+ obj = self.pool.get(obj_name)
+ self._action(cr, uid, [rule_id], obj.browse(cr, uid, ids, context=context))
+ return True
+
+ def _create(self, old_create, model, context=None):
+ if not context:
+ context = {}
+ def make_call_old(cr, uid, vals, context=context):
+ new_id = old_create(cr, uid, vals, context=context)
+ if not context.get('action'):
+ self.pre_action(cr, uid, [new_id], model, context=context)
+ return new_id
+ return make_call_old
+
+ def _write(self, old_write, model, context=None):
+ if not context:
+ context = {}
+ def make_call_old(cr, uid, ids, vals, context=context):
+ if isinstance(ids, (str, int, long)):
+ ids = [ids]
+ if not context.get('action'):
+ self.pre_action(cr, uid, ids, model, context=context)
+ return old_write(cr, uid, ids, vals, context=context)
+ return make_call_old
+
+ def _register_hook(self, cr, uid, ids, context=None):
+ if not context:
+ context = {}
+ model_pool = self.pool.get('ir.model')
+ for action_rule in self.browse(cr, uid, ids, context=context):
+ model = action_rule.name.model
+ obj_pool = self.pool.get(model)
+ obj_pool.__setattr__('create', self._create(obj_pool.create, model, context=context))
+ obj_pool.__setattr__('write', self._write(obj_pool.write, model, context=context))
+ return True
+
+ def create(self, cr, uid, vals, context=None):
+ res_id = super(base_action_rule, self).create(cr, uid, vals, context)
+ self._register_hook(cr, uid, [res_id], context=context)
+ return res_id
+
+ def write(self, cr, uid, ids, vals, context=None):
+ res = super(base_action_rule, self).write(cr, uid, ids, vals, context)
+ self._register_hook(cr, uid, ids, context=context)
+ return res
+
+ def _check(self, cr, uid, automatic=False, use_new_cursor=False, \
+ context=None):
+ """
+ This Function is call by scheduler.
+ """
+ rule_pool= self.pool.get('base.action.rule')
+ rule_ids = rule_pool.search(cr, uid, [], context=context)
+ return self._register_hook(cr, uid, rule_ids, context=context)
+
+
def format_body(self, body):
""" Foramat Action rule's body
@param self: The object pointer """
@@ -166,7 +233,6 @@ the rule to mark CC(mail to any other person defined in actions)."),
@param email: pass the emails
@param emailfrom: Pass name the email From else False
@param context: A standard dictionary for contextual values """
-
body = self.format_mail(obj, body)
if not emailfrom:
if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.address_id and\
@@ -188,8 +254,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param context: A standard dictionary for contextual values """
-
- ok = True
+ ok = True
if eval(action.domain):
obj_ids = obj._table.search(cr, uid, eval(action.domain), context=context)
if not obj.id in obj_ids:
@@ -210,7 +275,8 @@ the rule to mark CC(mail to any other person defined in actions)."),
ok = ok and (not action.trg_state_from or action.trg_state_from==obj.state)
if state_to:
ok = ok and (not action.trg_state_to or action.trg_state_to==state_to)
-
+ elif action.trg_state_to:
+ ok = False
reg_name = action.regex_name
result_name = True
if reg_name:
@@ -235,6 +301,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
context.update({'active_id':obj.id, 'active_ids':[obj.id]})
self.pool.get('ir.actions.server').run(cr, uid, [action.server_action_id.id], context)
write = {}
+
if hasattr(obj, 'user_id') and action.act_user_id:
obj.user_id = action.act_user_id
write['user_id'] = action.act_user_id.id
@@ -279,12 +346,10 @@ the rule to mark CC(mail to any other person defined in actions)."),
@param ids: List of Basic Action Rule’s IDs,
@param objects: pass objects
@param context: A standard dictionary for contextual values """
-
+ context.update({'action': True})
if not scrit:
scrit = []
- cr.execute("select id from base_action_rule order by sequence")
- rule_ids = map(lambda x: x[0], cr.fetchall())
- for action in self.browse(cr, uid, rule_ids):
+ for action in self.browse(cr, uid, ids):
level = action.max_level
if not level:
break
@@ -333,6 +398,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
self.do_action(cr, uid, action, model_obj, obj, context)
break
level -= 1
+ context.update({'action': False})
return True
def _check_mail(self, cr, uid, ids, context=None):
@@ -359,4 +425,27 @@ the rule to mark CC(mail to any other person defined in actions)."),
base_action_rule()
+
+class ir_cron(osv.osv):
+ _inherit = 'ir.cron'
+
+ def _poolJobs(self, db_name, check=False):
+ try:
+ db, pool = pooler.get_db_and_pool(db_name)
+ except:
+ return False
+ cr = db.cursor()
+ try:
+ next = datetime.now().strftime('%Y-%m-%d %H:00:00')
+ # Putting nextcall always less than current time in order to call it every time
+ cr.execute('UPDATE ir_cron set nextcall = \'%s\' where numbercall<>0 and active and model=\'base.action.rule\' ' % (next))
+ cr.commit()
+ res = super(ir_cron, self)._poolJobs(db_name, check=check)
+ finally:
+ cr.commit()
+ cr.close()
+
+ir_cron()
+
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_action_rule/base_action_rule_data.xml b/addons/base_action_rule/base_action_rule_data.xml
new file mode 100644
index 00000000000..288215202d6
--- /dev/null
+++ b/addons/base_action_rule/base_action_rule_data.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ Check Action Rules
+ 4
+ hours
+ -1
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 0882b6f0e1b..4f502a4406b 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -18,7 +18,8 @@
-
+
+
@@ -54,7 +55,6 @@
-
diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index 8a9764bff63..c16477280c7 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -377,6 +377,9 @@ property or property parameter."),
_defaults = {
'state': lambda *x: 'needs-action',
}
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ raise osv.except_osv(_('Warning!'), _('Can not Duplicate'))
def get_ics_file(self, cr, uid, event_obj, context=None):
"""
@@ -875,7 +878,7 @@ class calendar_event(osv.osv):
value = {
'duration': 24
}
- return {'value': value}
+ duration = 0.0
start = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S")
if end_date and not duration:
@@ -1005,17 +1008,17 @@ class calendar_event(osv.osv):
_columns = {
'id': fields.integer('ID'),
'sequence': fields.integer('Sequence'),
- 'name': fields.char('Description', size=64, required=False),
- 'date': fields.datetime('Date'),
- 'date_deadline': fields.datetime('Deadline'),
+ '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)]}),
'create_date': fields.datetime('Created', readonly=True),
- 'duration': fields.float('Duration'),
- 'description': fields.text('Your action'),
+ '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'),
- 'location': fields.char('Location', size=264, help="Location of Event"),
+ ('confidential', 'Confidential')], 'Mark as', 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'),
+ 'Show as', states={'done': [('readonly', True)]}),
'base_calendar_url': fields.char('Caldav URL', size=264),
'exdate': fields.text('Exception Date/Times', help="This property \
defines the list of date/time exceptions for arecurring calendar component."),
@@ -1029,14 +1032,14 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=-1SU'),
'rrule_type': fields.selection([('none', ''), ('daily', 'Daily'), \
('weekly', 'Weekly'), ('monthly', 'Monthly'), \
- ('yearly', 'Yearly'), ('custom', 'Custom')], 'Recurrency'),
- 'alarm_id': fields.many2one('res.alarm', 'Alarm'),
+ ('yearly', 'Yearly'), ('custom', 'Custom')], 'Recurrency', states={'done': [('readonly', True)]}),
+ 'alarm_id': fields.many2one('res.alarm', 'Alarm', states={'done': [('readonly', True)]}),
'base_calendar_alarm_id': fields.many2one('calendar.alarm', 'Alarm'),
'recurrent_uid': fields.integer('Recurrent ID'),
'recurrent_id': fields.datetime('Recurrent ID date'),
'vtimezone': fields.related('user_id', 'context_tz', type='char', size=24, \
string='Timezone', store=True),
- 'user_id': fields.many2one('res.users', 'Responsible'),
+ 'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}),
'freq': fields.selection([('None', 'No Repeat'), \
('secondly', 'Secondly'), \
('minutely', 'Minutely'), \
@@ -1068,7 +1071,7 @@ e.g.: Every other month on the last Sunday of the month for 10 occurrences:\
'end_date': fields.date('Repeat Until'),
'attendee_ids': fields.many2many('calendar.attendee', 'event_attendee_rel', \
'event_id', 'attendee_id', 'Attendees'),
- 'allday': fields.boolean('All Day'),
+ '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.")
}
diff --git a/addons/base_calendar/base_calendar_view.xml b/addons/base_calendar/base_calendar_view.xml
index 21b16443e0a..aa63dc696de 100644
--- a/addons/base_calendar/base_calendar_view.xml
+++ b/addons/base_calendar/base_calendar_view.xml
@@ -121,7 +121,7 @@
+ domain="[]" context="{'group_by':'state'}" />
@@ -138,7 +138,7 @@
+ parent="base.menu_base_config" sequence="15" />
diff --git a/addons/base_calendar/security/ir.model.access.csv b/addons/base_calendar/security/ir.model.access.csv
index a95b1e1a129..a334fd90081 100644
--- a/addons/base_calendar/security/ir.model.access.csv
+++ b/addons/base_calendar/security/ir.model.access.csv
@@ -1,9 +1,5 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
-"access_calendar_attendee","calendar.attendee","model_calendar_attendee",base.group_user,1,1,1,1
-"access_calendar_alarm","calendar.alarm","model_calendar_alarm",base.group_user,1,1,1,1
-"access_res_alarm","res.alarm","model_res_alarm",base.group_user,1,1,1,1
-"access_calendar_event_all","calendar.event","model_calendar_event",base.group_user,1,1,1,1
-"access_calendar_todo","calendar.todo","model_calendar_todo",base.group_user,1,1,1,1
-"access_base_calendar_invite_attendee","base_calendar.invite.attendee","model_base_calendar_invite_attendee",base.group_user,1,1,1,1
-"access_calendar_event_edit_all","calendar_event_edit_all","model_calendar_event_edit_all",base.group_user,1,1,1,1
-"access_base_calendar_set_exrule","base.calendar.set.exrule","model_base_calendar_set_exrule",base.group_user,1,1,1,1
+"access_calendar_attendee","calendar.attendee","model_calendar_attendee","base.group_user",1,1,1,1
+"access_calendar_alarm","calendar.alarm","model_calendar_alarm","base.group_user",1,1,1,1
+"access_res_alarm","res.alarm","model_res_alarm","base.group_user",1,1,1,1
+"access_calendar_todo","calendar.todo","model_calendar_todo","base.group_user",1,1,1,1
diff --git a/addons/base_calendar/wizard/base_calendar_invite_attendee.py b/addons/base_calendar/wizard/base_calendar_invite_attendee.py
index cb3e4d2e62a..ebbfe6c48d2 100644
--- a/addons/base_calendar/wizard/base_calendar_invite_attendee.py
+++ b/addons/base_calendar/wizard/base_calendar_invite_attendee.py
@@ -65,7 +65,6 @@ send an Email to Invited Person')
context = {}
model = False
- model_field = False
context_id = context and context.get('active_id', False) or False
if not context or not context.get('model'):
return {}
diff --git a/addons/base_calendar/wizard/base_calendar_set_exrule.py b/addons/base_calendar/wizard/base_calendar_set_exrule.py
index ec7fcc50e9e..febfb39e1ef 100644
--- a/addons/base_calendar/wizard/base_calendar_set_exrule.py
+++ b/addons/base_calendar/wizard/base_calendar_set_exrule.py
@@ -104,11 +104,14 @@ class base_calendar_set_exrule(osv.osv_memory):
weekstring = ''
monthstring = ''
yearstring = ''
-
+ ex_id = base_calendar.base_calendar_id2real_id(context['active_id'])
+ model = context.get('model', False)
+ model_obj = self.pool.get(model)
for datas in self.read(cr, uid, ids, context=context):
freq = datas.get('freq')
if freq == 'None':
- return ''
+ model_obj.write(cr, uid, ex_id,{'exrule': ''})
+ return{}
interval_srting = datas.get('interval') and (';INTERVAL=' + str(datas.get('interval'))) or ''
@@ -143,12 +146,8 @@ class base_calendar_set_exrule(osv.osv_memory):
exrule_string = 'FREQ=' + freq.upper() + weekstring + interval_srting \
+ enddate + monthstring + yearstring
- ex_id = base_calendar.base_calendar_id2real_id(context['active_id'])
- model = context.get('model', False)
- model_obj = self.pool.get(model)
- exrule_value = model_obj.write(cr, uid,ex_id,{
- 'exrule': exrule_string,
- })
+
+ model_obj.write(cr, uid, ex_id,{'exrule': exrule_string})
return {}
_defaults = {
diff --git a/addons/base_calendar/wizard/base_calendar_set_exrule_view.xml b/addons/base_calendar/wizard/base_calendar_set_exrule_view.xml
index cc88dc90c02..bc663e0835f 100644
--- a/addons/base_calendar/wizard/base_calendar_set_exrule_view.xml
+++ b/addons/base_calendar/wizard/base_calendar_set_exrule_view.xml
@@ -49,11 +49,13 @@
attrs="{'required' : [('freq','=','yearly')]}"/>
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/addons/base_contact/__init__.py b/addons/base_contact/__init__.py
index 7cd056c1c20..84054cd59e7 100644
--- a/addons/base_contact/__init__.py
+++ b/addons/base_contact/__init__.py
@@ -20,5 +20,7 @@
##############################################################################
import base_contact
+import base_contact_installer
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_contact/__openerp__.py b/addons/base_contact/__openerp__.py
index a0fc97aa5a1..8c58d44ff4c 100644
--- a/addons/base_contact/__openerp__.py
+++ b/addons/base_contact/__openerp__.py
@@ -45,6 +45,7 @@
'update_xml': [
'security/ir.model.access.csv',
'base_contact_view.xml',
+ 'base_contact_installer_view.xml',
'process/base_contact_process.xml'
],
'demo_xml': ['base_contact_demo.xml'],
diff --git a/addons/base_contact/base_contact_demo.xml b/addons/base_contact/base_contact_demo.xml
index 6acdd08cf14..2c76b1844e8 100644
--- a/addons/base_contact/base_contact_demo.xml
+++ b/addons/base_contact/base_contact_demo.xml
@@ -179,7 +179,7 @@
CTO
-
+
diff --git a/addons/base_contact/base_contact_installer.py b/addons/base_contact/base_contact_installer.py
new file mode 100644
index 00000000000..3cb32017111
--- /dev/null
+++ b/addons/base_contact/base_contact_installer.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+from lxml import etree
+from osv import fields, osv
+
+class base_contact_installer(osv.osv_memory):
+ _name = 'base.contact.installer'
+ _inherit = 'res.config.installer'
+
+ _columns = {
+ 'name': fields.char('Name', size=64),
+ 'migrate': fields.boolean('Migrate', help="If you select this, all addresses will be migrated."),
+ }
+
+ def execute(self, cr, uid, ids, context=None):
+ """
+ This function is used to create contact and address from existing partner address
+ """
+ cr.execute("""DROP TRIGGER IF EXISTS contactjob on res_partner_contact;
+ DROP LANGUAGE IF EXISTS plpgsql CASCADE;
+ CREATE LANGUAGE plpgsql ;
+ CREATE OR REPLACE FUNCTION add_to_job() RETURNS TRIGGER AS $contactjob$
+ DECLARE
+ new_name varchar;
+ new_phonenum varchar;
+ BEGIN
+ IF(TG_OP='INSERT') THEN
+ INSERT INTO res_partner_job(contact_id, address_id, function, state) VALUES(NEW.id, NEW.website::integer,NEW.first_name, 'current');
+ UPDATE res_partner_contact set first_name=Null, website=Null, active=True where id=NEW.id;
+ END IF;
+ RETURN NEW;
+ END;
+ $contactjob$ LANGUAGE plpgsql;
+ CREATE TRIGGER contactjob AFTER INSERT ON res_partner_contact FOR EACH ROW EXECUTE PROCEDURE add_to_job();""")
+ cr.commit()
+
+ cr.execute("INSERT into res_partner_contact (name, title, email, first_name, website) (SELECT coalesce(name, 'Noname'), title, email, function , to_char(id, '99999999') from res_partner_address)")
+ cr.commit()
+
+ cr.execute("DROP TRIGGER IF EXISTS contactjob on res_partner_contact")
+ cr.execute("DROP LANGUAGE IF EXISTS plpgsql CASCADE;")
+ cr.execute("DROP FUNCTION IF EXISTS add_to_job()")
+ cr.commit()
+
+base_contact_installer()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_contact/base_contact_installer_view.xml b/addons/base_contact/base_contact_installer_view.xml
new file mode 100644
index 00000000000..3d93faa5728
--- /dev/null
+++ b/addons/base_contact/base_contact_installer_view.xml
@@ -0,0 +1,56 @@
+
+
+
+ base.contact.installer.view
+ base.contact.installer
+ form
+
+
+
+
+ Address's Migration to Contacts
+
+
+
+ Select the Option for Addresses Migration
+
+
+ You can migrate Partner's current addresses to the contact.
+
+
+ 13
+
+
+
+ Migrate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Address Migration
+ ir.actions.act_window
+ base.contact.installer
+
+ form
+ form
+ new
+
+
+
+
+ 3
+
+
+
+
diff --git a/addons/base_module_quality/i18n/el.po b/addons/base_module_quality/i18n/el.po
index 9ae13c3add3..1d65ed479be 100644
--- a/addons/base_module_quality/i18n/el.po
+++ b/addons/base_module_quality/i18n/el.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base_module_quality
diff --git a/addons/base_module_quality/i18n/es.po b/addons/base_module_quality/i18n/es.po
index fbb4ecf48fb..c68bb5d0a60 100644
--- a/addons/base_module_quality/i18n/es.po
+++ b/addons/base_module_quality/i18n/es.po
@@ -15,7 +15,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base_module_quality
diff --git a/addons/base_module_quality/pep8_test/pep8_test.py b/addons/base_module_quality/pep8_test/pep8_test.py
index 52c04756382..4aaaaa7bddc 100644
--- a/addons/base_module_quality/pep8_test/pep8_test.py
+++ b/addons/base_module_quality/pep8_test/pep8_test.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -15,7 +15,7 @@
# 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 .
+# along with this program. If not, see .
#
##############################################################################
@@ -48,7 +48,7 @@ PEP-8 Test , copyright of py files check, method can not call from loops
list_files.append(os.path.join(i, j))
py_list = []
for file_py in list_files:
- if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__terp__.py'):
+ if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__openerp__.py'):
file_path = os.path.join(module_path, file_py)
py_list.append(file_path)
diff --git a/addons/base_module_quality/pylint_test/pylint_test.py b/addons/base_module_quality/pylint_test/pylint_test.py
index 8dbbce0e2ce..12400dbb196 100644
--- a/addons/base_module_quality/pylint_test/pylint_test.py
+++ b/addons/base_module_quality/pylint_test/pylint_test.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -15,7 +15,7 @@
# 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 .
+# along with this program. If not, see .
#
##############################################################################
@@ -50,7 +50,7 @@ class quality_test(base_module_quality.abstract_quality_check):
flag = False
self.result_details += '''%s'''%(self.get_style())
for file_py in list_files:
- if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__terp__.py'):
+ if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__openerp__.py'):
if not flag:
flag = True
file_path = os.path.join(module_path, file_py)
diff --git a/addons/base_module_quality/structure_test/structure_test.py b/addons/base_module_quality/structure_test/structure_test.py
index 466976f5d17..10b80aaacdd 100644
--- a/addons/base_module_quality/structure_test/structure_test.py
+++ b/addons/base_module_quality/structure_test/structure_test.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -15,7 +15,7 @@
# 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 .
+# along with this program. If not, see .
#
##############################################################################
@@ -82,7 +82,7 @@ This test checks if the module satisfy tiny structure
# module files calculation (module.py,module_view.xml,etc..)
com_list = ['_unit_test.xml', '.py', '_view.xml', '_workflow.xml' , '_wizard.xml', '_report.xml', '_data.xml', '_demo.xml', '_security.xml', '_sequence.xml', '_graph.xml']
com_list = map(lambda x: module_name + x, com_list)
- main_file = ['__init__.py', '__terp__.py']
+ main_file = ['__init__.py', '__openerp__.py']
com_list.extend(main_file)
module_dict['module'] = filter(lambda x: len(x.split(".")) > 1, module_dict['module'])
score = self.get_score(module_dict['module'], com_list)
diff --git a/addons/base_module_quality/terp_test/terp_test.py b/addons/base_module_quality/terp_test/terp_test.py
index 993a80fe32b..b2d71b9fbd9 100644
--- a/addons/base_module_quality/terp_test/terp_test.py
+++ b/addons/base_module_quality/terp_test/terp_test.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -15,7 +15,7 @@
# 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 .
+# along with this program. If not, see .
#
##############################################################################
@@ -49,13 +49,13 @@ class quality_test(base_module_quality.abstract_quality_check):
score = 1.0
feel_good_factor = 0
feel_bad_factor = 0
- if '__terp__.py' not in list_files:
+ if '__openerp__.py' not in list_files:
self.no_terp = True
- self.result += _("The module does not contain the __terp__.py file")
+ self.result += _("The module does not contain the __openerp__.py file")
return None
result_dict = {}
result_dict1 = {}
- terp_file = os.path.join(module_path,'__terp__.py')
+ terp_file = os.path.join(module_path,'__openerp__.py')
res = eval(tools.file_open(terp_file).read())
terp_keys = ['category', 'name', 'description', 'author', 'website', 'update_xml', 'init_xml', 'depends', 'version', 'active', 'installable', 'demo_xml']
for key in terp_keys:
@@ -117,7 +117,7 @@ class quality_test(base_module_quality.abstract_quality_check):
self.result_details += self.get_result_details(result_dict)
self.result_details += self.get_result_details(result_dict1)
- return [_('__terp__.py file'), score]
+ return [_('__openerp__.py file'), score]
def run_test(self, cr, uid, module_path):
terp_score = self.run_test_terp(cr, uid, module_path)
@@ -125,7 +125,7 @@ class quality_test(base_module_quality.abstract_quality_check):
if self.score*100 < self.min_score:
self.message = 'Score is below than minimal score(%s%%)' % self.min_score
if terp_score:
- self.result = self.get_result({'__terp__.py': terp_score})
+ self.result = self.get_result({'__openerp__.py': terp_score})
return None
def get_result(self, dict_terp):
@@ -144,4 +144,4 @@ class quality_test(base_module_quality.abstract_quality_check):
return res
return ""
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_report_creator/i18n/el.po b/addons/base_report_creator/i18n/el.po
index a914194a57b..ea439e5dad8 100644
--- a/addons/base_report_creator/i18n/el.po
+++ b/addons/base_report_creator/i18n/el.po
@@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"X-Poedit-Country: GREECE\n"
"X-Poedit-Language: Greek\n"
diff --git a/addons/base_setup/base_setup_installer.xml b/addons/base_setup/base_setup_installer.xml
index 46c4dbc6e0b..6608cea061b 100644
--- a/addons/base_setup/base_setup_installer.xml
+++ b/addons/base_setup/base_setup_installer.xml
@@ -13,9 +13,7 @@
Now that OpenERP is installed, We have selected applications commonly useful to users which you can install directly, as well as sets of applications for more specific types or groups of businesses (the vertical modules).
-
-If you don't think you need any of these right now, you can easily install them later on.
+ >The most common applications have been pre selected. You can directly install them. You can either choose generic modules, or select modules for specific business sectors and industries. If you do not think you need any of these right now, you can easily install them later.
diff --git a/addons/base_setup/base_setup_todo.xml b/addons/base_setup/base_setup_todo.xml
index 5ec9be53d76..0bf0fbb09be 100644
--- a/addons/base_setup/base_setup_todo.xml
+++ b/addons/base_setup/base_setup_todo.xml
@@ -26,9 +26,9 @@
-
+
diff --git a/addons/base_setup/gtk_contact_form.xml b/addons/base_setup/gtk_contact_form.xml
index 41711032bf0..fcbaa9867e7 100644
--- a/addons/base_setup/gtk_contact_form.xml
+++ b/addons/base_setup/gtk_contact_form.xml
@@ -11,7 +11,7 @@
Contact Information
- Information about you and the company you are related too. The Basic information related to the company has already been collected and some more information required by you to fill.
+ To receive more information, please fill in the form about you and your company. Documentation and/or information will be sent to you as soon as possible.Would you like more information or documentation ?
diff --git a/addons/board_association/i18n/el.po b/addons/board_association/i18n/el.po
deleted file mode 100644
index 35fcc48ad27..00000000000
--- a/addons/board_association/i18n/el.po
+++ /dev/null
@@ -1,71 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * board_association
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.0\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-24 01:15+0000\n"
-"Last-Translator: Panayiotis Konstantinidis \n"
-"Language-Team: nls@hellug.gr \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
-"X-Generator: Launchpad (build Unknown)\n"
-"X-Poedit-Country: GREECE\n"
-"X-Poedit-Language: Greek\n"
-"X-Poedit-SourceCharset: utf-8\n"
-
-#. module: board_association
-#: model:ir.ui.menu,name:board_association.menu_board_associations_manager
-msgid "Associations"
-msgstr "Συνεταιρισμοί"
-
-#. module: board_association
-#: model:ir.module.module,shortdesc:board_association.module_meta_information
-msgid "Dashboard for Associations"
-msgstr "Πίνακας για Συνεταιρισμούς"
-
-#. module: board_association
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "Άκυρο XML για Αρχιτεκτονική Όψης!"
-
-#. module: board_association
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_association.open_board_associations_manager
-msgid "Association Dashboard"
-msgstr "Πίνακας Συνεταιρισμών"
-
-#. module: board_association
-#: view:board.board:0
-msgid "My tasks"
-msgstr "Οι αναθέσεις μου"
-
-#. module: board_association
-#: view:board.board:0
-msgid "New members"
-msgstr "Νέα μέλη"
-
-#. module: board_association
-#: view:board.board:0
-msgid "Unpaid Invoices"
-msgstr "Απλήρωτα Τιμολόγια"
-
-#. module: board_association
-#: constraint:ir.actions.act_window:0
-msgid "Invalid model name in the action definition."
-msgstr "Λανθασμένο όνομα μοντέλου στον ορισμό ενέργειας"
-
-#. module: board_association
-#: view:board.board:0
-msgid "Next Events"
-msgstr "Επόμενα Συμβάντα"
-
-#. module: board_association
-#: view:board.board:0
-msgid "Registrations by Events"
-msgstr "Καταχωρήσεις ανά Συμβάν"
diff --git a/addons/board_auction/i18n/el.po b/addons/board_auction/i18n/el.po
deleted file mode 100644
index f99a794521e..00000000000
--- a/addons/board_auction/i18n/el.po
+++ /dev/null
@@ -1,125 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * board_auction
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.0\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-24 01:15+0000\n"
-"Last-Translator: Panayiotis Konstantinidis \n"
-"Language-Team: nls@hellug.gr \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
-"X-Generator: Launchpad (build Unknown)\n"
-"X-Poedit-Country: GREECE\n"
-"X-Poedit-Language: Greek\n"
-"X-Poedit-SourceCharset: utf-8\n"
-
-#. module: board_auction
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "Invalid XML for View Architecture!"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Objects by day"
-msgstr "Αντικείμενα ανά Ημέρα"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Objects statistics"
-msgstr "Στατιστικά Αντικειμένων"
-
-#. module: board_auction
-#: model:ir.ui.menu,name:board_auction.menu_board_auction_manager
-msgid "Auction Manager"
-msgstr "Υπεύθυνος Δημοπρασίας"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Summary pointing by user"
-msgstr "Περίληψη χτυπημάτων ανά χρήστη"
-
-#. module: board_auction
-#: model:ir.ui.menu,name:board_auction.menu_board_auction
-msgid "Auction Member"
-msgstr "Μέλος Δημοπρασίας"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "My Latest Deposits"
-msgstr "Οι Τελευταίες Καταθέσεις μου"
-
-#. module: board_auction
-#: model:ir.actions.act_window,name:board_auction.open_board_auction
-msgid "Auction member board"
-msgstr "Πίνακας μέλους δημοπρασίας"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Auction manager "
-msgstr "Υπεύθυνος Δημοπρασίας "
-
-#. module: board_auction
-#: model:ir.module.module,shortdesc:board_auction.module_meta_information
-msgid "Board for Auction"
-msgstr "Πίνακας Δημοπρασίας"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Estimations/Adjudication"
-msgstr "Εκτιμήσεις/Κατακυρώσεις"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Total Adjudications"
-msgstr "Σύνολο Κατακυρώσεων"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Latest objects"
-msgstr "Τελευταία αντικείμενα"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Latest deposits"
-msgstr "Τελευταίες καταθέσεις"
-
-#. module: board_auction
-#: constraint:ir.actions.act_window:0
-msgid "Invalid model name in the action definition."
-msgstr "Λανθασμένο όνομα μοντέλου στον ορισμό ενέργειας"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Menu"
-msgstr "Μενού"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "My objects By Day"
-msgstr "Τα Ανικείμενά μου ανά Ημέρα"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "My board"
-msgstr "Ο Πίνακάς μου"
-
-#. module: board_auction
-#: model:ir.actions.act_window,name:board_auction.open_board_auction_manager
-msgid "Auction manager board"
-msgstr "Πίνακας Υπεύθυνου Δημοπρασίας"
-
-#. module: board_auction
-#: view:board.board:0
-msgid "Min/Adj/Max"
-msgstr "Ελαχ./Επικ./Μέγ."
-
-#. module: board_auction
-#: view:board.board:0
-msgid "My Latest Objects"
-msgstr "Τα Τελευταία μου Αντικείμενα"
diff --git a/addons/board_crm_configuration/i18n/el.po b/addons/board_crm_configuration/i18n/el.po
deleted file mode 100644
index e2f697e23fd..00000000000
--- a/addons/board_crm_configuration/i18n/el.po
+++ /dev/null
@@ -1,122 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * board_crm_configuration
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.0\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-24 01:16+0000\n"
-"Last-Translator: Panayiotis Konstantinidis \n"
-"Language-Team: nls@hellug.gr \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
-"X-Generator: Launchpad (build Unknown)\n"
-"X-Poedit-Country: GREECE\n"
-"X-Poedit-Language: Greek\n"
-"X-Poedit-SourceCharset: utf-8\n"
-
-#. module: board_crm_configuration
-#: model:ir.module.module,shortdesc:board_crm_configuration.module_meta_information
-msgid "Dashboard for CRM Configuration"
-msgstr "Πίνακας Ρυθμίσεων CRM"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-#: model:ir.ui.menu,name:board_crm_configuration.menu_board_statistics_dash
-msgid "Statistics Dashboard"
-msgstr "Πίνακας Στατιστικών Μεγεθών"
-
-#. module: board_crm_configuration
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "Άκυρο XML για Αρχιτεκτονική Όψης!"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_crm_configuration.act_oppor_categ
-msgid "Opportunities By Categories"
-msgstr "Ευκαιρίες ανά Κατηγορίες"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_crm_configuration.act_my_cases
-msgid "My Cases"
-msgstr "Τα Θέματά μου"
-
-#. module: board_crm_configuration
-#: model:ir.actions.act_window,name:board_crm_configuration.open_board_crm
-msgid "CRM Dashboard"
-msgstr "Πίνακας Αναφορών CRM"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-#: model:ir.ui.menu,name:board_crm_configuration.menu_board_crm
-msgid "Connecting Dashboard"
-msgstr "Σύνδεση Πινάκων Αναφορών"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_crm_configuration.act_leads_month_user
-msgid "Leads Of The Month By User"
-msgstr "Σύνδεσμοι Μηνός ανά Χρήστη"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-#: view:report.crm.case.section.stage:0
-msgid "Leads By Stage"
-msgstr "Σύνδεσμοι ανά Στάδιο"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-msgid "My Meetings"
-msgstr "Οι Συσκέψεις μου"
-
-#. module: board_crm_configuration
-#: model:ir.ui.menu,name:board_crm_configuration.menu_board_crm_config
-msgid "CRM Configuration"
-msgstr "Ρυθμίσεις CRM"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_crm_configuration.act_jobs_categ
-msgid "Jobs Requests Of The Month by Applied Job"
-msgstr "Αιτήσεις Εργασίας του Μήνα ανά Θέση Αίτησης"
-
-#. module: board_crm_configuration
-#: constraint:ir.actions.act_window:0
-msgid "Invalid model name in the action definition."
-msgstr "Λανθασμένο όνομα μοντέλου στον ορισμό ενέργειας"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-msgid "My Sales Pipeline"
-msgstr "Το Κανάλι Πωλήσεών μου"
-
-#. module: board_crm_configuration
-#: view:report.crm.case.user:0
-msgid "Cases by User and Section"
-msgstr "Θέματα ανά Χρήστη και Τμήμα"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-msgid "My Leads By Stage"
-msgstr "Οι Σύνδεσμοί μου ανά Στάδιο"
-
-#. module: board_crm_configuration
-#: view:report.crm.case.categ:0
-msgid "Cases by Sections and Categories"
-msgstr "Θέματα ανά Τμήμα και Κατηγορίες"
-
-#. module: board_crm_configuration
-#: model:ir.actions.act_window,name:board_crm_configuration.open_board_statistical_dash
-msgid "CRM - Statistics Dashboard"
-msgstr "CRM - Πίνακας Στατιστικών Μεγεθών"
-
-#. module: board_crm_configuration
-#: view:board.board:0
-msgid "My Leads"
-msgstr "Οι Σύνδεσμοί μου"
diff --git a/addons/board_document/i18n/el.po b/addons/board_document/i18n/el.po
deleted file mode 100644
index 338203acd35..00000000000
--- a/addons/board_document/i18n/el.po
+++ /dev/null
@@ -1,92 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * board_document
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.0\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-24 01:21+0000\n"
-"Last-Translator: Panayiotis Konstantinidis \n"
-"Language-Team: nls@hellug.gr \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
-"X-Generator: Launchpad (build Unknown)\n"
-"X-Poedit-Country: GREECE\n"
-"X-Poedit-Language: Greek\n"
-"X-Poedit-SourceCharset: utf-8\n"
-
-#. module: board_document
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "Άκυρο XML για Αρχιτεκτονική Όψης!"
-
-#. module: board_document
-#: view:board.board:0
-msgid "New Files"
-msgstr "Νέα Αρχεία"
-
-#. module: board_document
-#: model:ir.actions.act_window,name:board_document.open_board_document_manager
-#: model:ir.ui.menu,name:board_document.menu_board_document_manager
-msgid "Document Dashboard"
-msgstr "Πίνακας Εγγραφών"
-
-#. module: board_document
-#: view:board.board:0
-msgid "Wall of Shame"
-msgstr "Τείχος της Ντροπής"
-
-#. module: board_document
-#: view:board.board:0
-msgid "File Size by Month"
-msgstr "Μέγεθος Αρχείων ανά Μήνα"
-
-#. module: board_document
-#: view:board.board:0
-msgid "Files by Month"
-msgstr "Αρχεία ανά Μήνα"
-
-#. module: board_document
-#: model:ir.actions.act_window,name:board_document.open_board_document_manager1
-#: model:ir.ui.menu,name:board_document.menu_board_document_manager1
-msgid "Statistics by User"
-msgstr "Στατιστικά ανά Χρήστη"
-
-#. module: board_document
-#: view:board.board:0
-msgid "Files by Resource Type"
-msgstr "Αρχεία ανά Τύπο Προέλευσης"
-
-#. module: board_document
-#: constraint:ir.actions.act_window:0
-msgid "Invalid model name in the action definition."
-msgstr "Λανθασμένο όνομα μοντέλου στον ορισμό ενέργειας"
-
-#. module: board_document
-#: model:ir.module.module,shortdesc:board_document.module_meta_information
-msgid "Dashboard for Document Management"
-msgstr "Πίνακας Διαχείρισης Εγγραφών"
-
-#. module: board_document
-#: view:board.board:0
-msgid "Files by Partner"
-msgstr "Αρχεία ανά Συνεργάτη"
-
-#. module: board_document
-#: model:ir.ui.menu,name:board_document.menu_board_document
-msgid "Document"
-msgstr "Έγγραφο"
-
-#. module: board_document
-#: view:board.board:0
-msgid "Files by Users"
-msgstr "Αρχεία ανά Χρήστη"
-
-#. module: board_document
-#: view:board.board:0
-msgid "Document board"
-msgstr "Πίνακας εγγράφου"
diff --git a/addons/board_project/i18n/el.po b/addons/board_project/i18n/el.po
deleted file mode 100644
index 4b6cc7b8820..00000000000
--- a/addons/board_project/i18n/el.po
+++ /dev/null
@@ -1,142 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * board_project
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.0\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-24 01:22+0000\n"
-"Last-Translator: Panayiotis Konstantinidis \n"
-"Language-Team: nls@hellug.gr \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
-"X-Generator: Launchpad (build Unknown)\n"
-"X-Poedit-Country: GREECE\n"
-"X-Poedit-Language: Greek\n"
-"X-Poedit-SourceCharset: utf-8\n"
-
-#. module: board_project
-#: view:board.board:0
-msgid "My project's planning"
-msgstr "Σχεδιασμός Έργων μου"
-
-#. module: board_project
-#: view:hr_timesheet_sheet.sheet:0
-#: model:ir.actions.act_window,name:board_project.act_hr_timesheet_sheet
-msgid "Timesheets"
-msgstr "Φύλλα Χρόνου Εργασίας"
-
-#. module: board_project
-#: constraint:ir.actions.act_window:0
-msgid "Invalid model name in the action definition."
-msgstr "Λανθασμένο όνομα μοντέλου στον ορισμό ενέργειας"
-
-#. module: board_project
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_project.act_my_project
-msgid "My projects"
-msgstr "Τα Έργα μου"
-
-#. module: board_project
-#: model:ir.actions.act_window,name:board_project.action_view_task_tree_deadline
-msgid "My Task's Deadlines"
-msgstr "Προθεσμίες Αναθέσεών μου"
-
-#. module: board_project
-#: view:project.task:0
-msgid "My Tasks"
-msgstr "Οι Αναθέσεις μου"
-
-#. module: board_project
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_project.action_view_board_note_tree
-msgid "Public Notes"
-msgstr "Κοινοποιημένες Σημειώσεις"
-
-#. module: board_project
-#: model:ir.actions.act_window,name:board_project.open_board_project
-#: model:ir.ui.menu,name:board_project.menu_board_project
-msgid "Project Dashboard"
-msgstr "Πίνακας Έργων"
-
-#. module: board_project
-#: model:ir.module.module,shortdesc:board_project.module_meta_information
-msgid "Board for project users"
-msgstr "Πίνακας Χρηστών Έργου"
-
-#. module: board_project
-#: model:ir.actions.act_window,name:board_project.action_project_pipeline_user
-msgid "Pipeline of tasks"
-msgstr "Κανάλι Αναθέσεων"
-
-#. module: board_project
-#: view:board.board:0
-msgid "My Planning"
-msgstr "Ο Σχεδιασμός μου"
-
-#. module: board_project
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_project.act_my_account
-msgid "My accounts to invoice"
-msgstr "Οι λογαριασμοί μου προς τιμολόγηση"
-
-#. module: board_project
-#: model:ir.actions.act_window,name:board_project.open_board_project_manager
-#: model:ir.ui.menu,name:board_project.menu_board_project_manager
-msgid "Project Manager Dashboard"
-msgstr "Πίνακας Αναφορών Διευθυντή Έργου"
-
-#. module: board_project
-#: view:board.board:0
-msgid "My Deadlines"
-msgstr "Οι Προθεσμίες μου"
-
-#. module: board_project
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "Άκυρο XML για Αρχιτεκτονική Όψης!"
-
-#. module: board_project
-#: view:board.board:0
-msgid "User's timesheets"
-msgstr "Φύλλα χρόνου χρηστών"
-
-#. module: board_project
-#: model:ir.ui.menu,name:board_project.next_id_86
-msgid "Project"
-msgstr "Έργο"
-
-#. module: board_project
-#: view:board.board:0
-msgid "Project manager board"
-msgstr "Πίνακας διευθυντή έργου"
-
-#. module: board_project
-#: view:board.board:0
-#: model:ir.actions.act_window,name:board_project.action_view_task_tree
-msgid "My Open Tasks"
-msgstr "Οι Ανοικτές Αναθέσεις μου"
-
-#. module: board_project
-#: view:board.board:0
-msgid "My Board"
-msgstr "Ο Πίνακάς μου"
-
-#. module: board_project
-#: view:board.board:0
-msgid "My tasks board"
-msgstr "Ο πίνακας αναθέσεών μου"
-
-#. module: board_project
-#: view:board.board:0
-msgid "My user's pipeline"
-msgstr "Το κανάλι μου"
-
-#. module: board_project
-#: view:board.board:0
-msgid "My Timesheet"
-msgstr "Το Φύλλο Χρόνου μου"
diff --git a/addons/caldav/wizard/calendar_event_export.py b/addons/caldav/wizard/calendar_event_export.py
index 856d9e9bc91..0be54df9f56 100644
--- a/addons/caldav/wizard/calendar_event_export.py
+++ b/addons/caldav/wizard/calendar_event_export.py
@@ -32,16 +32,6 @@ class calendar_event_export(osv.osv_memory):
"""
Export Calendar Event.
"""
- def process_export_ics(self, cr, uid, ids, context):
- """
- Get Default value for file_path field.
- """
- model = context.get('model', 'basic.calendar')
- model_obj = self.pool.get(model)
-
- calendar = model_obj.export_cal(cr, uid, context['active_ids'], context)
- self.write(cr, uid, ids, {'file_path': base64.encodestring(calendar)})
- return False
def default_get(self, cr, uid, fields, context):
"""
@@ -54,6 +44,9 @@ class calendar_event_export(osv.osv_memory):
name = 'OpenERP %s.ics' % (model_obj._description)
if 'name' in fields:
res.update({'name': name})
+ if 'file_path' in fields:
+ calendar = model_obj.export_cal(cr, uid, context['active_ids'], context)
+ res.update({'file_path': base64.encodestring(calendar)})
return res
_name = "calendar.event.export"
diff --git a/addons/caldav/wizard/calendar_event_export_view.xml b/addons/caldav/wizard/calendar_event_export_view.xml
index 227822966d0..cfadf945bf4 100644
--- a/addons/caldav/wizard/calendar_event_export_view.xml
+++ b/addons/caldav/wizard/calendar_event_export_view.xml
@@ -13,8 +13,8 @@
-
-
+
+
diff --git a/addons/crm/__init__.py b/addons/crm/__init__.py
index 362444ccc2c..e56ed80af30 100644
--- a/addons/crm/__init__.py
+++ b/addons/crm/__init__.py
@@ -20,7 +20,6 @@
##############################################################################
import crm
-import crm_mailgate
import crm_action_rule
import crm_segmentation
import crm_meeting
diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py
index 5dcb655e8db..973bb12dc5c 100644
--- a/addons/crm/__openerp__.py
+++ b/addons/crm/__openerp__.py
@@ -69,8 +69,10 @@ Create dashboard for CRM that includes:
'crm_opportunity_data.xml',
'crm_phonecall_data.xml',
],
-
'update_xml': [
+ 'security/crm_security.xml',
+ 'security/ir.model.access.csv',
+
'wizard/crm_lead_to_partner_view.xml',
'wizard/crm_lead_to_opportunity_view.xml',
@@ -98,9 +100,6 @@ Create dashboard for CRM that includes:
'crm_opportunity_view.xml',
'crm_opportunity_menu.xml',
- 'security/crm_security.xml',
- 'security/ir.model.access.csv',
-
'report/crm_lead_report_view.xml',
'report/crm_phonecall_report_view.xml',
diff --git a/addons/crm/board_crm_view.xml b/addons/crm/board_crm_view.xml
index 69ca8e964e9..4729ab7283d 100644
--- a/addons/crm/board_crm_view.xml
+++ b/addons/crm/board_crm_view.xml
@@ -19,15 +19,16 @@
crm.leadformtree,form
-
+ [('user_id','=',uid),('state','!=','pending'),('state','!=','cancel')]
+
crm.meetingformtree,form
- [('user_id','=',uid),('state','!=','pending'),('state','!=','cancel')]
+ [('user_id','=',uid),('state','!=','cancel'),('date','ilike',time.strftime("%Y-%m"))]
@@ -53,34 +54,28 @@
-
-
-
-
-
-
-
@@ -105,7 +100,5 @@
action="open_board_crm"
sequence="1"
id="menu_board_crm" icon="terp-graph"/>
-
-
diff --git a/addons/crm/crm.py b/addons/crm/crm.py
index 7510bc48914..c46519cdb97 100644
--- a/addons/crm/crm.py
+++ b/addons/crm/crm.py
@@ -118,15 +118,18 @@ class crm_case(object):
@param context: A standard dictionary for contextual values"""
if not context:
context = {}
-
s = self.get_stage_dict(cr, uid, ids, context=context)
section = self._name
+ stage = False
+ stage_pool = self.pool.get('crm.case.stage')
for case in self.browse(cr, uid, ids, context):
if section in s:
st = case.stage_id.id or False
if st in s[section]:
- self.write(cr, uid, [case.id], {'stage_id': s[section][st]})
- return True
+ data = {'stage_id': s[section][st]}
+ stage = s[section][st]
+ self.write(cr, uid, [case.id], data)
+ return stage
def get_stage_dict(self, cr, uid, ids, context=None):
"""This function gives dictionary for stage according to stage levels
@@ -162,12 +165,18 @@ class crm_case(object):
s = self.get_stage_dict(cr, uid, ids, context=context)
section = self._name
+ stage_pool = self.pool.get('crm.case.stage')
for case in self.browse(cr, uid, ids, context):
if section in s:
st = case.stage_id.id or False
s[section] = dict([(v, k) for (k, v) in s[section].iteritems()])
if st in s[section]:
- self.write(cr, uid, [case.id], {'stage_id': s[section][st]})
+ data = {'stage_id': s[section][st]}
+ if s[section][st]:
+ stage = stage_pool.browse(cr, uid, s[section][st], context=context)
+ if stage.on_change:
+ data.update({'probability': stage.probability})
+ self.write(cr, uid, [case.id], data)
return True
def onchange_partner_id(self, cr, uid, ids, part, email=False):
@@ -181,7 +190,8 @@ class crm_case(object):
"""
if not part:
return {'value': {'partner_address_id': False,
- 'email_from': False,
+ 'email_from': False,
+ 'phone': False
}}
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
data = {'partner_address_id': addr['contact']}
@@ -200,7 +210,7 @@ class crm_case(object):
if not add:
return {'value': {'email_from': False}}
address = self.pool.get('res.partner.address').browse(cr, uid, add)
- return {'value': {'email_from': address.email}}
+ return {'value': {'email_from': address.email, 'phone': address.phone}}
def _history(self, cr, uid, cases, keyword, history=False, subject=None, email=False, details=None, email_from=False, message_id=False, attach=[], context={}):
mailgate_pool = self.pool.get('mailgate.thread')
@@ -541,7 +551,7 @@ class crm_case_resource_type(osv.osv):
_rec_name = "name"
_columns = {
- 'name': fields.char('Case Resource Type', size=64, required=True, translate=True),
+ 'name': fields.char('Resource Type', size=64, required=True, translate=True),
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
'object_id': fields.many2one('ir.model', 'Object Name'),
}
diff --git a/addons/crm/crm_action_rule.py b/addons/crm/crm_action_rule.py
index 9092efef8e8..2c0c5327e5d 100644
--- a/addons/crm/crm_action_rule.py
+++ b/addons/crm/crm_action_rule.py
@@ -69,12 +69,10 @@ this if you want the rule to send an email to the partner."),
return tools.email_send(emailfrom, emails, name, body, reply_to=reply_to, openobject_id=str(obj.id))
def do_check(self, cr, uid, action, obj, context={}):
-
""" @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 context: A standard dictionary for contextual values"""
-
ok = super(base_action_rule, self).do_check(cr, uid, action, obj, context=context)
if hasattr(obj, 'section_id'):
@@ -89,7 +87,6 @@ this if you want the rule to send an email to the partner."),
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param context: A standard dictionary for contextual values """
-
res = super(base_action_rule, self).do_action(cr, uid, action, model_obj, obj, context=context)
write = {}
@@ -125,7 +122,7 @@ this if you want the rule to send an email to the partner."),
@param context: A standard dictionary for contextual values """
res = super(base_action_rule, self).state_get(cr, uid, context=context)
- return res + [('escalate', 'Escalate')] + crm.AVAILABLE_STATES
+ return res + crm.AVAILABLE_STATES
def priority_get(self, cr, uid, context={}):
diff --git a/addons/crm/crm_data.xml b/addons/crm/crm_data.xml
index 1873f53f573..e494db325e5 100644
--- a/addons/crm/crm_data.xml
+++ b/addons/crm/crm_data.xml
@@ -1,22 +1,9 @@
-
- Sales Department
- Sales
-
-
-
-
- Check cases rules
- 4
- hours
- -1
-
-
-
-
-
-
+
+ Sales Department
+ Sales
+
diff --git a/addons/crm/crm_installer_view.xml b/addons/crm/crm_installer_view.xml
index 9d92f6f1b95..6d8f4b7120f 100644
--- a/addons/crm/crm_installer_view.xml
+++ b/addons/crm/crm_installer_view.xml
@@ -25,26 +25,25 @@
Configure
-
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index c1060f3e658..bf6d391ab82 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -27,16 +27,16 @@ import time
import mx.DateTime
from tools.translate import _
from crm import crm_case
+import collections
+import binascii
+import tools
class crm_lead(osv.osv, crm_case):
""" CRM Lead Case """
-
_name = "crm.lead"
_description = "Lead"
_order = "priority, id desc"
- _inherit = ['res.partner.address']
- _inherits = {'mailgate.thread': 'thread_id'}
-
+ _inherit = ['mailgate.thread','res.partner.address']
def _compute_day(self, cr, uid, ids, fields, args, context={}):
"""
@param cr: the current row, from the database cursor,
@@ -96,23 +96,22 @@ class crm_lead(osv.osv, crm_case):
_columns = {
# From crm.case
- 'name': fields.char('Name', size=64),
- 'active': fields.boolean('Active', required=False),
+ 'name': fields.char('Name', size=64),
+ 'active': fields.boolean('Active', required=False),
'date_action_last': fields.datetime('Last Action', readonly=1),
'date_action_next': fields.datetime('Next Action', readonly=1),
- 'email_from': fields.char('Email', size=128, help="These people will receive email."),
+ 'email_from': fields.char('Email', size=128, help="E-mail address of the contact"),
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
- select=True, help='Sales team to which Case belongs to.\
- Define Responsible user and Email account for mail gateway.'),
+ select=True, help='Sales team to which this case belongs to.\
+ Defines responsible user and e-mail address for the mail gateway.'),
'create_date': fields.datetime('Creation Date' , readonly=True),
'email_cc': fields.text('Watchers Emails', size=252 , help="These \
-people will receive a copy of the future communication between partner \
-and users by email"),
+addresses will receive a copy of the future e-mail communication between partner \
+and users"),
'description': fields.text('Notes'),
- 'write_date': fields.datetime('Update Date' , readonly=True),
+ 'write_date': fields.datetime('Update Date' , readonly=True),
# Lead fields
- 'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'categ_id': fields.many2one('crm.case.categ', 'Lead Source', \
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.lead')]"),
@@ -120,6 +119,8 @@ and users by email"),
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.lead')]"),
'partner_name': fields.char("Partner Name", size=64),
+ 'optin': fields.boolean('Opt-In'),
+ 'optout': fields.boolean('Opt-Out'),
'type':fields.selection([
('lead','Lead'),
('opportunity','Opportunity'),
@@ -142,6 +143,8 @@ and users by email"),
\nIf the case is in progress the state is set to \'Open\'.\
\nWhen the case is over, the state is set to \'Done\'.\
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
+ 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('model','=',_name)]),
+ 'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
}
_defaults = {
@@ -149,6 +152,7 @@ and users by email"),
'user_id': crm_case._get_default_user,
'email_from': crm_case._get_default_email,
'state': lambda *a: 'draft',
+ 'type': lambda *a: 'lead',
'section_id': crm_case._get_section,
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
@@ -232,6 +236,112 @@ and users by email"),
}
return value
+ def stage_next(self, cr, uid, ids, context=None):
+ stage = super(crm_lead, self).stage_next(cr, uid, ids, context)
+ if stage:
+ stage_obj = self.pool.get('crm.case.stage').browse(cr, uid, stage, context=context)
+ if stage_obj.on_change:
+ data = {'probability': stage_obj.probability}
+ self.write(cr, uid, ids, data)
+ return stage
+
+ def message_new(self, cr, uid, msg, context):
+ """
+ Automatically calls when new email message arrives
+
+ @param self: The object pointer
+ @param cr: the current row, from the database cursor,
+ @param uid: the current user’s ID for security checks
+ """
+
+ mailgate_pool = self.pool.get('email.server.tools')
+
+ subject = msg.get('subject')
+ body = msg.get('body')
+ msg_from = msg.get('from')
+ priority = msg.get('priority')
+
+ vals = {
+ 'name': subject,
+ 'email_from': msg_from,
+ 'email_cc': msg.get('cc'),
+ 'description': body,
+ 'user_id': False,
+ }
+ if msg.get('priority', False):
+ vals['priority'] = priority
+
+ res = mailgate_pool.get_partner(cr, uid, msg.get('from') or msg.get_unixfrom())
+ if res:
+ vals.update(res)
+
+ res = self.create(cr, uid, vals, context)
+
+ attachents = msg.get('attachments', [])
+ for attactment in attachents or []:
+ data_attach = {
+ 'name': attactment,
+ 'datas':binascii.b2a_base64(str(attachents.get(attactment))),
+ 'datas_fname': attactment,
+ 'description': 'Mail attachment',
+ 'res_model': self._name,
+ 'res_id': res,
+ }
+ self.pool.get('ir.attachment').create(cr, uid, data_attach)
+
+ return res
+
+ def message_update(self, cr, uid, ids, vals={}, msg="", default_act='pending', context={}):
+ """
+ @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 update mail’s IDs
+ """
+
+ if isinstance(ids, (str, int, long)):
+ ids = [ids]
+
+ msg_from = msg['from']
+ if msg.get('priority'):
+ vals['priority'] = msg.get('priority')
+
+ maps = {
+ 'cost':'planned_cost',
+ 'revenue': 'planned_revenue',
+ 'probability':'probability'
+ }
+ vls = {}
+ for line in msg['body'].split('\n'):
+ line = line.strip()
+ res = tools.misc.command_re.match(line)
+ if res and maps.get(res.group(1).lower()):
+ key = maps.get(res.group(1).lower())
+ vls[key] = res.group(2).lower()
+ vals.update(vls)
+
+ # Unfortunately the API is based on lists
+ # but we want to update the state based on the
+ # previous state, so we have to loop:
+ for case in self.browse(cr, uid, ids, context=context):
+ values = dict(vals)
+ if case.state == crm.AVAILABLE_STATES[4][0]: #pending
+ values.update(state=crm.AVAILABLE_STATES[1][0]) #open
+ res = self.write(cr, uid, [case.id], values, context=context)
+
+ return res
+
+ def msg_send(self, cr, uid, id, *args, **argv):
+
+ """ Send The Message
+ @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 email’s IDs
+ @param *args: Return Tuple Value
+ @param **args: Return Dictionary of Keyword Value
+ """
+ return True
crm_lead()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm/crm_lead_data.xml b/addons/crm/crm_lead_data.xml
index 17211a9ef66..2b47140e396 100644
--- a/addons/crm/crm_lead_data.xml
+++ b/addons/crm/crm_lead_data.xml
@@ -2,79 +2,79 @@
-
+
New
-
+ Assigned
-
+ In Process
-
+ Converted
-
+ Recycled
-
+ Dead
-
+ Telesales
-
+ Mail
-
+ Email
-
+ Print
-
+ Web
-
+ Radio
-
+ Television
-
+ Newsletter
-
+
diff --git a/addons/crm/crm_lead_menu.xml b/addons/crm/crm_lead_menu.xml
index cea854427dc..6edce727647 100644
--- a/addons/crm/crm_lead_menu.xml
+++ b/addons/crm/crm_lead_menu.xml
@@ -1,6 +1,6 @@
-
+
Leads
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index c33339047d8..379644e72b1 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -2,7 +2,7 @@
-
+
Lead Stages
@@ -18,7 +18,7 @@
parent="menu_crm_config_lead" />
-
+
Lead Resource Type
@@ -34,7 +34,7 @@
groups="base.group_extended" sequence="2"
parent="menu_crm_config_lead" />
-
+
CRM - Leads Form
@@ -146,6 +146,11 @@
+
+
+
+
+
@@ -160,9 +165,10 @@
-
-
+
+
+
@@ -199,18 +205,19 @@
-
+
- CRM - Leads Tree
+ Leadscrm.leadtree
-
+
-
+
+
@@ -224,8 +231,7 @@
-
+
-
+
CRM - Leads Calendar
@@ -256,17 +262,16 @@
calendar
-
+
-
+
-
+
CRM - Leads Search
@@ -296,6 +301,7 @@
('create_date','>=',(datetime.date.today()-datetime.timedelta(days=7)).strftime('%%Y-%%m-%%d'))]"
/>
+
@@ -315,6 +321,20 @@
help="Show Sales Team"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -330,6 +350,5 @@
-
diff --git a/addons/crm/crm_mailgate.py b/addons/crm/crm_mailgate.py
deleted file mode 100644
index f2380182aad..00000000000
--- a/addons/crm/crm_mailgate.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import time
-import re
-import os
-
-import binascii
-import mx.DateTime
-import base64
-
-from tools.translate import _
-
-import tools
-from osv import fields,osv,orm
-from osv.orm import except_orm
-import collections
-
-from tools import command_re
-
-class mailgate_thread(osv.osv):
- """ mailgate_thread """
-
- _name = "mailgate.thread"
- _inherit = "mailgate.thread"
-
- def message_new(self, cr, uid, msg, context):
- """
- Automatically calls when new email message arrives
-
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user’s ID for security checks
- """
-
- mailgate_pool = self.pool.get('email.server.tools')
-
- subject = msg.get('subject')
- body = msg.get('body')
- msg_from = msg.get('from')
- priority = msg.get('priority')
-
- vals = {
- 'name': subject,
- 'email_from': msg_from,
- 'email_cc': msg.get('cc'),
- 'description': body,
- 'user_id': False,
- }
- if msg.get('priority', False):
- vals['priority'] = priority
-
- res = mailgate_pool.get_partner(cr, uid, msg.get('from'))
- if res:
- vals.update(res)
- res = self.create(cr, uid, vals, context)
- cases = self.browse(cr, uid, [res])
- self._history(cr, uid, cases, _('Receive'), history=True, details=body, email_from=msg_from, message_id=msg.get('id'))
-
- attachents = msg.get('attachments', [])
- for attactment in attachents or []:
- data_attach = {
- 'name': attactment,
- 'datas':binascii.b2a_base64(str(attachents.get(attactment))),
- 'datas_fname': attactment,
- 'description': 'Mail attachment',
- 'res_model': self._name,
- 'res_id': res,
- }
- self.pool.get('ir.attachment').create(cr, uid, data_attach)
-
- return res
-
- def message_update(self, cr, uid, ids, vals={}, msg="", default_act='pending', context={}):
- """
- @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 update mail’s IDs
- """
-
- if isinstance(ids, (str, int, long)):
- ids = [ids]
-
- msg_from = msg['from']
- vals.update({
- 'description': msg['body']
- })
- if msg.get('priority', False):
- vals['priority'] = msg.get('priority')
-
- maps = {
- 'cost':'planned_cost',
- 'revenue': 'planned_revenue',
- 'probability':'probability'
- }
- vls = { }
- for line in msg['body'].split('\n'):
- line = line.strip()
- res = command_re.match(line)
- if res and maps.get(res.group(1).lower(), False):
- key = maps.get(res.group(1).lower())
- vls[key] = res.group(2).lower()
-
- vals.update(vls)
- res = self.write(cr, uid, ids, vals)
- cases = self.browse(cr, uid, ids)
- message_id = context.get('references_id', False)
- self._history(cr, uid, cases, _('Receive'), history=True, details=msg['body'], email_from=msg_from, message_id=message_id)
- #getattr(self, act)(cr, uid, select)
- return res
-
- def emails_get(self, cr, uid, ids, context=None):
-
- """
- Get Emails
- @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 email’s IDs
- @param context: A standard dictionary for contextual values
- """
- res = {}
-
- if isinstance(ids, (str, int, long)):
- select = [long(ids)]
- else:
- select = ids
-
- for thread in self.browse(cr, uid, select, context=context):
- values = collections.defaultdict(set)
-
- for message in thread.message_ids:
- user_email = (message.user_id and message.user_id.address_id and message.user_id.address_id.email) or False
- values['user_email'].add(user_email)
- values['email_from'].add(message.email_from)
- values['email_cc'].add(message.email_cc or False)
-
- res[str(thread.id)] = dict((key,list(values[key])) for key, value in values.iteritems())
-
- return res
-
- def msg_send(self, cr, uid, id, *args, **argv):
-
- """ Send The Message
- @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 email’s IDs
- @param *args: Return Tuple Value
- @param **args: Return Dictionary of Keyword Value
- """
- return True
-
-mailgate_thread()
diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py
index e45ee85b31d..4f68d2d2564 100644
--- a/addons/crm/crm_meeting.py
+++ b/addons/crm/crm_meeting.py
@@ -43,32 +43,32 @@ class crm_meeting(osv.osv, crm_case):
_name = 'crm.meeting'
_description = "Meeting"
_order = "id desc"
- _inherit = ["calendar.event"]
- _inherits = {'mailgate.thread': 'thread_id'}
-
+ _inherit = ['mailgate.thread',"calendar.event"]
_columns = {
# From crm.case
- 'name': fields.char('Summary', size=124, required=True),
- 'partner_id': fields.many2one('res.partner', 'Partner'),
+ 'name': fields.char('Summary', size=124, required=True, states={'done': [('readonly', True)]}),
+ 'partner_id': fields.many2one('res.partner', 'Partner', states={'done': [('readonly', True)]}),
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
- domain="[('partner_id','=',partner_id)]"),
- 'section_id': fields.many2one('crm.case.section', 'Sales Team', \
+ domain="[('partner_id','=',partner_id)]", states={'done': [('readonly', True)]}),
+ 'section_id': fields.many2one('crm.case.section', 'Sales Team', states={'done': [('readonly', True)]}, \
select=True, help='Sales team to which Case belongs to.\
Define Responsible user and Email account for mail gateway.'),
- 'email_from': fields.char('Email', size=128, help="These people will receive email."),
+ 'email_from': fields.char('Email', size=128, states={'done': [('readonly', True)]}, help="These people will receive email."),
'id': fields.integer('ID'),
-
+ 'create_date': fields.datetime('Creation Date' , readonly=True),
+ 'write_date': fields.datetime('Write Date' , readonly=True),
# Meeting fields
- 'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'categ_id': fields.many2one('crm.case.categ', 'Meeting Type', \
domain="[('object_id.model', '=', 'crm.meeting')]", \
),
'phonecall_id': fields.many2one ('crm.phonecall', 'Phonecall'),
'opportunity_id': fields.many2one ('crm.lead', 'Opportunity', domain="[('type', '=', 'opportunity')]"),
'attendee_ids': fields.many2many('calendar.attendee', 'meeting_attendee_rel',\
- 'event_id', 'attendee_id', 'Attendees'),
+ 'event_id', 'attendee_id', 'Attendees', states={'done': [('readonly', True)]}),
'date_closed': fields.datetime('Closed', readonly=True),
- 'date_deadline': fields.datetime('Deadline'),
+ 'date_deadline': fields.datetime('Deadline', states={'done': [('readonly', True)]}),
+ 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('model','=',_name)]),
+ 'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
'state': fields.selection([('open', 'Confirmed'),
('draft', 'Unconfirmed'),
('cancel', 'Cancelled'),
diff --git a/addons/crm/crm_meeting_data.xml b/addons/crm/crm_meeting_data.xml
index e96e17ac6a9..a7e4b400d76 100644
--- a/addons/crm/crm_meeting_data.xml
+++ b/addons/crm/crm_meeting_data.xml
@@ -1,30 +1,30 @@
-
+
-
- Customer Meeting
-
-
-
+
+ Customer Meeting
+
+
+
-
- Internal Meeting
-
-
-
+
+ Internal Meeting
+
+
+
-
- Phone Call
-
-
-
+
+ Phone Call
+
+
+
- Case Meeting
- crm.meeting
-
-
+ Case Meeting
+ crm.meeting
+
+
diff --git a/addons/crm/crm_meeting_menu.xml b/addons/crm/crm_meeting_menu.xml
index ec58c116baf..bf1a8459655 100644
--- a/addons/crm/crm_meeting_menu.xml
+++ b/addons/crm/crm_meeting_menu.xml
@@ -1,6 +1,6 @@
-
+
@@ -214,10 +215,27 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -268,6 +286,10 @@
help="Current Meetings"/>
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm/crm_opportunity.py b/addons/crm/crm_opportunity.py
index 440033a2400..4faebe37d91 100644
--- a/addons/crm/crm_opportunity.py
+++ b/addons/crm/crm_opportunity.py
@@ -109,7 +109,7 @@ class crm_opportunity(osv.osv):
_defaults = {
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
- 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
+ 'priority': crm.AVAILABLE_PRIORITIES[2][0],
}
def action_makeMeeting(self, cr, uid, ids, context=None):
@@ -143,9 +143,10 @@ class crm_opportunity(osv.osv):
context = {
'default_opportunity_id': opp.id,
'default_partner_id': opp.partner_id and opp.partner_id.id or False,
+ 'default_user_id': uid,
'default_section_id': opp.section_id and opp.section_id.id or False,
'default_email_from': opp.email_from,
- 'default_state': 'open',
+ 'default_state': 'open',
'default_name': opp.name
}
value = {
diff --git a/addons/crm/crm_opportunity_data.xml b/addons/crm/crm_opportunity_data.xml
index b6b62628e4b..a7cfd2d46ca 100644
--- a/addons/crm/crm_opportunity_data.xml
+++ b/addons/crm/crm_opportunity_data.xml
@@ -4,91 +4,91 @@
Existing Customer
-
+ Self Generated
-
-
+
+
Employee
-
+ Partner
-
+ Campaign
-
-
+
+
Website
-
-
+
+
Word of mouth
-
-
+
+
Other
-
-
+
+
Prospecting
-
+ Needs Analysis
-
+ Value Proposition
-
+ Proposal/Price Quote
-
+ Negotiation/Review
-
+ Closed Won
-
+ Closed Lost
-
+ Existing Business
-
-
+
+
New Business
-
+
diff --git a/addons/crm/crm_opportunity_demo.xml b/addons/crm/crm_opportunity_demo.xml
index aa965a07594..3c06d16dc19 100644
--- a/addons/crm/crm_opportunity_demo.xml
+++ b/addons/crm/crm_opportunity_demo.xml
@@ -55,7 +55,7 @@
-
+
diff --git a/addons/crm/crm_opportunity_menu.xml b/addons/crm/crm_opportunity_menu.xml
index cb24990416f..60ade626071 100644
--- a/addons/crm/crm_opportunity_menu.xml
+++ b/addons/crm/crm_opportunity_menu.xml
@@ -1,15 +1,15 @@
-
+
diff --git a/addons/crm/crm_opportunity_view.xml b/addons/crm/crm_opportunity_view.xml
index 550d82f86ac..7e0042f8944 100644
--- a/addons/crm/crm_opportunity_view.xml
+++ b/addons/crm/crm_opportunity_view.xml
@@ -154,6 +154,8 @@
+
+
@@ -246,6 +248,7 @@
+
+
+
-
-
+
+
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index e8a14df42a8..8ccd8acd0a4 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -21,7 +21,7 @@
from osv import fields, osv
from crm import crm
-
+import time
class crm_claim(osv.osv, crm.crm_case):
"""
Crm claim
@@ -29,10 +29,8 @@ class crm_claim(osv.osv, crm.crm_case):
_name = "crm.claim"
_description = "Claim Cases"
_order = "id desc"
- _inherits = {'mailgate.thread': 'thread_id'}
-
+ _inherit = ['mailgate.thread']
_columns = {
- 'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'id': fields.integer('ID', readonly=True),
'name': fields.char('Name', size=128, required=True),
'active': fields.boolean('Active', required=False),
@@ -90,6 +88,8 @@ class crm_claim(osv.osv, crm.crm_case):
\nIf the case is in progress the state is set to \'Open\'.\
\nWhen the case is over, the state is set to \'Done\'.\
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
+ 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('model','=',_name)]),
+ 'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
}
_defaults = {
@@ -100,9 +100,46 @@ class crm_claim(osv.osv, crm.crm_case):
'email_from':crm.crm_case. _get_default_email,
'state': lambda *a: 'draft',
'section_id':crm.crm_case. _get_section,
+ 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
}
+
+ def onchange_partner_id(self, cr, uid, ids, part, email=False):
+ """This function returns value of partner address based on partner
+ @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 case IDs
+ @param part: Partner's id
+ @email: Partner's email ID
+ """
+ if not part:
+ return {'value': {'partner_address_id': False,
+ 'email_from': False,
+ 'partner_phone': False,
+ 'partner_mobile': False
+ }}
+ addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
+ data = {'partner_address_id': addr['contact']}
+ data.update(self.onchange_partner_address_id(cr, uid, ids, addr['contact'])['value'])
+ print data
+ return {'value': data}
+
+ def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
+ """This function returns value of partner email based on Partner Address
+ @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 case IDs
+ @param add: Id of Partner's address
+ @email: Partner's email ID
+ """
+ if not add:
+ return {'value': {'email_from': False}}
+ address = self.pool.get('res.partner.address').browse(cr, uid, add)
+ return {'value': {'email_from': address.email, 'partner_phone': address.phone, 'partner_mobile': address.mobile}}
+
crm_claim()
diff --git a/addons/crm_claim/crm_claim_menu.xml b/addons/crm_claim/crm_claim_menu.xml
index 40f077d49f0..14754ff7857 100644
--- a/addons/crm_claim/crm_claim_menu.xml
+++ b/addons/crm_claim/crm_claim_menu.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/addons/document/document.py b/addons/document/document.py
index 5d3075f7a4a..aa893b617c3 100644
--- a/addons/document/document.py
+++ b/addons/document/document.py
@@ -98,6 +98,7 @@ class document_file(osv.osv):
('binary','Binary'),
],'Type', help="Type is used to separate URL and binary File"),
+ 'company_id': fields.many2one('res.company', 'Company'),
}
def __get_def_directory(self, cr, uid, context=None):
@@ -105,6 +106,7 @@ class document_file(osv.osv):
return dirobj._get_root_directory(cr, uid, context)
_defaults = {
+ 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.attachment', context=c),
'user_id': lambda self, cr, uid, ctx:uid,
'file_size': lambda self, cr, uid, ctx:0,
'store_method': lambda *args: 'db',
diff --git a/addons/document/document_data.xml b/addons/document/document_data.xml
index 77c80b078d1..c2bef5de34f 100644
--- a/addons/document/document_data.xml
+++ b/addons/document/document_data.xml
@@ -9,15 +9,9 @@
- Default File storage
-
-
-
-
- DB storage
-
-
-
+ Default DB storage
+ db
+
@@ -60,7 +54,7 @@
- Personnal Folders
+ Personal Foldersressource
diff --git a/addons/document/document_directory.py b/addons/document/document_directory.py
index 1d0bbf3ed7c..fee633b7169 100644
--- a/addons/document/document_directory.py
+++ b/addons/document/document_directory.py
@@ -60,6 +60,7 @@ class document_directory(osv.osv):
'ressource_tree': fields.boolean('Tree Structure',
help="Check this if you want to use the same tree structure as the object selected in the system."),
'dctx_ids': fields.one2many('document.directory.dctx', 'dir_id', 'Context fields'),
+ 'company_id': fields.many2one('res.company', 'Company'),
}
@@ -92,6 +93,7 @@ class document_directory(osv.osv):
return None
_defaults = {
+ 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'document.directory', context=c),
'user_id': lambda self,cr,uid,ctx: uid,
'domain': lambda self,cr,uid,ctx: '[]',
'type': lambda *args: 'directory',
@@ -112,7 +114,7 @@ class document_directory(osv.osv):
while d2 and d2.parent_id:
s = d2.name + (s and ('/' + s) or '')
d2 = d2.parent_id
- res.append((d.id, s))
+ res.append((d.id, s or d.name))
return res
def get_full_path(self, cr, uid, dir_id, context=None):
diff --git a/addons/document/document_storage.py b/addons/document/document_storage.py
index e680bca5983..90be2bc47df 100644
--- a/addons/document/document_storage.py
+++ b/addons/document/document_storage.py
@@ -24,6 +24,8 @@ from osv import osv, fields
import os
import tools
import base64
+import logging
+
from tools.misc import ustr
from tools.translate import _
@@ -96,6 +98,8 @@ class document_storage(osv.osv):
"""
_name = 'document.storage'
_description = 'Storage Media'
+ _doclog = logging.getLogger('document')
+
_columns = {
'name': fields.char('Name', size=64, required=True, select=1),
'write_date': fields.datetime('Date Modified', readonly=True),
@@ -151,7 +155,7 @@ class document_storage(osv.osv):
# On a migrated db, some files may have the wrong storage type
# try to fix their directory.
if ira.file_size:
- netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id)
+ self._doclog.warning( "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id)
return None
fpath = os.path.join(boo.path, ira.store_fname)
return file(fpath, 'rb').read()
@@ -167,7 +171,7 @@ class document_storage(osv.osv):
# On a migrated db, some files may have the wrong storage type
# try to fix their directory.
if ira.file_size:
- netsvc.Logger().notifyChannel('document',netsvc.LOG_WARNING,"ir.attachment #%d does not have a filename, trying the name." %ira.id)
+ self._doclog.warning("ir.attachment #%d does not have a filename, trying the name." %ira.id)
sfname = ira.name
fpath = os.path.join(boo.path,ira.store_fname or ira.name)
if os.path.exists(fpath):
@@ -187,7 +191,6 @@ class document_storage(osv.osv):
if not context:
context = {}
boo = self.browse(cr, uid, id, context)
- logger = netsvc.Logger()
if fil_obj:
ira = fil_obj
else:
@@ -195,7 +198,7 @@ class document_storage(osv.osv):
if not boo.online:
raise RuntimeError('media offline')
- logger.notifyChannel('document', netsvc.LOG_DEBUG, "Store data for ir.attachment #%d" % ira.id)
+ self._doclog.debug( "Store data for ir.attachment #%d" % ira.id)
store_fname = None
fname = None
if boo.type == 'filestore':
@@ -214,14 +217,14 @@ class document_storage(osv.osv):
fp = file(fname, 'wb')
fp.write(data)
fp.close()
- logger.notifyChannel('document', netsvc.LOG_DEBUG, "Saved data to %s" % fname)
+ self._doclog.debug( "Saved data to %s" % fname)
filesize = len(data) # os.stat(fname).st_size
store_fname = os.path.join(flag, filename)
# TODO Here, an old file would be left hanging.
- except Exception, e :
- netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Couldn't save data: %s" % str(e))
+ except Exception, e:
+ self._doclog.warning( "Couldn't save data to %s", path, exc_info=True)
raise except_orm(_('Error!'), str(e))
elif boo.type == 'db':
filesize = len(data)
@@ -250,14 +253,12 @@ class document_storage(osv.osv):
fp = file(fname,'wb')
fp.write(data)
fp.close()
- logger.notifyChannel('document',netsvc.LOG_DEBUG,"Saved data to %s" % fname)
+ self._doclog.debug("Saved data to %s", fname)
filesize = len(data) # os.stat(fname).st_size
store_fname = os.path.join(*npath)
# TODO Here, an old file would be left hanging.
except Exception,e :
- import traceback
- traceback.print_exc()
- netsvc.Logger().notifyChannel('document',netsvc.LOG_WARNING,"Couldn't save data: %s" % e)
+ self._doclog.warning("Couldn't save data:", exc_info=True)
raise except_orm(_('Error!'), str(e))
else:
raise TypeError("No %s storage" % boo.type)
@@ -271,8 +272,8 @@ class document_storage(osv.osv):
try:
mime, icont = cntIndex.doIndex(data, ira.datas_fname,
ira.file_type or None, fname)
- except Exception, e:
- logger.notifyChannel('document', netsvc.LOG_DEBUG, 'Cannot index file: %s' % str(e))
+ except Exception:
+ self._doclog.debug('Cannot index file:', exc_info=True)
pass
# a hack: /assume/ that the calling write operation will not try
@@ -284,7 +285,7 @@ class document_storage(osv.osv):
file_node.content_type = mime
return True
except Exception, e :
- netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Couldn't save data: %s" % str(e))
+ self._doclog.warning( "Couldn't save data:", exc_info=True)
# should we really rollback once we have written the actual data?
# at the db case (only), that rollback would be safe
raise except_orm(_('Error at doc write!'), str(e))
@@ -319,9 +320,9 @@ class document_storage(osv.osv):
try:
os.unlink(fname)
except Exception, e:
- netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Could not remove file %s, please remove manually." % fname)
+ self._doclog.warning("Could not remove file %s, please remove manually.", fname, exc_info=True)
else:
- netsvc.Logger().notifyChannel('document', netsvc.LOG_WARNING, "Unknown unlink key %s" % ktype)
+ self._doclog.warning("Unknown unlink key %s" % ktype)
return True
diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml
index 29f3617d64f..5dc1bbcf0f8 100644
--- a/addons/document/document_view.xml
+++ b/addons/document/document_view.xml
@@ -3,7 +3,7 @@
-
+
@@ -13,14 +13,15 @@
form
-
+
-
+
+
-
+
@@ -35,17 +36,31 @@
-
-
+
+ Search View: Document Storage
+ document.storage
+ search
+
+
+
+
+
+
+
+
+
+
+
ir.actions.act_windowdocument.storageformtree,form
+
+
@@ -96,7 +112,7 @@
-
+
@@ -119,6 +135,7 @@
document.directorydocument.directorytree
+ child_ids
@@ -130,12 +147,35 @@
+
+ Search View: Document Directory
+ document.directory
+ search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Directoriesir.actions.act_windowdocument.directoryformtree,form
+
@@ -159,7 +199,7 @@
ir.actions.act_window
- Directorie's Structure
+ Directories' Structuredocument.directorytree
@@ -180,7 +220,8 @@
-
+
+
@@ -193,10 +234,7 @@
-
-
-
@@ -219,7 +257,9 @@
-
+
+
+
@@ -245,11 +285,15 @@
help="Filter on my Attachment" />
+
+
+
+
@@ -260,7 +304,7 @@
tree
-
+
@@ -273,8 +317,10 @@
+ Documentsir.actions.act_windowir.attachment
+ Documentform
@@ -287,9 +333,10 @@
ir.actions.act_windowir.attachment
+ Directoryform[('parent_id','child_of',active_id)]
- {'parent_id':'active_id'}
+ {'parent_id':active_id}
@@ -349,6 +396,9 @@
res_model="ir.attachment"
src_model="document.directory"/>
+
+
+
diff --git a/addons/document/i18n/el.po b/addons/document/i18n/el.po
index 9b425c31b89..56b87d3cc6d 100644
--- a/addons/document/i18n/el.po
+++ b/addons/document/i18n/el.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: document
diff --git a/addons/document/i18n/es.po b/addons/document/i18n/es.po
index c491e4daa8d..1c062b61792 100644
--- a/addons/document/i18n/es.po
+++ b/addons/document/i18n/es.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: document
diff --git a/addons/document/nodes.py b/addons/document/nodes.py
index df1878ad798..dcd864e6db0 100644
--- a/addons/document/nodes.py
+++ b/addons/document/nodes.py
@@ -339,7 +339,8 @@ class node_dir(node_database):
fil_id = fil_obj.create(cr, uid, val, context=ctx)
fil = fil_obj.browse(cr, uid, fil_id, context=ctx)
fnode = node_file(path, self, self.context, fil)
- fnode.set_data(cr, data, fil)
+ if data is not None:
+ fnode.set_data(cr, data, fil)
return fnode
def get_etag(self, cr):
@@ -667,7 +668,7 @@ class node_file(node_class):
self.file_id = fil.id
#todo: more info from ir_attachment
if fil.file_type and '/' in fil.file_type:
- self.mimetype = fil.file_type
+ self.mimetype = str(fil.file_type)
self.create_date = fil.create_date
self.write_date = fil.write_date or fil.create_date
self.content_length = fil.file_size
@@ -809,7 +810,7 @@ class node_content(node_class):
(self.extension,))
res = cr.fetchall()
if res and res[0][0]:
- self.mimetype = res[0][0]
+ self.mimetype = str(res[0][0])
def get_data(self, cr, fil_obj = None):
diff --git a/addons/document/report/document_report.py b/addons/document/report/document_report.py
index d3964fc2d99..130a313dfd6 100644
--- a/addons/document/report/document_report.py
+++ b/addons/document/report/document_report.py
@@ -19,16 +19,6 @@
#
##############################################################################
-# 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-##############################################################################
from osv import fields,osv
import time
@@ -53,9 +43,10 @@ class report_document_user(osv.osv):
'partner':fields.char('Partner',size=64,readonly=True),
}
def init(self, cr):
- cr.execute("""
- create or replace view report_document_user as (
- select
+ tools.drop_view_if_exists(cr, 'report_document_user')
+ cr.execute("""
+ CREATE OR REPLACE VIEW report_document_user as (
+ SELECT
min(f.id) as id,
to_char(f.create_date, 'YYYY') as name,
to_char(f.create_date, 'MM') as month,
@@ -67,12 +58,12 @@ class report_document_user(osv.osv):
f.file_size as file_size,
min(d.type) as type,
f.write_date as change_date
- from ir_attachment f
+ FROM ir_attachment f
left join document_directory d on (f.parent_id=d.id and d.name<>'')
inner join res_users u on (f.user_id=u.id)
group by to_char(f.create_date, 'YYYY'), to_char(f.create_date, 'MM'),d.name,f.parent_id,d.type,f.create_date,f.user_id,f.file_size,u.name,d.type,f.write_date
)
- """)
+ """)
report_document_user()
class report_files_partner(osv.osv):
@@ -94,7 +85,7 @@ class report_files_partner(osv.osv):
def init(self, cr):
tools.drop_view_if_exists(cr, 'report_files_partner')
cr.execute("""
- create or replace view report_files_partner as (
+ CREATE VIEW report_files_partner as (
select min(f.id) as id,count(*) as nbr,
to_char(f.create_date,'YYYY') as name,
min(to_char(f.create_date,'MM')) as month,
@@ -119,7 +110,8 @@ class report_document_file(osv.osv):
}
_order = "month"
def init(self, cr):
- cr.execute("""
+ tools.drop_view_if_exists(cr, 'report_document_file')
+ cr.execute("""
create or replace view report_document_file as (
select min(f.id) as id,
count(*) as nbr,
@@ -128,7 +120,7 @@ class report_document_file(osv.osv):
from ir_attachment f
group by EXTRACT(MONTH FROM f.create_date)
)
- """)
+ """)
report_document_file()
@@ -145,7 +137,8 @@ class report_document_wall(osv.osv):
}
def init(self, cr):
- cr.execute("""
+ tools.drop_view_if_exists(cr, 'report_document_wall')
+ cr.execute("""
create or replace view report_document_wall as (
select max(f.id) as id,
to_char(min(f.create_date),'YYYY-MM-DD HH24:MI:SS') as last,
@@ -159,7 +152,7 @@ class report_document_wall(osv.osv):
group by i.user_id) group by f.user_id,f.create_date
having (CURRENT_DATE - to_date(to_char(f.create_date,'YYYY-MM-DD'),'YYYY-MM-DD')) > 30
)
- """)
+ """)
report_document_wall()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/document/security/document_security.xml b/addons/document/security/document_security.xml
index 4eb257a2325..333cc853542 100644
--- a/addons/document/security/document_security.xml
+++ b/addons/document/security/document_security.xml
@@ -2,6 +2,10 @@
+
+ Document / User
+
+
Document / Manager
diff --git a/addons/document/security/ir.model.access.csv b/addons/document/security/ir.model.access.csv
index 245bcbffeab..a4412195745 100644
--- a/addons/document/security/ir.model.access.csv
+++ b/addons/document/security/ir.model.access.csv
@@ -19,3 +19,5 @@
"access_report_document_file_group_system","report.document.file group system","model_report_document_file","base.group_system",1,0,0,0
"access_report_document_wall_group_document_manager","report.document.wall document manager","model_report_document_wall","document.group_document_manager",1,0,0,0
"access_report_document_wall_group_system","report.document.wall group system","model_report_document_wall","base.group_system",1,0,0,0
+"access_document_configuation","document.configuration document manager","model_document_configuration","document.group_document_manager",1,1,1,1
+"access_document_configuation_system","document.configuration group system","model_document_configuration","base.group_system",1,1,1,1
diff --git a/addons/document/std_index.py b/addons/document/std_index.py
index c4f7d787d4d..2a588a017c1 100644
--- a/addons/document/std_index.py
+++ b/addons/document/std_index.py
@@ -19,10 +19,11 @@
#
##############################################################################
+from content_index import indexer, cntIndex
+from subprocess import Popen, PIPE
import StringIO
import odt2txt
-from subprocess import Popen, PIPE
-from content_index import indexer, cntIndex
+import sys, zipfile, xml.dom.minidom
def _to_unicode(s):
try:
@@ -36,17 +37,26 @@ def _to_unicode(s):
except UnicodeError:
return s
+def textToString(element) :
+ buffer = u""
+ for node in element.childNodes :
+ if node.nodeType == xml.dom.Node.TEXT_NODE :
+ buffer += node.nodeValue
+ elif node.nodeType == xml.dom.Node.ELEMENT_NODE :
+ buffer += textToString(node)
+ return buffer
+
class TxtIndex(indexer):
def _getMimeTypes(self):
return ['text/plain','text/html','text/diff','text/xml', 'text/*',
- 'application/xml']
+ 'application/xml']
def _getExtensions(self):
return ['.txt', '.py']
- def _doIndexContent(self, content):
+ def _doIndexContent(self,content):
return content
-
+
cntIndex.register(TxtIndex())
class PptxIndex(indexer):
@@ -56,15 +66,24 @@ class PptxIndex(indexer):
def _getExtensions(self):
return ['.pptx']
- def _doIndexFile(self, fname):
- # pptx2txt.pl package not support in windows platform.
- # Download pptx2txt package from http://sourceforge.net/projects/pptx2txt/" link.
- # To install this tool, just copy pptx2txt.pl to appropriate place (e.g. /usr/bin directory)
- fp = Popen(['pptx2txt.pl', fname], shell=False, stdout=PIPE).stdout
- fp.read()
- file_obj = open(str(fname + ".txt"), "r")
- data = file_obj.read()
- return _to_unicode(data)
+ def _doIndexFile(self,fname):
+ def toString () :
+ """ Converts the document to a string. """
+ buffer = u""
+ for val in ["a:t"]:
+ for paragraph in content.getElementsByTagName(val) :
+ buffer += textToString(paragraph) + "\n"
+ return buffer
+
+ data = []
+ zip = zipfile.ZipFile(fname)
+ files = filter(lambda x: x.startswith('ppt/slides/slide'), zip.namelist())
+ for i in range(1, len(files) + 1):
+ content = xml.dom.minidom.parseString(zip.read('ppt/slides/slide%s.xml' % str(i)))
+ res = toString().encode('ascii','replace')
+ data.append(res)
+
+ return _to_unicode('\n'.join(data))
cntIndex.register(PptxIndex())
@@ -77,32 +96,59 @@ class DocIndex(indexer):
def _doIndexFile(self,fname):
fp = Popen(['antiword', fname], shell=False, stdout=PIPE).stdout
- return _to_unicode( fp.read())
+ return _to_unicode(fp.read())
cntIndex.register(DocIndex())
class DocxIndex(indexer):
def _getMimeTypes(self):
return [ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']
-
+
def _getExtensions(self):
return ['.docx']
- def _doIndexFile(self, fname):
- # docx2txt.pl package not support in windows platform.
- # Download docx2txt package from "http://sourceforge.net/projects/docx2txt/" link.
- # In case, you don't want to use Makefile for installation, you can follow these steps for manual installation.
- # Copy docx2txt.pl, docx2txt.sh and docx2txt.config to appropriate place (e.g. /usr/bin directory) . used following command.
- # --> cp docx2txt.pl docx2txt.sh docx2txt.config /usr/bin/
+ def _doIndexFile(self,fname):
+ zip = zipfile.ZipFile(fname)
+ content = xml.dom.minidom.parseString(zip.read("word/document.xml"))
+ def toString () :
+ """ Converts the document to a string. """
+ buffer = u""
+ for val in ["w:p", "w:h", "text:list"]:
+ for paragraph in content.getElementsByTagName(val) :
+ buffer += textToString(paragraph) + "\n"
+ return buffer
- fp = Popen(['docx2txt.pl', fname], shell=False, stdout=PIPE).stdout
- fp.read()
- file_obj = open(str(fname + ".txt"), "r")
- data = file_obj.read()
- return _to_unicode(data)
+ res = toString().encode('ascii','replace')
+
+ return _to_unicode(res)
cntIndex.register(DocxIndex())
+
+class XlsxIndex(indexer):
+ def _getMimeTypes(self):
+ return [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
+
+ def _getExtensions(self):
+ return ['.xlsx']
+
+ def _doIndexFile(self,fname):
+ zip = zipfile.ZipFile(fname)
+ content = xml.dom.minidom.parseString(zip.read("xl/sharedStrings.xml"))
+ def toString () :
+ """ Converts the document to a string. """
+ buffer = u""
+ for val in ["t"]:
+ for paragraph in content.getElementsByTagName(val) :
+ buffer += textToString(paragraph) + "\n"
+ return buffer
+
+ res = toString().encode('ascii','replace')
+
+ return _to_unicode(res)
+
+cntIndex.register(XlsxIndex())
+
class PdfIndex(indexer):
def _getMimeTypes(self):
return [ 'application/pdf']
@@ -131,21 +177,33 @@ class ImageNoIndex(indexer):
cntIndex.register(ImageNoIndex())
-#class Doc(indexer):
- #def _getDefMime(self,ext):
+# other opendocument formats:
+# chart-template chart database
+# formula-template formula graphics-template graphics
+# image
+# presentation-template presentation spreadsheet-template spreadsheet
+
+class OpenDoc(indexer):
+ """ Index OpenDocument files.
+
+ Q: is it really worth it to index spreadsheets, or do we only get a
+ meaningless list of numbers (cell contents) ?
+ """
+ def _getMimeTypes(self):
+ otypes = [ 'text', 'text-web', 'text-template', 'text-master' ]
+ return map(lambda a: 'application/vnd.oasis.opendocument.'+a, otypes)
+
+ def _getExtensions(self):
+ return ['.odt', '.ott', ] # '.ods'
+
+ def _doIndexContent(self, content):
+ s = StringIO.StringIO(content)
+ o = odt2txt.OpenDocumentTextFile(s)
+ result = _to_unicode(o.toString())
+ s.close()
+ return result
+
+cntIndex.register(OpenDoc())
-#def content_index(content, filename=None, content_type=None):
- #fname,ext = os.path.splitext(filename)
- #result = ''
- #elif ext in ('.xls','.ods','.odt','.odp'):
- #s = StringIO.StringIO(content)
- #o = odt2txt.OpenDocumentTextFile(s)
- #result = _to_unicode(o.toString())
- #s.close()
- #elif ext in ('.txt','.py','.patch','.html','.csv','.xml'):
- #result = content
- #else:
- #result = content
- #return result
#eof
diff --git a/addons/document/test_cindex.py b/addons/document/test_cindex.py
index 7c0bcb987f3..267e0497950 100644
--- a/addons/document/test_cindex.py
+++ b/addons/document/test_cindex.py
@@ -31,6 +31,9 @@ for fname in args:
else:
res = cntIndex.doIndex(None, fname, None, fname,True)
+ if options.verbose:
+ for line in res[:5]:
+ print line
except Exception,e:
import traceback,sys
tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback))
diff --git a/addons/document/wizard/__init__.py b/addons/document/wizard/__init__.py
new file mode 100644
index 00000000000..b143b583426
--- /dev/null
+++ b/addons/document/wizard/__init__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+import document_configuration
diff --git a/addons/document/wizard/document_configuration.py b/addons/document/wizard/document_configuration.py
new file mode 100644
index 00000000000..a497eb6af90
--- /dev/null
+++ b/addons/document/wizard/document_configuration.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+from osv import osv, fields
+class document_configuration(osv.osv_memory):
+
+ _name='document.configuration'
+ _description = 'Auto Directory Configuration'
+ _inherit = 'res.config'
+
+ _columns = {
+ 'sale_order' : fields.boolean('Sale Order', help="Auto directory configuration for Sale Orders and Quotation with report."),
+ 'product' : fields.boolean('Product', help="Auto directory configuration for Products."),
+ 'project': fields.boolean('Project', help="Auto directory configuration for Projects."),
+ }
+
+
+ def execute(self, cr, uid, ids, context=None):
+ conf_id = ids and ids[0] or False
+ conf = self.browse(cr, uid, conf_id, context)
+ dir_pool = self.pool.get('document.directory')
+ data_pool = self.pool.get('ir.model.data')
+ model_pool = self.pool.get('ir.model')
+ content_pool = self.pool.get('document.directory.content')
+ if conf.sale_order and self.pool.get('sale.order'):
+ # Sale order
+ dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_sale_order_all')
+ if dir_data_id:
+ sale_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id
+ else:
+ sale_dir_id = data_pool.create(cr, uid, {'name': 'Sale Orders'})
+ mid = model_pool.search(cr, uid, [('model','=','sale.order')])
+ dir_pool.write(cr, uid, [sale_dir_id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ 'domain': '[]',
+ })
+ # Qutation
+ dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_sale_order_quote')
+ if dir_data_id:
+ quta_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id
+ else:
+ quta_dir_id = data_pool.create(cr, uid, {'name': 'Sale Quotations'})
+
+ dir_pool.write(cr, uid, [quta_dir_id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ 'domain': "[('state','=','draft')]",
+ })
+ # Sale Order Report
+ order_report_data_id = data_pool._get_id(cr, uid, 'sale', 'report_sale_order')
+ if order_report_data_id:
+ order_report_id = data_pool.browse(cr, uid, order_report_data_id, context=context).res_id
+
+ content_pool.create(cr, uid, {
+ 'name': "Print Order",
+ 'suffix': "_print",
+ 'report_id': order_report_id,
+ 'extension': '.pdf',
+ 'include_name': 1,
+ 'directory_id': sale_dir_id,
+ })
+
+ content_pool.create(cr, uid, {
+ 'name': "Print Qutation",
+ 'suffix': "_print",
+ 'report_id': order_report_id,
+ 'extension': '.pdf',
+ 'include_name': 1,
+ 'directory_id': quta_dir_id,
+ })
+
+
+ if conf.product and self.pool.get('product.product'):
+ # Product
+ dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_product')
+ if dir_data_id:
+ product_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id
+ else:
+ product_dir_id = data_pool.create(cr, uid, {'name': 'Products'})
+
+ mid = model_pool.search(cr, uid, [('model','=','product.product')])
+ dir_pool.write(cr, uid, [product_dir_id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ })
+
+ if conf.project and self.pool.get('account.analytic.account'):
+ # Project
+ dir_data_id = data_pool._get_id(cr, uid, 'document', 'dir_project')
+ if dir_data_id:
+ project_dir_id = data_pool.browse(cr, uid, dir_data_id, context=context).res_id
+ else:
+ project_dir_id = data_pool.create(cr, uid, {'name': 'Projects'})
+
+ mid = model_pool.search(cr, uid, [('model','=','account.analytic.account')])
+ dir_pool.write(cr, uid, [project_dir_id], {
+ 'type':'ressource',
+ 'ressource_type_id': mid[0],
+ 'domain': '[]',
+ 'ressource_tree': 1
+ })
+document_configuration()
diff --git a/addons/document/wizard/document_configuration_view.xml b/addons/document/wizard/document_configuration_view.xml
new file mode 100644
index 00000000000..c6f40deb429
--- /dev/null
+++ b/addons/document/wizard/document_configuration_view.xml
@@ -0,0 +1,50 @@
+
+
+
+ Auto Configure Directory
+ document.configuration
+ form
+
+
+
+
+ Auto Configure
+
+
+ Resource Directory Configuration
+
+
+ Choose the following Resouces to auto directory configuration.
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Auto Configure Directory
+ ir.actions.act_window
+ document.configuration
+
+ form
+ form
+ new
+
+
+
+
+
+
+
+
diff --git a/addons/document_ftp/__init__.py b/addons/document_ftp/__init__.py
index 45ec4a6b67f..af514df8985 100644
--- a/addons/document_ftp/__init__.py
+++ b/addons/document_ftp/__init__.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
#
##############################################################################
-import doc_conf_wizard
import ftpserver
+import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/document_ftp/__openerp__.py b/addons/document_ftp/__openerp__.py
index 18042dabf93..a2b88d0a2a2 100644
--- a/addons/document_ftp/__openerp__.py
+++ b/addons/document_ftp/__openerp__.py
@@ -33,7 +33,8 @@
'depends': ['base', 'document'],
'init_xml': [],
'update_xml': [
- 'document_ftp_view.xml',
+ 'wizard/ftp_configuration_view.xml',
+ 'wizard/ftp_browse_view.xml',
'security/ir.model.access.csv'
],
'demo_xml': [],
diff --git a/addons/document_ftp/doc_conf_wizard.py b/addons/document_ftp/doc_conf_wizard.py
deleted file mode 100644
index 0f2f970572e..00000000000
--- a/addons/document_ftp/doc_conf_wizard.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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
-#
-##############################################################################
-
-import base64
-
-from osv import osv, fields
-from osv.orm import except_orm
-from tools import config
-import urlparse
-
-import os
-
-class document_configuration_wizard(osv.osv_memory):
-
- _name='document.configuration.wizard'
- _description = 'Auto Directory Configuration'
- _inherit = 'res.config'
- _rec_name = 'host'
- _columns = {
- 'host': fields.char('Address', size=64,
- help="Server address or IP and port to which users should connect to for DMS access",
- required=True),
- }
-
- _defaults = {
- 'host': config.get('ftp_server_host', 'localhost') + ':' + config.get('ftp_server_port', '8021'),
- }
-
- def execute(self, cr, uid, ids, context=None):
- conf = self.browse(cr, uid, ids[0], context)
- obj=self.pool.get('document.directory')
- objid=self.pool.get('ir.model.data')
-
- if self.pool.get('sale.order'):
- id = objid._get_id(cr, uid, 'document', 'dir_sale_order_all')
- id = objid.browse(cr, uid, id, context=context).res_id
- mid = self.pool.get('ir.model').search(cr, uid, [('model','=','sale.order')])
- obj.write(cr, uid, [id], {
- 'type':'ressource',
- 'ressource_type_id': mid[0],
- 'domain': '[]',
- })
- aid = objid._get_id(cr, uid, 'sale', 'report_sale_order')
- aid = objid.browse(cr, uid, aid, context=context).res_id
-
- self.pool.get('document.directory.content').create(cr, uid, {
- 'name': "Print Order",
- 'suffix': "_print",
- 'report_id': aid,
- 'extension': '.pdf',
- 'include_name': 1,
- 'directory_id': id,
- })
- id = objid._get_id(cr, uid, 'document', 'dir_sale_order_quote')
- id = objid.browse(cr, uid, id, context=context).res_id
- obj.write(cr, uid, [id], {
- 'type':'ressource',
- 'ressource_type_id': mid[0],
- 'domain': "[('state','=','draft')]",
- })
-
- if self.pool.get('product.product'):
- id = objid._get_id(cr, uid, 'document', 'dir_product')
- id = objid.browse(cr, uid, id, context=context).res_id
- mid = self.pool.get('ir.model').search(cr, uid, [('model','=','product.product')])
- obj.write(cr, uid, [id], {
- 'type':'ressource',
- 'ressource_type_id': mid[0],
- })
-
- if self.pool.get('stock.location'):
- aid = objid._get_id(cr, uid, 'stock', 'report_product_history')
- aid = objid.browse(cr, uid, aid, context=context).res_id
-
- self.pool.get('document.directory.content').create(cr, uid, {
- 'name': "Product Stock",
- 'suffix': "_stock_forecast",
- 'report_id': aid,
- 'extension': '.pdf',
- 'include_name': 1,
- 'directory_id': id,
- })
-
- if self.pool.get('account.analytic.account'):
- id = objid._get_id(cr, uid, 'document', 'dir_project')
- id = objid.browse(cr, uid, id, context=context).res_id
- mid = self.pool.get('ir.model').search(cr, uid, [('model','=','account.analytic.account')])
- obj.write(cr, uid, [id], {
- 'type':'ressource',
- 'ressource_type_id': mid[0],
- 'domain': '[]',
- 'ressource_tree': 1
- })
-
- # Update the action for FTP browse.
- aid = objid._get_id(cr, uid, 'document_ftp', 'action_document_browse')
- aid = objid.browse(cr, uid, aid, context=context).res_id
- self.pool.get('ir.actions.url').write(cr, uid, [aid], {'url': 'ftp://'+(conf.host or 'localhost:8021')+'/'})
-document_configuration_wizard()
diff --git a/addons/document_ftp/security/ir.model.access.csv b/addons/document_ftp/security/ir.model.access.csv
index c9c082f4397..b3ffdbd5350 100644
--- a/addons/document_ftp/security/ir.model.access.csv
+++ b/addons/document_ftp/security/ir.model.access.csv
@@ -1,3 +1,6 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
-"access_document_configuation_wizard","document.configuration.wizard document manager","model_document_configuration_wizard","document.group_document_manager",1,1,1,1
-"access_document_configuation_wizard_sytem","document.configuration.wizard group system","model_document_configuration_wizard","base.group_system",1,1,1,1
+"access_document_ftp_browse","document.ftp.browse document manager","model_document_ftp_browse","document.group_document_manager",1,1,1,1
+"access_document_ftp_browse","document.ftp.browse group system","model_document_ftp_browse","base.group_system",1,1,1,1
+"access_document_ftp_configuation","document.ftp.configuration document manager","model_document_ftp_configuration","document.group_document_manager",1,1,1,1
+"access_document_ftp_configuation_system","document.ftp.configuration group system","model_document_ftp_configuration","base.group_system",1,1,1,1
+
diff --git a/addons/account_report_india/__openerp__.py b/addons/document_ftp/wizard/__init__.py
similarity index 56%
rename from addons/account_report_india/__openerp__.py
rename to addons/document_ftp/wizard/__init__.py
index 0765af339a1..40997cc6b90 100644
--- a/addons/account_report_india/__openerp__.py
+++ b/addons/document_ftp/wizard/__init__.py
@@ -1,8 +1,8 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
+# Copyright (C) 2004-2010 Tiny SPRL ().
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -18,30 +18,8 @@
# along with this program. If not, see .
#
##############################################################################
+import ftp_browse
+import ftp_configuration
-{
- "name" : "Accounting Reports",
- "version" : "1.0",
- "depends" : [
- "account"
- ],
- "author" : "Tiny ERP",
- "description": """Accounting Reports
-Modules gives the 2 most Important Reports for the Accounting
-* Profit and Loss Account
-* Balance Sheet
- """,
- "website" : "http://tinyerp.com/module_account.html",
- "category" : "Generic Modules/Accounting",
- "init_xml" : [
- ],
- "demo_xml" : [
-
- ],
- "update_xml" : [
- "wizard/account_pl_report_view.xml",
- "wizard/account_bs_report_view.xml"
- ],
- "active": False,
- "installable": True
-}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/document_ftp/wizard/ftp_browse.py b/addons/document_ftp/wizard/ftp_browse.py
new file mode 100644
index 00000000000..d033302f22a
--- /dev/null
+++ b/addons/document_ftp/wizard/ftp_browse.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+from osv import osv, fields
+from tools.translate import _
+from document_ftp import ftpserver
+class document_ftp_browse(osv.osv_memory):
+ _name = 'document.ftp.browse'
+ _description = 'Document FTP Browse'
+
+ _columns = {
+ 'url' : fields.char('FTP Server', size=64, required=True),
+ }
+
+ def default_get(self, cr, uid, fields, context=None):
+ res = {}
+ if 'url' in fields:
+ user_pool = self.pool.get('res.users')
+ current_user = user_pool.browse(cr, uid, uid, context=context)
+ dir_pool = self.pool.get('document.directory')
+ data_pool = self.pool.get('ir.model.data')
+ aid = data_pool._get_id(cr, uid, 'document_ftp', 'action_document_browse')
+ aid = data_pool.browse(cr, uid, aid, context=context).res_id
+ ftp_url = self.pool.get('ir.actions.url').browse(cr, uid, aid, context=context)
+ url = ftp_url.url and ftp_url.url.split('ftp://') or []
+ if url:
+ url = url[1]
+ else:
+ url = '%s:%s' %(ftpserver.HOST, ftpserver.PORT)
+ res['url'] = 'ftp://%s@%s'%(current_user.login, url)
+ return res
+
+ def browse_ftp(self, cr, uid, ids, context):
+ data_id = ids and ids[0] or False
+ data = self.browse(cr, uid, data_id, context)
+ final_url = data.url
+ return {
+ 'type': 'ir.actions.act_url',
+ 'url':final_url,
+ 'target': 'new'
+ }
+document_ftp_browse()
+
diff --git a/addons/document_ftp/wizard/ftp_browse_view.xml b/addons/document_ftp/wizard/ftp_browse_view.xml
new file mode 100644
index 00000000000..44cedccfc3e
--- /dev/null
+++ b/addons/document_ftp/wizard/ftp_browse_view.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ Document FTP Browse
+ document.ftp.browse
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Document Browse
+ ir.actions.act_window
+ document.ftp.browse
+
+ form
+ form
+ new
+
+
+
+
+
+
diff --git a/addons/document_ftp/wizard/ftp_configuration.py b/addons/document_ftp/wizard/ftp_configuration.py
new file mode 100644
index 00000000000..40926bdf7c9
--- /dev/null
+++ b/addons/document_ftp/wizard/ftp_configuration.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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
+#
+##############################################################################
+
+import base64
+
+from osv import osv, fields
+from osv.orm import except_orm
+from tools import config
+import urlparse
+
+import os
+
+class document_ftp_configuration(osv.osv_memory):
+
+ _name='document.ftp.configuration'
+ _description = 'Auto Directory Configuration'
+ _inherit = 'res.config'
+ _rec_name = 'host'
+ _columns = {
+ 'host': fields.char('Address', size=64,
+ help="Server address or IP and port to which users should connect to for DMS access",
+ required=True),
+ }
+
+ _defaults = {
+ 'host': config.get('ftp_server_host', 'localhost') + ':' + config.get('ftp_server_port', '8021'),
+ }
+
+ def execute(self, cr, uid, ids, context=None):
+ conf = self.browse(cr, uid, ids[0], context)
+ dir_pool = self.pool.get('document.directory')
+ data_pool = self.pool.get('ir.model.data')
+ # Update the action for FTP browse.
+ aid = data_pool._get_id(cr, uid, 'document_ftp', 'action_document_browse')
+ aid = data_pool.browse(cr, uid, aid, context=context).res_id
+ self.pool.get('ir.actions.url').write(cr, uid, [aid], {'url': 'ftp://'+(conf.host or 'localhost:8021')+'/'})
+document_ftp_configuration()
diff --git a/addons/document_ftp/document_ftp_view.xml b/addons/document_ftp/wizard/ftp_configuration_view.xml
similarity index 76%
rename from addons/document_ftp/document_ftp_view.xml
rename to addons/document_ftp/wizard/ftp_configuration_view.xml
index d3f4c09498c..df3aee360af 100644
--- a/addons/document_ftp/document_ftp_view.xml
+++ b/addons/document_ftp/wizard/ftp_configuration_view.xml
@@ -3,26 +3,19 @@
Browse Filesftp://localhost:8021/
-
-
+
- Auto Configure Directory
- document.configuration.wizard
+ FTP Server Configuration
+ document.ftp.configurationform
- Auto Configure
+ FTP Server Configuration
FTP Server Configuration
@@ -43,9 +36,9 @@
- Auto Configure Directory
+ FTP Server Configurationir.actions.act_window
- document.configuration.wizard
+ document.ftp.configurationformform
diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py
index 88f855f75f0..880074173ea 100644
--- a/addons/document_webdav/dav_fs.py
+++ b/addons/document_webdav/dav_fs.py
@@ -55,8 +55,6 @@ class openerp_dav_handler(dav_interface):
M_NS={ "DAV:" : dav_interface.M_NS['DAV:'],}
def __init__(self, parent, verbose=False):
- self.db_name = False
- self.directory_id=False
self.db_name_list=[]
self.parent = parent
self.baseuri = parent.baseuri
@@ -65,10 +63,10 @@ class openerp_dav_handler(dav_interface):
def get_propnames(self, uri):
props = self.PROPS
self.parent.log_message('get propnames: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
if cr: cr.close()
+ # TODO: maybe limit props for databases..?
return props
node = self.uri2object(cr, uid, pool, uri2)
if node:
@@ -83,7 +81,6 @@ class openerp_dav_handler(dav_interface):
raise DAV_NotFound
def match_prop(self, uri, match, ns, propname):
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
if cr: cr.close()
@@ -104,8 +101,7 @@ class openerp_dav_handler(dav_interface):
pname -- name of the property
"""
if self.M_NS.has_key(ns):
- return dav_interface.get_prop(self, uri, ns, propname)
- if uri[-1]=='/':uri=uri[:-1]
+ return dav_interface.get_prop(self, uri, ns, propname)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
if cr: cr.close()
@@ -114,19 +110,46 @@ class openerp_dav_handler(dav_interface):
if not node:
cr.close()
raise DAV_NotFound
- res = node.get_dav_eprop(cr, ns, propname)
+ res = node.get_dav_eprop(cr, ns, propname)
cr.close()
return res
- def get_db(self,uri):
- names=self.uri2local(uri).split('/')
- self.db_name=False
- if len(names) > 1:
- self.db_name=self.uri2local(uri).split('/')[1]
- if self.db_name=='':
- raise Exception,'Plese specify Database name in folder'
- return self.db_name
-
+ def get_db(self, uri, rest_ret=False, allow_last=False):
+ """Parse the uri and get the dbname and the rest.
+ Db name should be the first component in the unix-like
+ path supplied in uri.
+
+ @param rest_ret Instead of the db_name, return (db_name, rest),
+ where rest is the remaining path
+ @param allow_last If the dbname is the last component in the
+ path, allow it to be resolved. The default False value means
+ we will not attempt to use the db, unless there is more
+ path.
+
+ @return db_name or (dbname, rest) depending on rest_ret,
+ will return dbname=False when component is not found.
+ """
+
+ uri2 = self.uri2local(uri)
+ if uri2.startswith('/'):
+ uri2 = uri2[1:]
+ names=uri2.split('/',1)
+ db_name=False
+ rest = None
+ if allow_last:
+ ll = 0
+ else:
+ ll = 1
+ if len(names) > ll and names[0]:
+ db_name = names[0]
+ names = names[1:]
+
+ if rest_ret:
+ if len(names):
+ rest = names[0]
+ return db_name, rest
+ return db_name
+
def urijoin(self,*ajoin):
""" Return the base URI of this request, or even join it with the
@@ -140,20 +163,25 @@ class openerp_dav_handler(dav_interface):
result = s.exp_list()
self.db_name_list=[]
for db_name in result:
- db = pooler.get_db_only(db_name)
- cr = db.cursor()
- cr.execute("select id from ir_module_module where name = 'document' and state='installed' ")
- res=cr.fetchone()
- if res and len(res):
- self.db_name_list.append(db_name)
- cr.close()
+ cr = None
+ try:
+ db = pooler.get_db_only(db_name)
+ cr = db.cursor()
+ cr.execute("SELECT id FROM ir_module_module WHERE name = 'document' AND state='installed' ")
+ res=cr.fetchone()
+ if res and len(res):
+ self.db_name_list.append(db_name)
+ except Exception, e:
+ self.parent.log_error("Exception in db list: %s" % e)
+ finally:
+ if cr:
+ cr.close()
return self.db_name_list
def get_childs(self, uri, filters=None):
""" return the child objects as self.baseuris for the given URI """
self.parent.log_message('get childs: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
- cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri, allow_last=True)
if not dbname:
if cr: cr.close()
@@ -194,38 +222,33 @@ class openerp_dav_handler(dav_interface):
#
# pos: -1 to get the parent of the uri
#
- def get_cr(self, uri):
+ def get_cr(self, uri, allow_last=False):
+ """ Split the uri, grab a cursor for that db
+ """
pdb = self.parent.auth_proxy.last_auth
- reluri = self.uri2local(uri)
- try:
- dbname = reluri.split('/')[1]
- except:
- dbname = False
+ dbname, uri2 = self.get_db(uri, rest_ret=True, allow_last=allow_last)
+ uri2 = (uri2 and uri2.split('/')) or []
if not dbname:
- return None, None, None, False, None
- if not pdb and dbname:
- # if dbname was in our uri, we should have authenticated
- # against that.
- raise Exception("Programming error")
- #assert pdb == dbname, " %s != %s" %(pdb, dbname)
+ return None, None, None, False, uri2
+ # if dbname was in our uri, we should have authenticated
+ # against that.
+ assert pdb == dbname, " %s != %s" %(pdb, dbname)
res = self.parent.auth_proxy.auth_creds.get(dbname, False)
- if not res:
+ if not res:
self.parent.auth_proxy.checkRequest(self.parent, uri, dbname)
- res = self.parent.auth_proxy.auth_creds[dbname]
+ res = self.parent.auth_proxy.auth_creds[dbname]
user, passwd, dbn2, uid = res
db,pool = pooler.get_db_and_pool(dbname)
cr = db.cursor()
- uri2 = reluri.split('/')[2:]
return cr, uid, pool, dbname, uri2
- def uri2object(self, cr, uid, pool,uri):
+ def uri2object(self, cr, uid, pool, uri):
if not uid:
return None
return pool.get('document.directory').get_object(cr, uid, uri)
- def get_data(self,uri):
+ def get_data(self,uri, rrange=None):
self.parent.log_message('GET: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
try:
if not dbname:
@@ -234,6 +257,9 @@ class openerp_dav_handler(dav_interface):
if not node:
raise DAV_NotFound(uri2)
try:
+ if rrange:
+ self.parent.log_error("Doc get_data cannot use range")
+ raise DAV_Error(409)
datas = node.get_data(cr)
except TypeError,e:
import traceback
@@ -256,7 +282,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_resourcetype(self,uri):
""" return type of object """
self.parent.log_message('get RT: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
try:
if not dbname:
@@ -272,7 +297,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_displayname(self,uri):
self.parent.log_message('get DN: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
cr.close()
@@ -288,7 +312,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_getcontentlength(self, uri):
""" return the content length of an object """
self.parent.log_message('get length: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
result = 0
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
@@ -306,7 +329,6 @@ class openerp_dav_handler(dav_interface):
def _get_dav_getetag(self,uri):
""" return the ETag of an object """
self.parent.log_message('get etag: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
result = 0
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
@@ -323,7 +345,6 @@ class openerp_dav_handler(dav_interface):
@memoize(CACHE_SIZE)
def get_lastmodified(self, uri):
""" return the last modified date of the object """
- if uri[-1]=='/':uri=uri[:-1]
today = time.time()
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
@@ -342,7 +363,6 @@ class openerp_dav_handler(dav_interface):
@memoize(CACHE_SIZE)
def get_creationdate(self, uri):
""" return the last modified date of the object """
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
raise DAV_Error, 409
@@ -361,7 +381,6 @@ class openerp_dav_handler(dav_interface):
@memoize(CACHE_SIZE)
def _get_dav_getcontenttype(self,uri):
self.parent.log_message('get contenttype: %s' % uri)
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
return 'httpd/unix-directory'
@@ -369,7 +388,7 @@ class openerp_dav_handler(dav_interface):
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound(uri2)
- result = node.mimetype
+ result = str(node.mimetype)
return result
#raise DAV_NotFound, 'Could not find %s' % path
finally:
@@ -434,10 +453,8 @@ class openerp_dav_handler(dav_interface):
def rmcol(self,uri):
""" delete a collection """
- if uri[-1]=='/':uri=uri[:-1]
-
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
- if not dbname: # *-*
+ if not dbname:
raise DAV_Error, 409
node = self.uri2object(cr, uid, pool, uri2)
node.rmcol(cr)
@@ -447,7 +464,6 @@ class openerp_dav_handler(dav_interface):
return 204
def rm(self,uri):
- if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
if not dbname:
cr.close()
@@ -626,3 +642,5 @@ class openerp_dav_handler(dav_interface):
def is_collection(self, uri):
""" test if the given uri is a collection """
return self._get_dav_resourcetype(uri)==COLLECTION
+
+#eof
diff --git a/addons/document_webdav/i18n/el.po b/addons/document_webdav/i18n/el.po
index eaf94e5c066..5cda9602def 100644
--- a/addons/document_webdav/i18n/el.po
+++ b/addons/document_webdav/i18n/el.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: document_webdav_old
diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py
index 2406bc10492..e904d2ecfb7 100644
--- a/addons/document_webdav/webdav.py
+++ b/addons/document_webdav/webdav.py
@@ -3,6 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
+# Copyright (c) 1999 Christian Scholz (ruebe@aachen.heimat.de)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -48,7 +49,9 @@ def mk_prop_response(self, uri, good_props, bad_props, doc):
uparts=urlparse.urlparse(uri)
fileloc=uparts[2]
href=doc.createElement("D:href")
- huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc))
+ davpath = self._dataclass.parent.get_davpath()
+ hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc))
+ huri=doc.createTextNode(hurl)
href.appendChild(huri)
re.appendChild(href)
@@ -111,5 +114,45 @@ def mk_prop_response(self, uri, good_props, bad_props, doc):
return re
-PROPFIND.mk_prop_response = mk_prop_response
+def mk_propname_response(self,uri,propnames,doc):
+ """ make a new result element for a PROPNAME request
+
+ This will simply format the propnames list.
+ propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
+
+ """
+ re=doc.createElement("D:response")
+
+ # write href information
+ uparts=urlparse.urlparse(uri)
+ fileloc=uparts[2]
+ href=doc.createElement("D:href")
+ davpath = self._dataclass.parent.get_davpath()
+ hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc))
+ huri=doc.createTextNode(hurl)
+ href.appendChild(huri)
+ re.appendChild(href)
+
+ ps=doc.createElement("D:propstat")
+ nsnum=0
+
+ for ns,plist in propnames.items():
+ # write prop element
+ pr=doc.createElement("D:prop")
+ nsp="ns"+str(nsnum)
+ pr.setAttribute("xmlns:"+nsp,ns)
+ nsnum=nsnum+1
+
+ # write propertynames
+ for p in plist:
+ pe=doc.createElement(nsp+":"+p)
+ pr.appendChild(pe)
+
+ ps.appendChild(pr)
+ re.appendChild(ps)
+
+ return re
+
+PROPFIND.mk_prop_response = mk_prop_response
+PROPFIND.mk_propname_response = mk_propname_response
diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py
index 80b8b6bb898..610e51a0f07 100644
--- a/addons/document_webdav/webdav_server.py
+++ b/addons/document_webdav/webdav_server.py
@@ -33,6 +33,7 @@ from dav_fs import openerp_dav_handler
from tools.config import config
from DAV.WebDAVServer import DAVRequestHandler
from service.websrv_lib import HTTPDir,FixSendError
+from BaseHTTPServer import BaseHTTPRequestHandler
import urlparse
import urllib
from string import atoi,split
@@ -42,6 +43,9 @@ def OpenDAVConfig(**kw):
class OpenDAV:
def __init__(self, **kw):
self.__dict__.update(**kw)
+
+ def getboolean(self, word):
+ return self.__dict__.get(word, False)
class Config:
DAV = OpenDAV(**kw)
@@ -51,6 +55,7 @@ def OpenDAVConfig(**kw):
class DAVHandler(FixSendError,DAVRequestHandler):
verbose = False
+ protocol_version = 'HTTP/1.1'
def get_userinfo(self,user,pw):
return False
@@ -64,18 +69,17 @@ class DAVHandler(FixSendError,DAVRequestHandler):
pass
def get_db_from_path(self, uri):
- if uri or uri == '/':
- dbs = self.IFACE_CLASS.db_list()
- res = len(dbs) and dbs[0] or False
- else:
- res = self.IFACE_CLASS.get_db(uri)
+ # interface class will handle all cases.
+ res = self.IFACE_CLASS.get_db(uri, allow_last=True)
return res
def setup(self):
- davpath = '/'+config.get_misc('webdav','vdir','webdav')
+ self.davpath = '/'+config.get_misc('webdav','vdir','webdav')
self.baseuri = "http://%s:%d/"% (self.server.server_name, self.server.server_port)
self.IFACE_CLASS = openerp_dav_handler(self, self.verbose)
+ def get_davpath(self):
+ return self.davpath
def log_message(self, format, *args):
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_DEBUG_RPC, format % args)
@@ -83,6 +87,17 @@ class DAVHandler(FixSendError,DAVRequestHandler):
def log_error(self, format, *args):
netsvc.Logger().notifyChannel('xmlrpc', netsvc.LOG_WARNING, format % args)
+ def send_response(self, code, message=None):
+ # the BufferingHttpServer will send Connection: close , while
+ # the BaseHTTPRequestHandler will only accept int code.
+ # workaround both of them.
+ BaseHTTPRequestHandler.send_response(self, int(code), message)
+
+ def send_header(self, key, value):
+ if key == 'Connection' and value == 'close':
+ self.close_connection = 1
+ DAVRequestHandler.send_header(self, key, value)
+
def do_PUT(self):
dc=self.IFACE_CLASS
uri=urlparse.urljoin(self.get_baseuri(dc), self.path)
@@ -161,8 +176,18 @@ class DAVHandler(FixSendError,DAVRequestHandler):
self.send_body(None, '201', 'Created', '', headers=headers)
+from service.http_server import reg_http_service,OpenERPAuthProvider
+
+class DAVAuthProvider(OpenERPAuthProvider):
+ def authenticate(self, db, user, passwd, client_address):
+ """ authenticate, but also allow the False db, meaning to skip
+ authentication when no db is specified.
+ """
+ if db is False:
+ return True
+ return OpenERPAuthProvider.authenticate(self, db, user, passwd, client_address)
+
try:
- from service.http_server import reg_http_service,OpenERPAuthProvider
if (config.get_misc('webdav','enable',True)):
directory = '/'+config.get_misc('webdav','vdir','webdav')
@@ -177,7 +202,7 @@ try:
conf = OpenDAVConfig(**_dc)
handler._config = conf
- reg_http_service(HTTPDir(directory,DAVHandler,OpenERPAuthProvider()))
+ reg_http_service(HTTPDir(directory,DAVHandler,DAVAuthProvider()))
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_INFO, "WebDAV service registered at path: %s/ "% directory)
except Exception, e:
logger = netsvc.Logger()
diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py
index 37b38774a7d..0ca89a5bbb8 100644
--- a/addons/email_template/email_template.py
+++ b/addons/email_template/email_template.py
@@ -108,7 +108,7 @@ class email_template(osv.osv):
'enforce_from_account':fields.many2one(
'email_template.account',
string="Enforce From Account",
- help="Emails will be sent only from this account."),
+ help="Emails will be sent only from this account(which are approved)."),
'from_email' : fields.related('enforce_from_account', 'email_id',
type='char', string='From',),
'def_to':fields.char(
@@ -222,39 +222,41 @@ class email_template(osv.osv):
'template_language' : lambda *a:'mako',
}
+
_sql_constraints = [
('name', 'unique (name)', _('The template name must be unique !'))
]
- def create(self, cr, uid, vals, context=None):
- id = super(email_template, self).create(cr, uid, vals, context)
- src_obj = self.pool.get('ir.model').read(cr, uid, vals['object_name'], ['model'], context)['model']
+ def create_action(self, cr, uid, ids, context):
+ vals = {}
+ template_obj = self.browse(cr, uid, ids)[0]
+ src_obj = template_obj.object_name.model
vals['ref_ir_act_window'] = self.pool.get('ir.actions.act_window').create(cr, uid, {
- 'name': _("%s Mail Form") % vals['name'],
+ 'name': template_obj.name,
'type': 'ir.actions.act_window',
'res_model': 'email_template.send.wizard',
'src_model': src_obj,
'view_type': 'form',
- 'context': "{'src_model':'%s','template_id':'%d','src_rec_id':active_id,'src_rec_ids':active_ids}" % (src_obj, id),
+ 'context': "{'src_model':'%s','template_id':'%d','src_rec_id':active_id,'src_rec_ids':active_ids}" % (src_obj, template_obj.id),
'view_mode':'form,tree',
'view_id': self.pool.get('ir.ui.view').search(cr, uid, [('name', '=', 'email_template.send.wizard.form')], context=context)[0],
'target': 'new',
'auto_refresh':1
}, context)
vals['ref_ir_value'] = self.pool.get('ir.values').create(cr, uid, {
- 'name': _('Send Mail (%s)') % vals['name'],
+ 'name': _('Send Mail (%s)') % template_obj.name,
'model': src_obj,
'key2': 'client_action_multi',
'value': "ir.actions.act_window," + str(vals['ref_ir_act_window']),
'object': True,
}, context)
- self.write(cr, uid, id, {
+ self.write(cr, uid, ids, {
'ref_ir_act_window': vals['ref_ir_act_window'],
'ref_ir_value': vals['ref_ir_value'],
}, context)
- return id
+ return True
- def unlink(self, cr, uid, ids, context=None):
+ def unlink_action(self, cr, uid, ids, context):
for template in self.browse(cr, uid, ids, context):
obj = self.pool.get(template.object_name.model)
try:
@@ -264,6 +266,13 @@ class email_template(osv.osv):
self.pool.get('ir.values').unlink(cr, uid, template.ref_ir_value.id, context)
except:
raise osv.except_osv(_("Warning"), _("Deletion of Record failed"))
+
+ def delete_action(self, cr, uid, ids, context):
+ self.unlink_action(cr, uid, ids, context)
+ return True
+
+ def unlink(self, cr, uid, ids, context=None):
+ self.unlink_action(cr, uid, ids, context)
return super(email_template, self).unlink(cr, uid, ids, context)
def copy(self, cr, uid, id, default=None, context=None):
@@ -580,8 +589,8 @@ class email_template(osv.osv):
context)
print 'Sending', mailbox_id
- self.pool.get('email_template.mailbox').send_this_mail(cursor, user, [mailbox_id], context)
return mailbox_id
+
def generate_mail(self,
cursor,
@@ -595,6 +604,7 @@ class email_template(osv.osv):
if not template:
raise Exception("The requested template could not be loaded")
print 'loaded', record_ids
+ result = True
for record_id in record_ids:
mailbox_id = self._generate_mailbox_item_from_template(
cursor,
@@ -625,7 +635,9 @@ class email_template(osv.osv):
{'folder':'outbox'},
context=context
)
- return True
+ # TODO : manage return value of all the records
+ result = self.pool.get('email_template.mailbox').send_this_mail(cursor, user, [mailbox_id], context)
+ return result
email_template()
@@ -641,7 +653,7 @@ class email_template_preview(osv.osv_memory):
if 'template_id' in context.keys():
ref_obj_id = self.pool.get('email.template').read(cr, uid, context['template_id'], ['object_name'], context)
ref_obj_name = self.pool.get('ir.model').read(cr, uid, ref_obj_id['object_name'][0], ['model'], context)['model']
- ref_obj_ids = self.pool.get(ref_obj_name).search(cr, uid, [], context=context)
+ ref_obj_ids = self.pool.get(ref_obj_name).search(cr, uid, [], 0, 20, 'id desc', context=context)
ref_obj_recs = self.pool.get(ref_obj_name).name_get(cr, uid, ref_obj_ids, context)
return ref_obj_recs
diff --git a/addons/email_template/email_template_account.py b/addons/email_template/email_template_account.py
index 0bcf3c3d099..9ea1cd5b8fa 100644
--- a/addons/email_template/email_template_account.py
+++ b/addons/email_template/email_template_account.py
@@ -97,9 +97,12 @@ class email_template_account(osv.osv):
context
)['name'],
'state':lambda * a:'draft',
+ 'smtpport':lambda *a:25,
+ 'smtpserver':lambda *a:'localhost',
+ 'company':lambda *a:'yes',
'user':lambda self, cursor, user, context:user,
- 'send_pref':lambda * a: 'html',
- 'smtptls':lambda * a:True,
+ 'send_pref':lambda *a: 'html',
+ 'smtptls':lambda *a:True,
}
_sql_constraints = [
@@ -266,7 +269,7 @@ class email_template_account(osv.osv):
return result
def send_mail(self, cr, uid, ids, addresses, subject='', body=None, payload=None, context=None):
- #TODO: Replace all this crap with a single email object
+ #TODO: Replace all this with a single email object
if body is None:
body = {}
if payload is None:
@@ -320,19 +323,20 @@ class email_template_account(osv.osv):
msg.attach(part)
except Exception, error:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed. Probable Reason:MIME Error\nDescription: %s") % (id, error))
- return error
+ return {'error_msg': "Server Send Error\nDescription: %s"%error}
try:
#print msg['From'],toadds
serv.sendmail(msg['From'], addresses_l['all'], msg.as_string())
except Exception, error:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed. Probable Reason:Server Send Error\nDescription: %s") % (id, error))
- return error
+ return {'error_msg': "Server Send Error\nDescription: %s"%error}
#The mail sending is complete
serv.close()
logger.notifyChannel(_("Email Template"), netsvc.LOG_INFO, _("Mail from Account %s successfully Sent.") % (id))
return True
else:
logger.notifyChannel(_("Email Template"), netsvc.LOG_ERROR, _("Mail from Account %s failed. Probable Reason:Account not approved") % id)
+ return {'error_msg':"Mail from Account %s failed. Probable Reason:Account not approved"% id}
def extracttime(self, time_as_string):
"""
@@ -394,7 +398,6 @@ class email_template_account(osv.osv):
return date_as_date
def send_receive(self, cr, uid, ids, context=None):
- self.get_mails(cr, uid, ids, context)
for id in ids:
ctx = context.copy()
ctx['filters'] = [('account_id', '=', id)]
diff --git a/addons/email_template/email_template_mailbox.py b/addons/email_template/email_template_mailbox.py
index fe9ca334d21..b20fa9f76bf 100644
--- a/addons/email_template/email_template_mailbox.py
+++ b/addons/email_template/email_template_mailbox.py
@@ -41,6 +41,7 @@ class email_template_mailbox(osv.osv):
return True
def send_this_mail(self, cr, uid, ids=None, context=None):
+ result = True
for id in (ids or []):
try:
account_obj = self.pool.get('email_template.account')
@@ -56,18 +57,19 @@ class email_template_mailbox(osv.osv):
values['subject'] or u'',
{'text':values.get('body_text', u'') or u'', 'html':values.get('body_html', u'') or u''},
payload=payload, context=context)
-
if result == True:
self.write(cr, uid, id, {'folder':'sent', 'state':'na', 'date_mail':time.strftime("%Y-%m-%d %H:%M:%S")}, context)
self.historise(cr, uid, [id], "Email sent successfully", context)
else:
- self.historise(cr, uid, [id], result, context)
+ error = result['error_msg']
+ self.historise(cr, uid, [id], error, context)
+
except Exception, error:
logger = netsvc.Logger()
logger.notifyChannel(_("Power Email"), netsvc.LOG_ERROR, _("Sending of Mail %s failed. Probable Reason:Could not login to server\nError: %s") % (id, error))
self.historise(cr, uid, [id], error, context)
self.write(cr, uid, id, {'state':'na'}, context)
- return True
+ return result
def historise(self, cr, uid, ids, message='', context=None):
for id in ids:
diff --git a/addons/email_template/email_template_view.xml b/addons/email_template/email_template_view.xml
index 934a7324b07..3346c6c6162 100644
--- a/addons/email_template/email_template_view.xml
+++ b/addons/email_template/email_template_view.xml
@@ -8,33 +8,29 @@
form
-
-
-
-
- Registrations
- ir.actions.act_window
- event.registration.list
- form
- form
-
- {'record_id' : active_id}
- new
-
-
-
-
-
- Event Registrations
- client_action_multi
-
- action
- event.event
-
-
-
-
\ No newline at end of file
diff --git a/addons/event/wizard/event_registrations_partner.py b/addons/event/wizard/event_registrations_partner.py
deleted file mode 100644
index e8fe43f97e0..00000000000
--- a/addons/event/wizard/event_registrations_partner.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-from osv import fields, osv
-from tools.translate import _
-
-class event_partners_list(osv.osv_memory):
- """ Event Partners """
- _name = "event.partners.list"
- _description = "List Event Partners"
-
- def list_partners(self, cr, uid, ids, context={}):
- obj_reg = self.pool.get('event.registration')
- mod_obj = self.pool.get('ir.model.data')
- list_partner = []
- reg_ids = obj_reg.search(cr, uid, [('event_id','in',context['active_ids'])], context=context)
- data_reg = obj_reg.browse(cr, uid, reg_ids, context=context)
- for reg in data_reg:
- if not reg.partner_id.id in list_partner:
- list_partner.append(reg.partner_id.id)
- result = mod_obj._get_id(cr, uid, 'base', 'view_res_partner_filter')
- id = mod_obj.read(cr, uid, result, ['res_id'], context=context)
- model_data_ids = mod_obj.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_partner_form')], context=context)
- resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
- return {
- 'domain': "[('id','in', ["+','.join(map(str, list_partner))+"])]",
- 'name': _('Event Partners'),
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'res.partner',
- 'views': [(False,'tree'),(resource_id,'form')],
- 'type': 'ir.actions.act_window',
- 'search_view_id': id['res_id']
- }
-
-event_partners_list()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/event/wizard/event_registrations_partner.xml b/addons/event/wizard/event_registrations_partner.xml
deleted file mode 100644
index c700bde11f9..00000000000
--- a/addons/event/wizard/event_registrations_partner.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
- Event Partners
- event.partners.list
- form
-
-
-
-
-
-
-
-
-
- List Register Partners
- ir.actions.act_window
- event.partners.list
- form
- form
-
- {'record_id' : active_id}
- new
-
-
-
-
-
- Event Partners
- client_action_multi
-
- action
- event.event
-
-
-
-
\ No newline at end of file
diff --git a/addons/event_project/i18n/el.po b/addons/event_project/i18n/el.po
new file mode 100644
index 00000000000..e693321250f
--- /dev/null
+++ b/addons/event_project/i18n/el.po
@@ -0,0 +1,88 @@
+# Greek translation for openobject-addons
+# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2009-08-28 16:01+0000\n"
+"PO-Revision-Date: 2010-06-24 22:21+0000\n"
+"Last-Translator: Panayiotis Konstantinidis \n"
+"Language-Team: Greek \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#. module: event_project
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "Λανθασμένο XML για προβολή αρχιτεκτονικής!"
+
+#. module: event_project
+#: model:ir.actions.wizard,name:event_project.wizard_event_task
+msgid "Tasks"
+msgstr "Εργασίες"
+
+#. module: event_project
+#: wizard_button:event.project,init,done:0
+msgid "Ok"
+msgstr "Εντάξει"
+
+#. module: event_project
+#: model:ir.module.module,description:event_project.module_meta_information
+msgid ""
+"Organization and management of events.\n"
+"\n"
+" This module allow you to create retro planning for managing your "
+"events.\n"
+msgstr ""
+"Οργάνωση και διαχείριση συμβάντων.\n"
+"\n"
+" Αυτή το τμήμα του προγράμματος σας επιτρέπει να κάνετε ανασχεδιασμό για "
+"τη διαχείριση των συμβάντων σας.\n"
+
+#. module: event_project
+#: view:event.event:0
+msgid "Remaining Tasks"
+msgstr "Εργασίες που παραμένουν"
+
+#. module: event_project
+#: model:ir.module.module,shortdesc:event_project.module_meta_information
+msgid "Event - Project"
+msgstr "Συμβάν - Έργο"
+
+#. module: event_project
+#: field:event.event,project_id:0
+#: wizard_field:event.project,init,project_id:0
+#: model:ir.actions.wizard,name:event_project.event_wiz
+msgid "Project"
+msgstr "Έργο"
+
+#. module: event_project
+#: field:event.event,task_ids:0
+msgid "Project tasks"
+msgstr "Εργασίες Έργου"
+
+#. module: event_project
+#: wizard_button:event.project,init,end:0
+msgid "Cancel"
+msgstr "Ακύρωση"
+
+#. module: event_project
+#: view:event.event:0
+msgid "Create Retro-Planning"
+msgstr "Δημιουργία προγραμματισμού"
+
+#. module: event_project
+#: wizard_view:event.project,init:0
+msgid "Event"
+msgstr "Συμβάν"
+
+#. module: event_project
+#: view:event.event:0
+msgid "Tasks management"
+msgstr "Διαχείριση εργασιών"
diff --git a/addons/fetchmail/__openerp__.py b/addons/fetchmail/__openerp__.py
index a1276c11643..31037cca63f 100644
--- a/addons/fetchmail/__openerp__.py
+++ b/addons/fetchmail/__openerp__.py
@@ -24,7 +24,7 @@
{
"name" : "Fetchmail Server",
"version" : "1.0",
- "depends" : ["base"],
+ "depends" : ["base", 'mail_gateway'],
"author" : "Tiny",
"description": """Fetchmail:
* Fetch email from Pop / IMAP server
diff --git a/addons/fetchmail/fetchmail.py b/addons/fetchmail/fetchmail.py
index aa403cc0090..947434052ae 100644
--- a/addons/fetchmail/fetchmail.py
+++ b/addons/fetchmail/fetchmail.py
@@ -19,140 +19,57 @@
#
##############################################################################
-import os
-import re
import time
-import email
-import binascii
-import mimetypes
-
from imaplib import IMAP4
-from imaplib import IMAP4_SSL
-
+from imaplib import IMAP4_SSL
from poplib import POP3
from poplib import POP3_SSL
-from email.header import Header
-from email.header import decode_header
-
import netsvc
-from osv import osv
-from osv import fields
-from tools.translate import _
+from osv import osv, fields
logger = netsvc.Logger()
-def html2plaintext(html, body_id=None, encoding='utf-8'):
- ## (c) Fry-IT, www.fry-it.com, 2007
- ##
- ## download here: http://www.peterbe.com/plog/html2plaintext
- """ from an HTML text, convert the HTML to plain text.
- If @body_id is provided then this is the tag where the
- body (not necessarily ) starts.
- """
- try:
- from BeautifulSoup import BeautifulSoup, SoupStrainer, Comment
- except:
- return html
-
- urls = []
- if body_id is not None:
- strainer = SoupStrainer(id=body_id)
- else:
- strainer = SoupStrainer('body')
-
- soup = BeautifulSoup(html, parseOnlyThese=strainer, fromEncoding=encoding)
- for link in soup.findAll('a'):
- title = link.renderContents()
- for url in [x[1] for x in link.attrs if x[0]=='href']:
- urls.append(dict(url=url, tag=str(link), title=title))
-
- html = soup.__str__()
-
- url_index = []
- i = 0
- for d in urls:
- if d['title'] == d['url'] or 'http://'+d['title'] == d['url']:
- html = html.replace(d['tag'], d['url'])
- else:
- i += 1
- html = html.replace(d['tag'], '%s [%s]' % (d['title'], i))
- url_index.append(d['url'])
-
- html = html.replace('','*').replace('','*')
- html = html.replace('','*').replace('','*')
- html = html.replace('
','*').replace('
','*')
- html = html.replace('
','**').replace('
','**')
- html = html.replace('
','**').replace('
','**')
- html = html.replace('','/').replace('','/')
-
- # the only line breaks we respect is those of ending tags and
- # breaks
-
- html = html.replace('\n',' ')
- html = html.replace(' ', '\n')
- html = html.replace('
', '\n')
- html = html.replace('', '\n\n')
- html = re.sub(' ', '\n', html)
- html = html.replace(' ' * 2, ' ')
-
- # for all other tags we failed to clean up, just remove then and
- # complain about them on the stderr
- def desperate_fixer(g):
- #print >>sys.stderr, "failed to clean up %s" % str(g.group())
- return ' '
-
- html = re.sub('<.*?>', desperate_fixer, html)
-
- # lstrip all lines
- html = '\n'.join([x.lstrip() for x in html.splitlines()])
-
- for i, url in enumerate(url_index):
- if i == 0:
- html += '\n\n'
- html += '[%s] %s\n' % (i+1, url)
- return html
-
class email_server(osv.osv):
-
+
_name = 'email.server'
_description = "POP/IMAP Server"
-
+
_columns = {
- 'name':fields.char('Name', size=256, required=True, readonly=False),
- 'active':fields.boolean('Active', required=False),
+ 'name':fields.char('Name', size=256, required=True, readonly=False),
+ 'active':fields.boolean('Active', required=False),
'state':fields.selection([
- ('draft','Not Confirmed'),
- ('wating','Waiting for Verification'),
- ('done','Confirmed'),
- ],'State', select=True, readonly=True),
- 'server' : fields.char('Server', size=256, required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'port' : fields.integer('Port', required=True, readonly=True, states={'draft':[('readonly',False)]}),
+ ('draft', 'Not Confirmed'),
+ ('wating', 'Waiting for Verification'),
+ ('done', 'Confirmed'),
+ ], 'State', select=True, readonly=True),
+ 'server' : fields.char('Server', size=256, required=True, readonly=True, states={'draft':[('readonly', False)]}),
+ 'port' : fields.integer('Port', required=True, readonly=True, states={'draft':[('readonly', False)]}),
'type':fields.selection([
- ('pop','POP Server'),
- ('imap','IMAP Server'),
- ],'State', select=True, readonly=False),
- 'is_ssl':fields.boolean('SSL ?', required=False),
- 'attach':fields.boolean('Add Attachments ?', required=False),
- 'date': fields.date('Date', readonly=True, states={'draft':[('readonly',False)]}),
- 'user' : fields.char('User Name', size=256, required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'password' : fields.char('Password', size=1024, invisible=True, required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'note': fields.text('Description'),
- 'action_id':fields.many2one('ir.actions.server', 'Reply Email', required=False, domain="[('state','=','email')]"),
- 'object_id': fields.many2one('ir.model',"Model", required=True),
- 'priority': fields.integer('Server Priority', readonly=True, states={'draft':[('readonly',False)]}, help="Priority between 0 to 10, select define the order of Processing"),
- 'user_id':fields.many2one('res.users', 'User', required=False),
+ ('pop', 'POP Server'),
+ ('imap', 'IMAP Server'),
+ ], 'Server Type', select=True, readonly=False),
+ 'is_ssl':fields.boolean('SSL ?', required=False),
+ 'attach':fields.boolean('Add Attachments ?', required=False),
+ 'date': fields.date('Date', readonly=True, states={'draft':[('readonly', False)]}),
+ 'user' : fields.char('User Name', size=256, required=True, readonly=True, states={'draft':[('readonly', False)]}),
+ 'password' : fields.char('Password', size=1024, invisible=True, required=True, readonly=True, states={'draft':[('readonly', False)]}),
+ 'note': fields.text('Description'),
+ 'action_id':fields.many2one('ir.actions.server', 'Reply Email', required=False, domain="[('state','=','email')]"),
+ 'object_id': fields.many2one('ir.model', "Model", required=True),
+ 'priority': fields.integer('Server Priority', readonly=True, states={'draft':[('readonly', False)]}, help="Priority between 0 to 10, select define the order of Processing"),
+ 'user_id':fields.many2one('res.users', 'User', required=False),
}
_defaults = {
- 'state': lambda *a: "draft",
- 'active': lambda *a: True,
- 'priority': lambda *a: 5,
- 'date': lambda *a: time.strftime('%Y-%m-%d'),
- 'user_id': lambda self, cr, uid, ctx: uid,
+ 'state': lambda *a: "draft",
+ 'active': lambda *a: True,
+ 'priority': lambda *a: 5,
+ 'date': lambda *a: time.strftime('%Y-%m-%d'),
+ 'user_id': lambda self, cr, uid, ctx: uid,
}
-
+
def check_duplicate(self, cr, uid, ids):
vals = self.read(cr, uid, ids, ['user', 'password'])[0]
cr.execute("select count(id) from email_server where user='%s' and password='%s'" % (vals['user'], vals['password']))
@@ -160,201 +77,43 @@ class email_server(osv.osv):
if res:
if res[0] > 1:
return False
- return True
+ return True
_constraints = [
(check_duplicate, 'Warning! Can\'t have duplicate server configuration!', ['user', 'password'])
]
-
+
def onchange_server_type(self, cr, uid, ids, server_type=False, ssl=False):
port = 0
if server_type == 'pop':
port = ssl and 995 or 110
elif server_type == 'imap':
port = ssl and 993 or 143
-
+
return {'value':{'port':port}}
-
- def _process_email(self, cr, uid, server, message, context={}):
- context.update({
- 'server_id':server.id
- })
- history_pool = self.pool.get('mail.server.history')
- msg_txt = email.message_from_string(message)
- message_id = msg_txt.get('Message-ID', False)
-
- msg = {}
- if not message_id:
- return False
-
- fields = msg_txt.keys()
-
- msg['id'] = message_id
- msg['message-id'] = message_id
-
- def _decode_header(txt):
- txt = txt.replace('\r', '')
- return ' '.join(map(lambda (x, y): unicode(x, y or 'ascii'), decode_header(txt)))
-
- if 'Subject' in fields:
- msg['subject'] = _decode_header(msg_txt.get('Subject'))
-
- if 'Content-Type' in fields:
- msg['content-type'] = msg_txt.get('Content-Type')
-
- if 'From' in fields:
- msg['from'] = _decode_header(msg_txt.get('From'))
-
- if 'Delivered-To' in fields:
- msg['to'] = _decode_header(msg_txt.get('Delivered-To'))
-
- if 'Cc' in fields:
- msg['cc'] = _decode_header(msg_txt.get('Cc'))
-
- if 'Reply-To' in fields:
- msg['reply'] = _decode_header(msg_txt.get('Reply-To'))
-
- if 'Date' in fields:
- msg['date'] = msg_txt.get('Date')
-
- if 'Content-Transfer-Encoding' in fields:
- msg['encoding'] = msg_txt.get('Content-Transfer-Encoding')
-
- if 'References' in fields:
- msg['references'] = msg_txt.get('References')
-
- if 'X-openerp-caseid' in fields:
- msg['caseid'] = msg_txt.get('X-openerp-caseid')
-
- if 'X-Priority' in fields:
- msg['priority'] = msg_txt.get('X-priority', '3 (Normal)').split(' ')[0]
-
- if not msg_txt.is_multipart() or 'text/plain' in msg.get('content-type', None):
- encoding = msg_txt.get_content_charset()
- msg['body'] = msg_txt.get_payload(decode=True)
- if encoding:
- msg['body'] = msg['body'].decode(encoding).encode('utf-8')
-
- attachents = {}
- if msg_txt.is_multipart() or 'multipart/alternative' in msg.get('content-type', None):
- body = ""
- counter = 1
- for part in msg_txt.walk():
- if part.get_content_maintype() == 'multipart':
- continue
-
- encoding = part.get_content_charset()
-
- if part.get_content_maintype()=='text':
- content = part.get_payload(decode=True)
- filename = part.get_filename()
- if filename :
- attachents[filename] = content
- else:
- if encoding:
- content = unicode(content, encoding)
- if part.get_content_subtype() == 'html':
- body = html2plaintext(content)
- elif part.get_content_subtype() == 'plain':
- body = content
- elif part.get_content_maintype()=='application' or part.get_content_maintype()=='image' or part.get_content_maintype()=='text':
- filename = part.get_filename();
- if filename :
- attachents[filename] = part.get_payload(decode=True)
- else:
- res = part.get_payload(decode=True)
- if encoding:
- res = res.decode(encoding).encode('utf-8')
-
- body += res
-
- msg['body'] = body
- msg['attachments'] = attachents
-
-
- res_id = False
- if msg.get('references', False):
- id = False
- ref = msg.get('references')
- if '\r\n' in ref:
- ref = msg.get('references').split('\r\n')
- else:
- ref = msg.get('references').split(' ')
-
- if ref:
- hids = history_pool.search(cr, uid, [('name','=',ref[0].strip())])
- if hids:
- id = hids[0]
- history = history_pool.browse(cr, uid, id)
- model_pool = self.pool.get(server.object_id.model)
- context.update({
- 'references_id':ref[0]
- })
- vals = {
-
- }
- if hasattr(model_pool, 'message_update'):
- model_pool.message_update(cr, uid, [history.res_id], vals, msg, context=context)
- else:
- logger.notifyChannel('imap', netsvc.LOG_WARNING, 'method def message_update is not define in model %s' % (model_pool._name))
- return False
- res_id = id
- else:
- model_pool = self.pool.get(server.object_id.model)
- if hasattr(model_pool, 'message_new'):
- res_id = model_pool.message_new(cr, uid, msg, context)
- else:
- logger.notifyChannel('imap', netsvc.LOG_WARNING, 'method def message_new is not define in model %s' % (model_pool._name))
- return False
-
- if server.attach:
- for attactment in attachents or []:
- data_attach = {
- 'name': attactment,
- 'datas':binascii.b2a_base64(str(attachents.get(attactment))),
- 'datas_fname': attactment,
- 'description': 'Mail attachment',
- 'res_model': server.object_id.model,
- 'res_id': res_id,
- }
- self.pool.get('ir.attachment').create(cr, uid, data_attach)
-
- if server.action_id:
- action_pool = self.pool.get('ir.actions.server')
- action_pool.run(cr, uid, [server.action_id.id], {'active_id':res_id, 'active_ids':[res_id]})
-
- res = {
- 'name': message_id,
- 'res_id': res_id,
- 'server_id': server.id,
- 'note': msg.get('body', msg.get('from')),
- 'ref_id':msg.get('references', msg.get('id')),
- 'type':server.type
- }
- his_id = history_pool.create(cr, uid, res)
-
- return res_id
def set_draft(self, cr, uid, ids, context={}):
self.write(cr, uid, ids , {'state':'draft'})
return True
-
+
def button_fetch_mail(self, cr, uid, ids, context={}):
self.fetch_mail(cr, uid, ids)
# sendmail_thread = threading.Thread(target=self.fetch_mail, args=(cr, uid, ids))
# sendmail_thread.start()
return True
-
+
def _fetch_mails(self, cr, uid, ids=False, context={}):
if not ids:
ids = self.search(cr, uid, [])
return self.fetch_mail(cr, uid, ids, context)
-
- def fetch_mail(self, cr, uid, ids, context={}):
+ def fetch_mail(self, cr, uid, ids, context=None):
+ if not context:
+ context = {}
+ email_tool = self.pool.get('email.server.tools')
for server in self.browse(cr, uid, ids, context):
logger.notifyChannel('imap', netsvc.LOG_INFO, 'fetchmail start checking for new emails on %s' % (server.name))
-
+ context.update({'server_id': server.id, 'server_type': server.type})
count = 0
try:
if server.type == 'imap':
@@ -363,17 +122,21 @@ class email_server(osv.osv):
imap_server = IMAP4_SSL(server.server, int(server.port))
else:
imap_server = IMAP4(server.server, int(server.port))
-
+
imap_server.login(server.user, server.password)
imap_server.select()
- result, data = imap_server.search(None, '(UNSEEN)')
+ result, data = imap_server.search(None, '(UNSEEN)')
for num in data[0].split():
result, data = imap_server.fetch(num, '(RFC822)')
- if self._process_email(cr, uid, server, data[0][1], context):
+ res_id = email_tool.process_email(cr, uid, server.object_id.model, data[0][1], attach=server.attach, context=context)
+ if res_id and server.action_id:
+ action_pool = self.pool.get('ir.actions.server')
+ action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]})
+
imap_server.store(num, '+FLAGS', '\\Seen')
- count += 1
+ count += 1
logger.notifyChannel('imap', netsvc.LOG_INFO, 'fetchmail fetch/process %s email(s) from %s' % (count, server.name))
-
+
imap_server.close()
imap_server.logout()
elif server.type == 'pop':
@@ -382,7 +145,7 @@ class email_server(osv.osv):
pop_server = POP3_SSL(server.server, int(server.port))
else:
pop_server = POP3(server.server, int(server.port))
-
+
#TODO: use this to remove only unread messages
#pop_server.user("recent:"+server.user)
pop_server.user(server.user)
@@ -393,79 +156,62 @@ class email_server(osv.osv):
for num in range(1, numMsgs + 1):
(header, msges, octets) = pop_server.retr(num)
msg = '\n'.join(msges)
- self._process_email(cr, uid, server, msg, context)
+ res_id = email_tool.process_email(cr, uid, server.object_id.model, data[0][1], attach=server.attach, context=context)
+ if res_id and server.action_id:
+ action_pool = self.pool.get('ir.actions.server')
+ action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]})
+
pop_server.dele(num)
pop_server.quit()
-
+
logger.notifyChannel('imap', netsvc.LOG_INFO, 'fetchmail fetch %s email(s) from %s' % (numMsgs, server.name))
-
+
self.write(cr, uid, [server.id], {'state':'done'})
except Exception, e:
logger.notifyChannel(server.type, netsvc.LOG_WARNING, '%s' % (e))
-
+
return True
email_server()
-class mail_server_history(osv.osv):
+class mailgate_message(osv.osv):
+
+ _inherit = "mailgate.message"
- _name = "mail.server.history"
- _description = "Mail Server History"
-
_columns = {
- 'name': fields.char('Message Id', size=256, readonly=True, help="Message Id in Email Server.", select=True),
- 'ref_id': fields.char('Referance Id', size=256, readonly=True, help="Message Id in Email Server.", select=True),
- 'res_id': fields.integer("Resource ID", readonly=True, select=True),
- 'server_id': fields.many2one('email.server',"Mail Server", readonly=True, select=True),
- 'model_id':fields.related('server_id', 'object_id', type='many2one', relation='ir.model', string='Model', readonly=True, select=True),
- 'note': fields.text('Notes', readonly=True),
- 'create_date': fields.datetime('Created Date', readonly=True),
+ 'server_id': fields.many2one('email.server', "Mail Server", readonly=True, select=True),
'type':fields.selection([
- ('pop','POP Server'),
- ('imap','IMAP Server'),
- ],'State', select=True, readonly=True),
+ ('pop', 'POP Server'),
+ ('imap', 'IMAP Server'),
+ ], 'Server Type', select=True, readonly=True),
}
_order = 'id desc'
-
-mail_server_history()
-class fetchmail_tool(osv.osv):
-
- _name = 'email.server.tools'
- _description = "Email Tools"
- _auto = False
-
- def to_email(self, text):
- _email = re.compile(r'.*<.*@.*\..*>', re.UNICODE)
- def record(path):
- eml = path.group()
- index = eml.index('<')
- eml = eml[index:-1].replace('<','').replace('>','')
- return eml
-
- bits = _email.sub(record, text)
- return bits
-
- def get_partner(self, cr, uid, from_email, context=None):
- """
- @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 from_email: email address based on that function will search for the correct
- """
-
- res = {
- 'partner_address_id': False,
- 'partner_id': False
- }
- from_email = self.to_email(from_email)
- address_ids = self.pool.get('res.partner.address').search(cr, uid, [('email', '=', from_email)])
- if address_ids:
- address = self.pool.get('res.partner.address').browse(cr, uid, address_ids[0])
- res['partner_address_id'] = address_ids[0]
- res['partner_id'] = address.partner_id.id
-
+ def create(self, cr, uid, values, context=None):
+ if not context:
+ context={}
+ server_id = context.get('server_id',False)
+ server_type = context.get('server_type',False)
+ if server_id:
+ values['server_id'] = server_id
+ if server_type:
+ values['server_type'] = server_type
+ res = super(mailgate_message,self).create(cr, uid, values, context=context)
return res
-
-fetchmail_tool()
+
+ def write(self, cr, uid, ids, values, context=None):
+ if not context:
+ context={}
+ server_id = context.get('server_id',False)
+ server_type = context.get('server_type',False)
+ if server_id:
+ values['server_id'] = server_id
+ if server_type:
+ values['server_type'] = server_type
+ res = super(mailgate_message,self).write(cr, uid, ids, values, context=context)
+ return res
+
+mailgate_message()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/fetchmail/fetchmail_view.xml b/addons/fetchmail/fetchmail_view.xml
index 510b31b6131..330f9fec349 100644
--- a/addons/fetchmail/fetchmail_view.xml
+++ b/addons/fetchmail/fetchmail_view.xml
@@ -103,82 +103,54 @@
action="action_email_server_tree_imap"
/>
-
- mail.server.history.tree
- mail.server.history
- tree
-
-
-
-
-
-
-
-
-
-
-
- mail.server.history.form
- mail.server.history
- form
-
-
-
\ No newline at end of file
+
diff --git a/addons/mail_gateway/res_partner.py b/addons/mail_gateway/res_partner.py
new file mode 100644
index 00000000000..54bed6a5b56
--- /dev/null
+++ b/addons/mail_gateway/res_partner.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+from osv import fields,osv
+
+class res_partner(osv.osv):
+ """ Inherits partner and adds CRM information in the partner form """
+ _inherit = 'res.partner'
+ _columns = {
+ 'emails': fields.one2many('mailgate.message', 'partner_id',\
+ 'Emails', readonly=True),
+ }
+
+res_partner()
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail_gateway/res_partner_view.xml b/addons/mail_gateway/res_partner_view.xml
new file mode 100644
index 00000000000..3cb1bb7fe5a
--- /dev/null
+++ b/addons/mail_gateway/res_partner_view.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ res.partner.emails.info.inherit
+ res.partner
+ form
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py
index c4cad98b046..166e1e8781f 100755
--- a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py
+++ b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL ().
# Copyright (C) 2010-TODAY OpenERP S.A. (http://www.openerp.com)
@@ -17,108 +17,19 @@
# 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 .
+# along with this program. If not, see
#
###########################################################################################
-import re
-import smtplib
-import email
-import mimetypes
-from email.Header import decode_header
-from email.MIMEText import MIMEText
-import xmlrpclib
-import os
-import binascii
-import time
-import socket
import logging
-import sys
import optparse
-
-email_re = re.compile(r"([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6})")
-case_re = re.compile(r"\[([0-9]+)\]", re.UNICODE)
-command_re = re.compile("^Set-([a-z]+) *: *(.+)$", re.I + re.UNICODE)
-reference_re = re.compile("<.*-openobject-(\\d+)@(.*)>", re.UNICODE)
-
-priorities = {
- '1': '1 (Highest)',
- '2': '2 (High)',
- '3': '3 (Normal)',
- '4': '4 (Low)',
- '5': '5 (Lowest)',
-}
-
-def html2plaintext(html, body_id=None, encoding='utf-8'):
- ## (c) Fry-IT, www.fry-it.com, 2007
- ##
- ## download here: http://www.peterbe.com/plog/html2plaintext
-
-
- """ from an HTML text, convert the HTML to plain text.
- If @body_id is provided then this is the tag where the
- body (not necessarily ) starts.
- """
- try:
- from BeautifulSoup import BeautifulSoup, SoupStrainer, Comment
- except:
- return html
-
- urls = []
- if body_id is not None:
- strainer = SoupStrainer(id=body_id)
- else:
- strainer = SoupStrainer('body')
-
- soup = BeautifulSoup(html, parseOnlyThese=strainer, fromEncoding=encoding)
- for link in soup.findAll('a'):
- title = unicode(link)
- for url in [x[1] for x in link.attrs if x[0]=='href']:
- urls.append(dict(url=url, tag=unicode(link), title=title))
-
- html = unicode(soup)
-
- url_index = []
- i = 0
- for d in urls:
- if d['title'] == d['url'] or 'http://'+d['title'] == d['url']:
- html = html.replace(d['tag'], d['url'])
- else:
- i += 1
- html = html.replace(d['tag'], '%s [%s]' % (d['title'], i))
- url_index.append(d['url'])
-
- html = html.replace('', '*').replace('', '*')
- html = html.replace('', '*').replace('', '*')
- html = html.replace('
', '*').replace('
', '*')
- html = html.replace('
', '**').replace('
', '**')
- html = html.replace('
', '**').replace('
', '**')
- html = html.replace('', '/').replace('', '/')
-
- # the only line breaks we respect is those of ending tags and
- # breaks
-
- html = html.replace('\n', ' ')
- html = html.replace(' ', '\n')
- html = html.replace('
', '\n')
- html = html.replace('', '\n\n')
- html = re.sub(' ', '\n', html)
- html = html.replace(' ' * 2, ' ')
-
- html = re.sub('<.*?>', ' ', html)
-
- # lstrip all lines
- html = '\n'.join([x.lstrip() for x in html.splitlines()])
-
- for i, url in enumerate(url_index):
- if i == 0:
- html += '\n\n'
- html += '[%s] %s\n' % (i+1, url)
- return html
+import sys
+import xmlrpclib
+import email
class rpc_proxy(object):
- def __init__(self, uid, passwd, host='localhost', port=8069, path='object', dbname='terp'):
- self.rpc = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (host, port, path))
+ def __init__(self, uid, passwd, host='localhost', port=8069, path='object', dbname='terp'):
+ self.rpc = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (host, port, path), allow_none=True)
self.user_id = uid
self.passwd = passwd
self.dbname = dbname
@@ -127,7 +38,7 @@ class rpc_proxy(object):
return self.rpc.execute(self.dbname, self.user_id, self.passwd, *request, **kwargs)
class email_parser(object):
- def __init__(self, uid, password, model, email, email_default, dbname, host, port):
+ def __init__(self, uid, password, model, email_default, dbname, host, port):
self.rpc = rpc_proxy(uid, password, host=host, port=port, dbname=dbname)
try:
self.model_id = int(model)
@@ -135,313 +46,26 @@ class email_parser(object):
except:
self.model_id = self.rpc('ir.model', 'search', [('model', '=', model)])[0]
self.model = str(model)
- self.email = email
self.email_default = email_default
- self.canal_id = False
- def email_get(self, email_from):
- res = email_re.search(email_from)
- return res and res.group(1)
- def partner_get(self, email):
- mail = self.email_get(email)
- adr_ids = self.rpc('res.partner.address', 'search', [('email', '=', mail)])
- if not adr_ids:
- return {}
- adr = self.rpc('res.partner.address', 'read', adr_ids, ['partner_id'])
- return {
- 'partner_address_id': adr[0]['id'],
- 'partner_id': adr[0].get('partner_id', False) and adr[0]['partner_id'][0] or False
- }
-
- def _to_decode(self, s, charsets):
- for charset in charsets:
- if charset:
- try:
- return s.decode(charset)
- except UnicodeError:
- pass
- return s.decode('latin1')
-
- def _decode_header(self, text):
- if text:
- text = decode_header(text.replace('\r', ''))
- return ''.join(map(lambda x:self._to_decode(x[0], [x[1]]), text or []))
-
- def msg_new(self, msg):
- message = self.msg_body_get(msg)
- msg_subject = self._decode_header(msg['Subject'])
- msg_from = self._decode_header(msg['From'])
- msg_to = self._decode_header(msg['To'])
- msg_cc = self._decode_header(msg['Cc'] or '')
-
- data = {
- 'name': msg_subject,
- 'email_from': msg_from,
- 'email_cc': msg_cc,
- 'user_id': False,
- 'description': message['body'],
- 'state' : 'draft',
- }
- data.update(self.partner_get(msg_from))
-
- values = {
- 'message_ids' : [
- (0, 0, {
- 'model_id' : self.rpc('ir.model', 'search', [('name', '=', self.model)])[0],
- 'date' : time.strftime('%Y-%m-%d %H:%M:%S'),
- 'description' : message['body'],
- 'email_from' : msg_from,
- 'email_to' : msg_to,
- 'name' : 'Receive',
- 'history' : True,
- 'user_id' : self.rpc.user_id,
- }
- )
- ]
- }
- thread_id = self.rpc('mailgate.thread', 'create', values)
- data['thread_id'] = thread_id
- oid = self.rpc(self.model, 'create', data)
-
- attachments = message['attachment']
- for attach in attachments or []:
- data_attach = {
- 'name': str(attach),
- 'datas': binascii.b2a_base64(str(attachments[attach])),
- 'datas_fname': str(attach),
- 'description': 'Mail attachment',
- 'res_model': self.model,
- 'res_id': oid
- }
- self.rpc('ir.attachment', 'create', data_attach)
-
- return (oid, thread_id,)
-
- def msg_body_get(self, msg):
- message = {
- 'body' : '',
- 'attachment' : {},
- }
- attachment = message['attachment'];
- counter = 1;
-
- for part in msg.walk():
- if part.get_content_maintype() == 'multipart':
- continue
-
- if part.get_content_maintype()=='text':
- buf = part.get_payload(decode=True)
- if buf:
- txt = self._to_decode(buf, part.get_charsets())
- txt = re.sub("<\/?(\w)>", '', txt)
- if txt and part.get_content_subtype() == 'plain':
- message['body'] += txt
- elif txt and part.get_content_subtype() == 'html':
- message['body'] += html2plaintext(txt)
-
- filename = part.get_filename();
- if filename :
- attachment[filename] = part.get_payload(decode=True);
-
- elif part.get_content_maintype() in ('application', 'image', 'text'):
- filename = part.get_filename();
- if not filename :
- filename = 'attach_file'+str(counter);
- counter += 1;
-
- attachment[filename] = part.get_payload(decode=True);
- message['attachment'] = attachment
- #end for
- return message
-
- def msg_user(self, msg, id):
- body = self.msg_body_get(msg)
-
- # handle email body commands (ex: Set-State: Draft)
- actions = {}
- body_data=''
- for line in body['body'].split('\n'):
- res = command_re.match(line)
- if res:
- actions[res.group(1).lower()] = res.group(2).lower()
- else:
- body_data += line+'\n'
- body['body'] = body_data
-
- data = {
-# 'description': body['body'],
- }
- act = 'case_open'
- if 'state' in actions:
- if actions['state'] in ['draft', 'close', 'cancel', 'open', 'pending']:
- act = 'case_' + actions['state']
-
- for k1, k2 in [('cost', 'planned_cost'), ('revenue', 'planned_revenue'), ('probability', 'probability')]:
- try:
- data[k2] = float(actions[k1])
- except:
- pass
-
- if 'priority' in actions:
- if actions['priority'] in ('1', '2', '3', '4', '5'):
- data['priority'] = actions['priority']
-
- if 'partner' in actions:
- data['email_from'] = actions['partner'][:128]
-
- if 'user' in actions:
- uids = self.rpc('res.users', 'name_search', actions['user'])
- if uids:
- data['user_id'] = uids[0][0]
-
- self.rpc(self.model, act, [id])
- self.rpc(self.model, 'write', [id], data)
- attachments = body['attachment']
- for attach in attachments or []:
- data_attach = {
- 'name': str(attach),
- 'datas': binascii.b2a_base64(str(attachments[attach])),
- 'datas_fname': str(attach),
- 'description': 'Mail attachment',
- 'res_model': self.model,
- 'res_id': id
- }
- self.rpc('ir.attachment', 'create', data_attach)
-
- self.create_message(id, msg['From'], msg['To'], 'Send', message['body'])
-
- return id
-
- def create_message(self, oid, email_from, email_to, name, body):
- """
- This functions creates a message in the thread
-
- > create_message(id, msg['From'], msg['To'], 'Send', message['body'])
- """
- values = {
- 'thread_id' : self.rpc(self.model, 'read', [oid], ['thread_id'])[0]['thread_id'][0],
- 'model_id' : self.rpc('ir.model', 'search', [('name', '=', self.model)])[0],
- 'res_id' : oid,
- 'date' : time.strftime('%Y-%m-%d %H:%M:%S'),
- 'description' : body,
- 'email_from' : self._decode_header(email_from),
- 'email_to' : self._decode_header(email_to),
- 'name' : name,
- 'history' : True,
- 'user_id' : self.rpc.user_id,
- }
- return self.rpc('mailgate.message', 'create', values)
-
- def msg_send(self, msg, emails, priority=None):
- if not emails:
- return False
-
- msg['To'] = emails[0]
- if len(emails) > 1:
- msg['Cc'] = ','.join(emails[1:])
- msg['Reply-To'] = self.email
-
- if priority:
- msg['X-Priority'] = priorities.get(priority, '3 (Normal)')
-
- s = smtplib.SMTP()
- s.connect()
- s.sendmail(self.email, emails, msg.as_string())
- s.close()
- return True
-
- def msg_partner(self, msg, id):
- message = self.msg_body_get(msg)
- body = message['body']
- act = 'case_open'
- self.rpc(self.model, act, [id])
- attachments = message['attachment']
- for attach in attachments or []:
- data_attach = {
- 'name': str(attach),
- 'datas': binascii.b2a_base64(str(attachments[attach])),
- 'datas_fname': str(attach),
- 'description': 'Mail attachment',
- 'res_model': self.model,
- 'res_id': id
- }
- self.rpc('ir.attachment', 'create', data_attach)
-
- self.create_message(id, msg['From'], msg['To'], 'Send', message['body'])
- return id
-
- def msg_test(self, msg, case_str):
- if not case_str:
- return (False, False)
-
- case_id = int(case_str)
- emails = self.rpc(self.model, 'emails_get', [case_id])
- return (case_id, emails)
-
- def parse(self, msg):
- case_str = reference_re.search(msg.get('References', ''))
- if case_str:
- case_str = case_str.group(1)
- else:
- case_str = case_re.search(msg.get('Subject', ''))
- if case_str:
- case_str = case_str.group(1)
-
- logging.info("email: %s -> %s -- %s", msg['From'], self.email, msg['Subject'])
- (case_id, emails) = self.msg_test(msg, case_str)
- thread_id = None
- if case_id:
- values = self.rpc(self.model, 'read', [case_id], ['thread_id'])
- if values:
- thread_id = values[0]['thread_id'][0]
- emails = emails[str(thread_id)]
-
- user_email = filter(None, emails['user_email'])[0]
-
- if user_email and self.email_get(user_email) == self.email_get(self._decode_header(msg['From'])):
- self.msg_user(msg, case_id)
- else:
- self.msg_partner(msg, case_id)
- else:
- case_id, thread_id = self.msg_new(msg)
- subject = self._decode_header(msg['Subject'])
- msg['Subject'] = "[%s] %s" % (case_id, subject,)
- msg['Message-Id'] = "<%s-openerpcrm-%s@%s>" % (time.time(), case_id, socket.gethostname(),)
-
- logging.info(" case: %r", case_id)
- logging.info(" thread: %r", thread_id)
-
- values = self.rpc(self.model, 'emails_get', [case_id])
-
- emails = values[str(thread_id)]
-
- priority = emails.get('piority', [3])[0]
- em = emails['user_email'] + emails['email_from'] + emails['email_cc']
- emails = map(self.email_get, filter(None, em))
-
- mm = [self._decode_header(msg['From']), self._decode_header(msg['To'])]+self._decode_header(msg.get('Cc', '')).split(',')
- msg_mails = map(self.email_get, filter(None, mm))
-
- emails = filter(lambda m: m and m not in msg_mails, emails)
+ def parse(self, message):
try:
- self.msg_send(msg, emails, priority)
- except:
- if self.email_default:
- a = self._decode_header(msg['Subject'])
- msg['Subject'] = '[OpenERP-CaseError] ' + a
- self.msg_send(msg, self.email_default.split(','))
- return case_id, thread_id, emails
+ res_id = self.rpc('email.server.tools', 'process_email', self.model, message)
+ except Exception, e:
+ logger = logging.getLogger('mail-gateway')
+ logger.warning('Failed to process incoming email. Source of the failed mail is available at debug level.', exc_info=True)
+ logger.debug('Source of the mail that failed to parse:', message)
+ res_id = False
if __name__ == '__main__':
parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.0')
- group = optparse.OptionGroup(parser, "Note",
+ group = optparse.OptionGroup(parser, "Note",
"This program parse a mail from standard input and communicate "
"with the Open ERP server for case management in the CRM module.")
parser.add_option_group(group)
parser.add_option("-u", "--user", dest="userid", help="ID of the user in Open ERP", default=1, type='int')
parser.add_option("-p", "--password", dest="password", help="Password of the user in Open ERP", default='admin')
- parser.add_option("-e", "--email", dest="email", help="Email address used in the From field of outgoing messages")
parser.add_option("-o", "--model", dest="model", help="Name or ID of crm model", default="crm.lead")
parser.add_option("-m", "--default", dest="default", help="Default eMail in case of any trouble.", default=None)
parser.add_option("-d", "--dbname", dest="dbname", help="Database name (default: terp)", default='terp')
@@ -452,10 +76,10 @@ if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s %(message)s")
- parser = email_parser(options.userid, options.password, options.model, options.email, options.default, dbname=options.dbname, host=options.host, port=options.port)
+ parser = email_parser(options.userid, options.password, options.model, options.default, dbname=options.dbname, host=options.host, port=options.port)
- msg_txt = email.message_from_file(sys.stdin)
+ msg_txt = sys.stdin.read()
parser.parse(msg_txt)
-
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/marketing/__openerp__.py b/addons/marketing/__openerp__.py
index 6db46333985..e3890ffe8f6 100644
--- a/addons/marketing/__openerp__.py
+++ b/addons/marketing/__openerp__.py
@@ -30,9 +30,10 @@
'website': 'http://www.openerp.com',
'init_xml': [],
'update_xml': [
- 'marketing_view.xml',
- 'security/ir.model.access.csv'
- ],
+ 'security/marketing_security.xml',
+ 'security/ir.model.access.csv',
+ 'marketing_view.xml'
+ ],
'demo_xml': [],
'installable': True,
'active': False,
diff --git a/addons/marketing/marketing_view.xml b/addons/marketing/marketing_view.xml
index 64ea6111bd5..a3288fb471f 100644
--- a/addons/marketing/marketing_view.xml
+++ b/addons/marketing/marketing_view.xml
@@ -1,8 +1,9 @@
-
+
-
+
marketing.installer.view
diff --git a/addons/marketing/security/marketing_security.xml b/addons/marketing/security/marketing_security.xml
new file mode 100644
index 00000000000..232b3ecce79
--- /dev/null
+++ b/addons/marketing/security/marketing_security.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ Marketing / User
+
+
+
+
diff --git a/addons/marketing_campaign/__init__.py b/addons/marketing_campaign/__init__.py
index d37d8604380..23796d1baaf 100644
--- a/addons/marketing_campaign/__init__.py
+++ b/addons/marketing_campaign/__init__.py
@@ -20,6 +20,7 @@
##############################################################################
import marketing_campaign
+import res_partner
import report
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/marketing_campaign/__openerp__.py b/addons/marketing_campaign/__openerp__.py
index 8abbf9eb706..1044030df7e 100644
--- a/addons/marketing_campaign/__openerp__.py
+++ b/addons/marketing_campaign/__openerp__.py
@@ -24,20 +24,27 @@
"name" : "",
"version" : "1.1",
"depends" : ["marketing",
- "crm",
+ "crm",
"document",
"email_template"
],
- "author" : "Tiny",
+ "author" : "OpenERP SA",
"category": 'Generic Modules/Marketing',
"description": """
+Allows you to setup leads automation through marketing campaigns. The campaigns
+are dynamic and multi-channels. The process:
+* Design marketing campaigns that incluces mail templates, reports to print,
+ miscelleanous actions, etc.
+* Define segments that are selections of target people
+* Launch your campaign to automate communications.
""",
'website': 'http://www.openerp.com',
'init_xml': [],
'update_xml': [
'marketing_campaign_view.xml',
- 'marketing_campaign_data.xml',
- 'marketing_campaign_workflow.xml',
+ 'marketing_campaign_data.xml',
+ 'marketing_campaign_workflow.xml',
+ 'res_partner_view.xml',
'report/campaign_analysis_view.xml',
"security/marketing_campaign_security.xml",
"security/ir.model.access.csv"
diff --git a/addons/marketing_campaign/marketing_campaign.py b/addons/marketing_campaign/marketing_campaign.py
index feeaa074b6d..a9f898f3270 100644
--- a/addons/marketing_campaign/marketing_campaign.py
+++ b/addons/marketing_campaign/marketing_campaign.py
@@ -50,8 +50,8 @@ this campaign to be run"),
('manual', 'With Manual Confirmation'),
('active', 'Normal')],
'Mode', required=True, help= \
-"""Test - It creates and process all the workitems directly (without waiting for the delay on transitions) but do not send emails or produce reports.
-Test in Realtime - It creates and process all the workitems directly but do not send emails or produce reports.
+"""Test - It creates and process all the activities directly (without waiting for the delay on transitions) but do not send emails or produce reports.
+Test in Realtime - It creates and process all the activities directly but do not send emails or produce reports.
With Manual Confirmation - the campaigns runs normally, but the user has to validate all workitem manually.
Normal - the campaign runs normally and automatically sends all emails and reports"""),
'state': fields.selection([('draft', 'Draft'),
@@ -73,11 +73,19 @@ you required for the campaign"),
campaign = self.browse(cr, uid, ids[0])
if not campaign.activity_ids :
raise osv.except_osv("Error", "There is no activitity in the campaign")
- act_ids = [ act_id.id for act_id in campaign.activity_ids]
- act_ids = self.pool.get('marketing.campaign.activity').search(cr, uid,
- [('id', 'in', act_ids), ('start', '=', True)])
+ actvity_ids = [ act_id.id for act_id in campaign.activity_ids]
+ act_obj = self.pool.get('marketing.campaign.activity')
+ act_ids = act_obj.search(cr, uid, [('id', 'in', actvity_ids),
+ ('start', '=', True)])
if not act_ids :
raise osv.except_osv("Error", "There is no starting activitity in the campaign")
+ act_ids = act_obj.search(cr, uid, [('id', 'in', actvity_ids),
+ ('type', '=', 'email')])
+ for activity in act_obj.browse(cr, uid, act_ids):
+ if not activity.email_template_id.enforce_from_account :
+ raise osv.except_osv("Error", "Campaign cannot be start : Email Account is missing in email activity")
+ if activity.email_template_id.enforce_from_account.state != 'approved' :
+ raise osv.except_osv("Error", "Campaign cannot be start : Email Account is not approved for email activity")
self.write(cr, uid, ids, {'state': 'running'})
return True
@@ -239,7 +247,7 @@ class marketing_campaign_activity(osv.osv):
def __init__(self, *args):
self._actions = {'paper' : self.process_wi_report,
'email' : self.process_wi_email,
- 'server_action' : self.process_wi_action,
+ 'action' : self.process_wi_action,
}
return super(marketing_campaign_activity, self).__init__(*args)
@@ -273,13 +281,17 @@ class marketing_campaign_activity(osv.osv):
return True
def process_wi_email(self, cr, uid, activity, workitem, context=None):
- return self.pool.get('email.template').generate_mail(cr, uid, activity.email_template_id.id, [workitem.res_id], context=context)
+ return self.pool.get('email.template').generate_mail(cr, uid,
+ activity.email_template_id.id,
+ [workitem.res_id], context=context)
def process_wi_action(self, cr, uid, activity, workitem, context={}):
context = {}
server_obj = self.pool.get('ir.actions.server')
- server_obj.run(cr, uid, [activity.server_action_id.id], context)
- return True
+ context['active_id'] = workitem.res_id
+ res = server_obj.run(cr, uid, [activity.server_action_id.id], context)
+ #server action return False if the action is perfomed except client_action,other and python code
+ return res==False and True or res
def process(self, cr, uid, act_id, wi_id, context={}):
activity = self.browse(cr, uid, act_id)
@@ -339,7 +351,7 @@ class marketing_campaign_workitem(osv.osv):
type='many2one', relation='marketing.campaign', string='Campaign', readonly=True),
'object_id': fields.related('segment_id', 'campaign_id', 'object_id',
type='many2one', relation='ir.model', string='Object', select=1),
- 'res_id': fields.integer('Resource ID', select=1),
+ 'res_id': fields.integer('Resource ID', select=1, readonly=1),
'res_name': fields.function(_res_name_get, method=True, string='Resource Name', type="char", size=64),
'date': fields.datetime('Execution Date'),
'partner_id': fields.many2one('res.partner', 'Partner', select=1),
@@ -408,7 +420,7 @@ class marketing_campaign_workitem(osv.osv):
else:
vals = {'state': 'exception'}
if type(result) == type({}) and 'error_msg' in result:
- vals['error_msg'] = result['error_msg']
+ vals['error_msg'] = result['error_msg']
self.write(cr, uid, wi.id, vals)
else:
self.write(cr, uid, wi.id, {'state': 'cancelled'})
diff --git a/addons/marketing_campaign/marketing_campaign_data.xml b/addons/marketing_campaign/marketing_campaign_data.xml
index 81402dd73c2..42ed4d12118 100644
--- a/addons/marketing_campaign/marketing_campaign_data.xml
+++ b/addons/marketing_campaign/marketing_campaign_data.xml
@@ -5,7 +5,7 @@
- Check Workitem
+ Check Marketing Campaign Activities1hours-1
diff --git a/addons/marketing_campaign/marketing_campaign_view.xml b/addons/marketing_campaign/marketing_campaign_view.xml
index f8dfc003369..d7d5cfe22d4 100644
--- a/addons/marketing_campaign/marketing_campaign_view.xml
+++ b/addons/marketing_campaign/marketing_campaign_view.xml
@@ -2,6 +2,8 @@
+
+
+
True
@@ -39,7 +39,7 @@
state_cancel_set()
-
+
@@ -66,7 +66,7 @@
True
-
+
True
@@ -95,7 +95,7 @@
state_cancel_set()
-
+
diff --git a/addons/event/wizard/event_registration.py b/addons/marketing_campaign/res_partner.py
similarity index 54%
rename from addons/event/wizard/event_registration.py
rename to addons/marketing_campaign/res_partner.py
index 4803d118610..2ec92522d6a 100644
--- a/addons/event/wizard/event_registration.py
+++ b/addons/marketing_campaign/res_partner.py
@@ -19,32 +19,19 @@
#
##############################################################################
-from osv import fields, osv
+from osv import fields,osv
-class event_registration_list(osv.osv_memory):
- """ List Event Registration """
- _name = "event.registration.list"
- _description = "List Event Registrations"
+class res_partner(osv.osv):
+ """ Inherits partner and adds CRM information in the partner form """
+ _inherit = 'res.partner'
- def open_registration(self, cr, uid, ids, context={}):
- if not context.get('active_id', None):
- return {
- 'name': 'Event Registrations',
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'event.registration',
- 'type': 'ir.actions.act_window'
- }
+ _columns = {
+ 'workitem_ids': fields.one2many('marketing.campaign.workitem', 'partner_id',\
+ 'Workitems', readonly=True),
- return {
- 'domain': [('section_id', '=', context['active_id'])],
- 'name': 'Event Registrations',
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'event.registration',
- 'type': 'ir.actions.act_window'
- }
+ }
+
+res_partner()
-event_registration_list()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/marketing_campaign/res_partner_view.xml b/addons/marketing_campaign/res_partner_view.xml
new file mode 100644
index 00000000000..a035a4ea5f0
--- /dev/null
+++ b/addons/marketing_campaign/res_partner_view.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ res.partner.workitem.info.inherit
+ res.partner
+ form
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/marketing_campaign/security/ir.model.access.csv b/addons/marketing_campaign/security/ir.model.access.csv
index dfafc2cd8a5..43a24d9e5eb 100644
--- a/addons/marketing_campaign/security/ir.model.access.csv
+++ b/addons/marketing_campaign/security/ir.model.access.csv
@@ -5,3 +5,4 @@
"access_marketing_campaign_workitem_campaignadmin","marketing.campaign.workitem","model_marketing_campaign_workitem","marketing_campaign.res_groups_marketing_campaign",1,1,1,1
"access_marketing_campaign_transition_campaignadmin","marketing.campaign.transition","model_marketing_campaign_transition","marketing_campaign.res_groups_marketing_campaign",1,1,1,1
"access_marketing_campaign_analysis_campaignadmin","campaign.analysis","model_campaign_analysis","marketing_campaign.res_groups_marketing_campaign",1,0,0,0
+"access_marketing_campaign_workitem_all","marketing.campaign.workitem","model_marketing_campaign_workitem","base.group_user",1,0,0,0
diff --git a/addons/membership/__init__.py b/addons/membership/__init__.py
index 4ae17c80e71..7e377bcdace 100644
--- a/addons/membership/__init__.py
+++ b/addons/membership/__init__.py
@@ -21,5 +21,6 @@
import membership
import wizard
+import report
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/membership/__openerp__.py b/addons/membership/__openerp__.py
index 49297bc010d..1de648ff8e8 100644
--- a/addons/membership/__openerp__.py
+++ b/addons/membership/__openerp__.py
@@ -43,10 +43,12 @@ invoice and send propositions for membership renewal.
'security/ir.model.access.csv',
'wizard/membership_invoice_view.xml',
'membership_view.xml',
+ 'report/report_membership_view.xml',
'wizard/membership_unpaid_invoice_view.xml',
'process/membership_process.xml'
],
'demo_xml': ['membership_demo.xml'],
+ 'test': ['test/test_membership.yml'],
'installable': True,
'active': False,
'certificate': '0042907796381',
diff --git a/addons/membership/membership.py b/addons/membership/membership.py
index 1ef69c142c6..a772661bf0c 100644
--- a/addons/membership/membership.py
+++ b/addons/membership/membership.py
@@ -201,10 +201,10 @@ class membership_line(osv.osv):
_name = 'membership.membership_line'
_columns = {
'partner': fields.many2one('res.partner', 'Partner', ondelete='cascade', select=1),
- 'date_from': fields.date('From'),
- 'date_to': fields.date('To'),
+ 'date_from': fields.date('From', readonly=True),
+ 'date_to': fields.date('To', readonly=True),
'date_cancel' : fields.date('Cancel date'),
- 'account_invoice_line': fields.many2one('account.invoice.line', 'Account Invoice line'),
+ 'account_invoice_line': fields.many2one('account.invoice.line', 'Account Invoice line', readonly=True),
'state': fields.function(_state, method=True, string='State', type='selection', selection=STATE),
}
_rec_name = 'partner'
@@ -221,6 +221,7 @@ class Partner(osv.osv):
_inherit = 'res.partner'
def _get_partner_id(self, cr, uid, ids, context=None):
+
data_inv = self.pool.get('membership.membership_line').browse(cr, uid, ids, context)
list_partner = []
for data in data_inv:
@@ -298,55 +299,47 @@ class Partner(osv.osv):
res_state = self._membership_state(cr, uid, [partner_data.associate_member.id], name, args, context)
res[id] = res_state[partner_data.associate_member.id]
return res
-
- def _membership_start(self, cr, uid, ids, name, args, context=None):
- '''Return the start date of membership'''
+
+ def _membership_date(self, cr, uid, ids, name, args, context=None):
+
+ '''Return date of membership'''
+
+ name = name[0]
res = {}
member_line_obj = self.pool.get('membership.membership_line')
+
for partner in self.browse(cr, uid, ids):
+
if partner.associate_member:
- partner_id = partner.associate_member.id
+ partner_id = partner.associate_member.id
else:
- partner_id = partner.id
- line_id = member_line_obj.search(cr, uid, [('partner', '=', partner_id)],
- limit=1, order='date_from')
- if line_id:
- res[partner.id] = member_line_obj.read(cr, uid, line_id[0],
- ['date_from'])['date_from']
- else:
- res[partner.id] = False
- return res
-
- def _membership_stop(self, cr, uid, ids, name, args, context=None):
- '''Return the stop date of membership'''
- res = {}
- member_line_obj = self.pool.get('membership.membership_line')
- for partner in self.browse(cr, uid, ids):
- cr.execute('select membership_state from res_partner where id=%s', (partner.id,))
- data_state = cr.fetchall()
- if partner.associate_member:
- partner_id = partner.associate_member.id
- else:
- partner_id = partner.id
- line_id = member_line_obj.search(cr, uid, [('partner', '=', partner_id)],
- limit=1, order='date_to desc')
- if line_id:
- res[partner.id] = member_line_obj.read(cr, uid, line_id[0],
- ['date_to'])['date_to']
- else:
- res[partner.id] = False
- return res
-
- def _membership_cancel(self, cr, uid, ids, name, args, context=None):
- '''Return the cancel date of membership'''
- res = {}
- member_line_obj = self.pool.get('membership.membership_line')
- for partner in self.browse(cr, uid, ids, context=context):
- res[partner.id] = False
- if partner.membership_state == 'canceled':
- line_id = member_line_obj.search(cr, uid, [('partner', '=', partner.id)],limit=1, order='date_cancel')
+ partner_id = partner.id
+
+ res[partner.id]={
+ 'membership_start': False,
+ 'membership_stop': False,
+ 'membership_cancel': False
+ }
+
+ if name == 'membership_start':
+ line_id = member_line_obj.search(cr, uid, [('partner', '=', partner_id)],
+ limit=1, order='date_from')
if line_id:
- res[partner.id] = member_line_obj.read(cr, uid, line_id[0],['date_cancel'])['date_cancel']
+ res[partner.id]['membership_start'] = member_line_obj.read(cr, uid, line_id[0],
+ ['date_from'])['date_from']
+
+ if name == 'membership_stop':
+ line_id1 = member_line_obj.search(cr, uid, [('partner', '=', partner_id)],
+ limit=1, order='date_to desc')
+ if line_id1:
+ res[partner.id]['membership_stop'] = member_line_obj.read(cr, uid, line_id1[0],
+ ['date_to'])['date_to']
+ if name == 'membership_cancel':
+ if partner.membership_state == 'canceled':
+ line_id2 = member_line_obj.search(cr, uid, [('partner', '=', partner.id)],limit=1, order='date_cancel')
+ if line_id2:
+ res[partner.id]['membership_cancel'] = member_line_obj.read(cr, uid, line_id2[0],['date_cancel'])['date_cancel']
+
return res
def _get_partners(self, cr, uid, ids, context={}):
@@ -377,17 +370,17 @@ class Partner(osv.osv):
}
),
'membership_start': fields.function(
- _membership_start, method=True,
+ _membership_date, method=True, multi='membeship_start',
string = 'Start membership date', type = 'date',
store = {
'account.invoice':(_get_invoice_partner,['state'], 10),
- 'membership.membership_line':(_get_partner_id,['state'], 10),
+ 'membership.membership_line':(_get_partner_id,['state'], 10, ),
'res.partner':(lambda self,cr,uid,ids,c={}:ids, ['free_member'], 10)
}
),
'membership_stop': fields.function(
- _membership_stop, method = True,
- string = 'Stop membership date', type = 'date',
+ _membership_date, method = True,
+ string = 'Stop membership date', type = 'date', multi='membership_stop',
store = {
'account.invoice':(_get_invoice_partner,['state'], 10),
'membership.membership_line':(_get_partner_id,['state'], 10),
@@ -396,8 +389,8 @@ class Partner(osv.osv):
),
'membership_cancel': fields.function(
- _membership_cancel, method = True,
- string = 'Cancel membership date', type='date',
+ _membership_date, method = True,
+ string = 'Cancel membership date', type='date', multi='membership_cancel',
store = {
'account.invoice':(_get_invoice_partner,['state'], 11),
'membership.membership_line':(_get_partner_id,['state'], 10),
@@ -491,160 +484,6 @@ class Invoice(osv.osv):
return super(Invoice, self).action_cancel(cr, uid, ids, context)
Invoice()
-
-class ReportPartnerMemberYear(osv.osv):
- '''Membership by Years'''
-
- _name = 'report.partner_member.year'
- _description = __doc__
- _auto = False
- _rec_name = 'year'
- _columns = {
- 'year': fields.char('Year', size='4', readonly=True, select=1),
- 'canceled_number': fields.integer('Canceled', readonly=True),
- 'waiting_number': fields.integer('Waiting', readonly=True),
- 'invoiced_number': fields.integer('Invoiced', readonly=True),
- 'paid_number': fields.integer('Paid', readonly=True),
- 'canceled_amount': fields.float('Canceled', digits=(16, 2), readonly=True),
- 'waiting_amount': fields.float('Waiting', digits=(16, 2), readonly=True),
- 'invoiced_amount': fields.float('Invoiced', digits=(16, 2), readonly=True),
- 'paid_amount': fields.float('Paid', digits=(16, 2), readonly=True),
- 'currency': fields.many2one('res.currency', 'Currency', readonly=True,
- select=2),
- }
-
- def init(self, cr):
- '''Create the view'''
- cr.execute("""
- CREATE OR REPLACE VIEW report_partner_member_year AS (
- SELECT
- MIN(id) AS id,
- COUNT(ncanceled) as canceled_number,
- COUNT(npaid) as paid_number,
- COUNT(ninvoiced) as invoiced_number,
- COUNT(nwaiting) as waiting_number,
- SUM(acanceled) as canceled_amount,
- SUM(apaid) as paid_amount,
- SUM(ainvoiced) as invoiced_amount,
- SUM(awaiting) as waiting_amount,
- year,
- currency
- FROM (SELECT
- CASE WHEN ai.state = 'cancel' THEN ml.id END AS ncanceled,
- CASE WHEN ai.state = 'paid' THEN ml.id END AS npaid,
- CASE WHEN ai.state = 'open' THEN ml.id END AS ninvoiced,
- CASE WHEN (ai.state = 'draft' OR ai.state = 'proforma')
- THEN ml.id END AS nwaiting,
- CASE WHEN ai.state = 'cancel'
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS acanceled,
- CASE WHEN ai.state = 'paid'
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS apaid,
- CASE WHEN ai.state = 'open'
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS ainvoiced,
- CASE WHEN (ai.state = 'draft' OR ai.state = 'proforma')
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS awaiting,
- TO_CHAR(ml.date_from, 'YYYY') AS year,
- ai.currency_id AS currency,
- MIN(ml.id) AS id
- FROM membership_membership_line ml
- JOIN (account_invoice_line ail
- LEFT JOIN account_invoice ai
- ON (ail.invoice_id = ai.id))
- ON (ml.account_invoice_line = ail.id)
- JOIN res_partner p
- ON (ml.partner = p.id)
- GROUP BY TO_CHAR(ml.date_from, 'YYYY'), ai.state,
- ai.currency_id, ml.id) AS foo
- GROUP BY year, currency)
- """)
-
-ReportPartnerMemberYear()
-
-
-class ReportPartnerMemberYearNew(osv.osv):
- '''New Membership by Years'''
-
- _name = 'report.partner_member.year_new'
- _description = __doc__
- _auto = False
- _rec_name = 'year'
- _columns = {
- 'year': fields.char('Year', size='4', readonly=True, select=1),
- 'canceled_number': fields.integer('Canceled', readonly=True),
- 'waiting_number': fields.integer('Waiting', readonly=True),
- 'invoiced_number': fields.integer('Invoiced', readonly=True),
- 'paid_number': fields.integer('Paid', readonly=True),
- 'canceled_amount': fields.float('Canceled', digits=(16, 2), readonly=True),
- 'waiting_amount': fields.float('Waiting', digits=(16, 2), readonly=True),
- 'invoiced_amount': fields.float('Invoiced', digits=(16, 2), readonly=True),
- 'paid_amount': fields.float('Paid', digits=(16, 2), readonly=True),
- 'currency': fields.many2one('res.currency', 'Currency', readonly=True,
- select=2),
- }
-
- def init(self, cursor):
- '''Create the view'''
- cursor.execute("""
- CREATE OR REPLACE VIEW report_partner_member_year_new AS (
- SELECT
- MIN(id) AS id,
- COUNT(ncanceled) AS canceled_number,
- COUNT(npaid) AS paid_number,
- COUNT(ninvoiced) AS invoiced_number,
- COUNT(nwaiting) AS waiting_number,
- SUM(acanceled) AS canceled_amount,
- SUM(apaid) AS paid_amount,
- SUM(ainvoiced) AS invoiced_amount,
- SUM(awaiting) AS waiting_amount,
- year,
- currency
- FROM (SELECT
- CASE WHEN ai.state = 'cancel' THEN ml2.id END AS ncanceled,
- CASE WHEN ai.state = 'paid' THEN ml2.id END AS npaid,
- CASE WHEN ai.state = 'open' THEN ml2.id END AS ninvoiced,
- CASE WHEN (ai.state = 'draft' OR ai.state = 'proforma')
- THEN ml2.id END AS nwaiting,
- CASE WHEN ai.state = 'cancel'
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS acanceled,
- CASE WHEN ai.state = 'paid'
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS apaid,
- CASE WHEN ai.state = 'open'
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS ainvoiced,
- CASE WHEN (ai.state = 'draft' OR ai.state = 'proforma')
- THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
- ELSE 0 END AS awaiting,
- TO_CHAR(ml2.date_from, 'YYYY') AS year,
- ai.currency_id AS currency,
- MIN(ml2.id) AS id
- FROM (SELECT
- partner AS id,
- MIN(date_from) AS date_from
- FROM membership_membership_line
- GROUP BY partner
- ) AS ml1
- JOIN membership_membership_line ml2
- JOIN (account_invoice_line ail
- LEFT JOIN account_invoice ai
- ON (ail.invoice_id = ai.id))
- ON (ml2.account_invoice_line = ail.id)
- ON (ml1.id = ml2.partner AND ml1.date_from = ml2.date_from)
- JOIN res_partner p
- ON (ml2.partner = p.id)
- GROUP BY TO_CHAR(ml2.date_from, 'YYYY'), ai.state,
- ai.currency_id, ml2.id) AS foo
- GROUP BY year, currency
- )
- """)
-
-ReportPartnerMemberYearNew()
-
class account_invoice_line(osv.osv):
_inherit='account.invoice.line'
@@ -703,4 +542,4 @@ class account_invoice_line(osv.osv):
return result
account_invoice_line()
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/membership/membership_view.xml b/addons/membership/membership_view.xml
index 142e27c1337..15d9ec146d9 100644
--- a/addons/membership/membership_view.xml
+++ b/addons/membership/membership_view.xml
@@ -39,7 +39,8 @@
-
+
+
@@ -117,28 +118,32 @@
search
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
res.partner.select2res.partnersearch
-
+
+
-
+
+
+
-
-
@@ -149,6 +154,7 @@
res.partner[('membership_state','<>','none'),('membership_state','<>','canceled'),('membership_state','<>','old'),('membership_state','<>','waiting')]
+ {"search_default_old": 1}
@@ -229,7 +235,6 @@
-
@@ -238,211 +243,6 @@
sequence="2"
id="menu_reporting"/>
-
-
-
-
- report.partner_member.year.tree
- report.partner_member.year
- tree
-
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year.tree
- report.partner_member.year
- tree
-
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year.graph1
- report.partner_member.year
- graph
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year.graph2
- report.partner_member.year
- graph
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year
- form
-
-
-
-
- tree
-
-
-
-
-
-
-
- tree
-
-
-
-
-
-
- graph
-
-
-
-
-
-
- graph
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year_new.tree
- report.partner_member.year_new
- tree
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year_new.tree
- report.partner_member.year_new
- tree
-
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year_new.graph1
- report.partner_member.year_new
- graph
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year_new.graph2
- report.partner_member.year_new
- graph
-
-
-
-
-
-
-
-
-
-
-
-
- report.partner_member.year_new
- form
-
-
-
-
- tree
-
-
-
-
-
-
- tree
-
-
-
-
-
-
- graph
-
-
-
-
-
-
- graph
-
-
-
-
-
diff --git a/addons/account_report_india/wizard/__init__.py b/addons/membership/report/__init__.py
old mode 100755
new mode 100644
similarity index 87%
rename from addons/account_report_india/wizard/__init__.py
rename to addons/membership/report/__init__.py
index 2a870d96fad..dd247c52f3a
--- a/addons/account_report_india/wizard/__init__.py
+++ b/addons/membership/report/__init__.py
@@ -1,8 +1,8 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
+# Copyright (C) 2004-2010 Tiny SPRL ().
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,5 +19,4 @@
#
##############################################################################
-import account_bs_report
-import account_pl_report
\ No newline at end of file
+import report_membership
diff --git a/addons/membership/report/report_membership.py b/addons/membership/report/report_membership.py
new file mode 100644
index 00000000000..cd0142f5604
--- /dev/null
+++ b/addons/membership/report/report_membership.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+from osv import fields, osv
+import tools
+
+
+class report_membership(osv.osv):
+ '''Membership by Years'''
+
+ _name = 'report.membership'
+ _description = __doc__
+ _auto = False
+ _rec_name = 'year'
+ _columns = {
+ 'year': fields.char('Year', size=4, readonly=True, select=1),
+ 'month':fields.selection([('01', 'January'), ('02', 'February'), \
+ ('03', 'March'), ('04', 'April'),\
+ ('05', 'May'), ('06', 'June'), \
+ ('07', 'July'), ('08', 'August'),\
+ ('09', 'September'), ('10', 'October'),\
+ ('11', 'November'), ('12', 'December')], 'Month', readonly=True),
+ 'create_date': fields.datetime('Create Date', readonly=True),
+ 'canceled_number': fields.integer('Canceled', readonly=True),
+ 'waiting_number': fields.integer('Waiting', readonly=True),
+ 'invoiced_number': fields.integer('Invoiced', readonly=True),
+ 'paid_number': fields.integer('Paid', readonly=True),
+ 'canceled_amount': fields.float('Canceled', digits=(16, 2), readonly=True),
+ 'waiting_amount': fields.float('Waiting', digits=(16, 2), readonly=True),
+ 'invoiced_amount': fields.float('Invoiced', digits=(16, 2), readonly=True),
+ 'paid_amount': fields.float('Paid', digits=(16, 2), readonly=True),
+ 'currency': fields.many2one('res.currency', 'Currency', readonly=True,
+ select=2),
+
+ 'state':fields.selection([('draft', 'Non Member'),
+ ('cancel', 'Cancelled Member'),
+ ('done', 'Old Member'),
+ ('open', 'Invoiced Member'),
+ ('free', 'Free Member'), ('paid', 'Paid Member')], 'State'),
+ 'partner_id': fields.many2one('res.partner', 'Members', readonly=True, select=3)
+
+
+}
+
+ def init(self, cr):
+ '''Create the view'''
+ cr.execute("""
+ CREATE OR REPLACE VIEW report_membership AS (
+ SELECT
+ MIN(id) as id,
+ COUNT(ncanceled) as canceled_number,
+ COUNT(npaid) as paid_number,
+ COUNT(ninvoiced) as invoiced_number,
+ COUNT(nwaiting) as waiting_number,
+ SUM(acanceled) as canceled_amount,
+ SUM(apaid) as paid_amount,
+ SUM(ainvoiced) as invoiced_amount,
+ SUM(awaiting) as waiting_amount,
+ year,
+ month,
+ create_date,
+ partner_id,
+ state,
+ currency
+
+ FROM (SELECT
+ CASE WHEN ai.state = 'cancel' THEN ml.id END AS ncanceled,
+ CASE WHEN ai.state = 'paid' THEN ml.id END AS npaid,
+ CASE WHEN ai.state = 'open' THEN ml.id END AS ninvoiced,
+ CASE WHEN (ai.state = 'draft' OR ai.state = 'proforma')
+ THEN ml.id END AS nwaiting,
+ CASE WHEN ai.state = 'cancel'
+ THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
+ ELSE 0 END AS acanceled,
+ CASE WHEN ai.state = 'paid'
+ THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
+ ELSE 0 END AS apaid,
+ CASE WHEN ai.state = 'open'
+ THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
+ ELSE 0 END AS ainvoiced,
+ CASE WHEN (ai.state = 'draft' OR ai.state = 'proforma')
+ THEN SUM(ail.price_unit * ail.quantity * (1 - ail.discount / 100))
+ ELSE 0 END AS awaiting,
+ TO_CHAR(ml.date_from, 'YYYY') AS year,
+ TO_CHAR(ml.date_from, 'MM')as month,
+ TO_CHAR(ml.date_from, 'YYYY-MM-DD') as create_date,
+ ai.partner_id AS partner_id,
+ ai.currency_id AS currency,
+ ai.state as state,
+ MIN(ml.id) AS id
+ FROM membership_membership_line ml
+ JOIN (account_invoice_line ail
+ LEFT JOIN account_invoice ai
+ ON (ail.invoice_id = ai.id))
+ ON (ml.account_invoice_line = ail.id)
+ JOIN res_partner p
+ ON (ml.partner = p.id)
+ GROUP BY TO_CHAR(ml.date_from, 'YYYY'), TO_CHAR(ml.date_from, 'MM'), TO_CHAR(ml.date_from, 'YYYY-MM-DD'), ai.state, ai.partner_id,
+ ai.currency_id, ml.id) AS foo
+ GROUP BY year, month, create_date, currency, partner_id, state)
+ """)
+
+report_membership()
+
+#
\ No newline at end of file
diff --git a/addons/membership/report/report_membership_view.xml b/addons/membership/report/report_membership_view.xml
new file mode 100644
index 00000000000..76c0dff4404
--- /dev/null
+++ b/addons/membership/report/report_membership_view.xml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+ report.membership.tree
+ report.membership
+ tree
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ report.membership.search
+ report.membership
+ search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ report.membership.graph1
+ report.membership
+ graph
+
+
+
+
+
+
+
+
+
+
+
+
+ report.membership
+ form
+
+ {"search_default_member":1}
+
+
+
+
+ tree
+
+
+
+
+
+
+
+ graph
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/membership/security/ir.model.access.csv b/addons/membership/security/ir.model.access.csv
index cb722db567a..9f2d1681b0f 100644
--- a/addons/membership/security/ir.model.access.csv
+++ b/addons/membership/security/ir.model.access.csv
@@ -1,7 +1,6 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_membership_membership_line_partner_manager","membership.membership_line partner_manager","model_membership_membership_line","base.group_partner_manager",1,1,1,1
"access_membership_membership_line","membership.membership_line","model_membership_membership_line",,1,0,0,0
-"access_report_partner_member_year","report.partner_member.year","model_report_partner_member_year","base.group_partner_manager",1,0,0,0
-"access_report_partner_member_year_new","report.partner_member.year_new","model_report_partner_member_year_new","base.group_partner_manager",1,0,0,0
+"access_report_membership","report.membership","model_report_membership","base.group_partner_manager",1,0,0,0
"access_membership_invoice","membership.invoice","model_membership_invoice",,1,1,1,1
"access_membership_unpaid_invoice","membership.unpaid.invoice","model_membership_unpaid_invoice",,1,0,0,0
diff --git a/addons/membership/test/test_membership.yml b/addons/membership/test/test_membership.yml
new file mode 100644
index 00000000000..5a67ea7f476
--- /dev/null
+++ b/addons/membership/test/test_membership.yml
@@ -0,0 +1,115 @@
+- |
+ In Order to test the Membership in OpenERP, which allows us to manage all operations for managing memberships.
+- |
+ We have to create "Membership Products" to make it available for partner or customer to make membership with it.
+ select product type to "service" type and membership field is ticked to visible this product while creating membership for the partner.
+-
+ !record {model: product.product, id: product_product_membershipproduct0}:
+ categ_id: product.cat1
+ membership: 1
+ membership_date_from: '2009-06-01'
+ membership_date_to: '2010-06-01'
+ name: Membership Products
+ type: service
+ list_price: 80.00
+
+- |
+ I create new member "Mark Johnson" and I provide an address to this
+ new customer, as well as an email "info@mycustomer.com".
+-
+ !record {model: res.partner, id: res_partner_markjohnson0}:
+ address:
+ - city: paris
+ country_id: base.fr
+ name: Arthur Grosbonnet
+ street: 1 rue Rockfeller
+ title: M.
+ type: default
+ zip: '75016'
+ credit_limit: 0.0
+ membership_amount: 0.0
+ name: Mark Johnson
+ property_account_payable: account.a_pay
+ property_account_receivable: account.a_recv
+
+- |
+ I check that "Current membership state" is set to "Non Member".
+-
+ !assert {model: res.partner, id: res_partner_markjohnson0}:
+ - membership_state == 'none'
+- |
+ I can make it a Free member by selecting the "Free member" check box.
+-
+ !record {model: res.partner, id: membership.res_partner_markjohnson0}:
+ free_member: 1
+- |
+ Now, I create Membership Invoices using wizard available on partner and Select Membership Product.
+-
+ !record {model: membership.invoice, id: membership_invoice_0}:
+ product_id: membership.product_product_membershipproduct0
+- |
+ I check that address is defined or not for this Member.
+-
+ !python {model: membership.invoice}: |
+ partner_ids = [ref('res_partner_markjohnson0')]
+ addre_obj = self.pool.get('res.partner.address')
+ ids = addre_obj.search(cr, uid, [('partner_id', '=', partner_ids)])
+
+ addre_id = addre_obj.browse(cr, uid, ids)[0]
+ assert addre_id.partner_id
+ assert addre_id.id
+ assert addre_id.type
+
+- |
+ I click on "Confirm" button of this wizard.
+-
+ !python {model: membership.invoice}: |
+ self.membership_invoice(cr, uid, [ref("membership_invoice_0")], {"active_ids": [ref("membership.res_partner_markjohnson0")]})
+
+- |
+ I check that Invoice is created for this members.
+-
+ !python {model: res.partner}: |
+ invoice_obj = self.pool.get('account.invoice')
+ partner_obj = self.pool.get('res.partner')
+ product_obj = self.pool.get('product.product')
+ invoice_line_obj = self.pool.get(('account.invoice.line'))
+
+ partner_id = self.browse(cr, uid, [ref('res_partner_markjohnson0')])[0]
+ ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner_id.id), ('account_id', '=', partner_id.property_account_receivable.id)])
+ invoice_id = invoice_obj.browse(cr, uid, ids)[0]
+
+ product = product_obj.browse(cr, uid, [ref('product_product_membershipproduct0')], context=context)[0]
+ line_ids = invoice_line_obj.search(cr, uid, [('product_id', '=', product.id), ('invoice_id', '=', invoice_id.id)])
+ line_id = invoice_line_obj.browse(cr, uid, line_ids)[0]
+
+ assert line_id.product_id.id == product.id
+ assert invoice_id.partner_id.id == partner_id.id
+
+- |
+ I check that the "Current membership state" will remain same untill opening the invoice.
+-
+ !assert {model: res.partner, id: res_partner_markjohnson0}:
+ - membership_state == 'free'
+
+- |
+ "Current membership state" of any member depends on the state of invoice.
+ So, I check that invoice is in draft state then the "membership state" of a member is "Waiting member".
+-
+ !python {model: membership.membership_line}: |
+ partner_id = self.pool.get('res.partner').browse(cr, uid, [ref('res_partner_markjohnson0')])[0]
+ ids = self.search(cr, uid, [('partner', '=', partner_id.id)])
+ current_id = self.browse(cr, uid, ids)[0]
+
+ partner_obj = self.pool.get('res.partner')
+ inv_obj = self.pool.get('account.invoice')
+
+ ids = inv_obj.search(cr, uid, [('partner_id', '=', partner_id.id), ('account_id', '=', partner_id.property_account_receivable.id)])
+ inv_id = inv_obj.browse(cr, uid, ids)[0]
+ if inv_id.state == 'draft':
+ assert current_id == 'waiting'
+- |
+ When the invoice is in open state it become Invoiced Member, When the invoice is in paid state the same "Current membership state" changed to Paid Member.
+ Now, If we cancel the invoice "Current membership state" changed to Cancel Member.
+
+
\ No newline at end of file
diff --git a/addons/membership/wizard/membership_invoice_view.xml b/addons/membership/wizard/membership_invoice_view.xml
index c18c53d6679..858ac50425c 100644
--- a/addons/membership/wizard/membership_invoice_view.xml
+++ b/addons/membership/wizard/membership_invoice_view.xml
@@ -12,7 +12,7 @@
-
+
diff --git a/addons/membership/wizard/membership_unpaid_invoice.py b/addons/membership/wizard/membership_unpaid_invoice.py
index 1b9a6ac3464..f403e78c81d 100644
--- a/addons/membership/wizard/membership_unpaid_invoice.py
+++ b/addons/membership/wizard/membership_unpaid_invoice.py
@@ -29,7 +29,7 @@ class member_unpaid_invoice(osv.osv_memory):
'product': fields.many2one('product.product','Membership product', size=64,required=True, help='Select Membership product'),
}
- def _invoice_membership(self, cr, uid, ids, context):
+ def invoice_membership(self, cr, uid, ids, context):
model_obj = self.pool.get('ir.model.data')
partners = []
result = model_obj._get_id(cr, uid, 'base', 'view_res_partner_filter')
@@ -56,4 +56,4 @@ class member_unpaid_invoice(osv.osv_memory):
member_unpaid_invoice()
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/membership/wizard/membership_unpaid_invoice_view.xml b/addons/membership/wizard/membership_unpaid_invoice_view.xml
index 52825386cb7..6b57c49572b 100644
--- a/addons/membership/wizard/membership_unpaid_invoice_view.xml
+++ b/addons/membership/wizard/membership_unpaid_invoice_view.xml
@@ -12,8 +12,8 @@
-
-
+
+
diff --git a/addons/mrp/board_manufacturing_demo.xml b/addons/mrp/board_manufacturing_demo.xml
index 080467eb8b7..aea87558a1c 100644
--- a/addons/mrp/board_manufacturing_demo.xml
+++ b/addons/mrp/board_manufacturing_demo.xml
@@ -1,13 +1,13 @@
-
+
diff --git a/addons/mrp/i18n/zh_CN.po b/addons/mrp/i18n/zh_CN.po
index afa393000d3..98db38dddd9 100644
--- a/addons/mrp/i18n/zh_CN.po
+++ b/addons/mrp/i18n/zh_CN.po
@@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:57+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: mrp
diff --git a/addons/mrp_operations/i18n/es.po b/addons/mrp_operations/i18n/es.po
index c278fc52afd..e29983cadcb 100644
--- a/addons/mrp_operations/i18n/es.po
+++ b/addons/mrp_operations/i18n/es.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: mrp_operations
diff --git a/addons/olap/i18n/es.po b/addons/olap/i18n/es.po
index b7e1d5eeaea..6af368a67b2 100644
--- a/addons/olap/i18n/es.po
+++ b/addons/olap/i18n/es.po
@@ -15,7 +15,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: olap
diff --git a/addons/olap/i18n/et.po b/addons/olap/i18n/et.po
index ead8009afcc..77464b4f4f0 100644
--- a/addons/olap/i18n/et.po
+++ b/addons/olap/i18n/et.po
@@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2009-11-26 05:24+0000\n"
-"PO-Revision-Date: 2010-05-07 10:06+0000\n"
+"PO-Revision-Date: 2010-06-25 18:21+0000\n"
"Last-Translator: lyyser \n"
"Language-Team: Estonian \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-22 04:20+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: olap
@@ -192,7 +192,7 @@ msgstr ""
#: wizard_button:olap.query_builder,exec,exec:0
#: wizard_button:olap.query_builder,ok,exec:0
msgid "Execute"
-msgstr ""
+msgstr "Käivita"
#. module: olap
#: wizard_button:olap.application.configuration,configure,end:0
@@ -202,7 +202,7 @@ msgstr ""
#: wizard_button:olap.query.logs.clear,ok,end:0
#: view:olap.warehouse.wizard:0
msgid "Ok"
-msgstr ""
+msgstr "Ok"
#. module: olap
#: model:ir.ui.menu,name:olap.menu_bi_conf_known_application
@@ -213,7 +213,7 @@ msgstr ""
#: wizard_field:olap.query_builder,exec,level:0
#: wizard_field:olap.query_builder,ok,level:0
msgid "Level"
-msgstr ""
+msgstr "Tase"
#. module: olap
#: field:olap.level,column_id_name:0
@@ -237,7 +237,7 @@ msgstr ""
#. module: olap
#: field:olap.saved.query,name:0
msgid "Query Name"
-msgstr ""
+msgstr "Päringu nimi"
#. module: olap
#: wizard_field:olap.query_builder,exec,mdx_query:0
@@ -258,12 +258,12 @@ msgstr "Primaarvõti"
#. module: olap
#: model:ir.actions.act_window,name:olap.act_bi_auto_configure
msgid "Auto Configuration"
-msgstr ""
+msgstr "Automaatne seadistamine"
#. module: olap
#: field:olap.schema,note:0
msgid "Schema description"
-msgstr ""
+msgstr "Skeemi kirjeldus"
#. module: olap
#: model:ir.actions.act_window,name:olap.act_bi_load_db_wizard
diff --git a/addons/olap_crm/olap_crm.xml b/addons/olap_crm/olap_crm.xml
index 96dadb7d783..619e133e609 100644
--- a/addons/olap_crm/olap_crm.xml
+++ b/addons/olap_crm/olap_crm.xml
@@ -1,6 +1,6 @@
-
+
-
+
diff --git a/addons/project/i18n/es.po b/addons/project/i18n/es.po
index 175a17229bc..7f5b605cdf1 100644
--- a/addons/project/i18n/es.po
+++ b/addons/project/i18n/es.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:57+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: project
diff --git a/addons/project/project_mailgate.py b/addons/project/project_mailgate.py
index 93c9732c720..5409aa4e752 100644
--- a/addons/project/project_mailgate.py
+++ b/addons/project/project_mailgate.py
@@ -77,7 +77,7 @@ class project_tasks(osv.osv):
getattr(self,act)(cr, uid, [id])
return True
- def emails_get(self, cr, uid, ids, context={}):
+ def message_followers(self, cr, uid, ids, context={}):
res = []
if isinstance(ids, (str, int, long)):
select = [ids]
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index 86250622c5a..7b299cdcccc 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -1,7 +1,11 @@
-
+
+
diff --git a/addons/project/res_partner.py b/addons/project/res_partner.py
new file mode 100644
index 00000000000..f0297cf6a72
--- /dev/null
+++ b/addons/project/res_partner.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+from osv import fields,osv
+
+class res_partner(osv.osv):
+ """ Inherits partner and adds CRM information in the partner form """
+ _inherit = 'res.partner'
+ _columns = {
+ 'task_ids': fields.one2many('project.task', 'partner_id', 'Tasks'),
+ }
+res_partner()
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project/res_partner_view.xml b/addons/project/res_partner_view.xml
new file mode 100644
index 00000000000..4778c0f1017
--- /dev/null
+++ b/addons/project/res_partner_view.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+ res.partner.task.info.inherit
+ res.partner
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/project/security/ir.model.access.csv b/addons/project/security/ir.model.access.csv
index 502c8af0596..0c030e0c701 100644
--- a/addons/project/security/ir.model.access.csv
+++ b/addons/project/security/ir.model.access.csv
@@ -23,3 +23,5 @@
"access_partner_task manager","base.res.partner manager","base.model_res_partner","project.group_project_manager",1,0,0,0
"access_partner_address_task user","base.res.partner.address user","base.model_res_partner_address","project.group_project_user",1,0,0,0
"access_partner_address_task manager","base.res.partner.address manager","base.model_res_partner_address","project.group_project_manager",1,0,0,0
+"access_task_on_partner","project.task on partners","model_project_task","base.group_user",1,0,0,0
+"access_project_on_partner","project.project on partners","model_project_project","base.group_user",1,0,0,0
diff --git a/addons/project_gtd/i18n/zh_CN.po b/addons/project_gtd/i18n/zh_CN.po
index f25a51b156d..cc32edbe876 100644
--- a/addons/project_gtd/i18n/zh_CN.po
+++ b/addons/project_gtd/i18n/zh_CN.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-03-20 09:47+0000\n"
-"Last-Translator: Black Jack \n"
+"PO-Revision-Date: 2010-06-27 22:23+0000\n"
+"Last-Translator: Fan.Khiyon \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-22 04:13+0000\n"
+"X-Launchpad-Export-Date: 2010-06-28 03:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: project_gtd
@@ -30,7 +30,7 @@ msgstr "对象名必须以x_开头并且不能包含特殊字符"
#. module: project_gtd
#: model:ir.model,name:project_gtd.model_project_gtd_timebox
msgid "project.gtd.timebox"
-msgstr ""
+msgstr "project.gtd.timebox"
#. module: project_gtd
#: model:ir.actions.act_window,name:project_gtd.act_timebox_tasks_my_deadline_open
diff --git a/addons/project_issue/__openerp__.py b/addons/project_issue/__openerp__.py
index 7339399cc08..97f9e96afa0 100644
--- a/addons/project_issue/__openerp__.py
+++ b/addons/project_issue/__openerp__.py
@@ -34,7 +34,7 @@
'crm',
'project',
'hr_timesheet_sheet',
- 'project_long_term',
+ 'resource'
],
'init_xml': [
'project_issue_data.xml'
diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py
index c763306e602..b9d7baed6dd 100644
--- a/addons/project_issue/project_issue.py
+++ b/addons/project_issue/project_issue.py
@@ -31,12 +31,15 @@ from crm import crm
from osv import fields,osv,orm
from osv.orm import except_orm
from tools.translate import _
+import collections
+import binascii
+import tools
class project_issue(osv.osv, crm.crm_case):
_name = "project.issue"
_description = "Project Issue"
_order = "priority, id desc"
- _inherits = {'mailgate.thread': 'thread_id'}
+ _inherit = ['mailgate.thread']
def case_open(self, cr, uid, ids, *args):
"""
@@ -121,7 +124,6 @@ class project_issue(osv.osv, crm.crm_case):
return res
_columns = {
- 'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'id': fields.integer('ID'),
'name': fields.char('Name', size=128, required=True),
'active': fields.boolean('Active', required=False),
@@ -179,6 +181,10 @@ class project_issue(osv.osv, crm.crm_case):
method=True, multi='working_days_open', type="float", store=True),
'working_hours_close': fields.function(_compute_day, string='Working Hours to Close the Issue', \
method=True, multi='working_days_close', type="float", store=True),
+ 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('model','=',_name)]),
+ 'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
+ 'date_action_last': fields.datetime('Last Action', readonly=1),
+ 'date_action_next': fields.datetime('Next Action', readonly=1),
}
def _get_project(self, cr, uid, context):
@@ -298,5 +304,107 @@ class project_issue(osv.osv, crm.crm_case):
self.write(cr, uid, [case.id], data)
return True
+ def message_new(self, cr, uid, msg, context):
+ """
+ Automatically calls when new email message arrives
+
+ @param self: The object pointer
+ @param cr: the current row, from the database cursor,
+ @param uid: the current user’s ID for security checks
+ """
+
+ mailgate_pool = self.pool.get('email.server.tools')
+
+ subject = msg.get('subject')
+ body = msg.get('body')
+ msg_from = msg.get('from')
+ priority = msg.get('priority')
+
+ vals = {
+ 'name': subject,
+ 'email_from': msg_from,
+ 'email_cc': msg.get('cc'),
+ 'description': body,
+ 'user_id': False,
+ }
+ if msg.get('priority', False):
+ vals['priority'] = priority
+
+ res = mailgate_pool.get_partner(cr, uid, msg.get('from'))
+ if res:
+ vals.update(res)
+ res = self.create(cr, uid, vals, context)
+ self.convert_to_bug(cr, uid, [res], context=context)
+
+ attachents = msg.get('attachments', [])
+ for attactment in attachents or []:
+ data_attach = {
+ 'name': attactment,
+ 'datas':binascii.b2a_base64(str(attachents.get(attactment))),
+ 'datas_fname': attactment,
+ 'description': 'Mail attachment',
+ 'res_model': self._name,
+ 'res_id': res,
+ }
+ self.pool.get('ir.attachment').create(cr, uid, data_attach)
+
+ return res
+
+ def message_update(self, cr, uid, ids, vals={}, msg="", default_act='pending', context={}):
+ """
+ @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 update mail’s IDs
+ """
+
+ if isinstance(ids, (str, int, long)):
+ ids = [ids]
+
+ msg_from = msg['from']
+ vals.update({
+ 'description': msg['body']
+ })
+ if msg.get('priority', False):
+ vals['priority'] = msg.get('priority')
+
+ maps = {
+ 'cost':'planned_cost',
+ 'revenue': 'planned_revenue',
+ 'probability':'probability'
+ }
+ vls = { }
+ for line in msg['body'].split('\n'):
+ line = line.strip()
+ res = tools.misc.command_re.match(line)
+ if res and maps.get(res.group(1).lower(), False):
+ key = maps.get(res.group(1).lower())
+ vls[key] = res.group(2).lower()
+
+ vals.update(vls)
+ res = self.write(cr, uid, ids, vals)
+ return res
+
+
+ def msg_send(self, cr, uid, id, *args, **argv):
+
+ """ Send The Message
+ @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 email’s IDs
+ @param *args: Return Tuple Value
+ @param **args: Return Dictionary of Keyword Value
+ """
+ return True
+
project_issue()
+class project(osv.osv):
+ _inherit = "project.project"
+ _columns = {
+ 'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report"),
+ }
+project()
+
+
diff --git a/addons/project_issue/project_issue_demo.xml b/addons/project_issue/project_issue_demo.xml
index ed031672360..aee12ccf01e 100644
--- a/addons/project_issue/project_issue_demo.xml
+++ b/addons/project_issue/project_issue_demo.xml
@@ -1,290 +1,278 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/project_issue/project_issue_menu.xml b/addons/project_issue/project_issue_menu.xml
index ea902ea599f..fefdd496559 100644
--- a/addons/project_issue/project_issue_menu.xml
+++ b/addons/project_issue/project_issue_menu.xml
@@ -1,6 +1,6 @@
-
+
######################## ISSUE TRACKING (menu) ###########################
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml
index 973e0a1a20c..fd523ad7774 100644
--- a/addons/project_issue/project_issue_view.xml
+++ b/addons/project_issue/project_issue_view.xml
@@ -95,7 +95,7 @@
diff --git a/addons/project_planning/project_planning.py b/addons/project_planning/project_planning.py
index 2124b59b5c3..23fb780f334 100644
--- a/addons/project_planning/project_planning.py
+++ b/addons/project_planning/project_planning.py
@@ -383,7 +383,7 @@ class report_account_analytic_planning_account(osv.osv):
FROM report_account_analytic_planning_line
WHERE planning_id = %s AND account_id=%s
)""", (line.planning_id.id,line.account_id.id ))
- result[line.id] = cr.fetchall()[0][0] / div *div2
+ result[line.id] = cr.fetchall()[0][0] / div * div2
return result
def _get_timesheets(self, cr, uid, ids, name, args, context):
@@ -493,13 +493,13 @@ where user_id=%s and account_id=%s and date>=%s and date<=%s''', (line.user_id.i
for line in self.browse(cr, uid, ids, context):
where = ''
if line.user_id:
- where='user_id='+str(line.user_id.id)+' and '
+ where = 'user_id=' + str(line.user_id.id) + ' and '
cr.execute('''select
sum(planned_hours)
from
project_task
where
- '''+where+'''
+ ''' + where + '''
project_id in (select id from project_project where category_id=%s) and
date_close>=%s and
date_close<=%s''', (
diff --git a/addons/project_retro_planning/i18n/zh_TW.po b/addons/project_retro_planning/i18n/zh_TW.po
index b87c61bd408..f5f267875ca 100644
--- a/addons/project_retro_planning/i18n/zh_TW.po
+++ b/addons/project_retro_planning/i18n/zh_TW.po
@@ -7,16 +7,16 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-01-30 12:44+0000\n"
-"Last-Translator: <>\n"
+"PO-Revision-Date: 2010-06-27 14:09+0000\n"
+"Last-Translator: Rossi Liu \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-22 04:19+0000\n"
+"X-Launchpad-Export-Date: 2010-06-28 03:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: project_retro_planning
#: model:ir.module.module,shortdesc:project_retro_planning.module_meta_information
msgid "Project Retro planning"
-msgstr ""
+msgstr "舊有的規劃項目"
diff --git a/addons/project_timesheet/i18n/es.po b/addons/project_timesheet/i18n/es.po
index 777b9212e77..28dd6ec6d3c 100644
--- a/addons/project_timesheet/i18n/es.po
+++ b/addons/project_timesheet/i18n/es.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: project_timesheet
diff --git a/addons/purchase/i18n/el.po b/addons/purchase/i18n/el.po
index 09f8256c503..bcf0c1b089b 100644
--- a/addons/purchase/i18n/el.po
+++ b/addons/purchase/i18n/el.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-16 19:12+0000\n"
-"Last-Translator: Andreas Porevopoulos \n"
+"PO-Revision-Date: 2010-06-26 00:12+0000\n"
+"Last-Translator: Fotis Tsamis \n"
"Language-Team: nls@hellug.gr \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-22 03:56+0000\n"
+"X-Launchpad-Export-Date: 2010-06-27 03:47+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"X-Poedit-Country: GREECE\n"
"X-Poedit-Language: Greek\n"
@@ -788,7 +788,7 @@ msgstr "Προϊόν"
#: field:purchase.order.line,name:0
#: rml:purchase.quotation:0
msgid "Description"
-msgstr "Περογραφή"
+msgstr "Περιγραφή"
#. module: purchase
#: model:process.transition,name:purchase.process_transition_productrecept0
diff --git a/addons/purchase/i18n/es.po b/addons/purchase/i18n/es.po
index a8e5b9f94ff..f49b031bfd4 100644
--- a/addons/purchase/i18n/es.po
+++ b/addons/purchase/i18n/es.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-03-20 19:39+0000\n"
-"Last-Translator: Jonay \n"
+"PO-Revision-Date: 2010-06-27 20:58+0000\n"
+"Last-Translator: Borja López Soilán (Pexego) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-22 03:57+0000\n"
+"X-Launchpad-Export-Date: 2010-06-28 03:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: purchase
@@ -681,7 +681,7 @@ msgstr "Posición fiscal"
#. module: purchase
#: rml:purchase.order:0
msgid "Request for Quotation N°"
-msgstr ""
+msgstr "Petición de presupuesto Nº"
#. module: purchase
#: field:purchase.order,invoice_id:0
diff --git a/addons/report_analytic_planning/i18n/es.po b/addons/report_analytic_planning/i18n/es.po
deleted file mode 100644
index bf4ebb8ce76..00000000000
--- a/addons/report_analytic_planning/i18n/es.po
+++ /dev/null
@@ -1,347 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * report_analytic_planning
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.0\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-23 17:32+0000\n"
-"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
-"\n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
-"X-Generator: Launchpad (build Unknown)\n"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "To:"
-msgstr "Hasta:"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Planning by Account"
-msgstr "Planificación por cuenta"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "Summary by project"
-msgstr "Resumen por proyecto"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.line,amount_unit:0
-msgid "Qty UoM"
-msgstr "Ctdad UdM"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,user_id:0
-msgid "Responsible"
-msgstr "Responsable"
-
-#. module: report_analytic_planning
-#: model:ir.model,name:report_analytic_planning.model_report_account_analytic_planning_stat
-msgid "Planning stat"
-msgstr "Estad. planificación"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,state:0
-msgid "Status"
-msgstr "Estado"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.line,account_id:0
-msgid "Analytic account"
-msgstr "Cuenta analítica"
-
-#. module: report_analytic_planning
-#: constraint:ir.actions.act_window:0
-msgid "Invalid model name in the action definition."
-msgstr "Nombre de modelo no válido en la definición de acción."
-
-#. module: report_analytic_planning
-#: constraint:ir.model:0
-msgid ""
-"The Object name must start with x_ and not contain any special character !"
-msgstr ""
-"¡El nombre del objeto debe empezar con x_ y no contener ningún carácter "
-"especial!"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_stat_form
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning_stat
-msgid "Planning Statistics"
-msgstr "Estadísticas de planificación"
-
-#. module: report_analytic_planning
-#: model:ir.model,name:report_analytic_planning.model_report_account_analytic_planning_stat_account
-msgid "Planning account stat"
-msgstr "Estad. cuenta planificación"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.stat,sum_amount:0
-msgid "Planned hours"
-msgstr "Horas planeadas"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "Real"
-msgstr "Real"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_stat_my_form
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning_stat_my
-msgid "My Planning Statistics"
-msgstr "Mis estadísticas de planificación"
-
-#. module: report_analytic_planning
-#: model:ir.module.module,description:report_analytic_planning.module_meta_information
-msgid "Planning on analytic accounts."
-msgstr "Planificación a partir de cuentas analíticas."
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,name:0
-msgid "Planning Name"
-msgstr "Nombre planificación"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "Quantities"
-msgstr "Cantidades"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "HR Planning"
-msgstr "Planificación RRHH"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.stat,sum_amount_real:0
-#: field:report_account_analytic.planning.stat.account,sum_amount_real:0
-#: field:report_account_analytic.planning.stat.user,sum_amount_real:0
-msgid "Timesheet"
-msgstr "Hoja de asistencia"
-
-#. module: report_analytic_planning
-#: model:ir.model,name:report_analytic_planning.model_report_account_analytic_planning_line
-#: view:report_account_analytic.planning:0
-msgid "Planning Line"
-msgstr "Línea de planificación"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "Responsible:"
-msgstr "Responsable:"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.line,amount:0
-msgid "Quantity"
-msgstr "Cantidad"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Quantities by Account"
-msgstr "Cantidades por cuenta"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "From:"
-msgstr "Desde:"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Time by Account"
-msgstr "Tiempo por cuenta"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,date_to:0
-msgid "End Date"
-msgstr "Fecha final"
-
-#. module: report_analytic_planning
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "¡XML inválido para la definición de la vista!"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Time by User"
-msgstr "Tiempo por usuario"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_stat_my_manager_form
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning_stat_my_manager
-msgid "Planning Statistics of My Projects"
-msgstr "Estadísticas de planificación de mis proyectos"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_form_current
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning_current
-msgid "Current Planning"
-msgstr "Planificación actual"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "Summary by user"
-msgstr "Resumen por usuario"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Analysis"
-msgstr "Análisis"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.line,user_id:0
-#: rml:report_account_analytic.planning.print:0
-#: field:report_account_analytic.planning.stat,user_id:0
-#: field:report_account_analytic.planning.stat.user,user_id:0
-msgid "User"
-msgstr "Usuario"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "Project"
-msgstr "Proyecto"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Total Timesheet"
-msgstr "Total hoja de servicios"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "Details of user's time by projects"
-msgstr "Detalle del tiempo del usuario por proyectos"
-
-#. module: report_analytic_planning
-#: model:ir.model,name:report_analytic_planning.model_report_account_analytic_planning_stat_user
-msgid "Planning user stat"
-msgstr "Estad. planificación del usuario"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-#: field:report_account_analytic.planning.stat.account,quantity:0
-#: field:report_account_analytic.planning.stat.user,quantity:0
-msgid "Planned"
-msgstr "Planificado"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,stat_ids:0
-msgid "Planning analysis"
-msgstr "Análisis planificación"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "["
-msgstr "["
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,line_ids:0
-msgid "Planning lines"
-msgstr "Líneas planificación"
-
-#. module: report_analytic_planning
-#: model:ir.module.module,shortdesc:report_analytic_planning.module_meta_information
-msgid "Analytic planning - Reporting"
-msgstr "Informes - Planificación analítica"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-msgid "]"
-msgstr "]"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_form_my
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning_my2
-msgid "My Planning"
-msgstr "Mi planificación"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,stat_user_ids:0
-msgid "Planning by user"
-msgstr "Planificación por usuario"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.line,note:0
-msgid "Note"
-msgstr "Nota"
-
-#. module: report_analytic_planning
-#: rml:report_account_analytic.planning.print:0
-#: field:report_account_analytic.planning.stat,sum_amount_tasks:0
-msgid "Tasks"
-msgstr "Tareas"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,stat_account_ids:0
-msgid "Planning by account"
-msgstr "Planificación por cuenta"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Quantities by User"
-msgstr "Cantidades por usuario"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_form_current_my
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning_current_my
-msgid "My Current Planning"
-msgstr "Mi planificación actual"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.stat.account,account_id:0
-msgid "Analytic Account"
-msgstr "Cuenta analítica"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning.stat,manager_id:0
-msgid "Manager"
-msgstr "Responsable"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_form
-#: model:ir.actions.report.xml,name:report_analytic_planning.report_planning
-#: model:ir.model,name:report_analytic_planning.model_report_account_analytic_planning
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning
-#: model:ir.ui.menu,name:report_analytic_planning.next_id_85
-#: model:ir.ui.menu,name:report_analytic_planning.planning_main
-#: view:report_account_analytic.planning:0
-#: field:report_account_analytic.planning.line,planning_id:0
-#: field:report_account_analytic.planning.stat,planning_id:0
-#: field:report_account_analytic.planning.stat.account,planning_id:0
-#: field:report_account_analytic.planning.stat.user,planning_id:0
-msgid "Planning"
-msgstr "Planificación"
-
-#. module: report_analytic_planning
-#: selection:report_account_analytic.planning,state:0
-msgid "Done"
-msgstr "Realizado"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning:0
-msgid "Total Planned"
-msgstr "Total planeado"
-
-#. module: report_analytic_planning
-#: field:report_account_analytic.planning,date_from:0
-msgid "Start Date"
-msgstr "Fecha inicial"
-
-#. module: report_analytic_planning
-#: view:report_account_analytic.planning.stat:0
-msgid "Planning statistics"
-msgstr "Estadísticas de planificación"
-
-#. module: report_analytic_planning
-#: selection:report_account_analytic.planning,state:0
-msgid "Open"
-msgstr "Abierto"
-
-#. module: report_analytic_planning
-#: model:ir.actions.act_window,name:report_analytic_planning.action_account_analytic_planning_form_new
-#: model:ir.ui.menu,name:report_analytic_planning.menu_report_account_analytic_planning_new
-msgid "New Planning"
-msgstr "Nueva planificación"
diff --git a/addons/report_task/i18n/es.po b/addons/report_task/i18n/es.po
deleted file mode 100644
index 8bb396c5454..00000000000
--- a/addons/report_task/i18n/es.po
+++ /dev/null
@@ -1,269 +0,0 @@
-# Translation of OpenERP Server.
-# This file contains the translation of the following modules:
-# * report_task
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: OpenERP Server 5.0.0\n"
-"Report-Msgid-Bugs-To: support@openerp.com\n"
-"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-06-23 17:33+0000\n"
-"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
-"\n"
-"Language-Team: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:47+0000\n"
-"X-Generator: Launchpad (build Unknown)\n"
-
-#. module: report_task
-#: selection:report.closed.task,state:0
-msgid "In Progress"
-msgstr "En proceso"
-
-#. module: report_task
-#: model:ir.actions.act_window,name:report_task.action_project_task
-#: model:ir.ui.menu,name:report_task.menu_project_task_user_tree
-#: view:report.task.user.pipeline.open:0
-msgid "Tasks by User"
-msgstr "Tareas por usuario"
-
-#. module: report_task
-#: constraint:ir.model:0
-msgid ""
-"The Object name must start with x_ and not contain any special character !"
-msgstr ""
-"¡El nombre del objeto debe empezar con x_ y no contener ningún carácter "
-"especial!"
-
-#. module: report_task
-#: field:report.closed.task,remaining_hours:0
-msgid "Remaining Hours"
-msgstr "Horas restantes"
-
-#. module: report_task
-#: selection:report.task.user.pipeline.open,task_state:0
-msgid "No Task"
-msgstr "No hay tarea"
-
-#. module: report_task
-#: model:ir.module.module,shortdesc:report_task.module_meta_information
-msgid "Report on tasks by user for projects"
-msgstr "Informe de tareas por usuario para proyectos"
-
-#. module: report_task
-#: view:report.closed.task:0
-msgid "Delay"
-msgstr "Retraso"
-
-#. module: report_task
-#: selection:report.closed.task,priority:0
-msgid "Very Low"
-msgstr "Muy baja"
-
-#. module: report_task
-#: selection:report.closed.task,state:0
-#: selection:report.task.user.pipeline.open,task_state:0
-msgid "Draft"
-msgstr "Borrador"
-
-#. module: report_task
-#: selection:report.closed.task,priority:0
-msgid "Low"
-msgstr "Baja"
-
-#. module: report_task
-#: constraint:ir.actions.act_window:0
-msgid "Invalid model name in the action definition."
-msgstr "Nombre de modelo no válido en la definición de acción."
-
-#. module: report_task
-#: field:report.closed.task,name:0
-msgid "Task summary"
-msgstr "Resumen de tarea"
-
-#. module: report_task
-#: selection:report.closed.task,state:0
-#: selection:report.task.user.pipeline.open,task_state:0
-msgid "Pending"
-msgstr "Pendiente"
-
-#. module: report_task
-#: field:report.closed.task,state:0
-#: field:report.task.user.pipeline.open,task_state:0
-msgid "Status"
-msgstr "Estado"
-
-#. module: report_task
-#: selection:report.closed.task,priority:0
-msgid "Medium"
-msgstr "Media"
-
-#. module: report_task
-#: model:ir.actions.act_window,name:report_task.action_report_timesheet_task_user
-#: model:ir.ui.menu,name:report_task.menu_timesheet_task_user
-msgid "Timesheet / Task Hours Per Month"
-msgstr "Tiempo / Horas de tareas por mes"
-
-#. module: report_task
-#: field:report.closed.task,progress:0
-msgid "Progress (%)"
-msgstr "Progreso (%)"
-
-#. module: report_task
-#: field:report.closed.task,priority:0
-msgid "Importance"
-msgstr "Importancia"
-
-#. module: report_task
-#: field:report.task.user.pipeline.open,company_id:0
-msgid "Company"
-msgstr "Compañía"
-
-#. module: report_task
-#: model:ir.ui.menu,name:report_task.next_id_57
-msgid "Reporting"
-msgstr "Informe"
-
-#. module: report_task
-#: model:ir.module.module,description:report_task.module_meta_information
-msgid ""
-"Gives statistics on tasks by user on projects to check the pipeline of users."
-msgstr ""
-"Proporciona estadísticas de tareas por usuario en proyectos para comprobar "
-"el trabajo encadenado de los usuarios."
-
-#. module: report_task
-#: field:report.task.user.pipeline.open,user_id:0
-#: field:report.timesheet.task.user,user_id:0
-msgid "User"
-msgstr "Usuario"
-
-#. module: report_task
-#: model:ir.actions.act_window,name:report_task.action_closed_task_board
-msgid "Task Closed Within Past 15 Days"
-msgstr "Tareas cerradas en los últimos 15 días"
-
-#. module: report_task
-#: selection:report.closed.task,priority:0
-msgid "Very urgent"
-msgstr "Muy urgente"
-
-#. module: report_task
-#: selection:report.closed.task,state:0
-#: selection:report.task.user.pipeline.open,task_state:0
-msgid "Done"
-msgstr "Realizada"
-
-#. module: report_task
-#: field:report.task.user.pipeline.open,task_hrs:0
-#: field:report.timesheet.task.user,task_hrs:0
-msgid "Task Hours"
-msgstr "Horas de tarea"
-
-#. module: report_task
-#: constraint:ir.ui.view:0
-msgid "Invalid XML for View Architecture!"
-msgstr "¡XML inválido para la definición de la vista!"
-
-#. module: report_task
-#: field:report.closed.task,delay_hours:0
-msgid "Delay Hours"
-msgstr "Horas de retraso"
-
-#. module: report_task
-#: field:report.closed.task,project_id:0
-msgid "Project"
-msgstr "Proyecto"
-
-#. module: report_task
-#: field:report.task.user.pipeline.open,task_nbr:0
-msgid "Task Number"
-msgstr "Número de tarea"
-
-#. module: report_task
-#: model:ir.model,name:report_task.model_report_timesheet_task_user
-msgid "report.timesheet.task.user"
-msgstr ""
-
-#. module: report_task
-#: model:ir.model,name:report_task.model_report_task_user_pipeline_open
-msgid "Tasks by user and project"
-msgstr "Tareas por usuario y proyecto"
-
-#. module: report_task
-#: view:report.closed.task:0
-msgid "Planned"
-msgstr "Planificado"
-
-#. module: report_task
-#: selection:report.closed.task,state:0
-#: selection:report.task.user.pipeline.open,task_state:0
-msgid "Cancelled"
-msgstr "Cancelado"
-
-#. module: report_task
-#: view:report.timesheet.task.user:0
-msgid "Timesheet/Task hours Report Per Month"
-msgstr "Horario / Informe de horas de trabajo por mes"
-
-#. module: report_task
-#: field:report.task.user.pipeline.open,task_progress:0
-msgid "Task Progress"
-msgstr "Progreso de la tarea"
-
-#. module: report_task
-#: field:report.closed.task,date_close:0
-msgid "Date Closed"
-msgstr "Fecha de cierre"
-
-#. module: report_task
-#: field:report.closed.task,user_id:0
-msgid "Assigned to"
-msgstr "Asignado a"
-
-#. module: report_task
-#: field:report.closed.task,sequence:0
-msgid "Sequence"
-msgstr "Secuencia"
-
-#. module: report_task
-#: model:ir.model,name:report_task.model_report_closed_task
-msgid "Closed Task Report"
-msgstr "Informe de tareas cerradas"
-
-#. module: report_task
-#: field:report.timesheet.task.user,name:0
-msgid "Month"
-msgstr "Mes"
-
-#. module: report_task
-#: selection:report.closed.task,priority:0
-msgid "Urgent"
-msgstr "Urgente"
-
-#. module: report_task
-#: field:report.closed.task,date_deadline:0
-msgid "Deadline"
-msgstr "Fecha límite"
-
-#. module: report_task
-#: field:report.timesheet.task.user,timesheet_hrs:0
-msgid "Timesheet Hours"
-msgstr "Horas del horario"
-
-#. module: report_task
-#: view:report.closed.task:0
-msgid "Closed Tasks"
-msgstr "Tareas cerradas"
-
-#. module: report_task
-#: selection:report.task.user.pipeline.open,task_state:0
-msgid "Open"
-msgstr "Abrir"
-
-#. module: report_task
-#: field:report.closed.task,planned_hours:0
-msgid "Planned Hours"
-msgstr "Horas planeadas"
diff --git a/addons/sale/board_sale_demo.xml b/addons/sale/board_sale_demo.xml
index 996821c02e1..09419de206c 100644
--- a/addons/sale/board_sale_demo.xml
+++ b/addons/sale/board_sale_demo.xml
@@ -1,17 +1,17 @@
-
+
-
+
diff --git a/addons/sale/board_sale_view.xml b/addons/sale/board_sale_view.xml
index c89b90ecb65..2f290ce5dd8 100644
--- a/addons/sale/board_sale_view.xml
+++ b/addons/sale/board_sale_view.xml
@@ -30,11 +30,11 @@
+
+
+
+
diff --git a/addons/sale_crm/sale_crm_view.xml b/addons/sale_crm/sale_crm_view.xml
index 565fd687b4e..5cf4cf552f0 100644
--- a/addons/sale_crm/sale_crm_view.xml
+++ b/addons/sale_crm/sale_crm_view.xml
@@ -9,7 +9,7 @@
-
+
diff --git a/addons/sale_crm/sale_crm_wizard.xml b/addons/sale_crm/sale_crm_wizard.xml
deleted file mode 100644
index 74dcf06e901..00000000000
--- a/addons/sale_crm/sale_crm_wizard.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/addons/sale_crm/wizard/__init__.py b/addons/sale_crm/wizard/__init__.py
index 87048a13fc4..04f40c92207 100644
--- a/addons/sale_crm/wizard/__init__.py
+++ b/addons/sale_crm/wizard/__init__.py
@@ -19,7 +19,7 @@
#
##############################################################################
-import makesale
+import crm_make_sale
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/sale_crm/wizard/crm_make_sale.py b/addons/sale_crm/wizard/crm_make_sale.py
new file mode 100644
index 00000000000..db6bcd832b3
--- /dev/null
+++ b/addons/sale_crm/wizard/crm_make_sale.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# 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 .
+#
+##############################################################################
+
+from osv import fields, osv
+from tools.translate import _
+from mx.DateTime import now
+
+
+class crm_make_sale(osv.osv_memory):
+ """ Make sale order for crm """
+
+ _name = "crm.make.sale"
+ _description = "Make sale"
+
+ def _selectPartner(self, cr, uid, context=None):
+ """
+ This function gets default value for partner_id field.
+ @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 context: A standard dictionary for contextual values
+ @return : default value of partner_id field.
+ """
+ if not context:
+ context = {}
+
+ active_id = context and context.get('active_id', False) or False
+ if not active_id:
+ return False
+ lead_obj = self.pool.get('crm.lead')
+ lead = lead_obj.read(cr, uid, active_id, ['partner_id'])
+ return lead['partner_id']
+
+ def makeOrder(self, cr, uid, ids, context=None):
+ """
+ This function create Quotation on given case.
+ @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 make sale' ids
+ @param context: A standard dictionary for contextual values
+ @return : Dictionary value of created sale order.
+ """
+ if not context:
+ context = {}
+
+ mod_obj = self.pool.get('ir.model.data')
+
+
+ result = mod_obj._get_id(cr, uid, 'sale', 'view_sales_order_filter')
+ id = mod_obj.read(cr, uid, result, ['res_id'])
+
+ case_obj = self.pool.get('crm.lead')
+ sale_obj = self.pool.get('sale.order')
+ partner_obj = self.pool.get('res.partner')
+ sale_line_obj = self.pool.get('sale.order.line')
+
+ data = context and context.get('active_ids', []) or []
+
+ for make in self.browse(cr, uid, ids):
+ default_partner_addr = partner_obj.address_get(cr, uid, [make.partner_id.id],
+ ['invoice', 'delivery', 'contact'])
+ default_pricelist = partner_obj.browse(cr, uid, make.partner_id.id,
+ context).property_product_pricelist.id
+ fpos_data = partner_obj.browse(cr, uid, make.partner_id.id, context).property_account_position
+ new_ids = []
+
+ for case in case_obj.browse(cr, uid, data):
+ if case.partner_id and case.partner_id.id:
+ partner_id = case.partner_id.id
+ fpos = case.partner_id.property_account_position and case.partner_id.property_account_position.id or False
+ partner_addr = partner_obj.address_get(cr, uid, [case.partner_id.id],
+ ['invoice', 'delivery', 'contact'])
+ pricelist = partner_obj.browse(cr, uid, case.partner_id.id,
+ context).property_product_pricelist.id
+ else:
+ partner_id = make.partner_id.id
+ fpos = fpos_data and fpos_data.id or False
+ partner_addr = default_partner_addr
+ pricelist = default_pricelist
+
+ if False in partner_addr.values():
+ raise osv.except_osv(_('Data Insufficient!'),_('Customer has no addresses defined!'))
+
+ vals = {
+ 'origin': 'CRM-Opportunity:%s' % str(case.id),
+ 'section_id': case.section_id and case.section_id.id or False,
+ 'picking_policy': make.picking_policy,
+ 'shop_id': make.shop_id.id,
+ 'partner_id': partner_id,
+ 'pricelist_id': pricelist,
+ 'partner_invoice_id': partner_addr['invoice'],
+ 'partner_order_id': partner_addr['contact'],
+ 'partner_shipping_id': partner_addr['delivery'],
+ 'order_policy': 'manual',
+ 'date_order': now(),
+ 'fiscal_position': fpos,
+ }
+
+ if partner_id:
+ partner = partner_obj.browse(cr, uid, partner_id, context=context)
+ vals['user_id'] = partner.user_id and partner.user_id.id or uid
+
+ if make.analytic_account.id:
+ vals['project_id'] = make.analytic_account.id
+ new_id = sale_obj.create(cr, uid, vals)
+ for product_id in make.product_ids:
+ value = sale_line_obj.product_id_change(cr, uid, [], pricelist,
+ product_id.id, qty=1, partner_id=partner_id, fiscal_position=fpos)['value']
+ value['product_id'] = product_id.id
+ value['order_id'] = new_id
+ value['tax_id'] = [(6,0,value['tax_id'])]
+ sale_line_obj.create(cr, uid, value)
+
+ case_obj.write(cr, uid, [case.id], {'ref': 'sale.order,%s' % new_id})
+ new_ids.append(new_id)
+
+ if make.close:
+ case_obj.case_close(cr, uid, data)
+
+ if not new_ids:
+ return {}
+ if len(new_ids)<=1:
+ value = {
+ 'domain': str([('id', 'in', new_ids)]),
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'sale.order',
+ 'view_id': False,
+ 'type': 'ir.actions.act_window',
+ 'res_id': new_ids and new_ids[0]
+
+ }
+
+
+ else:
+ value = {
+ 'domain': str([('id', 'in', new_ids)]),
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'sale.order',
+ 'view_id': False,
+ 'type': 'ir.actions.act_window',
+ 'res_id':new_ids
+ }
+ return value
+
+
+ _columns = {
+ 'shop_id': fields.many2one('sale.shop', 'Shop', required = True),
+ 'partner_id': fields.many2one('res.partner', 'Customer', required = True, help = 'Use this partner if there is no partner on the Opportunity'),
+ 'picking_policy': fields.selection([('direct','Partial Delivery'),
+ ('one','Complete Delivery')], 'Picking Policy', required = True),
+ 'product_ids': fields.many2many('product.product', 'product_sale_rel',\
+ 'sale_id', 'product_id', 'Products'),
+ 'analytic_account': fields.many2one('account.analytic.account', 'Analytic Account'),
+ 'close': fields.boolean('Close Case', help = 'Check this to close the case after having created the sale order.'),
+ }
+ _defaults = {
+ 'partner_id': _selectPartner,
+ 'close': lambda *a: 1
+ }
+
+crm_make_sale()
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/sale_crm/wizard/crm_make_sale_view.xml b/addons/sale_crm/wizard/crm_make_sale_view.xml
new file mode 100644
index 00000000000..a1da3ed1fec
--- /dev/null
+++ b/addons/sale_crm/wizard/crm_make_sale_view.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+ crm.make.sale.form
+ crm.make.sale
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Make Quotation
+ ir.actions.act_window
+ crm.make.sale
+ form
+ form
+ new
+
+
+
+
diff --git a/addons/sale_crm/wizard/makesale.py b/addons/sale_crm/wizard/makesale.py
deleted file mode 100644
index e4aacce1044..00000000000
--- a/addons/sale_crm/wizard/makesale.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-from mx.DateTime import now
-
-import wizard
-import netsvc
-import ir
-import pooler
-from tools.translate import _
-
-sale_form = """
-
-
-
-
-
-
-
-
-
"""
-
-sale_fields = {
- 'shop_id': {'string': 'Shop', 'type': 'many2one', 'relation': 'sale.shop'},
- 'partner_id': {'string': 'Customer', 'type': 'many2one',
- 'relation': 'res.partner',
- 'help': 'Use this partner if there is no partner on the case'},
- 'picking_policy': {'string': 'Picking Policy', 'type': 'selection',
- 'selection': [('direct', 'Partial Delivery'), ('one', 'Complete Delivery')]},
- 'products': {'string': 'Products', 'type': 'many2many',
- 'relation': 'product.product'},
- 'analytic_account': {'string': 'Analytic Account', 'type': 'many2one',
- 'relation': 'account.analytic.account'},
- 'close': {'string': 'Close Case', 'type': 'boolean', 'default': lambda *a: 1,
- 'help': 'Check this to close the case after having created the sale order.'},
-}
-
-
-class make_sale(wizard.interface):
-
- def _selectPartner(self, cr, uid, data, context):
- case_obj = pooler.get_pool(cr.dbname).get('crm.lead')
- case = case_obj.read(cr, uid, data['ids'], ['partner_id'])
- return {'partner_id': case[0]['partner_id']}
-
- def _makeOrder(self, cr, uid, data, context):
- pool = pooler.get_pool(cr.dbname)
- mod_obj = pool.get('ir.model.data')
- result = mod_obj._get_id(cr, uid, 'sale', 'view_sales_order_filter')
- id = mod_obj.read(cr, uid, result, ['res_id'])
- case_obj = pool.get('crm.lead')
- sale_obj = pool.get('sale.order')
- partner_obj = pool.get('res.partner')
- sale_line_obj = pool.get('sale.order.line')
-
- default_partner_addr = partner_obj.address_get(cr, uid, [data['form']['partner_id']],
- ['invoice', 'delivery', 'contact'])
- default_pricelist = partner_obj.browse(cr, uid, data['form']['partner_id'],
- context).property_product_pricelist.id
- fpos_data = partner_obj.browse(cr, uid, data['form']['partner_id'],context).property_account_position
- new_ids = []
-
- for case in case_obj.browse(cr, uid, data['ids']):
- if case.partner_id and case.partner_id.id:
- partner_id = case.partner_id.id
- fpos = case.partner_id.property_account_position and case.partner_id.property_account_position.id or False
- partner_addr = partner_obj.address_get(cr, uid, [case.partner_id.id],
- ['invoice', 'delivery', 'contact'])
- pricelist = partner_obj.browse(cr, uid, case.partner_id.id,
- context).property_product_pricelist.id
- else:
- partner_id = data['form']['partner_id']
- fpos = fpos_data and fpos_data.id or False
- partner_addr = default_partner_addr
- pricelist = default_pricelist
-
- if False in partner_addr.values():
- raise wizard.except_wizard(_('Data Insufficient!'),_('Customer has no addresses defined!'))
-
- vals = {
- 'origin': 'CRM-Opportunity:%s' % str(case.id),
- 'section_id': case.section_id and case.section_id.id or False,
- 'picking_policy': data['form']['picking_policy'],
- 'shop_id': data['form']['shop_id'],
- 'partner_id': partner_id,
- 'pricelist_id': pricelist,
- 'partner_invoice_id': partner_addr['invoice'],
- 'partner_order_id': partner_addr['contact'],
- 'partner_shipping_id': partner_addr['delivery'],
- 'order_policy': 'manual',
- 'date_order': now(),
- 'fiscal_position': fpos,
- }
-
- if partner_id:
- partner = partner_obj.browse(cr, uid, partner_id, context=context)
- vals['user_id'] = partner.user_id and partner.user_id.id or uid
-
- if data['form']['analytic_account']:
- vals['project_id'] = data['form']['analytic_account']
-
- vals.update( sale_obj.onchange_partner_id(cr, uid, [], partner_id).get('value',{}) )
- new_id = sale_obj.create(cr, uid, vals)
- if data['form']['products']:
- for product_id in data['form']['products'][0][2]:
- value = {
- 'price_unit': 0.0,
- 'product_id': product_id,
- 'order_id': new_id,
- }
- value.update( sale_line_obj.product_id_change(cr, uid, [], pricelist,product_id, qty=1, partner_id=partner_id, fiscal_position=fpos)['value'] )
- value['tax_id'] = [(6,0,value['tax_id'])]
- sale_line_obj.create(cr, uid, value)
-
- case_obj.write(cr, uid, [case.id], {'ref': 'sale.order,%s' % new_id})
- new_ids.append(new_id)
-
- if data['form']['close']:
- case_obj.case_close(cr, uid, data['ids'])
-
- if not new_ids:
- return {}
-
- if len(new_ids)<=1:
- value = {
- 'domain': str([('id', 'in', new_ids)]),
- 'view_type': 'form',
- 'view_mode': 'form',
- 'res_model': 'sale.order',
- 'view_id': False,
- 'type': 'ir.actions.act_window',
- 'res_id': new_ids and new_ids[0]
- }
- else:
- value = {
- 'domain': str([('id', 'in', new_ids)]),
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'sale.order',
- 'view_id': False,
- 'type': 'ir.actions.act_window',
- 'res_id':new_ids
- }
-
- return value
-
- states = {
- 'init': {
- 'actions': [_selectPartner],
- 'result': {'type': 'form', 'arch': sale_form, 'fields': sale_fields,
- 'state' : [('end', 'Cancel', 'gtk-cancel'),('order', 'Create', 'gtk-apply')]}
- },
- 'order': {
- 'actions': [],
- 'result': {'type': 'action', 'action': _makeOrder, 'state': 'end'}
- }
- }
-
-make_sale('crm.opportunity.make_order')
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/sale_delivery_report/__openerp__.py b/addons/sale_delivery_report/__openerp__.py
index a5f6cc437fd..dfcbe1acb29 100644
--- a/addons/sale_delivery_report/__openerp__.py
+++ b/addons/sale_delivery_report/__openerp__.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -15,7 +15,7 @@
# 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 .
+# along with this program. If not, see .
#
##############################################################################
@@ -29,7 +29,7 @@
'depends': ['sale', 'delivery'],
'init_xml': [],
'update_xml': [
- 'delivery_report.xml'
+ 'sale_delivery_report.xml'
],
'demo_xml': [],
'installable': True,
diff --git a/addons/sale_delivery_report/delivery_report.xml b/addons/sale_delivery_report/sale_delivery_report.xml
similarity index 100%
rename from addons/sale_delivery_report/delivery_report.xml
rename to addons/sale_delivery_report/sale_delivery_report.xml
diff --git a/addons/sale_journal/i18n/es.po b/addons/sale_journal/i18n/es.po
index c096276892c..c2bfada3ab3 100644
--- a/addons/sale_journal/i18n/es.po
+++ b/addons/sale_journal/i18n/es.po
@@ -7,14 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-11-17 10:39+0000\n"
-"Last-Translator: Jordi Esteve (www.zikzakmedia.com) "
-"\n"
+"PO-Revision-Date: 2010-06-27 22:12+0000\n"
+"Last-Translator: Borja López Soilán (Pexego) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-22 04:10+0000\n"
+"X-Launchpad-Export-Date: 2010-06-28 03:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: sale_journal
@@ -315,7 +314,7 @@ msgstr "Activo"
#. module: sale_journal
#: model:ir.actions.act_window,name:sale_journal.act_sale_journal_sale_journal_2_sale_order_draft
msgid "Draft sales"
-msgstr "Borrador de ventas"
+msgstr "Ventas borrador"
#. module: sale_journal
#: selection:sale_journal.sale.stats,state:0
@@ -335,7 +334,7 @@ msgstr "diario_venta.factura.tipo.árbol"
#. module: sale_journal
#: view:sale_journal.sale.journal:0
msgid "Confirm Sales"
-msgstr "Confirmar las ventas"
+msgstr "Confirmar ventas"
#. module: sale_journal
#: field:sale_journal.picking.journal,date_created:0
@@ -383,7 +382,7 @@ msgstr "Realizado"
#. module: sale_journal
#: selection:sale_journal.sale.stats,state:0
msgid "Cancel"
-msgstr "Cancelar"
+msgstr "Cancelado"
#. module: sale_journal
#: field:sale_journal.picking.journal,picking_stats_ids:0
diff --git a/addons/sale_journal/sale_journal.py b/addons/sale_journal/sale_journal.py
index 41d770d5760..63bef68b4d6 100644
--- a/addons/sale_journal/sale_journal.py
+++ b/addons/sale_journal/sale_journal.py
@@ -127,6 +127,7 @@ class picking_journal(osv.osv):
'state': fields.selection([
('draft','Draft'),
('open','Open'),
+ ('cancel','Cancel'),
('done','Done'),
], 'Creation date', required=True, readonly=True),
'note': fields.text('Note'),
@@ -138,6 +139,7 @@ class picking_journal(osv.osv):
'state': lambda self,cr,uid,context: 'draft',
}
def button_picking_cancel(self, cr, uid, ids, context={}):
+ self.write(cr, uid, ids, {'state':'cancel'})
for id in ids:
pick_ids = self.pool.get('stock.picking').search(cr, uid, [('journal_id','=',id)])
for pickid in pick_ids:
@@ -177,7 +179,7 @@ res_partner()
class picking(osv.osv):
_inherit="stock.picking"
_columns = {
- 'journal_id': fields.many2one('sale_journal.picking.journal', 'Journal'),
+ 'journal_id': fields.many2one('sale_journal.picking.journal', 'Journal', domain=[('state','!=', 'done')]),
'sale_journal_id': fields.many2one('sale_journal.sale.journal', 'Sale Journal'),
'invoice_type_id': fields.many2one('sale_journal.invoice.type', 'Invoice Type', readonly=True)
}
@@ -186,7 +188,7 @@ picking()
class sale(osv.osv):
_inherit="sale.order"
_columns = {
- 'journal_id': fields.many2one('sale_journal.sale.journal', 'Journal'),
+ 'journal_id': fields.many2one('sale_journal.sale.journal', 'Journal', domain=[('state','!=', 'done')]),
'invoice_type_id': fields.many2one('sale_journal.invoice.type', 'Invoice Type')
}
def action_ship_create(self, cr, uid, ids, *args):
diff --git a/addons/sale_journal/sale_journal_view.xml b/addons/sale_journal/sale_journal_view.xml
index 08d197e3441..052d7e09777 100644
--- a/addons/sale_journal/sale_journal_view.xml
+++ b/addons/sale_journal/sale_journal_view.xml
@@ -113,13 +113,16 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -131,6 +134,7 @@
sale_journal.sale.journalformtree,form
+ {'search_default_user_id':uid}
@@ -386,7 +390,7 @@
-
+
@@ -417,13 +421,15 @@
-
-
+
+
+
+
-
-
-
-
+
+
+
+
@@ -436,6 +442,7 @@
sale_journal.picking.journalformtree,form
+ {'search_default_user_id':uid}
diff --git a/addons/sale_margin/i18n/et.po b/addons/sale_margin/i18n/et.po
new file mode 100644
index 00000000000..d4178048461
--- /dev/null
+++ b/addons/sale_margin/i18n/et.po
@@ -0,0 +1,370 @@
+# Estonian translation for openobject-addons
+# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2009-11-25 14:28+0000\n"
+"PO-Revision-Date: 2010-06-25 18:17+0000\n"
+"Last-Translator: lyyser \n"
+"Language-Team: Estonian \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:58+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#. module: sale_margin
+#: selection:report.account.invoice,type:0
+#: selection:report.account.invoice.category,type:0
+#: selection:report.account.invoice.partner,type:0
+#: selection:report.account.invoice.partner.product,type:0
+#: selection:report.account.invoice.product,type:0
+msgid "Customer Refund"
+msgstr "Kliendi tagasimakse"
+
+#. module: sale_margin
+#: model:ir.model,name:sale_margin.model_report_account_invoice_product
+msgid "report.account.invoice.product"
+msgstr ""
+
+#. module: sale_margin
+#: constraint:ir.model:0
+msgid ""
+"The Object name must start with x_ and not contain any special character !"
+msgstr ""
+"Objekti nimi peab algama x_'ga ja ei tohi sisaldada ühtegi erisümbolit !"
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_all_invoice_by_product
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_invoice_by_product
+msgid "Invoices by Product"
+msgstr ""
+
+#. module: sale_margin
+#: selection:report.account.invoice,type:0
+#: selection:report.account.invoice.category,type:0
+#: selection:report.account.invoice.partner,type:0
+#: selection:report.account.invoice.partner.product,type:0
+#: selection:report.account.invoice.product,type:0
+msgid "Customer Invoice"
+msgstr "Kliendi arve"
+
+#. module: sale_margin
+#: wizard_view:stock.invoice_onshipping,init:0
+msgid "Create invoices"
+msgstr "Loo arved"
+
+#. module: sale_margin
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "Vigane XML vaate arhitektuurile!"
+
+#. module: sale_margin
+#: model:ir.model,name:sale_margin.model_report_account_invoice_partner_product
+msgid "report.account.invoice.partner.product"
+msgstr ""
+
+#. module: sale_margin
+#: selection:report.account.invoice,type:0
+#: selection:report.account.invoice.category,type:0
+#: selection:report.account.invoice.partner,type:0
+#: selection:report.account.invoice.partner.product,type:0
+#: selection:report.account.invoice.product,type:0
+msgid "Supplier Invoice"
+msgstr "Tarnija arve"
+
+#. module: sale_margin
+#: field:report.account.invoice,state:0
+#: field:report.account.invoice.category,state:0
+#: field:report.account.invoice.partner,state:0
+#: field:report.account.invoice.partner.product,state:0
+#: field:report.account.invoice.product,state:0
+msgid "State"
+msgstr ""
+
+#. module: sale_margin
+#: view:stock.picking:0
+msgid "Create Invoice"
+msgstr "Loo arve"
+
+#. module: sale_margin
+#: selection:report.account.invoice,state:0
+#: selection:report.account.invoice.category,state:0
+#: selection:report.account.invoice.partner,state:0
+#: selection:report.account.invoice.partner.product,state:0
+#: selection:report.account.invoice.product,state:0
+msgid "Draft"
+msgstr "Mustand"
+
+#. module: sale_margin
+#: constraint:ir.actions.act_window:0
+msgid "Invalid model name in the action definition."
+msgstr "Vigane mudeli nimi toimingu definitsioonis."
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_all_month_product
+msgid "All Months"
+msgstr "Kõik kuud"
+
+#. module: sale_margin
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_partner_product_tree
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_partner_product_tree_all
+msgid "report.account.invoice.partner.product.tree"
+msgstr ""
+
+#. module: sale_margin
+#: field:report.account.invoice,type:0
+#: field:report.account.invoice.category,type:0
+#: field:report.account.invoice.partner,type:0
+#: field:report.account.invoice.partner.product,type:0
+#: field:report.account.invoice.product,type:0
+#: wizard_field:stock.invoice_onshipping,init,type:0
+msgid "Type"
+msgstr "Tüüp"
+
+#. module: sale_margin
+#: wizard_field:stock.invoice_onshipping,init,journal_id:0
+msgid "Destination Journal"
+msgstr "Sihtkoha päevik"
+
+#. module: sale_margin
+#: view:stock.picking:0
+msgid "Supplier Invoices"
+msgstr "Tarnija arved"
+
+#. module: sale_margin
+#: field:report.account.invoice.partner.product,product_id:0
+#: field:report.account.invoice.product,product_id:0
+msgid "Product"
+msgstr "Toode"
+
+#. module: sale_margin
+#: view:report.account.invoice.partner:0
+msgid "Invoices by partner"
+msgstr ""
+
+#. module: sale_margin
+#: view:report.account.invoice.category:0
+msgid "Invoices by category"
+msgstr "Arved kategooria järgi"
+
+#. module: sale_margin
+#: selection:report.account.invoice,state:0
+#: selection:report.account.invoice.category,state:0
+#: selection:report.account.invoice.partner,state:0
+#: selection:report.account.invoice.partner.product,state:0
+#: selection:report.account.invoice.product,state:0
+msgid "Paid"
+msgstr "Makstud"
+
+#. module: sale_margin
+#: model:ir.actions.wizard,name:sale_margin.wizard_picking_invoice_create
+#: wizard_button:stock.invoice_onshipping,init,create_invoice:0
+msgid "Create invoice"
+msgstr "Loo arve"
+
+#. module: sale_margin
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_category_tree
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_category_tree_all
+msgid "report.account.invoice.category.tree"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_all_invoice_by_partner_product
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_invoice_by_partner_product
+msgid "Invoices by Partner and Product"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.model,name:sale_margin.model_report_account_invoice_category
+msgid "report.account.invoice.category"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_this_month_product
+msgid "This Month"
+msgstr "See kuu"
+
+#. module: sale_margin
+#: field:report.account.invoice.category,categ_id:0
+msgid "Categories"
+msgstr "Kategooriad"
+
+#. module: sale_margin
+#: field:account.invoice.line,cost_price:0
+#: field:report.account.invoice,cost_price:0
+#: field:report.account.invoice.category,cost_price:0
+#: field:report.account.invoice.partner,cost_price:0
+#: field:report.account.invoice.partner.product,cost_price:0
+#: field:report.account.invoice.product,cost_price:0
+#: field:sale.order.line,purchase_price:0
+msgid "Cost Price"
+msgstr "Ostuhind"
+
+#. module: sale_margin
+#: wizard_field:stock.invoice_onshipping,init,group:0
+msgid "Group by partner"
+msgstr "Grupeeri partneri järgi"
+
+#. module: sale_margin
+#: model:ir.model,name:sale_margin.model_report_account_invoice_partner
+msgid "report.account.invoice.partner"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_all_invoice_by_partner
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_invoice_by_partner
+msgid "Invoices by Partner"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_all_invoice_by_category
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_invoice_by_category
+msgid "Invoices by Category"
+msgstr ""
+
+#. module: sale_margin
+#: view:report.account.invoice.partner.product:0
+msgid "Invoices by partner and product"
+msgstr ""
+
+#. module: sale_margin
+#: field:report.account.invoice,amount:0
+#: field:report.account.invoice.category,amount:0
+#: field:report.account.invoice.partner,amount:0
+#: field:report.account.invoice.partner.product,amount:0
+#: field:report.account.invoice.product,amount:0
+msgid "Amount"
+msgstr "Hulk"
+
+#. module: sale_margin
+#: wizard_field:stock.invoice_onshipping,init,invoice_date:0
+msgid "Invoiced date"
+msgstr "Arve kuupäeva"
+
+#. module: sale_margin
+#: selection:report.account.invoice,type:0
+#: selection:report.account.invoice.category,type:0
+#: selection:report.account.invoice.partner,type:0
+#: selection:report.account.invoice.partner.product,type:0
+#: selection:report.account.invoice.product,type:0
+msgid "Supplier Refund"
+msgstr "Tarnija tagasimakse"
+
+#. module: sale_margin
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_partner_tree
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_partner_tree_all
+msgid "report.account.invoice.partner.tree"
+msgstr ""
+
+#. module: sale_margin
+#: field:report.account.invoice,margin:0
+#: field:report.account.invoice.category,margin:0
+#: field:report.account.invoice.partner,margin:0
+#: field:report.account.invoice.partner.product,margin:0
+#: field:report.account.invoice.product,margin:0
+#: field:sale.order,margin:0
+#: field:sale.order.line,margin:0
+msgid "Margin"
+msgstr "Veeris"
+
+#. module: sale_margin
+#: field:report.account.invoice,quantity:0
+#: field:report.account.invoice.category,quantity:0
+#: field:report.account.invoice.partner,quantity:0
+#: field:report.account.invoice.partner.product,quantity:0
+#: field:report.account.invoice.product,quantity:0
+msgid "Quantity"
+msgstr "Kogus"
+
+#. module: sale_margin
+#: view:report.account.invoice.product:0
+msgid "Invoices by product"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.module.module,shortdesc:sale_margin.module_meta_information
+msgid "Margins in Sale Orders"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.model,name:sale_margin.model_report_account_invoice
+msgid "report.account.invoice"
+msgstr ""
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_all_invoice_by_invoices
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_invoice_by_invoices
+#: view:report.account.invoice:0
+#: view:stock.picking:0
+#: field:stock.picking,invoice_ids:0
+msgid "Invoices"
+msgstr "Arved"
+
+#. module: sale_margin
+#: selection:report.account.invoice,state:0
+#: selection:report.account.invoice.category,state:0
+#: selection:report.account.invoice.partner,state:0
+#: selection:report.account.invoice.partner.product,state:0
+#: selection:report.account.invoice.product,state:0
+msgid "Pro-forma"
+msgstr "Pro-forma"
+
+#. module: sale_margin
+#: field:report.account.invoice,name:0
+#: field:report.account.invoice.category,name:0
+#: field:report.account.invoice.partner,name:0
+#: field:report.account.invoice.partner.product,name:0
+#: field:report.account.invoice.product,name:0
+msgid "Month"
+msgstr "Kuu"
+
+#. module: sale_margin
+#: selection:report.account.invoice,state:0
+#: selection:report.account.invoice.category,state:0
+#: selection:report.account.invoice.partner,state:0
+#: selection:report.account.invoice.partner.product,state:0
+#: selection:report.account.invoice.product,state:0
+msgid "Canceled"
+msgstr "Katkestatud"
+
+#. module: sale_margin
+#: model:ir.ui.menu,name:sale_margin.menu_report_account_invoice_product
+msgid "Invoice"
+msgstr "Arve"
+
+#. module: sale_margin
+#: wizard_button:stock.invoice_onshipping,init,end:0
+msgid "Cancel"
+msgstr "Katkesta"
+
+#. module: sale_margin
+#: field:report.account.invoice.partner,partner_id:0
+#: field:report.account.invoice.partner.product,partner_id:0
+msgid "Partner"
+msgstr "Partner"
+
+#. module: sale_margin
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_tree
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_tree_all
+msgid "report.account.invoice.tree"
+msgstr ""
+
+#. module: sale_margin
+#: selection:report.account.invoice,state:0
+#: selection:report.account.invoice.category,state:0
+#: selection:report.account.invoice.partner,state:0
+#: selection:report.account.invoice.partner.product,state:0
+#: selection:report.account.invoice.product,state:0
+msgid "Open"
+msgstr "Ava"
+
+#. module: sale_margin
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_product_tree
+#: model:ir.actions.act_window,name:sale_margin.action_report_account_invoice_product_tree_all
+msgid "report.account.invoice.product.tree"
+msgstr ""
diff --git a/addons/sale_margin/sale_margin.py b/addons/sale_margin/sale_margin.py
index c390bf769e2..80bb542fa3d 100644
--- a/addons/sale_margin/sale_margin.py
+++ b/addons/sale_margin/sale_margin.py
@@ -26,6 +26,16 @@ class sale_order_line(osv.osv):
_name = "sale.order.line"
_inherit = "sale.order.line"
+ def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
+ uom=False, qty_uos=0, uos=False, name='', partner_id=False,
+ lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False):
+ res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
+ uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
+ lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag)
+ purchase_price = self.pool.get('product.product').browse(cr, uid, product).standard_price
+ res['value'].update({'purchase_price':purchase_price})
+ return res
+
def _product_margin(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for line in self.browse(cr, uid, ids):
diff --git a/addons/sale_margin/sale_margin_view.xml b/addons/sale_margin/sale_margin_view.xml
index 1b46a850df8..0b470ec824c 100644
--- a/addons/sale_margin/sale_margin_view.xml
+++ b/addons/sale_margin/sale_margin_view.xml
@@ -13,6 +13,31 @@
+
+
+ sale.order.line.margin.view.form
+ form
+ sale.order
+
+
+
+
+
+
+
+
+
+ sale.order.line.tree.margin.view.form
+ form
+ sale.order
+
+
+
+
+
+
+
+
sale.order.margin.view.treetree
@@ -24,7 +49,7 @@
-
+
sale.order.margin.line.view.treetree
@@ -42,7 +67,7 @@
picking.margin.view.formformstock.picking
-
+
diff --git a/addons/scrum/scrum.py b/addons/scrum/scrum.py
index 40f17319df7..bcd67c757c4 100644
--- a/addons/scrum/scrum.py
+++ b/addons/scrum/scrum.py
@@ -108,7 +108,7 @@ class scrum_sprint(osv.osv):
'date_stop': fields.date('Ending Date', required=True),
'project_id': fields.many2one('project.project', 'Project', required=True, domain=[('scrum','=',1)], help="If you have [?] in the project name, it means there are no analytic account linked to this project."),
'product_owner_id': fields.many2one('res.users', 'Product Owner', required=True,help="The person who is responsible for the product"),
- 'scrum_master_id': fields.many2one('res.users', 'Scrum Manager', required=True,help="The person who is maintains the processes for the product"),
+ 'scrum_master_id': fields.many2one('res.users', 'Scrum Master', required=True,help="The person who is maintains the processes for the product"),
'meeting_ids': fields.one2many('scrum.meeting', 'sprint_id', 'Daily Scrum'),
'review': fields.text('Sprint Review'),
'retrospective': fields.text('Sprint Retrospective'),
@@ -308,9 +308,9 @@ class scrum_meeting(osv.osv):
if context is None:
context = {}
meeting_id = self.browse(cr, uid, ids)[0]
- email = meeting_id.sprint_id.scrum_master_id.user_email
- if email:
- self.email_send(cr, uid, ids, email, context=context)
+ user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
+ if meeting_id and meeting_id.sprint_id.scrum_master_id.user_email:
+ self.email_send(cr, uid, ids, meeting_id.sprint_id.scrum_master_id.user_email)
else:
raise osv.except_osv(_('Error !'), _('Please provide email address for scrum master defined on sprint.'))
return True
@@ -320,9 +320,8 @@ class scrum_meeting(osv.osv):
context = {}
context.update({'button_send_product_owner': True})
meeting_id = self.browse(cr, uid, ids)[0]
- email = meeting_id.sprint_id.product_owner_id.user_email
- if email:
- self.email_send(cr, uid, ids, email, context=context)
+ if meeting_id.sprint_id.product_owner_id.user_email:
+ self.email_send(cr,uid,ids,meeting_id.sprint_id.product_owner_id.user_email)
else:
raise osv.except_osv(_('Error !'), _('Please provide email address for product owner defined on sprint.'))
return True
diff --git a/addons/scrum/scrum_view.xml b/addons/scrum/scrum_view.xml
index d6a63d4eae6..db4d5d7af81 100644
--- a/addons/scrum/scrum_view.xml
+++ b/addons/scrum/scrum_view.xml
@@ -34,7 +34,7 @@
tree
-
+
@@ -152,7 +152,12 @@
domain="[('sprint_id','=',False)]"
help="Backlogs Not Assigned To Sprints."/>
-
+
+
+
@@ -161,7 +166,10 @@
-
+
+
+
+
diff --git a/addons/stock/i18n/es.po b/addons/stock/i18n/es.po
index 4b8113738fd..3b8da43d1c7 100644
--- a/addons/stock/i18n/es.po
+++ b/addons/stock/i18n/es.po
@@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-06-24 03:46+0000\n"
+"X-Launchpad-Export-Date: 2010-06-26 03:57+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: stock
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 2442320d3ba..cf3026494aa 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -408,7 +408,7 @@ stock_location()
class stock_tracking(osv.osv):
_name = "stock.tracking"
- _description = "Stock Tracking Lots"
+ _description = "Packs"
def checksum(sscc):
salt = '31' * 8 + '3'
@@ -424,7 +424,7 @@ class stock_tracking(osv.osv):
_columns = {
'name': fields.char('Tracking ID', size=64, required=True),
- 'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the tracking lots without removing it."),
+ 'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the pack without removing it."),
'serial': fields.char('Reference', size=64),
'move_ids': fields.one2many('stock.move', 'tracking_id', 'Moves Tracked'),
'date': fields.datetime('Created Date', required=True),
@@ -535,10 +535,10 @@ class stock_picking(osv.osv):
seq_obj_name = 'stock.picking.' + vals['type']
vals['name'] = self.pool.get('ir.sequence').get(cr, user, seq_obj_name)
type_list = {
- 'out':_('Packing List'),
+ 'out':_('Picking List'),
'in':_('Reception'),
- 'internal': _('Internal picking'),
- 'delivery': _('Delivery order')
+ 'internal': _('Internal Picking'),
+ 'delivery': _('Delivery Order')
}
new_id = super(stock_picking, self).create(cr, user, vals, context)
if not vals.get('auto_picking', False):
@@ -711,7 +711,7 @@ class stock_picking(osv.osv):
"""
for pick in self.browse(cr, uid, ids, context=context):
type_list = {
- 'out':'Packing List',
+ 'out':'Picking List',
'in':'Reception',
'internal': 'Internal picking',
'delivery': 'Delivery order'
@@ -1007,6 +1007,18 @@ class stock_picking(osv.osv):
}, context=context)
return res
+ def test_done(self, cr, uid, ids, context={}):
+ ok = False
+ for pick in self.browse(cr, uid, ids, context=context):
+ if not pick.move_lines:
+ return True
+ for move in pick.move_lines:
+ if move.state not in ('cancel','done'):
+ return False
+ if move.state=='done':
+ ok = True
+ return ok
+
def test_cancel(self, cr, uid, ids, context={}):
""" Test whether the move lines are canceled or not.
@return: True or False
@@ -1298,7 +1310,7 @@ class stock_move(osv.osv):
return (res and res[0]) or False
_name = "stock.move"
_description = "Stock Move"
- _order = 'date_planned desc'
+ _order = 'date_expected desc, id'
_log_create = False
def name_get(self, cr, uid, ids, context={}):
@@ -1352,7 +1364,7 @@ class stock_move(osv.osv):
'address_id': fields.many2one('res.partner.address', 'Dest. Address', help="Address where goods are to be delivered"),
'prodlot_id': fields.many2one('stock.production.lot', 'Production Lot', help="Production lot is used to put a serial number on the production"),
- 'tracking_id': fields.many2one('stock.tracking', 'Tracking Lot', select=True, help="Tracking lot is the code that will be put on the logistical unit/pallet"),
+ 'tracking_id': fields.many2one('stock.tracking', 'Pack', select=True, help="This is the code that will be put on the logistical unit: pallet, box, pack."),
# 'lot_id': fields.many2one('stock.lot', 'Consumer lot', select=True, readonly=True),
'auto_validate': fields.boolean('Auto Validate'),
@@ -1834,11 +1846,10 @@ class stock_move(osv.osv):
for id in ids:
wf_service.trg_trigger(uid, 'stock.move', id, cr)
- # We should remove this
picking_obj = self.pool.get('stock.picking')
- for pick in picking_obj.browse(cr, uid, picking_ids):
- if len([(move.state in ('done','cancelled')) for move in pick.move_lines]) == len(pick.move_lines):
- picking_obj.action_done(cr, uid, [pick.id])
+ wf_service = netsvc.LocalService("workflow")
+ for pick_id in picking_ids:
+ wf_service.trg_write(uid, 'stock.picking', pick_id, cr)
for (id,name) in picking_obj.name_get(cr, uid, picking_ids):
message = _('Document') + " '" + name + "' "+ _("is processed")
diff --git a/addons/stock/stock_sequence.xml b/addons/stock/stock_sequence.xml
index 9c5083d13b4..06d898c6637 100644
--- a/addons/stock/stock_sequence.xml
+++ b/addons/stock/stock_sequence.xml
@@ -61,11 +61,11 @@
Sequences from tracking numbers
-->
- Stock Production Lots
+ Production Lotsstock.lot.serial
- Stock Production Lots
+ Production Lotsstock.lot.serial7
@@ -74,12 +74,12 @@
- Stock Tracking Lots
+ Packsstock.lot.tracking
- Stock Tracking Lots
+ Packsstock.lot.tracking7
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index 11d89996c60..3128b3592ed 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -154,7 +154,7 @@
stock.trackingform
-