[MERGE]: Merged with lp:openobject-addons

bzr revid: atp@tinyerp.com-20120906113441-sutt7m5zv1wa0814
This commit is contained in:
Atul Patel (OpenERP) 2012-09-06 17:04:41 +05:30
commit d3ba827de7
219 changed files with 4585 additions and 8022 deletions

View File

@ -430,7 +430,7 @@ class account_bank_statement(osv.osv):
'name': st_number,
'balance_end_real': st.balance_end
}, context=context)
self.message_append_note(cr, uid, [st.id], body=_('Statement %s is confirmed, journal items are created.') % (st_number,), context=context)
self.message_post(cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st_number,), context=context)
return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
def button_cancel(self, cr, uid, ids, context=None):

View File

@ -1045,7 +1045,7 @@ class account_invoice(osv.osv):
if obj_inv.type in ('out_invoice', 'out_refund'):
ctx = self.get_log_context(cr, uid, context=ctx)
message = _("Invoice '%s' is validated.") % name
self.message_append_note(cr, uid, [inv_id], body=message, context=context)
self.message_post(cr, uid, [inv_id], body=message, context=context)
return True
def action_cancel(self, cr, uid, ids, *args):
@ -1275,7 +1275,7 @@ class account_invoice(osv.osv):
# TODO: use currency's formatting function
msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining).") % \
(name, pay_amount, code, invoice.amount_total, code, total, code)
self.message_append_note(cr, uid, [inv_id], body=msg, context=context)
self.message_post(cr, uid, [inv_id], body=msg, context=context)
self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context)
# Update the stored value (fields.function), so we write to trigger recompute
@ -1288,24 +1288,25 @@ class account_invoice(osv.osv):
def _get_document_type(self, type):
type_dict = {
'out_invoice': 'Customer invoice',
'in_invoice': 'Supplier invoice',
'out_refund': 'Customer Refund',
'in_refund': 'Supplier Refund',
# Translation markers will have no effect at runtime, only used to properly flag export
'out_invoice': _('Customer invoice'),
'in_invoice': _('Supplier invoice'),
'out_refund': _('Customer Refund'),
'in_refund': _('Supplier Refund'),
}
return type_dict.get(type, 'Invoice')
def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id],body=_("%s <b>created</b>.") % (self._get_document_type(obj.type)), context=context)
self.message_post(cr, uid, [obj.id], body=_("%s <b>created</b>.") % (_(self._get_document_type(obj.type))), context=context)
def confirm_paid_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (self._get_document_type(obj.type)), context=context)
for obj in self.browse(cr, uid, ids, context=context):
self.message_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (_(self._get_document_type(obj.type))), context=context)
def invoice_cancel_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (self._get_document_type(obj.type)), context=context)
self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (_(self._get_document_type(obj.type))), context=context)
account_invoice()

View File

@ -383,7 +383,7 @@
<field name="type">cash</field>
<field name="profit_account_id" model="account.account" ref="rsa" />
<field name="loss_account_id" model="account.account" ref="rsa" />
<field name="internal_account_id" model="account.account" ref="chart0" />
<field name="internal_account_id" model="account.account" ref="rsa" />
<field name="with_last_closing_balance" eval="True" />
<field name="cash_control" eval="True" />
<field name="view_id" ref="account_journal_bank_view"/>

View File

@ -123,64 +123,6 @@
</div>
</div>
]]></field>
<field name="body_text"><![CDATA[
Hello${object.partner_id.name and ' ' or ''}${object.partner_id.name or ''},
A new invoice is available for ${object.partner_id.name}:
| Invoice number: *${object.number}*
| Invoice total: *${object.amount_total} ${object.currency_id.name}*
| Invoice date: ${object.date_invoice}
% if object.origin:
| Order reference: ${object.origin}
% endif
| Your contact: ${object.user_id.name} ${object.user_id.email and '<%s>'%(object.user_id.email) or ''}
You can view the invoice document, download it and pay online using the following link:
${ctx.get('edi_web_url_view') or 'n/a'}
% if object.company_id.paypal_account and object.type in ('out_invoice', 'in_refund'):
<%
comp_name = quote(object.company_id.name)
inv_number = quote(object.number)
paypal_account = quote(object.company_id.paypal_account)
inv_amount = quote(str(object.amount_total))
cur_name = quote(object.currency_id.name)
paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=%s&item_name=%s%%20Invoice%%20%s"\
"&invoice=%s&amount=%s&currency_code=%s&button_subtype=services&no_note=1&bn=OpenERP_Invoice_PayNow_%s" % \
(paypal_account,comp_name,inv_number,inv_number,inv_amount,cur_name,cur_name)
%>
It is also possible to directly pay with Paypal:
${paypal_url}
% endif
If you have any question, do not hesitate to contact us.
Thank you for choosing ${object.company_id.name}!
--
${object.user_id.name} ${object.user_id.email and '<%s>'%(object.user_id.email) or ''}
${object.company_id.name}
% if object.company_id.street:
${object.company_id.street or ''}
% endif
% if object.company_id.street2:
${object.company_id.street2}
% endif
% if object.company_id.city or object.company_id.zip:
${object.company_id.zip or ''} ${object.company_id.city or ''}
% endif
% if object.company_id.country_id:
${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}
% endif
% if object.company_id.phone:
Phone: ${object.company_id.phone}
% endif
% if object.company_id.website:
${object.company_id.website or ''}
% endif
]]></field>
</record>
</data>
</openerp>

View File

@ -9538,7 +9538,7 @@ msgid "Refund"
msgstr ""
#. module: account
#: model:email.template,body_text:account.email_template_edi_invoice
#: model:email.template,body:account.email_template_edi_invoice
msgid "\n"
"Hello${object.address_invoice_id.name and ' ' or ''}${object.address_invoice_id.name or ''},\n"
"\n"

View File

@ -40,6 +40,10 @@ class CashBox(osv.osv_memory):
return {}
def _create_bank_statement_line(self, cr, uid, box, record, context=None):
values = self._compute_values_for_statement_line(cr, uid, box, record, context=context)
return self.pool.get('account.bank.statement.line').create(cr, uid, values, context=context)
class CashBoxIn(CashBox):
_name = 'cash.box.in'
@ -49,30 +53,24 @@ class CashBoxIn(CashBox):
'ref' : fields.char('Reference', size=32),
})
def _create_bank_statement_line(self, cr, uid, box, record, context=None):
absl_proxy = self.pool.get('account.bank.statement.line')
values = {
def _compute_values_for_statement_line(self, cr, uid, box, record, context=None):
return {
'statement_id' : record.id,
'journal_id' : record.journal_id.id,
'account_id' : record.journal_id.internal_account_id.id,
'amount' : box.amount or 0.0,
'ref' : "%s" % (box.ref or ''),
'ref' : '%s' % (box.ref or ''),
'name' : box.name,
}
return absl_proxy.create(cr, uid, values, context=context)
CashBoxIn()
class CashBoxOut(CashBox):
_name = 'cash.box.out'
def _create_bank_statement_line(self, cr, uid, box, record, context=None):
absl_proxy = self.pool.get('account.bank.statement.line')
def _compute_values_for_statement_line(self, cr, uid, box, record, context=None):
amount = box.amount or 0.0
values = {
return {
'statement_id' : record.id,
'journal_id' : record.journal_id.id,
'account_id' : record.journal_id.internal_account_id.id,
@ -80,6 +78,4 @@ class CashBoxOut(CashBox):
'name' : box.name,
}
return absl_proxy.create(cr, uid, values, context=context)
CashBoxOut()

View File

@ -21,13 +21,14 @@
</record>
<!-- Notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Accounting and Finance has been installed.</value>
<value>With OpenERP's accounting, you can get an instant access to all your financial data, setup your analytic accounting, forecast your taxes, control your budgets, easily create and send invoices, record bank statements, etc.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Accounting and Finance application installed!</field>
<field name="body">With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc.
The accounting features are fully integrated with others OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</value>
</function>
The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</field>
</record>
</data>
</openerp>

View File

@ -213,8 +213,6 @@ class account_followup_print_all(osv.osv_memory):
mod_obj = self.pool.get('ir.model.data')
move_obj = self.pool.get('account.move.line')
user_obj = self.pool.get('res.users')
line_obj = self.pool.get('account_followup.stat')
mail_message = self.pool.get('mail.message')
if context is None:
context = {}
@ -235,13 +233,7 @@ class account_followup_print_all(osv.osv_memory):
total_amt += line.debit - line.credit
dest = False
if partner:
if partner.type=='contact':
if adr.email:
dest = [partner.email]
if (not dest) and partner.type=='default':
if partner.email:
dest = [partner.email]
src = tools.config.options['email_from']
dest = [partner.email]
if not data.partner_lang:
body = data.email_body
else:
@ -281,7 +273,12 @@ class account_followup_print_all(osv.osv_memory):
msg = ''
if dest:
try:
mail_message.schedule_with_attach(cr, uid, src, dest, sub, body, context=context)
vals = {'state': 'outgoing',
'subject': sub,
'body_html': '<pre>%s</pre>' % body,
'email_to': dest,
'email_from': data_user.email or tools.config.options['email_from']}
self.pool.get('mail.mail').create(cr, uid, vals, context=context)
msg_sent += partner.name + '\n'
except Exception, e:
raise osv.except_osv('Error !', e )

View File

@ -1293,17 +1293,17 @@ class account_voucher(osv.osv):
def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
message = "%s <b>created</b>." % self._document_type[obj.type or False]
self.message_append_note(cr, uid, [obj.id], body=message, context=context)
self.message_post(cr, uid, [obj.id], body=message, context=context)
def post_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
message = "%s '%s' is <b>posted</b>." % (self._document_type[obj.type or False], obj.move_id.name)
self.message_append_note(cr, uid, [obj.id], body=message, context=context)
self.message_post(cr, uid, [obj.id], body=message, context=context)
def reconcile_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
message = "%s <b>reconciled</b>." % self._document_type[obj.type or False]
self.message_append_note(cr, uid, [obj.id], body=message, context=context)
self.message_post(cr, uid, [obj.id], body=message, context=context)
account_voucher()

View File

@ -2,15 +2,16 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module eInvoicing &amp; Payments has been installed.</value>
<value>OpenERP's electronic invoicing allows to ease and fasten the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">eInvoicing &amp; Payments application installed!</field>
<field name="body">OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
You can track customer payments easily and automate the reminders. You get an overview of the discussion with your customers on each invoice to ensure a full traceability.
You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability.
If you want to use advanced accounting features, you should install the "Accounting and Finance" module.</value>
</function>
For advanced accounting features, you should install the "Accounting and Finance" module.</field>
</record>
</data>
</openerp>

View File

@ -297,7 +297,7 @@ class account_analytic_account(osv.osv):
def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name), context=context)
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name), context=context)
account_analytic_account()

View File

@ -4,7 +4,7 @@
<t t-extend="Login">
<t t-jquery=".oe_login .oe_login_logo" t-operation="after">
<ul class="openid_providers">
<ul class="openid_providers oe_semantic_html_override">
<li><a href="#login,password" title="Password" data-url="" id="btn_password">Password</a></li>
<li><a href="#google" title="Google" data-url="https://www.google.com/accounts/o8/id">Google</a></li>
<li><a href="#googleapps" title="Google Apps" data-url="https://www.google.com/accounts/o8/site-xrds?hd={id}">Google</a></li>

View File

@ -9,16 +9,13 @@
<field name="email_from"><![CDATA[${object.company_id.name} <${object.company_id.email}>]]></field>
<field name="email_to" eval="False"><!--(set by reset_password module)--></field>
<field name="subject">Password reset</field>
<field name="body_text"><![CDATA[
A password reset was requested the OpenERP account linked to this email on ${object._auth_reset_password_host()}
<field name="body_html"><![CDATA[
<p>A password reset was requested the OpenERP account linked to this email on ${object._auth_reset_password_host()}</p>
You may change your password following this link:
<p>You may change your password following this <a href="${object._auth_reset_password_link()}">link</a>,
or by copy-pasting the following URL in your browser: ${object._auth_reset_password_link()}</p>
${object._auth_reset_password_link()}
If you don't have asked for password reset, you can safely ignore this email.
]]></field>
<p>Note: If you did not ask for a password reset, you can safely ignore this email.</p>]]></field>
</record>
<!-- TODO get own css -->

View File

@ -302,33 +302,27 @@ the rule to mark CC(mail to any other person defined in actions)."),
return self.format_body(body % data)
def email_send(self, cr, uid, obj, emails, body, emailfrom=None, context=None):
""" send email
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param email: pass the emails
@param emailfrom: Pass name the email From else False
@param context: A standard dictionary for contextual values """
if not emailfrom:
emailfrom = tools.config.get('email_from', False)
if context is None:
context = {}
mail_message = self.pool.get('mail.message')
emailfrom = tools.config.get('email_from')
body = self.format_mail(obj, body)
if not emailfrom:
if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.email:
emailfrom = obj.user_id.email
name = '[%d] %s' % (obj.id, tools.ustr(obj.name))
if not emailfrom and hasattr(obj, 'user_id') and obj.user_id and obj.user_id.email:
emailfrom = obj.user_id.email
emailfrom = tools.ustr(emailfrom)
reply_to = emailfrom
if not emailfrom:
raise osv.except_osv(_('Error!'),
_("No email ID found for your company address."))
return mail_message.schedule_with_attach(cr, uid, emailfrom, emails, name, body, model='base.action.rule', reply_to=reply_to, res_id=obj.id)
_("Missing default email address or missing email on responsible user"))
return self.pool.get('mail.mail').create(cr, uid,
{ 'email_from': emailfrom,
'email_to': emails.join(','),
'reply_to': reply_to,
'state': 'outgoing',
'subject': '[%d] %s' % (obj.id, tools.ustr(obj.name)),
'body_html': '<pre>%s</pre>' % body,
'res_id': obj.id,
'model': obj._table_name,
'auto_delete': True
}, context=context)
def do_check(self, cr, uid, action, obj, context=None):
@ -438,11 +432,8 @@ the rule to mark CC(mail to any other person defined in actions)."),
if len(emails) and action.act_mail_body:
emails = list(set(emails))
email_from = safe_eval(action.act_email_from, {}, locals_for_emails)
def to_email(text):
return re.findall(r'([^ ,<@]+@[^> ,]+)', text or '')
emails = to_email(','.join(filter(None, emails)))
email_froms = to_email(email_from)
emails = tools.email_split(','.join(filter(None, emails)))
email_froms = tools.email_split(email_from)
if email_froms:
self.email_send(cr, uid, obj, emails, action.act_mail_body, emailfrom=email_froms[0])
return True

View File

@ -471,18 +471,10 @@ property or property parameter."),
def _send_mail(self, cr, uid, ids, mail_to, email_from=tools.config.get('email_from', False), context=None):
"""
Send mail for event invitation to event attendees.
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of attendees IDs.
@param email_from: Email address for user sending the mail
@param context: A standard dictionary for contextual values
@return: True
"""
if context is None:
context = {}
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.name
mail_message = self.pool.get('mail.message')
for att in self.browse(cr, uid, ids, context=context):
sign = att.sent_by_uid and att.sent_by_uid.signature or ''
sign = '<br>'.join(sign and sign.split('\n') or [])
@ -508,17 +500,18 @@ property or property parameter."),
}
body = html_invitation % body_vals
if mail_to and email_from:
attach = self.get_ics_file(cr, uid, res_obj, context=context)
mail_message.schedule_with_attach(cr, uid,
email_from,
mail_to,
sub,
body,
attachments=attach and {'invitation.ics': attach} or None,
content_subtype='html',
reply_to=email_from,
context=context
)
ics_file = self.get_ics_file(cr, uid, res_obj, context=context)
vals = {'email_from': email_from,
'email_to': mail_to,
'state': 'outgoing',
'subject': sub,
'body_html': body,
'auto_delete': True}
if ics_file:
vals['attachment_ids'] = [(0,0,{'name': 'invitation.ics',
'datas_fname': 'invitation.ics',
'datas': str(ics_file).encode('base64')})]
self.pool.get('mail.mail').create(cr, uid, vals, context=context)
return True
def onchange_user_id(self, cr, uid, ids, user_id, *args, **argv):
@ -812,7 +805,6 @@ class calendar_alarm(osv.osv):
"""
if context is None:
context = {}
mail_message = self.pool.get('mail.message')
current_datetime = datetime.now()
alarm_ids = self.search(cr, uid, [('state', '!=', 'done')], context=context)
@ -849,36 +841,10 @@ class calendar_alarm(osv.osv):
else:
re_dates = [alarm.trigger_date]
for r_date in re_dates:
ref = alarm.model_id.model + ',' + str(alarm.res_id)
# search for alreay sent requests
#if request_obj.search(cr, uid, [('trigger_date', '=', r_date), ('ref_doc1', '=', ref)], context=context):
#continue
# Deactivated because of the removing of res.request
# TODO: when cleaning calendar module, re-add this in a new mechanism
#if alarm.action == 'display':
#value = {
#'name': alarm.name,
#'act_from': alarm.user_id.id,
#'act_to': alarm.user_id.id,
#'body': alarm.description,
#'trigger_date': r_date,
#'ref_doc1': ref
#}
#request_id = request_obj.create(cr, uid, value)
#request_ids = [request_id]
#for attendee in res_obj.attendee_ids:
#if attendee.user_id:
#value['act_to'] = attendee.user_id.id
#request_id = request_obj.create(cr, uid, value)
#request_ids.append(request_id)
#request_obj.request_send(cr, uid, request_ids)
if re_dates:
if alarm.action == 'email':
sub = '[Openobject Reminder] %s' % (alarm.name)
body = """
sub = '[OpenERP Reminder] %s' % (alarm.name)
body = """<pre>
Event: %s
Event Date: %s
Description: %s
@ -888,20 +854,21 @@ From:
----
%s
</pre>
""" % (alarm.name, alarm.trigger_date, alarm.description, \
alarm.user_id.name, alarm.user_id.signature)
mail_to = [alarm.user_id.email]
for att in alarm.attendee_ids:
mail_to.append(att.user_id.email)
if mail_to:
mail_message.schedule_with_attach(cr, uid,
tools.config.get('email_from', False),
mail_to,
sub,
body,
context=context
)
vals = {
'state': 'outgoing',
'subject': sub,
'body_html': body,
'email_to': mail_to,
'email_from': tools.config.get('email_from', mail_to),
}
self.pool.get('mail.mail').create(cr, uid, vals, context=context)
if next_trigger_date:
update_vals.update({'trigger_date': next_trigger_date})
else:
@ -1616,36 +1583,6 @@ class calendar_todo(osv.osv):
calendar_todo()
class ir_attachment(osv.osv):
_name = 'ir.attachment'
_inherit = 'ir.attachment'
def search_count(self, cr, user, args, context=None):
new_args = []
for domain_item in args:
if isinstance(domain_item, (list, tuple)) and len(domain_item) == 3 and domain_item[0] == 'res_id':
new_args.append((domain_item[0], domain_item[1], base_calendar_id2real_id(domain_item[2])))
else:
new_args.append(domain_item)
return super(ir_attachment, self).search_count(cr, user, new_args, context)
def create(self, cr, uid, vals, context=None):
if context:
id = context.get('default_res_id', False)
context.update({'default_res_id' : base_calendar_id2real_id(id)})
return super(ir_attachment, self).create(cr, uid, vals, context=context)
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
new_args = []
for domain_item in args:
if isinstance(domain_item, (list, tuple)) and len(domain_item) == 3 and domain_item[0] == 'res_id':
new_args.append((domain_item[0], domain_item[1], base_calendar_id2real_id(domain_item[2])))
else:
new_args.append(domain_item)
return super(ir_attachment, self).search(cr, uid, new_args, offset=offset,
limit=limit, order=order, context=context, count=False)
ir_attachment()
class ir_values(osv.osv):
_inherit = 'ir.values'

View File

