[MERGE] Latest trunk
bzr revid: mat@openerp.com-20130320092510-w6roigzs70hwwbfe
This commit is contained in:
@@ -30,7 +30,6 @@
|
||||
</record>
|
||||
|
||||
<record id="account_payment_term_line_15days" model="account.payment.term.line">
|
||||
<field name="name">15 Days</field>
|
||||
<field name="value">balance</field>
|
||||
<field eval="15" name="days"/>
|
||||
<field eval="0" name="days2"/>
|
||||
@@ -48,7 +47,6 @@
|
||||
</record>
|
||||
|
||||
<record id="account_payment_term_line_net" model="account.payment.term.line">
|
||||
<field name="name">30 Net Days</field>
|
||||
<field name="value">balance</field>
|
||||
<field eval="30" name="days"/>
|
||||
<field eval="0" name="days2"/>
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
<field name="note">30 Days End of Month</field>
|
||||
</record>
|
||||
<record id="account_payment_term_line" model="account.payment.term.line">
|
||||
<field name="name">30 Days End of Month</field>
|
||||
<field name="value">balance</field>
|
||||
<field eval="30" name="days"/>
|
||||
<field eval="-1" name="days2"/>
|
||||
@@ -147,16 +146,13 @@
|
||||
<field name="note">30% Advance End 30 Days</field>
|
||||
</record>
|
||||
<record id="account_payment_term_line_advance1" model="account.payment.term.line">
|
||||
<field name="name">30% Advance</field>
|
||||
<field name="value">procent</field>
|
||||
<field eval="3" name="sequence"/>
|
||||
<field eval="0.300000" name="value_amount"/>
|
||||
<field eval="0" name="days"/>
|
||||
<field eval="0" name="days2"/>
|
||||
<field eval="account_payment_term_advance" name="payment_id"/>
|
||||
</record>
|
||||
<record id="account_payment_term_line_advance2" model="account.payment.term.line">
|
||||
<field name="name">Remaining Balance</field>
|
||||
<field name="value">balance</field>
|
||||
<field eval="30" name="days"/>
|
||||
<field eval="-1" name="days2"/>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<field name="name">Invoice - Send by Email</field>
|
||||
<field name="email_from">${object.user_id.email or object.company_id.email or 'noreply@localhost'}</field>
|
||||
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a'})</field>
|
||||
<field name="email_recipients">${object.partner_id.id}</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="account.model_account_invoice"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="report_template" ref="account_invoices"/>
|
||||
|
||||
@@ -276,7 +276,7 @@
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('invoice_id','=',False)]</field>
|
||||
<field name="context">{'search_default_to_invoice': 1, 'search_default_sales': 1}</field>
|
||||
<field name="context">{'search_default_to_invoice': 1}</field>
|
||||
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
|
||||
@@ -53,7 +53,6 @@ have a new option to import payment orders as bank statement lines.
|
||||
'account_payment_view.xml',
|
||||
'account_payment_workflow.xml',
|
||||
'account_payment_sequence.xml',
|
||||
'account_invoice_view.xml',
|
||||
'account_payment_report.xml',
|
||||
],
|
||||
'demo': ['account_payment_demo.xml'],
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from datetime import datetime
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.osv import osv
|
||||
|
||||
class Invoice(osv.osv):
|
||||
_inherit = 'account.invoice'
|
||||
@@ -43,28 +42,6 @@ class Invoice(osv.osv):
|
||||
raise osv.except_osv(_('Error!'), _("You cannot cancel an invoice which has already been imported in a payment order. Remove it from the following payment order : %s."%(payment_order_name)))
|
||||
return super(Invoice, self).action_cancel(cr, uid, ids, context=context)
|
||||
|
||||
def _amount_to_pay(self, cursor, user, ids, name, args, context=None):
|
||||
'''Return the amount still to pay regarding all the payment orders'''
|
||||
if not ids:
|
||||
return {}
|
||||
res = {}
|
||||
for invoice in self.browse(cursor, user, ids, context=context):
|
||||
res[invoice.id] = 0.0
|
||||
if invoice.move_id:
|
||||
for line in invoice.move_id.line_id:
|
||||
if not line.date_maturity or \
|
||||
datetime.strptime(line.date_maturity, '%Y-%m-%d') \
|
||||
< datetime.today():
|
||||
res[invoice.id] += line.amount_to_pay
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'amount_to_pay': fields.function(_amount_to_pay,
|
||||
type='float', string='Amount to be paid',
|
||||
help='The amount which should be paid at the current date\n' \
|
||||
'minus the amount which is already in payment order'),
|
||||
}
|
||||
|
||||
Invoice()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="invoice_supplier_form" model="ir.ui.view">
|
||||
<field name="name">account.invoice.supplier.form.inherit</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account.invoice_supplier_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_bank_id" position="before">
|
||||
<field name="amount_to_pay"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -19,65 +19,12 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from operator import itemgetter
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.osv import osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
class account_move_line(osv.osv):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
def amount_to_pay(self, cr, uid, ids, name, arg=None, context=None):
|
||||
""" Return the amount still to pay regarding all the payemnt orders
|
||||
(excepting cancelled orders)"""
|
||||
if not ids:
|
||||
return {}
|
||||
cr.execute("""SELECT ml.id,
|
||||
CASE WHEN ml.amount_currency < 0
|
||||
THEN - ml.amount_currency
|
||||
ELSE ml.credit
|
||||
END -
|
||||
(SELECT coalesce(sum(amount_currency),0)
|
||||
FROM payment_line pl
|
||||
INNER JOIN payment_order po
|
||||
ON (pl.order_id = po.id)
|
||||
WHERE move_line_id = ml.id
|
||||
AND po.state != 'cancel') AS amount
|
||||
FROM account_move_line ml
|
||||
WHERE id IN %s""", (tuple(ids),))
|
||||
r = dict(cr.fetchall())
|
||||
return r
|
||||
|
||||
def _to_pay_search(self, cr, uid, obj, name, args, context=None):
|
||||
if not args:
|
||||
return []
|
||||
line_obj = self.pool.get('account.move.line')
|
||||
query = line_obj._query_get(cr, uid, context={})
|
||||
where = ' and '.join(map(lambda x: '''(SELECT
|
||||
CASE WHEN l.amount_currency < 0
|
||||
THEN - l.amount_currency
|
||||
ELSE l.credit
|
||||
END - coalesce(sum(pl.amount_currency), 0)
|
||||
FROM payment_line pl
|
||||
INNER JOIN payment_order po ON (pl.order_id = po.id)
|
||||
WHERE move_line_id = l.id
|
||||
AND po.state != 'cancel'
|
||||
) %(operator)s %%s ''' % {'operator': x[1]}, args))
|
||||
sql_args = tuple(map(itemgetter(2), args))
|
||||
|
||||
cr.execute(('''SELECT id
|
||||
FROM account_move_line l
|
||||
WHERE account_id IN (select id
|
||||
FROM account_account
|
||||
WHERE type=%s AND active)
|
||||
AND reconcile_id IS null
|
||||
AND credit > 0
|
||||
AND ''' + where + ' and ' + query), ('payable',)+sql_args )
|
||||
|
||||
res = cr.fetchall()
|
||||
if not res:
|
||||
return [('id', '=', '0')]
|
||||
return [('id', 'in', map(lambda x:x[0], res))]
|
||||
|
||||
def line2bank(self, cr, uid, ids, payment_type=None, context=None):
|
||||
"""
|
||||
Try to return for each Ledger Posting line a corresponding bank
|
||||
@@ -110,11 +57,6 @@ class account_move_line(osv.osv):
|
||||
raise osv.except_osv(_('Error!'), _('There is no partner defined on the entry line.'))
|
||||
return line2bank
|
||||
|
||||
_columns = {
|
||||
'amount_to_pay': fields.function(amount_to_pay,
|
||||
type='float', string='Amount to pay', fnct_search=_to_pay_search),
|
||||
}
|
||||
|
||||
account_move_line()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -352,7 +352,7 @@ class payment_line(osv.osv):
|
||||
|
||||
if move_line_id:
|
||||
line = move_line_obj.browse(cr, uid, move_line_id, context=context)
|
||||
data['amount_currency'] = line.amount_to_pay
|
||||
data['amount_currency'] = line.amount_residual_currency
|
||||
|
||||
res = self.onchange_amount(cr, uid, ids, data['amount_currency'], currency,
|
||||
company_currency, context)
|
||||
|
||||
@@ -2,29 +2,6 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- View used in the wizard -->
|
||||
<record id="view_move_line_form" model="ir.ui.view">
|
||||
<field name="name">account.move.line.form.inherit</field>
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="inherit_id" ref="account.view_move_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="reconcile_partial_id" position="after">
|
||||
<field name="amount_to_pay"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record model="ir.ui.view" id="view_move_line_tree_wiz">
|
||||
<field name="name">account.move.line.tree</field>
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="reconcile" position="after">
|
||||
<field name="amount_to_pay"/>
|
||||
</field>
|
||||
</field>
|
||||
</record> -->
|
||||
|
||||
<menuitem id="menu_main_payment" name="Payment" parent="account.menu_finance" sequence="7"/>
|
||||
|
||||
<record id="view_payment_mode_search" model="ir.ui.view">
|
||||
@@ -116,7 +93,7 @@
|
||||
<notebook>
|
||||
<page string="Payment">
|
||||
<group col="4">
|
||||
<field name="move_line_id" on_change="onchange_move_line(move_line_id,parent.mode,parent.date_prefered,parent.date_scheduled,currency,company_currency)" domain="[('reconcile_id','=', False), ('credit', '>',0),('amount_to_pay','>',0)] "/>
|
||||
<field name="move_line_id" on_change="onchange_move_line(move_line_id,parent.mode,parent.date_prefered,parent.date_scheduled,currency,company_currency)" domain="[('reconcile_id','=', False), ('credit', '>',0),('amount_residual','>',0)] "/>
|
||||
<separator colspan="4" string="Transaction Information"/>
|
||||
<field name="date"/>
|
||||
<label for="amount_currency" groups="base.group_multi_currency"/>
|
||||
@@ -242,7 +219,7 @@
|
||||
<page string="Payment">
|
||||
<group col="4">
|
||||
<field name="order_id"/>
|
||||
<field name="move_line_id" on_change="onchange_move_line(move_line_id, False, currency, company_currency)" domain="[('reconcile_id','=', False), ('credit', '>',0),('amount_to_pay','>',0)]"/>
|
||||
<field name="move_line_id" on_change="onchange_move_line(move_line_id, False, currency, company_currency)" domain="[('reconcile_id','=', False), ('credit', '>',0),('amount_residual','>',0)]"/>
|
||||
<separator colspan="4" string="Transaction Information"/>
|
||||
<field name="date"/>
|
||||
<label for="amount_currency" groups="base.group_multi_currency"/>
|
||||
|
||||
@@ -82,7 +82,7 @@ class payment_order_create(osv.osv_memory):
|
||||
date_to_pay = payment.date_scheduled
|
||||
payment_obj.create(cr, uid,{
|
||||
'move_line_id': line.id,
|
||||
'amount_currency': line.amount_to_pay,
|
||||
'amount_currency': line.amount_residual_currency,
|
||||
'bank_id': line2bank.get(line.id),
|
||||
'order_id': payment.id,
|
||||
'partner_id': line.partner_id and line.partner_id.id or False,
|
||||
@@ -102,7 +102,7 @@ class payment_order_create(osv.osv_memory):
|
||||
# payment = self.pool.get('payment.order').browse(cr, uid, context['active_id'], context=context)
|
||||
|
||||
# Search for move line to pay:
|
||||
domain = [('reconcile_id', '=', False), ('account_id.type', '=', 'payable'), ('amount_to_pay', '>', 0)]
|
||||
domain = [('reconcile_id', '=', False), ('account_id.type', '=', 'payable'), ('amount_residual', '>', 0)]
|
||||
domain = domain + ['|', ('date_maturity', '<=', search_due_date), ('date_maturity', '=', False)]
|
||||
line_ids = line_obj.search(cr, uid, domain, context=context)
|
||||
context.update({'line_ids': line_ids})
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Hungarian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-03-19 18:28+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hungarian <hu@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: 2013-03-20 04:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: auth_crypt
|
||||
#: field:res.users,password_crypt:0
|
||||
msgid "Encrypted Password"
|
||||
msgstr "Kódolt jalszó"
|
||||
|
||||
#. module: auth_crypt
|
||||
#: model:ir.model,name:auth_crypt.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Felhasználók"
|
||||
@@ -0,0 +1,135 @@
|
||||
# Hungarian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-03-19 18:17+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hungarian <hu@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: 2013-03-20 04:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,validation_endpoint:0
|
||||
msgid "Validation URL"
|
||||
msgstr "URL elérési út érvényesítés"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,auth_endpoint:0
|
||||
msgid "Authentication URL"
|
||||
msgstr "URL elérési út hitelesítés"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: model:ir.model,name:auth_oauth.model_base_config_settings
|
||||
msgid "base.config.settings"
|
||||
msgstr "base.config.settings"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,name:0
|
||||
msgid "Provider name"
|
||||
msgstr "Szolgáltató neve"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,scope:0
|
||||
msgid "Scope"
|
||||
msgstr "Hatáskör"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:res.users,oauth_provider_id:0
|
||||
msgid "OAuth Provider"
|
||||
msgstr "OAuth szolgáltató"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,css_class:0
|
||||
msgid "CSS class"
|
||||
msgstr "CSS osztály"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,body:0
|
||||
msgid "Body"
|
||||
msgstr "Törzs"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: model:ir.model,name:auth_oauth.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Felhasználók"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,sequence:0
|
||||
msgid "unknown"
|
||||
msgstr "ismeretlen"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:res.users,oauth_access_token:0
|
||||
msgid "OAuth Access Token"
|
||||
msgstr "OAuth hozzáférési Token"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,client_id:0
|
||||
#: field:base.config.settings,auth_oauth_facebook_client_id:0
|
||||
#: field:base.config.settings,auth_oauth_google_client_id:0
|
||||
msgid "Client ID"
|
||||
msgstr "Ügyfál ID azonosító"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: model:ir.ui.menu,name:auth_oauth.menu_oauth_providers
|
||||
msgid "OAuth Providers"
|
||||
msgstr "OAuth szolgáltatók"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: model:ir.model,name:auth_oauth.model_auth_oauth_provider
|
||||
msgid "OAuth2 provider"
|
||||
msgstr "OAuth2 szolgáltató"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:res.users,oauth_uid:0
|
||||
msgid "OAuth User ID"
|
||||
msgstr "OAuth felhasználó ID azonosító"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:base.config.settings,auth_oauth_facebook_enabled:0
|
||||
msgid "Allow users to sign in with Facebook"
|
||||
msgstr "Felhasználók Facebook keresztüli bejelentkezés engedélyezése"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: sql_constraint:res.users:0
|
||||
msgid "OAuth UID must be unique per provider"
|
||||
msgstr "OAuth UID egyedinek kell lennie mindegyik szolgáltatóhoz"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: help:res.users,oauth_uid:0
|
||||
msgid "Oauth Provider user_id"
|
||||
msgstr "Oauth szolgáltatói felhasználó_id"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,data_endpoint:0
|
||||
msgid "Data URL"
|
||||
msgstr "Adat URL elérési út"
|
||||
|
||||
#. module: auth_oauth
|
||||
#: view:auth.oauth.provider:0
|
||||
msgid "arch"
|
||||
msgstr ""
|
||||
|
||||
#. module: auth_oauth
|
||||
#: model:ir.actions.act_window,name:auth_oauth.action_oauth_provider
|
||||
msgid "Providers"
|
||||
msgstr ""
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:base.config.settings,auth_oauth_google_enabled:0
|
||||
msgid "Allow users to sign in with Google"
|
||||
msgstr ""
|
||||
|
||||
#. module: auth_oauth
|
||||
#: field:auth.oauth.provider,enabled:0
|
||||
msgid "Allowed"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,23 @@
|
||||
# Hungarian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-03-19 18:13+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hungarian <hu@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: 2013-03-20 04:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Felhasználók"
|
||||
@@ -0,0 +1,97 @@
|
||||
# Hungarian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-03-19 18:15+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hungarian <hu@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: 2013-03-20 04:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:24
|
||||
#, python-format
|
||||
msgid "Username"
|
||||
msgstr "Felhasználónév"
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:12
|
||||
#: view:res.users:0
|
||||
#, python-format
|
||||
msgid "OpenID"
|
||||
msgstr "OpenID"
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:30
|
||||
#: field:res.users,openid_url:0
|
||||
#, python-format
|
||||
msgid "OpenID URL"
|
||||
msgstr "OpenID URL elérési út"
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:9
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:10
|
||||
#, python-format
|
||||
msgid "Google"
|
||||
msgstr "Google"
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:11
|
||||
#, python-format
|
||||
msgid "Launchpad"
|
||||
msgstr "Launchpad/Kiadásiszerk"
|
||||
|
||||
#. module: auth_openid
|
||||
#: help:res.users,openid_email:0
|
||||
msgid "Used for disambiguation in case of a shared OpenID URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:18
|
||||
#, python-format
|
||||
msgid "Google Apps Domain"
|
||||
msgstr "Google Alk Domain"
|
||||
|
||||
#. module: auth_openid
|
||||
#: field:res.users,openid_email:0
|
||||
msgid "OpenID Email"
|
||||
msgstr "OpenID Email"
|
||||
|
||||
#. module: auth_openid
|
||||
#: field:res.users,openid_key:0
|
||||
msgid "OpenID Key"
|
||||
msgstr "OpenID Kulcs"
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:8
|
||||
#, python-format
|
||||
msgid "Password"
|
||||
msgstr "Jelszó"
|
||||
|
||||
#. module: auth_openid
|
||||
#. openerp-web
|
||||
#: code:addons/auth_openid/static/src/xml/auth_openid.xml:10
|
||||
#, python-format
|
||||
msgid "Google Apps"
|
||||
msgstr "Google Alk"
|
||||
|
||||
#. module: auth_openid
|
||||
#: model:ir.model,name:auth_openid.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Felhasználók"
|
||||
@@ -1,25 +1,15 @@
|
||||
.login .pane {
|
||||
width: 260px;
|
||||
height: 175px;
|
||||
}
|
||||
|
||||
.login .pane input[name='openid_url'] {
|
||||
.oe_login .oe_login_pane input[name='openid_url'] {
|
||||
background: #fff url(../img/login-bg.gif) no-repeat 1px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.auth_choice {
|
||||
position: static;
|
||||
display: none;
|
||||
.openerp .oe_login .openid_providers {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.openid_providers {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
float: right;
|
||||
.openerp .oe_login .openid_providers ul {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.openid_providers li {
|
||||
.openerp .oe_login .openid_providers ul li {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0 1px 3px 2px;
|
||||
@@ -29,7 +19,6 @@
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 1px solid #ddd;
|
||||
background: #fff url(../img/openid_16.png) no-repeat 50%;
|
||||
text-indent: -9999px;
|
||||
overflow: hidden;
|
||||
@@ -37,20 +26,16 @@
|
||||
}
|
||||
|
||||
.openid_providers a.selected {
|
||||
border-color: #9A0404;
|
||||
background-color: #DC5F59;
|
||||
}
|
||||
|
||||
.openid_providers a[title="Password"] { background-image: url(../img/textfield_key.png); }
|
||||
.openid_providers a[title="AOL"] { background-image: url(../img/aol.png); }
|
||||
.openid_providers a[title="ClaimID"] { background-image: url(../img/claimid.png); }
|
||||
.openid_providers a[title="Google"] { background-image: url(../img/googlefav.png); }
|
||||
.openid_providers a[title="Google Apps"] { background-image: url(../img/marketplace.gif); }
|
||||
.openid_providers a[title="MyOpenID"] { background-image: url(../img/myopenid.png); }
|
||||
.openid_providers a[title="VeriSign"] { background-image: url(../img/verisign.png); }
|
||||
.openid_providers a[title="Yahoo!"] { background-image: url(../img/yahoo.png); }
|
||||
.openid_providers a[title="Launchpad"] { background-image: url(../img/launchpad.png); }
|
||||
.openid_providers a[data-provider="Password"] { background-image: url(../img/textfield_key.png); }
|
||||
.openid_providers a[data-provider="AOL"] { background-image: url(../img/aol.png); }
|
||||
.openid_providers a[data-provider="ClaimID"] { background-image: url(../img/claimid.png); }
|
||||
.openid_providers a[data-provider="Google"] { background-image: url(../img/googlefav.png); }
|
||||
.openid_providers a[data-provider="Google Apps"] { background-image: url(../img/marketplace.gif); }
|
||||
.openid_providers a[data-provider="MyOpenID"] { background-image: url(../img/myopenid.png); }
|
||||
.openid_providers a[data-provider="VeriSign"] { background-image: url(../img/verisign.png); }
|
||||
.openid_providers a[data-provider="Yahoo!"] { background-image: url(../img/yahoo.png); }
|
||||
.openid_providers a[data-provider="Launchpad"] { background-image: url(../img/launchpad.png); }
|
||||
|
||||
|
||||
li.auth_choice.selected {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,16 @@ instance.web.Login = instance.web.Login.extend({
|
||||
self.$openid_selected_input = $();
|
||||
self.$openid_selected_provider = null;
|
||||
|
||||
|
||||
// Hook auth_signup events. noop if module is not installed.
|
||||
self.on('change:login_mode', self, function() {
|
||||
var mode = self.get('login_mode') || 'default';
|
||||
if (mode !== 'default') {
|
||||
return;
|
||||
}
|
||||
self.do_openid_select(self.$openid_selected_button, self.$openid_selected_provider, true);
|
||||
});
|
||||
|
||||
|
||||
var openIdProvider = null;
|
||||
if (self.has_local_storage && self.remember_credentials) {
|
||||
@@ -21,12 +31,10 @@ instance.web.Login = instance.web.Login.extend({
|
||||
}
|
||||
|
||||
if (openIdProvider) {
|
||||
$openid_selected_provider = openIdProvider;
|
||||
self.$openid_selected_provider = openIdProvider;
|
||||
self.do_openid_select('a[href="#' + openIdProvider + '"]', openIdProvider, true);
|
||||
|
||||
if (self.has_local_storage && self.remember_credentials) {
|
||||
self.$openid_selected_input.find('input').val(localStorage.getItem('openid-login'));
|
||||
}
|
||||
self.$openid_selected_input.find('input').val(localStorage.getItem('openid-login') || '');
|
||||
}
|
||||
else {
|
||||
self.do_openid_select('a[data-url=""]', 'login,password', true);
|
||||
@@ -49,11 +57,12 @@ instance.web.Login = instance.web.Login.extend({
|
||||
do_openid_select: function (button, provider, noautosubmit) {
|
||||
var self = this;
|
||||
|
||||
self.$('li[data-provider]').hide();
|
||||
self.$openid_selected_button.add(self.$openid_selected_input).removeClass('selected');
|
||||
self.$openid_selected_button = self.$el.find(button).addClass('selected');
|
||||
|
||||
var input = _(provider.split(',')).map(function(p) { return 'li[data-provider="'+p+'"]'; }).join(',');
|
||||
self.$openid_selected_input = self.$el.find(input).addClass('selected');
|
||||
self.$openid_selected_input = self.$el.find(input).show();
|
||||
|
||||
self.$openid_selected_input.find('input:first').focus();
|
||||
self.$openid_selected_provider = (self.$openid_selected_button.attr('href') || '').substr(1);
|
||||
@@ -62,7 +71,7 @@ instance.web.Login = instance.web.Login.extend({
|
||||
localStorage.setItem('openid-provider', self.$openid_selected_provider);
|
||||
}
|
||||
|
||||
if (!noautosubmit && self.$openid_selected_input.length == 0) {
|
||||
if (!noautosubmit && self.$openid_selected_input.length === 0) {
|
||||
self.$el.find('form').submit();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,44 +4,53 @@
|
||||
|
||||
<t t-extend="Login">
|
||||
<t t-jquery=".oe_login .oe_login_logo" t-operation="after">
|
||||
<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>
|
||||
<li><a href="#launchpad" title="Launchpad" data-url="https://launchpad.net/~{id}">Launchpad</a></li>
|
||||
<li><a href="#openid_url" title="OpenID" data-url="{id}">OpenID</a></li>
|
||||
</ul>
|
||||
<div class="openid_providers" data-modes="default openid"><ul>
|
||||
<li><a href="#login,password" data-provider='Password' title="Password" data-url="" id="btn_password">Password</a></li>
|
||||
<li><a href="#google" data-provider='Google' title="Google" data-url="https://www.google.com/accounts/o8/id">Google</a></li>
|
||||
<li><a href="#googleapps" data-provider='Google Apps' title="Google Apps" data-url="https://www.google.com/accounts/o8/site-xrds?hd={id}">Google</a></li>
|
||||
<li><a href="#launchpad" data-provider='Launchpad' title="Launchpad" data-url="https://launchpad.net/~{id}">Launchpad</a></li>
|
||||
<li><a href="#openid_url" data-provider='OpenID' title="OpenID" data-url="{id}">OpenID</a></li>
|
||||
</ul></div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-extend="Login">
|
||||
<t t-jquery=".oe_login .oe_login_pane form ul li:nth-child(4)" t-operation="after">
|
||||
<li>
|
||||
<t t-jquery=".oe_login .oe_login_pane form ul li:last-child()" t-operation="before">
|
||||
<li data-modes="openid" data-provider='googleapps'>
|
||||
Google Apps Domain
|
||||
</li>
|
||||
<li>
|
||||
<li data-modes="openid" data-provider='googleapps'>
|
||||
<input type="text" name="googleapps" />
|
||||
</li>
|
||||
<li>
|
||||
<li data-modes="openid" data-provider='launchpad'>
|
||||
Username
|
||||
</li>
|
||||
<li>
|
||||
<li data-modes="openid" data-provider='launchpad'>
|
||||
<input type="text" name="launchpad" />
|
||||
</li>
|
||||
<li>
|
||||
<li data-modes="openid" data-provider='openid_url'>
|
||||
OpenID URL
|
||||
</li>
|
||||
<li>
|
||||
<li data-modes="openid" data-provider='openid_url'>
|
||||
<input type="text" name="openid_url" />
|
||||
</li>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-extend="Login">
|
||||
<t t-jquery=".oe_login .oe_login_pane form ul li:has(input)">
|
||||
<t t-jquery=".oe_login .oe_login_pane form ul li:has(input[name=password])">
|
||||
this.each(function() {
|
||||
var $i = $(this);
|
||||
$i.add($i.prev()).attr('data-provider', 'password');
|
||||
});
|
||||
</t>
|
||||
<t t-jquery=".oe_login .oe_login_pane form ul li:has(input[name=login])">
|
||||
this.each(function() {
|
||||
var $i = $(this),
|
||||
dp = $i.find('input').attr('name');
|
||||
$i.add($i.prev()).attr('class', 'auth_choice').attr('data-provider', dp);
|
||||
dp = $i.find('input').attr('name'),
|
||||
$p = $i.prev();
|
||||
// $p may not be the correct label when auth_signup is installed.
|
||||
while(($p.attr('data-modes') || 'default') !== 'default') { $p = $p.prev(); }
|
||||
$i.add($p).attr('data-provider', dp);
|
||||
});
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -161,14 +161,12 @@ class res_users(osv.Model):
|
||||
def _get_state(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for user in self.browse(cr, uid, ids, context):
|
||||
res[user.id] = ('reset' if user.signup_valid else
|
||||
'active' if user.login_date else
|
||||
'new')
|
||||
res[user.id] = ('active' if user.login_date else 'new')
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'state': fields.function(_get_state, string='Status', type='selection',
|
||||
selection=[('new', 'New'), ('active', 'Active'), ('reset', 'Resetting Password')]),
|
||||
selection=[('new', 'Never Connected'), ('active', 'Activated')]),
|
||||
}
|
||||
|
||||
def signup(self, cr, uid, values, token=None, context=None):
|
||||
@@ -270,16 +268,7 @@ class res_users(osv.Model):
|
||||
if mail_state and mail_state['state'] == 'exception':
|
||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("Cannot send email: no outgoing email server configured.\nYou can configure it under %(menu:base_setup.menu_general_configuration)s."), context)
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'name': '_(Server Notification)',
|
||||
'tag': 'action_notify',
|
||||
'params': {
|
||||
'title': 'Mail Sent to: %s' % user.name,
|
||||
'text': 'You can reset the password by yourself using this <a href=%s>link</a>' % user.partner_id.signup_url,
|
||||
'sticky': True,
|
||||
}
|
||||
}
|
||||
return True
|
||||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
# overridden to automatically invite user to sign up
|
||||
|
||||
@@ -17,13 +17,25 @@
|
||||
<header>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<div class="oe_form_box_info oe_text_center" attrs="{'invisible': [('signup_valid', '!=', True)]}">
|
||||
<p attrs="{'invisible': [('state', '!=', 'active')]}">
|
||||
<b>A password reset has been requested for this user. An email containing the following link has been sent:</b>
|
||||
</p>
|
||||
<p attrs="{'invisible': [('state', '!=', 'new')]}">
|
||||
<b>An invitation email containing the following subscription link has been sent:</b>
|
||||
</p>
|
||||
<p><field class="oe_inline" name="signup_url" widget="url"/></p>
|
||||
<field name="signup_valid" invisible="1"/>
|
||||
</div>
|
||||
</xpath>
|
||||
<!-- add Reset Password button -->
|
||||
<xpath expr="//div[@class='oe_right oe_button_box']" position="replace">
|
||||
<div class="oe_right oe_button_box">
|
||||
<xpath expr="//div[@class='oe_right oe_button_box']//button" position="replace">
|
||||
<button string="Send Reset Password Instructions"
|
||||
type="object" name="action_reset_password" />
|
||||
</div>
|
||||
type="object" name="action_reset_password"
|
||||
attrs="{'invisible': [('state', '!=', 'active')]}"/>
|
||||
<button string="Send an Invitation Email"
|
||||
type="object" name="action_reset_password" context="{'create_user': 1}"
|
||||
attrs="{'invisible': [('state', '!=', 'new')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -56,7 +56,7 @@ openerp.auth_signup = function(instance) {
|
||||
self.rpc("/auth_signup/get_config", {dbname: dbname}).done(function(result) {
|
||||
self.signup_enabled = result.signup;
|
||||
self.reset_password_enabled = result.reset_password;
|
||||
if (self.$("form input[name=login]").val()){
|
||||
if (!self.signup_enabled || self.$("form input[name=login]").val()){
|
||||
self.set('login_mode', 'default');
|
||||
} else {
|
||||
self.set('login_mode', 'signup');
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
<li data-modes="default">Username</li>
|
||||
<li data-modes="signup reset">Username (Email)</li>
|
||||
</t>
|
||||
<t t-jquery="form ul:first li:has(input[name=login], input[name=password]), form ul:first li:contains('Password')">
|
||||
this.attr('data-modes', 'default signup reset');
|
||||
</t>
|
||||
<t t-jquery="form ul:first li:has(input[name=password])" t-operation="after">
|
||||
<li data-modes="signup reset">Confirm Password</li>
|
||||
<li data-modes="signup reset"><input name="confirm_password" type="password"/></li>
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 6.0dev\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-03-18 00:17+0000\n"
|
||||
"PO-Revision-Date: 2013-03-19 17:29+0000\n"
|
||||
"Last-Translator: krnkris <Unknown>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-18 04:46+0000\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-20 04:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: base_calendar
|
||||
@@ -257,7 +257,7 @@ msgstr "Hiba!"
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.attendee,role:0
|
||||
msgid "Chair Person"
|
||||
msgstr ""
|
||||
msgstr "Elnök személye"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:crm.meeting:0
|
||||
@@ -886,7 +886,7 @@ msgstr "Ügyféltalálkozó"
|
||||
msgid ""
|
||||
"Reference to the URIthat points to the directory information corresponding "
|
||||
"to the attendee."
|
||||
msgstr ""
|
||||
msgstr "URI hivatkozás mely a felszólaló információs könyvtárára mutat"
|
||||
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.event,month_list:0
|
||||
@@ -1099,6 +1099,7 @@ msgstr "Feladattal megbízva"
|
||||
#: help:calendar.alarm,action:0
|
||||
msgid "Defines the action to be invoked when an alarm is triggered"
|
||||
msgstr ""
|
||||
"Meghatározza a segítségül hivható műveletet egy vészjelzés beindítása esetén"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:crm.meeting:0
|
||||
@@ -1124,18 +1125,20 @@ msgid ""
|
||||
"If the active field is set to true, it will allow you to hide the event "
|
||||
"alarm information without removing it."
|
||||
msgstr ""
|
||||
"Ha egy aktív mező igazra állított, akkor lehetővé teszi az esemény riasztás "
|
||||
"információ eltüntetését annak törlése nélkül."
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.event,end_type:0
|
||||
#: field:calendar.todo,end_type:0
|
||||
#: field:crm.meeting,end_type:0
|
||||
msgid "Recurrence Termination"
|
||||
msgstr ""
|
||||
msgstr "Ismétlés megállítása"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:crm.meeting:0
|
||||
msgid "Until"
|
||||
msgstr ""
|
||||
msgstr "Eddig"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:res.alarm:0
|
||||
@@ -1145,12 +1148,12 @@ msgstr "Emlékeztető részletei"
|
||||
#. module: base_calendar
|
||||
#: model:crm.meeting.type,name:base_calendar.categ_meet3
|
||||
msgid "Off-site Meeting"
|
||||
msgstr ""
|
||||
msgstr "Külső találkozó"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:crm.meeting:0
|
||||
msgid "Day of Month"
|
||||
msgstr ""
|
||||
msgstr "A hónap napja"
|
||||
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.alarm,state:0
|
||||
@@ -1167,7 +1170,7 @@ msgstr "Ismétlés (nap/hét/hó/év)"
|
||||
#. module: base_calendar
|
||||
#: view:crm.meeting:0
|
||||
msgid "All Day?"
|
||||
msgstr ""
|
||||
msgstr "Minden nap?"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:calendar.event:0
|
||||
@@ -1188,6 +1191,16 @@ msgid ""
|
||||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"<p class=\"oe_view_nocontent_create\">\n"
|
||||
" Kattintson új találkozó ütemezéséhez.\n"
|
||||
" </p><p>\n"
|
||||
" A naptár az alkalmazottak között megosztott és teljesen "
|
||||
"integrált az\n"
|
||||
" egyéb alkalmazásokkal mint az alkalmazotti szabadságok vagy az "
|
||||
"üzleti\n"
|
||||
" lehetőségek.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
|
||||
#. module: base_calendar
|
||||
#: help:calendar.alarm,description:0
|
||||
@@ -1196,6 +1209,8 @@ msgid ""
|
||||
"calendar component, than that provided by the "
|
||||
"\"SUMMARY\" property"
|
||||
msgstr ""
|
||||
"Egy jóval összetettebb leírást biztosít a naptári bejegyzéshez, mint amit az "
|
||||
"\"ÖSSZEGZÉS\" tulajdonságoknál létre lett hozva"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:calendar.event:0
|
||||
@@ -1205,7 +1220,7 @@ msgstr "Felelős felhasználó"
|
||||
#. module: base_calendar
|
||||
#: view:crm.meeting:0
|
||||
msgid "Select Weekdays"
|
||||
msgstr ""
|
||||
msgstr "Munkanapokat válasszon"
|
||||
|
||||
#. module: base_calendar
|
||||
#: code:addons/base_calendar/base_calendar.py:1519
|
||||
@@ -1220,7 +1235,7 @@ msgstr "Foglalt"
|
||||
#. module: base_calendar
|
||||
#: model:ir.model,name:base_calendar.model_calendar_event
|
||||
msgid "Calendar Event"
|
||||
msgstr ""
|
||||
msgstr "Naptári esemény"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.event,recurrency:0
|
||||
@@ -1255,6 +1270,8 @@ msgstr "Kivétel szabály"
|
||||
msgid ""
|
||||
"To specify the language for text values in aproperty or property parameter."
|
||||
msgstr ""
|
||||
"Nyelv meghatározása a tulajdonság vagy a tulajdonság paraméter szöveg "
|
||||
"értékekhez."
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:calendar.event:0
|
||||
@@ -1269,6 +1286,8 @@ msgid ""
|
||||
"Defines a rule or repeating pattern of time to exclude from the recurring "
|
||||
"rule."
|
||||
msgstr ""
|
||||
"Meghatároz egy idő szabályt vagy ismétlődési mintát az ismétlődési "
|
||||
"szabályból való kizáráshoz."
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.event,month_list:0
|
||||
@@ -1282,17 +1301,17 @@ msgstr "Hónap"
|
||||
#: selection:calendar.todo,rrule_type:0
|
||||
#: selection:crm.meeting,rrule_type:0
|
||||
msgid "Day(s)"
|
||||
msgstr ""
|
||||
msgstr "Nap(ok)"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:calendar.event:0
|
||||
msgid "Confirmed Events"
|
||||
msgstr ""
|
||||
msgstr "Nyugtázozz események"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.attendee,dir:0
|
||||
msgid "URI Reference"
|
||||
msgstr ""
|
||||
msgstr "URI Referencia"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.alarm,description:0
|
||||
@@ -1331,7 +1350,7 @@ msgstr "ir.values"
|
||||
#. module: base_calendar
|
||||
#: view:crm.meeting:0
|
||||
msgid "Search Meetings"
|
||||
msgstr ""
|
||||
msgstr "Találkozó keresés"
|
||||
|
||||
#. module: base_calendar
|
||||
#: model:ir.model,name:base_calendar.model_ir_attachment
|
||||
@@ -1341,7 +1360,7 @@ msgstr "ir.attachment"
|
||||
#. module: base_calendar
|
||||
#: model:ir.model,name:base_calendar.model_crm_meeting_type
|
||||
msgid "Meeting Type"
|
||||
msgstr ""
|
||||
msgstr "Találkozó típusa"
|
||||
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.attendee,state:0
|
||||
@@ -1367,16 +1386,24 @@ msgid ""
|
||||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"<p class=\"oe_view_nocontent_create\">\n"
|
||||
" Kattintson új riasztás típus beállításához.\n"
|
||||
" </p><p>\n"
|
||||
" Meg tud határozni egy személyre szabott naptári riasztás "
|
||||
"típust melyet\n"
|
||||
" hozzá lehet rendelni naptári eseményhez vagy találkozókhoz.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
|
||||
#. module: base_calendar
|
||||
#: selection:crm.meeting,state:0
|
||||
msgid "Unconfirmed"
|
||||
msgstr ""
|
||||
msgstr "Nincs megerősítve"
|
||||
|
||||
#. module: base_calendar
|
||||
#: help:calendar.attendee,sent_by:0
|
||||
msgid "Specify the user that is acting on behalf of the calendar user"
|
||||
msgstr ""
|
||||
msgstr "Határozza meg a falhasználót aki a naptár felhasználója lesz"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:calendar.event:0
|
||||
@@ -1409,7 +1436,7 @@ msgstr "Név"
|
||||
#: field:calendar.todo,exdate:0
|
||||
#: field:crm.meeting,exdate:0
|
||||
msgid "Exception Date/Times"
|
||||
msgstr ""
|
||||
msgstr "Dátum/idő kivételek"
|
||||
|
||||
#. module: base_calendar
|
||||
#: help:calendar.alarm,name:0
|
||||
@@ -1417,11 +1444,13 @@ msgid ""
|
||||
"Contains the text to be used as the message subject for "
|
||||
"email or contains the text to be used for display"
|
||||
msgstr ""
|
||||
"Tartalmazza az e-mail tárgyaként felhasznált szöveget vagy a megjeleníteni "
|
||||
"kívánt üzenetet"
|
||||
|
||||
#. module: base_calendar
|
||||
#: model:ir.model,name:base_calendar.model_mail_message
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
msgstr "Üzenet"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.event,base_calendar_alarm_id:0
|
||||
@@ -1446,7 +1475,7 @@ msgstr "Április"
|
||||
#: code:addons/base_calendar/crm_meeting.py:106
|
||||
#, python-format
|
||||
msgid "Email addresses not found"
|
||||
msgstr ""
|
||||
msgstr "E-mail cím nem található"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:calendar.event:0
|
||||
@@ -1464,7 +1493,7 @@ msgstr "Hétköznap"
|
||||
#: code:addons/base_calendar/base_calendar.py:1013
|
||||
#, python-format
|
||||
msgid "Interval cannot be negative."
|
||||
msgstr ""
|
||||
msgstr "Intervallum nem lehet negatív."
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.event,byday:0
|
||||
@@ -1477,7 +1506,7 @@ msgstr "Nappal"
|
||||
#: code:addons/base_calendar/base_calendar.py:441
|
||||
#, python-format
|
||||
msgid "First you have to specify the date of the invitation."
|
||||
msgstr ""
|
||||
msgstr "Elöször meg kell határoznia a meghívó dátumát."
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.alarm,model_id:0
|
||||
@@ -1499,7 +1528,7 @@ msgstr "ID"
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.attendee,role:0
|
||||
msgid "For information Purpose"
|
||||
msgstr ""
|
||||
msgstr "Információs célokra"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.event,select1:0
|
||||
@@ -1511,7 +1540,7 @@ msgstr "Opció"
|
||||
#. module: base_calendar
|
||||
#: model:ir.model,name:base_calendar.model_calendar_attendee
|
||||
msgid "Attendee information"
|
||||
msgstr ""
|
||||
msgstr "Résztvevők információi"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.alarm,res_id:0
|
||||
@@ -1521,12 +1550,12 @@ msgstr "Erőforrás ID"
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.attendee,state:0
|
||||
msgid "Needs Action"
|
||||
msgstr ""
|
||||
msgstr "Beavatkozás szükséges"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.attendee,sent_by:0
|
||||
msgid "Sent By"
|
||||
msgstr ""
|
||||
msgstr "Küldte"
|
||||
|
||||
#. module: base_calendar
|
||||
#: field:calendar.event,sequence:0
|
||||
@@ -1540,7 +1569,7 @@ msgstr "Sorszám"
|
||||
#: help:calendar.todo,alarm_id:0
|
||||
#: help:crm.meeting,alarm_id:0
|
||||
msgid "Set an alarm at this time, before the event occurs"
|
||||
msgstr ""
|
||||
msgstr "Most beállított riasztás, mielőtt az esemény elkezdődne"
|
||||
|
||||
#. module: base_calendar
|
||||
#: view:calendar.event:0
|
||||
@@ -1560,7 +1589,7 @@ msgstr "Szombat"
|
||||
#: field:calendar.todo,interval:0
|
||||
#: field:crm.meeting,interval:0
|
||||
msgid "Repeat Every"
|
||||
msgstr ""
|
||||
msgstr "Ismétlés minden"
|
||||
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.event,byday:0
|
||||
@@ -1601,6 +1630,11 @@ msgid ""
|
||||
" * Points to a procedure resource, which is invoked when "
|
||||
" the alarm is triggered for procedure."
|
||||
msgstr ""
|
||||
"* Hangforrásra mutat, mely beindul, ha a hangra "
|
||||
"riasztást ad,\n"
|
||||
" * Fájl mely elküldésre szánt mint e-mail melléklet,\n"
|
||||
" * Művelet forrásra mutat, melyet segítségül hív ha "
|
||||
" a riasztás a művelet miatt lett kapcsolva."
|
||||
|
||||
#. module: base_calendar
|
||||
#: selection:calendar.event,byday:0
|
||||
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-18 04:46+0000\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-19 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: base_import
|
||||
|
||||
@@ -72,19 +72,4 @@
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<!-- Mail template is done in a NOUPDATE block
|
||||
so users can freely customize/delete them -->
|
||||
<data noupdate="1">
|
||||
|
||||
<!--Definition of an email template with an empty body that will be used in opportunity mailing. Used to give a
|
||||
basis for email recipients, name and to ease the definition of a further elaborated template. -->
|
||||
<record id="email_template_opportunity_mail" model="email.template">
|
||||
<field name="name">Opportunity - Send Emails</field>
|
||||
<field name="subject">${object.name}</field>
|
||||
<field name="model_id" ref="crm.model_crm_lead"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="email_recipients">${object.partner_id.id}</field>
|
||||
<field name="body_html"></field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -221,5 +221,17 @@
|
||||
<field name="relation_field">section_id</field>
|
||||
</record>
|
||||
|
||||
<!--Definition of an email template with an empty body that will be used in opportunity mailing.
|
||||
Used to give a basis for email recipients, name and to ease the definition of a further
|
||||
elaborated template. -->
|
||||
<record id="email_template_opportunity_mail" model="email.template">
|
||||
<field name="name">Lead/Opportunity Mass Mail</field>
|
||||
<field name="model_id" ref="crm.model_crm_lead"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="partner_to">${object.partner_id and object.partner_id.id}</field>
|
||||
<field name="email_to">${not object.partner_id and object.email_from}</field>
|
||||
<field name="body_html"></field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_right oe_button_box" name="buttons">
|
||||
<button type="action"
|
||||
name="%(act_crm_opportunity_crm_phonecall_new)d"
|
||||
string="Phone Calls"/>
|
||||
<button string="Schedule/Log Call"
|
||||
name="%(opportunity2phonecall_act)d"
|
||||
type="action"/>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
@@ -151,7 +151,8 @@
|
||||
-->
|
||||
</group>
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="user_id"
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads']}"/>
|
||||
<label for="section_id"/>
|
||||
<div>
|
||||
<field name="section_id"/>
|
||||
@@ -426,7 +427,7 @@
|
||||
</group>
|
||||
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_sale_salesman_all_leads']}"/>
|
||||
<label for="section_id"/>
|
||||
<div>
|
||||
<field name="section_id" widget="selection"/>
|
||||
@@ -436,7 +437,7 @@
|
||||
<group>
|
||||
<field name="categ_ids"
|
||||
string="Categories" widget="many2many_tags"
|
||||
context = "{'object_name': 'crm.lead'}"
|
||||
context="{'object_name': 'crm.lead'}"
|
||||
domain="[('object_id.model', '=', 'crm.lead')]"/>
|
||||
|
||||
</group>
|
||||
@@ -581,5 +582,29 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
MASS MAILING
|
||||
-->
|
||||
<act_window name="Lead/Opportunity Mass Mail"
|
||||
res_model="mail.compose.message"
|
||||
src_model="crm.lead"
|
||||
view_mode="form"
|
||||
multi="True"
|
||||
target="new"
|
||||
key2="client_action_multi"
|
||||
id="crm.action_lead_mass_mail"
|
||||
context="{
|
||||
'default_composition_mode': 'mass_mail',
|
||||
'default_email_to':'{$object.email or \'\'}',
|
||||
'default_use_template': True,
|
||||
'default_template_id': ref('crm.email_template_opportunity_mail'),
|
||||
}"/>
|
||||
|
||||
<!--Update of email_template defined in crm_lead_data, to add ref_ir_act_window
|
||||
allowing to have a well formed email template (context action considered as set). -->
|
||||
<record id="email_template_opportunity_mail" model="email.template">
|
||||
<field name="ref_ir_act_window" ref="crm.action_lead_mass_mail"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -13,7 +13,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-18 04:46+0000\n"
|
||||
"X-Launchpad-Export-Date: 2013-03-19 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: crm
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<field name="inherit_id" ref="base.view_partner_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="after">
|
||||
<field name="date_review_next"/>
|
||||
<field name="grade_id"/>
|
||||
<field name="activation"/>
|
||||
</field>
|
||||
@@ -104,17 +105,19 @@
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<page string="Geo Localization">
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Partner Activation" colspan="2"/>
|
||||
<field name="grade_id" widget="selection"/>
|
||||
<field name="activation" widget="selection"/>
|
||||
<field name="partner_weight"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Partner Review" colspan="2"/>
|
||||
<field name="date_review"/>
|
||||
<field name="date_review_next"/>
|
||||
<field name="date_partnership"/>
|
||||
<group>
|
||||
<group>
|
||||
<separator string="Partner Activation" colspan="2"/>
|
||||
<field name="grade_id" widget="selection"/>
|
||||
<field name="activation" widget="selection"/>
|
||||
<field name="partner_weight"/>
|
||||
</group>
|
||||
<group>
|
||||
<separator string="Partner Review" colspan="2"/>
|
||||
<field name="date_review"/>
|
||||
<field name="date_review_next"/>
|
||||
<field name="date_partnership"/>
|
||||
</group>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Geo Localization" colspan="2"/>
|
||||
|
||||
@@ -146,7 +146,9 @@ class email_template(osv.osv):
|
||||
help="Sender address (placeholders may be used here). If not set, the default "
|
||||
"value will be the author's email alias if configured, or email address."),
|
||||
'email_to': fields.char('To (Emails)', help="Comma-separated recipient addresses (placeholders may be used here)"),
|
||||
'email_recipients': fields.char('To (Partners)', help="Comma-separated ids of recipient partners (placeholders may be used here)"),
|
||||
'partner_to': fields.char('To (Partners)',
|
||||
help="Comma-separated ids of recipient partners (placeholders may be used here)",
|
||||
oldname='email_recipients'),
|
||||
'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,
|
||||
@@ -314,7 +316,7 @@ class email_template(osv.osv):
|
||||
template = self.get_email_template(cr, uid, template_id, res_id, context)
|
||||
values = {}
|
||||
for field in ['subject', 'body_html', 'email_from',
|
||||
'email_to', 'email_recipients', 'email_cc', 'reply_to']:
|
||||
'email_to', 'partner_to', 'email_cc', 'reply_to']:
|
||||
values[field] = self.render_template(cr, uid, getattr(template, field),
|
||||
template.model, res_id, context=context) \
|
||||
or False
|
||||
@@ -374,7 +376,7 @@ class email_template(osv.osv):
|
||||
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 {}
|
||||
del values['email_recipients'] # TODO Properly use them.
|
||||
del values['partner_to'] # TODO Properly use them.
|
||||
msg_id = mail_mail.create(cr, uid, values, context=context)
|
||||
# link attachments
|
||||
attachment_ids = []
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<group string="Addressing">
|
||||
<field name="email_from"/>
|
||||
<field name="email_to"/>
|
||||
<field name="email_recipients"/>
|
||||
<field name="partner_to"/>
|
||||
<field name="email_cc"/>
|
||||
<field name="reply_to"/>
|
||||
<field name="user_signature"/>
|
||||
@@ -78,7 +78,7 @@
|
||||
<field name="subject"/>
|
||||
<field name="email_from"/>
|
||||
<field name="email_to"/>
|
||||
<field name="email_recipients"/>
|
||||
<field name="partner_to"/>
|
||||
<field name="report_name"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
@@ -25,5 +25,35 @@
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--Definition of an email template with an empty body that will be used in partner mailing. Used to give a
|
||||
basis for email recipients, name and to ease the definition of a further elaborated template. -->
|
||||
<record id="email_template_partner" model="email.template">
|
||||
<field name="name">Partner Mass Mail</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="partner_to">${object.id}</field>
|
||||
</record>
|
||||
|
||||
<!-- Replace the default mass-mailing wizard in base with the composition wizard -->
|
||||
<act_window name="Partner Mass Mailing"
|
||||
res_model="mail.compose.message"
|
||||
src_model="res.partner"
|
||||
view_mode="form"
|
||||
multi="True"
|
||||
target="new"
|
||||
key2="client_action_multi"
|
||||
id="base.action_partner_mass_mail"
|
||||
context="{
|
||||
'default_composition_mode': 'mass_mail',
|
||||
'default_partner_to': '${object.id or \'\'}',
|
||||
'default_use_template': True,
|
||||
'default_template_id': ref('email_template_partner'),
|
||||
}"/>
|
||||
|
||||
<record id="email_template_partner" model="email.template">
|
||||
<field name="ref_ir_act_window" ref="base.action_partner_mass_mail"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -130,6 +130,7 @@ class test_message_compose(TestMailBase):
|
||||
# 1. Mass_mail on pigs and bird, with a default_partner_ids set to check he is correctly added
|
||||
context = {
|
||||
'default_composition_mode': 'mass_mail',
|
||||
'default_notify': True,
|
||||
'default_model': 'mail.group',
|
||||
'default_res_id': self.group_pigs_id,
|
||||
'default_template_id': email_template_id,
|
||||
@@ -170,20 +171,20 @@ class test_message_compose(TestMailBase):
|
||||
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird notified_partner_ids incorrect')
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE4: test newly introduced email_recipients field
|
||||
# CASE4: test newly introduced partner_to field
|
||||
# ----------------------------------------
|
||||
|
||||
# get already-created partners back
|
||||
p_b_id = self.res_partner.search(cr, uid, [('email', '=', 'b@b.b')])[0]
|
||||
p_c_id = self.res_partner.search(cr, uid, [('email', '=', 'c@c.c')])[0]
|
||||
p_d_id = self.res_partner.search(cr, uid, [('email', '=', 'd@d.d')])[0]
|
||||
# modify template: use email_recipients, use template and email address in email_to to test all features together
|
||||
# modify template: use partner_to, use template and email address in email_to to test all features together
|
||||
user_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'res.users')])[0]
|
||||
email_template.write(cr, uid, [email_template_id], {
|
||||
'model_id': user_model_id,
|
||||
'body_html': '${object.login}',
|
||||
'email_to': '${object.email} c@c',
|
||||
'email_recipients': '%i,%i' % (p_b_id, p_c_id),
|
||||
'partner_to': '%i,%i' % (p_b_id, p_c_id),
|
||||
'email_cc': 'd@d',
|
||||
})
|
||||
# patner by email + partner by id (no double)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<group>
|
||||
<field name="email_from" readonly="1"/>
|
||||
<field name="email_to" readonly="1"/>
|
||||
<field name="email_recipients" readonly="1"/>
|
||||
<field name="partner_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"/>
|
||||
|
||||
@@ -59,14 +59,21 @@ class mail_compose_message(osv.TransientModel):
|
||||
_columns = {
|
||||
# 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),
|
||||
'partner_to': fields.char('To (Partner IDs)',
|
||||
help="Comma-separated list of recipient partners ids (placeholders may be used here)"),
|
||||
'email_to': fields.char('To (Emails)',
|
||||
help="Comma-separated recipient addresses (placeholders may be used here)",),
|
||||
'email_cc': fields.char('Cc (Emails)',
|
||||
help="Carbon copy recipients (placeholders may be used here)"),
|
||||
}
|
||||
|
||||
def onchange_template_id(self, cr, uid, ids, template_id, composition_mode, model, res_id, context=None):
|
||||
""" - mass_mailing: we cannot render, so return the template values
|
||||
- normal mode: return rendered values """
|
||||
if 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')
|
||||
fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to']
|
||||
template_values = self.pool.get('email.template').read(cr, uid, template_id, fields, context)
|
||||
values = dict((field, template_values[field]) for field in fields if template_values.get(field))
|
||||
elif template_id:
|
||||
# FIXME odo: change the mail generation to avoid attachment duplication
|
||||
values = self.generate_email_for_composer(cr, uid, template_id, res_id, context=context)
|
||||
@@ -84,7 +91,7 @@ class mail_compose_message(osv.TransientModel):
|
||||
}
|
||||
values['attachment_ids'].append(ir_attach_obj.create(cr, uid, data_attach, context=context))
|
||||
else:
|
||||
values = self.default_get(cr, uid, ['body', 'subject', 'partner_ids', 'attachment_ids'], context=context)
|
||||
values = self.default_get(cr, uid, ['subject', 'body', 'email_from', 'email_to', 'email_cc', 'partner_to', 'reply_to', 'attachment_ids'], context=context)
|
||||
|
||||
if values.get('body_html'):
|
||||
values['body'] = values.pop('body_html')
|
||||
@@ -117,26 +124,31 @@ class mail_compose_message(osv.TransientModel):
|
||||
# Wizard validation and send
|
||||
#------------------------------------------------------
|
||||
|
||||
def _get_or_create_partners_from_values(self, cr, uid, rendered_values, context=None):
|
||||
""" Check for email_to, email_cc, partner_to """
|
||||
partner_ids = []
|
||||
mails = tools.email_split(rendered_values.pop('email_to', '') + ' ' + rendered_values.pop('email_cc', ''))
|
||||
for mail in mails:
|
||||
partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
|
||||
partner_ids.append(partner_id)
|
||||
partner_to = rendered_values.pop('partner_to', '')
|
||||
if partner_to:
|
||||
for partner_id in partner_to.split(','):
|
||||
if partner_id: # placeholders could generate '', 3, 2 due to some empty field values
|
||||
partner_ids.append(int(partner_id))
|
||||
return partner_ids
|
||||
|
||||
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_html', 'subject', 'email_to', 'email_recipients', 'email_cc', 'attachments']
|
||||
fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', '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
|
||||
partner_ids = set()
|
||||
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)
|
||||
partner_ids.add(partner_id)
|
||||
email_recipients = values.pop('email_recipients', '')
|
||||
if email_recipients:
|
||||
for partner_id in email_recipients.split(','):
|
||||
if partner_id: # placeholders could generate '', 3, 2 due to some empty field values
|
||||
partner_ids.add(int(partner_id))
|
||||
partner_ids = self._get_or_create_partners_from_values(cr, uid, values, context=context)
|
||||
# legacy template behavior: void values do not erase existing values and the
|
||||
# related key is removed from the values dict
|
||||
if partner_ids:
|
||||
@@ -153,6 +165,11 @@ class mail_compose_message(osv.TransientModel):
|
||||
values = {}
|
||||
# get values to return
|
||||
email_dict = super(mail_compose_message, self).render_message(cr, uid, wizard, res_id, context)
|
||||
# those values are not managed; they are readonly
|
||||
email_dict.pop('email_to', None)
|
||||
email_dict.pop('email_cc', None)
|
||||
email_dict.pop('partner_to', None)
|
||||
# update template values by wizard values
|
||||
values.update(email_dict)
|
||||
return values
|
||||
|
||||
|
||||
@@ -7,6 +7,22 @@
|
||||
<field name="model">mail.compose.message</field>
|
||||
<field name="inherit_id" ref="mail.email_compose_message_wizard_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='subject']" position="after">
|
||||
<label string="Template Recipients" for="partner_to"
|
||||
groups="base.group_no_one"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<div groups="base.group_no_one"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}">
|
||||
<group class="oe_grey">
|
||||
<!-- <label string="Partners" for="partner_to"/> -->
|
||||
<field name="partner_to" readonly="1"/>
|
||||
<!-- <label string="Email To" for="email_to"/> -->
|
||||
<field name="email_to" readonly="1"/>
|
||||
<!-- <label string="Email CC" for="email_cc"/> -->
|
||||
<field name="email_cc" readonly="1"/>
|
||||
</group>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//footer" position="inside">
|
||||
<group class="oe_right" col="1">
|
||||
<div>Use template
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" on_change="onchange_company(company_id)"/>
|
||||
<field name="user_id" on_change="onchange_user(user_id)" string="Related User"/>
|
||||
<field name="user_id" on_change="onchange_user(user_id)" string="Related User"
|
||||
context="{'default_groups_ref': ['base.group_user']}"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="notes" placeholder="Other Information ..." colspan="4"/>
|
||||
|
||||
@@ -374,6 +374,7 @@
|
||||
<field name="model">hr.holidays.status</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Leave Type" version="7.0">
|
||||
<sheet string="Leave Type">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="categ_id"/>
|
||||
@@ -392,6 +393,7 @@
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -107,7 +107,8 @@
|
||||
<field name="type_id" placeholder="Degree"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="user_id"
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_hr_manager']}"/>
|
||||
<label for="title_action"/>
|
||||
<div>
|
||||
<field name="date_action"/>
|
||||
@@ -341,6 +342,7 @@
|
||||
<field name="model">hr.recruitment.stage</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Stage" version="7.0">
|
||||
<sheet>
|
||||
<group string="Stage Definition">
|
||||
<group>
|
||||
<field name="name"/>
|
||||
@@ -354,6 +356,7 @@
|
||||
</group>
|
||||
<separator string="Requirements"/>
|
||||
<field name="requirements"/>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -399,10 +402,12 @@
|
||||
<field name="model">hr.recruitment.degree</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Degree" version="7.0">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="sequence" groups="base.group_no_one"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -436,8 +441,12 @@
|
||||
<field name="name">hr.recruitment.source.form</field>
|
||||
<field name="model">hr.recruitment.source</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Sources of Applicants">
|
||||
<field name="name"/>
|
||||
<form string="Sources of Applicants" version="7.0">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="top" string="Timesheet Activities">
|
||||
<field name="date" on_change="on_change_date(date)"/>
|
||||
<field name="user_id" on_change="on_change_user_id(user_id)" required="1" options='{"no_open": True}'/>
|
||||
<field name="user_id" on_change="on_change_user_id(user_id)" required="1" options='{"no_open": True}'
|
||||
context="{'default_groups_ref': [base.group_user']}"/>
|
||||
<field name="name"/>
|
||||
<field domain="[('type','=','normal'),('use_timesheets','=',1)]" name="account_id" context="{'default_use_timesheets': 1, 'default_type': 'contract'}"/>
|
||||
<field name="unit_amount" string="Duration" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" sum="Total time" widget="float_time"/>
|
||||
@@ -29,7 +30,8 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="user_id" on_change="on_change_user_id(user_id)" required="1"/>
|
||||
<field name="user_id" on_change="on_change_user_id(user_id)" required="1"
|
||||
context="{'default_groups_ref': [base.group_user']}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date" on_change="on_change_date(date)"/>
|
||||
|
||||
@@ -213,6 +213,7 @@ class hr_timesheet_sheet(osv.osv):
|
||||
|
||||
def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
|
||||
department_id = False
|
||||
user_id = False
|
||||
if employee_id:
|
||||
empl_id = self.pool.get('hr.employee').browse(cr, uid, employee_id, context=context)
|
||||
department_id = empl_id.department_id.id
|
||||
|
||||
@@ -324,7 +324,8 @@
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name='user_id'/>
|
||||
<field name='user_id'
|
||||
context="{'default_groups_ref': ['base.group_user', 'lunch.group_lunch_user']}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name='date'/>
|
||||
@@ -409,7 +410,8 @@
|
||||
<form string="cashmove form" version="7.0">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="user_id"
|
||||
context="{'default_groups_ref': ['base.group_user', 'lunch.group_lunch_user']}"/>
|
||||
<field name="date"/>
|
||||
<field name="amount"/>
|
||||
</group>
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
##############################################################################
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import tools, SUPERUSER_ID
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools.mail import plaintext2html
|
||||
|
||||
class mail_followers(osv.Model):
|
||||
""" mail_followers holds the data related to the follow mechanism inside
|
||||
@@ -105,6 +107,43 @@ class mail_notification(osv.Model):
|
||||
notify_pids.append(partner.id)
|
||||
return notify_pids
|
||||
|
||||
def get_signature_footer(self, cr, uid, user_id, res_model=None, res_id=None, context=None):
|
||||
""" Format a standard footer for notification emails (such as pushed messages
|
||||
notification or invite emails).
|
||||
Format:
|
||||
<p>--<br />
|
||||
Administrator
|
||||
</p>
|
||||
<div>
|
||||
<small>Send by <a ...>Your Company</a> using <a ...>OpenERP</a>.</small> OR
|
||||
<small>Send by Administrator using <a ...>OpenERP</a>.</small>
|
||||
</div>
|
||||
"""
|
||||
footer = ""
|
||||
if not user_id:
|
||||
return footer
|
||||
|
||||
# add user signature
|
||||
user = self.pool.get("res.users").browse(cr, SUPERUSER_ID, [user_id], context=context)[0]
|
||||
if user.signature:
|
||||
signature = plaintext2html(user.signature)
|
||||
else:
|
||||
signature = "--<br />%s" % user.name
|
||||
footer = tools.append_content_to_html(footer, signature, plaintext=False, container_tag='p')
|
||||
|
||||
# add company signature
|
||||
if user.company_id:
|
||||
company = user.company_id.website and "<a style='color:inherit' href='%s'>%s</a>" % (user.company_id.website, user.company_id.name) or user.company_id.name
|
||||
else:
|
||||
company = user.name
|
||||
signature_company = _('<small>Send by %(company)s using %(openerp)s.</small>' % {
|
||||
'company': company,
|
||||
'openerp': "<a style='color:inherit' href='https://www.openerp.com/'>OpenERP</a>"
|
||||
})
|
||||
footer = tools.append_content_to_html(footer, signature_company, plaintext=False, container_tag='div')
|
||||
|
||||
return footer
|
||||
|
||||
def _notify(self, cr, uid, msg_id, partners_to_notify=None, context=None):
|
||||
""" Send by email the notification depending on the user preferences
|
||||
|
||||
@@ -141,31 +180,25 @@ class mail_notification(osv.Model):
|
||||
# TDE FIXME: commented, to be improved in a future branch
|
||||
# quote_context = self.pool.get('mail.message').message_quote_context(cr, uid, msg_id, context=context)
|
||||
|
||||
mail_mail = self.pool.get('mail.mail')
|
||||
# add signature
|
||||
body_html = msg.body
|
||||
# if quote_context:
|
||||
# body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
|
||||
signature = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].signature or ''
|
||||
if signature:
|
||||
body_html = tools.append_content_to_html(body_html, signature, plaintext=True, container_tag='div')
|
||||
|
||||
# email_from: partner-user alias or partner email or mail.message email_from
|
||||
if msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].alias_domain and msg.author_id.user_ids[0].alias_name:
|
||||
email_from = '%s <%s@%s>' % (msg.author_id.name, msg.author_id.user_ids[0].alias_name, msg.author_id.user_ids[0].alias_domain)
|
||||
elif msg.author_id:
|
||||
email_from = '%s <%s>' % (msg.author_id.name, msg.author_id.email)
|
||||
else:
|
||||
email_from = msg.email_from
|
||||
user_id = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0] and msg.author_id.user_ids[0].id or None
|
||||
signature_company = self.get_signature_footer(cr, uid, user_id, res_model=msg.model, res_id=msg.res_id, context=context)
|
||||
body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div')
|
||||
|
||||
mail_values = {
|
||||
'mail_message_id': msg.id,
|
||||
'auto_delete': True,
|
||||
'body_html': body_html,
|
||||
'email_from': email_from,
|
||||
'recipient_ids': [(4, id) for id in notify_partner_ids]
|
||||
}
|
||||
if msg.email_from:
|
||||
mail_values['email_from'] = msg.email_from
|
||||
if msg.reply_to:
|
||||
mail_values['reply_to'] = msg.reply_to
|
||||
mail_mail = self.pool.get('mail.mail')
|
||||
email_notif_id = mail_mail.create(cr, uid, mail_values, context=context)
|
||||
try:
|
||||
return mail_mail.send(cr, uid, [email_notif_id], recipient_ids=notify_partner_ids, context=context)
|
||||
return mail_mail.send(cr, uid, [email_notif_id], context=context)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
+60
-52
@@ -55,22 +55,25 @@ class mail_mail(osv.Model):
|
||||
help="Permanently delete this email after sending it, to save space"),
|
||||
'references': fields.text('References', help='Message references, such as identifiers of previous messages', readonly=1),
|
||||
'email_from': fields.char('From', help='Message sender, taken from user preferences.'),
|
||||
'email_to': fields.text('To', help='Message recipients'),
|
||||
'email_to': fields.text('To', help='Message recipients (emails)'),
|
||||
'recipient_ids': fields.many2many('res.partner', string='To (Partners)'),
|
||||
'email_cc': fields.char('Cc', help='Carbon copy message recipients'),
|
||||
'reply_to': fields.char('Reply-To', help='Preferred response address for the message'),
|
||||
'body_html': fields.text('Rich-text Contents', help="Rich-text/HTML message"),
|
||||
|
||||
# If not set in create values, auto-detected based on create values (res_id, model, email_from)
|
||||
'reply_to': fields.char('Reply-To',
|
||||
help='Preferred response address for the message'),
|
||||
# Auto-detected based on create() - if 'mail_message_id' was passed then this mail is a notification
|
||||
# and during unlink() we will not cascade delete the parent and its attachments
|
||||
'notification': fields.boolean('Is Notification')
|
||||
'notification': fields.boolean('Is Notification',
|
||||
help='Mail has been created to notify people of an existing mail.message')
|
||||
}
|
||||
|
||||
def _get_default_from(self, cr, uid, context=None):
|
||||
this = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
this = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
|
||||
if this.alias_domain:
|
||||
return '%s@%s' % (this.alias_name, this.alias_domain)
|
||||
return '%s <%s@%s>' % (this.name, this.alias_name, this.alias_domain)
|
||||
elif this.email:
|
||||
return this.email
|
||||
return '%s <%s>' % (this.name, this.email)
|
||||
raise osv.except_osv(_('Invalid Action!'), _("Unable to send email, please configure the sender's email address or alias."))
|
||||
|
||||
_defaults = {
|
||||
@@ -82,12 +85,41 @@ class mail_mail(osv.Model):
|
||||
# protection for `default_type` values leaking from menu action context (e.g. for invoices)
|
||||
# To remove when automatic context propagation is removed in web client
|
||||
if context and context.get('default_type') and context.get('default_type') not in self._all_columns['type'].column.selection:
|
||||
context = dict(context, default_type = None)
|
||||
context = dict(context, default_type=None)
|
||||
return super(mail_mail, self).default_get(cr, uid, fields, context=context)
|
||||
|
||||
def _get_reply_to(self, cr, uid, values, context=None):
|
||||
""" Return a specific reply_to: alias of the document through message_get_reply_to
|
||||
or take the email_from
|
||||
"""
|
||||
if values.get('reply_to'):
|
||||
return values.get('reply_to')
|
||||
email_reply_to = False
|
||||
|
||||
# if model and res_id: try to use ``message_get_reply_to`` that returns the document alias
|
||||
if values.get('model') and values.get('res_id') and hasattr(self.pool.get(values.get('model')), 'message_get_reply_to'):
|
||||
email_reply_to = self.pool.get(values.get('model')).message_get_reply_to(cr, uid, [values.get('res_id')], context=context)[0]
|
||||
# no alias reply_to -> reply_to will be the email_from, only the email part
|
||||
if not email_reply_to and values.get('email_from'):
|
||||
emails = tools.email_split(values.get('email_from'))
|
||||
if emails:
|
||||
email_reply_to = emails[0]
|
||||
|
||||
# format 'Document name <email_address>'
|
||||
if email_reply_to and values.get('model') and values.get('res_id'):
|
||||
document_name = self.pool.get(values.get('model')).name_get(cr, SUPERUSER_ID, [values.get('res_id')], context=context)[0]
|
||||
if document_name:
|
||||
email_reply_to = _('Followers of %s <%s>') % (document_name[1], email_reply_to)
|
||||
|
||||
return email_reply_to
|
||||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
# notification field: if not set, set if mail comes from an existing mail.message
|
||||
if 'notification' not in values and values.get('mail_message_id'):
|
||||
values['notification'] = True
|
||||
# reply_to: if not set, set with default values that require creation values
|
||||
if not values.get('reply_to'):
|
||||
values['reply_to'] = self._get_reply_to(cr, uid, values, context=context)
|
||||
return super(mail_mail, self).create(cr, uid, values, context=context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
@@ -160,15 +192,12 @@ class mail_mail(osv.Model):
|
||||
return 'Re: %s' % (mail.record_name)
|
||||
return mail.subject
|
||||
|
||||
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
|
||||
""" Return a specific ir_email body. The main purpose of this method
|
||||
is to be inherited by Portal, to add a link for signing in, in
|
||||
def send_get_mail_body_footer(self, cr, uid, mail, partner=None, context=None):
|
||||
""" Return a specific footer for the ir_email body. The main purpose of this method
|
||||
is to be inherited by Portal, to add modify the link for signing in, in
|
||||
each notification email a partner receives.
|
||||
|
||||
:param browse_record mail: mail.mail browse_record
|
||||
:param browse_record partner: specific recipient partner
|
||||
"""
|
||||
body = mail.body_html
|
||||
body_footer = ""
|
||||
# partner is a user, link to a related document (incentive to install portal)
|
||||
if partner and partner.user_ids and mail.model and mail.res_id \
|
||||
and self.check_access_rights(cr, partner.user_ids[0].id, 'read', raise_exception=False):
|
||||
@@ -184,38 +213,24 @@ class mail_mail(osv.Model):
|
||||
'id': mail.res_id,
|
||||
}
|
||||
url = urljoin(base_url, "?%s#%s" % (urlencode(query), urlencode(fragment)))
|
||||
text = _("""<p>Access this document <a href="%s">directly in OpenERP</a></p>""") % url
|
||||
body = tools.append_content_to_html(body, ("<div><p>%s</p></div>" % text), plaintext=False)
|
||||
body_footer = _("""<small>Access this document <a style='color:inherit' href="%s">directly in OpenERP</a></small>""") % url
|
||||
except except_orm, e:
|
||||
pass
|
||||
return body
|
||||
return body_footer
|
||||
|
||||
def send_get_mail_reply_to(self, cr, uid, mail, partner=None, context=None):
|
||||
""" Return a specific ir_email reply_to.
|
||||
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
|
||||
""" Return a specific ir_email body. The main purpose of this method
|
||||
is to be inherited to add custom content depending on some module.
|
||||
|
||||
:param browse_record mail: mail.mail browse_record
|
||||
:param browse_record partner: specific recipient partner
|
||||
"""
|
||||
if mail.reply_to:
|
||||
return mail.reply_to
|
||||
email_reply_to = False
|
||||
body = mail.body_html
|
||||
|
||||
# if model and res_id: try to use ``message_get_reply_to`` that returns the document alias
|
||||
if mail.model and mail.res_id and hasattr(self.pool.get(mail.model), 'message_get_reply_to'):
|
||||
email_reply_to = self.pool.get(mail.model).message_get_reply_to(cr, uid, [mail.res_id], context=context)[0]
|
||||
# no alias reply_to -> reply_to will be the email_from, only the email part
|
||||
if not email_reply_to and mail.email_from:
|
||||
emails = tools.email_split(mail.email_from)
|
||||
if emails:
|
||||
email_reply_to = emails[0]
|
||||
|
||||
# format 'Document name <email_address>'
|
||||
if email_reply_to and mail.model and mail.res_id:
|
||||
document_name = self.pool.get(mail.model).name_get(cr, SUPERUSER_ID, [mail.res_id], context=context)[0]
|
||||
if document_name:
|
||||
email_reply_to = _('Followers of %s <%s>') % (document_name[1], email_reply_to)
|
||||
|
||||
return email_reply_to
|
||||
# add footer
|
||||
body_footer = self.send_get_mail_body_footer(cr, uid, mail, partner=partner, context=context)
|
||||
body = tools.append_content_to_html(body, body_footer, plaintext=False, container_tag='div')
|
||||
return body
|
||||
|
||||
def send_get_email_dict(self, cr, uid, mail, partner=None, context=None):
|
||||
""" Return a dictionary for specific email values, depending on a
|
||||
@@ -226,7 +241,6 @@ class mail_mail(osv.Model):
|
||||
"""
|
||||
body = self.send_get_mail_body(cr, uid, mail, partner=partner, context=context)
|
||||
subject = self.send_get_mail_subject(cr, uid, mail, partner=partner, context=context)
|
||||
reply_to = self.send_get_mail_reply_to(cr, uid, mail, partner=partner, context=context)
|
||||
body_alternative = tools.html2plaintext(body)
|
||||
email_to = [partner.email] if partner else tools.email_split(mail.email_to)
|
||||
return {
|
||||
@@ -234,10 +248,9 @@ class mail_mail(osv.Model):
|
||||
'body_alternative': body_alternative,
|
||||
'subject': subject,
|
||||
'email_to': email_to,
|
||||
'reply_to': reply_to,
|
||||
}
|
||||
|
||||
def send(self, cr, uid, ids, auto_commit=False, recipient_ids=None, context=None):
|
||||
def send(self, cr, uid, ids, auto_commit=False, context=None):
|
||||
""" Sends the selected emails immediately, ignoring their current
|
||||
state (mails that have already been sent should not be passed
|
||||
unless they should actually be re-sent).
|
||||
@@ -248,14 +261,10 @@ class mail_mail(osv.Model):
|
||||
:param bool auto_commit: whether to force a commit of the mail status
|
||||
after sending each mail (meant only for scheduler processing);
|
||||
should never be True during normal transactions (default: False)
|
||||
:param list recipient_ids: specific list of res.partner recipients.
|
||||
If set, one email is sent to each partner. Its is possible to
|
||||
tune the sent email through ``send_get_mail_body`` and ``send_get_mail_subject``.
|
||||
If not specified, one email is sent to mail_mail.email_to.
|
||||
:return: True
|
||||
"""
|
||||
ir_mail_server = self.pool.get('ir.mail_server')
|
||||
for mail in self.browse(cr, uid, ids, context=context):
|
||||
for mail in self.browse(cr, SUPERUSER_ID, ids, context=context):
|
||||
try:
|
||||
# handle attachments
|
||||
attachments = []
|
||||
@@ -263,11 +272,10 @@ class mail_mail(osv.Model):
|
||||
attachments.append((attach.datas_fname, base64.b64decode(attach.datas)))
|
||||
# specific behavior to customize the send email for notified partners
|
||||
email_list = []
|
||||
if recipient_ids:
|
||||
for partner in self.pool.get('res.partner').browse(cr, SUPERUSER_ID, recipient_ids, context=context):
|
||||
email_list.append(self.send_get_email_dict(cr, uid, mail, partner=partner, context=context))
|
||||
else:
|
||||
if mail.email_to:
|
||||
email_list.append(self.send_get_email_dict(cr, uid, mail, context=context))
|
||||
for partner in mail.recipient_ids:
|
||||
email_list.append(self.send_get_email_dict(cr, uid, mail, partner=partner, context=context))
|
||||
|
||||
# build an RFC2822 email.message.Message object and send it without queuing
|
||||
for email in email_list:
|
||||
@@ -278,7 +286,7 @@ class mail_mail(osv.Model):
|
||||
body = email.get('body'),
|
||||
body_alternative = email.get('body_alternative'),
|
||||
email_cc = tools.email_split(mail.email_cc),
|
||||
reply_to = email.get('reply_to'),
|
||||
reply_to = mail.reply_to,
|
||||
attachments = attachments,
|
||||
message_id = mail.message_id,
|
||||
references = mail.references,
|
||||
|
||||
@@ -14,31 +14,23 @@
|
||||
<button name="%(action_email_compose_message_wizard)d" string="Reply" type="action" icon="terp-mail-replied"
|
||||
context="{'default_composition_mode':'reply', 'default_parent_id': active_id}" states='received,sent,exception,cancel'/>
|
||||
</div>
|
||||
<notebook colspan="4">
|
||||
<page string="Message Details">
|
||||
<group>
|
||||
<group>
|
||||
<field name="email_from"/>
|
||||
<field name="email_to"/>
|
||||
<field name="email_cc"/>
|
||||
<field name="reply_to"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="partner_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Body">
|
||||
<field name="body_html"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<group>
|
||||
<field name="email_from"/>
|
||||
<field name="email_to"/>
|
||||
<field name="recipient_ids" widget="many2many_tags"/>
|
||||
<field name="email_cc"/>
|
||||
<field name="reply_to"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Body">
|
||||
<field name="body_html"/>
|
||||
</page>
|
||||
<page string="Advanced" groups="base.group_no_one">
|
||||
<group>
|
||||
<group>
|
||||
<field name="auto_delete"/>
|
||||
<field name="type"/>
|
||||
<field name="state" colspan="2"/>
|
||||
<field name="state"/>
|
||||
<field name="mail_server_id"/>
|
||||
<field name="model"/>
|
||||
<field name="res_id"/>
|
||||
@@ -46,6 +38,8 @@
|
||||
<group>
|
||||
<field name="message_id"/>
|
||||
<field name="references"/>
|
||||
<field name="partner_ids" widget="many2many_tags"/>
|
||||
<field name="notified_partner_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
@@ -67,7 +61,7 @@
|
||||
<field name="subject"/>
|
||||
<field name="author_id" string="User"/>
|
||||
<field name="message_id" invisible="1"/>
|
||||
<field name="partner_ids" invisible="1"/>
|
||||
<field name="recipient_ids" invisible="1"/>
|
||||
<field name="model" invisible="1"/>
|
||||
<field name="res_id" invisible="1"/>
|
||||
<field name="email_from" invisible="1"/>
|
||||
@@ -97,7 +91,7 @@
|
||||
<filter icon="terp-camera_test" name="type_notification" string="Notification" domain="[('type','=','notification')]"/>
|
||||
<group expand="0" string="Extended Filters...">
|
||||
<field name="author_id"/>
|
||||
<field name="partner_ids"/>
|
||||
<field name="recipient_ids"/>
|
||||
<field name="model"/>
|
||||
<field name="res_id"/>
|
||||
</group>
|
||||
|
||||
@@ -139,6 +139,8 @@ class mail_message(osv.Model):
|
||||
"message, comment for other messages such as user replies"),
|
||||
'email_from': fields.char('From',
|
||||
help="Email address of the sender. This field is set when no matching partner is found for incoming emails."),
|
||||
'reply_to': fields.char('Reply-To',
|
||||
help='Reply email address. Setting the reply_to bypasses the automatic thread creation.'),
|
||||
'author_id': fields.many2one('res.partner', 'Author', select=1,
|
||||
ondelete='set null',
|
||||
help="Author of the message. If not set, email_from may hold an email address that did not match any partner."),
|
||||
@@ -185,8 +187,9 @@ class mail_message(osv.Model):
|
||||
_defaults = {
|
||||
'type': 'email',
|
||||
'date': lambda *a: fields.datetime.now(),
|
||||
'author_id': lambda self, cr, uid, ctx={}: self._get_default_author(cr, uid, ctx),
|
||||
'author_id': lambda self, cr, uid, ctx=None: self._get_default_author(cr, uid, ctx),
|
||||
'body': '',
|
||||
'email_from': lambda self, cr, uid, ctx=None: self.pool.get('mail.mail')._get_default_from(cr, uid, ctx),
|
||||
}
|
||||
|
||||
#------------------------------------------------------
|
||||
@@ -731,7 +734,10 @@ class mail_message(osv.Model):
|
||||
if context is None:
|
||||
context = {}
|
||||
default_starred = context.pop('default_starred', False)
|
||||
if not values.get('message_id') and values.get('res_id') and values.get('model'):
|
||||
# generate message_id, to redirect answers to the right discussion thread
|
||||
if not values.get('message_id') and values.get('reply_to'):
|
||||
values['message_id'] = tools.generate_tracking_message_id('reply_to-%(model)s' % values)
|
||||
elif not values.get('message_id') and values.get('res_id') and values.get('model'):
|
||||
values['message_id'] = tools.generate_tracking_message_id('%(res_id)s-%(model)s' % values)
|
||||
elif not values.get('message_id'):
|
||||
values['message_id'] = tools.generate_tracking_message_id('private')
|
||||
|
||||
@@ -468,6 +468,7 @@ class mail_thread(osv.AbstractModel):
|
||||
# 1. Verify if this is a reply to an existing thread
|
||||
thread_references = references or in_reply_to
|
||||
ref_match = thread_references and tools.reference_re.search(thread_references)
|
||||
|
||||
if ref_match:
|
||||
thread_id = int(ref_match.group(1))
|
||||
model = ref_match.group(2) or model
|
||||
@@ -480,7 +481,10 @@ class mail_thread(osv.AbstractModel):
|
||||
|
||||
# Verify whether this is a reply to a private message
|
||||
if in_reply_to:
|
||||
message_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', in_reply_to)], limit=1, context=context)
|
||||
message_ids = self.pool.get('mail.message').search(cr, uid, [
|
||||
('message_id', '=', in_reply_to),
|
||||
'!', ('message_id', 'ilike', 'reply_to')
|
||||
], limit=1, context=context)
|
||||
if message_ids:
|
||||
message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
|
||||
_logger.debug('Routing mail with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
|
||||
@@ -1026,7 +1030,7 @@ class mail_thread(osv.AbstractModel):
|
||||
# Create and auto subscribe the author
|
||||
msg_id = mail_message.create(cr, uid, values, context=context)
|
||||
message = mail_message.browse(cr, uid, msg_id, context=context)
|
||||
if message.author_id and thread_id and type != 'notification':
|
||||
if message.author_id and thread_id and type != 'notification' and not context.get('mail_create_nosubscribe'):
|
||||
self.message_subscribe(cr, uid, [thread_id], [message.author_id.id], context=context)
|
||||
return msg_id
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name="email" position="before">
|
||||
<field name="signature" position="before">
|
||||
<field name="notification_email_send"/>
|
||||
</field>
|
||||
<field name="email" position="after">
|
||||
|
||||
@@ -561,6 +561,14 @@
|
||||
text-align: center;
|
||||
width:100%;
|
||||
}
|
||||
.openerp .oe_followers button.oe_invite{
|
||||
margin: 5px 0;
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
text-shadow: none;
|
||||
width: 100%;
|
||||
}
|
||||
.openerp .oe_followers button.oe_invite,
|
||||
.openerp .oe_followers button.oe_follower.oe_following{
|
||||
color: white;
|
||||
background-color: #3465A4;
|
||||
@@ -614,9 +622,6 @@
|
||||
margin-top: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.openerp .oe_followers .oe_invite{
|
||||
float: right;
|
||||
}
|
||||
.openerp .oe_followers .oe_partner {
|
||||
height: 32px;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -220,23 +220,16 @@ openerp_mail_followers = function(session, mail) {
|
||||
/** Display subtypes: {'name': default, followed} */
|
||||
display_subtypes:function (data, id) {
|
||||
var self = this;
|
||||
var subtype_list_ul = this.$('.oe_subtype_list');
|
||||
var records = [];
|
||||
var nb_subtype = 0;
|
||||
subtype_list_ul.empty();
|
||||
if (data[id]) {
|
||||
records = data[id].message_subtype_data;
|
||||
}
|
||||
_(records).each(function (record) {nb_subtype++;});
|
||||
if (nb_subtype > 1) {
|
||||
this.$('hr').show();
|
||||
_(records).each(function (record, record_name) {
|
||||
record.name = record_name;
|
||||
record.followed = record.followed || undefined;
|
||||
$(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') );
|
||||
});
|
||||
} else {
|
||||
this.$('hr').hide();
|
||||
var $list = this.$('.oe_subtype_list');
|
||||
$list.empty().hide();
|
||||
var records = data[this.view.datarecord.id || this.view.dataset.ids[0]].message_subtype_data;
|
||||
_(records).each(function (record, record_name) {
|
||||
record.name = record_name;
|
||||
record.followed = record.followed || undefined;
|
||||
$(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('.oe_subtype_list') );
|
||||
});
|
||||
if (_.size(records) > 1) {
|
||||
$list.show();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
</t>
|
||||
<div class="oe_subtype_list"></div>
|
||||
</div>
|
||||
<hr size="2"></hr>
|
||||
<div class='oe_follower_title_box'>
|
||||
<h4 class='oe_follower_title'>Followers</h4>
|
||||
<a t-if="widget.view_is_editable" href='#' class="oe_invite">Add others</a>
|
||||
<button t-if="widget.view_is_editable" href='#' class="oe_invite">Invite people</button>
|
||||
</div>
|
||||
<div class="oe_follower_list"></div>
|
||||
</div>
|
||||
|
||||
@@ -31,18 +31,18 @@ class test_invite(TestMailBase):
|
||||
# Do: create a mail_wizard_invite, validate it
|
||||
self._init_mock_build_email()
|
||||
context = {'default_res_model': 'mail.group', 'default_res_id': self.group_pigs_id}
|
||||
mail_invite_id = mail_invite.create(cr, self.user_raoul_id, {'partner_ids': [(4, self.partner_bert_id)]}, context)
|
||||
mail_invite_id = mail_invite.create(cr, self.user_raoul_id, {'partner_ids': [(4, self.partner_bert_id)], 'send_mail': True}, context)
|
||||
mail_invite.add_followers(cr, self.user_raoul_id, [mail_invite_id], {'default_model': 'mail.group', 'default_res_id': 0})
|
||||
|
||||
# Test: Pigs followers should contain Admin, Bert
|
||||
self.group_pigs.refresh()
|
||||
follower_ids = [follower.id for follower in self.group_pigs.message_follower_ids]
|
||||
self.assertEqual(set(follower_ids), set([self.partner_admin_id, self.partner_bert_id]), 'Pigs followers after invite is incorrect')
|
||||
self.assertEqual(set(follower_ids), set([self.partner_admin_id, self.partner_bert_id]), 'invite: Pigs followers after invite is incorrect')
|
||||
|
||||
# Test: (pretend to) send email and check subject, body
|
||||
self.assertEqual(len(self._build_email_kwargs_list), 1, 'sent email number incorrect, should be only for Bert')
|
||||
for sent_email in self._build_email_kwargs_list:
|
||||
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Pigs',
|
||||
'subject of invitation email is incorrect')
|
||||
self.assertTrue('You have been invited to follow Pigs' in sent_email.get('body'),
|
||||
'body of invitation email is incorrect')
|
||||
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs',
|
||||
'invite: subject of invitation email is incorrect')
|
||||
self.assertIn('Raoul Grosbedon invited you to follow Discussion group document: Pigs', sent_email.get('body'),
|
||||
'invite: body of invitation email is incorrect')
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.mail.tests.test_mail_base import TestMailBase
|
||||
from openerp.tools.mail import html_sanitize, append_content_to_html
|
||||
from openerp.tools.mail import html_sanitize
|
||||
|
||||
MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
|
||||
To: {to}
|
||||
@@ -84,23 +84,6 @@ Sylvie
|
||||
|
||||
class test_mail(TestMailBase):
|
||||
|
||||
def _mock_send_get_mail_body(self, *args, **kwargs):
|
||||
# def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None)
|
||||
body = append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner', plaintext=False)
|
||||
return body
|
||||
|
||||
def setUp(self):
|
||||
super(test_mail, self).setUp()
|
||||
|
||||
# Mock send_get_mail_body to test its functionality without other addons override
|
||||
self._send_get_mail_body = self.registry('mail.mail').send_get_mail_body
|
||||
self.registry('mail.mail').send_get_mail_body = self._mock_send_get_mail_body
|
||||
|
||||
def tearDown(self):
|
||||
# Remove mocks
|
||||
self.registry('mail.mail').send_get_mail_body = self._send_get_mail_body
|
||||
super(test_mail, self).tearDown()
|
||||
|
||||
def test_00_message_process(self):
|
||||
""" Testing incoming emails processing. """
|
||||
cr, uid, user_raoul = self.cr, self.uid, self.user_raoul
|
||||
@@ -329,7 +312,7 @@ class test_mail(TestMailBase):
|
||||
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
|
||||
# 1 - Bert Tartopoils, with email, should receive emails for comments and emails
|
||||
p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
|
||||
# 2 - Carine Poilvache, with email, should never receive emails
|
||||
# 2 - Carine Poilvache, with email, should receive emails for emails
|
||||
p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notification_email_send': 'email'})
|
||||
# 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message
|
||||
p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'notification_email_send': 'all'})
|
||||
@@ -341,11 +324,15 @@ class test_mail(TestMailBase):
|
||||
_subject = 'Pigs'
|
||||
_mail_subject = 'Re: %s' % (group_pigs.name)
|
||||
_body1 = '<p>Pigs rules</p>'
|
||||
_mail_body1 = '<p>Pigs rules</p>\n<div><p>Raoul</p></div>\n'
|
||||
_mail_bodyalt1 = 'Pigs rules\nRaoul\n'
|
||||
_mail_body1 = '<p>Pigs rules</p>'
|
||||
_mail_signature1 = '<p>Raoul</p>'
|
||||
_mail_bodyalt1 = 'Pigs rules\n'
|
||||
_mail_signaturealt1 = '\nRaoul\n'
|
||||
_body2 = '<html>Pigs rules</html>'
|
||||
_mail_body2 = '<div><p>Pigs rules</p></div>\n<div><p>Raoul</p></div>'
|
||||
_mail_bodyalt2 = 'Pigs rules\nRaoul'
|
||||
_mail_body2 = '<div><p>Pigs rules</p></div>'
|
||||
_mail_signature2 = '<p>Raoul</p>'
|
||||
_mail_bodyalt2 = 'Pigs rules\n'
|
||||
_mail_signaturealt2 = '\nRaoul\n'
|
||||
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
|
||||
|
||||
# ----------------------------------------
|
||||
@@ -366,12 +353,14 @@ class test_mail(TestMailBase):
|
||||
self.assertEqual(len(sent_emails), 2, 'sent_email number of sent emails incorrect')
|
||||
for sent_email in sent_emails:
|
||||
self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
|
||||
self.assertTrue(sent_email['body'] in [_mail_body1 + '\nBert Tartopoils\n', _mail_body1 + '\nAdministrator\n'],
|
||||
'sent_email body incorrect')
|
||||
self.assertIn(_mail_body1, sent_email['body'], 'sent_email body incorrect')
|
||||
self.assertIn(_mail_signature1, sent_email['body'], 'sent_email body incorrect (no signature)')
|
||||
self.assertIn("OpenERP", sent_email['body'], 'sent_email body incorrect (no OpenERP company)')
|
||||
# the html2plaintext uses etree or beautiful soup, so the result may be slighly different
|
||||
# depending if you have installed beautiful soup.
|
||||
self.assertTrue(sent_email['body_alternative'] in [_mail_bodyalt1 + '\nBert Tartopoils\n', _mail_bodyalt1 + '\nAdministrator\n'],
|
||||
'sent_email body_alternative is incorrect')
|
||||
self.assertIn(_mail_bodyalt1, sent_email['body_alternative'], 'sent_email body_alternative is incorrect')
|
||||
self.assertIn(_mail_signaturealt1, sent_email['body_alternative'], 'sent_email body_alternative is incorrect (no signature)')
|
||||
self.assertIn("OpenERP", sent_email['body_alternative'], 'sent_email body incorrect (no OpenERP company)')
|
||||
# Test: mail_message: notified_partner_ids = group followers
|
||||
message_pids = set([partner.id for partner in message1.notified_partner_ids])
|
||||
test_pids = set([self.partner_admin_id, p_b_id, p_c_id])
|
||||
@@ -405,7 +394,12 @@ class test_mail(TestMailBase):
|
||||
for sent_email in sent_emails:
|
||||
self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect')
|
||||
self.assertIn(_mail_body2, sent_email['body'], 'sent_email body incorrect')
|
||||
self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect')
|
||||
self.assertIn(_mail_signature2, sent_email['body'], 'sent_email body incorrect (no signature)')
|
||||
self.assertIn("OpenERP", sent_email['body'], 'sent_email body incorrect (no OpenERP company)')
|
||||
# body_alternative
|
||||
self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative is incorrect')
|
||||
self.assertIn(_mail_signaturealt2, sent_email['body_alternative'], 'sent_email body_alternative is incorrect (no signature)')
|
||||
self.assertIn("OpenERP", sent_email['body'], 'sent_email body incorrect (no OpenERP company)')
|
||||
# Test: mail_message: notified_partner_ids = group followers
|
||||
message_pids = set([partner.id for partner in message2.notified_partner_ids])
|
||||
test_pids = set([self.partner_admin_id, p_b_id, p_c_id, p_d_id])
|
||||
@@ -462,7 +456,7 @@ class test_mail(TestMailBase):
|
||||
# 2 - Carine Poilvache, with email, should never receive emails
|
||||
p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notification_email_send': 'email'})
|
||||
# 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message
|
||||
p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'notification_email_send': 'all'})
|
||||
p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'email': 'd@d', 'notification_email_send': 'all'})
|
||||
|
||||
# Subscribe #1
|
||||
group_pigs.message_subscribe([p_b_id])
|
||||
@@ -525,7 +519,7 @@ class test_mail(TestMailBase):
|
||||
# 1. mass_mail on pigs and bird
|
||||
compose_id = mail_compose.create(cr, uid,
|
||||
{'subject': _subject, 'body': '${object.description}'},
|
||||
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': False,
|
||||
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': False, 'default_notify': True,
|
||||
'active_ids': [self.group_pigs_id, group_bird_id]})
|
||||
compose = mail_compose.browse(cr, uid, compose_id)
|
||||
|
||||
|
||||
@@ -32,12 +32,19 @@ class invite_wizard(osv.osv_memory):
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
result = super(invite_wizard, self).default_get(cr, uid, fields, context=context)
|
||||
if 'message' in fields and result.get('res_model') and result.get('res_id'):
|
||||
document_name = self.pool.get(result.get('res_model')).name_get(cr, uid, [result.get('res_id')], context=context)[0][1]
|
||||
message = _('<div>You have been invited to follow %s.</div>' % document_name)
|
||||
user_name = self.pool.get('res.users').name_get(cr, uid, [uid], context=context)[0][1]
|
||||
model = result.get('res_model')
|
||||
res_id = result.get('res_id')
|
||||
if 'message' in fields and model and res_id:
|
||||
ir_model = self.pool.get('ir.model')
|
||||
model_ids = ir_model.search(cr, uid, [('model', '=', self.pool.get(model)._name)], context=context)
|
||||
model_name = ir_model.name_get(cr, uid, model_ids, context=context)[0][1]
|
||||
|
||||
document_name = self.pool.get(model).name_get(cr, uid, [res_id], context=context)[0][1]
|
||||
message = _('<div><p>Hello,</p><p>%s invited you to follow %s document: %s.<p></div>') % (user_name, model_name, document_name)
|
||||
result['message'] = message
|
||||
elif 'message' in fields:
|
||||
result['message'] = _('<div>You have been invited to follow a new document.</div>')
|
||||
result['message'] = _('<div><p>Hello,</p><p>%s invited you to follow a new document.</p></div>') % user_name
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
@@ -46,8 +53,12 @@ class invite_wizard(osv.osv_memory):
|
||||
help='Model of the followed resource'),
|
||||
'res_id': fields.integer('Related Document ID', select=1,
|
||||
help='Id of the followed resource'),
|
||||
'partner_ids': fields.many2many('res.partner', string='Partners'),
|
||||
'partner_ids': fields.many2many('res.partner', string='Recipients',
|
||||
help="List of partners that will be added as follower of the current document."),
|
||||
'message': fields.html('Message'),
|
||||
'send_mail': fields.boolean('Send Email',
|
||||
help="If checked, the partners will receive an email warning they have been "
|
||||
"added in the document's followers."),
|
||||
}
|
||||
|
||||
def add_followers(self, cr, uid, ids, context=None):
|
||||
@@ -59,23 +70,27 @@ class invite_wizard(osv.osv_memory):
|
||||
new_follower_ids = [p.id for p in wizard.partner_ids if p not in document.message_follower_ids]
|
||||
model_obj.message_subscribe(cr, uid, [wizard.res_id], new_follower_ids, context=context)
|
||||
|
||||
# send an email
|
||||
if wizard.message:
|
||||
ir_model = self.pool.get('ir.model')
|
||||
model_ids = ir_model.search(cr, uid, [('model', '=', model_obj._name)], context=context)
|
||||
model_name = ir_model.name_get(cr, uid, model_ids, context=context)[0][1]
|
||||
|
||||
# send an email if option checked and if a message exists (do not send void emails)
|
||||
if wizard.send_mail and wizard.message:
|
||||
# add signature
|
||||
user_id = self.pool.get("res.users").read(cr, uid, [uid], fields=["signature"], context=context)[0]
|
||||
signature = user_id and user_id["signature"] or ''
|
||||
if signature:
|
||||
wizard.message = tools.append_content_to_html(wizard.message, signature, plaintext=True, container_tag='div')
|
||||
# FIXME 8.0: use notification_email_send, send a wall message and let mail handle email notification + message box
|
||||
for follower_id in new_follower_ids:
|
||||
mail_mail = self.pool.get('mail.mail')
|
||||
# the invite wizard should create a private message not related to any object -> no model, no res_id
|
||||
mail_id = mail_mail.create(cr, uid, {
|
||||
'model': wizard.res_model,
|
||||
'res_id': wizard.res_id,
|
||||
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
|
||||
'body_html': '%s' % wizard.message,
|
||||
'auto_delete': True,
|
||||
}, context=context)
|
||||
mail_mail.send(cr, uid, [mail_id], recipient_ids=[follower_id], context=context)
|
||||
signature_company = self.pool.get('mail.notification').get_signature_footer(cr, uid, user_id=uid, res_model=wizard.res_model, res_id=wizard.res_id, context=context)
|
||||
wizard.message = tools.append_content_to_html(wizard.message, signature_company, plaintext=False, container_tag='div')
|
||||
|
||||
# send mail to new followers
|
||||
# the invite wizard should create a private message not related to any object -> no model, no res_id
|
||||
mail_mail = self.pool.get('mail.mail')
|
||||
mail_id = mail_mail.create(cr, uid, {
|
||||
'model': wizard.res_model,
|
||||
'res_id': wizard.res_id,
|
||||
'subject': _('Invitation to follow %s: %s') % (model_name, document.name_get()[0][1]),
|
||||
'body_html': '%s' % wizard.message,
|
||||
'auto_delete': True,
|
||||
'recipient_ids': [(4, id) for id in new_follower_ids]
|
||||
}, context=context)
|
||||
mail_mail.send(cr, uid, [mail_id], context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
<field name="partner_ids" widget="many2many_tags_email"
|
||||
placeholder="Add contacts to notify..."
|
||||
context="{'force_email':True, 'show_email':True}"/>
|
||||
<field name="message"/>
|
||||
<field name="send_mail"/>
|
||||
<field name="message" attrs="{'invisible': [('send_mail','!=',True)]}"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Add Followers"
|
||||
|
||||
@@ -113,6 +113,12 @@ class mail_compose_message(osv.TransientModel):
|
||||
'partner_ids': fields.many2many('res.partner',
|
||||
'mail_compose_message_res_partner_rel',
|
||||
'wizard_id', 'partner_id', 'Additional contacts'),
|
||||
'post': fields.boolean('Post a copy in the document',
|
||||
help='Post a copy of the message on the document communication history.'),
|
||||
'notify': fields.boolean('Notify followers',
|
||||
help='Notify followers of the document'),
|
||||
'same_thread': fields.boolean('Replies in the document',
|
||||
help='Replies to the messages will go into the selected document.'),
|
||||
'attachment_ids': fields.many2many('ir.attachment',
|
||||
'mail_compose_message_ir_attachments_rel',
|
||||
'wizard_id', 'attachment_id', 'Attachments'),
|
||||
@@ -121,9 +127,13 @@ class mail_compose_message(osv.TransientModel):
|
||||
|
||||
_defaults = {
|
||||
'composition_mode': 'comment',
|
||||
'email_from': lambda self, cr, uid, ctx={}: self.pool.get('mail.mail')._get_default_from(cr, uid, context=ctx),
|
||||
'body': lambda self, cr, uid, ctx={}: '',
|
||||
'subject': lambda self, cr, uid, ctx={}: False,
|
||||
'partner_ids': lambda self, cr, uid, ctx={}: [],
|
||||
'notify': lambda self, cr, uid, ctx={}: False,
|
||||
'post': lambda self, cr, uid, ctx={}: True,
|
||||
'same_thread': lambda self, cr, uid, ctx={}: True,
|
||||
}
|
||||
|
||||
def _notify(self, cr, uid, newid, context=None):
|
||||
@@ -195,6 +205,8 @@ class mail_compose_message(osv.TransientModel):
|
||||
|
||||
for wizard in self.browse(cr, uid, ids, context=context):
|
||||
mass_mail_mode = wizard.composition_mode == 'mass_mail'
|
||||
if mass_mail_mode: # mass mail: avoid any auto subscription because this could lead to people being follower of plenty of documents
|
||||
context['mail_create_nosubscribe'] = True
|
||||
active_model_pool = self.pool.get(wizard.model if wizard.model else 'mail.thread')
|
||||
|
||||
# wizard works in batch mode: [res_id] or active_ids
|
||||
@@ -216,11 +228,28 @@ class mail_compose_message(osv.TransientModel):
|
||||
new_attachments = email_dict.pop('attachments', [])
|
||||
post_values['attachments'] += new_attachments
|
||||
post_values.update(email_dict)
|
||||
# email_from: mass mailing only can specify another email_from
|
||||
if email_dict.get('email_from'):
|
||||
post_values['email_from'] = email_dict.pop('email_from')
|
||||
# replies redirection: mass mailing only
|
||||
if not wizard.same_thread:
|
||||
post_values['reply_to'] = email_dict.pop('reply_to')
|
||||
# clean the context (hint: mass mailing sets some default values that
|
||||
# could be wrongly interpreted by mail_mail)
|
||||
context.pop('default_email_to', None)
|
||||
context.pop('default_partner_ids', None)
|
||||
# post the message
|
||||
subtype = 'mail.mt_comment'
|
||||
if is_log:
|
||||
subtype = False
|
||||
active_model_pool.message_post(cr, uid, [res_id], type='comment', subtype=subtype, context=context, **post_values)
|
||||
if mass_mail_mode and not wizard.post:
|
||||
post_values['recipient_ids'] = [(4, id) for id in post_values.pop('partner_ids', [])]
|
||||
self.pool.get('mail.mail').create(cr, uid, post_values, context=context)
|
||||
else:
|
||||
subtype = 'mail.mt_comment'
|
||||
if is_log or (mass_mail_mode and not wizard.notify):
|
||||
subtype = False
|
||||
msg_id = active_model_pool.message_post(cr, uid, [res_id], type='comment', subtype=subtype, context=context, **post_values)
|
||||
# mass_mailing, post without notify: notify specific partners
|
||||
if mass_mail_mode and not wizard.notify and post_values['partner_ids']:
|
||||
self.pool.get('mail.notification')._notify(cr, uid, msg_id, post_values['partner_ids'], context=context)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -231,6 +260,8 @@ class mail_compose_message(osv.TransientModel):
|
||||
return {
|
||||
'subject': self.render_template(cr, uid, wizard.subject, wizard.model, res_id, context),
|
||||
'body': self.render_template(cr, uid, wizard.body, wizard.model, res_id, context),
|
||||
'email_from': self.render_template(cr, uid, wizard.email_from, wizard.model, res_id, context),
|
||||
'reply_to': self.render_template(cr, uid, wizard.reply_to, wizard.model, res_id, context),
|
||||
}
|
||||
|
||||
def render_template(self, cr, uid, template, model, res_id, context=None):
|
||||
|
||||
@@ -13,25 +13,33 @@
|
||||
<field name="res_id" invisible="1"/>
|
||||
<field name="parent_id" invisible="1"/>
|
||||
<!-- visible wizard -->
|
||||
<field name="email_from"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<field name="subject" placeholder="Subject..." required="True"/>
|
||||
<field name="post"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<field name="notify"
|
||||
attrs="{'invisible':['|', ('post', '!=', True), ('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<field name="same_thread"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<field name="reply_to" placeholder="Email address te redirect replies..."
|
||||
attrs="{'invisible':['|', ('same_thread', '=', True), ('composition_mode', '!=', 'mass_mail')],
|
||||
'required':[('same_thread', '!=', True)]}"/>
|
||||
<label for="partner_ids" string="Recipients"
|
||||
invisible="context.get('mail_compose_log', False)"/>
|
||||
<div groups="base.group_user" invisible="context.get('mail_compose_log', False)">
|
||||
<span attrs="{'invisible':['|', ('model', '=', False), ('composition_mode', '!=', 'mass_mail')]}">
|
||||
Followers of selected items and
|
||||
</span>
|
||||
<span attrs="{'invisible':['|', ('model', '=', False), ('composition_mode', '=', 'mass_mail')]}">
|
||||
attrs="{'invisible':[('composition_mode', '=', 'mass_mail')]}"/>
|
||||
<div groups="base.group_user"
|
||||
attrs="{'invisible':[('composition_mode', '=', 'mass_mail')]}">
|
||||
<span attrs="{'invisible':[('model', '=', False)]}">
|
||||
Followers of
|
||||
<field name="record_name" readonly="1" class="oe_inline"
|
||||
attrs="{'invisible':[('model', '=', False)]}"/>
|
||||
and
|
||||
<field name="record_name" readonly="1" class="oe_inline"/>
|
||||
and
|
||||
</span>
|
||||
<field name="partner_ids" widget="many2many_tags_email" placeholder="Add contacts to notify..."
|
||||
context="{'force_email':True, 'show_email':True}"/>
|
||||
</div>
|
||||
<field name="subject" placeholder="Subject..."/>
|
||||
</group>
|
||||
<field name="body"/>
|
||||
<field name="attachment_ids" widget="many2many_binary"/>
|
||||
<field name="attachment_ids" widget="many2many_binary" string="Attach a file"/>
|
||||
<footer>
|
||||
<button string="Send" name="send_mail" type="object" class="oe_highlight"/>
|
||||
or
|
||||
@@ -52,7 +60,7 @@
|
||||
</record>
|
||||
|
||||
<!-- Replace the default mass-mailing wizard in base with the composition wizard -->
|
||||
<act_window name="Mass Mailing"
|
||||
<act_window name="Partner Mass Mailing"
|
||||
res_model="mail.compose.message"
|
||||
src_model="res.partner"
|
||||
view_mode="form"
|
||||
@@ -60,6 +68,10 @@
|
||||
target="new"
|
||||
key2="client_action_multi"
|
||||
id="base.action_partner_mass_mail"
|
||||
context="{'default_composition_mode': 'mass_mail'}"/>
|
||||
context="{
|
||||
'default_composition_mode': 'mass_mail',
|
||||
'default_partner_to': '${object.id or \'\'}',
|
||||
}"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import osv
|
||||
from openerp.osv.orm import except_orm
|
||||
from openerp.tools import append_content_to_html
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
@@ -30,18 +29,17 @@ class mail_mail(osv.Model):
|
||||
""" Update of mail_mail class, to add the signin URL to notifications. """
|
||||
_inherit = 'mail.mail'
|
||||
|
||||
def send_get_mail_body(self, cr, uid, mail, partner=None, context=None):
|
||||
def send_get_mail_body_footer(self, cr, uid, mail, partner=None, context=None):
|
||||
""" add a signin link inside the body of a mail.mail
|
||||
:param mail: mail.mail browse_record
|
||||
:param partner: browse_record of the specific recipient partner
|
||||
:return: the resulting body_html
|
||||
"""
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
body = mail.body_html
|
||||
if partner:
|
||||
contex_signup = dict(context or {}, signup_valid=True)
|
||||
partner = partner_obj.browse(cr, SUPERUSER_ID, partner.id, context=contex_signup)
|
||||
text = _("""<p>Access your messages and personal documents through <a href="%s">our Customer Portal</a></p>""") % partner.signup_url
|
||||
body_footer = _("""<small>Access your messages and documents through <a style='color:inherit' href="%s">our Customer Portal</a></small>""") % partner.signup_url
|
||||
# partner is an user: add a link to the document if read access
|
||||
if partner.user_ids and mail.model and mail.res_id \
|
||||
and self.check_access_rights(cr, partner.user_ids[0].id, 'read', raise_exception=False):
|
||||
@@ -49,8 +47,9 @@ class mail_mail(osv.Model):
|
||||
try:
|
||||
self.pool.get(mail.model).check_access_rule(cr, related_user.id, [mail.res_id], 'read', context=context)
|
||||
url = partner_obj._get_signup_url_for_action(cr, related_user.id, [partner.id], action='', res_id=mail.res_id, model=mail.model, context=context)[partner.id]
|
||||
text = _("""<p>Access this document <a href="%s">directly in OpenERP</a></p>""") % url
|
||||
text = _("""<small>Access this document <a style='color:inherit' href="%s">directly in OpenERP</a></small>""") % url
|
||||
except except_orm, e:
|
||||
pass
|
||||
body = append_content_to_html(body, ("<div><p>%s</p></div>" % text), plaintext=False)
|
||||
return body
|
||||
return body_footer
|
||||
else:
|
||||
return super(mail_mail, self).send_get_mail_body_footer(cr, uid, mail, partner=partner, context=context)
|
||||
|
||||
@@ -106,7 +106,7 @@ class test_portal(TestMailBase):
|
||||
# Do: create a mail_wizard_invite, validate it
|
||||
self._init_mock_build_email()
|
||||
context = {'default_res_model': 'mail.group', 'default_res_id': self.group_pigs_id}
|
||||
mail_invite_id = mail_invite.create(cr, uid, {'partner_ids': [(4, partner_carine_id)]}, context)
|
||||
mail_invite_id = mail_invite.create(cr, uid, {'partner_ids': [(4, partner_carine_id)], 'send_mail': True}, context)
|
||||
mail_invite.add_followers(cr, uid, [mail_invite_id])
|
||||
|
||||
# Test: Pigs followers should contain Admin and Bert
|
||||
@@ -124,9 +124,9 @@ class test_portal(TestMailBase):
|
||||
# Test: (pretend to) send email and check subject, body
|
||||
self.assertEqual(len(self._build_email_kwargs_list), 1, 'sent email number incorrect, should be only for Bert')
|
||||
for sent_email in self._build_email_kwargs_list:
|
||||
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Pigs',
|
||||
'subject of invitation email is incorrect')
|
||||
self.assertTrue('You have been invited to follow Pigs' in sent_email.get('body'),
|
||||
'body of invitation email is incorrect')
|
||||
self.assertEqual(sent_email.get('subject'), 'Invitation to follow Discussion group: Pigs',
|
||||
'invite: subject of invitation email is incorrect')
|
||||
self.assertIn('Administrator invited you to follow Discussion group document: Pigs', sent_email.get('body'),
|
||||
'invite: body of invitation email is incorrect')
|
||||
self.assertTrue(partner_carine.signup_url in sent_email.get('body'),
|
||||
'body of invitation email does not contain signup url')
|
||||
'invite: body of invitation email does not contain signup url')
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<!-- Avoid auto-including this demo user in any default group -->
|
||||
<field name="groups_id" eval="[(5,)]"/>
|
||||
<field name="image">iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAAAAAAZai4+AAAMQElEQVR4nO2ce4wV1R3Hv7/fmbvrPliQZWEXWFgWEFgQBRNI0dZW7euPxliTRhNbW5NatammoaaPNKmpKRYiUunDFzEU28YYkRaiaX0hYhUELApaKG90l2VZdmVl2WXvnPPrH/c1M3d2uWdmePzB75+9d+7Mmc/8zjm/+T3OWRJciMLnGyBcLmLZyEUsG7mIZSNOAm2IQAAQQAAEAhBRrCYprjkVI6GPpkXFIIuHJYYJ6D/Wsb+97fiJk339A0ZVDa8bP3lG4xhAjDofWGIUcOifW3ceOFr026Q5V980CSbq2I2B5To49dILL/YAQE4tkhlf0ABG3Pzta+FG7EqJKEZL1/IZANgJuzMrBpxvvCuio7QeFcsVWTsLUEMogxSh7IEBcc8dVlrabyeoM40cRfjS3ihc0bC0bJoOp5R5lkLT1ghckbC0WV1bqiF20PCB/fiKpq30VUiVRgUozOgUY3mDaHaFKkmXeq5O/XehsTVDEc2dzX3Szqp1XPJTZCRRD4KYw+yFyBJtaVSTxGIxRkKmp6ZNG9nYNZUQEgAyo66ZnQrTizLPw250JYfF+OmHG7ZsukWKuQzeH1B2XJEMhHt10fM4+HHGDPwQRf1IqD1oZ7uS0hbpkfcYDWj51VgT1Jeo4+12vZhYJ8qoOlaAkrqWsGdtt2stMW3lfC6RyWG/n7ZrLvnIh04mcJ+ksYzqWE8hNmqYXTMRAzJWAXvOxABgDN/XporeNEL1sLLzEbF6deDWGr0AtOKFzxa//8g01Nq1HxFrfmUq0FO6UYmb6r37GcctOptkyuhzoS1+NGibBMSU2nTfu1xMBZYpZdoqZoyGRcVevGF1YvGy/lQ65HQj11m+EyMHZH4xrpi/zRpkYhPVHbH0T5PBckVeuQYYJDpTuM82ykgEKy2d38Wg4RnzsI+MZZCRBJaWVy4DDzqkU1hsHZIlgOXKCmeIQMjBl11jG/nEx3JllaJB32GUwhWt1lTxsbS8VD44FQM3tEbIjsTFMuZkS7E7moNycMnP+qPkbOJiubJ8MJNMCvjKZrGOqBPAMiZ9HYUqixygeZVIOgpVeDq2dBFufR9hIaDSbt1d99RDR7tBXCx0HA+LTJUu+8G9U+CWlGxKHivcSSfS1y5aAM2RWz8rVQymn7+6QJsYifkkqhhBYf3gL030nDxwVrSlzNd/4cZs+CxgGbqbB7f7pUn8TuQAAUnVVbGfNjaWMUX2IV0et9H4WJWTHT8X6ZpYoz3TSNzCnT5VbAaq4hUTkQDW2ZH4Qz77XCIioEwKILayktJWvqKpQ3PN1pIMllY4/f7h42r8lfUwiZjCeP5WRlxp/3VLJQA0LjwWrYAYkCSwXHm1GQA7DgPTdyfBlUhAtiYFJzvYHUw7oiM5pAljabO7xjOhU7gtUr3VL/HHp9BDPZ6clque26zsKikhEhtL+MA6b7JUaGBN3DYTwDK0q0vEd2BT/D5IwMik/VUekb2nbJNsRZIAVlFWpNeyNhAiCah7Qk1ANzWXxG00PhaZGXN9LjLTnIqQ4p2dJGAg+E4fBcnXwsoYdhL/VS3QX329YLhS6VnvVMV3bWIbZDFycAJSTABIpVD/XgIvxWRe1R/NBaAUA5gfYY1IsSTk2PQsagaAinlP9SXi2CTjBhpG95ZuU9Ewj5JxAxNzmjOOjZELyWkGIEZAcWP8vFygAdkFukr3IpaNXMSykeg5CI/bEMgk5X/QkVeCRzMQIia8duE/iwDRFMXAWmPliU6o6uwhs9eT6qZ09dgsVNdT82aOBgAtbKk1m04UgYCZobt27HhLLctm14w8s2RYbkkGG17dIAyAzMhh1zW3tMyb05gCRJO3e0u4V0lidDoTK3e/ufLez9cqVG7PuwpGfwsOcsH+s/mg2pUHAaBq7veffKNLRETSbol5gBKwjE6ntYhI/4F/PXzjpDIAoIo3CyG9lr4FcEBE5GCRJ9R35TsoZwBINd+8fENbBi1dQo5iaCxjXNcVETndvfH3d3wus1BGOaqMVspA4TQthyeDATDu9FbqjHtyPhSxykyP8Tfc/+yeUyIi2nWH9soGxzI6nbnDwO7V919bT1kiJoLCbyTtPdeVrWNAYHzTrwotB5vAAIiVwwBQOev2Fe/1ioiYoXo0FMtoN3PJwKH1S2+9fExmMDu5ma5wh0n7r0jLYjhEFfsCvqkr/x6WNxCUXV0/fPpNi9d/rEVE9CBsRTNRRDKrP/p2bv5o5+4OAHBgRPJlAaVv/ENw1SuZk4DA9AXsjXIXPHkrZa2QaIDA9NmJXWtQP+PK2dc0OQxooMi0ebEERkgRYPbv2rHzncMaABPE+BYZsZ73VEVwQRLTAQiQPjozwOW4t+x5wJOSkCyFtLevR/nsBbNmT68BoIXYG8XlsTSYoKAPtW3btr31GAAwS3HlBISb69ygkknvgoDNkaKkCJvvLT4VMNoGADHM6S1bUFl/+fx5k8aVAzCeCqSnQ/v3vHD/9fWZxkL3fWR+QsuJ4JIZIx0jQFBYKoFBJ2n50aA2mzhbNK79wsJ/7Pdemcd6+6HbWioZAKngur+AKPwlmIbU8hYDcPCTIJY2H1YPadyJM/Glqp57558O5NaXZLCMkesBwEmVUMhlXNUXmD6urAABDm4JArty16CrNzxsynEA4Jnc5Rl/iwyanXKGm9ZnfnUbtW1dYHOBoBUMCHrAvgYM/++vJSRKRLsuOFU5MzfsOdfuBNctPc/yWGAmEvaDAMGJgYC26dHPuEQnRdIVjQEswujSE4uaNmz0reIUdg9CAEHHp75mDO9YWXJWiTBlZO5zHmt86OKPcFHmCb+jRt1tGZyj/pXDgiWnSlUWCNNY/NoCGpzSk1Ka1273rhURnGiDAMI9x73aMvzBmtJ3OxCmIu+25Q6Nqyn1ckCod6nvOw71cmZD52H/eb/rLdn9JYOW/Jc8Vk1d6VgwtHa3Tw37cqr+xKMtrXY8V7y+efBGKxrznZf7a6jWIrMo3LPSd/a+3IdDvvMW9ZbcJAijJuYR8lhlE2wSnoZWdhbGMmFPFheefZ1GbX3eKrnbWCdBLNBEGyxR7U/nx6ewuy/Td4SufCsCLHNLnoYAoblgpAtRdVPpUAA0Huss7JHp+iyDJWjPJwPtpiEAzCh8zDVCaLQq1Ig6uDrXQ4JPjufU8ml3buqR/LbPQlkQzCn0VwGrPlgjOUMr9ETOjTI42MPZpk92ZZ/O8NvP22xoI6meWowFNIwo2p8zlBj+z4v5PtqdP9zTmf/4SNoqZJfLxoRpa/gltrWHx3N1Q9mVGwA0kH0pat60tvQ9jAAY44aJ51u2PakaaYel6fUXM6OLB/ZksYTRkZuTj7hWSSrCJOjiTjSYYNMKAMbjGXWw25bXFg6DAGje+He7rZLiefX40m7jLLE0vbyNDWDQ6jGinRmdm0VpuyGhaaoHxoM10RILnP4jAAj29ecXAOEoGNDqjdfsbBbBOxG9WPW2WIbX7WUD4KDHtB/JeBKPpG3r1RO99/dgNdpWJ4W7l8NAsN/TzLEBiOENL1uuhWBMTZkQbRHGVNvWcjX9+bAjjD0ebbX3ADLwYNi+mqGEMM2rXg9WlY1rk4GgnhXQ3F+IpQV9ndDq9ddsdywLZoRiATWWG6oAgFZ1KnS1FuIAlm6QWWLdjuZxXpaCtkzFKNvGYPjQGsLRo4W3DA+0Qb1su18ZhNomr1IKhELjI1S+aWk3DnntuXyC9MMh+8jOJOObJBwLY+3XoGjevUYO+B7nY7xgabMAMGb6pm4BizAqwtIYweO0y3fkY3dZlNLFXN837+u00SKCzYmhLRtafWk1943NVq5D9rLJ/hHkSQZtt4hg86Loi/63xuXFW8HPKISyHb6sawHLSJela5OcMCZ3+DbeeB+sujESVvCaKJUnNF7qO+Ad8qmmSFjBeRKh5kZodnz/GsGjLYNo2kpADFr8T+M1hLDcZZycCKb4NeLDsvVPkxKS8mmDYgHjYBWTJSgN4/0kni+EusrYy9QiCaGp3G+BfVijLVJvSQqhJeWfvz6s2gRWz0URwhWBI14sqR5zTmnyImWBEe8baOfLcJEe0zwEFjD2XNLkhTC8PgDi/2Yb7ycjhCnBf+PgxxoXe410NGkJ3teLRZhwnrCmBw/4tXVpVezVyBHE8LTgIb+2Kkach6lIMnps0KH1YZnhDecBizFhZHDs/B9R17D2kvkawAAAAABJRU5ErkJggg==</field>
|
||||
<field name="share" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="portal.group_anonymous" model="res.groups">
|
||||
|
||||
@@ -59,12 +59,11 @@ class sale_order(osv.Model):
|
||||
assert len(ids) == 1
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
partner = document.partner_id
|
||||
# TDE note: this code should be improved: used a real invite wizard instead of an ugly email
|
||||
if partner.id not in document.message_follower_ids:
|
||||
self.message_subscribe(cr, uid, ids, [partner.id], context=context)
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
mail_values = {
|
||||
'email_from': user.partner_id.email,
|
||||
'email_to': partner.email,
|
||||
'recipient_ids': [(4, partner.id)],
|
||||
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
|
||||
'body_html': 'You have been invited to follow %s' % document.name_get()[0][1],
|
||||
'auto_delete': True,
|
||||
@@ -72,7 +71,7 @@ class sale_order(osv.Model):
|
||||
}
|
||||
mail_obj = self.pool.get('mail.mail')
|
||||
mail_id = mail_obj.create(cr, uid, mail_values, context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], recipient_ids=[partner.id], context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], context=context)
|
||||
return super(sale_order, self).action_button_confirm(cr, uid, ids, context=context)
|
||||
|
||||
def get_signup_url(self, cr, uid, ids, context=None):
|
||||
@@ -120,12 +119,11 @@ class account_invoice(osv.Model):
|
||||
# fetch the partner's id and subscribe the partner to the invoice
|
||||
document = self.browse(cr, uid, ids[0], context=context)
|
||||
partner = document.partner_id
|
||||
# TDE note: this code should be improved: used a real invite wizard instead of an ugly email
|
||||
if partner.id not in document.message_follower_ids:
|
||||
self.message_subscribe(cr, uid, ids, [partner.id], context=context)
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
mail_values = {
|
||||
'email_from': user.partner_id.email,
|
||||
'email_to': partner.email,
|
||||
'recipient_ids': [(4, partner.id)],
|
||||
'subject': 'Invitation to follow %s' % document.name_get()[0][1],
|
||||
'body_html': 'You have been invited to follow %s' % document.name_get()[0][1],
|
||||
'auto_delete': True,
|
||||
@@ -133,7 +131,7 @@ class account_invoice(osv.Model):
|
||||
}
|
||||
mail_obj = self.pool.get('mail.mail')
|
||||
mail_id = mail_obj.create(cr, uid, mail_values, context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], recipient_ids=[partner.id], context=context)
|
||||
mail_obj.send(cr, uid, [mail_id], context=context)
|
||||
return super(account_invoice, self).invoice_validate(cr, uid, ids, context=context)
|
||||
|
||||
def get_signup_url(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<field name="name">Sales Order - Send by Email (Portal)</field>
|
||||
<field name="email_from">${object.user_id.email or ''}</field>
|
||||
<field name="subject">${object.company_id.name} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
|
||||
<field name="email_recipients">${object.partner_invoice_id.id}</field>
|
||||
<field name="partner_to">${object.partner_invoice_id.id}</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="report_template" ref="sale.report_sale_order"/>
|
||||
@@ -97,7 +97,7 @@
|
||||
<field name="name">Invoice - Send by Email (Portal)</field>
|
||||
<field name="email_from">${object.user_id.email or object.company_id.email or 'noreply@localhost'}</field>
|
||||
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a' })</field>
|
||||
<field name="email_recipients">${object.partner_id.id}</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="account.model_account_invoice"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="report_template" ref="account.account_invoices"/>
|
||||
|
||||
@@ -109,7 +109,8 @@
|
||||
<group name="inventory">
|
||||
<group name="status" string="Status">
|
||||
<field name="state"/>
|
||||
<field name="product_manager"/>
|
||||
<field name="product_manager"
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_sale_manager']}"/>
|
||||
</group>
|
||||
<group name="Weights" groups="product.group_stock_packaging" string="Weights">
|
||||
<field digits="(14, 3)" name="volume" attrs="{'readonly':[('type','=','service')]}"/>
|
||||
|
||||
@@ -100,7 +100,9 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="privacy_visibility"/>
|
||||
<field name="user_id" string="Project Manager" attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"/>
|
||||
<field name="user_id" string="Project Manager"
|
||||
attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"
|
||||
context="{'default_groups_ref': ['base.group_user', 'project.group_project_manager']}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
|
||||
@@ -381,7 +383,10 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="project_id" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/>
|
||||
<field name="user_id" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}" options='{"no_open": True}'/>
|
||||
<field name="user_id"
|
||||
attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"
|
||||
options='{"no_open": True}'
|
||||
context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/>
|
||||
<field name="planned_hours" widget="float_time"
|
||||
groups="project.group_time_work_estimation_tasks"
|
||||
on_change="onchange_planned(planned_hours, effective_hours)"/>
|
||||
|
||||
@@ -69,7 +69,8 @@
|
||||
<field name="categ_ids" widget="many2many_tags"/>
|
||||
<group>
|
||||
<group groups="base.group_user">
|
||||
<field name="user_id"/>
|
||||
<field name="user_id"
|
||||
context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id, email_from)"/>
|
||||
<field name="email_from"/>
|
||||
<label for="project_id" groups="base.group_user"/>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<field name="name">Purchase Order - Send by mail</field>
|
||||
<field name="email_from">${object.validator.email or ''}</field>
|
||||
<field name="subject">${object.company_id.name} Order (Ref ${object.name or 'n/a' })</field>
|
||||
<field name="email_recipients">${object.partner_id.id}</field>
|
||||
<field name="partner_to">${object.partner_id.id}</field>
|
||||
<field name="model_id" ref="purchase.model_purchase_order"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="report_template" ref="report_purchase_quotation"/>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@
|
||||
<field name="name">Sales Order - Send by Email</field>
|
||||
<field name="email_from">${object.user_id.email or ''}</field>
|
||||
<field name="subject">${object.company_id.name} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
|
||||
<field name="email_recipients">${object.partner_invoice_id.id}</field>
|
||||
<field name="partner_to">${object.partner_invoice_id.id}</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="report_template" ref="report_sale_order"/>
|
||||
|
||||
+1
-1
@@ -729,7 +729,7 @@ class sale_order_line(osv.osv):
|
||||
'salesman_id':fields.related('order_id', 'user_id', type='many2one', relation='res.users', store=True, string='Salesperson'),
|
||||
'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
|
||||
}
|
||||
_order = 'order_id desc, sequence'
|
||||
_order = 'order_id desc, sequence, id'
|
||||
_defaults = {
|
||||
'product_uom' : _get_uom_id,
|
||||
'discount': 0.0,
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Spanish (Colombia) translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
|
||||
"PO-Revision-Date: 2013-03-19 03:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Spanish (Colombia) <es_CO@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: 2013-03-20 04:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16532)\n"
|
||||
|
||||
#. module: sale_analytic_plans
|
||||
#: field:sale.order.line,analytics_id:0
|
||||
msgid "Analytic Distribution"
|
||||
msgstr "Distribución Analítica"
|
||||
|
||||
#. module: sale_analytic_plans
|
||||
#: model:ir.model,name:sale_analytic_plans.model_sale_order
|
||||
msgid "Sales Order"
|
||||
msgstr "Pedido de Venta"
|
||||
|
||||
#. module: sale_analytic_plans
|
||||
#: model:ir.model,name:sale_analytic_plans.model_sale_order_line
|
||||
msgid "Sales Order Line"
|
||||
msgstr "Línea de Pedido de Venta"
|
||||
@@ -88,7 +88,7 @@ openerp.web_linkedin = function(instance) {
|
||||
$("body").append(self.$linkedin);
|
||||
var tag = document.createElement('script');
|
||||
tag.type = 'text/javascript';
|
||||
tag.src = "http://platform.linkedin.com/in.js";
|
||||
tag.src = "https://platform.linkedin.com/in.js";
|
||||
tag.innerHTML = 'api_key : ' + self.api_key + '\nauthorize : true\nscope: r_network r_basicprofile'; // r_contactinfo r_fullprofile r_emailaddress';
|
||||
|
||||
document.getElementsByTagName('head')[0].appendChild(tag);
|
||||
|
||||
Reference in New Issue
Block a user