From 59f9be67f791f40d698b7183b81f7a7abc34a654 Mon Sep 17 00:00:00 2001 From: "Harry (OpenERP)" Date: Fri, 25 Jun 2010 01:23:32 +0530 Subject: [PATCH 1/7] [IMP] mail_gateway: * introduce 'email.server.tools' to process_email and send acknowdgement after creating new record * use 'email.server.tools' model in script and fetchmail module to processing email * start mailgateway services on crm.lead, project.issue, hr.applicant bzr revid: hmo@tinyerp.com-20100624195332-7qci6vrimvzple5w --- addons/crm/__init__.py | 1 - addons/crm/crm_lead.py | 127 ++++++ addons/crm/crm_mailgate.py | 172 -------- addons/crm/security/ir.model.access.csv | 3 +- addons/fetchmail/__openerp__.py | 2 +- addons/fetchmail/fetchmail.py | 410 +++--------------- addons/fetchmail/fetchmail_view.xml | 72 +-- addons/fetchmail/security/ir.model.access.csv | 2 - addons/hr_recruitment/hr_recruitment.py | 130 ++++++ addons/mail_gateway/mail_gateway.py | 348 ++++++++++++++- addons/mail_gateway/mail_gateway_view.xml | 73 +++- .../openerp_mailgate/openerp_mailgate.py | 395 +---------------- addons/project_issue/project_issue.py | 127 ++++++ 13 files changed, 880 insertions(+), 982 deletions(-) delete mode 100644 addons/crm/crm_mailgate.py 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/crm_lead.py b/addons/crm/crm_lead.py index e5e1c92daef..2700581d6cc 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -27,6 +27,9 @@ 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 """ @@ -235,6 +238,130 @@ and users by email"), } return value + 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) + + + 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 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) + values['priority'] = thread.priority + + res[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 + crm_lead() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/crm/crm_mailgate.py b/addons/crm/crm_mailgate.py deleted file mode 100644 index d39293e4716..00000000000 --- a/addons/crm/crm_mailgate.py +++ /dev/null @@ -1,172 +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/security/ir.model.access.csv b/addons/crm/security/ir.model.access.csv index 8befbd8c084..595e63736bf 100644 --- a/addons/crm/security/ir.model.access.csv +++ b/addons/crm/security/ir.model.access.csv @@ -30,9 +30,8 @@ "access_crm_lead2opportunity_partner","crm.lead2opportunity.partner","model_crm_lead2opportunity_partner","crm.group_crm_user",1,1,1,1 "access_crm_installer","crm.installer.rule","model_crm_installer","base.group_system",1,1,1,1 "access_crm_lead_forward_to_partner","crm.lead.forward.to.partner","model_crm_lead_forward_to_partner","crm.group_crm_user",1,1,1,1 -"access_mailgate_thread","mailgate.thread","model_mailgate_thread","crm.group_crm_user",1,1,1,1 "access_res_partner","res.partner.crm.user","base.model_res_partner","crm.group_crm_user",1,0,0,0 "access_res_partner_address","res.partner.address.crm.user","base.model_res_partner_address","crm.group_crm_user",1,0,0,0 "access_res_partner_category","res.partner.category.crm.user","base.model_res_partner_category","crm.group_crm_user",1,0,0,0 "mail_gateway_mailgate_message","mail_gateway.mailgate.message","mail_gateway.model_mailgate_message","crm.group_crm_user",1,1,1,1 -"mail_gateway_mailgate_thread","mail_gateway.mailgate.thread","model_mailgate_thread","crm.group_crm_user",1,1,1,1 +"mail_gateway_mailgate_thread","mail_gateway.mailgate.thread","mail_gateway.model_mailgate_thread","crm.group_crm_user",1,1,1,1 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..14981c13837 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'), + ], '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), } _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,41 @@ 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={}): + 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)) - + count = 0 try: if server.type == 'imap': @@ -363,17 +120,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)') 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, server_id=server.id, server_type=server.type, 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 +143,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 +154,38 @@ 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, server_id=server.id, server_type=server.type, 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'), + ], 'State', select=True, readonly=True), } _order = 'id desc' - -mail_server_history() -class fetchmail_tool(osv.osv): +mailgate_message() - _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 - - return res - -fetchmail_tool() +# 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 - -
- + + mailgate.message.tree + mailgate.message + tree + + + - - - - - - - - - - - - - - - - -
- + + + + + res_model="mailgate.message" src_model="email.server"/> - + Received Email History - mail.server.history + mailgate.message form tree,form - + {'type':'imap'} [('type','=','imap')] + id="menu_action_mailgate_message_tree" + action="action_mailgate_message_tree"/> - + Received Email History - mail.server.history + mailgate.message form tree,form - + {'type':'pop'} [('type','=','pop')] + id="menu_action_mailgate_message_tree_pop" + action="action_mailgate_message_tree_pop"/> diff --git a/addons/fetchmail/security/ir.model.access.csv b/addons/fetchmail/security/ir.model.access.csv index 907aa187913..7aa6c84d22b 100644 --- a/addons/fetchmail/security/ir.model.access.csv +++ b/addons/fetchmail/security/ir.model.access.csv @@ -1,4 +1,2 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" "access_email_server","email.server","model_email_server",,1,1,1,1 -"access_mail_server_history","mail.server.history","model_mail_server_history",,1,1,1,1 -"access_email_server_tools","email.server.tools","model_email_server_tools",,1,1,1,1 diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index cf194a60bb4..9d6c2cfbbbb 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -21,6 +21,11 @@ from osv import fields, osv from crm import crm +import tools +import collections +import binascii +import tools +from tools.translate import _ AVAILABLE_STATES = [ ('draft', 'New'), @@ -240,6 +245,131 @@ class hr_applicant(osv.osv, crm.crm_case): context.update({'survey_id': record.survey.id, 'response_id' : [record.response], 'response_no':0, }) value = self.pool.get("survey").action_print_survey(cr, uid, ids, context) return value + + 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) + + + 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 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) + values['priority'] = thread.priority + + res[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 + hr_applicant() class hr_job(osv.osv): diff --git a/addons/mail_gateway/mail_gateway.py b/addons/mail_gateway/mail_gateway.py index 7a7c00c9deb..edb723a3ba0 100644 --- a/addons/mail_gateway/mail_gateway.py +++ b/addons/mail_gateway/mail_gateway.py @@ -27,6 +27,7 @@ import email from email.header import decode_header import base64 import re +from tools.translate import _ class mailgate_thread(osv.osv): ''' @@ -37,14 +38,24 @@ class mailgate_thread(osv.osv): _rec_name = 'thread' _columns = { - 'thread': fields.char('Thread', size=32, required=False), - 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True)], readonly=True), - 'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False)], readonly=True), - 'model': fields.char('Model Name', size=64, required=False), - 'res_id': fields.integer('Resource ID'), - } - - def _history(self, cr, uid, cases, keyword, history=False, subject=None, email=False, details=None, email_from=False, message_id=False, attach=None, context=None): + 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True)]), + 'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False)]), + } + + def message_new(self, cr, uid, msg, context): + raise Exception, _('Method is not implemented') + + def message_update(self, cr, uid, ids, vals={}, msg="", default_act='pending', context={}): + raise Exception, _('Method is not implemented') + + def emails_get(self, cr, uid, ids, context=None): + raise Exception, _('Method is not implemented') + + def msg_send(self, cr, uid, id, *args, **argv): + raise Exception, _('Method is not implemented') + + def _history(self, cr, uid, cases, keyword, history=False, subject=None, email=False, details=None, \ + email_from=False, message_id=False, references=None, attach=None, context=None): """ @param self: The object pointer @param cr: the current row, from the database cursor, @@ -98,6 +109,7 @@ class mailgate_thread(osv.osv): (hasattr(case, 'user_id') and case.user_id and case.user_id.address_id and \ case.user_id.address_id.email) or tools.config.get('email_from', False), 'partner_id': hasattr(case, 'partner_id') and (case.partner_id and case.partner_id.id or False) or False, + 'references': references, 'message_id': message_id, 'attachment_ids': [(6, 0, attachments)] } @@ -125,7 +137,8 @@ class mailgate_message(osv.osv): 'email_to': fields.char('Email To', size=84), 'email_cc': fields.char('Email CC', size=84), 'email_bcc': fields.char('Email BCC', size=84), - 'message_id': fields.char('Message Id', size=1024, readonly=True, help="Message Id on Email Server.", select=True), + 'message_id': fields.char('Message Id', size=1024, readonly=True, help="Message Id on Email.", select=True), + 'references': fields.text('References', readonly=True, help="Referencess emails."), 'description': fields.text('Description'), 'partner_id': fields.many2one('res.partner', 'Partner', required=False), 'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments'), @@ -133,3 +146,320 @@ class mailgate_message(osv.osv): mailgate_message() +class mailgate_tool(osv.osv_memory): + + _name = 'email.server.tools' + _description = "Email Server Tools" + + 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 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 history(self, cr, uid, model, res_ids, msg, attach): + """This function creates history for mails fetched + @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 model: OpenObject Model + @param res_ids: Ids of the record of OpenObject model created + @param msg: Email details + @param attach: Email attachments + """ + if isinstance(res_ids, (int, long)): + res_ids = [res_ids] + + msg_pool = self.pool.get('mailgate.message') + for res_id in res_ids: + msg_data = { + 'name': msg.get('subject', 'No subject'), + 'date': msg.get('date') , + 'description': msg.get('body', msg.get('from')), + 'history': True, + 'res_model': model, + 'email_cc': msg.get('cc'), + 'email_from': msg.get('from'), + 'email_to': msg.get('to'), + 'message_id': msg.get('message-id'), + 'references': msg.get('references'), + 'res_id': res_id, + 'user_id': uid, + 'attachment_ids': [(6, 0, attach)] + } + msg_id = msg_pool.create(cr, uid, msg_data) + return True + + def email_send(self, cr, uid, model, res_id, msg, from_email=False, email_default=False): + """This function Sends return email on submission of Fetched email in OpenERP database + @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 model: OpenObject Model + @param res_id: Id of the record of OpenObject model created from the Email details + @param msg: Email details + @param email_default: Default Email address in case of any Problem + """ + history_pool = self.pool.get('mailgate.message') + model_pool = self.pool.get(model) + from_email = from_email or tools.config.get('email_from', None) + message = email.message_from_string(str(msg)) + subject = "[%s] %s" %(res_id, self._decode_header(message['Subject'])) + #msg_mails = [] + #mails = [self._decode_header(message['From']), self._decode_header(message['To'])] + #mails += self._decode_header(message.get('Cc', '')).split(',') + + values = {} + if hasattr(model_pool, 'emails_get'): + values = model_pool.emails_get(cr, uid, [res_id]) + emails = values.get(res_id, {}) + + priority = emails.get('priority', [3])[0] + em = emails['user_email'] + emails['email_from'] + emails['email_cc'] + msg_mails = map(self.to_email, filter(None, em)) + + #mm = [self._decode_header(message['From']), self._decode_header(message['To'])] + #mm += self._decode_header(message.get('Cc', '')).split(',') + + #msg_mails = map(self.to_email, filter(None, mm)) + + encoding = message.get_content_charset() + message['body'] = message.get_payload(decode=True) + if encoding: + message['body'] = tools.ustr(message['body'].decode(encoding)) + + body = _(""" +Hello %s, + + Your Request ID: %s + +Thanks + +-------- Original Message -------- +%s +""") %(self._decode_header(message['From']), res_id, message['body']) + res = None + try: + res = tools.email_send(from_email, msg_mails, subject, body, openobject_id=res_id) + except Exception, e: + if email_default: + temp_msg = '[%s] %s'%(res_id, self._decode_header(message['Subject'])) + del message['Subject'] + message['Subject'] = '[OpenERP-FetchError] %s' %(temp_msg) + tools.email_send(from_email, email_default, message.get('Subject'), message.get('body'), openobject_id=res_id) + return res + + def process_email(self, cr, uid, model, message, attach=True, context=None): + """This function Processes email and create record for given OpenERP model + @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 model: OpenObject Model + @param message: Email details + @param attach: Email attachments + @param context: A standard dictionary for contextual values""" + + model_pool = self.pool.get(model) + if not context: + context = {} + res_id = False + # Create New Record into particular model + def create_record(msg): + if hasattr(model_pool, 'message_new'): + res_id = model_pool.message_new(cr, uid, msg, context) + else: + data = { + 'name': msg.get('subject'), + 'email_from': msg.get('from'), + 'email_cc': msg.get('cc'), + 'user_id': False, + 'description': msg.get('body'), + 'state' : 'draft', + } + data.update(self.get_partner(cr, uid, msg.get('from'), context=context)) + res_id = model_pool.create(cr, uid, data, context=context) + + att_ids = [] + if attach: + for attachment in msg.get('attachments', []): + data_attach = { + 'name': attachment, + 'datas': binascii.b2a_base64(str(attachments.get(attachment))), + 'datas_fname': attachment, + 'description': 'Mail attachment', + 'res_model': model, + 'res_id': res_id, + } + att_ids.append(self.pool.get('ir.attachment').create(cr, uid, data_attach)) + + return res_id + + history_pool = self.pool.get('mailgate.message') + 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 + + if 'Subject' in fields: + msg['subject'] = self._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'] = self._decode_header(msg_txt.get('From')) + + if 'Delivered-To' in fields: + msg['to'] = self._decode_header(msg_txt.get('Delivered-To')) + + if 'Cc' in fields: + msg['cc'] = self._decode_header(msg_txt.get('Cc')) + + if 'Reply-To' in fields: + msg['reply'] = self._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-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'] = tools.ustr(msg['body']) + + attachments = {} + 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 : + attachments[filename] = content + else: + if encoding: + content = unicode(content, encoding) + if part.get_content_subtype() == 'html': + body = tools.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 : + attachments[filename] = part.get_payload(decode=True) + else: + res = part.get_payload(decode=True) + if encoding: + res = tools.ustr(res) + + body += res + + msg['body'] = body + msg['attachments'] = attachments + res_ids = [] + new_res_id = False + if msg.get('references', False): + references = msg.get('references') + if '\r\n' in references: + references = msg.get('references').split('\r\n') + else: + references = msg.get('references').split(' ') + for ref in references: + ref = ref.strip() + res_id = tools.misc.reference_re.search(ref) + if res_id: + res_id = res_id.group(1) + else: + res_id = tools.misc.res_re.search(msg['subject']) + if res_id: + res_id = res_id.group(1) + if res_id: + res_id = int(res_id) + res_ids.append(res_id) + model_pool = self.pool.get(model) + + vals = {} + if hasattr(model_pool, 'message_update'): + model_pool.message_update(cr, uid, [res_id], vals, msg, context=context) + + if not len(res_ids): + new_res_id = create_record(msg) + res_ids = [new_res_id] + # Store messages + if hasattr(model_pool, '_history'): + model_pool._history(cr, uid, res_ids, _('Receive'), history=True, + subject = msg.get('subject'), + email = msg.get('to'), + details = msg.get('body'), + email_from = msg.get('from'), + message_id = msg.get('message-id'), + references = msg.get('references', False), + attach = msg.get('attachments', {}).items(), + context = {'model' : model}) + else: + self.history(cr, uid, model, res_ids, msg, att_ids) + return new_res_id + + def get_partner(self, cr, uid, from_email, context=None): + """This function returns partner Id based on email passed + @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 + """ + address_pool = self.pool.get('res.partner.address') + res = { + 'partner_address_id': False, + 'partner_id': False + } + from_email = self.to_email(from_email) + address_ids = address_pool.search(cr, uid, [('email', '=', from_email)]) + if address_ids: + address = address_pool.browse(cr, uid, address_ids[0]) + res['partner_address_id'] = address_ids[0] + res['partner_id'] = address.partner_id.id + + return res + +mailgate_tool() + + diff --git a/addons/mail_gateway/mail_gateway_view.xml b/addons/mail_gateway/mail_gateway_view.xml index 95dce8054c1..09a24f92772 100644 --- a/addons/mail_gateway/mail_gateway_view.xml +++ b/addons/mail_gateway/mail_gateway_view.xml @@ -29,7 +29,7 @@ - + @@ -76,28 +76,30 @@ form
- + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -163,10 +165,33 @@ - Mailgateway Threads - mailgate.thread + Mailgateway Threads + mailgate.thread + tree,form + form + + + + + + tree + + + + + + form + + + + + + + Mailgateway Messages + mailgate.message tree,form form + [('history', '=', True)] @@ -195,4 +220,4 @@ /> - \ No newline at end of file + diff --git a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py index b9a9eefee15..f294c819c78 100755 --- a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py +++ b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py @@ -21,104 +21,15 @@ # ########################################################################################### -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 @@ -130,296 +41,28 @@ class email_parser(object): def __init__(self, uid, password, model, email, email_default, dbname, host, port): self.rpc = rpc_proxy(uid, password, host=host, port=port, dbname=dbname) try: + self.model_id = int(model) self.model = str(model) 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, { - 'res_model' : self.model, - '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, - } - ) - ] - } - 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, ) - - 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 = { - 'res_model' : self.model, - '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) - if case_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 = 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) - - 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, emails + res_id = self.rpc('email.server.tools', 'process_email', self.model, message) + except Exception, e: + res_id = False + +# Reply mail + if res_id: + self.rpc('email.server.tools', 'email_send', self.model, res_id, message, self.email, self.email_default) + + return res_id if __name__ == '__main__': parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.0') @@ -442,7 +85,7 @@ if __name__ == '__main__': parser = email_parser(options.userid, options.password, options.model, options.email, 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) diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index 5a709876f1a..3523485f542 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -31,6 +31,9 @@ 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" @@ -299,5 +302,129 @@ 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) + + + 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 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) + values['priority'] = thread.priority + + res[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 + project_issue() From 42976fd6e2d6f516ff03bccb0bc7e38f23d144fb Mon Sep 17 00:00:00 2001 From: Launchpad Code Hosting Date: Fri, 25 Jun 2010 04:47:37 +0100 Subject: [PATCH 2/7] Launchpad automatic translations update. bzr revid: codehost@crowberry-20100625034737-r4w1elrpti0szvhi --- addons/account/i18n/es.po | 11 +- addons/account/i18n/gl.po | 10 +- addons/account/i18n/zh_CN.po | 2 +- addons/account_budget/i18n/es.po | 2 +- addons/account_coda/i18n/es.po | 167 ++++++++++++++++++ addons/account_payment/i18n/es.po | 2 +- addons/auction/i18n/el.po | 187 +++++++++++---------- addons/audittrail/i18n/el.po | 68 ++++---- addons/base_module_quality/i18n/el.po | 2 +- addons/base_module_quality/i18n/es.po | 2 +- addons/base_report_creator/i18n/el.po | 2 +- addons/board_association/i18n/el.po | 2 +- addons/board_auction/i18n/el.po | 2 +- addons/board_crm_configuration/i18n/el.po | 2 +- addons/board_document/i18n/el.po | 2 +- addons/board_project/i18n/el.po | 2 +- addons/crm/i18n/es.po | 2 +- addons/crm_profiling/i18n/el.po | 2 +- addons/document/i18n/el.po | 2 +- addons/document/i18n/es.po | 2 +- addons/document_webdav/i18n/el.po | 2 +- addons/event_project/i18n/el.po | 88 ++++++++++ addons/hr/i18n/el.po | 2 +- addons/hr_contract/i18n/el.po | 2 +- addons/hr_expense/i18n/el.po | 2 +- addons/hr_holidays/i18n/el.po | 2 +- addons/hr_timesheet_invoice/i18n/es.po | 2 +- addons/hr_timesheet_sheet/i18n/el.po | 2 +- addons/mrp/i18n/zh_CN.po | 2 +- addons/mrp_operations/i18n/es.po | 2 +- addons/olap/i18n/es.po | 2 +- addons/point_of_sale/i18n/es.po | 2 +- addons/project/i18n/es.po | 2 +- addons/project_timesheet/i18n/es.po | 2 +- addons/report_analytic_planning/i18n/es.po | 2 +- addons/report_task/i18n/es.po | 2 +- addons/sale/i18n/es.po | 2 +- addons/stock/i18n/es.po | 2 +- addons/stock_location/i18n/es.po | 2 +- 39 files changed, 432 insertions(+), 165 deletions(-) create mode 100644 addons/account_coda/i18n/es.po create mode 100644 addons/event_project/i18n/el.po diff --git a/addons/account/i18n/es.po b/addons/account/i18n/es.po index 4779ae32dd5..fdc62db3d1b 100644 --- a/addons/account/i18n/es.po +++ b/addons/account/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: 2010-06-23 17:24+0000\n" -"Last-Translator: Jordi Esteve (www.zikzakmedia.com) " -"\n" +"PO-Revision-Date: 2010-06-24 10:03+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-24 03:47+0000\n" +"X-Launchpad-Export-Date: 2010-06-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: account @@ -806,7 +805,7 @@ msgstr "Cuenta de la empresa" #. module: account #: wizard_view:account.subscription.generate,init:0 msgid "Generate entries before:" -msgstr "Generar asientos antes:" +msgstr "Generar asientos hasta:" #. module: account #: rml:account.analytic.account.cost_ledger:0 @@ -3680,7 +3679,7 @@ msgstr "" #: wizard_field:account.invoice.pay,addendum,comment:0 #: wizard_field:account.invoice.pay,init,name:0 msgid "Entry Name" -msgstr "Núm. asiento" +msgstr "Descripción" #. module: account #: help:account.invoice,account_id:0 diff --git a/addons/account/i18n/gl.po b/addons/account/i18n/gl.po index 9ae3edbd1f1..4ec34c15268 100644 --- a/addons/account/i18n/gl.po +++ b/addons/account/i18n/gl.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-05-14 17:04+0000\n" +"PO-Revision-Date: 2010-06-24 09:57+0000\n" "Last-Translator: Borja López Soilán (Pexego) \n" "Language-Team: Galician \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:04+0000\n" +"X-Launchpad-Export-Date: 2010-06-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: account @@ -2047,7 +2047,7 @@ msgstr "" #. module: account #: field:account.journal,invoice_sequence_id:0 msgid "Invoice Sequence" -msgstr "" +msgstr "Secuencia de factura" #. module: account #: wizard_view:account.automatic.reconcile,init:0 @@ -3597,7 +3597,7 @@ msgstr "" #: wizard_field:account.invoice.pay,addendum,comment:0 #: wizard_field:account.invoice.pay,init,name:0 msgid "Entry Name" -msgstr "" +msgstr "Descripción" #. module: account #: help:account.invoice,account_id:0 @@ -5064,7 +5064,7 @@ msgstr "" #. module: account #: model:ir.model,name:account.model_fiscalyear_seq msgid "Maintains Invoice sequences with Fiscal Year" -msgstr "" +msgstr "Mantén secuencias de facturas con exercicio fiscal" #. module: account #: selection:account.account.balance.report,checktype,display_account:0 diff --git a/addons/account/i18n/zh_CN.po b/addons/account/i18n/zh_CN.po index 99660f05218..6f4caf1c7b8 100644 --- a/addons/account/i18n/zh_CN.po +++ b/addons/account/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:47+0000\n" +"X-Launchpad-Export-Date: 2010-06-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: account diff --git a/addons/account_budget/i18n/es.po b/addons/account_budget/i18n/es.po index 22fe5f58d28..fbb0fb4d22e 100644 --- a/addons/account_budget/i18n/es.po +++ b/addons/account_budget/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: account_budget diff --git a/addons/account_coda/i18n/es.po b/addons/account_coda/i18n/es.po new file mode 100644 index 00000000000..f8fd451970f --- /dev/null +++ b/addons/account_coda/i18n/es.po @@ -0,0 +1,167 @@ +# Spanish 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-24 13:11+0000\n" +"PO-Revision-Date: 2010-06-24 09:42+0000\n" +"Last-Translator: Borja López Soilán (Pexego) \n" +"Language-Team: Spanish \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-25 03:47+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#. module: account_coda +#: field:account.coda,journal_id:0 +#: wizard_field:account.coda_import,init,journal_id:0 +msgid "Bank Journal" +msgstr "Diario bancario" + +#. module: account_coda +#: constraint:ir.model:0 +msgid "" +"The Object name must start with x_ and not contain any special character !" +msgstr "" +"¡El objeto debe empezar con x_ y no puede contener ningún carácter especial!" + +#. module: account_coda +#: wizard_field:account.coda_import,extraction,note:0 +msgid "Log" +msgstr "Registro" + +#. module: account_coda +#: wizard_button:account.coda_import,extraction,open:0 +msgid "_Open Statement" +msgstr "" + +#. module: account_coda +#: model:ir.module.module,shortdesc:account_coda.module_meta_information +msgid "Account CODA" +msgstr "" + +#. module: account_coda +#: field:account.coda,name:0 +msgid "Coda file" +msgstr "" + +#. module: account_coda +#: wizard_view:account.coda_import,init:0 +msgid "Clic on 'New' to select your file :" +msgstr "" + +#. module: account_coda +#: model:ir.actions.wizard,name:account_coda.wizard_account_coda_import +msgid "Import Coda File" +msgstr "" + +#. module: account_coda +#: constraint:ir.actions.act_window:0 +msgid "Invalid model name in the action definition." +msgstr "Nombre de modelo inválido en la definición de acción." + +#. module: account_coda +#: field:account.coda,note:0 +msgid "Import log" +msgstr "Registro de importación" + +#. module: account_coda +#: wizard_field:account.coda_import,init,def_receivable:0 +msgid "Default receivable Account" +msgstr "Cuenta a recibir por defecto" + +#. module: account_coda +#: model:ir.module.module,description:account_coda.module_meta_information +msgid "" +"Module provides functionality to import\n" +" bank statements from .csv file.\n" +" Import coda file wizard is used to import bank statements." +msgstr "" + +#. module: account_coda +#: wizard_button:account.coda_import,extraction,end:0 +msgid "_Close" +msgstr "_Cerrar" + +#. module: account_coda +#: field:account.coda,statement_id:0 +msgid "Generated Bank Statement" +msgstr "Extracto bancario generado" + +#. module: account_coda +#: view:account.coda:0 +#: model:ir.actions.act_window,name:account_coda.act_account_payment_account_bank_statement +#: model:ir.actions.act_window,name:account_coda.action_account_coda +msgid "Coda import" +msgstr "" + +#. module: account_coda +#: field:account.coda,user_id:0 +msgid "User" +msgstr "Usuario" + +#. module: account_coda +#: constraint:ir.ui.view:0 +msgid "Invalid XML for View Architecture!" +msgstr "¡XML inválido para la estructura de la vista!" + +#. module: account_coda +#: model:ir.model,name:account_coda.model_account_coda +msgid "coda for an Account" +msgstr "" + +#. module: account_coda +#: wizard_field:account.coda_import,init,def_payable:0 +msgid "Default Payable Account" +msgstr "Cuenta a pagar por defecto" + +#. module: account_coda +#: model:ir.ui.menu,name:account_coda.menu_account_coda +msgid "Coda Statements" +msgstr "" + +#. module: account_coda +#: model:ir.ui.menu,name:account_coda.menu_account_coda_wizard +msgid "Import Coda Statements" +msgstr "" + +#. module: account_coda +#: wizard_button:account.coda_import,init,extraction:0 +msgid "_Ok" +msgstr "_Aceptar" + +#. module: account_coda +#: wizard_view:account.coda_import,extraction:0 +#: wizard_view:account.coda_import,init:0 +msgid "Import Coda Statement" +msgstr "" + +#. module: account_coda +#: field:account.bank.statement,coda_id:0 +msgid "Coda" +msgstr "" + +#. module: account_coda +#: wizard_view:account.coda_import,extraction:0 +msgid "Results :" +msgstr "Resultados :" + +#. module: account_coda +#: wizard_field:account.coda_import,init,coda:0 +msgid "Coda File" +msgstr "" + +#. module: account_coda +#: field:account.coda,date:0 +msgid "Import Date" +msgstr "Fecha de importación" + +#. module: account_coda +#: wizard_view:account.coda_import,init:0 +msgid "Select your bank journal :" +msgstr "Seleccione su diario bancario :" diff --git a/addons/account_payment/i18n/es.po b/addons/account_payment/i18n/es.po index 96b1e86eeb9..0248b3f62c5 100644 --- a/addons/account_payment/i18n/es.po +++ b/addons/account_payment/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: account_payment diff --git a/addons/auction/i18n/el.po b/addons/auction/i18n/el.po index ee0853b10fc..6e0265c94c5 100644 --- a/addons/auction/i18n/el.po +++ b/addons/auction/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:48+0000\n" +"PO-Revision-Date: 2010-06-24 22:06+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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: auction @@ -182,7 +182,7 @@ msgstr "ΦΠΑ" #. module: auction #: view:auction.lots:0 msgid "Statements" -msgstr "" +msgstr "Καταστάσεις" #. module: auction #: xsl:flagey.huissier:0 @@ -244,33 +244,34 @@ msgstr "Σύγχρονη Τέχνη" #: view:auction.lots:0 #: view:report.unclassified.objects:0 msgid "Ref" -msgstr "" +msgstr "Αναφορά" #. module: auction #: field:report.auction.view,nseller:0 msgid "No of sellers" -msgstr "" +msgstr "Αριθμός πωλητών" #. module: auction #: selection:auction.lots.send.aie,date_ask,lang:0 msgid "ned" -msgstr "" +msgstr "Κανονική ισοδύναμη απόκλιση" #. module: auction #: constraint:hr.attendance:0 msgid "Error: Sign in (resp. Sign out) must follow Sign out (resp. Sign in)" msgstr "" +"Σφάλμα: Η Είσοδος (ή Έξοδος) πρέπει να ακολουθείται από Έξοδο (Είσοδο)" #. module: auction #: view:auction.lots:0 #: field:report.buyer.auction,total_price:0 msgid "Total Adj." -msgstr "" +msgstr "Συνολική προσαρμογή" #. module: auction #: field:report.auction.view2,obj_margin_procent:0 msgid "Net margin (%)" -msgstr "" +msgstr "Καθαρό περιθώριο (%)" #. module: auction #: selection:auction.lots,state:0 @@ -278,28 +279,28 @@ msgstr "" #: selection:report.seller.auction,state:0 #: selection:report.unclassified.objects,state:0 msgid "Unsold" -msgstr "" +msgstr "Αδιάθετο" #. module: auction #: view:auction.dates:0 msgid "Dates" -msgstr "" +msgstr "Ημερομηνίες" #. module: auction #: constraint:product.template:0 msgid "Error: UOS must be in a different category than the UOM" -msgstr "" +msgstr "Error: UOS must be in a different category than the UOM" #. module: auction #: rml:auction.total.rml:0 msgid "Items" -msgstr "" +msgstr "Αντικείμενα" #. module: auction #: model:account.tax,name:auction.auction_tax5 #: field:auction.dates,seller_costs:0 msgid "Seller Costs" -msgstr "" +msgstr "Έξοδα πωλητών" #. module: auction #: view:auction.bid:0 @@ -309,75 +310,75 @@ msgstr "" #: model:ir.actions.report.xml,name:auction.bid_auction #: model:ir.ui.menu,name:auction.menu_action_bid_open msgid "Bids" -msgstr "" +msgstr "Προσφορές" #. module: auction #: model:ir.ui.menu,name:auction.auction_all_objects_menu msgid "All objects" -msgstr "" +msgstr "Όλα τα αντικείμενα" #. module: auction #: model:ir.actions.act_window,name:auction.action_auction_buyer_reporting_all2 msgid "Buyer's auction for all months" -msgstr "" +msgstr "Πληστηριασμοί αγοραστή για όλους τους μήνες" #. module: auction #: field:auction.bid,contact_tel:0 msgid "Contact" -msgstr "" +msgstr "Επικοινωνία" #. module: auction #: field:report.auction.view,obj_ret:0 #: field:report.object.encoded,obj_ret:0 #: field:report.object.encoded.manager,obj_ret:0 msgid "# obj ret" -msgstr "" +msgstr "Αριθμός αντικειμένων που επεστράφησαν" #. module: auction #: wizard_button:auction.lots.sms_send,init,send:0 msgid "Send SMS" -msgstr "" +msgstr "Αποστολή SMS" #. module: auction #: selection:auction.lot.category,aie_categ:0 msgid "Cont. Art/Painting" -msgstr "" +msgstr "Cont. Τέχνη/Ζωγραφική" #. module: auction #: field:auction.lots,sel_inv_id:0 msgid "Seller Invoice" -msgstr "" +msgstr "Τιμολόγιο πωλητή" #. module: auction #: view:auction.dates:0 msgid "Commissions" -msgstr "" +msgstr "Προμήθειες" #. module: auction #: wizard_button:auction.lots.numerotate,search,init:0 msgid "Back" -msgstr "" +msgstr "Πίσω" #. module: auction #: model:ir.actions.act_window,name:auction.action_all_objects_unsold msgid "Unsold objects" -msgstr "" +msgstr "Αδιάθετα αντικείμενα" #. module: auction #: model:ir.ui.menu,name:auction.menu_all_objects_sold1 msgid "Sold Objects" -msgstr "" +msgstr "Πουλημένα αντικείμενα" #. module: auction #: view:report.buyer.auction2:0 #: view:report.seller.auction2:0 msgid "Sum net margin" -msgstr "" +msgstr "Σύνολο καθαρού περιθωρίου" #. module: auction #: view:auction.deposit:0 msgid "Deposit Border Form" -msgstr "" +msgstr "Κατάθεση φόρμας συνόρων" #. module: auction #: field:auction.bid,bid_lines:0 @@ -385,12 +386,12 @@ msgstr "" #: rml:bids.lots:0 #: model:ir.model,name:auction.model_auction_bid_line msgid "Bid" -msgstr "" +msgstr "Προσφορά" #. module: auction #: wizard_field:auction.lots.send.aie,date_ask,lang:0 msgid "Langage" -msgstr "" +msgstr "Γλώσσα" #. module: auction #: field:auction.bid_line,lot_id:0 @@ -398,17 +399,17 @@ msgstr "" #: view:auction.lots:0 #: model:ir.model,name:auction.model_auction_lots msgid "Object" -msgstr "" +msgstr "Αντικείμενο" #. module: auction #: model:ir.actions.wizard,name:auction.wizard_map_user msgid "Map buyer username to Partners" -msgstr "" +msgstr "Καταγραφή του ονόματος χρήστη στους 'Συνεργάτες'" #. module: auction #: wizard_field:auction.lots.numerotate,search,lot_num:0 msgid "Inventory Number" -msgstr "" +msgstr "Αριθμός απογραφής" #. module: auction #: wizard_button:auction.lots.buyer_map,check,end:0 @@ -416,17 +417,17 @@ msgstr "" #: wizard_button:auction.lots.numerotate,search,end:0 #: wizard_button:auction.lots.numerotate_cont,init,end:0 msgid "Exit" -msgstr "" +msgstr "Έξοδος" #. module: auction #: field:report.buyer.auction2,net_revenue:0 msgid "Net Revenue" -msgstr "" +msgstr "Καθαρό έσοδο" #. module: auction #: view:report.buyer.auction:0 msgid "Auction buyer reporting form view" -msgstr "" +msgstr "Έντυπο έκθεσης άποψης των αγοραστών δημοπρασιών" #. module: auction #: field:auction.dates,state:0 @@ -436,17 +437,17 @@ msgstr "" #: field:report.seller.auction,state:0 #: field:report.unclassified.objects,state:0 msgid "Status" -msgstr "" +msgstr "Κατάσταση" #. module: auction #: model:ir.actions.wizard,name:auction.wizard_sms msgid "SMS Send" -msgstr "" +msgstr "Αποστολή γραπτού μηνύματος" #. module: auction #: selection:auction.lot.category,aie_categ:0 msgid "Antique/Cartoons" -msgstr "" +msgstr "Αντίκες/Γελοιογραφίες" #. module: auction #: view:auction.lots:0 @@ -454,42 +455,43 @@ msgstr "" #: selection:report.seller.auction,state:0 #: selection:report.unclassified.objects,state:0 msgid "Sold" -msgstr "" +msgstr "Πουλημένο" #. module: auction #: constraint:hr.employee:0 msgid "Error ! You cannot create recursive Hierarchy of Employees." msgstr "" +"Σφάλμα! Δε μπορείται να δημιουργήσετε αναδρομική ιεραρχία στους εργαζομένους" #. module: auction #: field:auction.bid_line,name:0 msgid "Bid date" -msgstr "" +msgstr "Ημερομηνία προσφορών" #. module: auction #: field:auction.dates,acc_expense:0 msgid "Expense Account" -msgstr "" +msgstr "Λογαριασμός Εξόδων" #. module: auction #: model:ir.ui.menu,name:auction.menu_wizard_emporte msgid "Deliveries Management" -msgstr "" +msgstr "Διαχείριση Παραδόσεων" #. module: auction #: field:auction.lots,obj_desc:0 msgid "Object Description" -msgstr "" +msgstr "Περιγραφή αντικειμένου" #. module: auction #: selection:auction.deposit,method:0 msgid "Contact the Seller" -msgstr "" +msgstr "Επικοινωνήστε με τον πωλητή" #. module: auction #: view:auction.lots:0 msgid "Auction Objects" -msgstr "" +msgstr "Δημοπρατημένα αντικείμενα" #. module: auction #: field:auction.lots,gross_revenue:0 @@ -497,60 +499,60 @@ msgstr "" #: field:report.object.encoded.manager,gross_revenue:0 #: field:report.seller.auction2,gross_revenue:0 msgid "Gross revenue" -msgstr "" +msgstr "Μικτό έσοδο" #. module: auction #: view:report.seller.auction2:0 msgid "Auction reporting2 form view" -msgstr "" +msgstr "Έντυπο αναφοράς άποψης Δημοπρασίας" #. module: auction #: model:ir.actions.wizard,name:auction.wizard_pay msgid "Pay objects of the buyer" -msgstr "" +msgstr "Πληρωμή αντικειμένων του αγοραστή" #. module: auction #: view:report.deposit.border:0 msgid "Depositer's statistics" -msgstr "" +msgstr "Στατιστικά αποταμιευτή" #. module: auction #: view:auction.lots:0 msgid "Buyer information" -msgstr "" +msgstr "Πληροφορίες Αγοραστή" #. module: auction #: model:ir.model,name:auction.model_report_seller_auction msgid "Auction Reporting on seller view" -msgstr "" +msgstr "Έντυπο αναφοράς άποψης των πωλητών για τη δημοπρασία" #. module: auction #: field:auction.lots,name2:0 msgid "Short Description (2)" -msgstr "" +msgstr "Σύντομη περιγραφή (2)" #. module: auction #: model:ir.model,name:auction.model_auction_dates msgid "auction.dates" -msgstr "" +msgstr "Δημοπρασίες.Ημερομηνίες" #. module: auction #: rml:auction.total.rml:0 #: model:ir.ui.menu,name:auction.auction_buyers_menu msgid "Buyers" -msgstr "" +msgstr "Αγοραστές" #. module: auction #: wizard_field:auction.pay.buy,init,amount:0 #: wizard_field:auction.pay.buy,init,amount2:0 #: wizard_field:auction.pay.buy,init,amount3:0 msgid "Amount paid" -msgstr "" +msgstr "Ποσό που πληρώθηκε" #. module: auction #: model:ir.ui.menu,name:auction.menu_report_latest_doposit_tree msgid "My Latest Deposits" -msgstr "" +msgstr "Οι Τελευταίες Καταθέσεις μου" #. module: auction #: field:auction.lots,lot_est1:0 @@ -559,105 +561,105 @@ msgstr "" #: field:report.auction.view,min_est:0 #: field:report.unclassified.objects,lot_est1:0 msgid "Minimum Estimation" -msgstr "" +msgstr "Ελάχιστος υπολογισμός" #. module: auction #: view:auction.dates:0 msgid "Accounting" -msgstr "" +msgstr "Λογιστική" #. module: auction #: model:ir.ui.menu,name:auction.menu_buyer_allmonth_view2 msgid "Buyer's Revenues" -msgstr "" +msgstr "Έσοδα του Αγοραστή" #. module: auction #: model:ir.model,name:auction.model_report_auction_adjudication msgid "report_auction_adjudication" -msgstr "" +msgstr "Αναφορά_δημοπρασίες_Διαγωνισμοί" #. module: auction #: field:auction.bid_line,price:0 msgid "Maximum Price" -msgstr "" +msgstr "Μέγιστη τιμή" #. module: auction #: selection:auction.lots.send.aie,date_ask,lang:0 msgid "eng" -msgstr "" +msgstr "Αγγλική" #. module: auction #: view:report.buyer.auction2:0 msgid "Auction buyer reporting tree view2" -msgstr "" +msgstr "Προβολή δέντρου εκθέσεων αγοραστή δημοπρασιών" #. module: auction #: wizard_view:auction.lots.sms_send,init:0 msgid "Bulk SMS send" -msgstr "" +msgstr "Μαζική αποστολή γραπτών μηνυμάτων" #. module: auction #: wizard_view:auction.taken,init:0 msgid "Select lots which are Sold" -msgstr "" +msgstr "Επιλέξτε παρτίδες που έχουν πουληθεί" #. module: auction #: field:auction.lots,statement_id:0 msgid "Payment" -msgstr "" +msgstr "Πληρωμή" #. module: auction #: selection:auction.lots.send.aie,date_ask,lang:0 msgid "fr" -msgstr "" +msgstr "Γαλλική" #. module: auction #: selection:auction.lot.category,aie_categ:0 msgid "Antique/Old weapons and militaria" -msgstr "" +msgstr "Αντίκες/ παλαιά όπλα και στρατιωτικά είδη" #. module: auction #: selection:auction.lot.category,aie_categ:0 msgid "Antique/Oriental Arts/Chineese furnitures" -msgstr "" +msgstr "Αντίκεςς/Ανατολίτικη τέχνη/Κινέζικα έπιπλα" #. module: auction #: selection:auction.deposit,method:0 msgid "Keep until sold" -msgstr "" +msgstr "Διατήρηση μέχρι να πουληθεί" #. module: auction #: wizard_button:auction.lots.numerotate,init,choice:0 #: wizard_button:auction.lots.send.aie,init,date_ask:0 #: wizard_button:auction.lots.send.aie.results,init,date_ask:0 msgid "Continue" -msgstr "" +msgstr "Συνεχίστε" #. module: auction #: field:report.object.encoded,obj_num:0 #: field:report.object.encoded.manager,obj_num:0 msgid "# of Encoded obj." -msgstr "" +msgstr "Πλήθος κωδικοποιημένων αντικειμένων" #. module: auction #: xsl:report.auction.vnd_bordereau:0 msgid "List N." -msgstr "" +msgstr "Λίστα Ν." #. module: auction #: field:report.deposit.border,moy_est:0 msgid "Avg. Est" -msgstr "" +msgstr "Μέσος υπολογισμός" #. module: auction #: rml:auction.total.rml:0 msgid "# of sellers:" -msgstr "" +msgstr "Πλήθος πωλητών:" #. module: auction #: constraint:product.product:0 msgid "Error: Invalid ean code" -msgstr "" +msgstr "Σφάλμα: Άκυρος κωδικός EAN" #. module: auction #: model:ir.module.module,description:auction.module_meta_information @@ -668,26 +670,33 @@ msgid "" " Delivery Management. \n" " " msgstr "" +"Αυτή η μονάδα παρέχει λειτουργικότητα στη \n" +" Διαχείριση καλλιτεχνών, αντικειμένων, πωλητών, αγοραστών και " +"δημοπρασίας.\n" +" Διαχείριση προσφορών, ιχνηλάτιση πουλημένων, πληρωμένων και απλήρωτων " +"αντικειμένων.\n" +" Διαχείριση παραδόσεων. \n" +" " #. module: auction #: rml:auction.total.rml:0 msgid "# of items taken away:" -msgstr "" +msgstr "πλήθος αντικειμένων που παραδόθηκαν:" #. module: auction #: model:ir.ui.menu,name:auction.menu_auction_allmonth_view1 msgid "Auction's Summary" -msgstr "" +msgstr "Περίληψη Δημοπρασίας" #. module: auction #: rml:buyer.list:0 msgid "%)" -msgstr "" +msgstr "%)" #. module: auction #: wizard_view:auction.lots.able,init:0 msgid "Confirmation set taken away" -msgstr "" +msgstr "Επιβεβαίωση αυτών που έχουν σταλθεί" #. module: auction #: wizard_field:auction.lots.make_invoice,init,objects:0 @@ -696,7 +705,7 @@ msgstr "" #: wizard_field:auction.lots.send.aie.results,date_ask,objects:0 #: field:report.deposit.border,nb_obj:0 msgid "# of objects" -msgstr "" +msgstr "ΠΛήθος αντικειμένων" #. module: auction #: field:auction.lots,lot_est2:0 @@ -705,42 +714,42 @@ msgstr "" #: field:report.auction.view,max_est:0 #: field:report.unclassified.objects,lot_est2:0 msgid "Maximum Estimation" -msgstr "" +msgstr "Μέγιστος υπολογισμός" #. module: auction #: field:auction.lots,buyer_price:0 msgid "Buyer price" -msgstr "" +msgstr "Τιμή αγοραστή" #. module: auction #: model:ir.actions.wizard,name:auction.auction_wizard_payer_sel msgid "Mark as paid for seller" -msgstr "" +msgstr "Σημειώστε το ως πληρωμένο για τον πωλητή" #. module: auction #: model:ir.actions.report.xml,name:auction.seller_form_id msgid "Seller List" -msgstr "" +msgstr "Λίστα πωλητών" #. module: auction #: field:auction.lots,is_ok:0 msgid "Buyer's payment" -msgstr "" +msgstr "ΠΛηρωμή αγοραστή" #. module: auction #: view:auction.dates:0 msgid "Close + Create all invoices" -msgstr "" +msgstr "Κλείσιμο + Δημιουργεία όλων των τιμολογίων" #. module: auction #: model:ir.actions.wizard,name:auction.auction_catalog_flagy msgid "Auction Catalog Flagey" -msgstr "" +msgstr "Κατάλογος δημοπρασιών Flagey" #. module: auction #: field:auction.lot.history,price:0 msgid "Withdrawn price" -msgstr "" +msgstr "Απόσυρση τιμής" #. module: auction #: model:account.tax,name:auction.auction_tax4 diff --git a/addons/audittrail/i18n/el.po b/addons/audittrail/i18n/el.po index 6abb75f9b34..4b438a11d61 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-25 03:47+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/base_module_quality/i18n/el.po b/addons/base_module_quality/i18n/el.po index 9ae13c3add3..4472efd47d4 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-25 03:47+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..fadb0ecd58e 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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: base_module_quality diff --git a/addons/base_report_creator/i18n/el.po b/addons/base_report_creator/i18n/el.po index a914194a57b..7efe97b103a 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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/board_association/i18n/el.po b/addons/board_association/i18n/el.po index 35fcc48ad27..9ef871e24af 100644 --- a/addons/board_association/i18n/el.po +++ b/addons/board_association/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:46+0000\n" +"X-Launchpad-Export-Date: 2010-06-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/board_auction/i18n/el.po b/addons/board_auction/i18n/el.po index f99a794521e..990647cd866 100644 --- a/addons/board_auction/i18n/el.po +++ b/addons/board_auction/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:46+0000\n" +"X-Launchpad-Export-Date: 2010-06-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/board_crm_configuration/i18n/el.po b/addons/board_crm_configuration/i18n/el.po index e2f697e23fd..93c5529b516 100644 --- a/addons/board_crm_configuration/i18n/el.po +++ b/addons/board_crm_configuration/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:46+0000\n" +"X-Launchpad-Export-Date: 2010-06-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/board_document/i18n/el.po b/addons/board_document/i18n/el.po index 338203acd35..e3ccc369296 100644 --- a/addons/board_document/i18n/el.po +++ b/addons/board_document/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/board_project/i18n/el.po b/addons/board_project/i18n/el.po index 4b6cc7b8820..cc09dff76e2 100644 --- a/addons/board_project/i18n/el.po +++ b/addons/board_project/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:46+0000\n" +"X-Launchpad-Export-Date: 2010-06-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/crm/i18n/es.po b/addons/crm/i18n/es.po index 974671e9272..6b5f93c446b 100644 --- a/addons/crm/i18n/es.po +++ b/addons/crm/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-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: crm diff --git a/addons/crm_profiling/i18n/el.po b/addons/crm_profiling/i18n/el.po index ce6a20ea15a..e253ca4c28c 100644 --- a/addons/crm_profiling/i18n/el.po +++ b/addons/crm_profiling/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/document/i18n/el.po b/addons/document/i18n/el.po index 9b425c31b89..5cc1498a931 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-25 03:47+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..8c53f9f604e 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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: document diff --git a/addons/document_webdav/i18n/el.po b/addons/document_webdav/i18n/el.po index eaf94e5c066..7870348b677 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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: document_webdav_old diff --git a/addons/event_project/i18n/el.po b/addons/event_project/i18n/el.po new file mode 100644 index 00000000000..6a5cc277123 --- /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-25 03:47+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/hr/i18n/el.po b/addons/hr/i18n/el.po index 5d965fa1178..0788b8cc952 100644 --- a/addons/hr/i18n/el.po +++ b/addons/hr/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/hr_contract/i18n/el.po b/addons/hr_contract/i18n/el.po index afdd0c4c3b8..21a86f08277 100644 --- a/addons/hr_contract/i18n/el.po +++ b/addons/hr_contract/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/hr_expense/i18n/el.po b/addons/hr_expense/i18n/el.po index 7ce942b3ff7..549a17a8579 100644 --- a/addons/hr_expense/i18n/el.po +++ b/addons/hr_expense/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/hr_holidays/i18n/el.po b/addons/hr_holidays/i18n/el.po index 2d0c0fa2310..3111dc75416 100644 --- a/addons/hr_holidays/i18n/el.po +++ b/addons/hr_holidays/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/hr_timesheet_invoice/i18n/es.po b/addons/hr_timesheet_invoice/i18n/es.po index 3a6afaac4ef..4eed72ce427 100644 --- a/addons/hr_timesheet_invoice/i18n/es.po +++ b/addons/hr_timesheet_invoice/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: hr_timesheet_invoice diff --git a/addons/hr_timesheet_sheet/i18n/el.po b/addons/hr_timesheet_sheet/i18n/el.po index 99558a120ff..ed36280ce80 100644 --- a/addons/hr_timesheet_sheet/i18n/el.po +++ b/addons/hr_timesheet_sheet/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" "X-Poedit-Country: GREECE\n" "X-Poedit-Language: Greek\n" diff --git a/addons/mrp/i18n/zh_CN.po b/addons/mrp/i18n/zh_CN.po index afa393000d3..bf522038e99 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-25 03:46+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..6d254bb9189 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-25 03:47+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..11eafbeca6d 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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: olap diff --git a/addons/point_of_sale/i18n/es.po b/addons/point_of_sale/i18n/es.po index 2856cdc128c..0e5300ef95a 100644 --- a/addons/point_of_sale/i18n/es.po +++ b/addons/point_of_sale/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-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: point_of_sale diff --git a/addons/project/i18n/es.po b/addons/project/i18n/es.po index 175a17229bc..2f46da3a0a2 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-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: project diff --git a/addons/project_timesheet/i18n/es.po b/addons/project_timesheet/i18n/es.po index 777b9212e77..0ab5c2a38c1 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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: project_timesheet diff --git a/addons/report_analytic_planning/i18n/es.po b/addons/report_analytic_planning/i18n/es.po index bf4ebb8ce76..c26f1f6dcd5 100644 --- a/addons/report_analytic_planning/i18n/es.po +++ b/addons/report_analytic_planning/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-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: report_analytic_planning diff --git a/addons/report_task/i18n/es.po b/addons/report_task/i18n/es.po index 8bb396c5454..0f0a57fb957 100644 --- a/addons/report_task/i18n/es.po +++ b/addons/report_task/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: report_task diff --git a/addons/sale/i18n/es.po b/addons/sale/i18n/es.po index 3c481e1f885..1ac3b8b4117 100644 --- a/addons/sale/i18n/es.po +++ b/addons/sale/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: sale diff --git a/addons/stock/i18n/es.po b/addons/stock/i18n/es.po index 4b8113738fd..02fbad114bd 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-25 03:46+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: stock diff --git a/addons/stock_location/i18n/es.po b/addons/stock_location/i18n/es.po index 70f2d3a33cd..20249109ac1 100644 --- a/addons/stock_location/i18n/es.po +++ b/addons/stock_location/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-25 03:47+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: stock_location From f936af868dfef0042180b52f41bb31073c500963 Mon Sep 17 00:00:00 2001 From: apa Date: Fri, 25 Jun 2010 10:42:53 +0530 Subject: [PATCH 3/7] [ADD/MOD]:sale_crm,crm: Reporting/Dashboards/CRM Configuration/Connecting Dashboard. * Rename with: Revenues by stage * Use staGe instead of state * Revenues should replace the column "Nbre of case" * Leads tree should be replaced with "My Opportunities",set opportunities instead of leads * add the tree "My Quotations" with a simplified view * add a tree that print the turnover by month of the current year. bzr revid: apa@apa-20100625051253-inp6usqqgkdezh1p --- addons/crm/board_crm_view.xml | 8 +- addons/crm/report/crm_lead_report_view.xml | 6 +- addons/sale_crm/__openerp__.py | 1 + addons/sale_crm/board_sale_crm_view.xml | 94 ++++++++++++++++++++++ 4 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 addons/sale_crm/board_sale_crm_view.xml diff --git a/addons/crm/board_crm_view.xml b/addons/crm/board_crm_view.xml index 69ca8e964e9..e39b0114e96 100644 --- a/addons/crm/board_crm_view.xml +++ b/addons/crm/board_crm_view.xml @@ -19,15 +19,16 @@ crm.lead form tree,form - + [('user_id','=',uid),('state','!=','pending'),('state','!=','cancel')] + crm.meeting form tree,form - [('user_id','=',uid),('state','!=','pending'),('state','!=','cancel')] + [('user_id','=',uid),('state','!=','cancel'),('date','ilike',time.strftime("%Y-%m"))] @@ -57,6 +58,7 @@ diff --git a/addons/crm/report/crm_lead_report_view.xml b/addons/crm/report/crm_lead_report_view.xml index 5292b297c89..014a08299e2 100644 --- a/addons/crm/report/crm_lead_report_view.xml +++ b/addons/crm/report/crm_lead_report_view.xml @@ -59,9 +59,9 @@ crm.lead.report graph - - - + + + diff --git a/addons/sale_crm/__openerp__.py b/addons/sale_crm/__openerp__.py index 9464db91b6f..f293b6ee436 100644 --- a/addons/sale_crm/__openerp__.py +++ b/addons/sale_crm/__openerp__.py @@ -40,6 +40,7 @@ crm modules. 'init_xml': [], 'update_xml': ['sale_crm_wizard.xml', 'sale_crm_view.xml', + 'board_sale_crm_view.xml', 'process/sale_crm_process.xml', 'security/sale_crm_security.xml', ], diff --git a/addons/sale_crm/board_sale_crm_view.xml b/addons/sale_crm/board_sale_crm_view.xml new file mode 100644 index 00000000000..42b7cc1cd47 --- /dev/null +++ b/addons/sale_crm/board_sale_crm_view.xml @@ -0,0 +1,94 @@ + + + + + + Quotations + sale.order + form + tree,form + [('state','=','draft'),('user_id','=',uid)] + + + + + turnover.by.month.tree + account.invoice.report + tree + + + + + + + + + + turnover.by.month.graph + account.invoice.report + graph + + + + + + + + + + account.invoice.report + form + graph,tree + + [('year','ilike',time.strftime('%Y')),('user_id','=',uid)] + {'group_by_no_leaf':1,'group_by':['month']} + + + + + CRM - Dashboard Form + board.board + form + + + + + + + + + + + + + + + + + + + + From b954fa03b19883c617abe31279ba3c5912025123 Mon Sep 17 00:00:00 2001 From: apa Date: Fri, 25 Jun 2010 10:57:32 +0530 Subject: [PATCH 4/7] [IMP]:crm:improved code. bzr revid: apa@apa-20100625052732-17fqd1hoacd7oehk --- addons/crm/board_crm_view.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/addons/crm/board_crm_view.xml b/addons/crm/board_crm_view.xml index e39b0114e96..4729ab7283d 100644 --- a/addons/crm/board_crm_view.xml +++ b/addons/crm/board_crm_view.xml @@ -54,35 +54,28 @@
- - - - - - -
@@ -107,7 +100,5 @@ action="open_board_crm" sequence="1" id="menu_board_crm" icon="terp-graph"/> - - From 30cd371bd2f26d78a981d28700b8f7079ca8f698 Mon Sep 17 00:00:00 2001 From: "Vir (Open ERP)" Date: Fri, 25 Jun 2010 13:15:55 +0530 Subject: [PATCH 5/7] [MOD] CRM : added crm object histroy tab in partner view bzr revid: vir@tinyerp.com-20100625074555-hq7kdfuvhcjsx9xz --- addons/crm/res_partner_view.xml | 112 ++++++++++++++++---------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/addons/crm/res_partner_view.xml b/addons/crm/res_partner_view.xml index 769cb5d5c81..d5bd5c1a3e9 100644 --- a/addons/crm/res_partner_view.xml +++ b/addons/crm/res_partner_view.xml @@ -4,62 +4,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + res.partner.crm.info.inherit + res.partner + form + + + + + + + + + + + + + + + + + + + + +