@ -43,7 +43,7 @@ class crm_meeting(base_state, osv.Model):
_name = 'crm.meeting'
_description = "Meeting"
_order = "id desc"
_inherit = ["calendar.event", 'ir.needaction_mixin', "mail.thread"]
_inherit = ["calendar.event", "mail.thread", 'ir.needaction_mixin']
_columns = {
# base_state required fields
'create_date': fields.datetime('Creation Date', readonly=True),
@ -70,13 +70,17 @@ class crm_meeting(base_state, osv.Model):
# OpenChatter
# ----------------------------------------
# shows events of the day for this user
def needaction_domain_get(self, cr, uid, domain=[], context={}):
return [('date','<=',time.strftime('%Y-%M-%D 23:59:59')), ('date_deadline','>=', time.strftime('%Y-%M-%D 00:00:00')), ('user_id','=',uid)]
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
return 'Meeting'
def case_open_send_note(self, cr, uid, ids, context=None):
return self.message_append_note(cr, uid, ids, body=_("Meeting has been <b>confirmed</b>."), context=context)
return self.message_post(cr, uid, ids, body=_("Meeting <b>confirmed</b>."), context=context)
def case_close_send_note(self, cr, uid, ids, context=None):
return self.message_append_note(cr, uid, ids, body=_("Meeting has been <b>done</b>."), context=context)
return self.message_post(cr, uid, ids, body=_("Meeting <b>completed</b>."), context=context)

View File

@ -170,7 +170,8 @@
<page string="Invitation Detail">
<button string="Invite People"
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
icon="terp-partner" type="action"
type="action"
attrs="{'readonly': [('state', '=', 'done')]}"
context="{'model' : 'crm.meeting', 'attendee_field':'attendee_ids'}" colspan="2"/>
<field name="attendee_ids" widget="one2many" mode="tree">
<tree string="Invitation details" editable="top">
@ -182,17 +183,16 @@
<button name="do_tentative"
states="needs-action,declined,accepted"
string="Uncertain" type="object"
icon="terp-crm" />
/>
<button name="do_accept" string="Accept"
states="needs-action,tentative,declined"
type="object" icon="gtk-apply" />
type="object" />
<button name="do_decline" string="Decline"
states="needs-action,tentative,accepted"
type="object" icon="gtk-cancel" />
type="object" />
<button
name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d"
string="Delegate" type="action"
icon="gtk-sort-descending"
states="needs-action,tentative,declined,accepted"
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
</tree>
@ -200,16 +200,16 @@
<header>
<button name="do_tentative" type="object"
states="needs-action,declined,accepted"
string="Uncertain" icon="terp-crm" />
string="Uncertain" />
<button name="do_accept" type="object"
states="needs-action,tentative,declined"
string="Accept" icon="gtk-apply" />
string="Accept" />
<button name="do_decline" type="object"
states="needs-action,tentative,accepted"
string="Decline" icon="gtk-cancel" />
string="Decline" />
<button name="%(base_calendar.action_view_calendar_invite_attendee_wizard)d" type="action"
states="needs-action,tentative,declined,accepted"
string="Delegate" icon="gtk-sort-descending"
string="Delegate"
context="{'model' : 'calendar.attendee', 'attendee_field' : 'child_ids'}" />
<field name="state" widget="statusbar" statusbar_visible="draft,open,done"/>
</header>
@ -244,13 +244,13 @@
<field name="name">CRM - Meetings Tree</field>
<field name="model">crm.meeting</field>
<field name="arch" type="xml">
<tree string="Meetings" fonts="bold:needaction_pending==True">
<tree string="Meetings" fonts="bold:message_unread==True">
<field name="name" string="Subject" />
<field name="user_id"/>
<field name="date"/>
<field name="state" invisible="True"/>
<field name="duration" />
<field name="needaction_pending" invisible="1"/>
<field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
@ -287,9 +287,9 @@
<field name="arch" type="xml">
<search string="Search Meetings">
<field name="name" string="Meeting" filter_domain="[('name','ilike',self)]"/>
<filter string="Inbox" help="Unread messages" icon="terp-mail-message-new" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<filter string="Inbox" help="Unread messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter string="My Meetings" help="My Meetings" icon="terp-personal" domain="[('user_id','=',uid)]"/>
<filter string="My Meetings" help="My Meetings" domain="[('user_id','=',uid)]"/>
<field name="user_id"/>
<field name="partner_ids"/>
</search>

View File

@ -0,0 +1,271 @@
# Norwegian Bokmal translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-09-04 13:40+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-09-05 04:46+0000\n"
"X-Generator: Launchpad (build 15901)\n"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,category:0
msgid "Category"
msgstr "Kategori"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_objects,save:0
msgid "Information"
msgstr "Informasjon"
#. module: base_module_record
#: model:ir.model,name:base_module_record.model_ir_module_record
msgid "ir.module.record"
msgstr "ir.modul.opptak"
#. module: base_module_record
#: wizard_button:base_module_record.module_record_data,info,end:0
#: wizard_button:base_module_record.module_record_data,save_yaml,end:0
msgid "End"
msgstr "Slutt"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_data,init:0
#: wizard_view:base_module_record.module_record_objects,init:0
msgid "Choose objects to record"
msgstr "Velg objekter til opptak"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,author:0
msgid "Author"
msgstr "Forfatter"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,directory_name:0
msgid "Directory Name"
msgstr "Navn på katalog"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_data,init,filter_cond:0
#: wizard_field:base_module_record.module_record_objects,init,filter_cond:0
msgid "Records only"
msgstr "Bare opptak"
#. module: base_module_record
#: selection:base_module_record.module_record_objects,info,data_kind:0
msgid "Demo Data"
msgstr "Demo data"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,save,module_filename:0
msgid "Filename"
msgstr "Filnavn"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,version:0
msgid "Version"
msgstr "Versjon"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_data,info:0
#: wizard_view:base_module_record.module_record_data,init:0
#: wizard_view:base_module_record.module_record_data,save_yaml:0
#: wizard_view:base_module_record.module_record_objects,init:0
msgid "Objects Recording"
msgstr "objekter Innspilling"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_objects,save:0
msgid ""
"If you think your module could interest other people, we'd like you to "
"publish it on http://www.openerp.com, in the 'Modules' section. You can do "
"it through the website or using features of the 'base_module_publish' module."
msgstr ""
"Hvis du tror din modul kan interessere andre mennesker, vil vi gjerne at du "
"publisere den på http://www.openerp.com, i 'Moduler-delen. Du kan gjøre det "
"gjennom nettstedet eller bruke funksjonene i «base_module_publish»-modulen."
#. module: base_module_record
#: wizard_field:base_module_record.module_record_data,init,check_date:0
#: wizard_field:base_module_record.module_record_objects,init,check_date:0
msgid "Record from Date"
msgstr "Dato fra opptak"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_data,end:0
#: wizard_view:base_module_record.module_record_objects,end:0
#: wizard_view:base_module_record.module_record_objects,info:0
#: wizard_view:base_module_record.module_record_objects,save:0
#: wizard_view:base_module_record.module_record_objects,save_yaml:0
msgid "Module Recording"
msgstr "Modul innspilling"
#. module: base_module_record
#: model:ir.actions.wizard,name:base_module_record.wizard_base_module_record_objects
#: model:ir.ui.menu,name:base_module_record.menu_wizard_base_module_record_objects
msgid "Export Customizations As a Module"
msgstr "Eksporter Tilpasninger som en modul"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_objects,save:0
msgid "Thanks in advance for your contribution."
msgstr "Takk på forhånd for ditt bidrag."
#. module: base_module_record
#: help:base_module_record.module_record_data,init,objects:0
#: help:base_module_record.module_record_objects,init,objects:0
msgid "List of objects to be recorded"
msgstr "Liste over objekter som skal spilles inn"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,description:0
msgid "Full Description"
msgstr "Full beskrivelse"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,name:0
msgid "Module Name"
msgstr "Modulnavn"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_data,init,objects:0
#: wizard_field:base_module_record.module_record_objects,init,objects:0
msgid "Objects"
msgstr "Objekter"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,save,module_file:0
#: wizard_field:base_module_record.module_record_objects,save_yaml,yaml_file:0
msgid "Module .zip File"
msgstr "Modul .zip fil"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_objects,save:0
msgid "Module successfully created!"
msgstr ""
#. module: base_module_record
#: wizard_view:base_module_record.module_record_objects,save_yaml:0
msgid "YAML file successfully created !"
msgstr "YAML fil opprettet!"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_data,info:0
#: wizard_view:base_module_record.module_record_data,save_yaml:0
msgid "Result, paste this to your module's xml"
msgstr "Resultatet, lim denne til modulen xml"
#. module: base_module_record
#: selection:base_module_record.module_record_data,init,filter_cond:0
#: selection:base_module_record.module_record_objects,init,filter_cond:0
msgid "Created"
msgstr "Opprettet"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_data,end:0
#: wizard_view:base_module_record.module_record_objects,end:0
msgid "Thanks For using Module Recorder"
msgstr "Takk for at du brukte Modul opptaker."
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,website:0
msgid "Documentation URL"
msgstr "Dokumentasjon URL"
#. module: base_module_record
#: selection:base_module_record.module_record_data,init,filter_cond:0
#: selection:base_module_record.module_record_objects,init,filter_cond:0
msgid "Modified"
msgstr "Modifisert"
#. module: base_module_record
#: wizard_button:base_module_record.module_record_data,init,record:0
#: wizard_button:base_module_record.module_record_objects,init,record:0
msgid "Record"
msgstr "Opptak"
#. module: base_module_record
#: wizard_button:base_module_record.module_record_objects,info,save:0
msgid "Continue"
msgstr "Fortsett"
#. module: base_module_record
#: model:ir.actions.wizard,name:base_module_record.wizard_base_module_record_data
#: model:ir.ui.menu,name:base_module_record.menu_wizard_base_module_record_data
msgid "Export Customizations As Data File"
msgstr "Eksport Tilpasninger Som datafil"
#. module: base_module_record
#: code:addons/base_module_record/wizard/base_module_save.py:129
#, python-format
msgid "Error"
msgstr "Feil"
#. module: base_module_record
#: selection:base_module_record.module_record_objects,info,data_kind:0
msgid "Normal Data"
msgstr "Normal data"
#. module: base_module_record
#: wizard_button:base_module_record.module_record_data,end,end:0
#: wizard_button:base_module_record.module_record_objects,end,end:0
msgid "OK"
msgstr "Ok"
#. module: base_module_record
#: model:ir.ui.menu,name:base_module_record.menu_wizard_base_mod_rec
msgid "Module Creation"
msgstr "modul Skapelsen"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_objects,info,data_kind:0
msgid "Type of Data"
msgstr "Type data"
#. module: base_module_record
#: wizard_view:base_module_record.module_record_objects,info:0
msgid "Module Information"
msgstr "Modul informasjon"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_data,init,info_yaml:0
#: wizard_field:base_module_record.module_record_objects,init,info_yaml:0
msgid "YAML"
msgstr "YAML"
#. module: base_module_record
#: wizard_field:base_module_record.module_record_data,info,res_text:0
#: wizard_field:base_module_record.module_record_data,save_yaml,res_text:0
msgid "Result"
msgstr "Resultat"
#. module: base_module_record
#: wizard_button:base_module_record.module_record_data,init,end:0
#: wizard_button:base_module_record.module_record_objects,info,end:0
#: wizard_button:base_module_record.module_record_objects,init,end:0
msgid "Cancel"
msgstr "Kanseller"
#. module: base_module_record
#: wizard_button:base_module_record.module_record_objects,save,end:0
#: wizard_button:base_module_record.module_record_objects,save_yaml,end:0
msgid "Close"
msgstr "Lukke"
#. module: base_module_record
#: selection:base_module_record.module_record_data,init,filter_cond:0
#: selection:base_module_record.module_record_objects,init,filter_cond:0
msgid "Created & Modified"
msgstr "Laget & Modifisert"
#~ msgid "Module successfully created !"
#~ msgstr "Modulen opprettet!"

View File

@ -0,0 +1,204 @@
# Norwegian Bokmal translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-09-04 13:59+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-09-05 04:46+0000\n"
"X-Generator: Launchpad (build 15901)\n"
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_sxw
msgid "base.report.sxw"
msgstr "basen.rapport.sxw"
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "OpenERP Report Designer Configuration"
msgstr "OpenERP Rapport Designer Konfigurasjon"
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid ""
"This plug-in allows you to create/modify OpenERP Reports into OpenOffice "
"Writer."
msgstr ""
"Denne plug-in tillater deg å lage / endre OpenERP rapporter i OpenOffice "
"Writer."
#. module: base_report_designer
#: view:base.report.file.sxw:0
msgid "Upload the modified report"
msgstr "Laste opp den endrede rapporten"
#. module: base_report_designer
#: view:base.report.file.sxw:0
msgid "The .SXW report"
msgstr ".SXW rapport"
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_designer_installer
msgid "base_report_designer.installer"
msgstr "basen.rapport.designer.installatør"
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "_Close"
msgstr "_Lukk"
#. module: base_report_designer
#: view:base.report.rml.save:0
msgid "The RML Report"
msgstr ""
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "Configure"
msgstr "Konfigurer"
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "title"
msgstr "tittel"
#. module: base_report_designer
#: field:base.report.file.sxw,report_id:0
#: field:base.report.sxw,report_id:0
msgid "Report"
msgstr "Rapport"
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_rml_save
msgid "base.report.rml.save"
msgstr "Basen.rapport.rml.lagre"
#. module: base_report_designer
#: model:ir.ui.menu,name:base_report_designer.menu_action_report_designer_wizard
msgid "Report Designer"
msgstr "Rapportdesigner"
#. module: base_report_designer
#: field:base_report_designer.installer,name:0
msgid "File name"
msgstr "Filnavn"
#. module: base_report_designer
#: view:base.report.file.sxw:0
#: view:base.report.sxw:0
msgid "Get a report"
msgstr "Få en rapport"
#. module: base_report_designer
#: view:base_report_designer.installer:0
#: model:ir.actions.act_window,name:base_report_designer.action_report_designer_wizard
msgid "OpenERP Report Designer"
msgstr "OpenERP Rapport designer"
#. module: base_report_designer
#: view:base.report.sxw:0
msgid "Continue"
msgstr "Fortsett"
#. module: base_report_designer
#: field:base.report.rml.save,file_rml:0
msgid "Save As"
msgstr "Lagre som"
#. module: base_report_designer
#: help:base_report_designer.installer,plugin_file:0
msgid ""
"OpenObject Report Designer plug-in file. Save as this file and install this "
"plug-in in OpenOffice."
msgstr ""
"OpenObject Report Designer plug-in-filen. Lagre som denne filen og "
"installere denne plugin-modulen i OpenOffice."
#. module: base_report_designer
#: view:base.report.rml.save:0
msgid "Save RML FIle"
msgstr "Lagre RML fil"
#. module: base_report_designer
#: field:base.report.file.sxw,file_sxw:0
#: field:base.report.file.sxw,file_sxw_upload:0
msgid "Your .SXW file"
msgstr "Din .SXW fil"
#. module: base_report_designer
#: view:base_report_designer.installer:0
msgid "Installation and Configuration Steps"
msgstr "Installasjon og Konfigurasjon trinn"
#. module: base_report_designer
#: field:base_report_designer.installer,description:0
msgid "Description"
msgstr "Beskrivelse:"
#. module: base_report_designer
#: view:base.report.file.sxw:0
msgid ""
"This is the template of your requested report.\n"
"Save it as a .SXW file and open it with OpenOffice.\n"
"Don't forget to install the OpenERP SA OpenOffice package to modify it.\n"
"Once it is modified, re-upload it in OpenERP using this wizard."
msgstr ""
"Dette er malen for den forespurte rapporten.\n"
"Lagre det som en. Sxw fil og åpne den med OpenOffice.\n"
"Ikke glem å installere OpenERP SA OpenOffice-pakken til å endre det.\n"
"Når den er modifisert, laste opp det i OpenERP bruke denne veiviseren."
#. module: base_report_designer
#: field:base_report_designer.installer,config_logo:0
msgid "Image"
msgstr "Bilde"
#. module: base_report_designer
#: model:ir.actions.act_window,name:base_report_designer.action_view_base_report_sxw
msgid "Base Report sxw"
msgstr "Basen rapport sxw"
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_base_report_file_sxw
msgid "base.report.file.sxw"
msgstr "basen.rapport.fil.sxw"
#. module: base_report_designer
#: field:base_report_designer.installer,plugin_file:0
msgid "OpenObject Report Designer Plug-in"
msgstr "OpenObject Rapport Designer Plug-in"
#. module: base_report_designer
#: model:ir.actions.act_window,name:base_report_designer.action_report_designer_installer
msgid "OpenERP Report Designer Installation"
msgstr "OpenERP Rapport Designer Installasjon"
#. module: base_report_designer
#: view:base.report.file.sxw:0
#: view:base.report.rml.save:0
#: view:base.report.sxw:0
#: view:base_report_designer.installer:0
msgid "Cancel"
msgstr "Kanseller"
#. module: base_report_designer
#: model:ir.model,name:base_report_designer.model_ir_actions_report_xml
msgid "ir.actions.report.xml"
msgstr "ir.handlinger.rapport.xml"
#. module: base_report_designer
#: view:base.report.sxw:0
msgid "Select your report"
msgstr "Velg din rapport"
#~ msgid "The RML report"
#~ msgstr "RML rapport"

View File

@ -297,55 +297,31 @@ class base_stage(object):
destination=False)
def remind_user(self, cr, uid, ids, context=None, attach=False, destination=True):
mail_message = self.pool.get('mail.message')
for case in self.browse(cr, uid, ids, context=context):
if not destination and not case.email_from:
return False
if not case.user_id.email:
return False
if destination and case.section_id.user_id:
case_email = case.section_id.user_id.email
else:
case_email = case.user_id.email
src = case_email
dest = case.user_id.email or ""
body = case.description or ""
for message in case.message_ids:
if message.email_from and message.body_text:
body = message.body_text
break
if not destination:
src, dest = dest, case.email_from
if body and case.user_id.signature:
if body:
body += '\n\n%s' % (case.user_id.signature)
else:
body = '\n\n%s' % (case.user_id.signature)
body = self.format_body(body)
attach_to_send = {}
if attach:
attach_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', case.id)])
attach_to_send = self.pool.get('ir.attachment').read(cr, uid, attach_ids, ['datas_fname', 'datas'])
attach_to_send = dict(map(lambda x: (x['datas_fname'], base64.decodestring(x['datas'])), attach_to_send))
# Send an email
subject = "Reminder: [%s] %s" % (str(case.id), case.name, )
mail_message.schedule_with_attach(cr, uid,
src,
[dest],
subject,
body,
model=self._name,
reply_to=case.section_id.reply_to,
res_id=case.id,
attachments=attach_to_send,
context=context
)
if 'message_post' in self:
for case in self.browse(cr, uid, ids, context=context):
if destination:
recipient_id = case.user_id.partner_id.id
else:
if not case.email_from:
return False
recipient_id = self.pool.get('res.partner').find_or_create(cr, uid, case.email_from, context=context)
body = case.description or ""
for message in case.message_ids:
if message.type == 'email' and message.body:
body = message.body
break
body = self.format_body(body)
attach_to_send = {}
if attach:
attach_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', case.id)])
attach_to_send = self.pool.get('ir.attachment').read(cr, uid, attach_ids, ['datas_fname', 'datas'])
attach_to_send = dict(map(lambda x: (x['datas_fname'], x['datas'].decode('base64')), attach_to_send))
subject = "Reminder: [%s] %s" % (case.id, case.name)
self.message_post(cr, uid, case.id, body=body,
subject=subject, attachments=attach_to_send,
partner_ids=[recipient_id], context=context)
return True
def _check(self, cr, uid, ids=False, context=None):
@ -360,17 +336,6 @@ class base_stage(object):
def format_mail(self, obj, body):
return self.pool.get('base.action.rule').format_mail(obj, body)
def message_thread_followers(self, cr, uid, ids, context=None):
res = {}
for case in self.browse(cr, uid, ids, context=context):
l=[]
if case.email_cc:
l.append(case.email_cc)
if case.user_id and case.user_id.email:
l.append(case.user_id.email)
res[case.id] = l
return res
# ******************************
# Notifications
# ******************************
@ -395,31 +360,31 @@ class base_stage(object):
def case_open_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>opened</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_close_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>closed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_cancel_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>canceled</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_pending_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s is now <b>pending</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_reset_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>renewed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_escalate_send_note(self, cr, uid, ids, new_section=None, context=None):
@ -428,5 +393,5 @@ class base_stage(object):
msg = '%s has been <b>escalated</b> to <b>%s</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context), new_section.name)
else:
msg = '%s has been <b>escalated</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], 'System Notification', msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True

View File

@ -179,13 +179,13 @@ class base_state(object):
# Notifications
# ******************************
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
return ''
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
return ''
def case_open_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>opened</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_escalate_send_note(self, cr, uid, ids, new_section=None, context=None):
@ -194,29 +194,29 @@ class base_state(object):
msg = '%s has been <b>escalated</b> to <b>%s</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context), new_section.name)
else:
msg = '%s has been <b>escalated</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], 'System Notification', msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_close_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>closed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_cancel_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>canceled</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_pending_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s is now <b>pending</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True
def case_reset_send_note(self, cr, uid, ids, context=None):
for id in ids:
msg = _('%s has been <b>renewed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=msg, context=context)
self.message_post(cr, uid, [id], body=msg, context=context)
return True

View File

@ -36,7 +36,7 @@
</div>
</t>
<t t-name="DashBoard.layouts">
<div class="oe_dashboard_layout_selector">
<div class="oe_dashboard_layout_selector oe_semantic_html_override">
<p>
<strong>Choose dashboard layout</strong>
</p>

View File

@ -46,21 +46,11 @@ class base_action_rule(osv.osv):
}
def email_send(self, cr, uid, obj, emails, body, emailfrom=tools.config.get('email_from', False), context=None):
mail_message = self.pool.get('mail.message')
body = self.format_mail(obj, body)
if not emailfrom:
if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.email:
emailfrom = obj.user_id.email
name = '[%d] %s' % (obj.id, tools.ustr(obj.name))
emailfrom = tools.ustr(emailfrom)
if hasattr(obj, 'section_id') and obj.section_id and obj.section_id.alias_id:
mail_id = super(base_action_rule, self).email_send(cr, uid, obj, emails, body, emailfrom=emailfrom, context=context)
if mail_id and hasattr(obj, 'section_id') and obj.section_id and obj.section_id.alias_id:
reply_to = obj.section_id.alias_id.name_get()[0][1]
else:
reply_to = emailfrom
if not emailfrom:
raise osv.except_osv(_('Error!'), _("There is no email for your company address."))
return mail_message.schedule_with_attach(cr, uid, emailfrom, emails, name, body, model=obj._name, reply_to=reply_to, res_id=obj.id)
self.pool.get('mail.mail').write(cr, uid, [mail_id], {'reply_to': reply_to}, context=context)
return mail_id
def do_check(self, cr, uid, action, obj, context=None):
ok = super(base_action_rule, self).do_check(cr, uid, action, obj, context=context)
@ -105,8 +95,8 @@ class base_action_rule(osv.osv):
write['email_cc'] = obj.act_email_cc
# Put state change by rule in communication history
if hasattr(obj, 'state') and hasattr(obj, 'message_append') and action.act_state:
model_obj.message_append(cr, uid, [obj], _(action.act_state))
if hasattr(obj, 'state') and hasattr(obj, 'message_post') and action.act_state:
model_obj.message_post(cr, uid, [obj], _(action.act_state), context=context)
model_obj.write(cr, uid, [obj.id], write, context)
super(base_action_rule, self).do_action(cr, uid, action, model_obj, obj, context=context)

View File

@ -55,21 +55,20 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module CRM has been installed</value>
<value>From the top menu Sales, you can: trace leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">CRM application installed!</field>
<field name="body">From the top Sales menu you can track leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.
To manage quotations and sale orders, install the "Sales Management" application.</field>
</record>
To manage quotations and sale orders, install the module "Sales Management".</value>
</function>
<record model="mail.alias" id="default_sales_alias">
<field name="alias_name">sales</field>
<field name="alias_model_id" ref="model_crm_lead"/>
<field name="alias_user_id" ref="base.user_root"/>
<field name="alias_defaults">{'type':'lead'}</field>
</record>
</data>
</openerp>

View File

