[[ get_account(data) or removeParentNode('para') ]] |
[[ get_fiscalyear(data) or '' ]] |
- [[ get_filter(data)=='No Filter' and get_filter(data) or removeParentNode('para') ]]
+ | [[ get_filter(data)=='No Filters' and get_filter(data) or removeParentNode('para') ]]
[[ get_filter(data)=='Date' or removeParentNode('blockTable') ]]
Start Date |
diff --git a/addons/account/report/account_general_ledger.py b/addons/account/report/account_general_ledger.py
index 294c7fa99cf..38f2392f740 100644
--- a/addons/account/report/account_general_ledger.py
+++ b/addons/account/report/account_general_ledger.py
@@ -299,10 +299,10 @@ class general_ledger(report_sxw.rml_parse, common_report_header):
def _get_sortby(self, data):
if self.sortby == 'sort_date':
- return 'Date'
+ return self._translate('Date')
elif self.sortby == 'sort_journal_partner':
- return 'Journal & Partner'
- return 'Date'
+ return self._translate('Journal & Partner')
+ return self._translate('Date')
report_sxw.report_sxw('report.account.general.ledger', 'account.account', 'addons/account/report/account_general_ledger.rml', parser=general_ledger, header='internal')
report_sxw.report_sxw('report.account.general.ledger_landscape', 'account.account', 'addons/account/report/account_general_ledger_landscape.rml', parser=general_ledger, header='internal landscape')
diff --git a/addons/account/report/common_report_header.py b/addons/account/report/common_report_header.py
index c93c3e02ee3..c5719d98b96 100644
--- a/addons/account/report/common_report_header.py
+++ b/addons/account/report/common_report_header.py
@@ -94,10 +94,10 @@ class common_report_header(object):
def _get_filter(self, data):
if data.get('form', False) and data['form'].get('filter', False):
if data['form']['filter'] == 'filter_date':
- return 'Date'
+ return self._translate('Date')
elif data['form']['filter'] == 'filter_period':
- return 'Periods'
- return 'No Filter'
+ return self._translate('Periods')
+ return self._translate('No Filters')
def _sum_debit_period(self, period_id, journal_id=None):
journals = journal_id or self.journal_ids
diff --git a/addons/account/static/src/js/account_move_reconciliation.js b/addons/account/static/src/js/account_move_reconciliation.js
index 8e72e24eb22..22fe9b7b392 100644
--- a/addons/account/static/src/js/account_move_reconciliation.js
+++ b/addons/account/static/src/js/account_move_reconciliation.js
@@ -48,7 +48,7 @@ openerp.account = function (instance) {
this.last_group_by = group_by;
this.old_search = _.bind(this._super, this);
var mod = new instance.web.Model("account.move.line", context, domain);
- return mod.call("list_partners_to_reconcile", []).pipe(function(result) {
+ return mod.call("list_partners_to_reconcile", []).then(function(result) {
var current = self.current_partner !== null ? self.partners[self.current_partner][0] : null;
self.partners = result;
var index = _.find(_.range(self.partners.length), function(el) {
@@ -74,7 +74,7 @@ openerp.account = function (instance) {
return fct();
} else {
return new instance.web.Model("res.partner").call("read",
- [self.partners[self.current_partner][0], ["last_reconciliation_date"]]).pipe(function(res) {
+ [self.partners[self.current_partner][0], ["last_reconciliation_date"]]).then(function(res) {
self.last_reconciliation_date =
instance.web.format_value(res.last_reconciliation_date, {"type": "datetime"}, _t("Never"));
return fct();
@@ -92,7 +92,7 @@ openerp.account = function (instance) {
return false;
}
- new instance.web.Model("ir.model.data").call("get_object_reference", ["account", "action_view_account_move_line_reconcile"]).pipe(function(result) {
+ new instance.web.Model("ir.model.data").call("get_object_reference", ["account", "action_view_account_move_line_reconcile"]).then(function(result) {
var additional_context = _.extend({
active_id: ids[0],
active_ids: ids,
@@ -101,7 +101,7 @@ openerp.account = function (instance) {
return self.rpc("/web/action/load", {
action_id: result[1],
context: additional_context
- }).then(function (result) {
+ }).done(function (result) {
result.context = _.extend(result.context || {}, additional_context);
result.flags = result.flags || {};
result.flags.new_window = true;
@@ -116,7 +116,7 @@ openerp.account = function (instance) {
mark_as_reconciled: function() {
var self = this;
var id = self.partners[self.current_partner][0];
- new instance.web.Model("res.partner").call("mark_as_reconciled", [[id]]).pipe(function() {
+ new instance.web.Model("res.partner").call("mark_as_reconciled", [[id]]).then(function() {
self.do_search(self.last_domain, self.last_context, self.last_group_by);
});
},
diff --git a/addons/account/test/account_report.yml b/addons/account/test/account_report.yml
index 64f8ccf838f..7fe3095d47f 100644
--- a/addons/account/test/account_report.yml
+++ b/addons/account/test/account_report.yml
@@ -31,7 +31,6 @@
-
!python {model: account.account}: |
ctx={}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
data_dict = {'chart_account_id':ref('account.chart0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_aged_balance_view',wiz_data=data_dict, context=ctx, our_module='account')
@@ -40,7 +39,6 @@
-
!python {model: account.account}: |
ctx={}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')]})
data_dict = {'chart_account_id':ref('account.chart0'), 'account_report_id': ref('account_financial_report_balancesheet0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_report',wiz_data=data_dict, context=ctx, our_module='account')
@@ -49,7 +47,6 @@
-
!python {model: account.account}: |
ctx={}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')]})
data_dict = {'chart_account_id':ref('account.chart0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_balance_menu',wiz_data=data_dict, context=ctx, our_module='account')
@@ -60,7 +57,6 @@
journal_ids = [ref('account.sales_journal'),ref('account.refund_sales_journal'),ref('account.expenses_journal'),ref('account.refund_expenses_journal'),
ref('account.bank_journal'),ref('account.check_journal'),ref('account.cash_journal')]
ctx={}
- ctx.update({'model': 'account.journal.period','active_ids':journal_ids})
data_dict = {'chart_account_id':ref('account.chart0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_central_journal',wiz_data=data_dict, context=ctx, our_module='account')
@@ -71,7 +67,6 @@
journal_ids = [ref('account.sales_journal'),ref('account.refund_sales_journal'),ref('account.expenses_journal'),ref('account.refund_expenses_journal'),
ref('account.bank_journal'),ref('account.check_journal'),ref('account.cash_journal')]
ctx={}
- ctx.update({'model': 'account.journal.period','active_ids':journal_ids})
data_dict = {'chart_account_id':ref('account.chart0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_journal',wiz_data=data_dict, context=ctx, our_module='account')
@@ -80,7 +75,6 @@
-
!python {model: account.account}: |
ctx={}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')]})
data_dict = {'chart_account_id':ref('account.chart0'),'landscape':False}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu',wiz_data=data_dict, context=ctx, our_module='account')
@@ -89,7 +83,6 @@
-
!python {model: account.account}: |
ctx={}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')]})
data_dict = {'chart_account_id':ref('account.chart0'),'landscape':True}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu',wiz_data=data_dict, context=ctx, our_module='account')
@@ -99,7 +92,6 @@
!python {model: account.journal.period}: |
journal_ids = [ref('account.sales_journal'),ref('account.refund_sales_journal'),ref('account.expenses_journal'),ref('account.refund_expenses_journal'),ref('account.bank_journal'),ref('account.check_journal'),ref('account.cash_journal')]
ctx={}
- ctx.update({'model': 'account.journal.period','active_ids':journal_ids})
data_dict = {'chart_account_id':ref('account.chart0'), 'period_from':ref('period_1'), 'period_to':ref('period_12')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_print_journal',wiz_data=data_dict, context=ctx, our_module='account')
@@ -109,7 +101,6 @@
!python {model: account.account}: |
ctx={}
data_dict = {'chart_account_id':ref('account.chart0')}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_balance',wiz_data=data_dict, context=ctx, our_module='account')
-
@@ -118,7 +109,6 @@
!python {model: account.account}: |
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'),'page_split': True}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_ledger',wiz_data=data_dict, context=ctx, our_module='account')
-
@@ -127,7 +117,6 @@
!python {model: res.partner}: |
ctx={}
data_dict = {'chart_account_id':ref('account.chart0'),'page_split': False}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')],'active_id':ref('account.chart0')})
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_partner_ledger',wiz_data=data_dict, context=ctx, our_module='account')
-
@@ -135,7 +124,6 @@
-
!python {model: account.account}: |
ctx={}
- ctx.update({'model': 'account.account','active_ids':[ref('account.chart0')]})
data_dict = {'chart_account_id':ref('account.chart0'), 'target_move': 'all', 'account_report_id': ref('account_financial_report_balancesheet0')}
from tools import test_reports
test_reports.try_report_action(cr, uid, 'action_account_report',wiz_data=data_dict, context=ctx, our_module='account')
diff --git a/addons/account/wizard/account_fiscalyear_close.py b/addons/account/wizard/account_fiscalyear_close.py
index 196c14d3792..dbf815d5218 100644
--- a/addons/account/wizard/account_fiscalyear_close.py
+++ b/addons/account/wizard/account_fiscalyear_close.py
@@ -226,7 +226,7 @@ class account_fiscalyear_close(osv.osv_memory):
for account in obj_acc_account.browse(cr, uid, account_ids, context={'fiscalyear': fy_id}):
balance_in_currency = 0.0
if account.currency_id:
- cr.execute('SELECT sum(amount_currency) as balance_in_currency FROM account_move_line ' \
+ cr.execute('SELECT sum(COALESCE(amount_currency,0.0)) as balance_in_currency FROM account_move_line ' \
'WHERE account_id = %s ' \
'AND ' + query_line + ' ' \
'AND currency_id = %s', (account.id, account.currency_id.id))
diff --git a/addons/account/wizard/account_report_common.py b/addons/account/wizard/account_report_common.py
index 9acc09e9026..4438484aaaf 100644
--- a/addons/account/wizard/account_report_common.py
+++ b/addons/account/wizard/account_report_common.py
@@ -119,7 +119,11 @@ class account_common_report(osv.osv_memory):
def _get_fiscalyear(self, cr, uid, context=None):
now = time.strftime('%Y-%m-%d')
- fiscalyears = self.pool.get('account.fiscalyear').search(cr, uid, [('date_start', '<', now), ('date_stop', '>', now)], limit=1 )
+ company_id = False
+ ids = context.get('active_ids', [])
+ if ids:
+ company_id = self.browse(cr, uid, ids[0], context=context).company_id.id
+ fiscalyears = self.pool.get('account.fiscalyear').search(cr, uid, [('date_start', '<', now), ('date_stop', '>', now), ('company_id', '=', company_id)], limit=1)
return fiscalyears and fiscalyears[0] or False
def _get_all_journal(self, cr, uid, context=None):
diff --git a/addons/account_analytic_plans/account_analytic_plans_view.xml b/addons/account_analytic_plans/account_analytic_plans_view.xml
index 76d6aeed7b8..e5c02c8640e 100644
--- a/addons/account_analytic_plans/account_analytic_plans_view.xml
+++ b/addons/account_analytic_plans/account_analytic_plans_view.xml
@@ -21,17 +21,17 @@
-
+
-
+
-
+
@@ -276,7 +276,7 @@
-
+
account.analytic.default.tree.plans
account.analytic.default
diff --git a/addons/account_anglo_saxon/invoice.py b/addons/account_anglo_saxon/invoice.py
index 693283b870b..26271015b7e 100644
--- a/addons/account_anglo_saxon/invoice.py
+++ b/addons/account_anglo_saxon/invoice.py
@@ -40,7 +40,7 @@ class account_invoice_line(osv.osv):
if inv.type in ('out_invoice','out_refund'):
for i_line in inv.invoice_line:
- if i_line.product_id:
+ if i_line.product_id and i_line.product_id.valuation == 'real_time':
if inv.type == 'out_invoice':
# debit account dacc will be the output account
# first check the product, if empty check the category
@@ -87,7 +87,7 @@ class account_invoice_line(osv.osv):
})
elif inv.type in ('in_invoice','in_refund'):
for i_line in inv.invoice_line:
- if i_line.product_id:
+ if i_line.product_id and i_line.product_id.valuation == 'real_time':
if i_line.product_id.type != 'service':
# get the price difference account at the product
acc = i_line.product_id.property_account_creditor_price_difference and i_line.product_id.property_account_creditor_price_difference.id
diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py
index ac9024fd51d..0dddf441c59 100644
--- a/addons/account_asset/account_asset.py
+++ b/addons/account_asset/account_asset.py
@@ -386,7 +386,7 @@ class account_asset_depreciation_line(osv.osv):
current_currency = line.asset_id.currency_id.id
context.update({'date': depreciation_date})
amount = currency_obj.compute(cr, uid, current_currency, company_currency, line.amount, context=context)
- sign = line.asset_id.category_id.journal_id.type = 'purchase' and 1 or -1
+ sign = (line.asset_id.category_id.journal_id.type == 'purchase' and 1) or -1
asset_name = line.asset_id.name
reference = line.name
move_vals = {
diff --git a/addons/account_budget/account_budget_view.xml b/addons/account_budget/account_budget_view.xml
index cb0466a1c92..d24124e307d 100644
--- a/addons/account_budget/account_budget_view.xml
+++ b/addons/account_budget/account_budget_view.xml
@@ -220,7 +220,18 @@
-
+
+
+ account.budget.line.search
+ crossovered.budget.lines
+ search
+
+
+
+
+
+
+
crossovered.budget.line.tree
crossovered.budget.lines
diff --git a/addons/account_check_writing/i18n/es.po b/addons/account_check_writing/i18n/es.po
index 81932642524..c473e077210 100644
--- a/addons/account_check_writing/i18n/es.po
+++ b/addons/account_check_writing/i18n/es.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
-"PO-Revision-Date: 2012-02-09 19:28+0000\n"
-"Last-Translator: FULL NAME \n"
+"PO-Revision-Date: 2012-11-09 12:09+0000\n"
+"Last-Translator: Pedro Manuel Baeza \n"
"Language-Team: Spanish \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-30 05:36+0000\n"
-"X-Generator: Launchpad (build 16206)\n"
+"X-Launchpad-Export-Date: 2012-11-10 04:59+0000\n"
+"X-Generator: Launchpad (build 16251)\n"
#. module: account_check_writing
#: selection:res.company,check_layout:0
@@ -154,7 +154,7 @@ msgstr "Compañías"
#. module: account_check_writing
#: view:res.company:0
msgid "Default Check Layout"
-msgstr ""
+msgstr "Comprobar formato por defecto"
#. module: account_check_writing
#: constraint:account.journal:0
diff --git a/addons/account_sequence/account_sequence_data.xml b/addons/account_sequence/account_sequence_data.xml
index 1ad362b3979..b2d40412d0d 100644
--- a/addons/account_sequence/account_sequence_data.xml
+++ b/addons/account_sequence/account_sequence_data.xml
@@ -43,6 +43,18 @@
+
+ Account Journal
+ account.journal
+
+
+
+ Account journal sequence
+ account.journal
+ AJ
+
+
+
diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py
index 8bd9a48b1f4..b0c53b72835 100644
--- a/addons/account_voucher/account_voucher.py
+++ b/addons/account_voucher/account_voucher.py
@@ -267,6 +267,7 @@ class account_voucher(osv.osv):
_order = "date desc, id desc"
# _rec_name = 'number'
_columns = {
+ 'active': fields.boolean('Active', help="By default, reconciliation vouchers made on draft bank statements are set as inactive, which allow to hide the customer/supplier payment while the bank statement isn't confirmed."),
'type':fields.selection([
('sale','Sale'),
('purchase','Purchase'),
@@ -328,6 +329,7 @@ class account_voucher(osv.osv):
'is_multi_currency': fields.boolean('Multi Currency Voucher', help='Fields with internal purpose only that depicts if the voucher is a multi currency one or not'),
}
_defaults = {
+ 'active': True,
'period_id': _get_period,
'partner_id': _get_partner,
'journal_id':_get_journal,
@@ -953,6 +955,9 @@ class account_voucher(osv.osv):
if voucher_brw.number:
name = voucher_brw.number
elif voucher_brw.journal_id.sequence_id:
+ if not voucher_brw.journal_id.sequence_id.active:
+ raise osv.except_osv(_('Configuration Error !'),
+ _('Please activate the sequence of selected journal !'))
name = seq_obj.next_by_id(cr, uid, voucher_brw.journal_id.sequence_id.id, context=context)
else:
raise osv.except_osv(_('Error!'),
@@ -1504,6 +1509,15 @@ account_voucher_line()
class account_bank_statement(osv.osv):
_inherit = 'account.bank.statement'
+ def button_confirm_bank(self, cr, uid, ids, context=None):
+ voucher_obj = self.pool.get('account.voucher')
+ voucher_ids = []
+ for statement in self.browse(cr, uid, ids, context=context):
+ voucher_ids += [line.voucher_id.id for line in statement.line_ids if line.voucher_id]
+ if voucher_ids:
+ voucher_obj.write(cr, uid, voucher_ids, {'active': True}, context=context)
+ return super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context)
+
def button_cancel(self, cr, uid, ids, context=None):
voucher_obj = self.pool.get('account.voucher')
for st in self.browse(cr, uid, ids, context=context):
@@ -1539,6 +1553,16 @@ account_bank_statement()
class account_bank_statement_line(osv.osv):
_inherit = 'account.bank.statement.line'
+ def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
+ res = super(account_bank_statement_line, self).onchange_partner_id(cr, uid, ids, partner_id, context=context)
+ if 'value' not in res:
+ res['value'] = {}
+ res['value'].update({'voucher_id' : False})
+ return res
+
+ def onchange_amount(self, cr, uid, ids, amount, context=None):
+ return {'value' : {'voucher_id' : False}}
+
def _amount_reconciled(self, cursor, user, ids, name, args, context=None):
if not ids:
return {}
@@ -1565,7 +1589,7 @@ class account_bank_statement_line(osv.osv):
_columns = {
'amount_reconciled': fields.function(_amount_reconciled,
string='Amount reconciled', type='float'),
- 'voucher_id': fields.many2one('account.voucher', 'Payment'),
+ 'voucher_id': fields.many2one('account.voucher', 'Reconciliation'),
}
def unlink(self, cr, uid, ids, context=None):
diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml
index babe60b640e..2cb393f4008 100644
--- a/addons/account_voucher/account_voucher_view.xml
+++ b/addons/account_voucher/account_voucher_view.xml
@@ -200,33 +200,29 @@
-
+
account.bank.statement.voucher.tree.inherit
account.bank.statement
-
+
+
+
+
+
+ onchange_amount(amount)
+
-
- account.bank.statement.voucher.form.inherit
- account.bank.statement
-
-
-
-
-
-
-
account.cash.statement.voucher.tree.inherit
account.bank.statement
diff --git a/addons/account_voucher/i18n/fr.po b/addons/account_voucher/i18n/fr.po
index ea825985448..bec649eaea1 100644
--- a/addons/account_voucher/i18n/fr.po
+++ b/addons/account_voucher/i18n/fr.po
@@ -7,14 +7,15 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n"
-"PO-Revision-Date: 2012-05-10 17:31+0000\n"
-"Last-Translator: Fabien (Open ERP) \n"
+"PO-Revision-Date: 2012-11-07 13:27+0000\n"
+"Last-Translator: Frederic Clementi - Camptocamp.com "
+"\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-30 05:19+0000\n"
-"X-Generator: Launchpad (build 16206)\n"
+"X-Launchpad-Export-Date: 2012-11-08 04:47+0000\n"
+"X-Generator: Launchpad (build 16232)\n"
#. module: account_voucher
#: view:sale.receipt.report:0
@@ -469,7 +470,7 @@ msgstr "Délai moyen de règlement"
#. module: account_voucher
#: field:res.company,income_currency_exchange_account_id:0
msgid "Income Currency Rate"
-msgstr "Taux de change d'achat"
+msgstr "Compte de gain de change"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1063
@@ -625,9 +626,9 @@ msgid ""
"Unable to create accounting entry for currency rate difference. You have to "
"configure the field 'Income Currency Rate' on the company! "
msgstr ""
-"Impossible de créer une entrée de la comptabilité à cause de la différence "
-"de taux de change. Vous devez configurer le champ 'Taux de change de vente' "
-"sur la société! "
+"Impossible de créer une écriture comptable à cause de la différence de taux "
+"de change. Vous devez configurer le champ 'Compte de gain de change' au "
+"niveau du formulaire de la société! "
#. module: account_voucher
#: view:account.voucher:0 view:sale.receipt.report:0
@@ -802,7 +803,7 @@ msgstr "Factures et transactions exceptionnelles"
#. module: account_voucher
#: field:res.company,expense_currency_exchange_account_id:0
msgid "Expense Currency Rate"
-msgstr "Taux de change de la dépense"
+msgstr "Compte de perte de change"
#. module: account_voucher
#: sql_constraint:account.invoice:0
@@ -1089,9 +1090,9 @@ msgid ""
"Unable to create accounting entry for currency rate difference. You have to "
"configure the field 'Expense Currency Rate' on the company! "
msgstr ""
-"Impossible de créer une entrée en comptabilité pour la différence de taux de "
-"change. Vous devez configurer le champ \"Taux de change d'achat\" de la "
-"société ! "
+"Impossible de créer une écriture comptable à cause de la différence de taux "
+"de change. Vous devez configurer le champ 'Compte de perte de change' au "
+"niveau du formulaire de la société! "
#. module: account_voucher
#: field:account.voucher,type:0
@@ -1156,7 +1157,7 @@ msgstr "Année"
#. module: account_voucher
#: field:account.voucher.line,amount_unreconciled:0
msgid "Open Balance"
-msgstr "Solde initial"
+msgstr "Restant dû"
#. module: account_voucher
#: view:account.voucher:0 field:account.voucher,amount:0
diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml
index 881a5e38f1c..b6f367601ff 100644
--- a/addons/account_voucher/voucher_payment_receipt_view.xml
+++ b/addons/account_voucher/voucher_payment_receipt_view.xml
@@ -54,6 +54,8 @@
-
+
crm.case.categ.form
@@ -238,7 +237,7 @@
-
+
@@ -297,7 +296,7 @@
+ parent="base.menu_crm_config_lead"/>
Cases by Sales Team
@@ -354,13 +353,13 @@
+ icon="gtk-execute"/>
+ icon="gtk-cancel"/>
+ icon="gtk-go-forward"/>
@@ -412,7 +411,7 @@
tree,form
- Click to define a new customer segmentation.
+ Click to define a new customer segmentation.
Create specific categories which you can assign to your
contacts to better manage your interactions with them. The
@@ -425,7 +424,7 @@
+ parent="base.menu_base_config"/>
@@ -466,11 +465,11 @@
form
tree,form
-
+
+ parent="base.menu_crm_config_lead"/>
diff --git a/addons/crm/i18n/es.po b/addons/crm/i18n/es.po
index fe2f139f682..a72a6ec2305 100644
--- a/addons/crm/i18n/es.po
+++ b/addons/crm/i18n/es.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n"
-"PO-Revision-Date: 2012-02-10 17:48+0000\n"
-"Last-Translator: Carlos Ch. \n"
+"PO-Revision-Date: 2012-11-09 12:10+0000\n"
+"Last-Translator: Pedro Manuel Baeza \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: 2012-10-30 04:57+0000\n"
-"X-Generator: Launchpad (build 16206)\n"
+"X-Launchpad-Export-Date: 2012-11-10 04:59+0000\n"
+"X-Generator: Launchpad (build 16251)\n"
#. module: crm
#: view:crm.lead.report:0
@@ -172,7 +172,7 @@ msgstr "Mes esperado de cierre"
#. module: crm
#: view:crm.lead2opportunity.partner.mass:0
msgid "Assigned Opportunities to"
-msgstr ""
+msgstr "Oportunidades asignadas a"
#. module: crm
#: view:crm.lead:0 field:crm.lead,partner_id:0 view:crm.lead.report:0
@@ -598,7 +598,7 @@ msgstr "Fecha de fin"
#. module: crm
#: view:crm.opportunity2phonecall:0 view:crm.phonecall2phonecall:0
msgid "Schedule/Log a Call"
-msgstr ""
+msgstr "Planificar/Registrar una llamada"
#. module: crm
#: constraint:base.action.rule:0
@@ -792,7 +792,7 @@ msgstr "Siguiente"
#. module: crm
#: field:crm.segmentation,som_interval:0
msgid "Days per Period"
-msgstr ""
+msgstr "Días por periodo"
#. module: crm
#: field:crm.meeting,byday:0
@@ -959,7 +959,7 @@ msgstr "Días para abrir"
#. module: crm
#: view:crm.meeting:0
msgid "Show Time as"
-msgstr ""
+msgstr "Mostrar hora como"
#. module: crm
#: view:crm.phonecall2partner:0
@@ -1342,7 +1342,7 @@ msgstr "Fecha escritura"
#. module: crm
#: view:crm.meeting:0
msgid "End of Recurrency"
-msgstr ""
+msgstr "Fin de recurrencia"
#. module: crm
#: view:crm.meeting:0
@@ -1392,6 +1392,12 @@ msgid ""
" \n"
"If the call needs to be done then the state is set to 'Not Held'."
msgstr ""
+"El estado se establece a 'Para hacer' cuando se crea el caso.\n"
+"Si es caso está en marcha, el estado se establece a 'Abierto.\n"
+"Cuando la llamada se termina, el estado se establece en 'Realizada'. "
+" \n"
+"Si la llamada está pendiente de ser realizada, entonces el estado se "
+"establece en 'Pendiente'."
#. module: crm
#: selection:crm.meeting,week_list:0
@@ -1449,7 +1455,7 @@ msgstr "Oportunidades por categorías"
#. module: crm
#: model:crm.case.section,name:crm.section_sales_marketing_department
msgid "Sales Marketing Department"
-msgstr ""
+msgstr "Departamento de ventas y marketing"
#. module: crm
#: view:crm.phonecall.report:0
@@ -1900,7 +1906,7 @@ msgstr "Responder a"
#. module: crm
#: view:crm.case.section:0
msgid "Select Stages for this Sales Team"
-msgstr ""
+msgstr "Seleccione etapas para este equipo de ventas"
#. module: crm
#: view:board.board:0
@@ -2015,7 +2021,7 @@ msgstr "Ubicación"
#. module: crm
#: model:ir.model,name:crm.model_crm_lead2opportunity_partner_mass
msgid "Mass Lead To Opportunity Partner"
-msgstr ""
+msgstr "Transformación masiva de iniciativa a oportunidad"
#. module: crm
#: view:crm.lead:0
@@ -2777,7 +2783,7 @@ msgstr "e-mail del contacto"
#. module: crm
#: field:crm.lead,referred:0
msgid "Referred by"
-msgstr ""
+msgstr "Referido por"
#. module: crm
#: view:crm.lead:0 model:ir.model,name:crm.model_crm_add_note
@@ -3541,7 +3547,7 @@ msgstr "Nuevas oportunidades"
#: code:addons/crm/crm_action_rule.py:61
#, python-format
msgid "No E-Mail Found for your Company address!"
-msgstr ""
+msgstr "No se encontró dirección de e-mail para el contacto de su compañía"
#. module: crm
#: field:crm.lead.report,email:0
@@ -3561,7 +3567,7 @@ msgstr "Oportunidades por usuario y equipo"
#. module: crm
#: view:crm.phonecall:0
msgid "Reset to Todo"
-msgstr ""
+msgstr "Cambiar a 'Para hacer'"
#. module: crm
#: field:crm.case.section,working_hours:0
@@ -3643,6 +3649,10 @@ msgid ""
"partner. From the phone call form, you can trigger a request for another "
"call, a meeting or an opportunity."
msgstr ""
+"Esta herramienta permite registrar sus llamadas entrantes sobre la marcha. "
+"Cada llamada que recibe aparecerá en el formulario de la empresa para trazar "
+"cada contacto que tiene con una empresa. Desde el formulario de llamadas, "
+"puede lanzar una petición para otra llamada, una reunión u oportunidad."
#. module: crm
#: selection:crm.lead.report,creation_month:0
@@ -3673,6 +3683,10 @@ msgid ""
"channels that will be maintained at the creation of a document in the "
"system. Some examples of channels can be: Website, Phone Call, Reseller, etc."
msgstr ""
+"Controle el origen de sus iniciativas y oportunidades de venta mediante la "
+"creación de canales específicos que se usarán en la creación de documentos "
+"en el sistema. Algunos ejemplos de canales son: Sitio web, llamada "
+"telefónica, distribuidores, ..."
#. module: crm
#: selection:crm.lead2opportunity.partner,name:0
@@ -3740,7 +3754,7 @@ msgstr "Año"
#. module: crm
#: constraint:res.partner:0
msgid "Error ! You cannot create recursive associated members."
-msgstr ""
+msgstr "¡Error! No puede crear miembros asociados recursivamente."
#. module: crm
#: model:crm.case.resource.type,name:crm.type_lead8
diff --git a/addons/crm/report/crm_phonecall_report_view.xml b/addons/crm/report/crm_phonecall_report_view.xml
index a2120aef6ab..1f1a4f91046 100644
--- a/addons/crm/report/crm_phonecall_report_view.xml
+++ b/addons/crm/report/crm_phonecall_report_view.xml
@@ -91,7 +91,7 @@
crm.phonecall.report
form
tree,graph
- {"search_default_year":1,"search_default_User":1,"search_default_This Month":1,'group_by_no_leaf':1,'group_by':[]}
+ {"search_default_year":1,"search_default_Salesperson":1,"search_default_This Month":1,'group_by_no_leaf':1,'group_by':[]}
From this report, you can analyse the performance of your sales team, based on their phone calls. You can group or filter the information according to several criteria and drill down the information, by adding more groups in the report.
diff --git a/addons/crm/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py
index 2473a83206c..ea96e1d16f1 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity.py
+++ b/addons/crm/wizard/crm_lead_to_opportunity.py
@@ -175,12 +175,19 @@ class crm_lead2opportunity_mass_convert(osv.osv_memory):
return res
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
+ """
+ When "massively" (more than one at a time) converting leads to
+ opportunities, check the salesteam_id and salesmen_ids and update
+ the values before calling super.
+ """
+ if context is None:
+ context = {}
data = self.browse(cr, uid, ids, context=context)[0]
salesteam_id = data.section_id and data.section_id.id or False
- salesman = []
+ salesmen_ids = []
if data.user_ids:
- salesman = [x.id for x in data.user_ids]
- vals.update({'user_ids': salesman, 'section_id': salesteam_id})
+ salesmen_ids = [x.id for x in data.user_ids]
+ vals.update({'user_ids': salesmen_ids, 'section_id': salesteam_id})
return super(crm_lead2opportunity_mass_convert, self)._convert_opportunity(cr, uid, ids, vals, context=context)
def mass_convert(self, cr, uid, ids, context=None):
diff --git a/addons/crm/wizard/crm_lead_to_partner.py b/addons/crm/wizard/crm_lead_to_partner.py
index c201f484989..c48990f5866 100644
--- a/addons/crm/wizard/crm_lead_to_partner.py
+++ b/addons/crm/wizard/crm_lead_to_partner.py
@@ -35,7 +35,7 @@ class crm_lead2partner(osv.osv_memory):
}
def view_init(self, cr, uid, fields, context=None):
"""
- This function checks for precondition before wizard executes
+ Check for precondition before wizard executes.
"""
if context is None:
context = {}
@@ -69,22 +69,19 @@ class crm_lead2partner(osv.osv_memory):
return partner_id
def default_get(self, cr, uid, fields, context=None):
- """
- This function gets default values
- """
- res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
+ res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
partner_id = self._select_partner(cr, uid, context=context)
if 'partner_id' in fields:
res.update({'partner_id': partner_id})
if 'action' in fields:
res.update({'action': partner_id and 'exist' or 'create'})
-
+
return res
def open_create_partner(self, cr, uid, ids, context=None):
"""
- This function Opens form of create partner.
+ Open form of create partner.
"""
view_obj = self.pool.get('ir.ui.view')
view_id = view_obj.search(cr, uid, [('model', '=', self._name), \
@@ -101,21 +98,21 @@ class crm_lead2partner(osv.osv_memory):
def _create_partner(self, cr, uid, ids, context=None):
"""
- This function Creates partner based on action.
+ Create partner based on action.
"""
if context is None:
context = {}
lead = self.pool.get('crm.lead')
- lead_ids = context and context.get('active_ids') or []
+ lead_ids = context.get('active_ids', [])
data = self.browse(cr, uid, ids, context=context)[0]
partner_id = data.partner_id and data.partner_id.id or False
return lead.convert_partner(cr, uid, lead_ids, data.action, partner_id, context=context)
def make_partner(self, cr, uid, ids, context=None):
"""
- This function Makes partner based on action.
+ Make a partner based on action.
+ Only called from form view, so only meant to convert one lead at a time.
"""
- # Only called from Form view, so only meant to convert one Lead.
lead_id = context and context.get('active_id') or False
partner_ids_map = self._create_partner(cr, uid, ids, context=context)
return self.pool.get('res.partner').redirect_partner_form(cr, uid, partner_ids_map.get(lead_id, False), context=context)
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index e4d5f5999cb..8308e5420d0 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -105,7 +105,7 @@ class crm_claim(base_stage, osv.osv):
'email_from': fields.char('Email', size=128, help="Destination email for email gateway."),
'partner_phone': fields.char('Phone', size=32),
'stage_id': fields.many2one ('crm.claim.stage', 'Stage',
- domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
+ domain="['&',('fold', '=', False),'|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
'cause': fields.text('Root Cause'),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
diff --git a/addons/crm_claim/crm_claim_data.xml b/addons/crm_claim/crm_claim_data.xml
index 33bd280c364..ed0558f72e9 100644
--- a/addons/crm_claim/crm_claim_data.xml
+++ b/addons/crm_claim/crm_claim_data.xml
@@ -43,38 +43,32 @@
-->
- Draft claim
+ New
draft
26
- Actions Defined
+ In Progress
open
27
- Actions Done
+ Settled
done
28
- Refused
- done
+ Rejected
+ cancel
29
-
- Cancelled
- cancel
- 30
-
-
-
+
diff --git a/addons/crm_claim/crm_claim_menu.xml b/addons/crm_claim/crm_claim_menu.xml
index 3782a3a7c00..4c0eca3d0f7 100644
--- a/addons/crm_claim/crm_claim_menu.xml
+++ b/addons/crm_claim/crm_claim_menu.xml
@@ -52,7 +52,7 @@
-
+
diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml
index 2b5ca4b1556..aa4243a6838 100644
--- a/addons/crm_claim/crm_claim_view.xml
+++ b/addons/crm_claim/crm_claim_view.xml
@@ -102,16 +102,11 @@
diff --git a/addons/email_template/tests/test_mail.py b/addons/email_template/tests/test_mail.py
index 7af05f38b0e..9a7b71a4e42 100644
--- a/addons/email_template/tests/test_mail.py
+++ b/addons/email_template/tests/test_mail.py
@@ -63,11 +63,16 @@ class test_message_compose(test_mail.TestMailMockups):
# Create template on mail.group, with attachments
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
email_template = self.registry('email.template')
- email_template_id = email_template.create(cr, uid, {'model_id': group_model_id,
- 'name': 'Pigs Template', 'subject': '${object.name}',
- 'body_html': '${object.description}', 'user_signature': True,
+ email_template_id = email_template.create(cr, uid, {
+ 'model_id': group_model_id,
+ 'name': 'Pigs Template',
+ 'subject': '${object.name}',
+ 'body_html': '${object.description}',
+ 'user_signature': True,
'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])],
- 'email_to': 'b@b.b c@c.c', 'email_cc': 'd@d.d'})
+ 'email_to': 'b@b.b c@c.c',
+ 'email_cc': 'd@d.d'
+ })
# ----------------------------------------
# CASE1: comment and save as template
@@ -76,9 +81,9 @@ class test_message_compose(test_mail.TestMailMockups):
# 1. Comment on pigs
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': 'Dummy body '},
- {'default_composition_mode': 'comment', 'default_model': 'mail.group',
+ {'default_composition_mode': 'comment',
+ 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
- 'default_template_id': email_template_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
@@ -97,8 +102,10 @@ class test_message_compose(test_mail.TestMailMockups):
# 1. Comment on pigs
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': 'Dummy body'},
- {'default_composition_mode': 'comment', 'default_model': 'mail.group',
+ {'default_composition_mode': 'comment',
+ 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
+ 'default_use_template': False,
'default_template_id': email_template_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
@@ -135,8 +142,10 @@ class test_message_compose(test_mail.TestMailMockups):
# 1. Mass_mail on pigs and bird, with a default_partner_ids set to check he is correctly added
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': 'Dummy body'},
- {'default_composition_mode': 'mass_mail', 'default_model': 'mail.group',
+ {'default_composition_mode': 'mass_mail',
+ 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
+ 'default_use_template': False,
'default_template_id': email_template_id,
'default_partner_ids': [p_a_id],
'active_ids': [self.group_pigs_id, self.group_bird_id]})
@@ -170,3 +179,26 @@ class test_message_compose(test_mail.TestMailMockups):
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of notified_partner_ids')
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird notified_partner_ids incorrect')
+
+ # ----------------------------------------
+ # CASE4: test newly introduced email_recipients 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
+ 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),
+ 'email_cc': 'd@d',
+ })
+ # patner by email + partner by id (no double)
+ send_to = [p_a_id, p_b_id, p_c_id, p_d_id]
+ # Generate messsage with default email and partner on template
+ mail_value = mail_compose.generate_email_for_composer(cr, uid, email_template_id, uid)
+ self.assertEqual(set(mail_value['partner_ids']), set(send_to), 'mail.message partner_ids list created by template is incorrect')
diff --git a/addons/email_template/wizard/email_template_preview_view.xml b/addons/email_template/wizard/email_template_preview_view.xml
index f91535a17a5..8dd4bc92ba7 100644
--- a/addons/email_template/wizard/email_template_preview_view.xml
+++ b/addons/email_template/wizard/email_template_preview_view.xml
@@ -17,6 +17,7 @@
+
diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py
index fe6f85da544..129c32722f5 100644
--- a/addons/email_template/wizard/mail_compose_message.py
+++ b/addons/email_template/wizard/mail_compose_message.py
@@ -52,8 +52,9 @@ class mail_compose_message(osv.TransientModel):
context = {}
result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
result['template_id'] = context.get('default_template_id', context.get('mail.compose.template_id', False))
+
# pre-render the template if any
- if result.get('use_template'):
+ if result.get('use_template') and result.get('template_id'):
onchange_res = self.onchange_use_template(cr, uid, [], result.get('use_template'), result.get('template_id'),
result.get('composition_mode'), result.get('model'), result.get('res_id'), context=context)
result.update(onchange_res['value'])
@@ -65,6 +66,10 @@ class mail_compose_message(osv.TransientModel):
'template_id': fields.selection(_get_templates, 'Template', size=-1),
}
+ _defaults = {
+ 'use_template': True,
+ }
+
def onchange_template_id(self, cr, uid, ids, use_template, template_id, composition_mode, model, res_id, context=None):
""" - use_template not set: return default_get
- use_template set in mass_mailing: we cannot render, so return the template values
@@ -148,15 +153,23 @@ class mail_compose_message(osv.TransientModel):
mail.compose.message, transform email_cc and email_to into partner_ids """
template_values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
# filter template values
- fields = ['body', 'body_html', 'subject', 'email_to', 'email_cc', 'attachments']
+ fields = ['body', 'body_html', 'subject', 'email_to', 'email_recipients', 'email_cc', 'attachments']
values = dict((field, template_values[field]) for field in fields if template_values.get(field))
values['body'] = values.pop('body_html', '')
# transform email_to, email_cc into partner_ids
values['partner_ids'] = []
+
mails = tools.email_split(values.pop('email_to', '') + ' ' + values.pop('email_cc', ''))
for mail in mails:
partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
values['partner_ids'].append(partner_id)
+ email_recipients = values.pop('email_recipients', '')
+ if email_recipients:
+ for partner_id in email_recipients.split(','):
+ values['partner_ids'].append(int(partner_id))
+
+ values['partner_ids'] = list(set(values['partner_ids']))
+
return values
def render_message(self, cr, uid, wizard, res_id, context=None):
diff --git a/addons/email_template/wizard/mail_compose_message_view.xml b/addons/email_template/wizard/mail_compose_message_view.xml
index 05d0e8dffa1..0a530299d4a 100644
--- a/addons/email_template/wizard/mail_compose_message_view.xml
+++ b/addons/email_template/wizard/mail_compose_message_view.xml
@@ -8,23 +8,23 @@
-
-
-
-
-
+
+
-
-
-
+
+
+ Use template
+
+
+ or
+
+
diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml
index 2895855fc2e..85e3020512e 100644
--- a/addons/event/event_view.xml
+++ b/addons/event/event_view.xml
@@ -510,7 +510,7 @@
event.registration
-
+
@@ -519,6 +519,7 @@
+
diff --git a/addons/event_sale/event_sale.py b/addons/event_sale/event_sale.py
index 2dd40a7c285..f4d7fcaa013 100644
--- a/addons/event_sale/event_sale.py
+++ b/addons/event_sale/event_sale.py
@@ -39,7 +39,7 @@ class sale_order_line(osv.osv):
_columns = {
'event_id': fields.many2one('event.event', 'Event', help="Choose an event and it will automatically create a registration for this event."),
#those 2 fields are used for dynamic domains and filled by onchange
- 'event_type_id': fields.related('event_type_id', type='many2one', relation="event.type", string="Event Type"),
+ 'event_type_id': fields.related('product_id','event_type_id', type='many2one', relation="event.type", string="Event Type"),
'event_ok': fields.related('product_id', 'event_ok', string='event_ok', type='boolean'),
}
diff --git a/addons/google_docs/static/src/js/gdocs.js b/addons/google_docs/static/src/js/gdocs.js
index 0cc93b2510c..45e1d09d42c 100644
--- a/addons/google_docs/static/src/js/gdocs.js
+++ b/addons/google_docs/static/src/js/gdocs.js
@@ -16,9 +16,9 @@ var _t = instance.web._t,
var view = self.getParent();
var ids = ( view.fields_view.type != "form" )? view.groups.get_selection().ids : [ view.datarecord.id ];
if( !_.isEmpty(ids) ){
- view.sidebar_context().then(function (context) {
+ view.sidebar_context().done(function (context) {
var ds = new instance.web.DataSet(this, 'ir.attachment', context);
- ds.call('google_doc_get', [view.dataset.model, ids, context]).then(function(r) {
+ ds.call('google_doc_get', [view.dataset.model, ids, context]).done(function(r) {
if (r == 'False') {
var params = {
error: response,
diff --git a/addons/hr/hr_view.xml b/addons/hr/hr_view.xml
index c4a622d7a4f..8918c5012c3 100644
--- a/addons/hr/hr_view.xml
+++ b/addons/hr/hr_view.xml
@@ -288,7 +288,7 @@
- Categories of Employee
+ Categories of Employees
hr.employee.category
form
tree,form
@@ -342,8 +342,8 @@
-
+
diff --git a/addons/hr/i18n/es_EC.po b/addons/hr/i18n/es_EC.po
index 32e81b6d14d..bfbbb7fa180 100644
--- a/addons/hr/i18n/es_EC.po
+++ b/addons/hr/i18n/es_EC.po
@@ -8,15 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n"
-"PO-Revision-Date: 2012-01-03 02:55+0000\n"
-"Last-Translator: Christopher Ormaza - (Ecuadorenlinea.net) "
-"\n"
+"PO-Revision-Date: 2012-11-10 17:20+0000\n"
+"Last-Translator: Cristian Salamea (Gnuthink) \n"
"Language-Team: Spanish (Ecuador) \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-30 05:17+0000\n"
-"X-Generator: Launchpad (build 16206)\n"
+"X-Launchpad-Export-Date: 2012-11-11 04:57+0000\n"
+"X-Generator: Launchpad (build 16251)\n"
#. module: hr
#: model:process.node,name:hr.process_node_openerpuser0
@@ -199,6 +198,8 @@ msgstr "Mujer"
msgid ""
"Expected number of employees for this job position after new recruitment."
msgstr ""
+"Número de Empleados para este puesto de trabajo después de las nuevas "
+"contrataciones"
#. module: hr
#: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_new_config
@@ -291,7 +292,7 @@ msgstr "Categorías"
#. module: hr
#: field:hr.job,expected_employees:0
msgid "Total Employees"
-msgstr ""
+msgstr "Total de Empleados"
#. module: hr
#: selection:hr.employee,marital:0
@@ -435,7 +436,7 @@ msgstr "Estado"
#: model:ir.actions.act_window,name:hr.open_view_categ_tree
#: model:ir.ui.menu,name:hr.menu_view_employee_category_tree
msgid "Categories Structure"
-msgstr ""
+msgstr "Estructura de categorías"
#. module: hr
#: field:hr.employee,partner_id:0
@@ -465,7 +466,7 @@ msgstr "¡Error! No se puede crear una jerarquía recursiva de empleados."
#. module: hr
#: model:ir.actions.act_window,name:hr.action2
msgid "Subordinate Hierarchy"
-msgstr ""
+msgstr "Jerarquía subirdinada"
#. module: hr
#: model:ir.actions.act_window,help:hr.view_department_form_installer
@@ -715,12 +716,12 @@ msgstr "Subordinados"
#. module: hr
#: field:hr.job,no_of_employee:0
msgid "Number of employees currently occupying this job position."
-msgstr ""
+msgstr "Número de empleados ocupando actualmente este puesto de trabajo"
#. module: hr
#: field:hr.job,no_of_recruitment:0
msgid "Number of new employees you expect to recruit."
-msgstr ""
+msgstr "Número de empleados que espera contratar"
#~ msgid "Working Time Categories"
#~ msgstr "Categorías de Horarios de Trabajo"
diff --git a/addons/hr_attendance/report/attendance_by_month.py b/addons/hr_attendance/report/attendance_by_month.py
index f104b9c287a..6d41869ff23 100644
--- a/addons/hr_attendance/report/attendance_by_month.py
+++ b/addons/hr_attendance/report/attendance_by_month.py
@@ -31,6 +31,7 @@ from report.interface import toxml
from report import report_sxw
from tools import ustr
from tools.translate import _
+from tools import to_xml
one_day = relativedelta(days=1)
month2name = [0, 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
@@ -111,7 +112,7 @@ class report_custom(report_rml):
%s
%s
- ''' % (str(rml_obj.formatLang(time.strftime("%Y-%m-%d"),date=True))+' ' + str(time.strftime("%H:%M")),pooler.get_pool(cr.dbname).get('res.users').browse(cr,uid,uid).company_id.name)
+ ''' % (str(rml_obj.formatLang(time.strftime("%Y-%m-%d"),date=True))+' ' + str(time.strftime("%H:%M")),to_xml(pooler.get_pool(cr.dbname).get('res.users').browse(cr,uid,uid).company_id.name))
first_date = str(month)
som = datetime.strptime(first_date, '%Y-%m-%d %H:%M:%S')
diff --git a/addons/hr_attendance/static/src/js/attendance.js b/addons/hr_attendance/static/src/js/attendance.js
index d92e7534786..84516353b9d 100644
--- a/addons/hr_attendance/static/src/js/attendance.js
+++ b/addons/hr_attendance/static/src/js/attendance.js
@@ -57,7 +57,7 @@ openerp.hr_attendance = function (instance) {
var employee = new instance.web.DataSetSearch(self, 'hr.employee', self.session.user_context, [
['user_id', '=', self.session.uid]
]);
- return employee.read_slice(['id', 'name', 'state', 'last_sign', 'attendance_access']).pipe(function (res) {
+ return employee.read_slice(['id', 'name', 'state', 'last_sign', 'attendance_access']).then(function (res) {
if (_.isEmpty(res) )
return;
if (res[0].attendance_access == false){
@@ -75,7 +75,7 @@ openerp.hr_attendance = function (instance) {
do_update: function () {
this._super();
var self = this;
- this.update_promise = this.update_promise.then(function () {
+ this.update_promise = this.update_promise.done(function () {
if (self.attendanceslider)
return;
self.attendanceslider = new instance.hr_attendance.AttendanceSlider(self);
diff --git a/addons/hr_evaluation/hr_evaluation.py b/addons/hr_evaluation/hr_evaluation.py
index b13e90cd627..eece0c7497e 100644
--- a/addons/hr_evaluation/hr_evaluation.py
+++ b/addons/hr_evaluation/hr_evaluation.py
@@ -291,6 +291,7 @@ survey_request()
class hr_evaluation_interview(osv.osv):
_name = 'hr.evaluation.interview'
_inherits = {'survey.request': 'request_id'}
+ _inherit = 'mail.thread'
_rec_name = 'request_id'
_description = 'Appraisal Interview'
_columns = {
diff --git a/addons/hr_evaluation/hr_evaluation_view.xml b/addons/hr_evaluation/hr_evaluation_view.xml
index 697ed6bacea..e0978847acb 100644
--- a/addons/hr_evaluation/hr_evaluation_view.xml
+++ b/addons/hr_evaluation/hr_evaluation_view.xml
@@ -266,7 +266,7 @@
Each employee may be assigned an Appraisal Plan. Such a plan
defines the frequency and the way you manage your periodic
personnel evaluation. You will be able to define steps and
- attach interviews to each step. OpenERP manages all kind of
+ attach interviews to each step. OpenERP manages all kinds of
evaluations: bottom-up, top-down, self-evaluation and final
evaluation by the manager.
diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py
index c9961fa8a1d..ccb8af68e21 100644
--- a/addons/hr_expense/hr_expense.py
+++ b/addons/hr_expense/hr_expense.py
@@ -64,22 +64,22 @@ class hr_expense_expense(osv.osv):
_description = "Expense"
_order = "id desc"
_columns = {
- 'name': fields.char('Description', size=128),
+ 'name': fields.char('Description', size=128, required=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
'id': fields.integer('Sheet ID', readonly=True),
- 'date': fields.date('Date', select=True),
+ 'date': fields.date('Date', select=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is done."),
- 'employee_id': fields.many2one('hr.employee', "Employee", required=True),
+ 'employee_id': fields.many2one('hr.employee', "Employee", required=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
'user_id': fields.many2one('res.users', 'User', required=True),
'date_confirm': fields.date('Confirmation Date', select=True, help="Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."),
'date_valid': fields.date('Validation Date', select=True, help="Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."),
- 'user_valid': fields.many2one('res.users', 'Validation By'),
+ 'user_valid': fields.many2one('res.users', 'Validation By', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
'account_move_id': fields.many2one('account.move', 'Ledger Posting'),
'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ),
'note': fields.text('Note'),
'amount': fields.function(_amount, string='Total Amount', digits_compute= dp.get_precision('Account')),
'voucher_id': fields.many2one('account.voucher', "Employee's Receipt"),
- 'currency_id': fields.many2one('res.currency', 'Currency', required=True),
- 'department_id':fields.many2one('hr.department','Department'),
+ 'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
+ 'department_id':fields.many2one('hr.department','Department', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
'company_id': fields.many2one('res.company', 'Company', required=True),
'state': fields.selection([
('draft', 'New'),
@@ -100,6 +100,12 @@ class hr_expense_expense(osv.osv):
'currency_id': _get_currency,
}
+ def unlink(self, cr, uid, ids, context=None):
+ for rec in self.browse(cr, uid, ids, context=context):
+ if rec.state != 'draft':
+ raise osv.except_osv(_('Warning!'),_('You can only delete draft expenses!'))
+ return super(hr_expense_expense, self).unlink(cr, uid, ids, context)
+
def onchange_currency_id(self, cr, uid, ids, currency_id=False, company_id=False, context=None):
res = {'value': {'journal_id': False}}
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type','=','purchase'), ('currency','=',currency_id), ('company_id', '=', company_id)], context=context)
@@ -236,16 +242,6 @@ class product_product(osv.osv):
'hr_expense_ok': fields.boolean('Can be Expensed', help="Specify if the product can be selected in an HR expense line."),
}
- def on_change_hr_expense_ok(self, cr, uid, id, hr_expense_ok):
-
- if not hr_expense_ok:
- return {}
- data_obj = self.pool.get('ir.model.data')
- cat_id = data_obj._get_id(cr, uid, 'hr_expense', 'cat_expense')
- categ_id = data_obj.browse(cr, uid, cat_id).res_id
- res = {'value' : {'type':'service','sale_ok' :False,'categ_id':categ_id }}
- return res
-
product_product()
class hr_expense_line(osv.osv):
diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml
index 74b77009aae..d4b7cbae1ce 100644
--- a/addons/hr_expense/hr_expense_view.xml
+++ b/addons/hr_expense/hr_expense_view.xml
@@ -195,7 +195,7 @@
-
+
diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py
index f315f3d4ef3..92b1d57ce15 100644
--- a/addons/hr_holidays/hr_holidays.py
+++ b/addons/hr_holidays/hr_holidays.py
@@ -90,6 +90,18 @@ class hr_holidays_status(osv.osv):
'color_name': 'red',
'active': True,
}
+
+ def name_get(self, cr, uid, ids, context=None):
+ if not ids:
+ return []
+ res = []
+ for record in self.browse(cr, uid, ids, context=context):
+ name = record.name
+ if not record.limit:
+ name = name + (' (%d/%d)' % (record.leaves_taken or 0.0, record.max_leaves or 0.0))
+ res.append((record.id, name))
+ return res
+
hr_holidays_status()
class hr_holidays(osv.osv):
@@ -113,6 +125,13 @@ class hr_holidays(osv.osv):
result[hol.id] = hol.number_of_days_temp
return result
+ def _check_date(self, cr, uid, ids):
+ for holiday in self.browse(cr, uid, ids):
+ holiday_ids = self.search(cr, uid, [('date_from', '<=', holiday.date_to), ('date_to', '>=', holiday.date_from), ('employee_id', '=', holiday.employee_id.id), ('id', '<>', holiday.id)])
+ if holiday_ids:
+ return False
+ return True
+
_columns = {
'name': fields.char('Description', size=64),
'state': fields.selection([('draft', 'To Submit'), ('cancel', 'Cancelled'),('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved')],
@@ -146,6 +165,10 @@ class hr_holidays(osv.osv):
'user_id': lambda obj, cr, uid, context: uid,
'holiday_type': 'employee'
}
+ _constraints = [
+ (_check_date, 'You can not have 2 leaves that overlaps on same day!', ['date_from','date_to']),
+ ]
+
_sql_constraints = [
('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "The employee or employee category of this request is missing."),
('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be anterior to the end date."),
@@ -252,6 +275,13 @@ class hr_holidays(osv.osv):
result['value']['number_of_days_temp'] = 0
return result
+
+ def write(self, cr, uid, ids, vals, context=None):
+ check_fnct = self.pool.get('hr.holidays.status').check_access_rights
+ for holiday in self.browse(cr, uid, ids, context=context):
+ if holiday.state in ('validate','validate1') and not check_fnct(cr, uid, 'write', raise_exception=False):
+ raise osv.except_osv(_('Warning!'),_('You cannot modify a leave request that has been approved. Contact a human resource manager.'))
+ return super(hr_holidays, self).write(cr, uid, ids, vals, context=context)
def set_to_draft(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {
diff --git a/addons/hr_holidays/hr_holidays_demo.xml b/addons/hr_holidays/hr_holidays_demo.xml
index 4c9d18683c7..accf8c26935 100644
--- a/addons/hr_holidays/hr_holidays_demo.xml
+++ b/addons/hr_holidays/hr_holidays_demo.xml
@@ -34,8 +34,8 @@
Summer Vacation
-
-
+
+
add
draft
7
@@ -45,8 +45,8 @@
International Tour
-
-
+
+
add
7
diff --git a/addons/hr_holidays/report/holidays_summary_report.py b/addons/hr_holidays/report/holidays_summary_report.py
index 8a782075853..cadd3a22ce6 100644
--- a/addons/hr_holidays/report/holidays_summary_report.py
+++ b/addons/hr_holidays/report/holidays_summary_report.py
@@ -31,6 +31,7 @@ import time
from report import report_sxw
from tools import ustr
from tools.translate import _
+from tools import to_xml
def lengthmonth(year, month):
if month == 2 and ((year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))):
@@ -240,7 +241,7 @@ class report_custom(report_rml):
%s
%s
- ''' % (str(rml_obj.formatLang(time.strftime("%Y-%m-%d"),date=True))+' ' + str(time.strftime("%H:%M")),pooler.get_pool(cr.dbname).get('res.users').browse(cr,uid,uid).company_id.name)
+ ''' % (str(rml_obj.formatLang(time.strftime("%Y-%m-%d"),date=True))+' ' + str(time.strftime("%H:%M")),to_xml(pooler.get_pool(cr.dbname).get('res.users').browse(cr,uid,uid).company_id.name))
# Computing the xml
xml='''
diff --git a/addons/hr_payroll/hr_payroll.py b/addons/hr_payroll/hr_payroll.py
index 53c84c65ee6..c0e4bc39321 100644
--- a/addons/hr_payroll/hr_payroll.py
+++ b/addons/hr_payroll/hr_payroll.py
@@ -326,6 +326,7 @@ class hr_payslip(osv.osv):
return self.write(cr, uid, ids, {'paid': True, 'state': 'done'}, context=context)
def hr_verify_sheet(self, cr, uid, ids, context=None):
+ self.compute_sheet(cr, uid, ids, context)
return self.write(cr, uid, ids, {'state': 'verify'}, context=context)
def refund_sheet(self, cr, uid, ids, context=None):
@@ -358,6 +359,12 @@ class hr_payslip(osv.osv):
def check_done(self, cr, uid, ids, context=None):
return True
+ def unlink(self, cr, uid, ids, context=None):
+ for payslip in self.browse(cr, uid, ids, context=context):
+ if payslip.state not in ['draft','cancel']:
+ raise osv.except_osv(_('Warning!'),_('You cannot delete a payslip which is not draft or cancelled!'))
+ return super(hr_payslip, self).unlink(cr, uid, ids, context)
+
#TODO move this function into hr_contract module, on hr.employee object
def get_contract(self, cr, uid, employee, date_from, date_to, context=None):
"""
diff --git a/addons/hr_payroll/hr_payroll_demo.xml b/addons/hr_payroll/hr_payroll_demo.xml
index 836814860c1..a22809b00e3 100644
--- a/addons/hr_payroll/hr_payroll_demo.xml
+++ b/addons/hr_payroll/hr_payroll_demo.xml
@@ -75,7 +75,7 @@
fix
- worked_days.WORK100.number_of_days
+ worked_days.WORK100 and worked_days.WORK100.number_of_days
MA
@@ -89,7 +89,7 @@
Get 1% of sales
- result = (inputs.SALEURO.amount + inputs.SALASIA.amount) * 0.01
+ result = ((inputs.SALEURO and inputs.SALEURO.amount) + (inputs.SALASIA and inputs.SALASIA.amount)) * 0.01
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index 03561da569e..0dd58937306 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -106,7 +106,7 @@
@@ -84,7 +89,6 @@
form
tree,form
- {'search_default_to_read_message':True}
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index f3203336615..ee00b88dbd9 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -74,17 +74,17 @@ class mail_thread(osv.AbstractModel):
- message_unread: has uid unread message for the document
- message_summary: html snippet summarizing the Chatter for kanban views """
res = dict((id, dict(message_unread=False, message_summary='')) for id in ids)
+ user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
- # search for unread messages, by reading directly mail.notification, as SUPERUSER
- notif_obj = self.pool.get('mail.notification')
- notif_ids = notif_obj.search(cr, SUPERUSER_ID, [
- ('partner_id.user_ids', 'in', [uid]),
- ('message_id.res_id', 'in', ids),
- ('message_id.model', '=', self._name),
- ('read', '=', False)
- ], context=context)
- for notif in notif_obj.browse(cr, SUPERUSER_ID, notif_ids, context=context):
- res[notif.message_id.res_id]['message_unread'] = True
+ # search for unread messages, directly in SQL to improve performances
+ cr.execute(""" SELECT m.res_id FROM mail_message m
+ RIGHT JOIN mail_notification n
+ ON (n.message_id = m.id AND n.partner_id = %s AND n.read = False)
+ WHERE m.model = %s AND m.res_id in %s""",
+ (user_pid, self._name, tuple(ids),))
+ msg_ids = [result[0] for result in cr.fetchall()]
+ for msg_id in msg_ids:
+ res[msg_id]['message_unread'] = True
for thread in self.browse(cr, uid, ids, context=context):
cls = res[thread.id]['message_unread'] and ' class="oe_kanban_mail_new"' or ''
diff --git a/addons/mail/mail_thread_view.xml b/addons/mail/mail_thread_view.xml
index 07b24725b05..cdeade04d84 100644
--- a/addons/mail/mail_thread_view.xml
+++ b/addons/mail/mail_thread_view.xml
@@ -4,48 +4,126 @@
Inbox
mail.wall
-
+ mail.message
+ {
+ 'default_model': 'res.users',
+ 'default_res_id': uid
+ }
+
+
+
+ Good Job! Your inbox is empty.
+
+ Your inbox contains private messages or emails sent to you
+ as well as information related to documents or people you
+ follow.
+
+
To: me
mail.wall
-
+ mail.message
+ {
+ 'default_model': 'res.users',
+ 'default_res_id': uid,
+ 'search_default_message_unread': True
+ }
+
+
+
+ No private message.
+
+ This list contains messages sent to you.
+
+
- Favorites
+ Todo
mail.wall
-
+ mail.message
+ {
+ 'default_model': 'res.users',
+ 'default_res_id': uid,
+ 'search_default_message_unread': True
+ }
+
+
+
+ No todo!
+
+ When you process messages in your inbox, you can mark some
+ as todo. From this menu, you can process all your todo.
+
+
Archives
mail.wall
-
+ {
+ 'default_model': 'res.users',
+ 'default_res_id': uid,
+ 'search_default_message_read': True
+ }
+
+
+
+ No message found.
+
+
Sent
mail.wall
-
+ {
+ 'default_model': 'res.users',
+ 'default_res_id': uid
+ }
+
+
+
+ No message sent yet.
+
+ Click on the top-right icon to compose a message. This
+ message will be sent by email if it's an internal contact.
+
+
-
-
+
@@ -61,7 +139,7 @@
- Favorites
+ Todo
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
index af3cc3ed359..18d19a848cc 100644
--- a/addons/mail/static/src/css/mail.css
+++ b/addons/mail/static/src/css/mail.css
@@ -1,7 +1,36 @@
+/* ------------ TOPBAR MAIL BUTTON --------------- */
+
+/* FIXME this css is not very pretty because it uses a
+ * 'button' element wich comes with a lot of inappropriate
+ * styling. Entypo is also a headache to center properly
+ * */
+
+.openerp .oe_topbar_item.oe_topbar_compose_full_email{
+ padding: 0px;
+ width: 32px;
+ height: 32px;
+}
+.openerp .oe_topbar_item.oe_topbar_compose_full_email button{
+ position: relative;
+ top: -3px; /* centering entypo ... urgh */
+ box-sizing: border-box;
+ border: none;
+ box-shadow: none;
+ color: white;
+ background: none;
+ text-shadow: 0px 1px 2px black;
+ width: 32px;
+ height: 32px;
+ padding: 0px;
+ margin: 0px
+ border-radius: 0px;
+}
/* ------------ MAIL WIDGET --------------- */
.openerp .oe_mail, .openerp .oe_mail *{
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.openerp .oe_mail {
display: block;
@@ -42,9 +71,10 @@
}
.openerp .oe_mail .oe_msg .oe_msg_footer{
padding-left: 4px;
+ padding-top: 3px;
overflow: hidden;
- opacity:0.8;
- -webkit-transition: opacity 0.2s linear;
+ margin-bottom: 4px;
+ font-size: 11px;
}
.openerp .oe_mail .oe_msg .oe_msg_content{
display: block;
@@ -80,18 +110,24 @@
.openerp .oe_mail .oe_msg.oe_msg_indented .oe_msg_content{
padding-top:2px;
}
+.openerp .oe_mail .oe_msg.oe_msg_indented .oe_msg_footer{
+ margin-bottom: 0px;
+}
+
/* b) Votes (likes) */
+
.openerp .oe_mail .oe_mail_vote_count{
display: inline;
position: relative;
- background: #7C7BAD;
- color: white;
+ background: white;
+ box-shadow: 0px 0px 0px 1px rgba(124, 123, 173, 0.36) inset;
+ color: #7c7bad;
text-shadow: none;
border-radius: 3px;
margin: 0px;
padding-left: 3px;
- padding-right: 18px;
- margin-right: 3px;
+ padding-right: 15px;
+ margin-right: 5px;
}
.openerp .oe_mail .oe_mail_vote_count .oe_e{
position: absolute;
@@ -102,12 +138,6 @@
/* c) Message action icons */
-.openerp .oe_mail .oe_msg.oe_msg_unread .oe_unread{
- display:none;
-}
-.openerp .oe_mail .oe_msg.oe_msg_read .oe_read{
- display:none;
-}
.openerp .oe_mail .oe_msg .oe_msg_icons{
float: right;
margin-top: 4px;
@@ -115,6 +145,9 @@
margin-left: 8px;
height: 24px;
-webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
.openerp .oe_mail .oe_msg .oe_msg_icons span{
float:right;
@@ -128,10 +161,16 @@
color: #FFF;
text-shadow: 0px 1px #AAA,0px -1px #AAA, -1px 0px #AAA, 1px 0px #AAA, 0px 3px 3px rgba(0,0,0,0.1);
-webkit-transition: all 0.2s linear;
+ -moz-transition: all 0.2s linear;
+ -o-transition: all 0.2s linear;
+ transition: all 0.2s linear;
}
.openerp .oe_mail .oe_msg:hover .oe_msg_icons a{
opacity: 1;
-webkit-transition: all 0.1s linear;
+ -moz-transition: all 0.1s linear;
+ -o-transition: all 0.1s linear;
+ transition: all 0.1s linear;
}
.openerp .oe_mail .oe_msg .oe_msg_icons .oe_star:hover a{
color: #FFF6C0;
@@ -155,7 +194,7 @@
}
.openerp .oe_mail .oe_msg .oe_msg_content textarea{
width: 100%;
- height: 32px;
+ height: 64px;
margin: 0px;
padding: 0px;
resize: vertical;
@@ -171,6 +210,150 @@
width: 100%;
}
+/* --------------------- ATTACHMENTS --------------------- */
+
+.openerp .oe_mail .oe_msg_attachment_list{
+ display: none;
+ margin-top: 12px;
+ margin-bottom: 12px;
+}
+.openerp .oe_mail .oe_msg_composer .oe_msg_attachment_list{
+ display: block;
+}
+.openerp .oe_mail .oe_attachment{
+ display: inline-block;
+ width: 100px;
+ margin: 2px;
+ min-height: 80px;
+ position: relative;
+ border-radius: 3px;
+ text-align: center;
+ vertical-align: top;
+}
+.openerp .oe_mail .oe_attachment .oe_name{
+ display: inline-block;
+ max-width: 100%;
+ padding: 1px 3px;
+ margin-top: 50px;
+ margin-bottom: 5px;
+ background: rgba(124, 123, 173, 0.13);
+ overflow: hidden;
+ color: #4c4c4c;
+ text-shadow: none;
+ border-radius: 3px;
+}
+
+.openerp .oe_mail .oe_attachment.oe_preview{
+ background: url( data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJ0lEQVQYV2MsLS39z4AGLCws0IUYGIeCwrVr12J45sSJE5ieGQIKAbuZKf/EMCs7AAAAAElFTkSuQmCC );
+}
+.openerp .oe_mail .oe_attachment .oe_progress_bar{
+ display: none;
+ position: absolute;
+ top: 18px;
+ left: 16px;
+ right: 16px;
+ height: 17px;
+ line-height: 13px;
+ padding: 0px;
+ background: #4BBD00;
+ color: white;
+ text-align: center;
+ border-radius: 3px;
+ border: solid 1px rgba(0,0,0,0.2);
+ box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.34);
+ -webkit-animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+ -moz-animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+ -o-animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+ animation: oe_mail_attach_loading_anim 0.75s infinite linear;
+}
+.openerp .oe_mail .oe_attachment.oe_uploading .oe_progress_bar{
+ display: block;
+}
+@-webkit-keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
+}
+@-moz-keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
+}
+@-o-keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
+}
+@keyframes oe_mail_attach_loading_anim{
+ 0% { background: #4BBD00 }
+ 50% { background: #009123 }
+ 100% { background: #4BBD00 }
+}
+.openerp .oe_mail .oe_attachment.oe_preview .oe_name{
+ position: absolute;
+ bottom: 0px;
+ margin: 0px;
+ left: 0px;
+ right: 0px;
+ max-height: 64px;
+ background: rgba(0,0,0,0.8);
+ color: white;
+ border-top-left-radius: 0px;
+ border-top-right-radius: 0px;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+}
+.openerp .oe_mail .oe_attachment.oe_preview:hover .oe_name{
+ opacity: 1;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+}
+.openerp .oe_mail .oe_attachment img{
+ position: absolute;
+ width: 48px;
+ height: 48px;
+ top: 0px;
+ left: 50%;
+ margin-left: -24px;
+}
+.openerp .oe_mail .oe_attachment.oe_preview img{
+ display: block;
+ position: relative;
+ margin:0px;
+ width: 100px;
+ height: 100px;
+ border-radius: 3px;
+ margin-left: -50px;
+}
+.openerp .oe_mail .oe_attachment .oe_delete{
+ display: none;
+}
+.openerp .oe_mail .oe_msg_composer .oe_attachment .oe_delete{
+ display: block;
+ position: absolute;
+ top: -7px;
+ right: 0px;
+ color: black;
+ text-shadow: 1px 0px white, -1px 0px white, 0px 1px white, 0px -1px white;
+ cursor: pointer;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+}
+.openerp .oe_mail .oe_msg_composer .oe_attachment:hover .oe_delete{
+ opacity: 1;
+ -webkit-transition: opacity 0.2s linear;
+ -moz-transition: opacity 0.2s linear;
+ -o-transition: opacity 0.2s linear;
+ transition: opacity 0.2s linear;
+}
/* ---------------- MESSAGE QUICK COMPOSER --------------- */
.openerp .oe_mail .oe_msg_composer .oe_msg_footer{
@@ -178,37 +361,6 @@
padding-top: 2px;
padding-bottom:6px;
}
-.openerp .oe_mail .oe_msg_attachments.oe_hidden,
-.openerp .oe_mail .oe_msg_images.oe_hidden{
- margin:0px;
- border: none;
- display: none;
-}
-.openerp .oe_mail .oe_msg_attachments{
- margin-bottom: 4px;
- margin-right: 0px;
- font-size: 12px;
- border-radius: 2px;
- border: solid 1px rgba(124,123,173,0.14);
-}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment{
- padding: 2px;
- padding-left: 4px;
- padding-right: 4px;
-}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment .oe_e{
- font-size: 23px;
- margin-top: -5px;
-}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment .oe_e:hover{
- text-decoration: none;
-}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment:nth-child(odd){
- background:white;
-}
-.openerp .oe_mail .oe_msg_attachments .oe_attachment:nth-child(even){
- background: #F4F5FA;
-}
.openerp .oe_mail .oe_msg_images {
display: block;
}
@@ -269,6 +421,7 @@
.openerp .oe_mail .oe_msg_content.oe_msg_more_message{
text-align: right;
+ cursor: pointer;
}
.openerp .oe_mail .oe_msg_content.oe_msg_more_message .oe_separator{
height: 0;
@@ -280,7 +433,7 @@
}
.openerp .oe_mail .oe_msg_more_message .oe_msg_fetch_more {
background: white;
- margin-right: 280px;
+ margin-right: 210px;
padding-left: 8px;
padding-right: 8px;
text-decoration: none;
@@ -298,6 +451,7 @@
padding-top: 5px;
width: 160px;
float: right;
+ margin-right: 16px;
}
/* a) THE FOLLOW BUTTON */
@@ -308,9 +462,22 @@
width:100%;
}
.openerp .oe_followers button.oe_follower.oe_following{
+ color: white;
background-color: #3465A4;
background-image: -webkit-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -moz-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -ms-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -o-linear-gradient(top, #729FCF, #3465A4);
+ background-image: linear-gradient(to bottom, #729FCF, #3465A4);
+}
+.openerp .oe_followers button.oe_follower.oe_following:hover{
color: white;
+ background-color: #A21A1A;
+ background-image: -webkit-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: -moz-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: -ms-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: -o-linear-gradient(top, #DF3F3F, #A21A1A);
+ background-image: linear-gradient(to bottom, #DF3F3F, #A21A1A);
}
.openerp .oe_followers button.oe_follower .oe_follow,
@@ -371,12 +538,17 @@
.openerp .oe_record_thread{
display: block;
- margin-right: 180px;
+ margin-left: 16px;
+ margin-right: 212px;
}
/* ----------- INBOX INTEGRATION ----------- */
.openerp .oe_mail_wall .oe_mail{
margin: 16px;
- width: 720px;
+ width: 600px;
+}
+
+.openerp .oe_mail .oe_view_nocontent > p {
+ padding-left: 15px;
}
diff --git a/addons/mail/static/src/css/mail_group.css b/addons/mail/static/src/css/mail_group.css
index b700cb8c80f..3146247c1bc 100644
--- a/addons/mail/static/src/css/mail_group.css
+++ b/addons/mail/static/src/css/mail_group.css
@@ -68,30 +68,31 @@
min-height: 120px;
}
-.oe_group_details a, .oe_group_details a:hover {
- font-weight: bold;
- color: #4c4c4c;
-}
-
.oe_group_details h4 {
margin: 0;
font-size: 13px;
}
-.oe_group_details h4 a {
- color: #4c4c4c;
-}
-
-.oe_group_details h4 a:hover {
- text-decoration: underline;
-}
-
.oe_group_details ul {
margin: 3px 0 5px;
padding: 0;
list-style: none;
}
-.oe_group_details li {
+.openerp .oe_group_details li {
margin: 2px 0;
}
+
+.openerp .oe_group_button {
+ padding-top: 7px;
+}
+
+.openerp .oe_group_button .oe_group_join {
+ color: white;
+ background-color: #3465A4;
+ background-image: -webkit-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -moz-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -ms-linear-gradient(top, #729FCF, #3465A4);
+ background-image: -o-linear-gradient(top, #729FCF, #3465A4);
+ background-image: linear-gradient(to bottom, #729FCF, #3465A4);
+}
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index 1eb3c29e556..e214168cb25 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -26,7 +26,8 @@ openerp.mail = function (session) {
'default_use_template', 'default_partner_ids', 'default_model',
'default_res_id', 'default_content_subtype', , 'default_subject',
'default_body', 'active_id', 'lang', 'bin_raw', 'tz',
- 'active_model', 'edi_web_url_view', 'active_ids']
+ 'active_model', 'edi_web_url_view', 'active_ids',
+ 'default_attachment_ids']
for (var key in action.context) {
if (_.indexOf(context_keys, key) == -1) {
action.context[key] = null;
@@ -54,8 +55,8 @@ openerp.mail = function (session) {
mail.ChatterUtils = {
/* Get an image in /web/binary/image?... */
- get_image: function (session, model, field, id) {
- return session.prefix + '/web/binary/image?session_id=' + session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '');
+ get_image: function (session, model, field, id, resize) {
+ return session.prefix + '/web/binary/image?session_id=' + session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '') + '&resize=' + (resize ? encodeURIComponent(resize) : '');
},
/* Get the url of an attachment {'id': id} */
@@ -111,10 +112,265 @@ openerp.mail = function (session) {
}
return domain;
- }
+ },
+
+ // inserts zero width space between each letter of a string so that
+ // the word will correctly wrap in html boxes smaller than the text
+ breakword: function(str){
+ var out = '';
+ if (!str) {
+ return str;
+ }
+ for(var i = 0, len = str.length; i < len; i++){
+ out += _.str.escapeHTML(str[i]) + '';
+ }
+ return out;
+ },
+
+ // returns the file type of a file based on its extension
+ // As it only looks at the extension it is quite approximative.
+ filetype: function(url){
+ url = url.filename || url;
+ var tokens = url.split('.');
+ if(tokens.length <= 1){
+ return 'unknown';
+ }
+ var extension = tokens[tokens.length -1];
+ if(extension.length === 0){
+ return 'unknown';
+ }else{
+ extension = extension.toLowerCase();
+ }
+ var filetypes = {
+ 'webimage': ['png','jpg','jpeg','jpe','gif'], // those have browser preview
+ 'image': ['tif','tiff','tga',
+ 'bmp','xcf','psd','ppm','pbm','pgm','pnm','mng',
+ 'xbm','ico','icon','exr','webp','psp','pgf','xcf',
+ 'jp2','jpx','dng','djvu','dds'],
+ 'vector': ['ai','svg','eps','vml','cdr','xar','cgm','odg','sxd'],
+ 'print': ['dvi','pdf','ps'],
+ 'document': ['doc','docx','odm','odt'],
+ 'presentation': ['key','keynote','odp','pps','ppt'],
+ 'font': ['otf','ttf','woff','eot'],
+ 'archive': ['zip','7z','ace','apk','bzip2','cab','deb','dmg','gzip','jar',
+ 'rar','tar','gz','pak','pk3','pk4','lzip','lz','rpm'],
+ 'certificate': ['cer','key','pfx','p12','pem','crl','der','crt','csr'],
+ 'audio': ['aiff','wav','mp3','ogg','flac','wma','mp2','aac',
+ 'm4a','ra','mid','midi'],
+ 'video': ['asf','avi','flv','mkv','m4v','mpeg','mpg','mpe','wmv','mp4','ogm'],
+ 'text': ['txt','rtf','ass'],
+ 'html': ['html','xhtml','xml','htm','css'],
+ 'disk': ['iso','nrg','img','ccd','sub','cdi','cue','mds','mdx'],
+ 'script': ['py','js','c','cc','cpp','cs','h','java','bat','sh',
+ 'd','rb','pl','as','cmd','coffee','m','r','vbs','lisp'],
+ 'spreadsheet': ['123','csv','ods','numbers','sxc','xls','vc','xlsx'],
+ 'binary': ['exe','com','bin','app'],
+ };
+ for(filetype in filetypes){
+ var ext_list = filetypes[filetype];
+ for(var i = 0, len = ext_list.length; i < len; i++){
+ if(extension === ext_list[i]){
+ return filetype;
+ }
+ }
+ }
+ return 'unknown';
+ },
+
};
+ /**
+ * ------------------------------------------------------------
+ * MessageCommon
+ * ------------------------------------------------------------
+ *
+ * Common base for expandables, chatter messages and composer. It manages
+ * the various variables common to those models.
+ */
+
+ mail.MessageCommon = session.web.Widget.extend({
+
+ /**
+ * ------------------------------------------------------------
+ * FIXME: this comment was moved as is from the ThreadMessage Init as
+ * part of a refactoring. Check that it is still correct
+ * ------------------------------------------------------------
+ * This widget handles the display of a messages in a thread.
+ * Displays a record and performs some formatting on the record :
+ * - record.date: formatting according to the user timezone
+ * - record.timerelative: relative time givein by timeago lib
+ * - record.avatar: image url
+ * - record.attachment_ids[].url: url of each attachmentThe
+ * thread view :
+ * - root thread
+ * - - sub message (parent_id = root message)
+ * - - - sub thread
+ * - - - - sub sub message (parent id = sub thread)
+ * - - sub message (parent_id = root message)
+ * - - - sub thread
+ */
+
+ init: function (parent, datasets, options) {
+ this._super(parent, options);
+
+ // record options
+ this.options = datasets.options || options || {};
+ // record domain and context
+ this.domain = datasets.domain || options.domain || [];
+ this.context = _.extend({
+ default_model: false,
+ default_res_id: 0,
+ default_parent_id: false }, options.context || {});
+
+ // data of this message
+ this.id = datasets.id || false,
+ this.last_id = this.id,
+ this.model = datasets.model || this.context.default_model || false,
+ this.res_id = datasets.res_id || this.context.default_res_id || false,
+ this.parent_id = datasets.parent_id || false,
+ this.type = datasets.type || false,
+ this.is_author = datasets.is_author || false,
+ this.is_private = datasets.is_private || false,
+ this.subject = datasets.subject || false,
+ this.name = datasets.name || false,
+ this.record_name = datasets.record_name || false,
+ this.body = datasets.body || false,
+ this.vote_nb = datasets.vote_nb || 0,
+ this.has_voted = datasets.has_voted || false,
+ this.is_favorite = datasets.is_favorite || false,
+ this.thread_level = datasets.thread_level || 0,
+ this.to_read = datasets.to_read || false,
+ this.author_id = datasets.author_id || false,
+ this.attachment_ids = datasets.attachment_ids || [],
+ this.partner_ids = datasets.partner_ids || [];
+ this._date = datasets.date;
+
+ this.format_data();
+
+ // record options and data
+ this.show_record_name = this.record_name && !this.thread_level && this.model != 'res.partner';
+ this.options.show_read = false;
+ this.options.show_unread = false;
+ if (this.options.show_read_unread_button) {
+ if (this.options.read_action == 'read') this.options.show_read = true;
+ else if (this.options.read_action == 'unread') this.options.show_unread = true;
+ else {
+ this.options.show_read = this.to_read;
+ this.options.show_unread = !this.to_read;
+ this.options.rerender = true;
+ this.options.toggle_read = true;
+ }
+ }
+ this.parent_thread = parent.messages != undefined ? parent : this.options.root_thread;
+ this.thread = false;
+ },
+
+ /* Convert date, timerelative and avatar in displayable data. */
+ format_data: function () {
+
+ //formating and add some fields for render
+ if (this._date) {
+ this.date = session.web.format_value(this._date, {type:"datetime"});
+ this.timerelative = $.timeago(this.date);
+ }
+ if (this.type == 'email' && (!this.author_id || !this.author_id[0])) {
+ this.avatar = ('/mail/static/src/img/email_icon.png');
+ } else if (this.author_id && this.template != 'mail.compose_message') {
+ this.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.author_id[0]);
+ } else {
+ this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
+ }
+
+ },
+
+
+ /* upload the file on the server, add in the attachments list and reload display
+ */
+ display_attachments: function () {
+ for (var l in this.attachment_ids) {
+ var attach = this.attachment_ids[l];
+ if (!attach.formating) {
+ attach.url = mail.ChatterUtils.get_attachment_url(this.session, attach);
+ attach.filetype = mail.ChatterUtils.filetype(attach.filename);
+ attach.name = mail.ChatterUtils.breakword(attach.name || attach.filename);
+ attach.formating = true;
+ }
+ }
+ this.$(".oe_msg_attachment_list").html( session.web.qweb.render('mail.thread.message.attachments', {'widget': this}) );
+ },
+
+ /* return the link to resized image
+ */
+ attachments_resize_image: function (id, resize) {
+ return mail.ChatterUtils.get_image(this.session, 'ir.attachment', 'datas', id, resize);
+ },
+
+ /* get all child message id linked.
+ * @return array of id
+ */
+ get_child_ids: function () {
+ return _.map(this.get_childs(), function (val) { return val.id; });
+ },
+
+ /* get all child message linked.
+ * @return array of message object
+ */
+ get_childs: function (nb_thread_level) {
+ var res=[];
+ if (arguments[1] && this.id) res.push(this);
+ if ((isNaN(nb_thread_level) || nb_thread_level>0) && this.thread) {
+ _(this.thread.messages).each(function (val, key) {
+ res = res.concat( val.get_childs((isNaN(nb_thread_level) ? undefined : nb_thread_level-1), true) );
+ });
+ }
+ return res;
+ },
+
+ /**
+ * search a message in all thread and child thread.
+ * This method return an object message.
+ * @param {object}{int} option.id
+ * @param {object}{string} option.model
+ * @param {object}{boolean} option._go_thread_wall
+ * private for check the top thread
+ * @return thread object
+ */
+ browse_message: function (options) {
+ // goto the wall thread for launch browse
+ if (!options._go_thread_wall) {
+ options._go_thread_wall = true;
+ for (var i in this.options.root_thread.messages) {
+ var res=this.options.root_thread.messages[i].browse_message(options);
+ if (res) return res;
+ }
+ }
+
+ if (this.id==options.id)
+ return this;
+
+ for (var i in this.thread.messages) {
+ if (this.thread.messages[i].thread) {
+ var res=this.thread.messages[i].browse_message(options);
+ if (res) return res;
+ }
+ }
+
+ return false;
+ },
+
+ /**
+ * call on_message_delete on his parent thread
+ */
+ destroy: function () {
+
+ this._super();
+ this.parent_thread.on_message_detroy(this);
+
+ }
+
+ });
+
/**
* ------------------------------------------------------------
* ComposeMessage widget
@@ -126,7 +382,7 @@ openerp.mail = function (session) {
* When the user focuses the textarea, the compose message is instantiated.
*/
- mail.ThreadComposeMessage = session.web.Widget.extend({
+ mail.ThreadComposeMessage = mail.MessageCommon.extend({
template: 'mail.compose_message',
/**
@@ -138,45 +394,22 @@ openerp.mail = function (session) {
*/
init: function (parent, datasets, options) {
- var self = this;
- this._super(parent);
- this.context = options.context || {};
- this.options = options.options;
-
+ this._super(parent, datasets, options);
this.show_compact_message = false;
-
- // data of this compose message
- this.attachment_ids = [];
- this.id = datasets.id;
- this.model = datasets.model;
- this.res_model = datasets.res_model;
- this.is_private = datasets.is_private || false;
- this.partner_ids = datasets.partner_ids || [];
- this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
- this.thread_level = datasets.thread_level;
- this.parent_thread= parent.messages!= undefined ? parent : false;
-
- this.ds_attachment = new session.web.DataSetSearch(this, 'ir.attachment');
this.show_delete_attachment = true;
-
- this.fileupload_id = _.uniqueId('oe_fileupload_temp');
- $(window).on(self.fileupload_id, self.on_attachment_loaded);
},
start: function () {
+ this._super.apply(this, arguments);
+
+ this.ds_attachment = new session.web.DataSetSearch(this, 'ir.attachment');
+ this.fileupload_id = _.uniqueId('oe_fileupload_temp');
+ $(window).on(this.fileupload_id, this.on_attachment_loaded);
+
this.display_attachments();
this.bind_events();
},
- /* upload the file on the server, add in the attachments list and reload display
- */
- display_attachments: function () {
- this.$(".oe_msg_attachment_list").html(
- session.web.qweb.render('mail.thread.message.attachments', {'widget': this}) );
- // event: delete an attachment
- this.$(".oe_msg_attachment_list").on('click', '.oe_mail_attachment_delete', this.on_attachment_delete);
- },
-
/* when a user click on the upload button, send file read on_attachment_loaded
*/
on_attachment_change: function (event) {
@@ -263,24 +496,31 @@ openerp.mail = function (session) {
this.$('textarea.oe_compact').on('focus', _.bind( this.on_compose_expandable, this));
// set the function called when attachments are added
- this.$el.on('change', 'input.oe_form_binary_file', _.bind( this.on_attachment_change, this) );
+ this.$('input.oe_form_binary_file').on('change', _.bind( this.on_attachment_change, this) );
- this.$el.on('click', '.oe_cancel', _.bind( this.on_cancel, this) );
- this.$el.on('click', '.oe_post', _.bind( this.on_message_post, this) );
- this.$el.on('click', '.oe_full', _.bind( this.on_compose_fullmail, this, 'reply') );
+ this.$('.oe_cancel').on('click', _.bind( this.on_cancel, this) );
+ this.$('.oe_post').on('click', _.bind( this.on_message_post, this) );
+ this.$('.oe_full').on('click', _.bind( this.on_compose_fullmail, this, this.id ? 'reply' : 'comment') );
/* stack for don't close the compose form if the user click on a button */
- this.$el.on('mousedown', '.oe_msg_footer', _.bind( function () { this.stay_open = true; }, this));
- this.$('textarea:not(.oe_compact):first').on('focus, mouseup, keydown', _.bind( function () { this.stay_open = false; }, this));
- this.$('textarea:not(.oe_compact):first').autosize();
+ this.$('.oe_msg_footer').on('mousedown', _.bind( function () { this.stay_open = true; }, this));
+ var ev_stay = {};
+ ev_stay.mouseup = ev_stay.keydown = ev_stay.focus = function () { self.stay_open = false; };
+ this.$('textarea:not(.oe_compact)').on(ev_stay);
+ this.$('textarea:not(.oe_compact)').autosize();
// auto close
- this.$el.on('blur', 'textarea:not(.oe_compact):first', _.bind( this.on_compose_expandable, this));
+ this.$('textarea:not(.oe_compact)').on('blur', _.bind( this.on_compose_expandable, this));
+
+ // event: delete child attachments off the oe_msg_attachment_list box
+ this.$(".oe_msg_attachment_list").on('click', '.oe_delete', this.on_attachment_delete);
},
on_compose_fullmail: function (default_composition_mode) {
if (default_composition_mode == 'reply') {
var context = {
+ 'default_model': this.context.default_model,
+ 'default_res_id': this.context.default_res_id,
'default_composition_mode': default_composition_mode,
'default_parent_id': this.id,
'default_body': mail.ChatterUtils.get_text2html(this.$el ? (this.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
@@ -357,10 +597,15 @@ openerp.mail = function (session) {
this.context.default_parent_id,
attachments,
this.parent_thread.context
- ]).then(function (record) {
+ ]).done(function (record) {
var thread = self.parent_thread;
+
+ if (self.options.display_indented_thread < self.thread_level && thread.parent_message) {
+ thread = thread.parent_message.parent_thread;
+ }
// create object and attach to the thread object
- thread.message_fetch(false, false, [record], function (arg, data) {
+ thread.message_fetch([['id', 'child_of', [self.id]]], false, [record], function (arg, data) {
+ data[0].no_sorted = true;
var message = thread.create_message_object( data[0] );
// insert the message on dom
thread.insert_message( message, self.$el );
@@ -419,30 +664,16 @@ openerp.mail = function (session) {
* - - visible message
* - - expandable
*/
- mail.ThreadExpandable = session.web.Widget.extend({
+ mail.ThreadExpandable = mail.MessageCommon.extend({
template: 'mail.thread.expandable',
- init: function (parent, datasets, context) {
- this._super(parent);
- this.domain = datasets.domain || [];
- this.options = datasets.options;
- this.context = _.extend({
- default_model: 'mail.thread',
- default_res_id: 0,
- default_parent_id: false }, context || {});
-
- // data of this expandable message
- this.id = datasets.id || -1,
- this.model = datasets.model || false,
- this.parent_id = datasets.parent_id || false,
- this.nb_messages = datasets.nb_messages || 0,
- this.thread_level = datasets.thread_level || 0,
- this.type = 'expandable',
- this.max_limit = this.id < 0 || false,
- this.flag_used = false,
- this.parent_thread= parent.messages!= undefined ? parent : this.options._parents[0];
+ init: function (parent, datasets, options) {
+ this._super(parent, datasets, options);
+ this.type = 'expandable';
+ this.max_limit = datasets.max_limit;
+ this.nb_messages = datasets.nb_messages;
+ this.flag_used = false;
},
-
start: function () {
this._super.apply(this, arguments);
@@ -460,7 +691,7 @@ openerp.mail = function (session) {
* Bind events in the widget. Each event is slightly described
* in the function. */
bind_events: function () {
- this.$el.on('click', 'a.oe_msg_fetch_more', this.on_expandable);
+ this.$('.oe_msg_more_message').on('click', this.on_expandable);
},
animated_destroy: function (fadeTime) {
@@ -480,154 +711,36 @@ openerp.mail = function (session) {
}
this.flag_used = true;
- this.animated_destroy(200);
- this.parent_thread.message_fetch(this.domain, this.context);
+ var self = this;
+
+ // read messages
+ self.parent_thread.message_fetch(this.domain, this.context, false, function (arg, data) {
+ // insert the message on dom after this message
+ self.id = false;
+ self.parent_thread.switch_new_message( data, self.$el );
+ self.animated_destroy(200);
+ });
+
return false;
},
- /**
- * call on_message_delete on his parent thread
- */
- destroy: function () {
-
- this._super();
- this.parent_thread.on_message_detroy(this);
-
- }
});
- /**
- * ------------------------------------------------------------
- * Thread Message Widget
- * ------------------------------------------------------------
- * This widget handles the display of a messages in a thread.
- * Displays a record and performs some formatting on the record :
- * - record.date: formatting according to the user timezone
- * - record.timerelative: relative time givein by timeago lib
- * - record.avatar: image url
- * - record.attachment_ids[].url: url of each attachmentThe
- * thread view :
- * - root thread
- * - - sub message (parent_id = root message)
- * - - - sub thread
- * - - - - sub sub message (parent id = sub thread)
- * - - sub message (parent_id = root message)
- * - - - sub thread
- */
- mail.ThreadMessage = session.web.Widget.extend({
+ mail.ThreadMessage = mail.MessageCommon.extend({
template: 'mail.thread.message',
- /**
- * @param {Object} parent parent
- * @param {Array} [domain]
- * @param {Object} [context] context of the thread. It should
- contain at least default_model, default_res_id. Please refer to
- the ComposeMessage widget for more information about it.
- * @param {Object} [options]
- * @param {Object} [thread] read obout mail.Thread object
- * @param {Object} [message]
- * @param {Number} [truncate_limit=250] number of character to
- * display before having a "show more" link; note that the text
- * will not be truncated if it does not have 110% of the parameter
- * @param {Boolean} [show_record_name]
- *... @param {int} [show_reply_button] number thread level to display the reply button
- *... @param {int} [show_read_unread_button] number thread level to display the read/unread button
- */
- init: function (parent, datasets, context) {
- this._super(parent);
-
- // record domain and context
- this.domain = datasets.domain || [];
- this.context = _.extend({
- default_model: 'mail.thread',
- default_res_id: 0,
- default_parent_id: false }, context || {});
-
- // record options
- this.options = datasets.options;
-
- // data of this message
- this.id = datasets.id || -1,
- this.model = datasets.model || false,
- this.parent_id = datasets.parent_id || false,
- this.res_id = datasets.res_id || false,
- this.type = datasets.type || false,
- this.is_author = datasets.is_author || false,
- this.is_private = datasets.is_private || false,
- this.subject = datasets.subject || false,
- this.name = datasets.name || false,
- this.record_name = datasets.record_name || false,
- this.body = datasets.body || false,
- this.vote_nb = datasets.vote_nb || 0,
- this.has_voted = datasets.has_voted || false,
- this.is_favorite = datasets.is_favorite || false,
- this.thread_level = datasets.thread_level || 0,
- this.to_read = datasets.to_read || false,
- this.author_id = datasets.author_id || [],
- this.attachment_ids = datasets.attachment_ids || [],
- this._date = datasets.date;
-
-
- this.show_reply_button = this.options.show_compose_message && this.options.show_reply_button > this.thread_level;
- this.show_read_unread_button = this.options.show_read_unread_button > this.thread_level;
-
- // record options and data
- this.parent_thread= parent.messages!= undefined ? parent : this.options._parents[0];
- this.thread = false;
-
- if ( this.id > 0 ) {
- this.formating_data();
- }
-
- this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification');
- this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
- this.ds_follow = new session.web.DataSetSearch(this, 'mail.followers');
- },
-
- /* Convert date, timerelative and avatar in displayable data. */
- formating_data: function () {
-
- //formating and add some fields for render
- this.date = session.web.format_value(this._date, {type:"datetime"});
- this.timerelative = $.timeago(this.date);
- if (this.type == 'email') {
- this.avatar = ('/mail/static/src/img/email_icon.png');
- } else {
- this.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.author_id[0]);
- }
- for (var l in this.attachment_ids) {
- var attach = this.attachment_ids[l];
- attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach);
-
- if ((attach.filename || attach.name).match(/[.](jpg|jpg|gif|png|tif|svg)$/i)) {
- attach.is_image = true;
- attach['url'] = mail.ChatterUtils.get_image(this.session, 'ir.attachment', 'datas', attach.id);
- }
- }
- },
start: function () {
this._super.apply(this, arguments);
this.expender();
- this.$el.hide().fadeIn(750, function () {$(this).css('display', '');});
- this.resize_img();
this.bind_events();
if(this.thread_level < this.options.display_indented_thread) {
this.create_thread();
}
this.$('.oe_msg_attachments, .oe_msg_images').addClass("oe_hidden");
- },
- resize_img: function () {
- var resize = function () {
- var h = $(this).height();
- var w = $(this).width();
- if ( h > 100 || w >100 ) {
- var ratio = 100 / (h > w ? h : w);
- $(this).attr("width", parseInt( w*ratio )).attr("height", parseInt( h*ratio ));
- }
- };
- this.$("img").load(resize).each(resize);
+ this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification');
+ this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
},
/**
@@ -635,30 +748,15 @@ openerp.mail = function (session) {
* in the function. */
bind_events: function () {
var self = this;
+ // header icons bindings
+ this.$('.oe_read').on('click', this.on_message_read);
+ this.$('.oe_unread').on('click', this.on_message_unread);
+ this.$('.oe_msg_delete').on('click', this.on_message_delete);
+ this.$('.oe_reply').on('click', this.on_message_reply);
+ this.$('.oe_star').on('click', this.on_star);
+ this.$('.oe_msg_vote').on('click', this.on_vote);
+ this.$('.oe_view_attachments').on('click', this.on_view_attachments);
- // event: click on 'Attachment(s)' in msg
- this.$('.oe_mail_msg_view_attachments').on('click', function (event) {
- var attach = self.$('.oe_msg_attachments:first, .oe_msg_images:first');
- if ( self.$('.oe_msg_attachments:first').hasClass("oe_hidden") ) {
- attach.removeClass("oe_hidden");
- } else {
- attach.addClass("oe_hidden");
- }
- self.resize_img();
- });
- // event: click on icone 'Read' in header
- this.$el.on('click', '.oe_read', this.on_message_read_unread);
- // event: click on icone 'UnRead' in header
- this.$el.on('click', '.oe_unread', this.on_message_read_unread);
- // event: click on 'Delete' in msg side menu
- this.$el.on('click', '.oe_msg_delete', this.on_message_delete);
-
- // event: click on 'Reply' in msg
- this.$el.on('click', '.oe_reply', this.on_message_reply);
- // event: click on 'Vote' button
- this.$el.on('click', '.oe_msg_vote', this.on_vote);
- // event: click on 'starred/favorite' button
- this.$el.on('click', '.oe_star', this.on_star);
},
/* Call the on_compose_message on the thread of this message. */
@@ -673,7 +771,7 @@ openerp.mail = function (session) {
this.$('.oe_msg_body:first').expander({
slicePoint: this.options.truncate_limit,
expandText: 'read more',
- userCollapseText: '[^]',
+ userCollapseText: 'read less',
detailClass: 'oe_msg_tail',
moreClass: 'oe_mail_expand',
lessClass: 'oe_mail_reduce',
@@ -717,6 +815,17 @@ openerp.mail = function (session) {
}
},
+ /* Call the on_compose_message on the thread of this message. */
+ on_view_attachments:function (event) {
+ event.stopPropagation();
+ var self = this;
+ if (!this.toggle_attachment) {
+ self.display_attachments();
+ this.toggle_attachment = true;
+ }
+ this.$('.oe_msg_attachment_list').toggle(200);
+ },
+
/**
* Wait a confirmation for delete the message on the DB.
* Make an animate destroy
@@ -732,81 +841,90 @@ openerp.mail = function (session) {
return false;
},
+ /* Check if the message must be destroy and detroy it or check for re render widget
+ * @param {callback} apply function
+ */
+ check_for_rerender: function () {
+ var self = this;
+
+ var messages = [this].concat(this.get_childs());
+ var message_ids = _.map(messages, function (msg) { return msg.id;});
+ var domain = mail.ChatterUtils.expand_domain( this.options.root_thread.domain )
+ .concat([["id", "in", message_ids ]]);
+
+ return this.parent_thread.ds_message.call('message_read', [undefined, domain, [], !!this.parent_thread.options.display_indented_thread, this.context, this.parent_thread.id])
+ .then( function (records) {
+ // remove message not loaded
+ _.map(messages, function (msg) {
+ if(!_.find(records, function (record) { return record.id == msg.id; })) {
+ msg.animated_destroy(150);
+ } else {
+ msg.renderElement();
+ msg.start()
+ }
+ });
+
+ });
+ },
+
+ on_message_read: function (event) {
+ event.stopPropagation();
+ this.on_message_read_unread(true);
+ return false;
+ },
+
+ on_message_unread: function (event) {
+ event.stopPropagation();
+ this.on_message_read_unread(false);
+ return false;
+ },
+
/*The selected thread and all childs (messages/thread) became read
* @param {object} mouse envent
*/
- on_message_read_unread: function (event) {
- event.stopPropagation();
- var self=this;
+ on_message_read_unread: function (read_value) {
+ var self = this;
+ var messages = [this].concat(this.get_childs());
- if ( (this.to_read && this.options.typeof_thread == 'inbox') ||
- (!this.to_read && this.options.typeof_thread == 'archives')) {
- this.animated_destroy(150);
- }
-
- // if this message is read, all childs message display is read
- this.ds_notification.call('set_message_read', [ [this.id].concat( this.get_child_ids() ) , this.to_read, this.context]).pipe(function () {
- self.$el.removeClass(self.to_read ? 'oe_msg_unread':'oe_msg_read').addClass(self.to_read ? 'oe_msg_read':'oe_msg_unread');
- self.to_read = !self.to_read;
- });
- return false;
- },
-
- /**
- * search a message in all thread and child thread.
- * This method return an object message.
- * @param {object}{int} option.id
- * @param {object}{string} option.model
- * @param {object}{boolean} option._go_thread_wall
- * private for check the top thread
- * @return thread object
- */
- browse_message: function (options) {
- // goto the wall thread for launch browse
- if (!options._go_thread_wall) {
- options._go_thread_wall = true;
- for (var i in this.options._parents[0].messages) {
- var res=this.options._parents[0].messages[i].browse_message(options);
- if (res) return res;
- }
- }
-
- if (this.id==options.id)
- return this;
-
- for (var i in this.thread.messages) {
- if (this.thread.messages[i].thread) {
- var res=this.thread.messages[i].browse_message(options);
- if (res) return res;
+ // inside the inbox, when the user mark a message as read/done, don't apply this value
+ // for the stared/favorite message
+ if (this.options.view_inbox && read_value) {
+ var messages = _.filter(messages, function (val) { return !val.is_favorite && val.id; });
+ if (!messages.length) {
+ this.check_for_rerender();
+ return false;
}
}
+ var message_ids = _.map(messages, function (val) { return val.id; });
+ this.ds_notification.call('set_message_read', [message_ids, read_value, this.context])
+ .then(function () {
+ // apply modification
+ _.each(messages, function (msg) {
+ msg.to_read = !read_value;
+ if (msg.options.toggle_read) {
+ msg.options.show_read = msg.to_read;
+ msg.options.show_unread = !msg.to_read;
+ }
+ });
+ // check if the message must be display, destroy or rerender
+ self.check_for_rerender();
+ });
return false;
},
- /* get all child message id linked.
- * @return array of id
- */
- get_child_ids: function () {
- var res=[]
- if (arguments[0]) res.push(this.id);
- if (this.thread) {
- res = res.concat( this.thread.get_child_ids(true) );
- }
- return res;
- },
-
/**
* add or remove a vote for a message and display the result
*/
on_vote: function (event) {
event.stopPropagation();
- var self=this;
- return this.ds_message.call('vote_toggle', [[self.id]]).pipe(function (vote) {
- self.has_voted = vote;
- self.vote_nb += self.has_voted ? 1 : -1;
- self.display_vote();
- });
+ this.ds_message.call('vote_toggle', [[this.id]])
+ .then(
+ _.bind(function (vote) {
+ this.has_voted = vote;
+ this.vote_nb += this.has_voted ? 1 : -1;
+ this.display_vote();
+ }, this));
return false;
},
@@ -814,10 +932,10 @@ openerp.mail = function (session) {
* Display the render of this message's vote
*/
display_vote: function () {
- var self = this;
- var vote_element = session.web.qweb.render('mail.thread.message.vote', {'widget': self});
- self.$(".oe_msg_vote:first").remove();
- self.$(".oe_mail_vote_count:first").replaceWith(vote_element);
+ var vote_element = session.web.qweb.render('mail.thread.message.vote', {'widget': this});
+ this.$(".oe_msg_footer:first .oe_mail_vote_count").remove();
+ this.$(".oe_msg_footer:first .oe_msg_vote").replaceWith(vote_element);
+ this.$('.oe_msg_vote').on('click', this.on_vote);
},
/**
@@ -827,34 +945,29 @@ openerp.mail = function (session) {
event.stopPropagation();
var self=this;
var button = self.$('.oe_star:first');
- return this.ds_message.call('favorite_toggle', [[self.id]]).pipe(function (star) {
- self.is_favorite=star;
- if (self.is_favorite) {
- button.addClass('oe_starred');
- } else {
- button.removeClass('oe_starred');
- if ( self.options.typeof_thread == 'stared' ) {
- self.animated_destroy(150);
+
+ this.ds_message.call('favorite_toggle', [[self.id]])
+ .then(function (star) {
+ self.is_favorite=star;
+ if (self.is_favorite) {
+ button.addClass('oe_starred');
+ } else {
+ button.removeClass('oe_starred');
}
- }
- });
+
+ if (self.options.view_inbox && self.is_favorite) {
+ self.on_message_read_unread(true);
+ } else {
+ self.check_for_rerender();
+ }
+ });
return false;
},
- /**
- * call on_message_delete on his parent thread
- */
- destroy: function () {
-
- this._super();
- this.parent_thread.on_message_detroy(this);
-
- }
-
});
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* Thread Widget
* ------------------------------------------------------------
*
@@ -881,14 +994,11 @@ openerp.mail = function (session) {
* @param {Object} [thread]
* @param {int} [display_indented_thread] number thread level to indented threads.
* other are on flat mode
- * @param {Select} [typeof_thread] inbox/archives/stared/sent
- * type of thread and option for user application like animate
- * destroy for read/unread
* @param {Array} [parents] liked with the parents thread
* use with browse, fetch... [O]= top parent
*/
init: function (parent, datasets, options) {
- this._super(parent);
+ this._super(parent, options);
this.domain = options.domain || [];
this.context = _.extend({
default_model: 'mail.thread',
@@ -896,21 +1006,24 @@ openerp.mail = function (session) {
default_parent_id: false }, options.context || {});
this.options = options.options;
- this.options._parents = (options.options._parents != undefined ? options.options._parents : []).concat( [this] );
-
+ this.options.root_thread = (options.options.root_thread != undefined ? options.options.root_thread : this);
+ this.options.show_compose_message = this.options.show_compose_message && (this.options.display_indented_thread >= this.thread_level || !this.thread_level);
+
// record options and data
this.parent_message= parent.thread!= undefined ? parent : false ;
// data of this thread
this.id = datasets.id || false,
- this.model = datasets.model || false,
+ this.last_id = datasets.last_id || false,
this.parent_id = datasets.parent_id || false,
+
this.is_private = datasets.is_private || false,
this.author_id = datasets.author_id || false,
this.thread_level = (datasets.thread_level+1) || 0,
this.partner_ids = _.filter(datasets.partner_ids, function (partner) { return partner[0]!=datasets.author_id[0]; } )
this.messages = [];
- this.show_compose_message = this.options.show_compose_message && (this.options.show_reply_button > this.thread_level || !this.thread_level);
+
+ this.options.flat_mode = !!(this.options.display_indented_thread > this.thread_level ? this.options.display_indented_thread - this.thread_level : 0);
// object compose message
this.compose_message = false;
@@ -934,13 +1047,10 @@ openerp.mail = function (session) {
'context': this.context,
'options': this.options,
});
- if (!this.thread_level) {
- // root view
+ if (!this.thread_level || this.thread_level > this.options.display_indented_thread) {
this.compose_message.insertBefore(this.$el);
- } else if (this.thread_level > this.options.display_indented_thread) {
- this.compose_message.insertAfter(this.$el);
} else {
- this.compose_message.appendTo(this.$el);
+ this.compose_message.prependTo(this.$el);
}
}
},
@@ -948,21 +1058,20 @@ openerp.mail = function (session) {
/* When the expandable object is visible on screen (with scrolling)
* then the on_expandable function is launch
*/
- on_scroll: function (event) {
- if (event)event.stopPropagation();
- this.$('.oe_msg_expandable:last');
-
- var message = this.messages[this.messages.length-1];
- if (message && message.type=="expandable" && message.max_limit) {
- var pos = message.$el.position();
+ on_scroll: function () {
+ var expandables =
+ _.each( _.filter(this.messages, function (val) {return val.max_limit && !val.parent_id;}), function (val) {
+ var pos = val.$el.position();
if (pos.top) {
/* bottom of the screen */
var bottom = $(window).scrollTop()+$(window).height()+200;
if (bottom > pos.top) {
- message.on_expandable();
+ val.on_expandable();
+ // load only one time
+ val.loading = true;
}
}
- }
+ });
},
/**
@@ -970,8 +1079,8 @@ openerp.mail = function (session) {
* in the function. */
bind_events: function () {
var self = this;
- self.$el.on('click', '.oe_mail_list_recipients .oe_more', self.on_show_recipients);
- self.$el.on('click', '.oe_mail_compose_textarea .oe_more_hidden', self.on_hide_recipients);
+ self.$('.oe_mail_list_recipients .oe_more').on('click', self.on_show_recipients);
+ self.$('.oe_mail_compose_textarea .oe_more_hidden').on('click', self.on_hide_recipients);
},
/**
@@ -981,6 +1090,7 @@ openerp.mail = function (session) {
var p=$(this).parent();
p.find('.oe_more_hidden, .oe_hidden').show();
p.find('.oe_more').hide();
+ return false;
},
/**
@@ -990,15 +1100,14 @@ openerp.mail = function (session) {
var p=$(this).parent();
p.find('.oe_more_hidden, .oe_hidden').hide();
p.find('.oe_more').show();
+ return false;
},
/* get all child message/thread id linked.
* @return array of id
*/
get_child_ids: function () {
- var res=[];
- _(this.get_childs()).each(function (val, key) { res.push(val.id); });
- return res;
+ return _.map(this.get_childs(), function (val) { return val.id; });
},
/* get all child message/thread linked.
@@ -1033,17 +1142,17 @@ openerp.mail = function (session) {
// goto the wall thread for launch browse
if (!options._go_thread_wall) {
options._go_thread_wall = true;
- return this.options._parents[0].browse_thread(options);
+ return this.options.root_thread.browse_thread(options);
}
- if (this.id==options.id) {
+ if (this.id == options.id) {
return this;
}
if (options.id) {
for (var i in this.messages) {
if (this.messages[i].thread) {
- var res=this.messages[i].thread.browse_thread({'id':options.id, '_go_thread_wall':true});
+ var res = this.messages[i].thread.browse_thread({'id':options.id, '_go_thread_wall':true});
if (res) return res;
}
}
@@ -1067,8 +1176,8 @@ openerp.mail = function (session) {
* @return message object
*/
browse_message: function (options) {
- if (this.options._parents[0].messages[0])
- return this.options._parents[0].messages[0].browse_message(options);
+ if (this.options.root_thread.messages[0])
+ return this.options.root_thread.messages[0].browse_message(options);
},
/**
@@ -1079,6 +1188,7 @@ openerp.mail = function (session) {
on_compose_message: function () {
this.instantiate_compose_message();
this.compose_message.on_compose_expandable();
+ return false;
},
/**
@@ -1086,8 +1196,8 @@ openerp.mail = function (session) {
*/
no_message: function () {
var no_message = $(session.web.qweb.render('mail.wall_no_message', {}));
- if (this.options.no_message) {
- no_message.html(this.options.no_message);
+ if (this.options.help) {
+ no_message.html(this.options.help);
}
no_message.appendTo(this.$el);
},
@@ -1101,18 +1211,20 @@ openerp.mail = function (session) {
* @param {Array} ids read (if the are some ids, the method don't use the domain)
*/
message_fetch: function (replace_domain, replace_context, ids, callback) {
- var self = this;
-
- // domain and context: options + additional
- fetch_domain = replace_domain ? replace_domain : this.domain;
- fetch_context = replace_context ? replace_context : this.context;
- var message_loaded_ids = this.id ? [this.id].concat( self.get_child_ids() ) : self.get_child_ids();
-
- // CHM note : option for sending in flat mode by server
- var thread_level = this.options.display_indented_thread > this.thread_level ? this.options.display_indented_thread - this.thread_level : 0;
-
- return this.ds_message.call('message_read', [ids, fetch_domain, message_loaded_ids, thread_level, fetch_context, this.context.default_parent_id || undefined])
- .then(callback ? _.bind(callback, this, arguments) : this.proxy('switch_new_message'));
+ return this.ds_message.call('message_read', [
+ // ids force to read
+ ids == false ? undefined : ids,
+ // domain + additional
+ (replace_domain ? replace_domain : this.domain),
+ // ids allready loaded
+ (this.id ? [this.id].concat( this.get_child_ids() ) : this.get_child_ids()),
+ // option for sending in flat mode by server
+ this.options.flat_mode,
+ // context + additional
+ (replace_context ? replace_context : this.context),
+ // parent_id
+ this.context.default_parent_id || undefined
+ ]).done(callback ? _.bind(callback, this, arguments) : this.proxy('switch_new_message'));
},
/**
@@ -1128,22 +1240,23 @@ openerp.mail = function (session) {
data.options = _.extend(self.options, data.options);
if (data.type=='expandable') {
- var message = new mail.ThreadExpandable(self, data, {
+ var message = new mail.ThreadExpandable(self, data, {'context':{
'default_model': data.model || self.context.default_model,
'default_res_id': data.res_id || self.context.default_res_id,
'default_parent_id': self.id,
- });
+ }});
} else {
- var message = new mail.ThreadMessage(self, data, {
+ var message = new mail.ThreadMessage(self, data, {'context':{
'default_model': data.model,
'default_res_id': data.res_id,
'default_parent_id': data.id,
- });
+ }});
}
// check if the message is already create
for (var i in self.messages) {
if (self.messages[i] && self.messages[i].id == message.id) {
+ console.log('Reload message', message.id);
self.messages[i].destroy();
}
}
@@ -1163,74 +1276,18 @@ openerp.mail = function (session) {
*/
insert_message: function (message, dom_insert_after) {
var self=this;
-
- if (this.show_compose_message && this.options.show_compact_message) {
+ if (this.options.show_compact_message > this.thread_level) {
this.instantiate_compose_message();
this.compose_message.do_show_compact();
}
- this.$('.oe_wall_no_message').remove();
+ this.$('.oe_view_nocontent').remove();
if (dom_insert_after) {
message.insertAfter(dom_insert_after);
- return message
- }
-
- // check older and newer message for insertion
- var message_newer = false;
- var message_older = false;
- if (message.id > 0) {
- for (var i in self.messages) {
- if (self.messages[i].id > message.id) {
- if (!message_newer || message_newer.id > self.messages[i].id) {
- message_newer = self.messages[i];
- }
- } else if (self.messages[i].id > 0 && self.messages[i].id < message.id) {
- if (!message_older || message_older.id < self.messages[i].id) {
- message_older = self.messages[i];
- }
- }
- }
- }
-
- var sort = (!!self.thread_level || message.id<0);
-
- if (sort) {
- if (message_older) {
-
- message.insertAfter(message_older.thread ? (message_older.thread.compose_message ? message_older.thread.compose_message.$el : message_older.thread.$el) : message_older.$el);
-
- } else if (message_newer) {
-
- message.insertBefore(message_newer.$el);
-
- } else if (message.id < 0) {
-
- message.appendTo(self.$el);
-
- } else {
-
- message.prependTo(self.$el);
- }
} else {
- if (message_older) {
-
- message.insertBefore(message_older.$el);
-
- } else if (message_newer) {
-
- message.insertAfter(message_newer.thread ? (message_newer.thread.compose_message ? message_newer.thread.compose_message.$el : message_newer.thread.$el) : message_newer.$el );
-
- } else if (message.id < 0) {
-
- message.prependTo(self.$el);
-
- } else {
-
- message.appendTo(self.$el);
-
- }
+ message.appendTo(self.$el);
}
return message
@@ -1241,7 +1298,7 @@ openerp.mail = function (session) {
* Each message is send to his parent object (or parent thread flat mode) for creating the object message.
* @param : {Array} datas from calling RPC to "message_read"
*/
- switch_new_message: function (records) {
+ switch_new_message: function (records, dom_insert_after) {
var self=this;
_(records).each(function (record) {
var thread = self.browse_thread({
@@ -1251,7 +1308,7 @@ openerp.mail = function (session) {
// create object and attach to the thread object
var message = thread.create_message_object( record );
// insert the message on dom
- thread.insert_message( message );
+ thread.insert_message( message, typeof dom_insert_after == 'object' ? dom_insert_after : false);
});
},
@@ -1262,6 +1319,10 @@ openerp.mail = function (session) {
on_message_detroy: function (message) {
this.messages = _.filter(this.messages, function (val) { return !val.isDestroyed(); });
+ if (this.options.root_thread == this && !this.messages.length) {
+ this.no_message();
+ }
+ return false;
},
@@ -1323,7 +1384,6 @@ openerp.mail = function (session) {
} else {
// create a expandable message
var expandable = new mail.ThreadExpandable(this, {
- 'id': message.id,
'model': message.model,
'parent_id': message.parent_id,
'nb_messages': 1,
@@ -1332,9 +1392,11 @@ openerp.mail = function (session) {
'domain': message_dom,
'options': message.options,
}, {
- 'default_model': message.model || this.context.default_model,
- 'default_res_id': message.res_id || this.context.default_res_id,
- 'default_parent_id': this.id,
+ 'context':{
+ 'default_model': message.model || this.context.default_model,
+ 'default_res_id': message.res_id || this.context.default_res_id,
+ 'default_parent_id': this.id,
+ }
});
// add object on array and DOM
@@ -1350,7 +1412,7 @@ openerp.mail = function (session) {
});
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* mail : root Widget
* ------------------------------------------------------------
*
@@ -1360,7 +1422,7 @@ openerp.mail = function (session) {
*/
session.web.client_actions.add('mail.Widget', 'session.mail.Widget');
mail.Widget = session.web.Widget.extend({
- template: 'mail.Widget',
+ template: 'mail.Root',
/**
* @param {Object} parent parent
@@ -1368,15 +1430,13 @@ openerp.mail = function (session) {
* @param {Object} [context] context of the thread. It should
* contain at least default_model, default_res_id. Please refer to
* the compose_message widget for more information about it.
- * ... @param {Select} [typeof_thread=(mail|stared|archives|send|other)]
- * options for destroy message when the user click on a button
* @param {Object} [options]
*... @param {Number} [truncate_limit=250] number of character to
* display before having a "show more" link; note that the text
* will not be truncated if it does not have 110% of the parameter
*... @param {Boolean} [show_record_name] display the name and link for do action
- *... @param {int} [show_reply_button] number thread level to display the reply button
- *... @param {int} [show_read_unread_button] number thread level to display the read/unread button
+ *... @param {boolean} [show_reply_button] display the reply button
+ *... @param {boolean} [show_read_unread_button] display the read/unread button
*... @param {int} [display_indented_thread] number thread level to indented threads.
* other are on flat mode
*... @param {Boolean} [show_compose_message] allow to display the composer
@@ -1387,35 +1447,25 @@ openerp.mail = function (session) {
* @param {String} [no_message] Message to display when there are no message
*/
init: function (parent, action) {
- var options = action.params || {};
- this._super(parent);
- this.domain = options.domain || [];
- this.context = options.context || {};
- this.search_results = {'domain': [], 'context': {}, 'groupby': {}};
+ this._super(parent, action);
+ var self = this;
+ this.action = _.clone(action);
+ this.domain = this.action.domain || this.action.params.domain || [];
+ this.context = this.action.context || this.action.params.context || {};
- this.options = _.extend({
- 'typeof_thread' : 'inbox',
+ this.action.params = _.extend({
'display_indented_thread' : -1,
- 'show_reply_button' : -1,
- 'show_read_unread_button' : -1,
+ 'show_reply_button' : false,
+ 'show_read_unread_button' : false,
'truncate_limit' : 250,
'show_record_name' : false,
'show_compose_message' : false,
'show_compact_message' : false,
+ 'view_inbox': false,
'message_ids': undefined,
- 'no_message': false
- }, options);
+ }, this.action.params);
- if (this.display_indented_thread === false) {
- this.display_indented_thread = -1;
- }
- if (this.show_reply_button === false) {
- this.show_reply_button = -1;
- }
- if (this.show_read_unread_button === false) {
- this.show_read_unread_button = -1;
- }
-
+ this.action.params.help = this.action.help || false;
},
start: function (options) {
@@ -1423,7 +1473,6 @@ openerp.mail = function (session) {
this.message_render();
this.bind_events();
},
-
/**
*Create the root thread and display this object in the DOM.
@@ -1435,35 +1484,32 @@ openerp.mail = function (session) {
this.thread = new mail.Thread(this, {}, {
'domain' : this.domain,
'context' : this.context,
- 'options': this.options,
+ 'options': this.action.params,
});
this.thread.appendTo( this.$el );
this.thread.no_message();
- this.thread.message_fetch(null, null, this.options.message_ids);
- if (this.options.show_compose_message) {
+ if (this.action.params.show_compose_message) {
this.thread.instantiate_compose_message();
- if (this.options.show_compact_message) {
- this.thread.compose_message.do_show_compact();
- } else {
- this.thread.compose_message.do_hide_compact();
- }
+ this.thread.compose_message.do_show_compact();
}
+
+ this.thread.message_fetch(null, null, this.action.params.message_ids);
+
},
bind_events: function () {
- if (this.context['typeof_thread']!='other') {
- $(document).scroll( this.thread.on_scroll );
- $(window).resize( this.thread.on_scroll );
- window.setTimeout( this.thread.on_scroll, 500 );
- }
+ $(document).scroll( _.bind(this.thread.on_scroll, this.thread) );
+ $(window).resize( _.bind(this.thread.on_scroll, this.thread) );
+ this.$el.resize( _.bind(this.thread.on_scroll, this.thread) );
+ window.setTimeout( _.bind(this.thread.on_scroll, this.thread), 500 );
}
});
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* mail_thread Widget
* ------------------------------------------------------------
*
@@ -1476,10 +1522,19 @@ openerp.mail = function (session) {
mail.RecordThread = session.web.form.AbstractField.extend({
template: 'mail.record_thread',
- init: function () {
+ init: function (parent, node) {
this._super.apply(this, arguments);
- this.options.domain = this.options.domain || [];
- this.options.context = {'default_model': 'mail.thread', 'default_res_id': false};
+ this.node = _.clone(node);
+
+ this.node.params = _.extend({
+ 'display_indented_thread': -1,
+ 'show_reply_button': false,
+ 'show_read_unread_button': false,
+ 'show_compose_message': this.view.is_action_enabled('edit'),
+ 'show_compact_message': 1,
+ }, this.node.params);
+
+ this.domain = this.node.params && this.node.params.domain || [];
},
start: function () {
@@ -1492,42 +1547,32 @@ openerp.mail = function (session) {
_check_visibility: function () {
this.$el.toggle(this.view.get("actual_mode") !== "create");
},
+
render_value: function () {
var self = this;
+
if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
this.$('oe_mail_thread').hide();
return;
}
- // update context
- _.extend(this.options.context, {
- default_res_id: this.view.datarecord.id,
- default_model: this.view.model,
- default_is_private: false });
- // update domain
- var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]);
- var show_compose_message = this.view.is_action_enabled('edit') ||
- (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
-
- var message_ids = this.getParent().fields.message_ids && this.getParent().fields.message_ids.get_value();
+ this.node.params = _.extend({
+ 'message_ids': this.getParent().fields.message_ids ? this.getParent().fields.message_ids.get_value() : undefined,
+ }, this.node.params);
+ this.node.context = {
+ 'default_res_id': this.view.datarecord.id || false,
+ 'default_model': this.view.model || false,
+ };
if (this.root) {
+ $('').insertAfter(this.root.$el);
this.root.destroy();
}
// create and render Thread widget
- this.root = new mail.Widget(this, { params: {
- 'domain' : domain,
- 'context' : this.options.context,
- 'typeof_thread': this.options.context['typeof_thread'] || 'other',
- 'display_indented_thread': -1,
- 'show_reply_button': 0,
- 'show_read_unread_button': -1,
- 'show_compose_message': show_compose_message,
- 'message_ids': message_ids,
- 'show_compact_message': true,
- 'no_message': this.node.attrs.help
- }}
- );
+ this.root = new mail.Widget(this, _.extend(this.node, {
+ 'domain' : (this.domain || []).concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]),
+
+ }));
return this.root.replace(this.$('.oe_mail-placeholder'));
},
@@ -1535,7 +1580,7 @@ openerp.mail = function (session) {
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* Wall Widget
* ------------------------------------------------------------
*
@@ -1543,6 +1588,7 @@ openerp.mail = function (session) {
* use is to receive a context and a domain, and to delegate the message
* fetching and displaying to the Thread widget.
*/
+
session.web.client_actions.add('mail.wall', 'session.mail.Wall');
mail.Wall = session.web.Widget.extend({
template: 'mail.wall',
@@ -1555,35 +1601,53 @@ openerp.mail = function (session) {
* contain default_model, default_res_id, to give it to the threads.
*/
init: function (parent, action) {
- this._super(parent);
- var options = action.params || {};
- this.options = options;
- this.options.domain = options.domain || [];
- this.options.context = options.context || {};
- this.search_results = {'domain': [], 'context': {}, 'groupby': {}}
- this.ds_msg = new session.web.DataSetSearch(this, 'mail.message');
+ this._super(parent, action);
+
+ this.action = _.clone(action);
+ this.domain = this.action.params.domain || this.action.domain || [];
+ this.context = this.action.params.context || this.action.context || {};
+
+ this.defaults = {};
+ for (var key in this.context) {
+ if (key.match(/^search_default_/)) {
+ this.defaults[key.replace(/^search_default_/, '')] = this.context[key];
+ }
+ }
+
+ this.action.params = _.extend({
+ 'display_indented_thread': 1,
+ 'show_reply_button': true,
+ 'show_read_unread_button': true,
+ 'show_compose_message': true,
+ 'show_compact_message': this.action.params.view_mailbox ? false : 1,
+ 'view_inbox': false,
+ }, this.action.params);
},
start: function () {
- this._super.apply(this, arguments);
- var searchview_ready = this.load_searchview({}, false);
- var thread_displayed = this.message_render();
- this.options.domain = this.options.domain.concat(this.search_results['domain']);
+ this._super.apply(this);
this.bind_events();
- return $.when(searchview_ready, thread_displayed);
+ var searchview_loaded = this.load_searchview(this.defaults);
+ if (! this.searchview.has_defaults) {
+ this.message_render();
+ }
+
},
/**
* Load the mail.message search view
* @param {Object} defaults ??
- * @param {Boolean} hidden some kind of trick we do not care here
*/
- load_searchview: function (defaults, hidden) {
+ load_searchview: function (defaults) {
var self = this;
- this.searchview = new session.web.SearchView(this, this.ds_msg, false, defaults || {}, hidden || false);
- return this.searchview.appendTo(this.$('.oe_view_manager_view_search')).then(function () {
- self.searchview.on('search_data', self, self.do_searchview_search);
- });
+ var ds_msg = new session.web.DataSetSearch(this, 'mail.message');
+ this.searchview = new session.web.SearchView(this, ds_msg, false, defaults || {}, false);
+ this.searchview.appendTo(this.$('.oe_view_manager_view_search'))
+ .then(function () { self.searchview.on('search_data', self, self.do_searchview_search); });
+ if (this.searchview.has_defaults) {
+ this.searchview.ready.then(this.searchview.do_search);
+ }
+ return this.searchview
},
/**
@@ -1600,32 +1664,25 @@ openerp.mail = function (session) {
contexts: contexts || [],
group_by_seq: groupbys || []
}).then(function (results) {
- self.search_results['context'] = results.context;
- self.search_results['domain'] = results.domain;
- self.root.destroy();
- return self.message_render();
+ if(self.root) {
+ $('').insertAfter(self.root.$el);
+ self.root.destroy();
+ }
+ return self.message_render(results);
});
},
-
/**
- *Create the root thread widget and display this object in the DOM
- */
+ * Create the root thread widget and display this object in the DOM
+ */
message_render: function (search) {
- var domain = this.options.domain.concat(this.search_results['domain']);
- var context = _.extend(this.options.context, search&&search.search_results['context'] ? search.search_results['context'] : {});
- this.root = new mail.Widget(this, { params: {
+ var domain = this.domain.concat(search && search['domain'] ? search['domain'] : []);
+ var context = _.extend(this.context, search && search['context'] ? search['context'] : {});
+
+ this.root = new mail.Widget(this, _.extend(this.action, {
'domain' : domain,
'context' : context,
- 'typeof_thread': context['typeof_thread'] || 'other',
- 'display_indented_thread': 1,
- 'show_reply_button': 10,
- 'show_read_unread_button': 11,
- 'show_compose_message': true,
- 'show_compact_message': false,
- }}
- );
-
+ }));
return this.root.replace(this.$('.oe_mail-placeholder'));
},
@@ -1653,19 +1710,18 @@ openerp.mail = function (session) {
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* UserMenu
* ------------------------------------------------------------
*
* Add a link on the top user bar for write a full mail
*/
session.web.ComposeMessageTopButton = session.web.Widget.extend({
- template:'mail.compose_message.button_top_bar',
+ template:'mail.ComposeMessageTopButton',
- start: function (parent, params) {
- var self = this;
- this.$el.on('click', 'button', self.on_compose_message );
- this._super(parent, params);
+ start: function () {
+ this.$('button').on('click', this.on_compose_message );
+ this._super();
},
on_compose_message: function (event) {
@@ -1675,26 +1731,22 @@ openerp.mail = function (session) {
res_model: 'mail.compose.message',
view_mode: 'form',
view_type: 'form',
- action_from: 'mail.ThreadComposeMessage',
views: [[false, 'form']],
target: 'new',
- context: {
- 'default_model': '',
- 'default_res_id': false,
- 'default_content_subtype': 'html',
- },
+ context: { 'default_content_subtype': 'html' },
};
session.client.action_manager.do_action(action);
},
-
});
- session.web.UserMenu = session.web.UserMenu.extend({
- start: function (parent, params) {
- var render = new session.web.ComposeMessageTopButton();
- render.insertAfter(this.$el);
- this._super(parent, params);
- }
+ session.web.UserMenu.include({
+ do_update: function(){
+ var self = this;
+ this._super.apply(this, arguments);
+ this.update_promise.then(function() {
+ var mail_button = new session.web.ComposeMessageTopButton();
+ mail_button.appendTo(session.webclient.$el.find('.oe_systray'));
+ });
+ },
});
-
};
diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js
index a13d2048bf3..7bb019cde4f 100644
--- a/addons/mail/static/src/js/mail_followers.js
+++ b/addons/mail/static/src/js/mail_followers.js
@@ -30,6 +30,8 @@ openerp_mail_followers = function(session, mail) {
this.ds_model = new session.web.DataSetSearch(this, this.view.model);
this.ds_follow = new session.web.DataSetSearch(this, this.field.relation);
this.ds_users = new session.web.DataSetSearch(this, 'res.users');
+
+ this.value = [];
},
start: function() {
@@ -41,6 +43,11 @@ openerp_mail_followers = function(session, mail) {
this._super();
},
+ set_value: function(_value) {
+ this.value = _value;
+ this._super(_value);
+ },
+
_check_visibility: function() {
this.$el.toggle(this.view.get("actual_mode") !== "create");
},
@@ -85,22 +92,23 @@ openerp_mail_followers = function(session, mail) {
read_value: function () {
var self = this;
- return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) {
- self.set_value(results[0].message_follower_ids);
+ return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).then(function (results) {
+ self.value = results[0].message_follower_ids;
+ self.render_value();
});
},
render_value: function () {
this.reinit();
- return this.fetch_followers(this.get("value"));
+ return this.fetch_followers(this.value);
},
fetch_followers: function (value_) {
this.value = value_ || {};
return this.ds_follow.call('read', [this.value, ['name', 'user_ids']])
- .pipe(this.proxy('display_followers'), this.proxy('fetch_generic'))
- .pipe(this.proxy('display_buttons'))
- .pipe(this.proxy('fetch_subtypes'));
+ .then(this.proxy('display_followers'), this.proxy('fetch_generic'))
+ .then(this.proxy('display_buttons'))
+ .then(this.proxy('fetch_subtypes'));
},
/** Read on res.partner failed: fall back on a generic case
@@ -109,10 +117,10 @@ openerp_mail_followers = function(session, mail) {
fetch_generic: function (error, event) {
var self = this;
event.preventDefault();
- return this.ds_users.call('read', [this.session.uid, ['partner_id']]).pipe(function (results) {
+ return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) {
var pid = results['partner_id'][0];
- self.message_is_follower = (_.indexOf(self.get('value'), pid) != -1);
- }).pipe(self.proxy('display_generic'));
+ self.message_is_follower = (_.indexOf(self.value, pid) != -1);
+ }).then(self.proxy('display_generic'));
},
_format_followers: function(count){
// TDE note: why redefining _t ?
@@ -131,7 +139,7 @@ openerp_mail_followers = function(session, mail) {
display_generic: function () {
var self = this;
var node_user_list = this.$('.oe_follower_list').empty();
- this.$('.oe_follower_title').html(this._format_followers(this.get('value').length));
+ this.$('.oe_follower_title').html(this._format_followers(this.value.length));
},
/** Display the followers */
@@ -179,7 +187,7 @@ openerp_mail_followers = function(session, mail) {
var subtype_list_ul = this.$('.oe_subtype_list').empty();
if (! this.message_is_follower) return;
var context = new session.web.CompoundContext(this.build_context(), {});
- this.ds_model.call('message_get_subscription_data', [[this.view.datarecord.id], context]).pipe(this.proxy('display_subtypes'));
+ this.ds_model.call('message_get_subscription_data', [[this.view.datarecord.id], context]).then(this.proxy('display_subtypes'));
},
/** Display subtypes: {'name': default, followed} */
@@ -206,7 +214,8 @@ openerp_mail_followers = function(session, mail) {
$(record).attr('checked',false);
});
var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context]).pipe(this.proxy('read_value'));
+ return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context])
+ .then(this.proxy('read_value'));
},
do_update_subscription: function (event) {
@@ -220,8 +229,8 @@ openerp_mail_followers = function(session, mail) {
});
var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], this.message_is_follower ? checklist:undefined, context])
- .pipe(this.proxy('read_value'));
+ return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], this.message_is_follower ? checklist : undefined, context])
+ .then(this.proxy('read_value'));
},
});
};
diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js
index 52dcbf7aeb5..cc701e8a585 100644
--- a/addons/mail/static/src/js/many2many_tags_email.js
+++ b/addons/mail/static/src/js/many2many_tags_email.js
@@ -46,7 +46,7 @@ instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags
["email", "=", false],
["notification_email_send", "in", ['all', 'comment']] ]],
{context: this.build_context()})
- .pipe(function (record_ids) {
+ .then(function (record_ids) {
// valid partner
var valid_partner = _.difference(ids, record_ids);
self.values = self.values.concat(valid_partner);
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index caa85cd3deb..2ba1733043a 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -1,8 +1,9 @@
-
-
+
+
@@ -38,7 +39,8 @@
-
+
+
@@ -69,33 +71,28 @@
Template used to display attachments in a mail.message
-->
-
-
-
-
-
- ...Upload in progress...
-
-
-
-
-
-
-
-
-
- [
-
+
+
+
+
+ [
+
+
+ uploading
+
-
-
-
-
-
-
+
+
+
+ [
+
+
+ uploading
+
+
-
+
@@ -112,7 +109,7 @@
To:
- Everyone
+ Followers
and
@@ -140,22 +137,20 @@
- News Feed
- /
-
+ Email box
|
|
-
@@ -168,7 +163,7 @@
display message on the wall when there are no message
-->
- You have no messages
+ No messages.
-
+
@@ -197,10 +192,11 @@
@@ -208,23 +204,26 @@
-
-
-
@@ -234,11 +233,12 @@
-
+
@@ -247,9 +247,9 @@
mail.compose_message.button_top_bar
render of the button on the user bar for open wizard compose message
-->
-
-
-
+
+
+
@@ -257,12 +257,11 @@
Template used to display Like/Unlike in a mail.message
-->
-
8
-
+
like
unlike
diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py
index 8e880a611a7..aea67dcdc13 100644
--- a/addons/mail/tests/test_mail.py
+++ b/addons/mail/tests/test_mail.py
@@ -576,7 +576,7 @@ class test_mail(TestMailMockups):
cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs
pigs_domain = [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)]
- # Data: create a discussion in Pigs (2 messages, one with 2 and one with 3 answers)
+ # Data: create a discussion in Pigs (3 threads, with respectively 0, 4 and 4 answers)
msg_id0 = self.group_pigs.message_post(body='0', subtype='mt_comment')
msg_id1 = self.group_pigs.message_post(body='1', subtype='mt_comment')
msg_id2 = self.group_pigs.message_post(body='2', subtype='mt_comment')
@@ -588,7 +588,8 @@ class test_mail(TestMailMockups):
msg_id8 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=msg_id4)
msg_id9 = self.group_pigs.message_post(body='1-1-1', subtype='mt_comment', parent_id=msg_id3)
msg_id10 = self.group_pigs.message_post(body='2-1-1', subtype='mt_comment', parent_id=msg_id4)
- msg_ids = [msg_id0, msg_id1, msg_id2, msg_id3, msg_id4, msg_id5, msg_id6, msg_id7, msg_id8, msg_id9, msg_id10]
+ msg_ids = [msg_id10, msg_id9, msg_id8, msg_id7, msg_id6, msg_id5, msg_id4, msg_id3, msg_id2, msg_id1, msg_id0]
+ ordered_msg_ids = [msg_id2, msg_id4, msg_id6, msg_id8, msg_id10, msg_id1, msg_id3, msg_id5, msg_id7, msg_id9, msg_id0]
# Test: read some specific ids
read_msg_list = self.mail_message.message_read(cr, uid, ids=msg_ids[2:4], domain=[('body', 'like', 'dummy')])
@@ -601,7 +602,8 @@ class test_mail(TestMailMockups):
self.assertEqual(msg_ids, read_msg_ids, 'message_read flat with domain on Pigs should equal all messages of Pigs')
read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=200, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list]
- self.assertEqual(msg_ids, read_msg_ids, 'message_read threaded with domain on Pigs should equal all messages of Pigs')
+ self.assertEqual(ordered_msg_ids, read_msg_ids,
+ 'message_read threaded with domain on Pigs should equal all messages of Pigs, and sort them with newer thread first, last message last in thread')
# ----------------------------------------
# CASE1: message_read with domain, threaded
@@ -611,6 +613,8 @@ class test_mail(TestMailMockups):
# Do: read last message, threaded
read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
+ # TDE TODO: test expandables order
+ type_list = map(lambda item: item.get('type'), read_msg_list)
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 4, 'message_read on last Pigs message should return 2 messages and 2 expandables')
self.assertEqual(set([msg_id2, msg_id10]), set(read_msg_ids), 'message_read on the last Pigs message should also get its parent')
@@ -618,7 +622,7 @@ class test_mail(TestMailMockups):
# Data: get expandables
new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list:
- if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1:
+ if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'):
new_threads_exp = msg
elif msg.get('type') == 'expandable':
new_msg_exp = msg
@@ -630,12 +634,20 @@ class test_mail(TestMailMockups):
self.assertIn(('id', 'child_of', msg_id2), domain, 'new messages expandable domain should contain a child_of condition')
self.assertIn(('id', '>=', msg_id4), domain, 'new messages expandable domain should contain an id greater than condition')
self.assertIn(('id', '<=', msg_id8), domain, 'new messages expandable domain should contain an id less than condition')
- self.assertEqual(new_msg_exp.get('parent_id'), msg_id2, 'new messages expandable should have ancestor_id set to the thread header')
- # Do: message_read with domain, thread_level=0, parent_id=msg_id2 (should be imposed by JS)
- read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=200, thread_level=0, parent_id=msg_id2)
+ self.assertEqual(new_msg_exp.get('parent_id'), msg_id2, 'new messages expandable should have parent_id set to the thread header')
+ # Do: message_read with domain, thread_level=0, parent_id=msg_id2 (should be imposed by JS), 2 messages
+ read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=2, thread_level=0, parent_id=msg_id2)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
- # Test: other message in thread have been fetch
- self.assertEqual(set([msg_id4, msg_id6, msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return all the previous messages')
+ new_msg_exp = [msg for msg in read_msg_list if msg.get('type') == 'expandable'][0]
+ # Test: structure content, 2 messages and 1 thread expandable
+ self.assertEqual(len(read_msg_list), 3, 'message_read in Pigs thread should return 2 messages and 1 expandables')
+ self.assertEqual(set([msg_id6, msg_id8]), set(read_msg_ids), 'message_read in Pigs thread should return 2 more previous messages in thread')
+ # Do: read the last message
+ read_msg_list = self.mail_message.message_read(cr, uid, domain=new_msg_exp.get('domain'), limit=2, thread_level=0, parent_id=msg_id2)
+ read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
+ # Test: structure content, 1 message
+ self.assertEqual(len(read_msg_list), 1, 'message_read in Pigs thread should return 1 message')
+ self.assertEqual(set([msg_id4]), set(read_msg_ids), 'message_read in Pigs thread should return the last message in thread')
# Do: fetch a new thread, domain from expandable
self.assertIsNotNone(new_threads_exp, 'message_read on last Pigs message should have returned a new threads expandable')
@@ -643,7 +655,7 @@ class test_mail(TestMailMockups):
# Test: expandable, conditions in domain
for condition in pigs_domain:
self.assertIn(condition, domain, 'new threads expandable domain should contain the message_read domain parameter')
- self.assertFalse(new_threads_exp.get('parent_id'), 'new threads expandable should not have an ancestor_id')
+ self.assertFalse(new_threads_exp.get('parent_id'), 'new threads expandable should not have an parent_id')
# Do: message_read with domain, thread_level=1 (should be imposed by JS)
read_msg_list = self.mail_message.message_read(cr, uid, domain=domain, limit=1, thread_level=1)
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
@@ -654,7 +666,7 @@ class test_mail(TestMailMockups):
# Data: get expandables
new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list:
- if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1:
+ if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'):
new_threads_exp = msg
elif msg.get('type') == 'expandable':
new_msg_exp = msg
@@ -701,7 +713,7 @@ class test_mail(TestMailMockups):
# Data: get expandables
new_threads_exp, new_msg_exp = None, None
for msg in read_msg_list:
- if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('id') == -1:
+ if msg.get('type') == 'expandable' and msg.get('nb_messages') == -1 and msg.get('max_limit'):
new_threads_exp = msg
# Do: fetch new messages, domain from expandable
@@ -715,7 +727,7 @@ class test_mail(TestMailMockups):
read_msg_ids = [msg.get('id') for msg in read_msg_list if msg.get('type') != 'expandable']
# Test: structure content, ancestor is added to the read messages, ordered by id, ancestor is set, 2 expandables
self.assertEqual(len(read_msg_list), 9, 'message_read on Pigs should return 9 messages and 0 expandable')
- self.assertEqual([msg_id0, msg_id1, msg_id2, msg_id3, msg_id4, msg_id5, msg_id6, msg_id7, msg_id8], read_msg_ids,
+ self.assertEqual([msg_id8, msg_id7, msg_id6, msg_id5, msg_id4, msg_id3, msg_id2, msg_id1, msg_id0], read_msg_ids,
'message_read, More on flat, should return all remaning messages')
def test_40_needaction(self):
diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py
index 50ecf9450da..1d495fddee7 100644
--- a/addons/mail/wizard/invite.py
+++ b/addons/mail/wizard/invite.py
@@ -33,6 +33,7 @@ class invite_wizard(osv.osv_memory):
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]
+ print "DOCUMENT_NAME: ",document_name
message = _('You have been invited to follow %s. ' % document_name)
result['message'] = message
elif 'message' in fields:
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index 33712847534..45082b9be4d 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -135,7 +135,12 @@ class mail_compose_message(osv.TransientModel):
related to.
:param int res_id: id of the document record this mail is related to
"""
- return {'model': model, 'res_id': res_id}
+ doc_name_get = self.pool.get(model).name_get(cr, uid, res_id, context=context)
+ if doc_name_get:
+ record_name = doc_name_get[0][1]
+ else:
+ record_name = False
+ return {'model': model, 'res_id': res_id, 'record_name': record_name}
def get_message_data(self, cr, uid, message_id, context=None):
""" Returns a defaults-like dict with initial values for the composition
@@ -161,6 +166,7 @@ class mail_compose_message(osv.TransientModel):
# update the result
result = {
+ 'record_name': message_data.record_name,
'model': message_data.model,
'res_id': message_data.res_id,
'parent_id': message_data.id,
diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml
index b9c3d237e78..86b1be6562f 100644
--- a/addons/mail/wizard/mail_compose_message_view.xml
+++ b/addons/mail/wizard/mail_compose_message_view.xml
@@ -14,10 +14,19 @@
-
+
+
+ Followers of
+
+ and
+
+
+
+ attrs="{'invisible':[('content_subtype', '=', 'plain')]}"/>
diff --git a/addons/marketing_campaign/marketing_campaign_view.xml b/addons/marketing_campaign/marketing_campaign_view.xml
index 189bd8285f2..ab45f802371 100644
--- a/addons/marketing_campaign/marketing_campaign_view.xml
+++ b/addons/marketing_campaign/marketing_campaign_view.xml
@@ -270,7 +270,7 @@
-
+
diff --git a/addons/mrp/i18n/sl.po b/addons/mrp/i18n/sl.po
index 83d80822eb7..c36878f4d1d 100644
--- a/addons/mrp/i18n/sl.po
+++ b/addons/mrp/i18n/sl.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:49+0000\n"
-"PO-Revision-Date: 2012-11-01 19:12+0000\n"
+"PO-Revision-Date: 2012-11-07 23:15+0000\n"
"Last-Translator: Dusan Laznik \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: 2012-11-03 05:03+0000\n"
-"X-Generator: Launchpad (build 16218)\n"
+"X-Launchpad-Export-Date: 2012-11-09 04:39+0000\n"
+"X-Generator: Launchpad (build 16250)\n"
#. module: mrp
#: view:mrp.routing.workcenter:0
@@ -34,7 +34,7 @@ msgstr ""
#. module: mrp
#: help:mrp.production,location_src_id:0
msgid "Location where the system will look for components."
-msgstr ""
+msgstr "Lokacija za iskanje komponent"
#. module: mrp
#: field:mrp.production,workcenter_lines:0
@@ -67,11 +67,13 @@ msgid ""
"The 'Minimum stock rule' allows the system to create procurement orders "
"automatically as soon as the minimum stock is reached."
msgstr ""
+"Pravilo \"Minimalna zaloga\" omogoča avtomatsko kreiranje naročil "
+"dobaviteljem."
#. module: mrp
#: field:mrp.production,picking_id:0
msgid "Picking list"
-msgstr ""
+msgstr "Dobavnica"
#. module: mrp
#: code:addons/mrp/report/price.py:130
@@ -83,18 +85,18 @@ msgstr "Urna postavka"
#: code:addons/mrp/report/price.py:139
#, python-format
msgid "Cost Price per Uom"
-msgstr ""
+msgstr "Stroškovna cena na enoto"
#. module: mrp
#: view:mrp.production:0
msgid "Scrap Products"
-msgstr ""
+msgstr "Odpis izdelkov"
#. module: mrp
#: model:ir.actions.act_window,name:mrp.mrp_routing_action
#: model:ir.ui.menu,name:mrp.menu_mrp_routing_action
msgid "Routings"
-msgstr ""
+msgstr "Delovni tok"
#. module: mrp
#: field:mrp.workcenter,product_id:0
@@ -139,7 +141,7 @@ msgstr "Dokončani proizvodi"
#. module: mrp
#: view:mrp.production:0
msgid "Manufacturing Orders which are currently in production."
-msgstr ""
+msgstr "Delovni nalogi trenutno v proizvodnji"
#. module: mrp
#: model:process.transition,name:mrp.process_transition_servicerfq0
@@ -204,6 +206,7 @@ msgid ""
"Fill this product to track easily your production costs in the analytic "
"accounting."
msgstr ""
+"Izpolnite ta izdelek , za spremljavo stroškov v analitičnem računovodstvu"
#. module: mrp
#: model:process.node,note:mrp.process_node_purchaseprocure0
@@ -246,12 +249,12 @@ msgstr "Nabava storitev"
#. module: mrp
#: view:mrp.workcenter:0
msgid "Capacity Information"
-msgstr ""
+msgstr "Informacije o kapacitetah"
#. module: mrp
#: field:mrp.production,move_created_ids2:0
msgid "Produced Products"
-msgstr ""
+msgstr "Končani izdelki"
#. module: mrp
#: report:mrp.production.order:0
@@ -294,7 +297,7 @@ msgstr ""
#. module: mrp
#: help:mrp.bom,position:0
msgid "Reference to a position in an external plan."
-msgstr ""
+msgstr "Referenca na pozicijo v drugem planu"
#. module: mrp
#: constraint:stock.move:0
@@ -309,12 +312,12 @@ msgstr ""
#. module: mrp
#: model:ir.model,name:mrp.model_mrp_product_produce
msgid "Product Produce"
-msgstr ""
+msgstr "Končani izdelki"
#. module: mrp
#: constraint:mrp.bom:0
msgid "Error ! You cannot create recursive BoM."
-msgstr ""
+msgstr "Napaka ! (Rekurzivna kosovnica)"
#. module: mrp
#: model:ir.model,name:mrp.model_mrp_routing_workcenter
@@ -324,7 +327,7 @@ msgstr ""
#. module: mrp
#: model:process.transition,name:mrp.process_transition_procurestockableproduct0
msgid "Procurement of stockable Product"
-msgstr ""
+msgstr "Nabava izdelka , ki se skladišči"
#. module: mrp
#: view:mrp.bom:0
@@ -361,7 +364,7 @@ msgstr "Potrdi Proizvodnjo"
msgid ""
"The system creates an order (production or purchased) depending on the sold "
"quantity and the products parameters."
-msgstr ""
+msgstr "Sistem kreira nalog(delovni ali nabavni), odvisno od parametrov"
#. module: mrp
#: model:process.transition,note:mrp.process_transition_stockproduction0
@@ -386,7 +389,7 @@ msgstr ""
msgid ""
"This is the Internal Picking List that brings the finished product to the "
"production plan"
-msgstr ""
+msgstr "To je interna dobavnica , ki prenese izdelke v plan proizvodnje"
#. module: mrp
#: model:ir.ui.menu,name:mrp.menu_view_resource_calendar_search_mrp
@@ -396,7 +399,7 @@ msgstr "Delovni čas"
#. module: mrp
#: model:ir.actions.act_window,name:mrp.action_report_in_out_picking_tree
msgid "Weekly Stock Value Variation"
-msgstr ""
+msgstr "Tedensko nihanje vrednosti zalog"
#. module: mrp
#: view:mrp.production:0
@@ -426,7 +429,7 @@ msgstr ""
#. module: mrp
#: view:board.board:0
msgid "Stock Value Variation"
-msgstr ""
+msgstr "Nihanje vrednosti zalog"
#. module: mrp
#: model:ir.actions.act_window,name:mrp.action2
@@ -436,7 +439,7 @@ msgstr "Struktura kosovnice"
#. module: mrp
#: model:process.node,note:mrp.process_node_serviceproduct0
msgid "Product type is service"
-msgstr ""
+msgstr "Vrsta izdelka je usluga"
#. module: mrp
#: sql_constraint:res.company:0
@@ -505,12 +508,12 @@ msgstr ""
#: view:mrp.routing:0
#: field:mrp.routing,location_id:0
msgid "Production Location"
-msgstr ""
+msgstr "Lokacija proizvodnje"
#. module: mrp
#: view:mrp.production:0
msgid "Change Qty"
-msgstr ""
+msgstr "Spremeni količino"
#. module: mrp
#: model:ir.actions.act_window,name:mrp.action_configure_workcenter
@@ -520,7 +523,7 @@ msgstr ""
#. module: mrp
#: view:mrp.production:0
msgid "Force Reservation"
-msgstr ""
+msgstr "Vsili rezervacijo"
#. module: mrp
#: field:report.mrp.inout,value:0
@@ -579,7 +582,7 @@ msgstr ""
#. module: mrp
#: field:mrp.workcenter,time_start:0
msgid "Time before prod."
-msgstr ""
+msgstr "Čas pred proizvodnjo"
#. module: mrp
#: help:mrp.routing,active:0
@@ -591,14 +594,14 @@ msgstr ""
#. module: mrp
#: model:process.transition,name:mrp.process_transition_billofmaterialrouting0
msgid "Material Routing"
-msgstr ""
+msgstr "Tok materiala"
#. module: mrp
#: view:mrp.production:0
#: field:mrp.production,move_lines2:0
#: report:mrp.production.order:0
msgid "Consumed Products"
-msgstr ""
+msgstr "Porabljeni izdelki"
#. module: mrp
#: model:ir.actions.act_window,name:mrp.action_mrp_workcenter_load_wizard
@@ -617,7 +620,7 @@ msgstr "Izdelek nima kosovnice"
#: model:ir.actions.act_window,name:mrp.mrp_bom_form_action2
#: model:ir.ui.menu,name:mrp.menu_mrp_bom_form_action2
msgid "Bill of Material Components"
-msgstr ""
+msgstr "Komponente sestavnice"
#. module: mrp
#: model:ir.model,name:mrp.model_stock_move
@@ -651,7 +654,7 @@ msgstr ""
#. module: mrp
#: help:mrp.workcenter,time_cycle:0
msgid "Time in hours for doing one cycle."
-msgstr ""
+msgstr "Čas za končanje cikla"
#. module: mrp
#: constraint:mrp.bom:0
@@ -666,7 +669,7 @@ msgstr "V proizvodnji"
#. module: mrp
#: model:ir.ui.menu,name:mrp.menu_mrp_property
msgid "Master Bill of Materials"
-msgstr ""
+msgstr "Glavna sastavnica"
#. module: mrp
#: help:mrp.bom,product_uos:0
@@ -695,7 +698,7 @@ msgstr ""
#. module: mrp
#: selection:mrp.workcenter.load,time_unit:0
msgid "Per month"
-msgstr ""
+msgstr "Mesečno"
#. module: mrp
#: code:addons/mrp/wizard/change_production_qty.py:78
@@ -707,13 +710,13 @@ msgstr ""
#. module: mrp
#: report:bom.structure:0
msgid "Product Name"
-msgstr ""
+msgstr "Ime Izdelka"
#. module: mrp
#: code:addons/mrp/mrp.py:503
#, python-format
msgid "Invalid action !"
-msgstr ""
+msgstr "Nepravilno dejanje!"
#. module: mrp
#: help:mrp.bom,product_efficiency:0
@@ -725,7 +728,7 @@ msgstr ""
#: code:addons/mrp/mrp.py:762
#, python-format
msgid "Warning!"
-msgstr ""
+msgstr "Opozorilo!"
#. module: mrp
#: report:mrp.production.order:0
@@ -741,17 +744,17 @@ msgstr ""
#. module: mrp
#: model:process.transition,name:mrp.process_transition_producttostockrules0
msgid "Procurement rule"
-msgstr ""
+msgstr "Pravilo nabave"
#. module: mrp
#: view:mrp.production:0
msgid "Partial"
-msgstr ""
+msgstr "Delno"
#. module: mrp
#: report:mrp.production.order:0
msgid "WorkCenter"
-msgstr ""
+msgstr "Proizvodni center"
#. module: mrp
#: model:process.transition,note:mrp.process_transition_procureserviceproduct0
@@ -769,7 +772,7 @@ msgstr "Nujno"
#. module: mrp
#: view:mrp.production:0
msgid "Manufacturing Orders which are waiting for raw materials."
-msgstr ""
+msgstr "Delovni nalogi , ki čakajo na material"
#. module: mrp
#: model:ir.actions.act_window,help:mrp.mrp_workcenter_action
@@ -780,16 +783,18 @@ msgid ""
"resource leave are not taken into account in the time computation of the "
"work center."
msgstr ""
+"Delovno enoto sestavljajo delavci in/ali stroji , ki predstavljajo eno enoto "
+"za planiranje kapacitet."
#. module: mrp
#: model:ir.model,name:mrp.model_mrp_production
msgid "Manufacturing Order"
-msgstr ""
+msgstr "Delovni nalog"
#. module: mrp
#: model:process.transition,name:mrp.process_transition_productionprocureproducts0
msgid "Procurement of raw material"
-msgstr ""
+msgstr "Nabava surovin"
#. module: mrp
#: view:mrp.production:0
@@ -806,7 +811,7 @@ msgstr ""
#: view:mrp.bom:0
#: view:mrp.production:0
msgid "Date"
-msgstr ""
+msgstr "Datum"
#. module: mrp
#: field:mrp.bom,type:0
@@ -823,7 +828,7 @@ msgstr ""
#. module: mrp
#: view:mrp.property:0
msgid "Search"
-msgstr ""
+msgstr "Iskanje"
#. module: mrp
#: code:addons/mrp/mrp.py:626
@@ -884,7 +889,7 @@ msgstr "Možno dati v zalogo"
#: code:addons/mrp/report/price.py:130
#, python-format
msgid "Work Center name"
-msgstr ""
+msgstr "Ime delovne eote"
#. module: mrp
#: field:mrp.routing,code:0
@@ -1034,7 +1039,7 @@ msgstr ""
#. module: mrp
#: help:mrp.workcenter,costs_hour:0
msgid "Specify Cost of Work Center per hour."
-msgstr ""
+msgstr "Cena delovne enote na uro"
#. module: mrp
#: help:mrp.workcenter,capacity_per_cycle:0
@@ -1095,7 +1100,7 @@ msgstr "Analitični dnevnik"
#: model:ir.ui.menu,name:mrp.menu_view_resource_search_mrp
#: field:mrp.routing,workcenter_lines:0
msgid "Work Centers"
-msgstr ""
+msgstr "Delovne enote"
#. module: mrp
#: selection:mrp.workcenter.load,time_unit:0
@@ -1110,6 +1115,8 @@ msgid ""
"They are attached to bills of materials that will define the required raw "
"materials."
msgstr ""
+"Delovni tok opredeljuje zaporedje delovnih enot in operacij za izdelavo "
+"določenega izdelka."
#. module: mrp
#: model:ir.actions.act_window,name:mrp.product_form_config_action
@@ -1152,7 +1159,7 @@ msgstr ""
#. module: mrp
#: view:report.workcenter.load:0
msgid "Work Center load"
-msgstr ""
+msgstr "Zasedenost delovnega centra"
#. module: mrp
#: help:mrp.production,location_dest_id:0
@@ -1853,7 +1860,7 @@ msgstr ""
#. module: mrp
#: field:mrp.routing.workcenter,routing_id:0
msgid "Parent Routing"
-msgstr ""
+msgstr "Nadrejeni delovni tok"
#. module: mrp
#: help:mrp.workcenter,time_start:0
@@ -2013,7 +2020,7 @@ msgstr ""
#: view:mrp.routing:0
#: model:process.node,name:mrp.process_node_routing0
msgid "Routing"
-msgstr "Usmerjanje"
+msgstr "Delovni tok"
#. module: mrp
#: field:mrp.production,date_planned:0
diff --git a/addons/mrp/report/price.py b/addons/mrp/report/price.py
index 527505d8ea5..b1e04749ab2 100644
--- a/addons/mrp/report/price.py
+++ b/addons/mrp/report/price.py
@@ -111,7 +111,7 @@ class report_custom(report_rml):
595.27
841.88
55.00mm,58.00mm,29.00mm,29.00mm,29.00mm
- """ % (user_pool.browse(cr, uid, uid).company_id.name)
+ """ % to_xml(user_pool.browse(cr, uid, uid).company_id.name)
config_stop = """
Generated by OpenERP
diff --git a/addons/mrp/res_config.py b/addons/mrp/res_config.py
index c1712b81a26..ec3deb524a3 100644
--- a/addons/mrp/res_config.py
+++ b/addons/mrp/res_config.py
@@ -28,10 +28,6 @@ class mrp_config_settings(osv.osv_memory):
_inherit = 'res.config.settings'
_columns = {
- 'module_stock_planning': fields.boolean('Manage master production shedule',
- help ="""This allows to create a manual procurement plan apart of the normal MRP scheduling,
- which works automatically based on minimum stock rules.
- This installs the module stock_planning."""),
'module_mrp_repair': fields.boolean("Manage repairs of products ",
help="""Allows to manage all product repairs.
* Add/remove products in the reparation
diff --git a/addons/mrp/res_config_view.xml b/addons/mrp/res_config_view.xml
index 6b4058fb7b4..2c7047380a8 100644
--- a/addons/mrp/res_config_view.xml
+++ b/addons/mrp/res_config_view.xml
@@ -56,10 +56,6 @@
-
-
-
-
diff --git a/addons/mrp_repair/mrp_repair.py b/addons/mrp_repair/mrp_repair.py
index bc9b9413c65..d79620ce93c 100644
--- a/addons/mrp_repair/mrp_repair.py
+++ b/addons/mrp_repair/mrp_repair.py
@@ -690,7 +690,7 @@ class mrp_repair_line(osv.osv, ProductChangeMixin):
'repair_id': fields.many2one('mrp.repair', 'Repair Order Reference',ondelete='cascade', select=True),
'type': fields.selection([('add','Add'),('remove','Remove')],'Type', required=True),
'to_invoice': fields.boolean('To Invoice'),
- 'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok','=',True)], required=True),
+ 'product_id': fields.many2one('product.product', 'Product', required=True),
'invoiced': fields.boolean('Invoiced',readonly=True),
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
'price_subtotal': fields.function(_amount_line, string='Subtotal',digits_compute= dp.get_precision('Account')),
diff --git a/addons/note/note_view.xml b/addons/note/note_view.xml
index 18a3ec840a9..5aae6204d86 100644
--- a/addons/note/note_view.xml
+++ b/addons/note/note_view.xml
@@ -120,7 +120,7 @@
-
+
diff --git a/addons/note/static/src/css/note.css b/addons/note/static/src/css/note.css
index 1b7e9315e74..16d71e28aa5 100644
--- a/addons/note/static/src/css/note.css
+++ b/addons/note/static/src/css/note.css
@@ -49,8 +49,8 @@
padding: 8px;
margin-left: 3px;
margin-right: 3px;
- padding-bottom: 16px;
- margin-bottom: 16px;
+ padding-bottom: 8px;
+ margin-bottom: 10px;
-webkit-transform: rotate(-2deg);
-o-transform: rotate(-2deg);
-moz-transform: rotate(-2deg);
diff --git a/addons/note/static/src/css/note.sass b/addons/note/static/src/css/note.sass
index b5bc28a2593..6f0c0883ae7 100644
--- a/addons/note/static/src/css/note.sass
+++ b/addons/note/static/src/css/note.sass
@@ -53,8 +53,8 @@
padding: 8px
margin-left: 3px
margin-right: 3px
- padding-bottom: 16px
- margin-bottom: 16px
+ padding-bottom: 8px
+ margin-bottom: 10px
@include rotate(-2deg)
@include transition(all, 300ms)
.oe_kanban_record:nth-of-type(even)
diff --git a/addons/pad/pad.py b/addons/pad/pad.py
index e5b36e5f64c..932fc5a21a4 100644
--- a/addons/pad/pad.py
+++ b/addons/pad/pad.py
@@ -19,7 +19,7 @@ class pad_common(osv.osv_memory):
pad = {
"server" : company.pad_server,
- "key" : company.pad_key or "4DxmsNIbnQUVQMW9S9tx2oLOSjFdrx1l",
+ "key" : company.pad_key,
}
# make sure pad server in the form of http://hostname
diff --git a/addons/pad/pad_demo.xml b/addons/pad/pad_demo.xml
index 407f90e8242..99c4b38481c 100644
--- a/addons/pad/pad_demo.xml
+++ b/addons/pad/pad_demo.xml
@@ -1,9 +1,13 @@
-
+
pad.openerp.com
+
+
+ 4DxmsNIbnQUVQMW9S9tx2oLOSjFdrx1l
+
diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js
index c1252642b91..929d62681c8 100644
--- a/addons/pad/static/src/js/pad.js
+++ b/addons/pad/static/src/js/pad.js
@@ -12,8 +12,9 @@ openerp.pad = function(instance) {
model: self.view.model,
field_name: self.name,
object_id: self.view.datarecord.id
- }}).then(function(data) {
+ }}).done(function(data) {
if(data&&data.url){
+ self.set({value: data.url});
_super(data.url);
self.renderElement();
}
diff --git a/addons/plugin_outlook/plugin_outlook.xml b/addons/plugin_outlook/plugin_outlook.xml
index e99fbf72b6d..91c51e87ad9 100644
--- a/addons/plugin_outlook/plugin_outlook.xml
+++ b/addons/plugin_outlook/plugin_outlook.xml
@@ -10,7 +10,11 @@
-
+
+
+
@@ -19,10 +23,10 @@
Click on the link above to download the installer for either 32 or 64 bits, and execute it.
System requirements:
-
- - 1. MS Outlook 2005 or above.
- - 2. MS .Net Framework 3.5 or above.
-
+
+ - MS Outlook 2005 or above.
+ - MS .Net Framework 3.5 or above.
+
@@ -51,7 +55,7 @@
-
diff --git a/addons/plugin_thunderbird/plugin_thunderbird.py b/addons/plugin_thunderbird/plugin_thunderbird.py
index 6473758883d..923611b97a9 100644
--- a/addons/plugin_thunderbird/plugin_thunderbird.py
+++ b/addons/plugin_thunderbird/plugin_thunderbird.py
@@ -30,13 +30,11 @@ class plugin_thunderbird_installer(osv.osv_memory):
'thunderbird': fields.boolean('Thunderbird Plug-in', help="Allows you to select an object that you would like to add to your email and its attachments."),
'plugin_name': fields.char('File name', size=64),
'plugin_file': fields.char('Thunderbird Plug-in', size=256, readonly=True, help="Thunderbird plug-in file. Save this file and install it in Thunderbird."),
- 'pdf_file': fields.char('Installation Manual', size=256, help="The documentation file :- how to install Thunderbird Plug-in.", readonly=True),
}
_defaults = {
'thunderbird': True,
'plugin_name': 'openerp_plugin.xpi',
- 'pdf_file': 'http://doc.openerp.com/book/2/2_6_Comms/2_6_Comms_thunderbird.html',
}
def default_get(self, cr, uid, fields, context=None):
@@ -45,4 +43,4 @@ class plugin_thunderbird_installer(osv.osv_memory):
res['plugin_file'] = base_url + '/plugin_thunderbird/static/openerp_plugin.xpi'
return res
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/plugin_thunderbird/plugin_thunderbird.xml b/addons/plugin_thunderbird/plugin_thunderbird.xml
index 5ea5fc38219..3774a369437 100644
--- a/addons/plugin_thunderbird/plugin_thunderbird.xml
+++ b/addons/plugin_thunderbird/plugin_thunderbird.xml
@@ -10,25 +10,28 @@
-
+
+
+
-
- Thunderbird plugin installation:
-
- - 1. Save the Thunderbird plug-in.
- - 2. From the Thunderbird menubar: Tools > Add-ons -> Screwdriver/Wrench Icon -> Install add-on from file...
- - 3. Select the plug-in (the file named openerp_plugin.xpi).
- - 4. Click "Install Now".
- - 5. Restart Thunderbird.
- - 6. From the Thunderbird menubar: OpenERP -> Configuration.
- - 7. Configure your openerp server.
-
+ Thunderbird plug-in installation:
+
+ - Save the Thunderbird plug-in.
+ - From the Thunderbird menubar: Tools > Add-ons -> Screwdriver/Wrench Icon -> Install add-on from file...
+ - Select the plug-in (the file named openerp_plugin.xpi).
+ - Click "Install Now".
+ - Restart Thunderbird.
+ - From the Thunderbird menubar: OpenERP -> Configuration.
+ - Configure your openerp server.
+
@@ -57,7 +60,7 @@
-
diff --git a/addons/point_of_sale/report/pos_receipt.py b/addons/point_of_sale/report/pos_receipt.py
index 2ee6b2e3360..58044c28c77 100644
--- a/addons/point_of_sale/report/pos_receipt.py
+++ b/addons/point_of_sale/report/pos_receipt.py
@@ -34,7 +34,7 @@ class order(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(order, self).__init__(cr, uid, name, context=context)
- user = pooler.get_pool(cr.dbname).get('res.users').browse(cr, uid, uid)
+ user = pooler.get_pool(cr.dbname).get('res.users').browse(cr, uid, uid, context=context)
partner = user.company_id.partner_id
self.localcontext.update({
diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js
index c96aff3d9c1..c5580ec8e46 100644
--- a/addons/point_of_sale/static/src/js/devices.js
+++ b/addons/point_of_sale/static/src/js/devices.js
@@ -37,12 +37,11 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
callbacks[i](params);
}
- this.connection.rpc('/pos/'+name, params || {}).then(function(result){
- ret.resolve(result);
- },
- function(error){
- ret.reject(error);
- });
+ this.connection.rpc('/pos/' + name, params || {}).done(function(result) {
+ ret.resolve(result);
+ }).fail(function(error) {
+ ret.reject(error);
+ });
return ret;
},
@@ -96,7 +95,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal
return this.weight;
}else{
this.message('weighting_read_kg',{})
- .then(function(weight){
+ .done(function(weight){
if(self.weighting && !self.bypass_proxy){
self.weight = weight;
}
diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js
index d7d6d3181f1..7301a85eb2d 100644
--- a/addons/point_of_sale/static/src/js/models.js
+++ b/addons/point_of_sale/static/src/js/models.js
@@ -59,10 +59,10 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
// Any change on this data made on the server is thus not reflected on the point of sale until it is relaunched.
// when all the data has loaded, we compute some stuff, and declare the Pos ready to be used.
$.when(this.load_server_data())
- .then(function(){
+ .done(function(){
//self.log_loaded_data(); //Uncomment if you want to log the data to the console for easier debugging
self.ready.resolve();
- },function(){
+ }).fail(function(){
//we failed to load some backend data, or the backend was badly configured.
//the error messages will be displayed in PosWidget
self.ready.reject();
@@ -78,7 +78,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
var self = this;
var loaded = self.fetch('res.users',['name','company_id'],[['id','=',this.session.uid]])
- .pipe(function(users){
+ .then(function(users){
self.set('user',users[0]);
return self.fetch('res.company',
@@ -93,19 +93,19 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
'partner_id',
],
[['id','=',users[0].company_id[0]]]);
- }).pipe(function(companies){
+ }).then(function(companies){
self.set('company',companies[0]);
return self.fetch('res.partner',['contact_address'],[['id','=',companies[0].partner_id[0]]]);
- }).pipe(function(company_partners){
+ }).then(function(company_partners){
self.get('company').contact_address = company_partners[0].contact_address;
return self.fetch('res.currency',['symbol','position'],[['id','=',self.get('company').currency_id[0]]]);
- }).pipe(function(currencies){
+ }).then(function(currencies){
self.set('currency',currencies[0]);
return self.fetch('product.uom', null, null);
- }).pipe(function(units){
+ }).then(function(units){
self.set('units',units);
var units_by_id = {};
for(var i = 0, len = units.length; i < len; i++){
@@ -114,15 +114,15 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
self.set('units_by_id',units_by_id);
return self.fetch('product.packaging', null, null);
- }).pipe(function(packagings){
+ }).then(function(packagings){
self.set('product.packaging',packagings);
return self.fetch('res.users', ['name','ean13'], [['ean13', '!=', false]]);
- }).pipe(function(users){
+ }).then(function(users){
self.set('user_list',users);
return self.fetch('account.tax', ['amount', 'price_include', 'type']);
- }).pipe(function(taxes){
+ }).then(function(taxes){
self.set('taxes', taxes);
return self.fetch(
@@ -130,7 +130,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
['id', 'journal_ids','name','user_id','config_id','start_at','stop_at'],
[['state', '=', 'opened'], ['user_id', '=', self.session.uid]]
);
- }).pipe(function(sessions){
+ }).then(function(sessions){
self.set('pos_session', sessions[0]);
return self.fetch(
@@ -141,7 +141,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
'iface_print_via_proxy','iface_cashdrawer','state','sequence_id','session_ids'],
[['id','=', self.get('pos_session').config_id[0]]]
);
- }).pipe(function(configs){
+ }).then(function(configs){
var pos_config = configs[0];
self.set('pos_config', pos_config);
self.iface_electronic_scale = !!pos_config.iface_electronic_scale;
@@ -151,15 +151,15 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
self.iface_cashdrawer = !!pos_config.iface_cashdrawer;
return self.fetch('sale.shop',[],[['id','=',pos_config.shop_id[0]]]);
- }).pipe(function(shops){
+ }).then(function(shops){
self.set('shop',shops[0]);
return self.fetch('product.packaging',['ean','product_id']);
- }).pipe(function(packagings){
+ }).then(function(packagings){
self.db.add_packagings(packagings);
return self.fetch('pos.category', ['id','name','parent_id','child_id','image'])
- }).pipe(function(categories){
+ }).then(function(categories){
self.db.add_categories(categories);
return self.fetch(
@@ -169,7 +169,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
[['pos_categ_id','!=', false],['sale_ok','=',true]],
{pricelist: self.get('shop').pricelist_id[0]} // context for price
);
- }).pipe(function(products){
+ }).then(function(products){
self.db.add_products(products);
return self.fetch(
@@ -177,14 +177,14 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
['account_id','currency','journal_id','state','name','user_id','pos_session_id'],
[['state','=','open'],['pos_session_id', '=', self.get('pos_session').id]]
);
- }).pipe(function(bank_statements){
+ }).then(function(bank_statements){
var journals = new Array();
_.each(bank_statements,function(statement) {
journals.push(statement.journal_id[0])
});
self.set('bank_statements', bank_statements);
return self.fetch('account.journal', undefined, [['id','in', journals]]);
- }).pipe(function(journals){
+ }).then(function(journals){
self.set('journals',journals);
// associate the bank statements with their journals.
diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js
index 8028349b177..0b8ab70a9c0 100644
--- a/addons/point_of_sale/static/src/js/screens.js
+++ b/addons/point_of_sale/static/src/js/screens.js
@@ -557,7 +557,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
setTimeout(function(){
var def = job.fun();
if(def){
- def.then(run);
+ def.done(run);
}else{
run();
}
@@ -615,7 +615,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
var def = new $.Deferred();
console.log("START");
self.pos.proxy.payment_request(self.pos.get('selectedOrder').getDueLeft())
- .then(function(ack){
+ .done(function(ack){
if(ack === 'ok'){
self.queue.schedule(self.update);
}else if(ack.indexOf('error') === 0){
@@ -638,7 +638,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
return def.resolve();
}
self.pos.proxy.payment_status()
- .then(function(status){
+ .done(function(status){
if(status.status === 'paid'){
var currentOrder = self.pos.get('selectedOrder');
@@ -941,8 +941,10 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
var self = this;
var x = new module.PaymentlineWidget(null, {
payment_line: newPaymentLine
- });
- x.on('delete_payment_line', self, self.deleteLine);
+ });
+ x.on('delete_payment_line', self, function(r) {
+ self.deleteLine(r);
+ });
x.appendTo(this.$('#paymentlines'));
},
renderElement: function() {
diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js
index ed9b1fd060a..c7874a4bd5c 100644
--- a/addons/point_of_sale/static/src/js/widgets.js
+++ b/addons/point_of_sale/static/src/js/widgets.js
@@ -315,7 +315,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this._super();
this.$('input').keyup(_.bind(this.changeAmount, this));
this.$('.delete-payment-line').click(function() {
- self.trigger('delete_payment_line');
+ self.trigger('delete_payment_line', self);
});
},
});
@@ -806,7 +806,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
start: function() {
var self = this;
- return self.pos.ready.then(function() {
+ return self.pos.ready.done(function() {
self.build_currency_template();
self.renderElement();
@@ -845,7 +845,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
self.$('.loader').animate({opacity:0},1500,'swing',function(){self.$('.loader').hide();});
self.$('.loader img').hide();
- },function(){ // error when loading models data from the backend
+ }).fail(function(){ // error when loading models data from the backend
self.$('.loader img').hide();
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_session_opening']], ['res_id'])
.pipe( _.bind(function(res){
@@ -1051,7 +1051,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
this.pos.barcode_reader.disconnect();
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id']).pipe(
_.bind(function(res) {
- return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(action) {
+ return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) {
+ var action = result;
action.context = _.extend(action.context || {}, {'cancel_action': {type: 'ir.actions.client', tag: 'reload'}});
//self.destroy();
this.do_action(action);
diff --git a/addons/point_of_sale/wizard/pos_payment.py b/addons/point_of_sale/wizard/pos_payment.py
index 9511aed6331..70b88f35e33 100644
--- a/addons/point_of_sale/wizard/pos_payment.py
+++ b/addons/point_of_sale/wizard/pos_payment.py
@@ -75,7 +75,7 @@ class pos_make_payment(osv.osv_memory):
def launch_payment(self, cr, uid, ids, context=None):
return {
- 'name': _('Paiement'),
+ 'name': _('Payment'),
'view_type': 'form',
'view_mode': 'form',
'res_model': 'pos.make.payment',
@@ -83,6 +83,7 @@ class pos_make_payment(osv.osv_memory):
'target': 'new',
'views': False,
'type': 'ir.actions.act_window',
+ 'context': context,
}
def print_report(self, cr, uid, ids, context=None):
diff --git a/addons/portal/wizard/share_wizard.py b/addons/portal/wizard/share_wizard.py
index b1b6e980dec..51e5e59eb0e 100644
--- a/addons/portal/wizard/share_wizard.py
+++ b/addons/portal/wizard/share_wizard.py
@@ -35,8 +35,8 @@ class share_wizard_portal(osv.TransientModel):
def _user_type_selection(self, cr, uid, context=None):
selection = super(share_wizard_portal, self)._user_type_selection(cr, uid, context=context)
- selection.extend([('existing','Users you already shared with'),
- ('groups','Existing Groups (e.g Portal Groups)')])
+ selection.extend([('existing',_('Users you already shared with')),
+ ('groups',_('Existing Groups (e.g Portal Groups)'))])
return selection
_columns = {
diff --git a/addons/portal_claim/portal_claim_view.xml b/addons/portal_claim/portal_claim_view.xml
index 86be0764d26..e08b39e476b 100644
--- a/addons/portal_claim/portal_claim_view.xml
+++ b/addons/portal_claim/portal_claim_view.xml
@@ -10,7 +10,14 @@
{"search_default_user_id":'', "stage_type":'claim'}
- Record and track your customers' claims. Claims may be linked to a sales order or a lot. You can send emails with attachments and keep the full history for a claim (emails sent, intervention type and so on). Claims may automatically be linked to an email address using the mail gateway module.
+
+
+ Click to register a new claim.
+
+ You can track your claims from this menu and the action we
+ will take.
+
+
diff --git a/addons/sale/edi/sale_order_action_data.xml b/addons/sale/edi/sale_order_action_data.xml
index 9796d0bda16..da1a1ceb393 100644
--- a/addons/sale/edi/sale_order_action_data.xml
+++ b/addons/sale/edi/sale_order_action_data.xml
@@ -25,7 +25,7 @@
Automated Sale Order Notification Mail
${object.user_id.email or ''}
${object.company_id.name} Order (Ref ${object.name or 'n/a' })
- ${object.partner_invoice_id.email}
+ ${object.partner_invoice_id.id}
-
-
+
+
+
diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py
index 4e6d6414ddf..9ea2215fe0f 100644
--- a/addons/sale/wizard/sale_make_invoice_advance.py
+++ b/addons/sale/wizard/sale_make_invoice_advance.py
@@ -123,6 +123,7 @@ class sale_advance_payment_inv(osv.osv_memory):
# create the invoice
inv_line_values = {
'name': res.get('name'),
+ 'origin': sale.name,
'account_id': res['account_id'],
'price_unit': inv_amount,
'quantity': wizard.qtty or 1.0,
diff --git a/addons/sale_crm/wizard/crm_make_sale.py b/addons/sale_crm/wizard/crm_make_sale.py
index 2597c1db56c..10225990229 100644
--- a/addons/sale_crm/wizard/crm_make_sale.py
+++ b/addons/sale_crm/wizard/crm_make_sale.py
@@ -64,7 +64,9 @@ class crm_make_sale(osv.osv_memory):
"""
if context is None:
context = {}
-
+ # update context: if come from phonecall, default state values can make the quote crash lp:1017353
+ context.pop('default_state', False)
+
case_obj = self.pool.get('crm.lead')
sale_obj = self.pool.get('sale.order')
partner_obj = self.pool.get('res.partner')
diff --git a/addons/share/static/src/js/share.js b/addons/share/static/src/js/share.js
index e73e68144d0..e627b555de3 100644
--- a/addons/share/static/src/js/share.js
+++ b/addons/share/static/src/js/share.js
@@ -15,7 +15,7 @@ openerp.share = function(session) {
self.rpc('/web/session/eval_domain_and_context', {
domains: [domain],
contexts: [view.dataset.context]
- }).then(function (result) {
+ }).done(function (result) {
Share.create({
name: action.name,
record_name: rec_name,
@@ -24,8 +24,8 @@ openerp.share = function(session) {
user_type: user_type || 'embedded',
view_type: view.fields_view.type,
invite: invite || false,
- }).then(function(share_id) {
- var step1 = Share.call('go_step_1', [[share_id]]).then(function(result) {
+ }).done(function(share_id) {
+ var step1 = Share.call('go_step_1', [[share_id]]).done(function(result) {
var action = result;
self.do_action(action);
});
@@ -37,7 +37,7 @@ openerp.share = function(session) {
if (!session.session.share_flag) {
session.session.share_flag = $.Deferred(function() {
var func = new session.web.Model("share.wizard").get_func("has_share");
- func(session.session.uid).pipe(function(res) {
+ func(session.session.uid).then(function(res) {
if(res) {
session.session.share_flag.resolve();
} else {
diff --git a/addons/share/wizard/share_wizard.py b/addons/share/wizard/share_wizard.py
index 360b1eff159..6a1f5681f4f 100644
--- a/addons/share/wizard/share_wizard.py
+++ b/addons/share/wizard/share_wizard.py
@@ -74,7 +74,7 @@ class share_wizard(osv.TransientModel):
def _user_type_selection(self, cr, uid, context=None):
"""Selection values may be easily overridden/extended via inheritance"""
- return [('embedded', 'Direct link or embed code'), ('emails','Emails'), ]
+ return [('embedded', _('Direct link or embed code')), ('emails',_('Emails')), ]
"""Override of create() to auto-compute the action name"""
def create(self, cr, uid, values, context=None):
diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml
index 250fe5245e7..594843eff8d 100644
--- a/addons/stock/product_view.xml
+++ b/addons/stock/product_view.xml
@@ -41,7 +41,7 @@
-
+
@@ -103,7 +103,7 @@
-
+
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 606cb9247d5..d18a55ea49a 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -1351,14 +1351,14 @@ class stock_picking(osv.osv):
wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_confirm', cr)
# Then we finish the good picking
self.write(cr, uid, [pick.id], {'backorder_id': new_picking})
- self.action_move(cr, uid, [new_picking])
+ self.action_move(cr, uid, [new_picking], context=context)
wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_done', cr)
wf_service.trg_write(uid, 'stock.picking', pick.id, cr)
delivered_pack_id = new_picking
back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name
self.back_order_send_note(cr, uid, ids, back_order_name, context)
else:
- self.action_move(cr, uid, [pick.id])
+ self.action_move(cr, uid, [pick.id], context=context)
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_done', cr)
delivered_pack_id = pick.id
self.ship_done_send_note(cr, uid, ids, context)
@@ -1553,7 +1553,7 @@ class stock_production_lot(osv.osv):
'product_id': lambda x, y, z, c: c.get('product_id', False),
}
_sql_constraints = [
- ('name_ref_uniq', 'unique (name, ref)', 'The combination of serial number and internal reference must be unique !'),
+ ('name_ref_uniq', 'unique (name, ref)', 'The combination of Serial Number and internal reference must be unique !'),
]
def action_traceability(self, cr, uid, ids, context=None):
""" It traces the information of a product
@@ -2123,7 +2123,7 @@ class stock_move(osv.osv):
old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
if old_ptype != picking.type:
old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
- self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name}, context=context)
+ self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name, 'type': old_ptype}, context=context)
else:
pickid = False
for move, (loc, dummy, delay, dummy, company_id, ptype) in todo:
@@ -2433,14 +2433,17 @@ class stock_move(osv.osv):
if move.picking_id:
picking_ids.append(move.picking_id.id)
if move.move_dest_id.id and (move.state != 'done'):
- self.write(cr, uid, [move.id], {'move_history_ids': [(4, move.move_dest_id.id)]})
- #cr.execute('insert into stock_move_history_ids (parent_id,child_id) values (%s,%s)', (move.id, move.move_dest_id.id))
- if move.move_dest_id.state in ('waiting', 'confirmed'):
- self.force_assign(cr, uid, [move.move_dest_id.id], context=context)
- if move.move_dest_id.picking_id:
- wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr)
- if move.move_dest_id.auto_validate:
- self.action_done(cr, uid, [move.move_dest_id.id], context=context)
+ # Downstream move should only be triggered if this move is the last pending upstream move
+ other_upstream_move_ids = self.search(cr, uid, [('id','!=',move.id),('state','not in',['done','cancel']),
+ ('move_dest_id','=',move.move_dest_id.id)], context=context)
+ if not other_upstream_move_ids:
+ self.write(cr, uid, [move.id], {'move_history_ids': [(4, move.move_dest_id.id)]})
+ if move.move_dest_id.state in ('waiting', 'confirmed'):
+ self.force_assign(cr, uid, [move.move_dest_id.id], context=context)
+ if move.move_dest_id.picking_id:
+ wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr)
+ if move.move_dest_id.auto_validate:
+ self.action_done(cr, uid, [move.move_dest_id.id], context=context)
self._create_product_valuation_moves(cr, uid, move, context=context)
if move.state not in ('confirmed','done','assigned'):
diff --git a/addons/stock/stock_sequence.xml b/addons/stock/stock_sequence.xml
index 6c0b3e84cf2..c3569c48c3e 100644
--- a/addons/stock/stock_sequence.xml
+++ b/addons/stock/stock_sequence.xml
@@ -17,7 +17,7 @@
Picking INT
- stock.picking.internal
+ stock.picking
|