@ -19,11 +19,9 @@
#
##############################################################################
import binascii
from base_status.base_stage import base_stage
import crm
from datetime import datetime
from mail.mail_message import to_email
from osv import fields, osv
import time
import tools
@ -40,8 +38,7 @@ class crm_lead(base_stage, osv.osv):
_name = "crm.lead"
_description = "Lead/Opportunity"
_order = "priority,date_action,id desc"
_inherit = ['ir.needaction_mixin', 'mail.thread']
_mail_compose_message = True
_inherit = ['mail.thread','ir.needaction_mixin']
def _get_default_section_id(self, cr, uid, context=None):
""" Gives default section by checking if present in the context """
@ -175,16 +172,6 @@ class crm_lead(base_stage, osv.osv):
else:
return [('id', '=', '0')]
def _get_email_subject(self, cr, uid, ids, fields, args, context=None):
res = {}
for obj in self.browse(cr, uid, ids, context=context):
res[obj.id] = ''
for msg in obj.message_ids:
if msg.email_from:
res[obj.id] = msg.subject
break
return res
_columns = {
'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null',
select=True, help="Optional linked partner, usually after conversion of the lead"),
@ -228,7 +215,6 @@ class crm_lead(base_stage, osv.osv):
When the case is over, the state is set to \'Done\'.\
If the case needs to be reviewed then the state is \
set to \'Pending\'.'),
'subjects': fields.function(_get_email_subject, fnct_search=_history_search, string='Subject of Email', type='char', size=64),
# Only used for type opportunity
'probability': fields.float('Success Rate (%)',group_operator="avg"),
@ -449,7 +435,7 @@ class crm_lead(base_stage, osv.osv):
oldest_id = opportunity_ids[0]
return self.browse(cr, uid, oldest_id, context=context)
def _mail_body_text(self, cr, uid, lead, fields, title=False, context=None):
def _mail_body(self, cr, uid, lead, fields, title=False, context=None):
body = []
if title:
body.append("%s\n" % (title))
@ -486,11 +472,11 @@ class crm_lead(base_stage, osv.osv):
for opportunity in opportunities:
subject.append(opportunity.name)
title = "%s : %s" % (merge_message, opportunity.name)
details.append(self._mail_body_text(cr, uid, opportunity, fields, title=title, context=context))
details.append(self._mail_body(cr, uid, opportunity, fields, title=title, context=context))
subject = subject[0] + ", ".join(subject[1:])
details = "\n\n".join(details)
return self.message_append_note(cr, uid, [opportunity_id], subject=subject, body=details)
return self.message_post(cr, uid, [opportunity_id], body=details, subject=subject, context=context)
def _merge_opportunity_history(self, cr, uid, opportunity_id, opportunities, context=None):
message = self.pool.get('mail.message')
@ -546,7 +532,7 @@ class crm_lead(base_stage, osv.osv):
oldest = self._merge_find_oldest(cr, uid, ids, context=context)
if ctx_opportunities :
first_opportunity = ctx_opportunities[0]
tail_opportunities = opportunities_list
tail_opportunities = opportunities_list + ctx_opportunities[1:]
else:
first_opportunity = opportunities_list[0]
tail_opportunities = opportunities_list[1:]
@ -606,19 +592,13 @@ class crm_lead(base_stage, osv.osv):
for lead in self.browse(cr, uid, ids, context=context):
if lead.state in ('done', 'cancel'):
continue
if user_ids or section_id:
self.allocate_salesman(cr, uid, [lead.id], user_ids, section_id, context=context)
vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
self.write(cr, uid, [lead.id], vals, context=context)
self.convert_opportunity_send_note(cr, uid, lead, context=context)
#TOCHECK: why need to change partner details in all messages of lead ?
if lead.partner_id:
msg_ids = [ x.id for x in lead.message_ids]
mail_message.write(cr, uid, msg_ids, {
'partner_id': lead.partner_id.id
}, context=context)
if user_ids or section_id:
self.allocate_salesman(cr, uid, ids, user_ids, section_id, context=context)
return True
def _lead_create_contact(self, cr, uid, lead, name, is_company, parent_id=False, context=None):
@ -630,7 +610,7 @@ class crm_lead(base_stage, osv.osv):
'parent_id': parent_id,
'phone': lead.phone,
'mobile': lead.mobile,
'email': lead.email_from and to_email(lead.email_from)[0],
'email': lead.email_from and tools.email_split(lead.email_from)[0],
'fax': lead.fax,
'title': lead.title and lead.title.id or False,
'function': lead.function,
@ -650,7 +630,7 @@ class crm_lead(base_stage, osv.osv):
partner_id = False
if lead.partner_name and lead.contact_name:
partner_id = self._lead_create_contact(cr, uid, lead, lead.partner_name, True, context=context)
self._lead_create_contact(cr, uid, lead, lead.contact_name, False, partner_id, context=context)
partner_id = self._lead_create_contact(cr, uid, lead, lead.contact_name, False, partner_id, context=context)
elif lead.partner_name and not lead.contact_name:
partner_id = self._lead_create_contact(cr, uid, lead, lead.partner_name, True, context=context)
elif not lead.partner_name and lead.contact_name:
@ -678,32 +658,16 @@ class crm_lead(base_stage, osv.osv):
if context is None:
context = {}
partner_ids = {}
force_partner_id = partner_id
for lead in self.browse(cr, uid, ids, context=context):
if action == 'create':
if not partner_id:
partner_id = self._create_lead_partner(cr, uid, lead, context)
partner_id = force_partner_id or self._create_lead_partner(cr, uid, lead, context=context)
self._lead_set_partner(cr, uid, lead, partner_id, context=context)
partner_ids[lead.id] = partner_id
return partner_ids
def _send_mail_to_salesman(self, cr, uid, lead, context=None):
"""
Send mail to salesman with updated Lead details.
@ lead: browse record of 'crm.lead' object.
"""
#TOFIX: mail template should be used here instead of fix subject, body text.
message = self.pool.get('mail.message')
email_to = lead.user_id and lead.user_id.email
if not email_to:
return False
email_from = lead.section_id and lead.section_id.user_id and lead.section_id.user_id.email or email_to
partner = lead.partner_id and lead.partner_id.name or lead.partner_name
subject = "lead %s converted into opportunity" % lead.name
body = "Info \n Id : %s \n Subject: %s \n Partner: %s \n Description : %s " % (lead.id, lead.name, lead.partner_id.name, lead.description)
return message.schedule_with_attach(cr, uid, email_from, [email_to], subject, body)
def allocate_salesman(self, cr, uid, ids, user_ids, team_id=False, context=None):
index = 0
for lead_id in ids:
@ -821,14 +785,13 @@ class crm_lead(base_stage, osv.osv):
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'description': msg.get('body'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
})
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
custom_values['priority'] = msg.get('priority')
custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from', False), context=context))
return super(crm_lead, self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
@ -841,18 +804,18 @@ class crm_lead(base_stage, osv.osv):
if update_vals is None: update_vals = {}
if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
vals['priority'] = msg.get('priority')
update_vals['priority'] = msg.get('priority')
maps = {
'cost':'planned_cost',
'revenue': 'planned_revenue',
'probability':'probability',
}
for line in msg.get('body_text', '').split('\n'):
for line in msg.get('body', '').split('\n'):
line = line.strip()
res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower()):
key = maps.get(res.group(1).lower())
vals[key] = res.group(2).lower()
update_vals[key] = res.group(2).lower()
return super(crm_lead, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
@ -860,15 +823,10 @@ class crm_lead(base_stage, osv.osv):
# OpenChatter methods and notifications
# ----------------------------------------
def message_get_monitored_follower_fields(self, cr, uid, ids, context=None):
""" Add 'user_id' to the monitored fields """
res = super(crm_lead, self).message_get_monitored_follower_fields(cr, uid, ids, context=context)
return res + ['user_id']
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """
stage_name = self.pool.get('crm.case.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
return self.message_post(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
def case_get_note_msg_prefix(self, cr, uid, lead, context=None):
if isinstance(lead, (int, long)):
@ -878,33 +836,33 @@ class crm_lead(base_stage, osv.osv):
def create_send_note(self, cr, uid, ids, context=None):
for id in ids:
message = _("%s has been <b>created</b>.")% (self.case_get_note_msg_prefix(cr, uid, id, context=context))
self.message_append_note(cr, uid, [id], body=message, context=context)
self.message_post(cr, uid, [id], body=message, context=context)
return True
def case_mark_lost_send_note(self, cr, uid, ids, context=None):
message = _("Opportunity has been <b>lost</b>.")
return self.message_append_note(cr, uid, ids, body=message, context=context)
return self.message_post(cr, uid, ids, body=message, context=context)
def case_mark_won_send_note(self, cr, uid, ids, context=None):
message = _("Opportunity has been <b>won</b>.")
return self.message_append_note(cr, uid, ids, body=message, context=context)
return self.message_post(cr, uid, ids, body=message, context=context)
def schedule_phonecall_send_note(self, cr, uid, ids, phonecall_id, action, context=None):
phonecall = self.pool.get('crm.phonecall').browse(cr, uid, [phonecall_id], context=context)[0]
if action == 'log': prefix = 'Logged'
else: prefix = 'Scheduled'
message = _("<b>%s a call</b> for the <em>%s</em>.") % (prefix, phonecall.date)
return self.message_append_note(cr, uid, ids, body=message, context=context)
return self.message_post(cr, uid, ids, body=message, context=context)
def _lead_set_partner_send_note(self, cr, uid, ids, context=None):
for lead in self.browse(cr, uid, ids, context=context):
message = _("%s <b>partner</b> is now set to <em>%s</em>." % (self.case_get_note_msg_prefix(cr, uid, lead, context=context), lead.partner_id.name))
lead.message_append_note(body=message)
lead.message_post(body=message)
return True
def convert_opportunity_send_note(self, cr, uid, lead, context=None):
message = _("Lead has been <b>converted to an opportunity</b>.")
lead.message_append_note(body=message)
lead.message_post(body=message)
return True
crm_lead()

View File

@ -552,86 +552,67 @@ Andrew</field>
<field name="subject">Plan to buy a Laptop</field>
<field name="model">crm.lead</field>
<field name="res_id" ref="crm_case_15"/>
<field name="content_subtype">html</field>
<field name="body_html">&lt;![CDATA[Email0 inquiry]]&gt;&lt;div&gt;&lt;font size="2"&gt;Hello,&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="2"&gt;&lt;br&gt;&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="2"&gt;I am interested in your company's product and I plan to buy a new laptop having latest technologies and affordable price.&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="2"&gt;Can you please send me product catalogue?&lt;/font&gt;&lt;/div&gt;</field>
<field name="body">&lt;![CDATA[Email0 inquiry]]&gt;&lt;div&gt;&lt;font size="2"&gt;Hello,&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="2"&gt;&lt;br&gt;&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="2"&gt;I am interested in your company's product and I plan to buy a new laptop having latest technologies and affordable price.&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="2"&gt;Can you please send me product catalogue?&lt;/font&gt;&lt;/div&gt;</field>
<field name="type">email</field>
<field name="state">received</field>
<field name="user_id" ref="base.user_demo"/>
</record>
<record id="message_note0" model="mail.message">
<field name="subject">Re: Plan to buy a Laptop</field>
<field name="model">crm.lead</field>
<field name="res_id" ref="crm_case_15"/>
<field name="parent_id" ref="message_email0"/>
<field name="content_subtype">plain</field>
<field name="body_text">Dear Customer,
<field name="type">comment</field>
<field name="body">Dear Customer,
Thanks for showing interest in our products.
We have attached the catalogue,
We would like to know your interests, Let us know if we can call you for more details.
Thanks</field>
<field name="type">email</field>
<field name="user_id" ref="base.user_root"/>
<field name="state">sent</field>
<field name="parent_id" ref="message_email0"/>
<field name="author_id" ref="base.partner_root"/>
</record>
<record id="message_note0_comment0" model="mail.message">
<field name="subject">Re: Plan to buy a Laptop</field>
<field name="model">crm.lead</field>
<field name="res_id" ref="crm_case_15"/>
<field name="content_subtype">html</field>
<field name="body_html">&lt;div&gt;Thanks for the information,&lt;/div&gt;&lt;div&gt;I will visit the store soon.&lt;/div&gt;</field>
<field name="type">comment</field>
<field name="body">&lt;div&gt;Thanks for the information,&lt;/div&gt;&lt;div&gt;I will visit the store soon.&lt;/div&gt;</field>
<field name="parent_id" ref="message_note0"/>
<field name="type">email</field>
<field name="user_id" ref="base.user_demo"/>
<field name="state">received</field>
<field name="author_id" ref="base.partner_demo"/>
</record>
<record id="message_note0_comment1" model="mail.message">
<field name="subject">Re: Plan to buy a Laptop</field>
<field name="model">crm.lead</field>
<field name="res_id" ref="crm_case_15"/>
<field name="content_subtype">html</field>
<field name="body_html">&lt;font color="#1f1f1f"&gt;Can you tell me if the store is open at 9:00 PM?&lt;/b&gt;&lt;/font&gt;</field>
<field name="type">comment</field>
<field name="body">&lt;font color="#1f1f1f"&gt;Can you tell me if the store is open at 9:00 PM?&lt;/b&gt;&lt;/font&gt;</field>
<field name="parent_id" ref="message_note0"/>
<field name="type">email</field>
<field name="state">received</field>
<field name="user_id" ref="base.user_demo"/>
<field name="author_id" ref="base.partner_demo"/>
</record>
<record id="message_email1" model="mail.message">
<field name="subject">Re: Plan to buy a Laptop</field>
<field name="model">crm.lead</field>
<field name="res_id" ref="crm_case_15"/>
<field name="content_subtype">plain</field>
<field name="body_text">Yes, its open till 10:00 PM, you are welcome!</field>
<field name="body">Yes, its open till 10:00 PM, you are welcome!</field>
<field name="type">email</field>
<field name="state">sent</field>
<field name="user_id" ref="base.user_root"/>
<field name="author_id" ref="base.partner_root"/>
</record>
<record id="message_email_12" model="mail.message">
<field name="subject">Inquiry</field>
<field name="model">crm.lead</field>
<field name="res_id" ref="crm_case_1"/>
<field name="content_subtype">plain</field>
<field name="body_text">Hello,
<field name="body">Hello,
I am Jason from Le Club SARL,
I am intertested to attend Training organized in your company,
Can you send details,</field>
<field name="type">email</field>
<field name="state">received</field>
<field name="user_id" ref="base.user_demo"/>
</record>
<record id="message_email_13" model="mail.message">
<field name="subject">Need Details</field>
<field name="model">crm.lead</field>
<field name="res_id" ref="crm_case_2"/>
<field name="content_subtype">plain</field>
<field name="body_text">Want to know features and benifits to use the new software.</field>
<field name="body">Want to know features and benifits to use the new software.</field>
<field name="type">comment</field>
<field name="user_id" ref="base.user_demo"/>
</record>
<!-- Call Function to set the opportunities as Unread -->
<function model="crm.lead" name="message_mark_as_unread"
eval="[ ref('crm_case_15'), ref('crm_case_16'),

View File

@ -246,7 +246,7 @@
<field name="name">Leads</field>
<field name="model">crm.lead</field>
<field name="arch" type="xml">
<tree string="Leads" fonts="bold:needaction_pending==True" colors="grey:state in ('cancel', 'done')">
<tree string="Leads" fonts="bold:message_unread==True" colors="grey:state in ('cancel', 'done')">
<field name="date_deadline" invisible="1"/>
<field name="create_date" groups="base.group_no_one"/>
<field name="name"/>
@ -261,8 +261,7 @@
<field name="type_id" invisible="1"/>
<field name="referred" invisible="1"/>
<field name="channel_id" invisible="1"/>
<field name="subjects" invisible="1"/>
<field name="needaction_pending" invisible="1"/>
<field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
@ -296,10 +295,10 @@
<field name="user_id"/>
<field name="partner_address_email"/>
<field name="message_summary"/>
<field name="needaction_pending"/>
<field name="message_unread"/>
<templates>
<t t-name="lead_details">
<ul class="oe_kanban_tooltip">
<ul class="oe_kanban_tooltip oe_semantic_html_override">
<li t-if="record.phone.raw_value"><b>Phone:</b> <field name="phone"/></li>
<li><b>Probability:</b> <field name="probability"/>%%</li>
<li><b>Creation date:</b> <field name="create_date"/></li>
@ -308,11 +307,11 @@
</t>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<div class="oe_dropdown_toggle oe_dropdown_kanban oe_semantic_html_override">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu">
<li><a type="edit" >Edit...</a></li>
<li><a type="delete">Delete</a></li>
<t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit...</a></li></t>
<t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
<li><a name="%(mail.action_email_compose_message_wizard)d" type="action">Send Email</a></li>
<li><a name="%(opportunity2phonecall_act)d" type="action">Log Call</a></li>
<li><a name="action_makeMeeting" type="object">Schedule Meeting</a></li>
@ -342,7 +341,6 @@
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
<div class="oe_kanban_footer_left">
<t t-if="record.needaction_pending.raw_value"><span class="oe_kanban_mail_new">New</span></t>
<t t-raw="record.message_summary.raw_value"/>
</div>
</div>
@ -362,10 +360,8 @@
<search string="Search Leads">
<field name="name" string="Lead / Customer" filter_domain="['|','|',('partner_name','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike',self)]" />
<!-- subjects is not set as store=True so, it is placed outside filter_domain-->
<field name="subjects"/>
<field name="create_date"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" name="new" help="New Leads" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Open" name="open" domain="[('state','=','open')]"/>
@ -545,7 +541,7 @@
<field name="name">Opportunities Tree</field>
<field name="model">crm.lead</field>
<field name="arch" type="xml">
<tree string="Opportunities" fonts="bold:needaction_pending==True" colors="gray:state in ('cancel', 'done');red:date_deadline and (date_deadline &lt; current_date)">
<tree string="Opportunities" fonts="bold:message_unread==True" colors="gray:state in ('cancel', 'done');red:date_deadline and (date_deadline &lt; current_date)">
<field name="date_deadline" invisible="1"/>
<field name="create_date" groups="base.group_no_one"/>
<field name="name" string="Opportunity"/>
@ -555,7 +551,6 @@
<field name="title_action" />
<field name="channel_id" invisible="1"/>
<field name="type_id" invisible="1"/>
<field name="subjects" invisible="1"/>
<field name="stage_id"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
@ -563,7 +558,7 @@
<field name="user_id"/>
<field name="priority" invisible="1"/>
<field name="state" groups="base.group_no_one"/>
<field name="needaction_pending" invisible="1"/>
<field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
@ -578,7 +573,7 @@
<field name="name" string="Opportunity / Customer"
filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
<field name="categ_ids" string="Category" filter_domain="[('categ_ids','ilike', self)]" />
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" help="New Opportunities" name="new" domain="[('state','=','draft')]"/>
<filter icon="terp-camera_test" string="Open" help="Open Opportunities" name="open" domain="[('state','=','open')]"/>

View File

@ -44,7 +44,7 @@ class crm_meeting(osv.Model):
def create_send_note(self, cr, uid, ids, context=None):
if context is None:
context = {}
# update context: if come from phonecall, default state values can make the message_append_note crash
# update context: if come from phonecall, default state values can make the message_post crash
context.pop('default_state', False)
for meeting in self.browse(cr, uid, ids, context=context):
# in the message, transpose meeting.date to the timezone of the current user
@ -53,14 +53,14 @@ class crm_meeting(osv.Model):
if meeting.opportunity_id: # meeting can be create from phonecalls or opportunities, therefore checking for the parent
lead = meeting.opportunity_id
message = _("Meeting linked to the opportunity <em>%s</em> has been <b>created</b> and <b>scheduled</b> on <em>%s</em>.") % (lead.name, meeting_date_tz)
lead.message_append_note(_('System Notification'), message)
lead.message_post(body=message)
elif meeting.phonecall_id:
phonecall = meeting.phonecall_id
message = _("Meeting linked to the phonecall <em>%s</em> has been <b>created</b> and <b>scheduled</b> on <em>%s</em>.") % (phonecall.name, meeting_date_tz)
phonecall.message_append_note(body=message)
phonecall.message_post(body=message)
else:
message = _("A meeting has been <b>scheduled</b> on <em>%s</em>.") % (meeting_date_tz)
meeting.message_append_note(body=message)
meeting.message_post(body=message)
return True
class calendar_attendee(osv.osv):

View File

@ -32,7 +32,7 @@ class crm_phonecall(base_state, osv.osv):
_name = "crm.phonecall"
_description = "Phonecall"
_order = "id desc"
_inherit = ['ir.needaction_mixin', 'mail.thread']
_inherit = ['mail.thread']
_columns = {
# base_state required fields
'date_action_last': fields.datetime('Last Action', readonly=1),
@ -177,11 +177,11 @@ class crm_phonecall(base_state, osv.osv):
if context is None:
context = {}
partner_ids = {}
force_partner_id = partner_id
for call in self.browse(cr, uid, ids, context=context):
if action == 'create':
if not partner_id:
partner_id = self._call_create_partner(cr, uid, call, context=context)
self._call_create_partner_address(cr, uid, call, partner_id, context=context)
partner_id = force_partner_id or self._call_create_partner(cr, uid, call, context=context)
self._call_create_partner_address(cr, uid, call, partner_id, context=context)
self._call_set_partner(cr, uid, [call.id], partner_id, context=context)
partner_ids[call.id] = partner_id
return partner_ids
@ -266,7 +266,7 @@ class crm_phonecall(base_state, osv.osv):
def case_reset_send_note(self, cr, uid, ids, context=None):
message = _('Phonecall has been <b>reset and set as open</b>.')
return self.message_append_note(cr, uid, ids, body=message, context=context)
return self.message_post(cr, uid, ids, body=message, context=context)
def case_open_send_note(self, cr, uid, ids, context=None):
lead_obj = self.pool.get('crm.lead')
@ -280,11 +280,11 @@ class crm_phonecall(base_state, osv.osv):
message = _("Phonecall linked to the opportunity <em>%s</em> has been <b>created</b> and <b>scheduled</b> on <em>%s</em>.") % (lead.name, phonecall_date_str)
else:
message = _("Phonecall has been <b>created and opened</b>.")
phonecall.message_append_note(body=message)
phonecall.message_post(body=message)
return True
def _call_set_partner_send_note(self, cr, uid, ids, context=None):
return self.message_append_note(cr, uid, ids, body=_("Partner has been <b>created</b>."), context=context)
return self.message_post(cr, uid, ids, body=_("Partner has been <b>created</b>."), context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -66,8 +66,7 @@
<field name="name">CRM - Phone Calls Tree</field>
<field name="model">crm.phonecall</field>
<field name="arch" type="xml">
<tree fonts="bold:needaction_pending==True" colors="gray:state in ('cancel','done');blue:state in ('pending',)" string="Phone Calls">
<field name="needaction_pending" invisible="1"/>
<tree colors="gray:state in ('cancel','done');blue:state in ('pending',)" string="Phone Calls">
<field name="date"/>
<field name="name"/>
<field name="partner_id"/>
@ -76,7 +75,6 @@
<field name="categ_id" invisible="1"/>
<field name="create_date" invisible="1"/>
<field name="opportunity_id" invisible="1"/>
<field name="needaction_pending" invisible="1"/>
<button string="Convert to Opportunity"
name="%(phonecall2opportunity_act)d"
states="open,pending"
@ -166,7 +164,7 @@
<field name="name">CRM - Logged Phone Calls Tree</field>
<field name="model">crm.phonecall</field>
<field name="arch" type="xml">
<tree string="Phone Calls" fonts="bold:needaction_pending==True" editable="top">
<tree string="Phone Calls" editable="top">
<field name="date"/>
<field name="name"/>
<field name="partner_id"
@ -180,7 +178,6 @@
<field name="state" invisible="1"/>
<field name="create_date" invisible="1"/>
<field name="opportunity_id" invisible="1"/>
<field name="needaction_pending" invisible="1"/>
<button string="Schedule Other Call"
icon="terp-call-start"
name="%(phonecall_to_phonecall_act)d"
@ -219,7 +216,6 @@
<search string="Search Phonecalls">
<field name="name" string="Phonecalls"/>
<field name="date"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<separator/>
<filter icon="terp-gtk-go-back-rtl" string="To Do" name="current" domain="[('state','=','open')]"/>
<separator/>

View File

@ -23,7 +23,7 @@
!python {model: mail.compose.message}: |
lead_ids = self.pool.get('crm.lead').search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
context.update({'active_model': 'crm.lead','active_id': lead_ids[0]})
id = self.create(cr, uid, {'body_text': "Merci à l'intérêt pour notre produit.nous vous contacterons bientôt. Merci", 'email_from': 'sales@mycompany.com'}, context=context)
id = self.create(cr, uid, {'body': "Merci à l'intérêt pour notre produit.nous vous contacterons bientôt. Merci", 'email_from': 'sales@mycompany.com'}, context=context)
try:
self.send_mail(cr, uid, [id], context=context)
except:
@ -34,12 +34,6 @@
!python {model: crm.lead}: |
lead_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
self.convert_partner(cr, uid, lead_ids, context=context)
-
Now, I search customer in regular customer list.
-
!python {model: crm.lead}: |
partner_ids = self.message_partner_by_email(cr, uid, 'Mr. John Right <info@customer.com>')
assert partner_ids.get('partner_id'), "Customer is not found in regular customer list."
-
I convert one phonecall request as a customer and put into regular customer list.
-

View File

@ -55,7 +55,7 @@
After communicated with customer, I put some notes with contract details.
-
!python {model: crm.lead}: |
self.message_append_note(cr, uid, [ref('crm_case_4')], subject='Test note', body='ces détails envoyés par le client sur le FAX pour la qualité')
self.message_post(cr, uid, [ref('crm_case_4')], subject='Test note', body='ces détails envoyés par le client sur le FAX pour la qualité')
-
I win this opportunity
-
@ -73,7 +73,7 @@
I convert mass lead into opportunity customer.
-
!python {model: crm.lead2opportunity.partner.mass}: |
context.update({'active_model': 'crm.lead', 'active_ids': [ref("crm_case_11"), ref("crm_case_2")], 'active_id': ref("crm_case_4")})
context.update({'active_model': 'crm.lead', 'active_ids': [ref("crm_case_11"), ref("crm_case_2")], 'active_id': ref("crm_case_11")})
id = self.create(cr, uid, {'user_ids': [ref('base.user_root')], 'section_id': ref('crm.section_sales_department')}, context=context)
self.mass_convert(cr, uid, [id], context=context)
-
@ -83,7 +83,8 @@
opp = self.browse(cr, uid, ref('crm_case_11'))
assert opp.name == "Need estimated cost for new project", "Opportunity name not correct"
assert opp.type == 'opportunity', 'Lead is not converted to opportunity!'
assert opp.partner_id.name == "Thomas Passot", 'Partner mismatch!'
expected_partner = "Thomas Passot"
assert opp.partner_id.name == expected_partner, 'Partner mismatch! %s vs %s' % (opp.partner_id.name, expected_partner)
assert opp.stage_id.id == ref("stage_lead1"), 'Stage of probability is incorrect!'
-
Then check for second lead converted on opportunity.

View File

@ -24,8 +24,6 @@ from tools.translate import _
import tools
import re
import time
class crm_lead2opportunity_partner(osv.osv_memory):
_name = 'crm.lead2opportunity.partner'
_description = 'Lead To Opportunity Partner'
@ -35,8 +33,8 @@ class crm_lead2opportunity_partner(osv.osv_memory):
'action': fields.selection([('exist', 'Link to an existing partner'), \
('create', 'Create a new partner'), \
('nothing', 'Do not link to a partner')], \
'Action', required=True),
'name': fields.selection([('convert', 'Convert to Opportunity'), ('merge', 'Merge with existing Opportunity')],'Select Action', required=True),
'Related Partner', required=True),
'name': fields.selection([('convert', 'Convert to Opportunities'), ('merge', 'Merge with existing Opportunities')], 'Conversion Action', required=True),
'opportunity_ids': fields.many2many('crm.lead', string='Opportunities', domain=[('type', '=', 'opportunity')]),
}
@ -68,8 +66,6 @@ class crm_lead2opportunity_partner(osv.osv_memory):
if ids:
opportunities.append(ids[0])
if not partner_id:
label = False
opp_ids = []
if email:
# Find email of existing opportunity matches the email_from of the lead
cr.execute("""select id from crm_lead where type='opportunity' and
@ -106,23 +102,36 @@ class crm_lead2opportunity_partner(osv.osv_memory):
if context is None:
context = {}
lead = self.pool.get('crm.lead')
partner_id = self._create_partner(cr, uid, ids, context=context)
res = False
partner_ids_map = self._create_partner(cr, uid, ids, context=context)
lead_ids = vals.get('lead_ids', [])
user_ids = vals.get('user_ids', False)
team_id = vals.get('section_id', False)
return lead.convert_opportunity(cr, uid, lead_ids, partner_id, user_ids, team_id, context=context)
for lead_id in lead_ids:
partner_id = partner_ids_map.get(lead_id, False)
# FIXME: cannot pass user_ids as the salesman allocation only works in batch
res = lead.convert_opportunity(cr, uid, [lead_id], partner_id, [], team_id, context=context)
# FIXME: must perform salesman allocation in batch separately here
user_ids = vals.get('user_ids', False)
if user_ids:
lead.allocate_salesman(cr, uid, lead_ids, user_ids, team_id=team_id, context=context)
return res
def _merge_opportunity(self, cr, uid, ids, opportunity_ids, action='merge', context=None):
#TOFIX: is it usefully ?
if context is None:
context = {}
merge_opportunity = self.pool.get('crm.merge.opportunity')
res = False
#If we convert in mass, don't merge if there is no other opportunity but no warning
if action == 'merge' and (len(opportunity_ids) > 1 or not context.get('mass_convert') ):
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [opportunity_ids[0].id])]}, context=context)
context.update({'lead_ids' : record_id, "convert" : True})
res = merge_opportunity.merge(cr, uid, data.opportunity_ids, context=context)
# Expected: all newly-converted leads (active_ids) will be merged with the opportunity(ies)
# that have been selected in the 'opportunity_ids' m2m, with all these records
# merged into the first opportunity (and the rest deleted)
opportunity_ids = [o.id for o in opportunity_ids]
lead_ids = context.get('active_ids', [])
if action == 'merge' and lead_ids and opportunity_ids:
# Add the leads in the to-merge list, next to other opps
# (the fact that they're passed in context['lead_ids'] means that
# they cannot be selected to contain the result of the merge.
opportunity_ids.extend(lead_ids)
context.update({'lead_ids': lead_ids, "convert" : True})
res = self.pool.get('crm.lead').merge_opportunity(cr, uid, opportunity_ids, context=context)
return res
def action_apply(self, cr, uid, ids, context=None):
@ -131,27 +140,37 @@ class crm_lead2opportunity_partner(osv.osv_memory):
"""
if not context:
context = {}
lead = self.pool.get('crm.lead')
lead_ids = context.get('active_ids', [])
data = self.browse(cr, uid, ids, context=context)[0]
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context)
self._merge_opportunity(cr, uid, ids, data.opportunity_ids, data.action, context=context)
self._merge_opportunity(cr, uid, ids, data.opportunity_ids, data.name, context=context)
return lead.redirect_opportunity_view(cr, uid, lead_ids[0], context=context)
crm_lead2opportunity_partner()
class crm_lead2opportunity_mass_convert(osv.osv_memory):
_name = 'crm.lead2opportunity.partner.mass'
_description = 'Mass Lead To Opportunity Partner'
_inherit = 'crm.lead2opportunity.partner'
_columns = {
'user_ids': fields.many2many('res.users', string='Salesmans'),
'user_ids': fields.many2many('res.users', string='Salesmen'),
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
}
def default_get(self, cr, uid, fields, context=None):
res = super(crm_lead2opportunity_mass_convert, self).default_get(cr, uid, fields, context)
if 'partner_id' in fields:
# avoid forcing the partner of the first lead as default
res['partner_id'] = False
if 'action' in fields:
res['action'] = 'create'
if 'name' in fields:
res['name'] = 'convert'
if 'opportunity_ids' in fields:
res['opportunity_ids'] = False
return res
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
data = self.browse(cr, uid, ids, context=context)[0]
salesteam_id = data.section_id and data.section_id.id or False
@ -162,9 +181,6 @@ class crm_lead2opportunity_mass_convert(osv.osv_memory):
return super(crm_lead2opportunity_mass_convert, self)._convert_opportunity(cr, uid, ids, vals, context=context)
def mass_convert(self, cr, uid, ids, context=None):
value = self.default_get(cr, uid, ['partner_id', 'opportunity_ids'], context=context)
value['opportunity_ids'] = [(6, 0, value['opportunity_ids'])]
self.write(cr, uid, ids, value, context=context)
return self.action_apply(cr, uid, ids, context=context)
crm_lead2opportunity_mass_convert()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -37,24 +37,38 @@
<field name="model">crm.lead2opportunity.partner.mass</field>
<field name="arch" type="xml">
<form string="Convert to Opportunity" version="7.0">
<field name="action"/>
<field name="name" colspan="4"/>
<group string="Assigned Opportunities to">
<field name="section_id"/>
<group string="Conversion Options">
<field name="action"/>
<field name="partner_id" attrs="{'invisible':[('action','!=','exist')],'required': [('action', '=', 'exist')]}"/>
<field name="name"/>
</group>
<separator string="Select Salesman"/>
<field name="user_ids">
<group string="Select Opportunities" attrs="{'invisible': [('name', '=', 'convert')]}">
<field name="opportunity_ids" colspan="4" nolabel="1" attrs="{'invisible': [('name', '=', 'convert')]}">
<tree>
<field name="name"/>
<field name="name" />
<field name="partner_id" />
<field name="user_id" />
<field name="section_id" />
</tree>
</field>
</group>
<group string="Assign opportunities to">
<field name="section_id" />
<field name="user_ids" colspan="4">
<tree>
<field name="name" />
</tree>
</field>
</group>
<footer>
<button name="mass_convert" string="Convert into Opportunities" type="object" class="oe_highlight"/>
<button name="mass_convert" string="Convert to Opportunities" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</footer>
</form>
</field>
</field>
</record>
<record id="action_crm_lead2opportunity_partner" model="ir.actions.act_window">

View File

@ -50,20 +50,20 @@ class crm_lead2partner(osv.osv_memory):
def _select_partner(self, cr, uid, context=None):
if context is None:
context = {}
lead = self.pool.get('crm.lead')
partner = self.pool.get('res.partner')
lead_ids = list(context and context.get('active_ids', []) or [])
if not len(lead_ids):
if not context.get('active_model') == 'crm.lead' or not context.get('active_id'):
return False
this = lead.browse(cr, uid, lead_ids[0], context=context)
# Find partner address matches the email_from of the lead
res = lead.message_partner_by_email(cr, uid, this.email_from, context=context)
partner_id = res.get('partner_id', False)
# Find partner name that matches the name of the lead
if not partner_id and this.partner_name:
partner = self.pool.get('res.partner')
lead = self.pool.get('crm.lead')
this = lead.browse(cr, uid, context.get('active_id'), context=context)
partner_id = False
if this.email_from:
partner_ids = partner.search(cr, uid, [('email', '=', this.email_from)], context=context)
if partner_ids:
partner_id = partner_ids[0]
if not this.partner_id and this.partner_name:
partner_ids = partner.search(cr, uid, [('name', '=', this.partner_name)], context=context)
if partner_ids and len(partner_ids):
partner_id = partner_ids[0]
if partner_ids:
partner_id = partner_ids[0]
return partner_id
def default_get(self, cr, uid, fields, context=None):
@ -107,15 +107,16 @@ class crm_lead2partner(osv.osv_memory):
lead_ids = context and context.get('active_ids') or []
data = self.browse(cr, uid, ids, context=context)[0]
partner_id = data.partner_id and data.partner_id.id or False
partner_ids = lead.convert_partner(cr, uid, lead_ids, data.action, partner_id, context=context)
return partner_ids[lead_ids[0]]
return lead.convert_partner(cr, uid, lead_ids, data.action, partner_id, context=context)
def make_partner(self, cr, uid, ids, context=None):
"""
This function Makes partner based on action.
"""
partner_id = self._create_partner(cr, uid, ids, context=context)
return self.pool.get('res.partner').redirect_partner_form(cr, uid, partner_id, context=context)
# Only called from Form view, so only meant to convert one Lead.
lead_id = context and context.get('active_id') or False
partner_ids_map = self._create_partner(cr, uid, ids, context=context)
return self.pool.get('res.partner').redirect_partner_form(cr, uid, partner_ids_map.get(lead_id, False), context=context)
crm_lead2partner()

View File

@ -57,12 +57,10 @@ class crm_phonecall2partner(osv.osv_memory):
if context is None:
context = {}
phonecall = self.pool.get('crm.phonecall')
data = self.browse(cr, uid, ids, context=context)[0]
call_ids = context and context.get('active_ids') or []
partner_id = data.partner_id and data.partner_id.id or False
partner_ids = phonecall.convert_partner(cr, uid, call_ids, data.action, partner_id, context=context)
return partner_ids[call_ids[0]]
return phonecall.convert_partner(cr, uid, call_ids, data.action, partner_id, context=context)
crm_phonecall2partner()

View File

@ -0,0 +1,33 @@
# Norwegian Bokmal translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-09-04 14:04+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-09-05 04:46+0000\n"
"X-Generator: Launchpad (build 15901)\n"
#. module: crm_caldav
#: model:ir.actions.act_window,name:crm_caldav.action_caldav_browse
msgid "Caldav Browse"
msgstr "CalDAV Bla"
#. module: crm_caldav
#: model:ir.ui.menu,name:crm_caldav.menu_caldav_browse
msgid "Synchronize This Calendar"
msgstr "Synkroniser denne kalenderen"
#. module: crm_caldav
#: model:ir.model,name:crm_caldav.model_crm_meeting
msgid "Meeting"
msgstr "Møte"

View File

@ -72,7 +72,7 @@ class crm_claim(base_stage, osv.osv):
_description = "Claim"
_order = "priority,date desc"
_inherit = ['mail.thread']
_mail_compose_message = True
_columns = {
'id': fields.integer('ID', readonly=True),
'name': fields.char('Claim Subject', size=128, required=True),
@ -194,13 +194,12 @@ class crm_claim(base_stage, osv.osv):
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'description': msg.get('body'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
})
if msg.get('priority'):
custom_values['priority'] = msg.get('priority')
custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from'), context=context))
return super(crm_claim,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
@ -220,7 +219,7 @@ class crm_claim(base_stage, osv.osv):
'revenue': 'planned_revenue',
'probability':'probability'
}
for line in msg['body_text'].split('\n'):
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()):
@ -239,16 +238,16 @@ class crm_claim(base_stage, osv.osv):
def create_send_note(self, cr, uid, ids, context=None):
msg = _('Claim has been <b>created</b>.')
return self.message_append_note(cr, uid, ids, body=msg, context=context)
return self.message_post(cr, uid, ids, body=msg, context=context)
def case_refuse_send_note(self, cr, uid, ids, context=None):
msg = _('Claim has been <b>refused</b>.')
return self.message_append_note(cr, uid, ids, body=msg, context=context)
return self.message_post(cr, uid, ids, body=msg, context=context)
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """
stage_name = self.pool.get('crm.claim.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
return self.message_post(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
class res_partner(osv.osv):

View File

@ -9,7 +9,6 @@
-
!python {model: crm.claim}: |
try:
self.message_update(cr, uid,[ref('crm_claim_4')], {'subject': 'Claim Update record','body_text': 'first training session completed',})
self.message_update(cr, uid,[ref('crm_claim_4')], {'subject': 'Claim Update record','body': 'first training session completed',})
except:
pass

View File

@ -38,7 +38,7 @@ class crm_helpdesk(base_state, osv.osv):
_description = "Helpdesk"
_order = "id desc"
_inherit = ['mail.thread']
_mail_compose_message = True
_columns = {
'id': fields.integer('ID', readonly=True),
'name': fields.char('Name', size=128, required=True),
@ -105,12 +105,11 @@ class crm_helpdesk(base_state, osv.osv):
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'description': msg.get('body'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
})
custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from'), context=context))
return super(crm_helpdesk,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
@ -130,7 +129,7 @@ class crm_helpdesk(base_state, osv.osv):
'revenue': 'planned_revenue',
'probability':'probability'
}
for line in msg['body_text'].split('\n'):
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()):
@ -149,7 +148,7 @@ class crm_helpdesk(base_state, osv.osv):
def create_send_note(self, cr, uid, ids, context=None):
msg = _('Case has been <b>created</b>.')
self.message_append_note(cr, uid, ids, body=msg, context=context)
self.message_post(cr, uid, ids, body=msg, context=context)
return True

View File

@ -97,7 +97,7 @@ class crm_helpdesk_report(osv.osv):
c.planned_cost,
count(*) as nbr,
extract('epoch' from (c.date_closed-c.create_date))/(3600*24) as delay_close,
(SELECT count(id) FROM mail_message WHERE model='crm.helpdesk' AND res_id=c.id AND email_from IS NOT NULL) AS email,
(SELECT count(id) FROM mail_message WHERE model='crm.helpdesk' AND res_id=c.id AND type = 'email') AS email,
abs(avg(extract('epoch' from (c.date_deadline - c.date_closed)))/(3600*24)) as delay_expected
from
crm_helpdesk c

View File

@ -23,7 +23,7 @@
!python {model: crm.helpdesk}: |
question_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
try:
self.message_update(cr, uid, question_ids, {'subject': 'Link of product', 'body_text': 'www.openerp.com'})
self.message_update(cr, uid, question_ids, {'subject': 'Link of product', 'body': 'www.openerp.com'})
except:
pass

View File

@ -19,8 +19,7 @@
attrs="{'invisible':[('partner_assigned_id','=',False)]}"
name="%(crm_lead_forward_to_partner_act)d"
icon="terp-mail-forward" type="action"
context="{'default_name': 'partner', 'default_partner_id': partner_assigned_id}"
/>
context="{'default_composition_mode': 'forward', 'default_partner_ids': [partner_assigned_id]}"/>
</div>
</group>
<group string="Geo Assignation">
@ -37,8 +36,6 @@
</field>
</record>
<record id="view_crm_opportunity_geo_assign_tree" model="ir.ui.view">
<field name="name">crm.lead.geo_assign.tree.inherit</field>
<field name="model">crm.lead</field>
@ -49,6 +46,7 @@
</field>
</field>
</record>
<record model="ir.ui.view" id="crm_opportunity_partner_filter">
<field name="name">crm.opportunity.partner.filter.assigned</field>
<field name="model">crm.lead</field>
@ -63,5 +61,6 @@
</field>
</field>
</record>
</data>
</openerp>

View File

@ -72,7 +72,7 @@ msgid "Geo Localize"
msgstr ""
#. module: crm_partner_assign
#: help:crm.lead.forward.to.partner,body_text:0
#: help:crm.lead.forward.to.partner,body:0
msgid "Plain-text version of the message"
msgstr ""
@ -129,7 +129,7 @@ msgid "Highest"
msgstr ""
#. module: crm_partner_assign
#: field:crm.lead.forward.to.partner,body_text:0
#: field:crm.lead.forward.to.partner,body:0
msgid "Text contents"
msgstr ""

View File

@ -29,8 +29,8 @@
I forward this opportunity to its nearest partner.
-
!python {model: crm.lead.forward.to.partner}: |
context.update({'active_model': 'crm.lead', 'active_id': ref('crm.crm_case_19'), 'active_ids': [ref('crm.crm_case_19')]})
forward_id = self.create(cr, uid, {'email_from': 'test@openerp.com', 'send_to': 'partner'}, context=context)
context.update({'default_model': 'crm.lead', 'default_res_id': ref('crm.crm_case_19'), 'active_ids': [ref('crm.crm_case_19')]})
forward_id = self.create(cr, uid, {}, context=context)
try:
self.action_forward(cr, uid, [forward_id], context=context)
except:

View File

@ -20,186 +20,153 @@
#
##############################################################################
import time
import re
import time
import tools
from osv import osv, fields
from tools.translate import _
from mail.mail_message import to_email
class crm_lead_forward_to_partner(osv.osv_memory):
"""Forwards lead history"""
""" Forward info history to partners. """
_name = 'crm.lead.forward.to.partner'
_inherit = "mail.compose.message"
def default_get(self, cr, uid, fields, context=None):
if context is None:
context = {}
# set as comment, perform overrided document-like action that calls get_record_data
old_mode = context.get('default_composition_mode', 'forward')
context['default_composition_mode'] = 'comment'
res = super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context)
# back to forward mode
context['default_composition_mode'] = old_mode
res['composition_mode'] = context['default_composition_mode']
return res
def _get_composition_mode_selection(self, cr, uid, context=None):
composition_mode = super(crm_lead_forward_to_partner, self)._get_composition_mode_selection(cr, uid, context=context)
composition_mode.append(('forward', 'Forward'))
return composition_mode
_columns = {
'send_to': fields.selection([('user', 'User'), ('partner', 'Partner'), \
('email', 'Email Address')], 'Send to', required=True),
'user_id': fields.many2one('res.users', "User"),
'attachment_ids': fields.many2many('ir.attachment','lead_forward_to_partner_attachment_rel', 'wizard_id', 'attachment_id', 'Attachments'),
'partner_id' : fields.many2one('res.partner', 'Partner'),
'history': fields.selection([('info', 'Case Information'), ('latest', 'Latest email'), ('whole', 'Whole Story')], 'Send history', required=True),
'partner_ids': fields.many2many('res.partner',
'lead_forward_to_partner_res_partner_rel',
'wizard_id', 'partner_id', 'Additional contacts'),
'attachment_ids': fields.many2many('ir.attachment',
'lead_forward_to_partner_attachment_rel',
'wizard_id', 'attachment_id', 'Attachments'),
'history_mode': fields.selection([('info', 'Case Information'),
('latest', 'Latest email'), ('whole', 'Whole Story')],
'Send history', required=True),
}
_defaults = {
'send_to' : 'email',
'history': 'latest',
'email_from': lambda s, cr, uid, c: s.pool.get('res.users').browse(cr, uid, uid, c).email,
'history_mode': 'latest',
'content_subtype': lambda self,cr, uid, context={}: 'html',
}
def on_change_email(self, cr, uid, ids, user, context=None):
if not user:
return {'value': {'email_to': False}}
return {'value': {'email_to': self.pool.get('res.users').browse(cr, uid, uid, context=context).email}}
def on_change_history(self, cr, uid, ids, history_type, context=None):
"""Gives message body according to type of history selected
* info: Forward the case information
* whole: Send the whole history
* latest: Send the latest histoy
def get_record_data(self, cr, uid, model, res_id, context=None):
""" Override of mail.compose.message, to add default values coming
form the related lead.
"""
#TODO: ids and context are not comming
res = {}
res_id = context.get('active_id')
model = context.get('active_model')
lead = self.pool.get(model).browse(cr, uid, res_id, context)
body_text = self._get_message_body_text(cr, uid, lead, history_type, context=context)
if body_text:
res = {'value': {'body_text' : body_text}}
res = super(crm_lead_forward_to_partner, self).get_record_data(cr, uid, model, res_id, context=context)
if model not in ('crm.lead') or not res_id:
return res
lead_obj = self.pool.get(model)
lead = lead_obj.browse(cr, uid, res_id, context=context)
subject = '%s: %s - %s' % (_('Fwd'), _('Lead forward'), lead.name)
body = self._get_message_body(cr, uid, lead, 'info', context=context)
res.update({
'subject': subject,
'body': body,
})
return res
def on_change_partner(self, cr, uid, ids, partner_id):
"""This function fills address information based on partner/user selected
"""
if not partner_id:
return {'value' : {'email_to' : False}}
partner_obj = self.pool.get('res.partner')
data = {}
partner = partner_obj.browse(cr, uid, [partner_id])
user_id = partner and partner[0].user_id or False
data.update({'email_from': partner and partner[0].email or "",
'email_cc' : user_id and user_id.user or '',
'user_id': user_id and user_id.id or False})
return {'value' : data}
def on_change_history_mode(self, cr, uid, ids, history_mode, model, res_id, context=None):
""" Update body when changing history_mode """
if model and model == 'crm.lead' and res_id:
lead = self.pool.get(model).browse(cr, uid, res_id, context=context)
body = self._get_message_body(cr, uid, lead, history_mode, context=context)
return {'value': {'body': body}}
def create(self, cr, uid, values, context=None):
""" TDE-HACK: remove 'type' from context, because when viewing an
opportunity form view, a default_type is set and propagated
to the wizard, that has a not matching type field. """
default_type = context.pop('default_type', None)
new_id = super(crm_lead_forward_to_partner, self).create(cr, uid, values, context=context)
if default_type:
context['default_type'] = default_type
return new_id
def action_forward(self, cr, uid, ids, context=None):
"""
Forward the lead to a partner
"""
""" Forward the lead to a partner """
if context is None:
context = {}
res = {'type': 'ir.actions.act_window_close'}
model = context.get('active_model')
if model not in ('crm.lead'):
wizard = self.browse(cr, uid, ids[0], context=context)
if wizard.model not in ('crm.lead'):
return res
this = self.browse(cr, uid, ids[0], context=context)
lead = self.pool.get(model)
lead_id = context and context.get('active_id', False) or False
lead_ids = lead_id and [lead_id] or []
mode = context.get('mail.compose.message.mode')
if mode == 'mass_mail':
lead = self.pool.get(wizard.model)
lead_ids = wizard.res_id and [wizard.res_id] or []
if wizard.composition_mode == 'mass_mail':
lead_ids = context and context.get('active_ids', []) or []
value = self.default_get(cr, uid, ['body_text', 'email_to', 'email_cc', 'subject', 'history'], context=context)
value = self.default_get(cr, uid, ['body', 'email_to', 'email_cc', 'subject', 'history_mode'], context=context)
self.write(cr, uid, ids, value, context=context)
context['mail.compose.message.mode'] = mode
self.send_mail(cr, uid, ids, context=context)
for case in lead.browse(cr, uid, lead_ids, context=context):
if (this.send_to == 'partner' and this.partner_id):
lead.assign_partner(cr, uid, [case.id], this.partner_id.id, context=context)
# for case in lead.browse(cr, uid, lead_ids, context=context):
# TODO: WHAT TO DO WITH THAT ?
# if (this.send_to == 'partner' and this.partner_id):
# lead.assign_partner(cr, uid, [case.id], this.partner_id.id, context=context)
if this.send_to == 'user':
lead.allocate_salesman(cr, uid, [case.id], [this.user_id.id], context=context)
email_cc = to_email(case.email_cc)
email_cc = email_cc and email_cc[0] or ''
new_cc = []
if email_cc:
new_cc.append(email_cc)
for to in this.email_to.split(','):
email_to = to_email(to)
email_to = email_to and email_to[0] or ''
if email_to not in new_cc:
new_cc.append(to)
update_vals = {'email_cc' : ', '.join(new_cc) }
lead.write(cr, uid, [case.id], update_vals, context=context)
# if this.send_to == 'user':
# lead.allocate_salesman(cr, uid, [case.id], [this.user_id.id], context=context)
return res
def _get_info_body_text(self, cr, uid, lead, context=None):
def _get_info_body(self, cr, uid, lead, context=None):
field_names = []
proxy = self.pool.get(lead._name)
if lead.type == 'opportunity':
field_names += ['partner_id']
field_names += [
'partner_name' , 'title', 'function', 'street', 'street2',
'partner_name' , 'title', 'function', 'street', 'street2',
'zip', 'city', 'country_id', 'state_id', 'email_from',
'phone', 'fax', 'mobile', 'categ_id', 'description',
]
return proxy._mail_body_text(cr, uid, lead, field_names, context=context)
return proxy._mail_body(cr, uid, lead, field_names, context=context)
def _get_message_body_text(self, cr, uid, lead, mode='whole', context=None):
"""This function gets whole communication history and returns as top posting style
def _get_message_body(self, cr, uid, lead, history_mode='whole', context=None):
""" This function gets whole communication history and returns as top
posting style
#1: form a body, based on the lead
#2: append to the body the communication history, based on the
history_mode parameter
- info: Forward the case information
- latest: Send the latest history
- whole: Send the whole history
:param lead: browse_record on crm.lead
:param history_mode: 'whole' or 'latest'
"""
mail_message = self.pool.get('mail.message')
message_ids = []
body = self._get_info_body_text(cr, uid, lead, context=context)
if mode in ('whole', 'latest'):
message_ids = lead.message_ids
message_ids = map(lambda x: x.id, filter(lambda x: x.email_from, message_ids))
if mode == 'latest' and len(message_ids):
message_ids = [message_ids[0]]
for message in mail_message.browse(cr, uid, message_ids, context=context):
header = '-------- Original Message --------'
sender = 'From: %s' %(message.email_from or '')
to = 'To: %s' % (message.email_to or '')
sentdate = 'Date: %s' % (message.date or '')
desc = '\n%s'%(message.body_text)
original = [header, sender, to, sentdate, desc, '\n']
original = '\n'.join(original)
body += original
body = self._get_info_body(cr, uid, lead, context=context)
if history_mode not in ('whole', 'latest'):
return body or ''
for message in lead.message_ids:
header = '-------- Original Message --------'
sentdate = 'Date: %s' % (message.date or '')
desc = '\n%s'%(message.body)
original = [header, sentdate, desc, '\n']
original = '\n'.join(original)
body += original
if history_mode == 'latest':
break
return body or ''
def get_value(self, cr, uid, model, res_id, context=None):
if context is None:
context = {}
res = super(crm_lead_forward_to_partner, self).get_value(cr, uid, model, res_id, context=context)
if model not in ("crm.lead"):
return res
proxy = self.pool.get(model)
partner = self.pool.get('res.partner')
lead = proxy.browse(cr, uid, res_id, context=context)
mode = context.get('mail.compose.message.mode')
if mode == "forward":
body_type = context.get('mail.compose.message.body')
email_cc = res.get('email_cc', "")
email = res.get('email_to', "")
subject = '%s: %s - %s' % (_('Fwd'), 'Lead forward', lead.name)
body = self._get_message_body_text(cr, uid, lead, body_type, context=context)
partner_assigned_id = lead.partner_assigned_id and lead.partner_assigned_id.id or False
user_id = False
if not partner_assigned_id:
partner_assigned_id = proxy.search_geo_partner(cr, uid, [lead.id], context=None).get(lead.id, False)
if partner_assigned_id:
assigned_partner = partner.browse(cr, uid, partner_assigned_id, context=context)
user_id = assigned_partner.user_id and assigned_partner.user_id.id or False
email_cc = assigned_partner.user_id and assigned_partner.user_id.email or ''
email = assigned_partner.email
res.update({
'subject' : subject,
'body_text' : body,
'email_cc' : email_cc,
'email_to' : email,
'partner_assigned_id': partner_assigned_id,
'user_id': user_id,
})
return res
def default_get(self, cr, uid, fields, context=None):
if context is None:
context = {}
context['mail.compose.message.mode'] = 'forward'
context['mail.compose.message.body'] = 'info'
return super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -7,42 +7,31 @@
<field name="model">crm.lead.forward.to.partner</field>
<field name="arch" type="xml">
<form string="Send Mail" version="7.0">
<field name="composition_mode" colspan="2" nolabel="1" invisible="1"/>
<field name="model" colspan="2" nolabel="1" invisible="1"/>
<field name="res_id" colspan="2" nolabel="1" invisible="1"/>
<separator string="Forward to Partner" colspan="4"/>
<group col="4" colspan="6">
<field name="history" colspan="2" on_change="on_change_history(history, context)"/>
<field name="send_to" colspan="2"/>
<group col="2" colspan="2" attrs="{ 'invisible' : [('send_to','!=','user')]}">
<field name="user_id"
attrs="{ 'required' : [('send_to','=','user')]}"
on_change="on_change_email(user_id)"/>
</group>
<group col="4" colspan="4" attrs="{'invisible' : [('send_to','!=','partner')]}">
<field name="partner_id" attrs="{'required' : [('send_to','=','partner')]}" on_change="on_change_partner(partner_id)" colspan="2"/>
</group>
<group col="4">
<field name="history_mode" colspan="4"
on_change="on_change_history_mode(history_mode, model, res_id)"/>
<field name="subject" colspan="4"/>
<field name="partner_ids" colspan="4" widget="many2many_tags"
on_change="onchange_partner_ids(partner_ids)"/>
<notebook colspan="4">
<page string="Body">
<field name="body"/>
</page>
<page string="Attachments">
<field name="attachment_ids"/>
</page>
</notebook>
</group>
<separator string="" colspan="4"/>
<group col="6" colspan="4">
<field name="email_from" colspan="4" required="1"/>
<field name="email_to" colspan="4" required="1"/>
<field name="email_cc" colspan="4"/>
<field name="email_bcc" colspan="4"/>
<field name="reply_to" colspan="4"/>
<field name="subject" colspan="4" widget="char" size="512"/>
</group>
<separator string="" colspan="4"/>
<notebook colspan="4">
<page string="Body">
<field name="body_text" colspan="4" nolabel="1"/>
</page>
<page string="Attachments">
<label string="Add here all attachments of the current document you want to include in the Email." colspan="4"/>
<field name="attachment_ids" colspan="4" nolabel="1"/>
</page>
</notebook>
<footer>
<button name="action_forward" string="Send" type="object" class="oe_highlight"/>
<button name="action_forward" string="Send" type="object"
class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
<button string="Cancel" special="cancel"
class="oe_link"/>
</footer>
</form>
</field>
@ -57,18 +46,14 @@
<field name="target">new</field>
</record>
<act_window id="action_crm_send_mass_forward"
multi="True"
key2="client_action_multi" name="Mass forward to partner"
res_model="crm.lead.forward.to.partner" src_model="crm.lead"
view_mode="form" target="new" view_type="form"
context="{'mail.compose.message.mode' : 'mass_mail'}"
context="{'default_composition_mode' : 'mass_mail'}"
view_id="crm_lead_forward_to_partner_form"
/>
/>
</data>
</openerp>

View File

@ -0,0 +1,95 @@
# Norwegian Bokmal translation for openobject-addons
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2012-09-04 14:07+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-09-05 04:46+0000\n"
"X-Generator: Launchpad (build 15901)\n"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_project_task
msgid "Task"
msgstr "Oppgave"
#. module: crm_todo
#: view:crm.lead:0
msgid "Timebox"
msgstr "Timeboks"
#. module: crm_todo
#: view:crm.lead:0
msgid "For cancelling the task"
msgstr "For å avbryte oppgaven"
#. module: crm_todo
#: constraint:project.task:0
msgid "Error ! Task end-date must be greater then task start-date"
msgstr "Feil! Oppgave sluttdato må være større enn oppgave startdato"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_crm_lead
msgid "crm.lead"
msgstr "crm.lead"
#. module: crm_todo
#: view:crm.lead:0
msgid "Next"
msgstr "Neste"
#. module: crm_todo
#: model:ir.actions.act_window,name:crm_todo.crm_todo_action
#: model:ir.ui.menu,name:crm_todo.menu_crm_todo
msgid "My Tasks"
msgstr "Mine oppgaver"
#. module: crm_todo
#: view:crm.lead:0
#: field:crm.lead,task_ids:0
msgid "Tasks"
msgstr "Oppgaver"
#. module: crm_todo
#: view:crm.lead:0
msgid "Done"
msgstr "Utført"
#. module: crm_todo
#: constraint:project.task:0
msgid "Error ! You cannot create recursive tasks."
msgstr "Feil! Du kan ikke lage en rekursive oppgaver."
#. module: crm_todo
#: view:crm.lead:0
msgid "Cancel"
msgstr "Kanseller"
#. module: crm_todo
#: view:crm.lead:0
msgid "Extra Info"
msgstr "Ekstra informasjon"
#. module: crm_todo
#: field:project.task,lead_id:0
msgid "Lead / Opportunity"
msgstr "Lede / mulighet"
#. module: crm_todo
#: view:crm.lead:0
msgid "For changing to done state"
msgstr "For å bytte til ferdig tilstand"
#. module: crm_todo
#: view:crm.lead:0
msgid "Previous"
msgstr "Tidligere"

View File

@ -6,7 +6,7 @@
<t t-call="WebClient"/>
</t>
<t t-name="EdiView">
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" id="oe_app" class="oe-application oe_forms">
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" id="oe_app" class="oe-application oe_forms oe_semantic_html_override">
<tr>
<td colspan="2" valign="top" id="oe_header" class="header">
<div> <a href="/" class="company_logo_link">

View File

@ -151,7 +151,7 @@
reference <strong><t t-esc="doc.internal_number"/></strong> on the transfer:
<br/><br/>
</p>
<ul class="oe_edi_nested_block_pay oe_edi_pay_wire_nested">
<ul class="oe_edi_nested_block_pay oe_edi_pay_wire_nested oe_semantic_html_override">
<t t-foreach="doc.company_address.bank_ids" t-as="bank_info">
<li><t t-esc="bank_info[1]"/></li>
</t>

View File

@ -151,7 +151,7 @@
reference <strong><t t-esc="doc.name"/></strong> on the transfer:
<br/><br/>
</p>
<ul class="oe_edi_nested_block_pay oe_edi_pay_wire_nested">
<ul class="oe_edi_nested_block_pay oe_edi_pay_wire_nested oe_semantic_html_override">
<t t-foreach="doc.company_address.bank_ids" t-as="bank_info">
<li><t t-esc="bank_info[1]"/></li>
</t>

View File

@ -28,6 +28,8 @@ from osv import osv
from osv import fields
import tools
from tools.translate import _
from tools.html_sanitize import html_sanitize
from tools import append_content_to_html
from urllib import quote as quote
_logger = logging.getLogger(__name__)
@ -38,10 +40,8 @@ except ImportError:
class email_template(osv.osv):
"Templates for sending email"
_inherit = 'mail.message'
_name = "email.template"
_description = 'Email Templates'
_rec_name = 'name' # override mail.message's behavior
def render_template(self, cr, uid, template, model, res_id, context=None):
"""Render the given template text, replace mako expressions ``${expr}``
@ -99,66 +99,46 @@ class email_template(osv.osv):
mod_name = False
if model_id:
mod_name = self.pool.get('ir.model').browse(cr, uid, model_id, context).model
return {'value':{'model': mod_name}}
def name_get(self, cr, uid, ids, context=None):
""" Override name_get of mail.message: return directly the template
name, and not the generated name from mail.message.common."""
return [(record.id, record.name) for record in self.browse(cr, uid, ids, context=context)]
return {'value': {'model': mod_name}}
_columns = {
'name': fields.char('Name', size=250),
'model_id': fields.many2one('ir.model', 'Related document model'),
'lang': fields.char('Language Selection', size=250,
'name': fields.char('Name'),
'model_id': fields.many2one('ir.model', 'Applies to', help="The kind of document with with this template can be used"),
'model': fields.related('model_id', 'model', type='char', string='Related Document Model',
size=128, select=True, store=True, readonly=True),
'lang': fields.char('Language',
help="Optional translation language (ISO code) to select when sending out an email. "
"If not set, the english version will be used. "
"This should usually be a placeholder expression "
"that provides the appropriate language code, e.g. "
"${object.partner_id.lang.code}."),
"${object.partner_id.lang.code}.",
placeholder="${object.partner_id.lang.code}"),
'user_signature': fields.boolean('Add Signature',
help="If checked, the user's signature will be appended to the text version "
"of the message"),
'report_name': fields.char('Report Filename', size=200, translate=True,
help="Name to use for the generated report file (may contain placeholders)\n"
"The extension can be omitted and will then come from the report type."),
'report_template':fields.many2one('ir.actions.report.xml', 'Optional report to print and attach'),
'ref_ir_act_window':fields.many2one('ir.actions.act_window', 'Sidebar action', readonly=True,
help="Sidebar action to make this template available on records "
"of the related document model"),
'ref_ir_value':fields.many2one('ir.values', 'Sidebar Button', readonly=True,
help="Sidebar button to open the sidebar action"),
'track_campaign_item': fields.boolean('Resource Tracking',
help="Enable this is you wish to include a special tracking marker "
"in outgoing emails so you can identify replies and link "
"them back to the corresponding resource record. "
"This is useful for CRM leads for example"),
# Overridden mail.message.common fields for technical reasons:
'model': fields.related('model_id','model', type='char', string='Related Document Model',
size=128, select=True, store=True, readonly=True),
# we need a separate m2m table to avoid ID collisions with the original mail.message entries
'attachment_ids': fields.many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id',
'attachment_id', 'Files to attach',
help="You may attach files to this template, to be added to all "
"emails created from this template"),
# Overridden mail.message.common fields to make tooltips more appropriate:
'subject':fields.char('Subject', size=512, translate=True, help="Subject (placeholders may be used here)",),
'email_from': fields.char('From', size=128, help="Sender address (placeholders may be used here)"),
'email_to': fields.char('To', size=256, help="Comma-separated recipient addresses (placeholders may be used here)"),
'email_cc': fields.char('Cc', size=256, help="Carbon copy recipients (placeholders may be used here)"),
'email_bcc': fields.char('Bcc', size=256, help="Blind carbon copy recipients (placeholders may be used here)"),
'reply_to': fields.char('Reply-To', size=250, help="Preferred response address (placeholders may be used here)"),
'subject': fields.char('Subject', translate=True, help="Subject (placeholders may be used here)",),
'email_from': fields.char('From', help="Sender address (placeholders may be used here)"),
'email_to': fields.char('To', help="Comma-separated recipient addresses (placeholders may be used here)"),
'email_cc': fields.char('Cc', help="Carbon copy recipients (placeholders may be used here)"),
'reply_to': fields.char('Reply-To', help="Preferred response address (placeholders may be used here)"),
'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False,
help="Optional preferred server for outgoing mails. If not set, the highest "
"priority one will be used."),
'body_text': fields.text('Text Contents', translate=True, help="Plaintext version of the message (placeholders may be used here)"),
'body_html': fields.text('Rich-text Contents', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
'message_id': fields.char('Message-Id', size=256, help="Message-ID SMTP header to use in outgoing messages based on this template. "
"Please note that this overrides the 'Resource Tracking' option, "
"so if you simply need to track replies to outgoing emails, enable "
"that option instead.\n"
"Placeholders must be used here, as this value always needs to be unique!"),
'body_html': fields.text('Body', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
'report_name': fields.char('Report Filename', translate=True,
help="Name to use for the generated report file (may contain placeholders)\n"
"The extension can be omitted and will then come from the report type."),
'report_template': fields.many2one('ir.actions.report.xml', 'Optional report to print and attach'),
'ref_ir_act_window': fields.many2one('ir.actions.act_window', 'Sidebar action', readonly=True,
help="Sidebar action to make this template available on records "
"of the related document model"),
'ref_ir_value': fields.many2one('ir.values', 'Sidebar Button', readonly=True,
help="Sidebar button to open the sidebar action"),
'attachment_ids': fields.many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id',
'attachment_id', 'Attachments',
help="You may attach files to this template, to be added to all "
"emails created from this template"),
'auto_delete': fields.boolean('Auto Delete', help="Permanently delete this email after sending it, to save space"),
# Fake fields used to implement the placeholder assistant
'model_object_field': fields.many2one('ir.model.fields', string="Field",
@ -172,12 +152,12 @@ class email_template(osv.osv):
help="When a relationship field is selected as first field, "
"this field lets you select the target field within the "
"destination document model (sub-model)."),
'null_value': fields.char('Null value', help="Optional value to use if the target field is empty", size=128),
'copyvalue': fields.char('Expression', size=256, help="Final placeholder expression, to be copy-pasted in the desired template field."),
'null_value': fields.char('Default Value', help="Optional value to use if the target field is empty"),
'copyvalue': fields.char('Placeholder Expression', help="Final placeholder expression, to be copy-pasted in the desired template field."),
}
_defaults = {
'track_campaign_item': True
'auto_delete': True,
}
def create_action(self, cr, uid, ids, context=None):
@ -195,7 +175,7 @@ class email_template(osv.osv):
'res_model': 'mail.compose.message',
'src_model': src_obj,
'view_type': 'form',
'context': "{'mail.compose.message.mode':'mass_mail', 'mail.compose.template_id' : %d}" % (template.id),
'context': "{'default_composition_mode': 'mass_mail', 'default_template_id' : %d}" % (template.id),
'view_mode':'form,tree',
'view_id': res_id,
'target': 'new',
@ -222,7 +202,7 @@ class email_template(osv.osv):
if template.ref_ir_value:
ir_values_obj = self.pool.get('ir.values')
ir_values_obj.unlink(cr, uid, template.ref_ir_value.id, context)
except:
except Exception:
raise osv.except_osv(_("Warning"), _("Deletion of the action record failed."))
return True
@ -294,65 +274,33 @@ class email_template(osv.osv):
:param res_id: id of the record to use for rendering the template (model
is taken from template definition)
:returns: a dict containing all relevant fields for creating a new
mail.message entry, with the addition one additional
special key ``attachments`` containing a list of
mail.mail entry, with one extra key ``attachments``, in the
format expected by :py:meth:`mail_thread.message_post`.
"""
if context is None:
context = {}
values = {
'subject': False,
'body_text': False,
'body_html': False,
'email_from': False,
'email_to': False,
'email_cc': False,
'email_bcc': False,
'reply_to': False,
'auto_delete': False,
'model': False,
'res_id': False,
'mail_server_id': False,
'attachments': False,
'attachment_ids': False,
'message_id': False,
'state': 'outgoing',
'content_subtype': 'plain',
'partner_ids': [],
}
if not template_id:
return values
report_xml_pool = self.pool.get('ir.actions.report.xml')
template = self.get_email_template(cr, uid, template_id, res_id, context)
for field in ['subject', 'body_text', 'body_html', 'email_from',
'email_to', 'email_cc', 'email_bcc', 'reply_to',
'message_id']:
values = {}
for field in ['subject', 'body_html', 'email_from',
'email_to', 'email_cc', 'reply_to']:
values[field] = self.render_template(cr, uid, getattr(template, field),
template.model, res_id, context=context) \
or False
# if email_to: find or create a partner
if values['email_to']:
partner_id = self.pool.get('mail.thread').message_partner_by_email(cr, uid, values['email_to'], context=context)['partner_id']
if not partner_id:
partner_id = self.pool.get('res.partner').name_create(cr, uid, values['email_to'], context=context)
values['partner_ids'] = [partner_id]
if values['body_html']:
values.update(content_subtype='html')
if template.user_signature:
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
values['body_text'] += '\n\n' + signature
values['body_html'] = append_content_to_html(values['body_html'], signature)
values.update(mail_server_id = template.mail_server_id.id or False,
auto_delete = template.auto_delete,
if values['body_html']:
values['body'] = html_sanitize(values['body_html'])
values.update(mail_server_id=template.mail_server_id.id or False,
auto_delete=template.auto_delete,
model=template.model,
res_id=res_id or False)
attachments = {}
# Add report as a Document
attachments = []
# Add report in attachments
if template.report_template:
report_name = self.render_template(cr, uid, template.report_name, template.model, res_id, context=context)
report_service = 'report.' + report_xml_pool.browse(cr, uid, template.report_template.id, context).report_name
@ -368,12 +316,11 @@ class email_template(osv.osv):
ext = "." + format
if not report_name.endswith(ext):
report_name += ext
attachments[report_name] = result
attachments.append(report_name, result)
# Add document attachments
# Add template attachments
for attach in template.attachment_ids:
# keep the bytes as fetched from the db, base64 encoded
attachments[attach.datas_fname] = attach.datas
attachments.append((attach.datas_fname, attach.datas))
values['attachments'] = attachments
return values
@ -391,12 +338,12 @@ class email_template(osv.osv):
:returns: id of the mail.message that was created
"""
if context is None: context = {}
mail_message = self.pool.get('mail.message')
mail_mail = self.pool.get('mail.mail')
ir_attachment = self.pool.get('ir.attachment')
values = self.generate_email(cr, uid, template_id, res_id, context=context)
assert 'email_from' in values, 'email_from is missing or empty after template rendering, send_mail() cannot proceed'
attachments = values.pop('attachments') or {}
msg_id = mail_message.create(cr, uid, values, context=context)
msg_id = mail_mail.create(cr, uid, values, context=context)
# link attachments
attachment_ids = []
for fname, fcontent in attachments.iteritems():
@ -404,15 +351,15 @@ class email_template(osv.osv):
'name': fname,
'datas_fname': fname,
'datas': fcontent,
'res_model': mail_message._name,
'res_model': mail_mail._name,
'res_id': msg_id,
}
context.pop('default_type', None)
attachment_ids.append(ir_attachment.create(cr, uid, attachment_data, context=context))
if attachment_ids:
mail_message.write(cr, uid, msg_id, {'attachment_ids': [(6, 0, attachment_ids)]}, context=context)
mail_mail.write(cr, uid, msg_id, {'attachment_ids': [(6, 0, attachment_ids)]}, context=context)
if force_send:
mail_message.send(cr, uid, [msg_id], context=context)
mail_mail.send(cr, uid, [msg_id], context=context)
return msg_id
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,99 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="email_template_form">
<field name="name">email.template.form</field>
<field name="model">email.template</field>
<field name="arch" type="xml">
<form string="Templates" version="7.0">
<sheet>
<group col="4">
<field name="name" required="1"/>
<field name="model_id" required="1" on_change="onchange_model_id(model_id)"/>
<field name="model" invisible="1"/>
</group>
<notebook>
<page string="Email Details">
<group>
<field name="email_from" required="1"/>
<field name="email_to" required="1"/>
<field name="email_cc"/>
<field name="email_bcc"/>
<field name="reply_to"/>
<field name="subject" required="1"/>
<notebook colspan="4">
<page string="Body (Text)">
<field name="body_text" colspan="4" width="250" height="250" nolabel="1"/>
</page>
<page string="Body (Rich/HTML)">
<field name="body_html" colspan="4" width="250" height="250" nolabel="1"/>
<label string="Note: This is Raw HTML." colspan="4"/>
</page>
</notebook>
<field name="user_signature"/>
<notebook colspan="4">
<page string="Dynamic Values Builder">
<group>
<field name="model_object_field"
domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]"
on_change="onchange_sub_model_object_value_field(model_object_field)"/>
<field name="sub_object" readonly="1"/>
<field name="sub_model_object_field"
domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]"
attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}"
on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
<field name="null_value" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)"/>
<field name="copyvalue"/>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only"/><h1><field name="name" required="1"/></h1>
<h3><label for="model_id"/><field name="model_id" required="1" on_change="onchange_model_id(model_id)" class="oe_inline"/></h3>
<field name="model" invisible="1"/>
</div>
<div class="oe_right oe_button_box" name="buttons">
<field name="ref_ir_act_window" invisible="1"/>
<button name="create_action" string="Add context action" type="object"
attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
help="Display an option on related documents to open a composition wizard with this template"/>
<button name="unlink_action" string="Remove context action" type="object"
attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
help="Remove the contextual action to use this template on related documents"/>
<button name="%(wizard_email_template_preview)d" string="Preview"
type="action" target="new"
context="{'template_id':active_id}"/>
</div>
<notebook>
<page string="Email Details">
<group>
<group string="Addressing">
<field name="email_from" required="1"/>
<field name="email_to" required="1"/>
<field name="email_cc"/>
<field name="reply_to"/>
<field name="user_signature"/>
</group>
<group string="Dynamic Value Builder" class="oe_edit_only">
<field name="model_object_field" domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]" on_change="onchange_sub_model_object_value_field(model_object_field)"/>
<field name="sub_object" readonly="1"/>
<field name="sub_model_object_field" domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]" attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
<field name="null_value" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)"/>
<field name="copyvalue"/>
</group>
<group string="Contents" colspan="2">
<field name="subject" required="1"/>
<field name="body_html" width="250" height="450" nolabel="1" colspan="2" placeholder="Email contents (in raw HTML format)"/>
</group>
</page>
</notebook>
<button name="%(wizard_email_template_preview)d" string="Preview Template"
type="action" colspan="4" target="new" icon="gtk-zoom-fit" context="{'template_id':active_id}"/>
</group>
</page>
<page string="Advanced">
<group colspan="2" col="2">
<group colspan="2" col="2">
<separator string="Sidebar Button" colspan="2"/>
<button name="create_action" string="Add sidebar button" type="object" icon="gtk-execute"
colspan="2" attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
help="Display a button in the sidebar of related documents to open a composition wizard with this template"
/>
<field name="ref_ir_act_window" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
<field name="ref_ir_value" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
<button name="unlink_action" string="Remove sidebar button" type="object" icon="gtk-delete"
colspan="2" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
help="Remove the sidebar button currently displayed on related documents"
/>
</group>
<group colspan="2" col="2">
<separator string="Advanced Options" colspan="2"/>
<field name="mail_server_id"/>
<field name="track_campaign_item"/>
<field name="message_id"/>
<field name="auto_delete"/>
</page>
<page string="Advanced">
<group>
<field name="lang"/>
<field name="mail_server_id"/>
<field name="auto_delete"/>
<field name="report_template" domain="[('model','=',model)]"/>
<field name="report_name" class="oe_inline"
attrs="{'invisible':[('report_template','=',False)]}"/>
<field name="attachment_ids">
<tree><field name="name"/></tree>
</field>
</group>
</group>
<group colspan="2" col="2">
<separator string="Attachments" colspan="2"/>
<notebook colspan="2">
<page string="Attach Report">
<group>
<field name="report_template" colspan="4"
domain="[('model','=',model)]"/>
<field name="report_name" colspan="4" />
</group>
</page>
<page string="Attach existing files">
<field name="attachment_ids" colspan="4" nolabel="1" height="350"/>
</page>
</notebook>
</group>
</page>
</notebook>
</sheet>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
@ -103,9 +71,9 @@
<field name="model">email.template</field>
<field name="arch" type="xml">
<tree string="Templates">
<field name="model_id"/>
<field name="mail_server_id" invisible="1"/>
<field name="name"/>
<field name="model_id"/>
<field name="subject"/>
<field name="email_from"/>
<field name="email_to"/>

View File

@ -289,8 +289,8 @@ msgid "Add Signature"
msgstr ""
#. module: email_template
#: help:email.template,body_text:0
#: help:email_template.preview,body_text:0
#: help:email.template,body:0
#: help:email_template.preview,body:0
msgid "Plaintext version of the message (placeholders may be used here)"
msgstr ""
@ -425,8 +425,8 @@ msgid "Cc"
msgstr ""
#. module: email_template
#: field:email.template,body_text:0
#: field:email_template.preview,body_text:0
#: field:email.template,body:0
#: field:email_template.preview,body:0
msgid "Text Contents"
msgstr ""

View File

@ -1,5 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_email_template,email.template,model_email_template,,1,0,0,0
access_email_template,email.template,model_email_template,,1,1,1,0
access_email_template_system,email.template system,model_email_template,base.group_system,1,1,1,1
access_email_template_manager,email.template,model_email_template,,1,1,1,1
access_email_template_preview_system,email.template.preview system,model_email_template_preview,base.group_system,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_email_template email.template model_email_template 1 0 1 0 1 0
3 access_email_template_system email.template system model_email_template base.group_system 1 1 1 1
access_email_template_manager email.template model_email_template 1 1 1 1
access_email_template_preview_system email.template.preview system model_email_template_preview base.group_system 1 1 1 1

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -18,7 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_mail
import project_mailgate
checks = [
test_mail,
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,186 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import base64
from openerp.tests import common
class test_message_compose(common.TransactionCase):
def _mock_smtp_gateway(self, *args, **kwargs):
return True
def _mock_build_email(self, *args, **kwargs):
self._build_email_args = args
self._build_email_kwargs = kwargs
return self.build_email_real(*args, **kwargs)
def setUp(self):
super(test_message_compose, self).setUp()
self.mail_group = self.registry('mail.group')
self.mail_mail = self.registry('mail.mail')
self.mail_message = self.registry('mail.message')
self.res_users = self.registry('res.users')
self.res_partner = self.registry('res.partner')
# Install mock SMTP gateway
self.build_email_real = self.registry('ir.mail_server').build_email
self.registry('ir.mail_server').build_email = self._mock_build_email
self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
# create a 'pigs' and 'bird' groups that will be used through the various tests
self.group_pigs_id = self.mail_group.create(self.cr, self.uid,
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !'})
self.group_bird_id = self.mail_group.create(self.cr, self.uid,
{'name': 'Bird', 'description': 'I am angry !'})
def test_00_message_compose_wizard(self):
""" Tests designed for the mail.compose.message wizard updated by email_template. """
cr, uid = self.cr, self.uid
mail_compose = self.registry('mail.compose.message')
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a.a'})
user_admin = self.res_users.browse(cr, uid, uid)
p_a_id = user_admin.partner_id.id
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
group_bird = self.mail_group.browse(cr, uid, self.group_bird_id)
# Mail data
_subject1 = 'Pigs'
_subject2 = 'Bird'
_body_html1 = 'Fans of Pigs, unite !\n<pre>Admin</pre>\n'
_body_html2 = 'I am angry !\n<pre>Admin</pre>\n'
_attachments = [
{'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment')},
{'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment')}
]
_attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
# Create template on mail.group, with attachments
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
email_template = self.registry('email.template')
email_template_id = email_template.create(cr, uid, {'model_id': group_model_id,
'name': 'Pigs Template', 'subject': '${object.name}',
'body_html': '${object.description}', 'user_signature': True,
'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])],
'email_to': 'b@b.b c@c.c', 'email_cc': 'd@d.d'})
# ----------------------------------------
# CASE1: comment and save as template
# ----------------------------------------
# 1. Comment on pigs
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': '<p>Dummy body</p>'},
{'default_composition_mode': 'comment', 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
'default_template_id': email_template_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# 2. Save current composition form as a template
mail_compose.save_as_template(cr, uid, [compose_id], context={'default_model': 'mail.group'})
# Test: email_template subject, body_html, model
last_template_id = email_template.search(cr, uid, [('model', '=', 'mail.group'), ('subject', '=', 'Forget me subject')], limit=1)[0]
self.assertTrue(last_template_id, 'email_template not found for model mail.group, subject Forget me subject')
last_template = email_template.browse(cr, uid, last_template_id)
self.assertEqual(last_template.body_html, '<p>Dummy body</p>', 'email_template incorrect body_html')
# ----------------------------------------
# CASE2: comment with template, save as template
# ----------------------------------------
# 1. Comment on pigs
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': 'Dummy body'},
{'default_composition_mode': 'comment', 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
'default_template_id': email_template_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# 2. Perform 'toggle_template', to set use_template and use template_id
mail_compose.toggle_template(cr, uid, [compose_id], {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
compose.refresh()
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
# Test: mail.compose.message: subject, body, content_subtype, partner_ids
self.assertEqual(compose.subject, _subject1, 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, _body_html1, 'mail.compose.message body incorrect')
self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message content_subtype incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# Test: mail.compose.message: attachments
# Test: mail.message: attachments
for attach in compose.attachment_ids:
self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
self.assertIn((attach.name, base64.b64decode(attach.datas)), _attachments_test,
'mail.message attachment name / data incorrect')
# 3. Perform 'toggle_template': template is not set anymore
mail_compose.toggle_template(cr, uid, [compose_id], {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
compose.refresh()
# Test: subject, body, partner_ids
self.assertEqual(compose.subject, False, 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, '', 'mail.compose.message body incorrect')
# ----------------------------------------
# CASE3: mass_mail with template
# ----------------------------------------
# 1. Mass_mail on pigs and bird, with a default_partner_ids set to check he is correctly added
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': 'Dummy body'},
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
'default_template_id': email_template_id,
'default_partner_ids': [p_a_id],
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# 2. Perform 'toggle_template', to set use_template and use template_id
mail_compose.toggle_template(cr, uid, [compose_id], {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
compose.refresh()
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = [p_a_id]
# Test: mail.compose.message: subject, body, content_subtype, partner_ids
self.assertEqual(compose.subject, '${object.name}', 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, '${object.description}', 'mail.compose.message body incorrect')
self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message content_subtype incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# 3. Post the comment, get created message
mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id, self.group_bird_id]})
group_pigs.refresh()
group_bird.refresh()
message_pigs = group_pigs.message_ids[0]
message_bird = group_bird.message_ids[0]
# Test: subject, body
self.assertEqual(message_pigs.subject, _subject1, 'mail.message subject on Pigs incorrect')
self.assertEqual(message_bird.subject, _subject2, 'mail.message subject on Bird incorrect')
self.assertEqual(message_pigs.body, _body_html1, 'mail.message body on Pigs incorrect')
self.assertEqual(message_bird.body, _body_html2, 'mail.message body on Bird incorrect')
# Test: partner_ids: p_a_id (default) + 3 newly created partners
message_pigs_pids = [partner.id for partner in message_pigs.partner_ids]
message_bird_pids = [partner.id for partner in message_bird.partner_ids]
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])]) + [p_a_id]
self.assertEqual(len(message_pigs_pids), len(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
self.assertEqual(len(message_bird_pids), len(partner_ids), 'mail.message on bird partner_ids incorrect')
self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird partner_ids incorrect')

View File

@ -26,7 +26,6 @@ class email_template_preview(osv.osv_memory):
_inherit = "email.template"
_name = "email_template.preview"
_description = "Email Template Preview"
_rec_name = "subject"
def _get_records(self, cr, uid, context=None):
"""
@ -66,30 +65,19 @@ class email_template_preview(osv.osv_memory):
return result
_columns = {
'res_id':fields.selection(_get_records, 'Sample Document'),
'res_id': fields.selection(_get_records, 'Sample Document'),
}
def on_change_res_id(self, cr, uid, ids, res_id, context=None):
if not res_id:
return {}
if not res_id: return {}
vals = {}
email_template = self.pool.get('email.template')
template_id = context and context.get('template_id')
template = email_template.get_email_template(cr, uid, template_id=template_id, record_id=res_id, context=context)
model = template.model
vals['email_to'] = self.render_template(cr, uid, template.email_to, model, res_id, context)
vals['email_cc'] = self.render_template(cr, uid, template.email_cc, model, res_id, context)
vals['email_bcc'] = self.render_template(cr, uid, template.email_bcc, model, res_id, context)
vals['reply_to'] = self.render_template(cr, uid, template.reply_to, model, res_id, context)
vals['subject'] = self.render_template(cr, uid, template.subject, model, res_id, context)
description = self.render_template(cr, uid, template.body_text, model, res_id, context) or ''
if template.user_signature:
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
description += '\n' + signature
vals['body_text'] = description
if template.body_html:
vals['body_html'] = self.render_template(cr, uid, template.body_html, model, res_id, context) or ''
vals['report_name'] = self.render_template(cr, uid, template.report_name, model, res_id, context)
template = email_template.browse(cr, uid, template_id, context=context)
vals['name'] = template.name
mail_values = email_template.generate_email(cr, uid, template_id, res_id, context=context)
for k in ('email_from','email_to','email_cc','reply_to','subject','body_html'):
vals[k] = mail_values[k]
return {'value': vals}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -6,27 +6,22 @@
<field name="name">email_template.preview.form</field>
<field name="model">email_template.preview</field>
<field name="arch" type="xml">
<form string="Email Preview">
<field name="model_id" invisible="1"/>
<field name="res_id" on_change="on_change_res_id(res_id, context)"/>
<group col="2" colspan="4">
<field name="email_to" readonly="1"/>
<field name="email_cc" readonly="1" attrs="{'invisible': [('email_cc','=',False)]}"/>
<field name="email_bcc" readonly="1" attrs="{'invisible': [('email_bcc','=',False)]}"/>
<field name="reply_to" readonly="1" attrs="{'invisible': [('reply_to','=',False)]}"/>
<field name="subject" readonly="1"/>
<form string="Email Preview" version="7.0">
<div>
<h2>Preview of <field name="name" readonly="1" class="oe_inline"/></h2>
<field name="model_id" invisible="1"/>
<h3>Using sample document
<field name="res_id" on_change="on_change_res_id(res_id, context)" class="oe_inline"/>
</h3>
</div>
<group>
<field name="email_from" readonly="1"/>
<field name="email_to" readonly="1"/>
<field name="email_cc" readonly="1" attrs="{'invisible':[('email_cc','=',False)]}"/>
<field name="reply_to" readonly="1" attrs="{'invisible':[('reply_to','=',False)]}"/>
<field name="subject" readonly="1"/>
<field name="body_html" widget="html" readonly="1"/>
</group>
<group col="4" colspan="4">
<notebook>
<page string="Body (Text)">
<field name="body_text" nolabel="1" colspan="4" height="350" width="350" readonly="1"/>
</page>
<page string="Body (Rich/HTML)" attrs="{'invisible': [('body_html','=', False)]}">
<field name="body_html" nolabel="1" colspan="4" height="350" width="350" readonly="1"/>
</page>
</notebook>
</group>
<field name="report_name" colspan="4" readonly="1"/>
</form>
</field>
</record>

View File

@ -19,138 +19,155 @@
#
##############################################################################
import base64
import tools
from osv import osv
from osv import fields
from tools.translate import _
import tools
class mail_compose_message(osv.osv_memory):
_inherit = 'mail.compose.message'
def _get_templates(self, cr, uid, context=None):
"""
Return Email Template of particular Model.
"""
if context is None:
context = {}
record_ids = []
email_template= self.pool.get('email.template')
model = False
if context.get('message_id'):
mail_message = self.pool.get('mail.message')
message_data = mail_message.browse(cr, uid, int(context.get('message_id')), context)
model = message_data.model
elif context.get('mail.compose.target.model') or context.get('active_model'):
model = context.get('mail.compose.target.model', context.get('active_model'))
email_template_obj = self.pool.get('email.template')
message_id = context.get('default_parent_id', context.get('message_id', context.get('active_id')))
if context.get('default_composition_mode') == 'reply' and message_id:
message_data = self.pool.get('mail.message').browse(cr, uid, message_id, context=context)
if message_data:
model = message_data.model
else:
model = context.get('default_model', context.get('active_model'))
if model:
record_ids = email_template.search(cr, uid, [('model', '=', model)])
return email_template.name_get(cr, uid, record_ids, context) + [(False,'')]
record_ids = email_template_obj.search(cr, uid, [('model', '=', model)], context=context)
return email_template_obj.name_get(cr, uid, record_ids, context) + [(False, '')]
return []
def default_get(self, cr, uid, fields, context=None):
if context is None:
context = {}
result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
result['template_id'] = context.get('default_template_id', context.get('mail.compose.template_id', False))
# force html when using templates
if result.get('use_template'):
result['content_subtype'] = 'html'
return result
_columns = {
'use_template': fields.boolean('Use Template'),
'template_id': fields.selection(_get_templates, 'Template',
size=-1 # means we want an int db column
),
}
_defaults = {
'template_id' : lambda self, cr, uid, context={} : context.get('mail.compose.template_id', False)
# incredible hack of the day: size=-1 means we want an int db column instead of an str one
'template_id': fields.selection(_get_templates, 'Template', size=-1),
}
def on_change_template(self, cr, uid, ids, use_template, template_id, email_from=None, email_to=None, context=None):
if context is None:
context = {}
values = {}
if template_id:
res_id = context.get('active_id', False)
if context.get('mail.compose.message.mode') == 'mass_mail':
# use the original template values - to be rendered when actually sent
# by super.send_mail()
values = self.pool.get('email.template').read(cr, uid, template_id, self.fields_get_keys(cr, uid), context)
else:
# render the mail as one-shot
values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
# get partner_ids back
values['dest_partner_ids'] = values['partner_ids']
# retrofit generated attachments in the expected field format
if values['attachments']:
attachment = values.pop('attachments')
attachment_obj = self.pool.get('ir.attachment')
att_ids = []
for fname, fcontent in attachment.iteritems():
data_attach = {
'name': fname,
'datas': fcontent,
'datas_fname': fname,
'description': fname,
'res_model' : self._name,
'res_id' : ids[0] if ids else False
}
att_ids.append(attachment_obj.create(cr, uid, data_attach))
values['attachment_ids'] = att_ids
def onchange_template_id(self, cr, uid, ids, use_template, template_id, composition_mode, model, res_id, context=None):
""" - use_template not set: return default_get
- use_template set in mass_mailing: we cannot render, so return the template values
- use_template set: return rendered values """
if use_template and template_id and composition_mode == 'mass_mail':
values = self.pool.get('email.template').read(cr, uid, template_id, ['subject', 'body_html'], context)
values.pop('id')
elif use_template and template_id:
values = self.generate_email_for_composer(cr, uid, template_id, res_id, context=context)
# transform attachments into attachment_ids
values['attachment_ids'] = []
ir_attach_obj = self.pool.get('ir.attachment')
for attach_fname, attach_datas in values.pop('attachments', []):
data_attach = {
'name': attach_fname,
'datas': attach_datas,
'datas_fname': attach_fname,
'res_model': model,
'res_id': res_id,
}
values['attachment_ids'].append(ir_attach_obj.create(cr, uid, data_attach, context=context))
else:
# restore defaults
values = self.default_get(cr, uid, self.fields_get_keys(cr, uid), context)
values.update(use_template=use_template, template_id=template_id)
values = self.default_get(cr, uid, ['body', 'body_html', 'subject', 'partner_ids', 'attachment_ids'], context=context)
if values.get('body_html'):
values['body'] = values.pop('body_html')
values.update(use_template=use_template, template_id=template_id)
return {'value': values}
def template_toggle(self, cr, uid, ids, context=None):
def toggle_template(self, cr, uid, ids, context=None):
""" hit toggle template mode button: calls onchange_use_template to
emulate an on_change, then writes the values to update the form. """
for record in self.browse(cr, uid, ids, context=context):
values = {}
use_template = record.use_template
# simulate an on_change on use_template
values.update(self.onchange_use_template(cr, uid, ids, not use_template, context=context)['value'])
record.write(values)
return False
onchange_res = self.onchange_use_template(cr, uid, ids, not record.use_template,
record.template_id, record.composition_mode, record.model, record.res_id, context=context).get('value', {})
# update partner_ids and attachment_ids
onchange_res['partner_ids'] = [(4, partner_id) for partner_id in onchange_res.pop('partner_ids', [])]
onchange_res['attachment_ids'] = [(4, attachment_id) for attachment_id in onchange_res.pop('attachment_ids', [])]
record.write(onchange_res)
return True
def onchange_use_template(self, cr, uid, ids, use_template, context=None):
values = {'use_template': use_template}
for record in self.browse(cr, uid, ids, context=context):
if not use_template:
# equivalent to choosing an empty template
onchange_template_values = self.on_change_template(cr, uid, record.id, use_template,
False, email_from=record.email_from, email_to=record.email_to, context=context)
values.update(onchange_template_values['value'])
return {'value': values}
def onchange_use_template(self, cr, uid, ids, use_template, template_id, composition_mode, model, res_id, context=None):
""" onchange_use_template (values: True or False). If use_template is
False, we do as an onchange with template_id False for values """
values = self.onchange_template_id(cr, uid, ids, use_template,
template_id, composition_mode, model, res_id, context=context)
# force html when using templates
if use_template:
values['value']['content_subtype'] = 'html'
return values
def save_as_template(self, cr, uid, ids, context=None):
if context is None:
context = {}
""" hit save as template button: current form value will be a new
template attached to the current document. """
email_template = self.pool.get('email.template')
model_pool = self.pool.get('ir.model')
ir_model_pool = self.pool.get('ir.model')
for record in self.browse(cr, uid, ids, context=context):
model = record.model or context.get('active_model')
model_ids = model_pool.search(cr, uid, [('model', '=', model)])
model_ids = ir_model_pool.search(cr, uid, [('model', '=', record.model)], context=context)
model_id = model_ids and model_ids[0] or False
model_name = ''
if model_id:
model_name = model_pool.browse(cr, uid, model_id, context=context).name
model_name = ir_model_pool.browse(cr, uid, model_id, context=context).name
template_name = "%s: %s" % (model_name, tools.ustr(record.subject))
values = {
'name': template_name,
'email_from': record.email_from or False,
'subject': record.subject or False,
'body_text': record.body_text or False,
'email_to': record.email_to or False,
'email_cc': record.email_cc or False,
'email_bcc': record.email_bcc or False,
'reply_to': record.reply_to or False,
'body_html': record.body or False,
'model_id': model_id or False,
'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])]
}
template_id = email_template.create(cr, uid, values, context=context)
record.write({'template_id': template_id,
'use_template': True})
record.write({'template_id': template_id, 'use_template': True})
return True
# _reopen same wizard screen with new template preselected
return False
#------------------------------------------------------
# Wizard validation and send
#------------------------------------------------------
def generate_email_for_composer(self, cr, uid, template_id, res_id, context=None):
""" Call email_template.generate_email(), get fields relevant for
mail.compose.message, transform email_cc and email_to into partner_ids """
template_values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
# filter template values
fields = ['body', 'body_html', 'subject', 'email_to', 'email_cc', 'attachments']
values = dict((field, template_values[field]) for field in fields if template_values.get(field))
values['body'] = values.pop('body_html', '')
# transform email_to, email_cc into partner_ids
values['partner_ids'] = []
mails = tools.email_split(values.pop('email_to', '') + ' ' + values.pop('email_cc', ''))
for mail in mails:
partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
values['partner_ids'].append(partner_id)
return values
def render_message(self, cr, uid, wizard, res_id, context=None):
""" Generate an email from the template for given (model, res_id) pair.
This method is meant to be inherited by email_template that will
produce a more complete dictionary, with email_to, ...
"""
# generate the composer email
values = self.generate_email_for_composer(cr, uid, wizard.template_id, res_id, context=context)
# get values to return
email_dict = super(mail_compose_message, self).render_message(cr, uid, wizard, res_id, context)
email_dict.update(values)
return email_dict
# override the basic implementation
def render_template(self, cr, uid, template, model, res_id, context=None):
return self.pool.get('email.template').render_template(cr, uid, template, model, res_id, context=context)

View File

@ -10,15 +10,16 @@
<data>
<xpath expr="//form/footer/button" position="before">
<field name="use_template" invisible="1"/>
<button icon="gtk-paste" type="object" name="template_toggle"
<button icon="gtk-paste" type="object" name="toggle_template"
string="" help="Use a message template" />
<button icon="gtk-save" type="object" name="save_as_template"
string="" help="Save as a new template"/>
</xpath>
<xpath expr="//form/notebook" position="after">
<group attrs="{'invisible':[('use_template','=',False)]}" colspan="4" col="4">
<field name="use_template" invisible="1"/>
<field name="template_id" colspan="3"
on_change="on_change_template(use_template, template_id, email_from, email_to, context)"/>
on_change="onchange_template_id(use_template, template_id, composition_mode, model, res_id, context)"/>
</group>
</xpath>
</data>
@ -31,20 +32,22 @@
<field name="inherit_id" ref="mail.email_compose_message_wizard_form_chatter"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='dest_partner_ids']" position="after">
<xpath expr="//field[@name='partner_ids']" position="after">
<field name="use_template" colspan="2" nolabel="1" invisible="1"
on_change="onchange_use_template(use_template, context)"/>
on_change="onchange_use_template(use_template, template_id, composition_mode, model, res_id, context)"/>
<field name="template_id" colspan="2" nolabel="1"
attrs="{'invisible':[('use_template','=',False)]}"
on_change="on_change_template(use_template, template_id, False, False, context)"/>
on_change="onchange_template_id(use_template, template_id, composition_mode, model, res_id, context)"/>
</xpath>
<xpath expr="//a[@class='oe_mail_compose_message_checklist']" position="before">
<xpath expr="//button[@class='oe_mail_compose_message_attachment']" position="before">
<button icon="/email_template/static/src/img/email_template.png"
type="object" name="template_toggle" string=""
help="Use a message template"/>
type="object" name="toggle_template" string=""
help="Use a message template"
attrs="{'invisible':[('content_subtype','!=','html')]}"/>
<button icon="/email_template/static/src/img/email_template_save.png"
type="object" name="save_as_template" string=""
help="Save as a new template"/>
help="Save as a new template"
attrs="{'invisible':[('content_subtype','!=','html')]}"/>
</xpath>
</data>
</field>

View File

@ -7,15 +7,12 @@
<field name="email_from" >${object.user_id.email or object.company_id.email or 'noreply@' + object.company_id.name + '.com'}</field>
<field name="email_to" >${object.email}</field>
<field name="subject">Your registration at ${object.event_id.name}</field>
<field name="body_text">
hello ${object.name},
The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin} to ${object.event_id.date_end}. For any further information please contact our event department.
we thank you for your participation
best regards
</field>
<field name="body_html"><![CDATA[
<p>Hello ${object.name},</p>
<p>The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin} to ${object.event_id.date_end}.
For any further information please contact our event department.</p>
<p>Thank you for your participation!</p>
<p>Best regards</p>]]></field>
</record>
</data>
@ -27,15 +24,12 @@
<field name="email_from" >${object.user_id.email or object.company_id.email or 'noreply@' + object.company_id.name + '.com'}</field>
<field name="email_to" >${object.email}</field>
<field name="subject">Your registration at ${object.event_id.name}</field>
<field name="body_text">
hello ${object.name},
We confirm you that your registration to the event ${object.event_id.name} has been recorded. You will automatically receive an email providing you more practical information (such as the schedule, the plan...) as soon as the event will be confirmed to be held.
we thank you for your participation
best regards
</field>
<field name="body_html"><![CDATA[
<p>Hello ${object.name},</p>
<p>We confirm that your registration to the event ${object.event_id.name} has been recorded.
You will automatically receive an email providing you more practical information (such as the schedule, the agenda...) as soon as the event is confirmed.</p>
<p>Thank you for your participation!</p>
<p>Best regards</p>]]></field>
</record>
<!-- Default Values -->

View File

@ -19,10 +19,8 @@
#
##############################################################################
import time
from osv import fields, osv
from tools.translate import _
import decimal_precision as dp
from openerp import SUPERUSER_ID
class event_type(osv.osv):
@ -49,11 +47,11 @@ class event_event(osv.osv):
_name = 'event.event'
_description = __doc__
_order = 'date_begin'
_inherit = ['ir.needaction_mixin','mail.thread']
_inherit = ['mail.thread','ir.needaction_mixin']
def name_get(self, cr, uid, ids, context=None):
if not ids:
return []
return []
res = []
for record in self.browse(cr, uid, ids, context=context):
date = record.date_begin.split(" ")[0]
@ -99,7 +97,6 @@ class event_event(osv.osv):
return self.write(cr, uid, ids, {'state': 'done'}, context=context)
def check_registration_limits(self, cr, uid, ids, context=None):
register_pool = self.pool.get('event.registration')
for self.event in self.browse(cr, uid, ids, context=context):
total_confirmed = self.event.register_current
if total_confirmed < self.event.register_min or total_confirmed > self.event.register_max and self.event.register_max!=0:
@ -109,7 +106,7 @@ class event_event(osv.osv):
for event in self.browse(cr, uid, ids, context=context):
available_seats = event.register_avail
if available_seats and no_of_registration > available_seats:
raise osv.except_osv(_('Warning!'),_("Only %d Seats are Available!") % (available_seats))
raise osv.except_osv(_('Warning!'),_("Only %d Seats are Available!") % (available_seats))
elif available_seats == 0:
raise osv.except_osv(_('Warning!'),_("No Tickets Available!"))
@ -139,7 +136,6 @@ class event_event(osv.osv):
@param context: A standard dictionary for contextual values
@return: Dictionary of function fields value.
"""
register_pool = self.pool.get('event.registration')
res = {}
for event in self.browse(cr, uid, ids, context=context):
res[event.id] = {}
@ -262,33 +258,52 @@ class event_event(osv.osv):
}
return {'value': dic}
def on_change_address_id(self, cr, uid, ids, address_id, context=None):
values = {
'street' : False,
'city' : False,
'zip' : False,
}
if isinstance(address_id, (long, int)):
address = self.pool.get('res.partner').browse(cr, uid, address_id, context=context)
values.update({
'street' : address.street,
'city' : address.city,
'zip' : address.zip,
})
return {'value' : values}
# ----------------------------------------
# OpenChatter methods and notifications
# ----------------------------------------
def create_send_note(self, cr, uid, ids, context=None):
message = _("Event has been <b>created</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def button_cancel_send_note(self, cr, uid, ids, context=None):
message = _("Event has been <b>cancelled</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def button_draft_send_note(self, cr, uid, ids, context=None):
message = _("Event has been set to <b>draft</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def button_done_send_note(self, cr, uid, ids, context=None):
message = _("Event has been <b>done</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def button_confirm_send_note(self, cr, uid, ids, context=None):
message = _("Event has been <b>confirmed</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
event_event()
@ -334,7 +349,7 @@ class event_registration(osv.osv):
return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
def confirm_registration(self, cr, uid, ids, context=None):
self.message_append(cr, uid, ids,_('State set to open'),body_text= _('Open'))
self.message_post(cr, uid, ids, body=_('State set to open'), context=context)
return self.write(cr, uid, ids, {'state': 'open'}, context=context)
def create(self, cr, uid, vals, context=None):
@ -364,13 +379,13 @@ class event_registration(osv.osv):
if today >= registration.event_id.date_begin:
values = {'state': 'done', 'date_closed': today}
self.write(cr, uid, ids, values)
self.message_append(cr, uid, ids, _('State set to Done'), body_text=_('Done'))
self.message_post(cr, uid, ids, body=_('State set to Done'), context=context)
else:
raise osv.except_osv(_('Error!'),_("You must wait for the starting day of the event to do this action.") )
return True
def button_reg_cancel(self, cr, uid, ids, context=None, *args):
self.message_append(cr, uid, ids,_('State set to Cancel'),body_text= _('Cancel'))
self.message_post(cr, uid, ids, body=_('State set to Cancel'), context=context)
return self.write(cr, uid, ids, {'state': 'cancel'})
def mail_user(self, cr, uid, ids, context=None):
@ -440,12 +455,12 @@ class event_registration(osv.osv):
def create_send_note(self, cr, uid, ids, context=None):
message = _("Registration has been <b>created</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def do_draft_send_note(self, cr, uid, ids, context=None):
message = _("Registration has been set as <b>draft</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
event_registration()

View File

@ -14,11 +14,13 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Events Organisation has been installed</value>
<value>From the top menu Events, you can organize events, manage registrations, automate communication around your event and sell events through your quotations.</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Events Organisation application installed!</field>
<field name="body">From the top Events menu, you can organize events, manage registrations, automate communication around your event and sell events through your quotations.</field>
</record>
</data>
</openerp>

View File

@ -124,7 +124,7 @@
<group>
<label for="address_id" string="Location Address"/>
<div>
<field name="address_id" widget="many2one_address_google_map" widget_option="{'placeholder':'.oe_google_map'}"/>
<field name="address_id" widget="many2one_address_google_map" widget_option="{'placeholder':'.oe_google_map'}" on_change="on_change_address_id(address_id)" />
<field name="street" placeholder="Street..."/>
<div>
<field name="zip" class="oe_inline" placeholder="Zip"/>
@ -143,7 +143,7 @@
</group>
</group>
</div>
<!-- <div class="oe_right" style="height: 200px"></div> -->
<div class="oe_google_map" style="height: 200px"></div>
<notebook>
<page string="Event Description">
<field name="note" colspan="4" nolabel="1"/>
@ -208,7 +208,7 @@
<field name="name">event.event.tree</field>
<field name="model">event.event</field>
<field name="arch" type="xml">
<tree string="Events" fonts="bold:needaction_pending==True" colors="red:(register_min and register_min&gt;register_current) or (register_max and register_max&lt;register_current);grey:state=='cancel'">
<tree string="Events" fonts="bold:message_unread==True" colors="red:(register_min and register_min&gt;register_current) or (register_max and register_max&lt;register_current);grey:state=='cancel'">
<field name="name" string="Name"/>
<field name="type"/>
<field name="date_begin"/>
@ -219,7 +219,7 @@
<field name="main_speaker_id" groups="base.extended"/>
<field name="user_id"/>
<field name="state"/>
<field name="needaction_pending" invisible="1"/>
<field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
@ -326,7 +326,7 @@
<field name="arch" type="xml">
<search string="Events">
<field name="name" string="Events"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter icon="terp-check" string="Unconfirmed" name="draft" domain="[('state','=','draft')]" help="Events in New state"/>
<filter icon="terp-camera_test" string="Confirmed" domain="[('state','=','confirm')]" help="Confirmed events"/>
@ -421,7 +421,7 @@
<field name="name">event.registration.tree</field>
<field name="model">event.registration</field>
<field name="arch" type="xml">
<tree string="Registration" fonts="bold:needaction_pending==True">
<tree string="Registration" fonts="bold:message_unread==True">
<field name="create_date"/>
<field name="partner_id"/>
<field name="name"/>
@ -431,7 +431,7 @@
<field name="user_id"/>
<field name="origin"/>
<field name="state"/>
<field name="needaction_pending" invisible="1"/>
<field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
@ -516,7 +516,7 @@
<field name="arch" type="xml">
<search string="Event Registration">
<field name="name" string="Participant" filter_domain="['|','|','|',('name','ilike',self),('partner_id','ilike',self),('email','ilike',self),('origin','ilike',self)]"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter icon="terp-check" string="New" name="draft" domain="[('state','=','draft')]" help="Registrations in unconfirmed state"/>
<filter icon="terp-camera_test" string="Confirmed" domain="[('state','=','open')]" help="Confirmed registrations"/>

View File

@ -88,5 +88,5 @@ class sale_order_line(osv.osv):
}
registration_id = registration_obj.create(cr, uid, dic, context=context)
message = _("The registration %s has been created from the Sale Order %s.") % (registration_id, order_line.order_id.name)
registration_obj.message_append_note(cr, uid, [registration_id], body=message, context=context)
registration_obj.message_post(cr, uid, [registration_id], body=message, context=context)
return super(sale_order_line, self).button_confirm(cr, uid, ids, context=context)

View File

@ -77,7 +77,7 @@ class fetchmail_server(osv.osv):
"emails to the existing conversations (documents)."),
'priority': fields.integer('Server Priority', readonly=True, states={'draft':[('readonly', False)]}, help="Defines the order of processing, "
"lower values mean higher priority"),
'message_ids': fields.one2many('mail.message', 'fetchmail_server_id', 'Messages', readonly=True),
'message_ids': fields.one2many('mail.mail', 'fetchmail_server_id', 'Messages', readonly=True),
'configuration' : fields.text('Configuration'),
'script' : fields.char('Script', readonly=True, size=64),
}
@ -232,8 +232,8 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS
server.write({'date': time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)})
return True
class mail_message(osv.osv):
_inherit = "mail.message"
class mail_mail(osv.osv):
_inherit = "mail.mail"
_columns = {
'fetchmail_server_id': fields.many2one('fetchmail.server', "Inbound Mail Server",
readonly=True,
@ -247,7 +247,7 @@ class mail_message(osv.osv):
fetchmail_server_id = context.get('fetchmail_server_id')
if fetchmail_server_id:
values['fetchmail_server_id'] = fetchmail_server_id
res = super(mail_message,self).create(cr, uid, values, context=context)
res = super(mail_mail,self).create(cr, uid, values, context=context)
return res
def write(self, cr, uid, ids, values, context=None):
@ -256,7 +256,7 @@ class mail_message(osv.osv):
fetchmail_server_id = context.get('fetchmail_server_id')
if fetchmail_server_id:
values['fetchmail_server_id'] = server_id
res = super(mail_message,self).write(cr, uid, ids, values, context=context)
res = super(mail_mail,self).write(cr, uid, ids, values, context=context)
return res

View File

@ -104,27 +104,16 @@
/>
<record model="ir.ui.view" id="email_message_tree_view">
<field name="name">mail.message.list.fetchmail</field>
<field name="model">mail.message</field>
<field name="inherit_id" ref="mail.view_email_message_tree"/>
<field name="name">mail.mail.form.fetchmail</field>
<field name="model">mail.mail</field>
<field name="inherit_id" ref="mail.view_mail_form"/>
<field name="arch" type="xml">
<field name="user_id" position="after">
<field name="references" position="after">
<field name="fetchmail_server_id"/>
</field>
</field>
</record>
<record model="ir.ui.view" id="email_message_search_view">
<field name="name">mail.message.inherit.search</field>
<field name="model">mail.message</field>
<field name="inherit_id" ref="mail.view_email_message_search"/>
<field name="arch" type="xml">
<xpath expr="/search/group/filter[@string='Thread']" position="before">
<filter string="Mail Server" icon="terp-accessories-archiver" domain="[]" context="{'group_by':'fetchmail_server_id'}"/>
</xpath>
</field>
</record>
<act_window
context="{'search_default_server_id': active_id, 'default_fetchmail_server_id': active_id}"
id="act_server_history" name="Messages" domain="[('email_from', '!=', False), ('fetchmail_server_id', '=', active_id)]"

View File

@ -212,7 +212,7 @@ class hr_employee(osv.osv):
try:
(model, mail_group_id) = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'group_all_employees')
employee = self.browse(cr, uid, employee_id, context=context)
self.pool.get('mail.group').message_append_note(cr, uid, [mail_group_id], body='Welcome to %s! Please help him make its first steps in OpenERP!' % (employee.name), context=context)
self.pool.get('mail.group').message_post(cr, uid, [mail_group_id], body='Welcome to %s! Please help them take the first steps with OpenERP!' % (employee.name), context=context)
except:
pass # group deleted: do not push a message
return employee_id

View File

@ -2,14 +2,16 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Employee Directory has been installed</value>
<value>Manage your human resources in OpenERP: employees and hierarchy, HR departments and jobs.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Employee Directory application installed!</field>
<field name="body">Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.
More HR features are available from the following modules: Recruitment Process (manage job positions and recruitment), Timesheets Validation (record timesheets and attendance), Leaves Management (keep track of employee leaves), Expenses Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager.)</value>
</function>
More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).</field>
</record>
<record id="employee" model="hr.employee">
<field name="name">Administrator</field>

View File

@ -128,7 +128,7 @@
<field name="last_login"/>
<templates>
<t t-name="kanban-box">
<div class="oe_employee_vignette">
<div class="oe_employee_vignette oe_semantic_html_override">
<div class="oe_employee_image">
<a type="open"><img t-att-src="kanban_image('hr.employee', 'image_medium', record.id.value)" class="oe_employee_picture"/></a>
</div>

View File

@ -38,11 +38,10 @@ created and it can be defined which level of employee hierarchy fills what and
final review and evaluation is done by the manager. Every evaluation filled by
the employees can be viewed in the form of pdf file.
""",
'demo': ['hr_evaluation_demo.xml'],
'data': [
"demo": ["hr_evaluation_demo.xml"],
"data": [
'security/ir.model.access.csv',
'security/hr_evaluation_security.xml',
# 'wizard/hr_evaluation_mail_view.xml',
'hr_evaluation_view.xml',
'report/hr_evaluation_report_view.xml',
'board_hr_evaluation_view.xml',

View File

@ -228,9 +228,13 @@ class hr_evaluation(osv.osv):
body = phase.mail_body % {'employee_name': child.name, 'user_signature': child.user_id.signature,
'eval_name': phase.survey_id.title, 'date': time.strftime('%Y-%m-%d'), 'time': time }
sub = phase.email_subject
dest = [child.work_email]
if dest:
mail_message.schedule_with_attach(cr, uid, evaluation.employee_id.work_email, dest, sub, body, context=context)
if child.work_email:
vals = {'state': 'outgoing',
'subject': sub,
'body_html': '<pre>%s</pre>' % body,
'email_to': child.work_email,
'email_from': evaluation.employee_id.work_email}
self.pool.get('mail.mail').create(cr, uid, vals, context=context)
self.write(cr, uid, ids, {'state':'wait'}, context=context)
return True

View File

@ -14,12 +14,14 @@
<field name="sequence">100</field>
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Employee Appraisals has been installed</value>
<value>Create evaluations for your subordinates or manager. You can define a plan with several surveys, where you organize evaluation surveys related to the hierarchy levels. Evaluations filled by employees can exported as pdf files.</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Employee Appraisals application installed!</field>
<field name="body">Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels.
Evaluations filled by employees may be exported as pdf files.</field>
</record>
<record id="survey_2" model="survey">
<field name="title">Self Appraisal</field>

View File

@ -267,16 +267,27 @@
<field name="arch" type="xml">
<form string="Interview Appraisal" version="7.0">
<header>
<button string="Cancel" name="survey_req_cancel" states="draft,waiting_answer" type="object" icon="gtk-cancel"/>
<button name="action_print_survey" string="Print Survey" type="object" states="draft" icon="gtk-print" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0}" attrs="{'readonly':[('survey_id','=',False)]}" class="oe_highlight"/>
<button string="Send Request" name="survey_req_waiting_answer" states="draft" type="object" icon="gtk-yes" class="oe_highlight"/>
<button name="%(survey.action_view_survey_question_message)d" string="Answer Survey" type="action" states="waiting_answer" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0, 'active' : response,'request' : True, 'object' : 'hr.evaluation.interview', 'cur_id' : active_id}" attrs="{'readonly':[('survey_id','=',False)]}"/>
<button string="Done" name="survey_req_done" states="waiting_answer" type="object" icon="gtk-jump-to"/>
<button string="Cancel" name="survey_req_cancel" type="object"
states="draft,waiting_answer"/>
<button string="Print Survey" name="action_print_survey" type="object"
states="draft" context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0}"
attrs="{'readonly':[('survey_id','=',False)]}" class="oe_highlight"/>
<button string="Send Request" name="survey_req_waiting_answer" type="object"
states="draft" class="oe_highlight"/>
<button string="Answer Survey" name="%(survey.action_view_survey_question_message)d" type="action"
states="waiting_answer"
context="{'survey_id': survey_id, 'response_id': [response], 'response_no':0, 'active' : response,'request' : True, 'object' : 'hr.evaluation.interview', 'cur_id' : active_id}"
attrs="{'readonly':[('survey_id','=',False)]}"/>
<button string="Done" name="survey_req_done" type="object"
states="waiting_answer"/>
<field name="state" widget="statusbar" statusbar_visible="waiting_answer,done"/>
</header>
<sheet>
<div class="oe_right oe_button_box" name="button_box">
<button string="Send Reminder Email" name="%(mail.action_email_compose_message_wizard)d" icon="terp-mail-message-new" type="action" states="waiting_answer"/>
<button string="Send Reminder Email" name="%(mail.action_email_compose_message_wizard)d" type="action"
states="waiting_answer"
context="{'default_body_text': 'Hello,\n\nKindly post your response for the survey interview.\n\nThanks',
'default_subject': 'Reminder to fill up Survey' }"/>
</div>
<group>
<group col="3" colspan="1">
@ -389,21 +400,23 @@
<!-- Email Compose message Action-->
<act_window
id="evaluation_reminders" name="Appraisal Reminders"
res_model="mail.compose.message"
src_model="hr.evaluation.interview"
view_type="form" view_mode="form"
target="new" multi="True"
key2="client_action_multi"
context="{'mail.compose.message.mode':'mass_mail'}"/>
id="evaluation_reminders" name="Appraisal Reminders"
res_model="mail.compose.message"
src_model="hr.evaluation.interview"
view_type="form" view_mode="form"
target="new" multi="True"
key2="client_action_multi"
context="{'default_composition_mode': 'mass_mail',
'default_body_text': 'Hello,\n\nKindly post your response for the survey interview.\n\nThanks',
'default_subject': 'Reminder to fill up Survey'}"/>
<!-- Appraisal Interviews Button on Employee Form -->
<act_window
context="{'search_default_user_to_review_id': [active_id], 'default_user_to_review_id': active_id}"
id="act_hr_employee_2_hr__evaluation_interview"
name="Appraisal Interviews"
res_model="hr.evaluation.interview"
src_model="hr.employee"/>
context="{'search_default_user_to_review_id': [active_id], 'default_user_to_review_id': active_id}"
id="act_hr_employee_2_hr__evaluation_interview"
name="Appraisal Interviews"
res_model="hr.evaluation.interview"
src_model="hr.employee"/>
</data>
</openerp>

View File

@ -1,25 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
#import hr_evaluation_mail
import mail_compose_message
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,42 +0,0 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import fields, osv
import tools
class hr_evaluation_reminder(osv.osv_memory):
_name = "hr.evaluation.reminder"
_description = "Sends Reminders to employees to fill the evaluations"
_columns = {
'evaluation_id': fields.many2one('hr.evaluation.interview', 'Interview', required=True)
}
def send_mail(self, cr, uid, ids, context=None):
mail_message = self.pool.get('mail.message')
hr_evaluation_interview_obj = self.pool.get('hr.evaluation.interview')
evaluation_data = self.read(cr, uid, ids, context=context)[0]
current_interview = hr_evaluation_interview_obj.browse(cr, uid, evaluation_data.get('evaluation_id'))
if current_interview.state == "waiting_answer" and current_interview.user_to_review_id.work_email :
msg = " Hello %s, \n\n Kindly post your response for '%s' survey interview. \n\n Thanks," %(current_interview.user_to_review_id.name, current_interview.survey_id.title)
mail_message.schedule_with_attach(cr, uid, tools.config['email_from'], [current_interview.user_to_review_id.work_email],\
'Reminder to fill up Survey', msg, context=context)
return {'type': 'ir.actions.act_window_close'}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_hr_evaluation_send_mail" model="ir.ui.view">
<field name="name">hr.evaluation.send.mail</field>
<field name="model">hr.evaluation.reminder</field>
<field name="arch" type="xml">
<form string="Evaluation Reminders" version="7.0">
<group string="Send Evaluation Reminder">
<field name="evaluation_id"/>
</group>
<footer>
<button name="send_mail" string="Send Mail" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_hr_evaluation_send_mail" model="ir.actions.act_window">
<field name="name">Evaluation Send Mail</field>
<field name="res_model">hr.evaluation.reminder</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_hr_evaluation_send_mail"/>
<field name="context">{'record_id':active_id}</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -1,54 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
##############################################################################
from osv import osv
from osv import fields
import tools
from tools.translate import _
class mail_compose_message(osv.osv_memory):
_inherit = 'mail.compose.message'
def get_value(self, cr, uid, model, resource_id, context=None):
'''
To get values of the resource_id for the model
@param model: Object
@param resource_id: id of a record for which values to be read
@return: Returns a dictionary
'''
if context is None:
context = {}
result = super(mail_compose_message, self).get_value(cr, uid, model, resource_id, context=context)
if model == 'hr.evaluation.interview' and resource_id:
model_pool = self.pool.get(model)
record_data = model_pool.browse(cr, uid, resource_id, context)
if record_data.state == "waiting_answer":
msg = _("Hello %s, \n\n Kindly post your response for '%s' survey interview. \n\n Thanks,") %(record_data.user_to_review_id.name, record_data.survey_id.title)
result.update({
'email_to': record_data.user_to_review_id.work_email or False,
'subject': _("Reminder to fill up Survey"),
'body_text': msg,
})
return result
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -21,14 +21,14 @@
{
'name': 'Expenses Management',
'name': 'Expense Management',
'version': '1.0',
'category': 'Human Resources',
'sequence': 30,
'summary': 'Expenses Validation, Invoicing',
'description': """
This module aims to manage employee's expenses.
===============================================
This module aims to manage employee expenses.
=============================================
The whole workflow is implemented:
----------------------------------

View File

@ -2,20 +2,20 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Expenses Management has been installed</value>
<value>Manage your employee's expenses, with validations by employee manager and accountant, creation and payment of invoices.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Expense Management application installed!</field>
<field name="body">Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.
This module also uses the analytic accounting and is compatible with the invoice on timesheet module so that you will be able to automatically re-invoice your customer's expenses if your work by project.</value>
</function>
This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.</field>
</record>
<!-- Resource: product.uom.categ -->
<record id="cat_expense" model="product.category">
<field name="parent_id" ref="product.product_category_all"/>
<field name="name">Expenses</field>
</record>
</data>
</openerp>

View File

@ -21,7 +21,7 @@
{
'name': 'Leaves Management',
'name': 'Leave Management',
'version': '1.5',
'author': 'OpenERP SA',
'category': 'Human Resources',
@ -29,8 +29,8 @@
'summary': 'Holidays, Allocation and Leave Requests',
'website': 'http://www.openerp.com',
'description': """
This module allows you to manage leaves and leave's requests.
=============================================================
This module allows you to manage leaves and leave requests.
===========================================================
Implements a dashboard for human resource management that includes:
-------------------------------------------------------------------

View File

@ -95,7 +95,7 @@ class hr_holidays(osv.osv):
_name = "hr.holidays"
_description = "Leave"
_order = "type desc, date_from asc"
_inherit = ['ir.needaction_mixin', 'mail.thread']
_inherit = [ 'mail.thread','ir.needaction_mixin']
def _employee_get(self, cr, uid, context=None):
ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context)
@ -344,62 +344,53 @@ class hr_holidays(osv.osv):
if leaves_rest < record.number_of_days_temp:
raise osv.except_osv(_('Warning!'), _('There are not enough %s allocated for employee %s; please create an allocation request for this leave type.') % (record.holiday_status_id.name, record.employee_id.name))
return True
# -----------------------------
# OpenChatter and notifications
# -----------------------------
def get_needaction_user_ids(self, cr, uid, ids, context=None):
result = super(hr_holidays, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context):
if obj.state == 'confirm' and obj.holiday_type == 'employee' and obj.employee_id.parent_id:
result[obj.id] = [obj.employee_id.parent_id.user_id.id]
elif obj.state == 'validate1':
# get group_hr_manager: everyone will be warned of second validation
res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_hr_manager') or False
obj_id = res and res[1] or False
if obj_id:
hr_manager_group = self.pool.get('res.groups').read(cr, uid, [obj_id], ['users'], context=context)[0]
result[obj.id] = hr_manager_group['users']
return result
def message_get_monitored_follower_fields(self, cr, uid, ids, context=None):
""" Add 'user_id' and 'manager' to the monitored fields """
res = super(hr_holidays, self).message_get_monitored_follower_fields(cr, uid, ids, context=context)
return res + ['user_id']
def needaction_domain_get(self, cr, uid, ids, context=None):
# to be tested, otherwise convert into employee_id in ...
emp_obj = self.pool.get('hr.employee')
empids = emp_obj.search(cr, uid, [('parent_id.user_id','=',uid)], context=context)
dom = [
'&', ('state','=','confirm'),('employee_id', 'in', empids)
]
# if this user is a hr.manager, he should do second validations
if self.pool.get('res.users').has_group(cr, uid, 'base.group_hr_manager'):
dom = ['|'] + dom + [ ('state','=','validate1') ]
return dom
def create_notificate(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, ids, _('System notification'),
_("The request has been <b>created</b> and is waiting confirmation."), type='notification', context=context)
self.message_post(cr, uid, ids,
_("The request has been <b>created</b> and is waiting confirmation."), context=context)
return True
def holidays_confirm_notificate(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids):
self.message_append_note(cr, uid, [obj.id], _('System notification'),
_("The request has been <b>submitted</b> and is waiting for validation by the manager."), type='notification')
self.message_post(cr, uid, [obj.id],
_("The request has been <b>submitted</b> and is waiting for validation by the manager."), context=context)
def holidays_first_validate_notificate(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, [obj.id], _('System notification'),
_("The request has been <b>approved</b>. A second validation is necessary and is now pending."), type='notification', context=context)
self.message_post(cr, uid, [obj.id],
_("The request has been <b>approved</b>. A second validation is necessary and is now pending."), context=context)
def holidays_validate_notificate(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids):
if obj.double_validation:
self.message_append_note(cr, uid, [obj.id], _('System notification'),
_("The request has been <b>double validated</b>. The validation process is now over."), type='notification', context=context)
self.message_post(cr, uid, [obj.id],
_("The request has been <b>double validated</b>. The validation process is now over."), context=context)
else:
self.message_append_note(cr, uid, [obj.id], _('System notification'),
_("The request has been <b>approved</b>. The validation process is now over."), type='notification', context=context)
self.message_post(cr, uid, [obj.id],
_("The request has been <b>approved</b>. The validation process is now over."), context=context)
def holidays_refuse_notificate(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids):
self.message_append_note(cr, uid, [obj.id], _('System notification'),
_("The request has been <b>refused</b>. The validation process is now over."), type='notification', context=context)
hr_holidays()
self.message_post(cr, uid, [obj.id],
_("The request has been <b>refused</b>. The validation process is now over."), context=context)
class resource_calendar_leaves(osv.osv):
_inherit = "resource.calendar.leaves"

View File

@ -13,12 +13,15 @@
<field name="sequence">100</field>
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Leaves Management has been installed</value>
<value>Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR people. Once validated, they are visible in the employee's calendar. HR people can define leave types and allocate off-days for employees.</value>
</function>
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Leave Management application installed!</field>
<field name="body">Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.
Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.</field>
</record>
<!-- Casual leave -->
<record model="hr.holidays.status" id="holiday_status_cl">

View File

@ -44,7 +44,6 @@
<field name="arch" type="xml">
<search string="Search Leave">
<field name="date_from"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<separator/>
<filter icon="terp-check" domain="[('state','=','draft')]" string="To Confirm"/>
<filter icon="terp-camera_test" domain="[('state','=','confirm')]" string="To Approve" name="approve"/>
@ -170,8 +169,7 @@
<field name="name">hr.holidays.allocation.tree</field>
<field name="model">hr.holidays</field>
<field name="arch" type="xml">
<tree fonts="bold:needaction_pending==True" colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Allocation Requests">
<field name="needaction_pending" invisible="1"/>
<tree colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Allocation Requests">
<field name="employee_id"/>
<field name="holiday_type"/>
<field name="category_id"/>
@ -218,8 +216,7 @@
<field name="model">hr.holidays</field>
<field name="priority">20</field>
<field name="arch" type="xml">
<tree fonts="bold:needaction_pending==True" colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leaves Summary">
<field name="needaction_pending" invisible="1"/>
<tree colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leaves Summary">
<field name="employee_id"/>
<field name="category_id" invisible="1"/>
<field name="department_id" invisible="1"/>
@ -241,8 +238,7 @@
<field name="name">hr.holidays.tree</field>
<field name="model">hr.holidays</field>
<field name="arch" type="xml">
<tree fonts="bold:needaction_pending==True" colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leave Requests">
<field name="needaction_pending" invisible="1"/>
<tree colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leave Requests">
<field name="employee_id"/>
<field name="holiday_type" string="Mode" groups="base.group_hr_user"/>
<field name="name"/>

View File

@ -90,8 +90,7 @@ class hr_applicant(base_stage, osv.Model):
_name = "hr.applicant"
_description = "Applicant"
_order = "id desc"
_inherit = ['ir.needaction_mixin', 'mail.thread']
_mail_compose_message = True
_inherit = ['mail.thread', 'ir.needaction_mixin']
def _get_default_department_id(self, cr, uid, context=None):
""" Gives default department by checking if present in the context """
@ -161,13 +160,11 @@ class hr_applicant(base_stage, osv.Model):
date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
date_open = datetime.strptime(issue.date_open, "%Y-%m-%d %H:%M:%S")
ans = date_open - date_create
date_until = issue.date_open
elif field in ['day_close']:
if issue.date_closed:
date_create = datetime.strptime(issue.create_date, "%Y-%m-%d %H:%M:%S")
date_close = datetime.strptime(issue.date_closed, "%Y-%m-%d %H:%M:%S")
date_until = issue.date_closed
ans = date_close - date_create
if ans:
duration = float(ans.days)
@ -328,14 +325,13 @@ class hr_applicant(base_stage, osv.Model):
if custom_values is None: custom_values = {}
custom_values.update({
'name': msg.get('subject') or _("No Subject"),
'description': msg.get('body_text'),
'description': msg.get('body'),
'email_from': msg.get('from'),
'email_cc': msg.get('cc'),
'user_id': False,
})
if msg.get('priority'):
custom_values['priority'] = msg.get('priority')
custom_values.update(self.message_partner_by_email(cr, uid, msg.get('from', False), context=context))
return super(hr_applicant,self).message_new(cr, uid, msg, custom_values=custom_values, context=context)
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
@ -360,7 +356,7 @@ class hr_applicant(base_stage, osv.Model):
'revenue': 'planned_revenue',
'probability': 'probability',
}
for line in msg.get('body_text', '').split('\n'):
for line in msg.get('body', '').split('\n'):
line = line.strip()
res = tools.misc.command_re.match(line)
if res and maps.get(res.group(1).lower(), False):
@ -457,23 +453,18 @@ class hr_applicant(base_stage, osv.Model):
# OpenChatter methods and notifications
# -------------------------------------------------------
def message_get_monitored_follower_fields(self, cr, uid, ids, context=None):
""" Add 'user_id' to the monitored fields """
res = super(hr_applicant, self).message_get_monitored_follower_fields(cr, uid, ids, context=context)
return res + ['user_id']
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
""" Override of the (void) default notification method. """
if not stage_id: return True
stage_name = self.pool.get('hr.recruitment.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
return self.message_post(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
return 'Applicant'
def case_open_send_note(self, cr, uid, ids, context=None):
message = _("Applicant has been set <b>in progress</b>.")
return self.message_append_note(cr, uid, ids, body=message, context=context)
return self.message_post(cr, uid, ids, body=message, context=context)
def case_close_send_note(self, cr, uid, ids, context=None):
if context is None:
@ -481,23 +472,23 @@ class hr_applicant(base_stage, osv.Model):
for applicant in self.browse(cr, uid, ids, context=context):
if applicant.emp_id:
message = _("Applicant has been <b>hired</b> and created as an employee.")
self.message_append_note(cr, uid, [applicant.id], body=message, context=context)
self.message_post(cr, uid, [applicant.id], body=message, context=context)
else:
message = _("Applicant has been <b>hired</b>.")
self.message_append_note(cr, uid, [applicant.id], body=message, context=context)
self.message_post(cr, uid, [applicant.id], body=message, context=context)
return True
def case_cancel_send_note(self, cr, uid, ids, context=None):
msg = 'Applicant <b>refused</b>.'
return self.message_append_note(cr, uid, ids, body=msg, context=context)
return self.message_post(cr, uid, ids, body=msg, context=context)
def case_reset_send_note(self, cr, uid, ids, context=None):
message =_("Applicant has been set as <b>new</b>.")
return self.message_append_note(cr, uid, ids, body=message, context=context)
return self.message_post(cr, uid, ids, body=message, context=context)
def create_send_note(self, cr, uid, ids, context=None):
message = _("Applicant has been <b>created</b>.")
return self.message_append_note(cr, uid, ids, body=message, context=context)
return self.message_post(cr, uid, ids, body=message, context=context)
class hr_job(osv.osv):

View File

@ -2,14 +2,15 @@
<openerp>
<data noupdate="1">
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Recruitment Process has been installed</value>
<value>Manage job positions and the recruitment process in your company. This module is integrated with the module Survey to help you to define interviews for different jobs.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Recruitment Process application installed!</field>
<field name="body">Manage job positions and your company's recruitment process. This application is integrated with the Survey application to help you define interviews for different jobs.
You can automatically create application records from an email gateway, that you can configure in the Human Resources Settings.</value>
</function>
You can automatically receive job application though an email gateway, see the Human Resources settings.</field>
</record>
<!-- Meeting Types (for interview meetings) -->
<record model="crm.meeting.type" id="categ_meet_interview">

View File

@ -76,8 +76,8 @@
<field name="name">Applicants</field>
<field name="model">hr.applicant</field>
<field name="arch" type="xml">
<tree string="Applicants" fonts="bold:needaction_pending==True" colors="grey:state in ('cancel','done');blue:state=='pending'">
<field name="needaction_pending" invisible="1"/>
<tree string="Applicants" fonts="bold:message_unread==True" colors="grey:state in ('cancel','done');blue:state=='pending'">
<field name="message_unread" invisible="1"/>
<field name="create_date" groups="base.group_no_one"/>
<field name="name" string="Subject"/>
<field name="partner_name"/>
@ -208,7 +208,7 @@
<field name="arch" type="xml">
<search string="Search Jobs">
<field name="partner_name" filter_domain="['|','|',('name','ilike',self),('partner_name','ilike',self),('email_from','ilike',self)]" string="Subject / Applicant"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="needaction_pending" domain="[('needaction_pending','=',True)]"/>
<filter icon="terp-mail-message-new" string="Inbox" help="Unread messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter icon="terp-document-new" string="New" domain="[('state','=','draft')]" help="All Initial Jobs"/>
<filter icon="terp-camera_test" string="In Progress" domain="[('state','=','open')]" help="Open Jobs"/>
@ -271,19 +271,19 @@
<field name="categ_ids"/>
<templates>
<t t-name="kanban-tooltip">
<ul class="oe_kanban_tooltip">
<ul class="oe_kanban_tooltip oe_semantic_html_override">
<li t-if="record.type_id.raw_value"><b>Degree:</b> <field name="type_id"/></li>
<li t-if="record.partner_id.raw_value"><b>Contact:</b> <field name="partner_id"/></li>
<li t-if="record.department_id.raw_value"><b>Departement:</b> <field name="department_id"/></li>
</ul>
</t>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click oe_semantic_html_override">
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">i</span>
<ul class="oe_dropdown_menu">
<li><a type="edit">Edit...</a></li>
<li><a type="delete">Delete</a></li>
<t t-if="widget.view.is_action_enabled('edit')"><li><a type="edit">Edit...</a></li></t>
<t t-if="widget.view.is_action_enabled('delete')"><li><a type="delete">Delete</a></li></t>
<li><a name="action_makeMeeting" type="object">Schedule Interview</a></li>
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
</ul>

View File

@ -95,25 +95,25 @@ class account_analytic_account(osv.osv):
def set_close(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state':'close'}, context=context)
message = _("Contract has been <b>closed</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def set_cancel(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state':'cancelled'}, context=context)
message = _("Contract has been <b>cancelled</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def set_open(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state':'open'}, context=context)
message = _("Contract has been <b>opened</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
def set_pending(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state':'pending'}, context=context)
message = _("Contract has been set as <b>pending</b>.")
self.message_append_note(cr, uid, ids, body=message, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
return True
account_analytic_account()

View File

@ -27,8 +27,8 @@
'sequence': 16,
'summary': 'Timesheets, Attendances, Activities',
'description': """
This module helps you to easily encode and validate timesheet and attendances within the same view.
===================================================================================================
This module helps you to easily record and validate timesheets and attendances within the same view.
====================================================================================================
* It will maintain attendances and track (sign in/sign out) events.
* Track the timesheet lines.

View File

@ -1,24 +1,23 @@
<?xml version="1.0" ?>
<openerp>
<data noupdate="1">
<!-- Notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Module Timesheets Validation has been installed</value>
<value>From the top menu "Human Resources", encode and validate timesheets and attendances.</value>
</function>
<!-- notify all employees of module installation -->
<record model="mail.message" id="hr_timesheet_module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Timesheet Validation application installed!</field>
<field name="body">From the top menu "Human Resources", enter and validate timesheets and attendances.</field>
</record>
<record id="ir_actions_server_timsheet_sheet" model="ir.actions.server">
<field eval="5" name="sequence"/>
<field eval="&quot;&quot;&quot;code&quot;&quot;&quot;" name="state"/>
<field eval="&quot;&quot;&quot;ir.actions.server&quot;&quot;&quot;" name="type"/>
<field name="sequence" eval="5"/>
<field name="state">code</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="model_hr_timesheet_current_open"/>
<field eval="[(6,0,[])]" name="child_ids"/>
<field eval="&quot;&quot;&quot;action = pool.get('hr.timesheet.current.open').open_timesheet(cr, uid, None, context)&quot;&quot;&quot;" name="code"/>
<field eval="&quot;&quot;&quot;True&quot;&quot;&quot;" name="condition"/>
<field eval="&quot;&quot;&quot;My Timesheet&quot;&quot;&quot;" name="name"/>
<field name="code">action = pool.get('hr.timesheet.current.open').open_timesheet(cr, uid, None, context)</field>
<field name="condition">True</field>
<field name="name">My Timesheet</field>
</record>
<menuitem name="My Current Timesheet" id="menu_act_hr_timesheet_sheet_form_my_current" parent="hr_attendance.menu_hr_time_tracking" action="ir_actions_server_timsheet_sheet" sequence="1"/>

View File

@ -67,21 +67,21 @@ class idea_idea(osv.osv):
def idea_cancel(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, { 'state': 'cancel' })
self.message_append_note(cr, uid, ids, body=_('Idea canceled.'), context=context)
self.message_post(cr, uid, ids, body=_('Idea canceled.'), context=context)
return True
def idea_open(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, { 'state': 'open'})
self.message_append_note(cr, uid, ids, body=_('Idea accepted.'), context=context)
self.message_post(cr, uid, ids, body=_('Idea accepted.'), context=context)
return True
def idea_close(self, cr, uid, ids, context={}):
self.message_append_note(cr, uid, ids, body=_('Idea done.'), context=context)
self.message_post(cr, uid, ids, body=_('Idea done.'), context=context)
self.write(cr, uid, ids, { 'state': 'close' })
return True
def idea_draft(self, cr, uid, ids, context={}):
self.message_append_note(cr, uid, ids, body=_('Idea reset to draft.'), context=context)
self.message_post(cr, uid, ids, body=_('Idea reset to draft.'), context=context)
self.write(cr, uid, ids, { 'state': 'draft' })
return True
idea_idea()

View File

@ -425,7 +425,7 @@ class import_framework(Thread):
email_id = email_obj.create(self.cr, self.uid, {
'email_from' : 'import@module.openerp',
'email_to' : self.email,
'body_text' : self.get_email_body(result, error),
'body' : self.get_email_body(result, error),
'subject' : self.get_email_subject(result, error),
'auto_delete' : True})
email_obj.send(self.cr, self.uid, [email_id])

View File

@ -226,7 +226,7 @@ class sugar_import(import_framework):
'model': 'model',
'partner_id/.id': 'partner_id/.id',
'user_id/id': ref(self.TABLE_USER, 'assigned_user_id'),
'body_text': 'description',
'body': 'description',
'body_html' : 'description_html',
}

View File

@ -20,12 +20,12 @@
##############################################################################
import mail_alias
import mail_message
import mail_followers
import mail_message
import mail_mail
import mail_thread
import mail_group
import mail_vote
import ir_needaction
import res_partner
import res_users
import report

View File

@ -64,6 +64,7 @@ The main features of the module are:
'wizard/mail_compose_message_view.xml',
'res_config_view.xml',
'mail_message_view.xml',
'mail_mail_view.xml',
'mail_followers_view.xml',
'mail_thread_view.xml',
'mail_group_view.xml',

View File

@ -3,49 +3,43 @@
<data noupdate="1">
<record id="message_blogpost0" model="mail.message">
<field name="subject">Internal company announce</field>
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="content_subtype">html</field>
<field name="body_html"><![CDATA[Your monthly meal vouchers arrived. You can get them at Christine's office.
This month you also have 250 EUR of eco-checks for all employees that worked with us since 1 year minimum.]]></field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="body">Your monthly meal vouchers arrived. You can get them at Christine's office.
This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</field>
<field name="type">comment</field>
<field name="user_id" ref="base.user_root"/>
</record>
<record id="message_blogpost0_comment0" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="content_subtype">html</field>
<field name="body_html"><![CDATA[Great.]]></field>
<field name="body"><![CDATA[Great.]]></field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="user_id" ref="base.user_root"/>
</record>
<record id="message_blogpost0_comment1" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="content_subtype">html</field>
<field name="body_html"><![CDATA[Yes, that's a good news.]]></field>
<field name="body">Thanks, but where is Christine's office, if I may ask? (I'm new here)</field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="user_id" ref="base.user_demo"/>
</record>
<record id="message_blogpost0_comment2" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="content_subtype">html</field>
<field name="body_html"><![CDATA[Sure: Curabitur tempor bibendum diam, et euismod ante rutrum vel.
In quis purus neque. Integer sodales dolor eu elit fringilla blandit. Maecenas lacus nisi, facilisis sit amet viverra eu, tristique vel augue.
Donec viverra congue dui eu blandit. In lacinia molestie nulla, ut sagittis risus feugiat eu.
Check the file in attachment for more information ! (third comment)]]></field>
<field name="body">Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!</field>
<field name="parent_id" ref="message_blogpost0"/>
<field name="type">comment</field>
<field name="user_id" ref="base.user_root"/>
</record>
<record id="message_blogpost0_comment1_2" model="mail.message">
<field name="model">mail.group</field>
<field name="res_id" ref="group_all_employees"/>
<field name="body">Building B3, second floor on the right :-)</field>
<field name="parent_id" ref="message_blogpost0_comment1"/>
<field name="type">comment</field>
</record>
<record model="ir.config_parameter" id="user_mail_alias">

View File

@ -13,16 +13,16 @@
</record>
<!-- notify all employees of module installation -->
<function model="mail.group" name="message_append_note">
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
<value eval="[ref('mail.group_all_employees')]"/>
<value>Welcome to OpenERP!</value>
<value>Your homepage is a summary of messages you received and key information about documents you follow.
<record model="mail.message" id="module_install_notification">
<field name="model">mail.group</field>
<field name="res_id" ref="mail.group_all_employees"/>
<field name="type">notification</field>
<field name="subject">Welcome to OpenERP!</field>
<field name="body">Your homepage is a summary of messages you received and key information about documents you follow.
The top menu bar contains all applications you installed. You can use this &lt;i&gt;Settings&lt;/i&gt; menu to install more applications, activate others features or give access to new users.
To setup your preferences (name, email signature, avatar), click on the top right corner.</value>
</function>
To setup your preferences (name, email signature, avatar), click on the top right corner.</field>
</record>
</data>
</openerp>

View File

@ -57,7 +57,7 @@ Use the thread viewer widget inside your form view by using the mail_thread widg
Send notifications
+++++++++++++++++++
When sending a notification is required in your workflow or business logic, use the ``message_append_note`` method. This method is a shortcut to the ``message_append`` method that takes all ``mail.message`` fields as arguments. This latter method calls ``message_create`` that
When sending a notification is required in your workflow or business logic, use the ``message_post`` method. This method is a shortcut to the ``message_append`` method that takes all ``mail.message`` fields as arguments. This latter method calls ``message_create`` that
- creates the message
- parses the body to find users you want to push the message to (finding and parsing ``@login`` in the message body)
@ -74,7 +74,7 @@ You should therefore not worry about subscriptions or anything else than sending
return res
def do_something_send_note(self, cr, uid, ids, context=None):
self.message_append_note(cr, uid, ids, _('My subject'),
self.message_post(cr, uid, ids, _('My subject'),
_("has received a <b>notification</b> and is happy for it."), context=context)
Notifications guidelines
@ -147,7 +147,7 @@ The best way to direct the messages that will be displayed in the OpenChatter wi
# add: search in the current task project messages
'&', '&', ('res_id', '=', my_task.project_id.id), ('model', '=', 'project.project'),
# ... containing the task name
'|', ('body_text', 'like', '%s' % (my_task.name)), ('body_html', 'like', '%s' % (my_task.name))
'|', ('body', 'like', '%s' % (my_task.name)), ('body_html', 'like', '%s' % (my_task.name))
] + domain, limit=limit, offset=offset, context=context)
# if asked: add ancestor ids to have complete threads
if (ascent): msg_ids = self._message_add_ancestor_ids(cr, uid, ids, msg_ids, root_ids, context=context)

View File

@ -1,15 +1,15 @@
.. _mail_state:
message_state
message_unread
=============
``message_state`` is a boolean field that states whether the document
``message_unread`` is a boolean field that states whether the document
has unread messages. In previous versions, some documents were going
back to ``pending`` state when receiving an email through the mail
gateway. Now the state related to messages differs from the state or
stage of the document itself.
message_state and need action mechanism
message_unread and need action mechanism
+++++++++++++++++++++++++++++++++++++++
The ``mail`` module introduces a default behavior for the need_action
@ -23,6 +23,6 @@ mechanism [REF].
"""
result = super(ir_needaction_mixin, self).get_needaction_user_ids(cr, uid, ids, context=context)
for obj in self.browse(cr, uid, ids, context=context):
if obj.message_state == False and obj.user_id:
if obj.message_unread == False and obj.user_id:
result[obj.id].append(obj.user_id.id)
return result

Some files were not shown because too many files have changed in this diff Show More