Filter By [[ get_filter(data)!='No Filter' and get_filter(data) ]]
+
Filter By [[ get_filter(data)!='No Filters' and get_filter(data) ]]
[[ 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/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/tests/__init__.py b/addons/account/tests/__init__.py
new file mode 100644
index 00000000000..11fe4186db6
--- /dev/null
+++ b/addons/account/tests/__init__.py
@@ -0,0 +1,4 @@
+from . import test_tax
+
+fast_suite = [test_tax,
+ ]
diff --git a/addons/account/tests/test_tax.py b/addons/account/tests/test_tax.py
new file mode 100644
index 00000000000..a172a17e30d
--- /dev/null
+++ b/addons/account/tests/test_tax.py
@@ -0,0 +1,49 @@
+from openerp.tests.common import TransactionCase
+
+class TestTax(TransactionCase):
+ """Tests for taxes (account.tax)
+
+ We don't really need at this point to link taxes to tax codes
+ (account.tax.code) nor to companies (base.company) to check computation
+ results.
+ """
+
+ def setUp(self):
+ super(TestTax, self).setUp()
+ self.tax_model = self.registry('account.tax')
+
+ def test_programmatic_tax(self):
+ cr, uid = self.cr, self.uid
+ tax_id = self.tax_model.create(cr, uid, dict(
+ name="Programmatic tax",
+ type='code',
+ python_compute='result = 12.0',
+ python_compute_inv='result = 11.0',
+ ))
+
+ tax_records = self.tax_model.browse(cr, uid, [tax_id])
+ res = self.tax_model.compute_all(cr, uid, tax_records, 50.0, 2)
+
+ tax_detail = res['taxes'][0]
+ self.assertEquals(tax_detail['amount'], 24.0)
+ self.assertEquals(res['total_included'], 124.0)
+
+ def test_percent_tax(self):
+ """Test computations done by a 10 percent tax."""
+ cr, uid = self.cr, self.uid
+ tax_id = self.tax_model.create(cr, uid, dict(
+ name="Percent tax",
+ type='percent',
+ amount='0.1',
+ ))
+
+ tax_records = self.tax_model.browse(cr, uid, [tax_id])
+ res = self.tax_model.compute_all(cr, uid, tax_records, 50.0, 2)
+
+ tax_detail = res['taxes'][0]
+ self.assertEquals(tax_detail['amount'], 10.0)
+ self.assertEquals(res['total_included'], 110.0)
+
+ # now the inverse computation
+ res = self.tax_model.compute_inv(cr, uid, tax_records, 55.0, 2)
+ self.assertEquals(res[0]['amount'], 10.0)
diff --git a/addons/account/wizard/account_financial_report_view.xml b/addons/account/wizard/account_financial_report_view.xml
index 8388284be4a..507809e1961 100644
--- a/addons/account/wizard/account_financial_report_view.xml
+++ b/addons/account/wizard/account_financial_report_view.xml
@@ -14,15 +14,19 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
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_open_closed_fiscalyear.py b/addons/account/wizard/account_open_closed_fiscalyear.py
index b8d64fac0b5..1b5622a589d 100644
--- a/addons/account/wizard/account_open_closed_fiscalyear.py
+++ b/addons/account/wizard/account_open_closed_fiscalyear.py
@@ -27,7 +27,7 @@ class account_open_closed_fiscalyear(osv.osv_memory):
_description = "Choose Fiscal Year"
_columns = {
'fyear_id': fields.many2one('account.fiscalyear', \
- 'Fiscal Year to Open', required=True, help='Select Fiscal Year which you want to remove entries for its End of year entries journal'),
+ 'Fiscal Year', required=True, help='Select Fiscal Year which you want to remove entries for its End of year entries journal'),
}
def remove_entries(self, cr, uid, ids, context=None):
@@ -36,7 +36,7 @@ class account_open_closed_fiscalyear(osv.osv_memory):
data = self.browse(cr, uid, ids, context=context)[0]
period_journal = data.fyear_id.end_journal_period_id or False
if not period_journal:
- raise osv.except_osv(_('Error!'), _('You have to set the end of the fiscal year for this journal.'))
+ raise osv.except_osv(_('Error!'), _("You have to set the 'End of Year Entries Journal' for this Fiscal Year which is set after generating opening entries from 'Generate Opening Entries'."))
ids_move = move_obj.search(cr, uid, [('journal_id','=',period_journal.journal_id.id),('period_id','=',period_journal.period_id.id)])
if ids_move:
diff --git a/addons/account/wizard/account_open_closed_fiscalyear_view.xml b/addons/account/wizard/account_open_closed_fiscalyear_view.xml
index c2c271af41b..d4cfd398920 100644
--- a/addons/account/wizard/account_open_closed_fiscalyear_view.xml
+++ b/addons/account/wizard/account_open_closed_fiscalyear_view.xml
@@ -5,14 +5,18 @@
account.open.closed.fiscalyear.formaccount.open.closed.fiscalyear
-
diff --git a/addons/account/wizard/account_report_account_balance_view.xml b/addons/account/wizard/account_report_account_balance_view.xml
index b2c8ccd3011..3609ee3b4de 100644
--- a/addons/account/wizard/account_report_account_balance_view.xml
+++ b/addons/account/wizard/account_report_account_balance_view.xml
@@ -9,8 +9,7 @@
-
-
+
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_accountant/account_accountant_data.xml b/addons/account_accountant/account_accountant_data.xml
index cf143b1bb58..c7d6eb80bc6 100644
--- a/addons/account_accountant/account_accountant_data.xml
+++ b/addons/account_accountant/account_accountant_data.xml
@@ -26,12 +26,10 @@
mail.groupnotification
+ Accounting and Finance application installed!
- The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.
- ]]>
+ With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc.
+
The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.
]]>
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.plansaccount.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..a44226e76c8 100644
--- a/addons/account_asset/account_asset.py
+++ b/addons/account_asset/account_asset.py
@@ -377,16 +377,15 @@ class account_asset_depreciation_line(osv.osv):
move_line_obj = self.pool.get('account.move.line')
currency_obj = self.pool.get('res.currency')
created_move_ids = []
+ asset_ids = []
for line in self.browse(cr, uid, ids, context=context):
- if currency_obj.is_zero(cr, uid, line.asset_id.currency_id, line.remaining_value):
- can_close = True
depreciation_date = time.strftime('%Y-%m-%d')
period_ids = period_obj.find(cr, uid, depreciation_date, context=context)
company_currency = line.asset_id.company_id.currency_id.id
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 = {
@@ -409,8 +408,8 @@ class account_asset_depreciation_line(osv.osv):
'period_id': period_ids and period_ids[0] or False,
'journal_id': journal_id,
'partner_id': partner_id,
- 'currency_id': company_currency <> current_currency and current_currency or False,
- 'amount_currency': company_currency <> current_currency and - sign * line.amount or 0.0,
+ 'currency_id': company_currency != current_currency and current_currency or False,
+ 'amount_currency': company_currency != current_currency and - sign * line.amount or 0.0,
'date': depreciation_date,
})
move_line_obj.create(cr, uid, {
@@ -423,16 +422,19 @@ class account_asset_depreciation_line(osv.osv):
'period_id': period_ids and period_ids[0] or False,
'journal_id': journal_id,
'partner_id': partner_id,
- 'currency_id': company_currency <> current_currency and current_currency or False,
- 'amount_currency': company_currency <> current_currency and sign * line.amount or 0.0,
+ 'currency_id': company_currency != current_currency and current_currency or False,
+ 'amount_currency': company_currency != current_currency and sign * line.amount or 0.0,
'analytic_account_id': line.asset_id.category_id.account_analytic_id.id,
'date': depreciation_date,
'asset_id': line.asset_id.id
})
self.write(cr, uid, line.id, {'move_id': move_id}, context=context)
created_move_ids.append(move_id)
- if can_close:
- asset_obj.write(cr, uid, [line.asset_id.id], {'state': 'close'}, context=context)
+ asset_ids.append(line.asset_id.id)
+ # we re-evaluate the assets to determine whether we can close them
+ for asset in asset_obj.browse(cr, uid, list(set(asset_ids)), context=context):
+ if currency_obj.is_zero(cr, uid, asset.currency_id, asset.value_residual):
+ asset.write({'state': 'close'})
return created_move_ids
account_asset_depreciation_line()
diff --git a/addons/account_bank_statement_extensions/account_bank_statement_view.xml b/addons/account_bank_statement_extensions/account_bank_statement_view.xml
index 3d5560856a3..adc2963c803 100644
--- a/addons/account_bank_statement_extensions/account_bank_statement_view.xml
+++ b/addons/account_bank_statement_extensions/account_bank_statement_view.xml
@@ -72,12 +72,12 @@
-
+
-
-
+
+
@@ -100,8 +100,8 @@
-
-
+
+
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.treecrossovered.budget.lines
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..32be8c34929 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,
@@ -381,8 +383,9 @@ class account_voucher(osv.osv):
total_tax = 0.0
if not tax[0].price_include:
- for tax_line in tax_pool.compute_all(cr, uid, tax, voucher_amount, 1).get('taxes', []):
- total_tax += tax_line.get('amount', 0.0)
+ for line in voucher.line_ids:
+ for tax_line in tax_pool.compute_all(cr, uid, tax, line.amount, 1).get('taxes', []):
+ total_tax += tax_line.get('amount', 0.0)
total += total_tax
else:
for line in voucher.line_ids:
@@ -413,31 +416,31 @@ class account_voucher(osv.osv):
line_ids = resolve_o2m_operations(cr, uid, line_pool, line_ids, ["amount"], context)
+ total_tax = 0.0
for line in line_ids:
line_amount = 0.0
line_amount = line.get('amount',0.0)
+
+ if tax_id:
+ tax = [tax_pool.browse(cr, uid, tax_id, context=context)]
+ if partner_id:
+ partner = partner_pool.browse(cr, uid, partner_id, context=context) or False
+ taxes = position_pool.map_tax(cr, uid, partner and partner.property_account_position or False, tax)
+ tax = tax_pool.browse(cr, uid, taxes, context=context)
+
+ if not tax[0].price_include:
+ for tax_line in tax_pool.compute_all(cr, uid, tax, line_amount, 1).get('taxes', []):
+ total_tax += tax_line.get('amount')
+
voucher_total += line_amount
-
- total = voucher_total
- total_tax = 0.0
- if tax_id:
- tax = [tax_pool.browse(cr, uid, tax_id, context=context)]
- if partner_id:
- partner = partner_pool.browse(cr, uid, partner_id, context=context) or False
- taxes = position_pool.map_tax(cr, uid, partner and partner.property_account_position or False, tax)
- tax = tax_pool.browse(cr, uid, taxes, context=context)
-
- if not tax[0].price_include:
- for tax_line in tax_pool.compute_all(cr, uid, tax, voucher_total, 1).get('taxes', []):
- total_tax += tax_line.get('amount')
- total += total_tax
+ total = voucher_total + total_tax
res.update({
- 'amount':total or voucher_total,
- 'tax_amount':total_tax
+ 'amount': total or voucher_total,
+ 'tax_amount': total_tax
})
return {
- 'value':res
+ 'value': res
}
def onchange_term_id(self, cr, uid, ids, term_id, amount):
@@ -953,6 +956,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 +1510,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 +1554,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 +1590,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_data.xml b/addons/account_voucher/account_voucher_data.xml
index 3d4252e697d..fc008e479e9 100644
--- a/addons/account_voucher/account_voucher_data.xml
+++ b/addons/account_voucher/account_voucher_data.xml
@@ -7,12 +7,10 @@
mail.groupnotification
+ eInvoicing & Payments application installed!
- You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.
- ]]>
+ OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
+
You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.
- 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 @@
formtree,form
diff --git a/addons/event/static/src/css/event.css b/addons/event/static/src/css/event.css
index f49f5474fa6..ff5bfaba19b 100644
--- a/addons/event/static/src/css/event.css
+++ b/addons/event/static/src/css/event.css
@@ -14,11 +14,13 @@
border-bottom-left-radius:3px;
border-bottom-right-radius:3px;
font-size: 12px;
+ border-collapse: separate;
text-align: center;
font-weight: bold;
color: #8A89BA;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
background-color: #FFFFFF;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}
.oe_event_month_year{
border-bottom-left-radius:3px;
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/fetchmail/fetchmail.py b/addons/fetchmail/fetchmail.py
index e0023697594..68f05dfeee2 100644
--- a/addons/fetchmail/fetchmail.py
+++ b/addons/fetchmail/fetchmail.py
@@ -243,20 +243,20 @@ class mail_mail(osv.osv):
def create(self, cr, uid, values, context=None):
if context is None:
- context={}
+ context = {}
fetchmail_server_id = context.get('fetchmail_server_id')
if fetchmail_server_id:
values['fetchmail_server_id'] = fetchmail_server_id
- res = super(mail_mail,self).create(cr, uid, values, context=context)
+ res = super(mail_mail, self).create(cr, uid, values, context=context)
return res
def write(self, cr, uid, ids, values, context=None):
if context is None:
- context={}
+ context = {}
fetchmail_server_id = context.get('fetchmail_server_id')
if fetchmail_server_id:
- values['fetchmail_server_id'] = server_id
- res = super(mail_mail,self).write(cr, uid, ids, values, context=context)
+ values['fetchmail_server_id'] = fetchmail_server_id
+ res = super(mail_mail, self).write(cr, uid, ids, values, context=context)
return res
diff --git a/addons/fleet/fleet.py b/addons/fleet/fleet.py
index 9b9986a0b01..be0e8b34351 100644
--- a/addons/fleet/fleet.py
+++ b/addons/fleet/fleet.py
@@ -720,7 +720,7 @@ class fleet_vehicle_log_contract(osv.Model):
'start_date': datetime.datetime.strftime(str_to_datetime(element.expiration_date) + datetime.timedelta(days=1), tools.DEFAULT_SERVER_DATE_FORMAT),
'expiration_date': datetime.datetime.strftime(enddate + diffdate, tools.DEFAULT_SERVER_DATE_FORMAT),
}
- newid = super(fleet_vehicle_log_contract, self).copy(cr, uid, [element.id], default, context=context)
+ newid = super(fleet_vehicle_log_contract, self).copy(cr, uid, element.id, default, context=context)
mod, modid = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'fleet_vehicle_log_contract_form')
return {
'name':_("Renew Contract"),
diff --git a/addons/fleet/fleet_view.xml b/addons/fleet/fleet_view.xml
index ecec39f22d8..8eb1baba760 100644
--- a/addons/fleet/fleet_view.xml
+++ b/addons/fleet/fleet_view.xml
@@ -522,7 +522,7 @@
fleet.vehicle.odometer.treefleet.vehicle.odometer
-
+
@@ -563,7 +563,7 @@
Vehicles Odometerfleet.vehicle.odometerform
- tree,form,graph
+ tree,graph{"search_default_groupby_vehicle" : True}
diff --git a/addons/fleet/static/src/img/icon.png b/addons/fleet/static/src/img/icon.png
index 3db7ae9fa49..5b41e43c5bd 100644
Binary files a/addons/fleet/static/src/img/icon.png and b/addons/fleet/static/src/img/icon.png differ
diff --git a/addons/hr/hr.py b/addons/hr/hr.py
index d57fcf49ab2..5f3a5653307 100644
--- a/addons/hr/hr.py
+++ b/addons/hr/hr.py
@@ -158,6 +158,8 @@ class hr_employee(osv.osv):
return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
_columns = {
+ #we need a related field in order to be able to sort the employee by name
+ 'name_related': fields.related('resource_id', 'name', type='char', string='Name', readonly=True, store=True),
'country_id': fields.many2one('res.country', 'Nationality'),
'birthday': fields.date("Date of Birth"),
'ssnid': fields.char('SSN No', size=32, help='Social Security Number'),
@@ -207,6 +209,8 @@ class hr_employee(osv.osv):
'last_login': fields.related('user_id', 'date', type='datetime', string='Latest Connection', readonly=1),
}
+ _order='name_related'
+
def create(self, cr, uid, data, context=None):
employee_id = super(hr_employee, self).create(cr, uid, data, context=context)
try:
diff --git a/addons/hr/hr_data.xml b/addons/hr/hr_data.xml
index 514cf1f80f6..25c882f2201 100644
--- a/addons/hr/hr_data.xml
+++ b/addons/hr/hr_data.xml
@@ -6,11 +6,11 @@
mail.groupnotification
+ Employee Directory application installed!
- Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.
-
-More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
-Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).
+ Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.
+
More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
+Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).
]]>
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 Employeeshr.employee.categoryformtree,form
@@ -342,8 +342,8 @@
-
+
diff --git a/addons/hr/static/src/css/hr.css b/addons/hr/static/src/css/hr.css
index 00ef92c0fd8..f395f9939e5 100644
--- a/addons/hr/static/src/css/hr.css
+++ b/addons/hr/static/src/css/hr.css
@@ -18,10 +18,11 @@
-o-border-radius: 3px;
-ms-border-radius: 3px;
border-radius: 3px;
+ border-collapse: separate;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
-o-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
- -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
+ box-shadow: 0 1px 4px 3px rgba(0, 0, 0, 0.4);
}
.oe_employee_picture {
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_evaluation/hr_evaluation_data.xml b/addons/hr_evaluation/hr_evaluation_data.xml
index 01915de76a0..2afb5200091 100644
--- a/addons/hr_evaluation/hr_evaluation_data.xml
+++ b/addons/hr_evaluation/hr_evaluation_data.xml
@@ -11,9 +11,9 @@
mail.groupnotification
+ Employee Appraisals application installed!
- Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels.
-Evaluations filled by employees may be exported as pdf files.
+ Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels. Evaluations filled by employees may be exported as pdf files.]]>
@@ -811,8 +811,8 @@ Once the form had been filled, the employee send it to his supervisor.
The comment you entered is in an invalid format.* His direct reports will be invited through OpenERP to express a feedback on their supervisor's leadership and to give their opinion about their own engagement and effectiveness, the continuous improvement and openness in action in the company, ...
-* The employees will send back their anonymous answers to OpenERP. The data will be handled by the HR manager and a brief summary of the data will be sent to the concerned supervisor, to his team and to the supervisor's supervisor.
-* The appraiser should rate the employee’s major work accomplishments and performance according to the metric provided below :
+* The employees will send back their anonymous answers to OpenERP. The data will be handled by the HR manager and a brief summary of the data will be sent to the concerned supervisor, to his team and to the supervisor's supervisor.
+* The appraiser should rate the employee’s major work accomplishments and performance according to the metric provided below :
1 - Significantly exceeds standards and expectations required of the position
2 - Exceeds standards and expectations
diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py
index 96a37c0e448..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)
diff --git a/addons/hr_expense/hr_expense_data.xml b/addons/hr_expense/hr_expense_data.xml
index 2a9f3ae0a56..f54156ac5ec 100644
--- a/addons/hr_expense/hr_expense_data.xml
+++ b/addons/hr_expense/hr_expense_data.xml
@@ -6,10 +6,10 @@
mail.groupnotification
+ Expense Management application installed!
- Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.
-
-This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.
+ Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.
+
This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.
]]>
diff --git a/addons/hr_holidays/hr_holidays_data.xml b/addons/hr_holidays/hr_holidays_data.xml
index afe2e69e697..5af0c60fc44 100644
--- a/addons/hr_holidays/hr_holidays_data.xml
+++ b/addons/hr_holidays/hr_holidays_data.xml
@@ -11,9 +11,10 @@
mail.groupnotification
+ Leave Management application installed!
- Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.
-Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.
+ Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.
+
Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.
diff --git a/addons/hr_timesheet/report/user_timesheet.py b/addons/hr_timesheet/report/user_timesheet.py
index 7699f94f41b..8d2a7d35678 100644
--- a/addons/hr_timesheet/report/user_timesheet.py
+++ b/addons/hr_timesheet/report/user_timesheet.py
@@ -28,6 +28,7 @@ import time
import pooler
from report import report_sxw
from tools import ustr
+from tools import to_xml
def lengthmonth(year, month):
if month == 2 and ((year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))):
@@ -94,7 +95,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,user_id).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,user_id).company_id.name))
account_xml = []
for account, telems in accounts.iteritems():
diff --git a/addons/hr_timesheet/wizard/hr_timesheet_print_employee.py b/addons/hr_timesheet/wizard/hr_timesheet_print_employee.py
index 75bb089bbc7..96ce23fb855 100644
--- a/addons/hr_timesheet/wizard/hr_timesheet_print_employee.py
+++ b/addons/hr_timesheet/wizard/hr_timesheet_print_employee.py
@@ -27,8 +27,9 @@ class analytical_timesheet_employee(osv.osv_memory):
_name = 'hr.analytical.timesheet.employee'
_description = 'Print Employee Timesheet & Print My Timesheet'
_columns = {
- 'month': fields.selection([(x, datetime.date(2000, x, 1).strftime('%B')) for x in range(1, 13)],
- 'Month', required=True),
+ 'month': fields.selection([(1,'January'), (2,'February'), (3,'March'), (4,'April'),
+ (5,'May'), (6,'June'), (7,'July'), (8,'August'), (9,'September'),
+ (10,'October'), (11,'November'), (12,'December')], 'Month', required=True),
'year': fields.integer('Year', required=True),
'employee_id': fields.many2one('hr.employee', 'Employee', required=True)
diff --git a/addons/hr_timesheet/wizard/hr_timesheet_print_users.py b/addons/hr_timesheet/wizard/hr_timesheet_print_users.py
index 865ccacb393..2a91bb607a4 100644
--- a/addons/hr_timesheet/wizard/hr_timesheet_print_users.py
+++ b/addons/hr_timesheet/wizard/hr_timesheet_print_users.py
@@ -27,8 +27,9 @@ class analytical_timesheet_employees(osv.osv_memory):
_name = 'hr.analytical.timesheet.users'
_description = 'Print Employees Timesheet'
_columns = {
- 'month': fields.selection([(x, datetime.date(2000, x, 1).strftime('%B')) for x in range(1, 13)],
- 'Month', required=True),
+ 'month': fields.selection([(1,'January'), (2,'February'), (3,'March'), (4,'April'),
+ (5,'May'), (6,'June'), (7,'July'), (8,'August'), (9,'September'),
+ (10,'October'), (11,'November'), (12,'December')], 'Month', required=True),
'year': fields.integer('Year', required=True),
'employee_ids': fields.many2many('hr.employee', 'timesheet_employee_rel', 'timesheet_id', 'employee_id', 'employees', required=True)
}
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml
index 87edf949972..095a92c032d 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml
@@ -6,8 +6,9 @@
mail.groupnotification
+ Timesheet Validation application installed!
- From the top menu "Human Resources", enter and validate timesheets and attendances.
+ From the top menu "Human Resources", enter and validate timesheets and attendances.]]>
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
index ee5a329c800..6de6be6c08d 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
@@ -162,7 +162,7 @@
-
+
diff --git a/addons/l10n_ar/i18n/es_AR.po b/addons/l10n_ar/i18n/es_AR.po
index 2260a43cf74..1f2b2dd250a 100644
--- a/addons/l10n_ar/i18n/es_AR.po
+++ b/addons/l10n_ar/i18n/es_AR.po
@@ -1,21 +1,21 @@
-# Spanish (Paraguay) translation for openobject-addons
-# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
+# Spanish (Argentina) translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openobject-addons package.
-# FIRST AUTHOR , 2011.
+# FIRST AUTHOR , 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2011-01-11 11:15+0000\n"
-"PO-Revision-Date: 2011-03-21 16:23+0000\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: Spanish (Paraguay) \n"
+"PO-Revision-Date: 2012-11-13 15:04+0000\n"
+"Last-Translator: Eduardo Alberto Calvo \n"
+"Language-Team: Spanish (Argentina) \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-03-22 04:36+0000\n"
-"X-Generator: Launchpad (build 12559)\n"
+"X-Launchpad-Export-Date: 2012-11-14 04:40+0000\n"
+"X-Generator: Launchpad (build 16251)\n"
#. module: l10n_ar
#: model:ir.module.module,description:l10n_ar.module_meta_information
@@ -31,7 +31,7 @@ msgstr ""
#. module: l10n_ar
#: model:ir.module.module,shortdesc:l10n_ar.module_meta_information
msgid "Argentinian Chart of Account"
-msgstr "Plan de cuentas de la Argentina"
+msgstr "Plan de cuentas de Argentina"
#. module: l10n_ar
#: model:ir.actions.todo,note:l10n_ar.config_call_account_template_in_minimal
@@ -45,7 +45,7 @@ msgid ""
"Chart of Accounts from a Chart Template."
msgstr ""
"Generar el plan contable a partir de una plantilla de plan contable. Se le "
-"pedirá el nombre de la compañía, la plantilla de plan contable a utilizar, "
+"pedirá el nombre de la compañia, la plantilla de plan contable a utilizar, "
"el número de dígitos para generar el código de las cuentas y de la cuenta "
"bancaria, la moneda para crear los diarios. Así pues, se genere una copia "
"exacta de la plantilla de plan contable.\n"
diff --git a/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py b/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py
index d15b300597e..53948945e04 100644
--- a/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py
+++ b/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py
@@ -65,6 +65,8 @@ class partner_vat(osv.osv_memory):
partners = []
partner_ids = obj_partner.search(cr, uid, [('vat_subjected', '!=', False), ('vat','ilike','BE%')], context=context)
+ if not partner_ids:
+ raise osv.except_osv(_('Error'),_('No belgian contact with a VAT number in your database.'))
cr.execute("""SELECT sub1.partner_id, sub1.name, sub1.vat, sub1.turnover, sub2.vat_amount
FROM (SELECT l.partner_id, p.name, p.vat, SUM(CASE WHEN c.code ='49' THEN -l.tax_amount ELSE l.tax_amount END) as turnover
FROM account_move_line l
@@ -190,7 +192,7 @@ class partner_vat_list(osv.osv_memory):
addr = obj_partner.address_get(cr, uid, [obj_cmpny.partner_id.id], ['invoice'])
if addr.get('invoice',False):
ads = obj_partner.browse(cr, uid, [addr['invoice']], context=context)[0]
- phone = ads.phone.replace(' ','') or ''
+ phone = ads.phone and ads.phone.replace(' ','') or ''
email = ads.email or ''
name = ads.name or ''
city = ads.city or ''
@@ -259,6 +261,8 @@ class partner_vat_list(osv.osv_memory):
# Turnover and Farmer tags are not included
client_datas = self._get_datas(cr, uid, ids, context=context)
+ if not client_datas:
+ raise osv.except_osv(_('Data Insufficient!'),_('No data available for the client.'))
data_client_info = ''
for amount_data in client_datas:
data_client_info += """
@@ -309,6 +313,8 @@ class partner_vat_list(osv.osv_memory):
datas['year'] = context['year']
datas['limit_amount'] = context['limit_amount']
datas['client_datas'] = self._get_datas(cr, uid, ids, context=context)
+ if not datas['client_datas']:
+ raise osv.except_osv(_('Error!'),_('No record to print.'))
return {
'type': 'ir.actions.report.xml',
'report_name': 'partner.vat.listing.print',
diff --git a/addons/l10n_be_coda/wizard/account_coda_import.py b/addons/l10n_be_coda/wizard/account_coda_import.py
index ca89cf78325..46c545f0f48 100644
--- a/addons/l10n_be_coda/wizard/account_coda_import.py
+++ b/addons/l10n_be_coda/wizard/account_coda_import.py
@@ -28,6 +28,7 @@ import logging
import re
from traceback import format_exception
from sys import exc_info
+from base_iban import base_iban
_logger = logging.getLogger(__name__)
class account_coda_import(osv.osv_memory):
@@ -398,6 +399,7 @@ class account_coda_import(osv.osv_memory):
st_line['account_id'] = transfer_acc
match = True
elif find_partner:
+ counterparty_number = base_iban._pretty_iban(base_iban._format_iban(counterparty_number))
bank_ids = partner_bank_obj.search(cr,uid,[('acc_number','=', counterparty_number)])
if not match and find_partner and bank_ids:
if len(bank_ids) > 1:
diff --git a/addons/l10n_be_hr_payroll/i18n/es.po b/addons/l10n_be_hr_payroll/i18n/es.po
new file mode 100644
index 00000000000..c0deb99952c
--- /dev/null
+++ b/addons/l10n_be_hr_payroll/i18n/es.po
@@ -0,0 +1,158 @@
+# Spanish translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-02-08 00:36+0000\n"
+"PO-Revision-Date: 2012-11-12 16:09+0000\n"
+"Last-Translator: FULL NAME \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-11-13 05:17+0000\n"
+"X-Generator: Launchpad (build 16251)\n"
+
+#. module: l10n_be_hr_payroll
+#: help:hr.employee,disabled_spouse_bool:0
+msgid "if recipient spouse is declared disabled by law"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: help:hr.employee,disabled_children_bool:0
+msgid "if recipient children is/are declared disabled by law"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,misc_onss_deduction:0
+msgid "Miscellaneous exempt ONSS "
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: model:ir.model,name:l10n_be_hr_payroll.model_hr_employee
+msgid "Employee"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,disabled_spouse_bool:0
+msgid "Disabled Spouse"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,retained_net_amount:0
+msgid "Net retained "
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,resident_bool:0
+msgid "Nonresident"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: help:hr.employee,resident_bool:0
+msgid "if recipient lives in a foreign country"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: view:hr.employee:0
+msgid "if spouse has professionnel income or not"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: view:hr.contract:0
+msgid "Miscellaneous"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,insurance_employee_deduction:0
+msgid "Insurance Group - by worker "
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: selection:hr.employee,spouse_fiscal_status:0
+msgid "With Income"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: selection:hr.employee,spouse_fiscal_status:0
+msgid "Without Income"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,disabled_children_number:0
+msgid "Number of disabled children"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,additional_net_amount:0
+msgid "Net supplements"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: constraint:hr.employee:0
+msgid "Error ! You cannot create recursive Hierarchy of Employees."
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,car_company_amount:0
+msgid "Company car employer"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,misc_advantage_amount:0
+msgid "Benefits of various nature "
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,car_employee_deduction:0
+msgid "Company Car Deduction for Worker"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,disabled_children_bool:0
+msgid "Disabled Children"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: model:ir.model,name:l10n_be_hr_payroll.model_hr_contract
+msgid "Contract"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,meal_voucher_amount:0
+msgid "Check Value Meal "
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,travel_reimbursement_amount:0
+msgid "Reimbursement of travel expenses"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: constraint:hr.contract:0
+msgid "Error! contract start-date must be lower then contract end-date."
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,spouse_fiscal_status:0
+msgid "Tax status for spouse"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: view:hr.contract:0
+msgid "by Worker"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: view:hr.employee:0
+msgid "number of dependent children declared as disabled"
+msgstr ""
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,meal_voucher_employee_deduction:0
+msgid "Check Value Meal - by worker "
+msgstr ""
diff --git a/addons/l10n_be_invoice_bba/i18n/es.po b/addons/l10n_be_invoice_bba/i18n/es.po
new file mode 100644
index 00000000000..42f11478e9d
--- /dev/null
+++ b/addons/l10n_be_invoice_bba/i18n/es.po
@@ -0,0 +1,141 @@
+# Spanish translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-02-08 00:36+0000\n"
+"PO-Revision-Date: 2012-11-12 16:43+0000\n"
+"Last-Translator: FULL NAME \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-11-13 05:17+0000\n"
+"X-Generator: Launchpad (build 16251)\n"
+
+#. module: l10n_be_invoice_bba
+#: sql_constraint:account.invoice:0
+msgid "Invoice Number must be unique per Company!"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: model:ir.model,name:l10n_be_invoice_bba.model_account_invoice
+msgid "Invoice"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: constraint:res.partner:0
+msgid "Error ! You cannot create recursive associated members."
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: constraint:account.invoice:0
+msgid "Invalid BBA Structured Communication !"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: selection:res.partner,out_inv_comm_algorithm:0
+msgid "Random"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: help:res.partner,out_inv_comm_type:0
+msgid "Select Default Communication Type for Outgoing Invoices."
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: help:res.partner,out_inv_comm_algorithm:0
+msgid ""
+"Select Algorithm to generate the Structured Communication on Outgoing "
+"Invoices."
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: code:addons/l10n_be_invoice_bba/invoice.py:114
+#: code:addons/l10n_be_invoice_bba/invoice.py:140
+#, python-format
+msgid ""
+"The daily maximum of outgoing invoices with an automatically generated BBA "
+"Structured Communications has been exceeded!\n"
+"Please create manually a unique BBA Structured Communication."
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: code:addons/l10n_be_invoice_bba/invoice.py:155
+#, python-format
+msgid "Error!"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: code:addons/l10n_be_invoice_bba/invoice.py:126
+#, python-format
+msgid ""
+"The Partner should have a 3-7 digit Reference Number for the generation of "
+"BBA Structured Communications!\n"
+"Please correct the Partner record."
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: code:addons/l10n_be_invoice_bba/invoice.py:113
+#: code:addons/l10n_be_invoice_bba/invoice.py:125
+#: code:addons/l10n_be_invoice_bba/invoice.py:139
+#: code:addons/l10n_be_invoice_bba/invoice.py:167
+#: code:addons/l10n_be_invoice_bba/invoice.py:177
+#: code:addons/l10n_be_invoice_bba/invoice.py:202
+#, python-format
+msgid "Warning!"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: selection:res.partner,out_inv_comm_algorithm:0
+msgid "Customer Reference"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: field:res.partner,out_inv_comm_type:0
+msgid "Communication Type"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: code:addons/l10n_be_invoice_bba/invoice.py:178
+#: code:addons/l10n_be_invoice_bba/invoice.py:203
+#, python-format
+msgid ""
+"The BBA Structured Communication has already been used!\n"
+"Please create manually a unique BBA Structured Communication."
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: selection:res.partner,out_inv_comm_algorithm:0
+msgid "Date"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: model:ir.model,name:l10n_be_invoice_bba.model_res_partner
+msgid "Partner"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: code:addons/l10n_be_invoice_bba/invoice.py:156
+#, python-format
+msgid ""
+"Unsupported Structured Communication Type Algorithm '%s' !\n"
+"Please contact your OpenERP support channel."
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: field:res.partner,out_inv_comm_algorithm:0
+msgid "Communication Algorithm"
+msgstr ""
+
+#. module: l10n_be_invoice_bba
+#: code:addons/l10n_be_invoice_bba/invoice.py:168
+#, python-format
+msgid ""
+"Empty BBA Structured Communication!\n"
+"Please fill in a unique BBA Structured Communication."
+msgstr ""
diff --git a/addons/l10n_ch/bank.py b/addons/l10n_ch/bank.py
index 79dcb1a6834..4e4c0e0aa8c 100644
--- a/addons/l10n_ch/bank.py
+++ b/addons/l10n_ch/bank.py
@@ -52,21 +52,6 @@ class ResPartnerBank(osv.osv):
'my_bank': fields.boolean('Use my account to print BVR ?', help="Check to print BVR invoices"),
}
- def name_get(self, cursor, uid, ids, context=None):
- if not len(ids):
- return []
- bank_type_obj = self.pool.get('res.partner.bank.type')
-
- type_ids = bank_type_obj.search(cursor, uid, [])
- bank_type_names = {}
- for bank_type in bank_type_obj.browse(cursor, uid, type_ids,
- context=context):
- bank_type_names[bank_type.code] = bank_type.name
- res = []
- for r in self.read(cursor, uid, ids, ['name','state'], context):
- res.append((r['id'], r['name']+' : '+bank_type_names.get(r['state'], '')))
- return res
-
def _prepare_name(self, bank):
"Hook to get bank number of bank account"
res = u''
diff --git a/addons/l10n_fr/fr_tax.xml b/addons/l10n_fr/fr_tax.xml
index fc5d4608f45..36c5feb47b6 100644
--- a/addons/l10n_fr/fr_tax.xml
+++ b/addons/l10n_fr/fr_tax.xml
@@ -131,8 +131,8 @@
-
-
+
+
diff --git a/addons/l10n_fr/plan_comptable_general.xml b/addons/l10n_fr/plan_comptable_general.xml
index 525dabfcc8a..268f4bd6336 100644
--- a/addons/l10n_fr/plan_comptable_general.xml
+++ b/addons/l10n_fr/plan_comptable_general.xml
@@ -3903,7 +3903,7 @@
Associés - Comptes courants455view
-
+ Pour frais avancés personnellement
@@ -3912,8 +3912,8 @@
Principal4551
- receivable
-
+ payable
+
@@ -3921,8 +3921,8 @@
Intérêts courus4558
- receivable
-
+ payable
+
diff --git a/addons/l10n_in_hr_payroll/i18n/es.po b/addons/l10n_in_hr_payroll/i18n/es.po
new file mode 100644
index 00000000000..52f443733fb
--- /dev/null
+++ b/addons/l10n_in_hr_payroll/i18n/es.po
@@ -0,0 +1,942 @@
+# Spanish translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-08-17 06:46+0000\n"
+"PO-Revision-Date: 2012-11-12 17:08+0000\n"
+"Last-Translator: FULL NAME \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-11-13 05:17+0000\n"
+"X-Generator: Launchpad (build 16251)\n"
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "E-mail Address"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:payment.advice.report,employee_bank_no:0
+msgid "Employee Bank Account"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Payment Advices which are in draft state"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Title"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "Payment Advice from"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_yearly_salary_detail
+msgid "Hr Salary Employee By Category Report"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Employees Salary Details"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Allowances with Basic:"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Department"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Deductions:"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "A/C no."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.contract,driver_salay:0
+msgid "Driver Salary"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.act_window,name:l10n_in_hr_payroll.action_yearly_salary_detail
+#: model:ir.actions.report.xml,name:l10n_in_hr_payroll.yearly_salary
+#: model:ir.ui.menu,name:l10n_in_hr_payroll.menu_yearly_salary_detail
+msgid "Yearly Salary by Employee"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.act_window,name:l10n_in_hr_payroll.act_hr_emp_payslip_list
+msgid "Payslips"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "March"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "("
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: field:hr.payroll.advice,company_id:0
+#: field:hr.payroll.advice.line,company_id:0
+#: view:payment.advice.report:0
+#: field:payment.advice.report,company_id:0
+msgid "Company"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "The Manager"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Letter Details"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid ","
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Set to Draft"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.employee,number_of_year:0
+msgid "Total years of work experience"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "to"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "Total :"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payslip.run,available_advice:0
+msgid "Made Payment Advice?"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Advices which are paid using NEFT transfer"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.contract,tds:0
+msgid "Amount for Tax Deduction at Source"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_hr_payslip
+msgid "Pay Slip"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+#: field:payment.advice.report,day:0
+msgid "Day"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Month of Payment Advices"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: constraint:hr.payslip:0
+msgid "Payslip 'Date From' must be before 'Date To'."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,batch_id:0
+msgid "Batch"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Code"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Other Information"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:hr.payroll.advice,state:0
+#: selection:payment.advice.report,state:0
+msgid "Cancelled"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "For"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Details by Salary Rule Category:"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.contract,voluntary_provident_fund:0
+msgid "VPF computed as percentage(%)"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,number:0
+#: report:paylip.details.in:0
+msgid "Reference"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: view:payment.advice.report:0
+msgid "Group By..."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.contract,medical_insurance:0
+msgid "Medical Insurance"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Identification No"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:hr.payroll.advice,state:0
+#: selection:payment.advice.report,state:0
+msgid "Confirmed"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+#: report:salary.employee.bymonth:0
+msgid "From"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice.line,bysal:0
+#: field:payment.advice.report,bysal:0
+#: report:payroll.advice:0
+msgid "By Salary"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: view:payment.advice.report:0
+msgid "Confirm"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,chaque_nos:0
+#: field:payment.advice.report,cheque_nos:0
+msgid "Cheque Numbers"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: constraint:res.company:0
+msgid "Error! You can not create recursive companies."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.act_window,name:l10n_in_hr_payroll.action_salary_employee_month
+#: model:ir.actions.report.xml,name:l10n_in_hr_payroll.hr_salary_employee_bymonth
+#: model:ir.ui.menu,name:l10n_in_hr_payroll.menu_salary_employee_month
+msgid "Yearly Salary by Head"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:184
+#, python-format
+msgid "You can not confirm Payment advice without advice lines."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,state:0
+#: field:payment.advice.report,state:0
+msgid "State"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "Yours Sincerely"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.contract,medical_insurance:0
+msgid "Deduction towards company provided medical insurance"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_hr_payroll_advice_line
+msgid "Bank Advice Lines"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Email"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.payslip.run,available_advice:0
+msgid ""
+"If this box is checked which means that Payment Advice exists for current "
+"batch"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:158
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:184
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:240
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:257
+#, python-format
+msgid "Error !"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.salary.employee.month:0
+#: view:yearly.salary.detail:0
+msgid "Print"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_hr_payslip_run
+msgid "Payslip Batches"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice.line,debit_credit:0
+#: report:payroll.advice:0
+msgid "C/D"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.employee.bymonth:0
+msgid "Yearly Salary Details"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.report.xml,name:l10n_in_hr_payroll.payroll_advice
+msgid "Print Advice"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,line_ids:0
+msgid "Employee Salary"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "July"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:res.company:0
+msgid "Configuration"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.act_window,name:l10n_in_hr_payroll.action_view_hr_bank_advice_tree
+#: model:ir.ui.menu,name:l10n_in_hr_payroll.hr_menu_payment_advice
+msgid "Payment Advices"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.act_window,name:l10n_in_hr_payroll.action_payment_advice_report_all
+#: model:ir.ui.menu,name:l10n_in_hr_payroll.menu_reporting_payment_advice
+#: view:payment.advice.report:0
+msgid "Advices Analysis"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.salary.employee.month:0
+msgid ""
+"This wizard will print report which displays employees break-up of Net Head "
+"for a specified dates."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice.line,ifsc:0
+msgid "IFSC"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Date To"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.contract,tds:0
+msgid "TDS"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.employee,join_date:0
+msgid "Join Date"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Confirm Advices"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: constraint:hr.contract:0
+msgid "Error! Contract start-date must be less than contract end-date."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:res.company,dearness_allowance:0
+msgid "Dearness Allowance"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "August"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.contract:0
+msgid "Deduction"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Search Payment advice"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "SI. No."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Payment Advices which are in confirm state"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "December"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Confirm Sheet"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+#: field:payment.advice.report,month:0
+msgid "Month"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Employee Code"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:hr.contract,city_type:0
+msgid "Non Metro"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.salary.employee.month:0
+#: view:yearly.salary.detail:0
+msgid "or"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_hr_salary_employee_month
+msgid "Hr Salary Employee By Month Report"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.salary.employee.month,category_id:0
+msgid "Category"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:240
+#, python-format
+msgid ""
+"Payment advice already exists for %s, 'Set to Draft' to create a new advice."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payslip.run:0
+msgid "To Advice"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.employee,number_of_year:0
+msgid "No. of Years of Service"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Note"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Salary Rule Category"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: selection:hr.payroll.advice,state:0
+#: view:payment.advice.report:0
+#: selection:payment.advice.report,state:0
+msgid "Draft"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Date From"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.contract,voluntary_provident_fund:0
+msgid "Voluntary Provident Fund"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Employee Name"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_payment_advice_report
+msgid "Payment Advice Analysis"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: view:payment.advice.report:0
+msgid "Status"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.contract,city_type:0
+msgid "Type of City"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:res.company,dearness_allowance:0
+msgid "Check this box if your company provide Dearness Allowance to employee"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice.line,ifsc_code:0
+#: field:payment.advice.report,ifsc_code:0
+#: report:payroll.advice:0
+msgid "IFSC Code"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "June"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+#: field:payment.advice.report,nbr:0
+msgid "# Payment Lines"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.report.xml,name:l10n_in_hr_payroll.payslip_details_report
+msgid "PaySlip Details"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Payment Lines"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,date:0
+#: field:payment.advice.report,date:0
+msgid "Date"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "November"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Extended Filters..."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.actions.act_window,help:l10n_in_hr_payroll.action_payment_advice_report_all
+msgid "This report performs analysis on Payment Advices"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "October"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+#: report:salary.detail.byyear:0
+msgid "Designation"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "January"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:yearly.salary.detail:0
+msgid "Pay Head Employee Breakup"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+#: report:payroll.advice:0
+msgid "Authorized Signature"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: model:ir.model,name:l10n_in_hr_payroll.model_hr_contract
+msgid "Contract"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice.line:0
+msgid "Advice Lines"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "To,"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.contract,driver_salay:0
+msgid "Check this box if you provide allowance for driver"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: field:hr.payroll.advice.line,advice_id:0
+#: field:hr.payslip,advice_id:0
+#: model:ir.model,name:l10n_in_hr_payroll.model_hr_payroll_advice
+msgid "Bank Advice"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Other No."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Draft Advices"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.payroll.advice,neft:0
+msgid "Check this box if your company use online transfer for salary"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "To"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:payment.advice.report,number:0
+msgid "Number"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "September"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: view:hr.salary.employee.month:0
+#: view:yearly.salary.detail:0
+msgid "Cancel"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Day of Payment Advices"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: constraint:hr.employee:0
+msgid "Error! You cannot create recursive hierarchy of Employee(s)."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:yearly.salary.detail:0
+msgid ""
+"This wizard will print report which display a pay head employee breakup for "
+"a specified dates."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payslip.run:0
+msgid "Payslip Batches ready to be Adviced"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Pay Slip Details"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Total Salary"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice.line,employee_id:0
+#: model:ir.model,name:l10n_in_hr_payroll.model_hr_employee
+#: view:payment.advice.report:0
+#: field:payment.advice.report,employee_id:0
+msgid "Employee"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+msgid "Compute Advice"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.employee,join_date:0
+msgid "Joining date of employee"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "Dear Sir/Madam,"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,note:0
+msgid "Description"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid ")"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:res.company:0
+msgid "Payroll"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "NEFT"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+#: report:salary.detail.byyear:0
+msgid "Address"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: field:hr.payroll.advice,bank_id:0
+#: view:payment.advice.report:0
+#: field:payment.advice.report,bank_id:0
+#: report:payroll.advice:0
+#: report:salary.detail.byyear:0
+msgid "Bank"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.salary.employee.month,end_date:0
+#: field:yearly.salary.detail,date_to:0
+msgid "End Date"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "February"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: sql_constraint:res.company:0
+msgid "The company name must be unique !"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payroll.advice:0
+#: field:hr.payroll.advice,name:0
+#: report:paylip.details.in:0
+#: field:payment.advice.report,name:0
+#: report:salary.employee.bymonth:0
+msgid "Name"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:hr.contract,city_type:0
+msgid "Metro"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.salary.employee.month:0
+#: field:hr.salary.employee.month,employee_ids:0
+#: view:yearly.salary.detail:0
+#: field:yearly.salary.detail,employee_ids:0
+msgid "Employees"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Bank Account"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "April"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "Name of the Employe"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:158
+#: code:addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py:257
+#, python-format
+msgid "Please define bank account for the %s employee"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.salary.employee.month,start_date:0
+#: field:yearly.salary.detail,date_from:0
+msgid "Start Date"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.contract:0
+msgid "Allowance"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.payroll.advice,bank_id:0
+msgid "Select the Bank from which the salary is going to be paid"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.salary.employee.month:0
+msgid "Employee Pay Head Breakup"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:salary.detail.byyear:0
+msgid "Phone No."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+msgid "Credit"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice.line,name:0
+#: report:payroll.advice:0
+msgid "Bank Account No."
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: help:hr.payroll.advice,date:0
+msgid "Advice Date is used to search Payslips"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: selection:payment.advice.report,month:0
+msgid "May"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:hr.payslip.run:0
+msgid "Create Advice"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+#: field:payment.advice.report,year:0
+msgid "Year"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: field:hr.payroll.advice,neft:0
+#: field:payment.advice.report,neft:0
+msgid "NEFT Transaction"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:paylip.details.in:0
+#: report:salary.detail.byyear:0
+#: report:salary.employee.bymonth:0
+msgid "Total"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: report:payroll.advice:0
+msgid "form period"
+msgstr ""
+
+#. module: l10n_in_hr_payroll
+#: view:payment.advice.report:0
+msgid "Year of Payment Advices"
+msgstr ""
diff --git a/addons/l10n_it/data/account.tax.code.template.csv b/addons/l10n_it/data/account.tax.code.template.csv
index 290396052f4..d6d6667f43b 100644
--- a/addons/l10n_it/data/account.tax.code.template.csv
+++ b/addons/l10n_it/data/account.tax.code.template.csv
@@ -60,6 +60,3 @@ IVC21det40,template_ivacode_pagata_21det40,IVA a credito 21% detraibile 40%,temp
IVC21Idet40,template_impcode_pagata_21det40,IVA a credito 21% detraibile 40% (imponibile),template_impcode_pagata
IVC21det50,template_ivacode_pagata_21det50,IVA a credito 21% detraibile 50%,template_ivacode_pagata
IVC21Idet50,template_impcode_pagata_21det50,IVA a credito 21% detraibile 50% (imponibile),template_impcode_pagata
-Rit,template_ra,Ritenute d'acconto,vat_code_chart_root
-RitD20,template_ritcode_20,Ritenute a debito 20%,template_ra
-RitD20I,template_ritimpcode_20,Ritenute a debito 20% (imponibile),template_ra
diff --git a/addons/l10n_it/data/account.tax.template.csv b/addons/l10n_it/data/account.tax.template.csv
index 36c4f99db79..641f495dd72 100644
--- a/addons/l10n_it/data/account.tax.template.csv
+++ b/addons/l10n_it/data/account.tax.template.csv
@@ -62,4 +62,3 @@ id,description,chart_template_id:id,name,sequence,amount,parent_id:id,child_depe
21I5,21I5,l10n_it_chart_template_generic,IVA al 21% detraibile al 50%,,0.21,,True,percent,,,purchase,template_impcode_pagata_21det50,,template_impcode_pagata_21det50,,,,False,-1,-1
21I5b,21I5b,l10n_it_chart_template_generic,IVA al 21% detraibile al 50% (I),1,0.5,21I5,False,percent,,,purchase,,,,,,,False,,
21I5a,21I5a,l10n_it_chart_template_generic,IVA al 21% detraibile al 50% (D),2,0,21I5,False,balance,1601,1601,purchase,,template_ivacode_pagata_21det50,,template_ivacode_pagata_21det50,,,False,,
-rit-20,rit-20,l10n_it_chart_template_generic,Ritenuta d'acconto al 20% (debito),,-0.2,,False,percent,2602,2602,purchase,template_ritimpcode_20,template_ritcode_20,template_ritimpcode_20,template_ritcode_20,-1,1,False,1,-1
diff --git a/addons/l10n_nl/account_chart_netherlands.xml b/addons/l10n_nl/account_chart_netherlands.xml
index 96100d9a442..f736c6f4895 100644
--- a/addons/l10n_nl/account_chart_netherlands.xml
+++ b/addons/l10n_nl/account_chart_netherlands.xml
@@ -1424,7 +1424,7 @@
-
+ Btw af te dragen laag1601other
@@ -1432,7 +1432,7 @@
-
+ Btw af te dragen hoog1602other
@@ -1448,7 +1448,7 @@
-
+ Btw te vorderen laag1611other
@@ -1456,7 +1456,7 @@
-
+ Btw te vorderen hoog1612other
@@ -3909,7 +3909,7 @@
1a
- Leveringen/diensten belast met 19% (BTW)
+ Leveringen/diensten belast met 21% (BTW)1b
@@ -4021,7 +4021,7 @@
1a
- Leveringen/diensten belast met 19% (omzet)
+ Leveringen/diensten belast met 21% (omzet)1b
@@ -4149,22 +4149,22 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
6% BTWpercent
-
-
+
+ sale
-
+ Verkopen/omzet hoog
- 19% BTW
-
+ 21% BTW
+ percent
-
-
+
+
@@ -4176,10 +4176,10 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
Verkopen/omzet overigvariabel BTW
-
+ percent
-
-
+
+
@@ -4194,20 +4194,20 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
6% BTWpercent
-
-
+
+ purchase
-
+ BTW te vorderen hoog (inkopen)
- 19% BTW
-
+ 21% BTW
+ percent
-
-
+
+ purchase
@@ -4216,10 +4216,10 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
BTW te vorderen overig (inkopen)variabel BTW
-
+ percent
-
-
+
+ purchase
@@ -4240,8 +4240,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
BTW af te dragen verlegd (inkopen)
- 19% BTW verlegd
-
+ 21% BTW verlegd
+ percent
@@ -4277,8 +4277,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
BTW te vorderen verlegd (inkopen)
- 19% BTW verlegd
-
+ 21% BTW verlegd
+ percent
@@ -4330,8 +4330,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4342,43 +4342,43 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
-
+ Inkopen import binnen EU hoog
- 19% BTW import binnen EU
-
+ 21% BTW import binnen EU
+ percentpurchase
-
+ Inkopen import binnen EU hoog(1)percent
-
-
-
+
+
+ purchase
-
+ Inkopen import binnen EU hoog(2)percent
-
-
-
+
+
+ purchase
@@ -4400,8 +4400,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4412,8 +4412,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4463,8 +4463,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4475,8 +4475,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4485,7 +4485,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
Inkopen import buiten EU hoogBTW import buiten EU
-
+ percent
@@ -4498,8 +4498,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4510,8 +4510,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4520,7 +4520,7 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
Inkopen import buiten EU overigBTW import buiten EU
-
+ percent
@@ -4533,8 +4533,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
@@ -4545,8 +4545,8 @@ TODO rubriek 1c en 1d moeten nog, zijn variabel, dus BTW percentage moet door ge
percent
-
-
+
+ purchase
diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py
index 003369be38f..b34993ffd32 100644
--- a/addons/mail/__init__.py
+++ b/addons/mail/__init__.py
@@ -22,12 +22,12 @@
import mail_message_subtype
import mail_alias
import mail_followers
+import mail_vote
import mail_favorite
import mail_message
import mail_mail
import mail_thread
import mail_group
-import mail_vote
import res_partner
import res_users
import report
diff --git a/addons/mail/data/mail_demo.xml b/addons/mail/data/mail_demo.xml
index 2ab391a3f02..a5eaa63956a 100644
--- a/addons/mail/data/mail_demo.xml
+++ b/addons/mail/data/mail_demo.xml
@@ -7,49 +7,85 @@
none
+
mail.group
- Your monthly meal vouchers arrived. You can get them at Christine's office.
-This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.
+ Your monthly meal vouchers arrived. You can get them at Christine's office.]]>comment
+
-
mail.group
-
+ Oh, I had forgotten. This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.]]>comment
+
-
mail.group
- Thanks, but where is Christine's office, if I may ask? (I'm new here)
+ Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!]]>comment
+
-
+
mail.group
- Building B3, second floor on the right :-)
+ Building B3, second floor on the right :-).]]>comment
+
+
-
mail.group
- Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!
+ Many thanks. Actually that's good news, next year I'll have to buy a new fridge, I think I will pay it with the eco-vouchers!]]>comment
+
+
+
+
+
+ Hello Demo User! I was wondering whether you had some issues with our secret task about putting cats everywhere in OpenERP.
+ comment
+
+
+
+
+
+ No specific issues, I think everything is clear.
+
+ comment
+
+
+
+
+
+ Ow, just to be sure... we were talking about lolcats, right ?
+
+ comment
+
+
+
+
+
+ Absolutely!
+
+ comment
+
+
+
diff --git a/addons/mail/data/mail_group_data.xml b/addons/mail/data/mail_group_data.xml
index 11d0ee7d04b..64d989f9e9d 100644
--- a/addons/mail/data/mail_group_data.xml
+++ b/addons/mail/data/mail_group_data.xml
@@ -9,7 +9,7 @@
Whole Company
- Discussion about best sales practices and deals.
+ General announces for all employees.
@@ -17,12 +17,11 @@
mail.groupnotification
+ Welcome to OpenERP!
- Your homepage is a summary of messages you received and key information about documents you follow.
-
-The top menu bar contains all applications you installed. You can use this <i>Settings</i> menu to install more applications, activate others features or give access to new users.
-
-To setup your preferences (name, email signature, avatar), click on the top right corner.
+ Your homepage is a summary of messages you received and key information about documents you follow.
+The top menu bar contains all applications you installed. You can use the Settings menu to install more applications, activate others features or give access to new users.
+To setup your preferences (name, email signature, avatar), click on the top right corner.
]]>
diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py
index e8cf2648f29..8d3876ec91f 100644
--- a/addons/mail/mail_followers.py
+++ b/addons/mail/mail_followers.py
@@ -61,10 +61,10 @@ class mail_notification(osv.Model):
_columns = {
'partner_id': fields.many2one('res.partner', string='Contact',
- ondelete='cascade', required=True),
- 'read': fields.boolean('Read'),
+ ondelete='cascade', required=True, select=1),
+ 'read': fields.boolean('Read', select=1),
'message_id': fields.many2one('mail.message', string='Message',
- ondelete='cascade', required=True),
+ ondelete='cascade', required=True, select=1),
}
_defaults = {
@@ -84,11 +84,13 @@ class mail_notification(osv.Model):
return False
def set_message_read(self, cr, uid, msg_ids, read=None, context=None):
- """ Set a message and its child messages as (un)read for uid.
+ """ Set messages as (un)read. Technically, the notifications related
+ to uid are set to (un)read. If for some msg_ids there are missing
+ notifications (i.e. due to load more or thread parent fetching),
+ they are created.
- :param bool read: read / unread
+ :param bool read: (un)read notification
"""
- # TDE note: use child_of or front-end send correct values ?
user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
notif_ids = self.search(cr, uid, [
('partner_id', '=', user_pid),
@@ -100,10 +102,9 @@ class mail_notification(osv.Model):
return self.write(cr, uid, notif_ids, {'read': read}, context=context)
# some messages do not have notifications: find which one, create notification, update read status
- exist_notification = dict.fromkeys(msg_ids, False)
- for notification in self.browse(cr, uid, notif_ids, context=context):
- exist_notification[notification.message_id] = True
- for msg_id in exist_notification.keys():
+ notified_msg_ids = [notification.message_id.id for notification in self.browse(cr, uid, notif_ids, context=context)]
+ to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids))
+ for msg_id in to_create_msg_ids:
self.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context)
return self.write(cr, uid, notif_ids, {'read': read}, context=context)
@@ -156,10 +157,10 @@ class mail_notification(osv.Model):
# add signature
body_html = msg.body
# if quote_context:
- # body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
- signature = msg.author_id and msg.author_id.user_ids[0].signature or ''
+ # body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
+ signature = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].signature or ''
if signature:
- body_html = tools.append_content_to_html(body_html, signature)
+ body_html = tools.append_content_to_html(body_html, signature, plaintext=True, container_tag='div')
mail_values = {
'mail_message_id': msg.id,
diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py
index d4c9c565bf3..b163882577b 100644
--- a/addons/mail/mail_group.py
+++ b/addons/mail/mail_group.py
@@ -130,7 +130,7 @@ class mail_group(osv.Model):
params = {
'search_view_id': search_ref and search_ref[1] or False,
'domain': [('model', '=', 'mail.group'), ('res_id', '=', mail_group_id)],
- 'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id},
+ 'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id, 'search_default_message_unread': True},
'res_model': 'mail.message',
'thread_level': 1,
}
diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml
index 2028e8d1b18..4a880a13c14 100644
--- a/addons/mail/mail_group_view.xml
+++ b/addons/mail/mail_group_view.xml
@@ -32,17 +32,18 @@
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index bd0ade31b68..9fd476d9d7f 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -25,6 +25,7 @@ import tools
from email.header import decode_header
from openerp import SUPERUSER_ID
from openerp.osv import osv, orm, fields
+from openerp.tools import html_email_clean
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
@@ -50,8 +51,9 @@ class mail_message(osv.Model):
_description = 'Message'
_inherit = ['ir.needaction_mixin']
_order = 'id desc'
+ _rec_name = 'record_name'
- _message_read_limit = 10
+ _message_read_limit = 30
_message_read_fields = ['id', 'parent_id', 'model', 'res_id', 'body', 'subject', 'date', 'to_read', 'email_from',
'type', 'vote_user_ids', 'attachment_ids', 'author_id', 'partner_ids', 'record_name', 'favorite_user_ids']
_message_record_name_length = 18
@@ -120,21 +122,26 @@ class mail_message(osv.Model):
"message, comment for other messages such as user replies"),
'email_from': fields.char('From',
help="Email address of the sender. This field is set when no matching partner is found for incoming emails."),
- 'author_id': fields.many2one('res.partner', 'Author',
+ 'author_id': fields.many2one('res.partner', 'Author', select=1,
+ ondelete='set null',
help="Author of the message. If not set, email_from may hold an email address that did not match any partner."),
'partner_ids': fields.many2many('res.partner', string='Recipients'),
'notified_partner_ids': fields.many2many('res.partner', 'mail_notification',
- 'message_id', 'partner_id', 'Recipients'),
+ 'message_id', 'partner_id', 'Notified partners',
+ help='Partners that have a notification pushing this message in their mailboxes'),
'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel',
'message_id', 'attachment_id', 'Attachments'),
- 'parent_id': fields.many2one('mail.message', 'Parent Message', select=True, ondelete='set null', help="Initial thread message."),
+ 'parent_id': fields.many2one('mail.message', 'Parent Message', select=True,
+ ondelete='set null', help="Initial thread message."),
'child_ids': fields.one2many('mail.message', 'parent_id', 'Child Messages'),
'model': fields.char('Related Document Model', size=128, select=1),
'res_id': fields.integer('Related Document ID', select=1),
'record_name': fields.function(_get_record_name, type='char',
store=True, string='Message Record Name',
help="Name get of the related document."),
- 'notification_ids': fields.one2many('mail.notification', 'message_id', 'Notifications'),
+ 'notification_ids': fields.one2many('mail.notification', 'message_id',
+ string='Notifications',
+ help='Technical field holding the message notifications. Use notified_partner_ids to access notified partners.'),
'subject': fields.char('Subject'),
'date': fields.datetime('Date'),
'message_id': fields.char('Message-Id', help='Message unique identifier', select=1, readonly=1),
@@ -142,7 +149,8 @@ class mail_message(osv.Model):
'to_read': fields.function(_get_to_read, fnct_search=_search_to_read,
type='boolean', string='To read',
help='Functional field to search for messages the current user has to read'),
- 'subtype_id': fields.many2one('mail.message.subtype', 'Subtype'),
+ 'subtype_id': fields.many2one('mail.message.subtype', 'Subtype',
+ ondelete='set null', select=1,),
'vote_user_ids': fields.many2many('res.users', 'mail_vote',
'message_id', 'user_id', string='Votes',
help='Users that voted for this message'),
@@ -200,67 +208,99 @@ class mail_message(osv.Model):
# Message loading for web interface
#------------------------------------------------------
- def _message_get_dict(self, cr, uid, message, context=None):
- """ Return a dict representation of the message. This representation is
- used in the JS client code, to display the messages.
+ def _message_read_dict_postprocess(self, cr, uid, messages, message_tree, context=None):
+ """ Post-processing on values given by message_read. This method will
+ handle partners in batch to avoid doing numerous queries.
- :param dict message: read result of a mail.message
+ :param list messages: list of message, as get_dict result
+ :param dict message_tree: {[msg.id]: msg browse record}
"""
- # TDE note: this method should be optimized, to lessen the number of queries, will be done ASAP
- is_author = False
- if message['author_id']:
- is_author = message['author_id'][0] == self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
- author_id = message['author_id']
- elif message['email_from']:
- author_id = (0, message['email_from'])
+ res_partner_obj = self.pool.get('res.partner')
+ ir_attachment_obj = self.pool.get('ir.attachment')
+ pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
- has_voted = False
- if uid in message.get('vote_user_ids'):
- has_voted = True
+ # 1. Aggregate partners (author_id and partner_ids) and attachments
+ partner_ids = set()
+ attachment_ids = set()
+ for key, message in message_tree.iteritems():
+ if message.author_id:
+ partner_ids |= set([message.author_id.id])
+ if message.partner_ids:
+ partner_ids |= set([partner.id for partner in message.partner_ids])
+ if message.attachment_ids:
+ attachment_ids |= set([attachment.id for attachment in message.attachment_ids])
- is_favorite = False
- if uid in message.get('favorite_user_ids'):
- is_favorite = True
+ # Filter author_ids uid can see
+ # partner_ids = self.pool.get('res.partner').search(cr, uid, [('id', 'in', partner_ids)], context=context)
+ partners = res_partner_obj.name_get(cr, uid, list(partner_ids), context=context)
+ partner_tree = dict((partner[0], partner) for partner in partners)
- is_private = True
- if message.get('model') and message.get('res_id'):
- is_private = False
+ # 2. Attachments
+ attachments = ir_attachment_obj.read(cr, uid, list(attachment_ids), ['id', 'datas_fname'], context=context)
+ attachments_tree = dict((attachment['id'], {'id': attachment['id'], 'filename': attachment['datas_fname']}) for attachment in attachments)
- try:
- attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, message['attachment_ids'], context=context)]
- except (orm.except_orm, osv.except_osv):
- attachment_ids = []
-
- # TDE note: should we send partner_ids ?
- # TDE note: shouldn't we separated followers and other partners ? costly to compute maybe ,
- try:
- partner_ids = self.pool.get('res.partner').name_get(cr, uid, message['partner_ids'], context=context)
- except (orm.except_orm, osv.except_osv):
+ # 3. Update message dictionaries
+ for message_dict in messages:
+ message_id = message_dict.get('id')
+ message = message_tree[message_id]
+ if message.author_id:
+ author = partner_tree[message.author_id.id]
+ else:
+ author = (0, message.email_from)
partner_ids = []
+ for partner in message.partner_ids:
+ if partner.id in partner_tree:
+ partner_ids.append(partner_tree[partner.id])
+ attachment_ids = []
+ for attachment in message.attachment_ids:
+ if attachment.id in attachments_tree:
+ attachment_ids.append(attachments_tree[attachment.id])
+ message_dict.update({
+ 'is_author': pid == author[0],
+ 'author_id': author,
+ 'partner_ids': partner_ids,
+ 'attachment_ids': attachment_ids,
+ })
+ return True
- return {
- 'id': message['id'],
- 'type': message['type'],
- 'attachment_ids': attachment_ids,
- 'body': message['body'],
- 'model': message['model'],
- 'res_id': message['res_id'],
- 'record_name': message['record_name'],
- 'subject': message['subject'],
- 'date': message['date'],
- 'author_id': author_id,
- 'is_author': is_author,
- 'partner_ids': partner_ids,
- 'parent_id': False,
- 'vote_nb': len(message['vote_user_ids']),
- 'has_voted': has_voted,
- 'is_private': is_private,
- 'is_favorite': is_favorite,
- 'to_read': message['to_read'],
- }
+ def _message_read_dict(self, cr, uid, message, parent_id=False, context=None):
+ """ Return a dict representation of the message. This representation is
+ used in the JS client code, to display the messages. Partners and
+ attachments related stuff will be done in post-processing in batch.
- def _message_read_add_expandables(self, cr, uid, message_list, read_messages,
- thread_level=0, message_loaded_ids=[], domain=[], parent_id=False, context=None, limit=None):
+ :param dict message: mail.message browse record
+ """
+ # private message: no model, no res_id
+ is_private = False
+ if not message.model or not message.res_id:
+ is_private = True
+ # votes and favorites: res.users ids, no prefetching should be done
+ vote_nb = len(message.vote_user_ids)
+ has_voted = uid in [user.id for user in message.vote_user_ids]
+ is_favorite = uid in [user.id for user in message.favorite_user_ids]
+
+ return {'id': message.id,
+ 'type': message.type,
+ 'body': html_email_clean(message.body),
+ 'model': message.model,
+ 'res_id': message.res_id,
+ 'record_name': message.record_name,
+ 'subject': message.subject,
+ 'date': message.date,
+ 'to_read': message.to_read,
+ 'parent_id': parent_id,
+ 'is_private': is_private,
+ 'author_id': False,
+ 'is_author': False,
+ 'partner_ids': [],
+ 'vote_nb': vote_nb,
+ 'has_voted': has_voted,
+ 'is_favorite': is_favorite,
+ 'attachment_ids': [],
+ }
+
+ def _message_read_add_expandables(self, cr, uid, messages, message_tree, parent_tree,
+ message_unload_ids=[], thread_level=0, domain=[], parent_id=False, context=None):
""" Create expandables for message_read, to load new messages.
1. get the expandable for new threads
if display is flat (thread_level == 0):
@@ -275,96 +315,82 @@ class mail_message(osv.Model):
for each hole in the child list based on message displayed,
create an expandable
- :param list message_list:list of message structure for the Chatter
+ :param list messages: list of message structure for the Chatter
widget to which expandables are added
- :param dict read_messages: dict [id]: read result of the messages to
- easily have access to their values, given their ID
+ :param dict message_tree: dict [id]: browse record of this message
+ :param dict parent_tree: dict [parent_id]: [child_ids]
+ :param list message_unload_ids: list of message_ids we do not want
+ to load
:return bool: True
"""
- def _get_expandable(domain, message_nb, parent_id, id, model):
+ def _get_expandable(domain, message_nb, parent_id, max_limit):
return {
'domain': domain,
'nb_messages': message_nb,
'type': 'expandable',
'parent_id': parent_id,
- 'id': id,
- # TDE note: why do we need model sometimes, and sometimes not ???
- 'model': model,
+ 'max_limit': max_limit,
}
- # all_not_loaded_ids = []
- id_list = sorted(read_messages.keys())
- if not id_list:
- return message_list
+ if not messages:
+ return True
+ message_ids = sorted(message_tree.keys())
# 1. get the expandable for new threads
if thread_level == 0:
- exp_domain = domain + [('id', '<', min(message_loaded_ids + id_list))]
+ exp_domain = domain + [('id', '<', min(message_unload_ids + message_ids))]
else:
- exp_domain = domain + ['!', ('id', 'child_of', message_loaded_ids + id_list)]
+ exp_domain = domain + ['!', ('id', 'child_of', message_unload_ids + parent_tree.keys())]
ids = self.search(cr, uid, exp_domain, context=context, limit=1)
if ids:
- message_list.append(_get_expandable(exp_domain, -1, parent_id, -1, None))
+ # inside a thread: prepend
+ if parent_id:
+ messages.insert(0, _get_expandable(exp_domain, -1, parent_id, True))
+ # new threads: append
+ else:
+ messages.append(_get_expandable(exp_domain, -1, parent_id, True))
# 2. get the expandables for new messages inside threads if display is not flat
if thread_level == 0:
return True
- for message_id in id_list:
- message = read_messages[message_id]
+ for message_id in message_ids:
+ message = message_tree[message_id]
- # message is not a thread header (has a parent_id)
- # TDE note: parent_id is false is there is a parent we can not see -> ok
- if message.get('parent_id'):
+ # generate only for thread header messages (TDE note: parent_id may be False is uid cannot see parent_id, seems ok)
+ if message.parent_id:
continue
- # TDE note: check search is correctly implemented in mail.message
- not_loaded_ids = self.search(cr, uid, [
- ('id', 'child_of', message['id']),
- ('id', 'not in', message_loaded_ids),
- ], context=context, limit=self._message_read_more_limit)
- if not not_loaded_ids:
+ # check there are message for expandable
+ child_ids = set([child.id for child in message.child_ids]) - set(message_unload_ids)
+ child_ids = sorted(list(child_ids), reverse=True)
+ if not child_ids:
continue
- # all_not_loaded_ids += not_loaded_ids
- # group childs not read
- id_min, id_max, nb = max(not_loaded_ids), 0, 0
- for not_loaded_id in not_loaded_ids:
- if not read_messages.get(not_loaded_id):
+ # make groups of unread messages
+ id_min, id_max, nb = max(child_ids), 0, 0
+ for child_id in child_ids:
+ if not child_id in message_ids:
nb += 1
- if id_min > not_loaded_id:
- id_min = not_loaded_id
- if id_max < not_loaded_id:
- id_max = not_loaded_id
+ if id_min > child_id:
+ id_min = child_id
+ if id_max < child_id:
+ id_max = child_id
elif nb > 0:
exp_domain = [('id', '>=', id_min), ('id', '<=', id_max), ('id', 'child_of', message_id)]
- message_list.append(_get_expandable(exp_domain, nb, message_id, id_min, message.get('model')))
- id_min, id_max, nb = max(not_loaded_ids), 0, 0
+ messages.append(_get_expandable(exp_domain, nb, message_id, False))
+ id_min, id_max, nb = max(child_ids), 0, 0
else:
- id_min, id_max, nb = max(not_loaded_ids), 0, 0
+ id_min, id_max, nb = max(child_ids), 0, 0
if nb > 0:
exp_domain = [('id', '>=', id_min), ('id', '<=', id_max), ('id', 'child_of', message_id)]
- message_list.append(_get_expandable(exp_domain, nb, message_id, id_min, message.get('model')))
-
- # message_loaded_ids = list(set(message_loaded_ids + read_messages.keys() + all_not_loaded_ids))
+ idx = [msg.get('id') for msg in messages].index(message_id) + 1
+ # messages.append(_get_expandable(exp_domain, nb, message_id, id_min))
+ messages.insert(idx, _get_expandable(exp_domain, nb, message_id, False))
return True
- def _get_parent(self, cr, uid, message, context=None):
- """ Tools method that tries to get the parent of a mail.message. If
- no parent, or if uid has no access right on the parent, False
- is returned.
-
- :param dict message: read result of a mail.message
- """
- if not message['parent_id']:
- return False
- parent_id = message['parent_id'][0]
- try:
- return self.read(cr, uid, parent_id, self._message_read_fields, context=context)
- except (orm.except_orm, osv.except_osv):
- return False
-
- def message_read(self, cr, uid, ids=None, domain=None, message_unload_ids=None, thread_level=0, context=None, parent_id=False, limit=None):
+ def message_read(self, cr, uid, ids=None, domain=None, message_unload_ids=None,
+ thread_level=0, context=None, parent_id=False, limit=None):
""" Read messages from mail.message, and get back a list of structured
messages to be displayed as discussion threads. If IDs is set,
fetch these records. Otherwise use the domain to fetch messages.
@@ -388,46 +414,56 @@ class mail_message(osv.Model):
ancestors and expandables
:return list: list of message structure for the Chatter widget
"""
- # print 'message_read', ids, domain, message_unload_ids, thread_level, context, parent_id, limit
assert thread_level in [0, 1], 'message_read() thread_level should be 0 (flat) or 1 (1 level of thread); given %s.' % thread_level
domain = domain if domain is not None else []
message_unload_ids = message_unload_ids if message_unload_ids is not None else []
if message_unload_ids:
domain += [('id', 'not in', message_unload_ids)]
limit = limit or self._message_read_limit
- read_messages = {}
+ message_tree = {}
message_list = []
+ parent_tree = {}
# no specific IDS given: fetch messages according to the domain, add their parents if uid has access to
if ids is None:
ids = self.search(cr, uid, domain, context=context, limit=limit)
- for message in self.read(cr, uid, ids, self._message_read_fields, context=context):
- message_id = message['id']
- # if not in tree and not in message_loaded list
- if not message_id in read_messages and not message_id in message_unload_ids:
- read_messages[message_id] = message
- message_list.append(self._message_get_dict(cr, uid, message, context=context))
+ # fetch parent if threaded, sort messages
+ for message in self.browse(cr, uid, ids, context=context):
+ message_id = message.id
+ if message_id in message_tree:
+ continue
+ message_tree[message_id] = message
- # get the older ancestor the user can read, update its ancestor field
- if not thread_level:
- message_list[-1]['parent_id'] = parent_id
- continue
- parent = self._get_parent(cr, uid, message, context=context)
- while parent and parent.get('id') != parent_id:
- message_list[-1]['parent_id'] = parent.get('id')
- message = parent
- parent = self._get_parent(cr, uid, message, context=context)
- # if in thread: add its ancestor to the list of messages
- if not message['id'] in read_messages and not message['id'] in message_unload_ids:
- read_messages[message['id']] = message
- message_list.append(self._message_get_dict(cr, uid, message, context=context))
+ # find parent_id
+ if thread_level == 0:
+ tree_parent_id = parent_id
+ else:
+ tree_parent_id = message_id
+ parent = message
+ while parent.parent_id and parent.parent_id.id != parent_id:
+ parent = parent.parent_id
+ tree_parent_id = parent.id
+ if not parent.id in message_tree:
+ message_tree[parent.id] = parent
+ # newest messages first
+ parent_tree.setdefault(tree_parent_id, [])
+ if tree_parent_id != message_id:
+ parent_tree[tree_parent_id].append(self._message_read_dict(cr, uid, message_tree[message_id], parent_id=tree_parent_id, context=context))
+
+ if thread_level:
+ for key, message_id_list in parent_tree.iteritems():
+ message_id_list.sort(key=lambda item: item['id'])
+ message_id_list.insert(0, self._message_read_dict(cr, uid, message_tree[key], context=context))
+
+ parent_list = parent_tree.items()
+ parent_list = sorted(parent_list, key=lambda item: max([msg.get('id') for msg in item[1]]) if item[1] else item[0], reverse=True)
+ message_list = [message for (key, msg_list) in parent_list for message in msg_list]
# get the child expandable messages for the tree
- message_list = sorted(message_list, key=lambda k: k['id'])
- self._message_read_add_expandables(cr, uid, message_list, read_messages, thread_level=thread_level,
- message_loaded_ids=message_unload_ids, domain=domain, parent_id=parent_id, context=context, limit=limit)
-
+ self._message_read_dict_postprocess(cr, uid, message_list, message_tree, context=context)
+ self._message_read_add_expandables(cr, uid, message_list, message_tree, parent_tree,
+ thread_level=thread_level, message_unload_ids=message_unload_ids, domain=domain, parent_id=parent_id, context=context)
return message_list
# TDE Note: do we need this ?
@@ -461,7 +497,6 @@ class mail_message(osv.Model):
- otherwise: remove the id
"""
# Rules do not apply to administrator
- # print '_search', uid, args
if uid == SUPERUSER_ID:
return super(mail_message, self)._search(cr, uid, args, offset=offset, limit=limit, order=order,
context=context, count=count, access_rights_uid=access_rights_uid)
@@ -599,6 +634,8 @@ class mail_message(osv.Model):
def create(self, cr, uid, values, context=None):
if not values.get('message_id') and values.get('res_id') and values.get('model'):
values['message_id'] = tools.generate_tracking_message_id('%(res_id)s-%(model)s' % values)
+ elif not values.get('message_id'):
+ values['message_id'] = tools.generate_tracking_message_id('private')
newid = super(mail_message, self).create(cr, uid, values, context)
self._notify(cr, SUPERUSER_ID, newid, context=context)
return newid
@@ -729,7 +766,7 @@ class mail_message(osv.Model):
], context=context)
fol_objs = fol_obj.read(cr, uid, fol_ids, ['partner_id'], context=context)
partners_to_notify |= set(fol['partner_id'][0] for fol in fol_objs)
- # when writing to a wall
+ # remove me from notified partners, unless the message is written on my own wall
if message.get('author_id') and message.get('model') == "res.partner" and message.get('res_id') == message.get('author_id')[0]:
partners_to_notify |= set([message.get('author_id')[0]])
elif message.get('author_id'):
diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml
index 93b35797fd5..7d2e9483773 100644
--- a/addons/mail/mail_message_view.xml
+++ b/addons/mail/mail_message_view.xml
@@ -59,21 +59,26 @@
+
+
-
+
+
@@ -84,7 +89,6 @@
formtree,form
- {'search_default_to_read_message':True}
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index f3203336615..ee1a015396b 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 ''
@@ -319,10 +319,12 @@ class mail_thread(osv.AbstractModel):
"""
assert isinstance(message, Message), 'message must be an email.message.Message at this point'
message_id = message.get('Message-Id')
+ references = decode_header(message, 'References')
+ in_reply_to = decode_header(message, 'In-Reply-To')
# 1. Verify if this is a reply to an existing thread
- references = decode_header(message, 'References') or decode_header(message, 'In-Reply-To')
- ref_match = references and tools.reference_re.search(references)
+ thread_references = references or in_reply_to
+ ref_match = thread_references and tools.reference_re.search(thread_references)
if ref_match:
thread_id = int(ref_match.group(1))
model = ref_match.group(2) or model
@@ -333,6 +335,14 @@ class mail_thread(osv.AbstractModel):
message_id, model, thread_id, custom_values, uid)
return [(model, thread_id, custom_values, uid)]
+ # Verify this is a reply to a private message
+ message_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', in_reply_to)], limit=1, context=context)
+ if message_ids:
+ message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
+ _logger.debug('Routing mail with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
+ message_id, message.id, custom_values, uid)
+ return [(False, 0, custom_values, uid)]
+
# 2. Look for a matching mail.alias entry
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
# for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
@@ -376,14 +386,19 @@ class mail_thread(osv.AbstractModel):
def message_process(self, cr, uid, model, message, custom_values=None,
save_original=False, strip_attachments=False,
thread_id=None, context=None):
- """Process an incoming RFC2822 email message, relying on
- ``mail.message.parse()`` for the parsing operation,
- and ``message_route()`` to figure out the target model.
+ """ Process an incoming RFC2822 email message, relying on
+ ``mail.message.parse()`` for the parsing operation,
+ and ``message_route()`` to figure out the target model.
- Once the target model is known, its ``message_new`` method
- is called with the new message (if the thread record did not exist)
+ Once the target model is known, its ``message_new`` method
+ is called with the new message (if the thread record did not exist)
or its ``message_update`` method (if it did).
+ There is a special case where the target model is False: a reply
+ to a private message. In this case, we skip the message_new /
+ message_update step, to just post a new message using mail_thread
+ message_post.
+
:param string model: the fallback model to use if the message
does not match any of the currently configured mail aliases
(may be None if a matching alias is supposed to be present)
@@ -425,15 +440,19 @@ class mail_thread(osv.AbstractModel):
for model, thread_id, custom_values, user_id in routes:
if self._name != model:
context.update({'thread_model': model})
- model_pool = self.pool.get(model)
- assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
- "Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
- (msg['message_id'], model)
- if thread_id and hasattr(model_pool, 'message_update'):
- model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
+ if model:
+ model_pool = self.pool.get(model)
+ assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
+ "Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
+ (msg['message_id'], model)
+ if thread_id and hasattr(model_pool, 'message_update'):
+ model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
+ else:
+ thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
else:
- thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
- model_pool.message_post(cr, uid, [thread_id], context=context, **msg)
+ assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message."
+ model_pool = self.pool.get('mail.thread')
+ model_pool.message_post_user_api(cr, uid, [thread_id], context=context, content_subtype='html', **msg)
return thread_id
def message_new(self, cr, uid, msg_dict, custom_values=None, context=None):
@@ -501,7 +520,7 @@ class mail_thread(osv.AbstractModel):
body = tools.ustr(body, encoding, errors='replace')
if message.get_content_type() == 'text/plain':
# text/plain ->
- body = tools.append_content_to_html(u'', body)
+ body = tools.append_content_to_html(u'', body, preserve=True)
else:
alternative = (message.get_content_type() == 'multipart/alternative')
for part in message.walk():
@@ -516,7 +535,7 @@ class mail_thread(osv.AbstractModel):
# 2) text/plain ->
if part.get_content_type() == 'text/plain' and (not alternative or not body):
body = tools.append_content_to_html(body, tools.ustr(part.get_payload(decode=True),
- encoding, errors='replace'))
+ encoding, errors='replace'), preserve=True)
# 3) text/html -> raw
elif part.get_content_type() == 'text/html':
html = tools.ustr(part.get_payload(decode=True), encoding, errors='replace')
@@ -556,7 +575,6 @@ class mail_thread(osv.AbstractModel):
"""
msg_dict = {
'type': 'email',
- 'subtype': 'mail.mt_comment',
'author_id': False,
}
if not isinstance(message, Message):
@@ -588,7 +606,7 @@ class mail_thread(osv.AbstractModel):
else:
msg_dict['email_from'] = message.get('from')
partner_ids = self._message_find_partners(cr, uid, message, ['From', 'To', 'Cc'], context=context)
- msg_dict['partner_ids'] = partner_ids
+ msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids]
if 'Date' in message:
date_hdr = decode(message.get('Date'))
@@ -629,7 +647,8 @@ class mail_thread(osv.AbstractModel):
mail.message ID. Extra keyword arguments will be used as default
column values for the new mail.message record.
Auto link messages for same id and object
- :param int thread_id: thread ID to post into, or list with one ID
+ :param int thread_id: thread ID to post into, or list with one ID;
+ if False/0, mail.message model will also be set as False
:param str body: body of the message, usually raw HTML that will
be sanitized
:param str subject: optional subject
@@ -639,10 +658,13 @@ class mail_thread(osv.AbstractModel):
``(name,content)``, where content is NOT base64 encoded
:return: ID of newly created mail.message
"""
- context = context or {}
- attachments = attachments or []
+ if context is None:
+ context = {}
+ if attachments is None:
+ attachments = {}
+
assert (not thread_id) or isinstance(thread_id, (int, long)) or \
- (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id"
+ (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id; should be 0, False, an ID or a list with one ID"
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id and thread_id[0]
mail_message = self.pool.get('mail.message')
@@ -682,7 +704,6 @@ class mail_thread(osv.AbstractModel):
# avoid loops when finding ancestors
processed_list = []
if message_ids:
- _counter, _counter_max = 0, 200
message = mail_message.browse(cr, SUPERUSER_ID, message_ids[0], context=context)
while (message.parent_id and message.parent_id.id not in processed_list):
processed_list.append(message.parent_id.id)
@@ -707,18 +728,45 @@ class mail_thread(osv.AbstractModel):
return mail_message.create(cr, uid, values, context=context)
- def message_post_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False, attachment_ids=None, context=None):
- """ Wrapper on message_post, used only in Chatter (JS). The purpose is
- to handle attachments.
- # TDE FIXME: body is plaintext: convert it into html
+ def message_post_user_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False,
+ attachment_ids=None, context=None, content_subtype='plaintext', **kwargs):
+ """ Wrapper on message_post, used for user input :
+ - mail gateway
+ - quick reply in Chatter (refer to mail.js), not
+ the mail.compose.message wizard
+ The purpose is to perform some pre- and post-processing:
+ - if body is plaintext: convert it into html
+ - if parent_id: handle reply to a previous message by adding the
+ parent partners to the message
+ - type and subtype: comment and mail.mt_comment by default
+ - attachment_ids: supposed not attached to any document; attach them
+ to the related document. Should only be set by Chatter.
"""
- new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type='comment',
- subtype='mail.mt_comment', parent_id=parent_id, context=context)
+ ir_attachment = self.pool.get('ir.attachment')
+ mail_message = self.pool.get('mail.message')
- # HACK FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
+ # 1. Pre-processing: body, partner_ids, type and subtype
+ if content_subtype == 'plaintext':
+ body = tools.plaintext2html(body)
+
+ partner_ids = kwargs.pop('partner_ids', [])
+ if parent_id:
+ parent_message = self.pool.get('mail.message').browse(cr, uid, parent_id, context=context)
+ partner_ids += [(4, partner.id) for partner in parent_message.partner_ids]
+ # TDE FIXME HACK: mail.thread -> private message
+ if self._name == 'mail.thread' and parent_message.author_id.id:
+ partner_ids.append((4, parent_message.author_id.id))
+
+ message_type = kwargs.pop('type', 'comment')
+ message_subtype = kwargs.pop('subtype', 'mail.mt_comment')
+
+ # 2. Post message
+ new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=message_type,
+ subtype=message_subtype, parent_id=parent_id, context=context, partner_ids=partner_ids, **kwargs)
+
+ # 3. Post-processing
+ # HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
if attachment_ids:
- ir_attachment = self.pool.get('ir.attachment')
- mail_message = self.pool.get('mail.message')
filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
('res_model', '=', 'mail.compose.message'),
('res_id', '=', 0),
diff --git a/addons/mail/mail_thread_view.xml b/addons/mail/mail_thread_view.xml
index 07b24725b05..3a37218c813 100644
--- a/addons/mail/mail_thread_view.xml
+++ b/addons/mail/mail_thread_view.xml
@@ -4,48 +4,126 @@
Inboxmail.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.
+
\n')
_mail_bodyalt2 = 'Pigs rules\nAdmin'
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
@@ -399,7 +367,7 @@ class test_mail(TestMailMockups):
# Test: sent_email: email send by server: correct subject, body, body_alternative
for sent_email in sent_emails:
self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
- self.assertEqual(sent_email['body'], _mail_body1 + '\n
Bert Tartopoils
\n', 'sent_email body incorrect')
+ self.assertEqual(sent_email['body'], _mail_body1 + '\nBert Tartopoils\n', 'sent_email body incorrect')
# the html2plaintext uses etree or beautiful soup, so the result may be slighly different
# depending if you have installed beautiful soup.
self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')
@@ -495,7 +463,8 @@ class test_mail(TestMailMockups):
# 1. Comment group_pigs with body_text and subject
compose_id = mail_compose.create(cr, uid,
{'subject': _subject, 'body_text': _body_text, 'partner_ids': [(4, p_c_id), (4, p_d_id)]},
- {'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id})
+ {'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id,
+ 'default_content_subtype': 'plaintext'})
compose = mail_compose.browse(cr, uid, compose_id)
# Test: mail.compose.message: composition_mode, model, res_id
self.assertEqual(compose.composition_mode, 'comment', 'mail.compose.message incorrect composition_mode')
@@ -576,7 +545,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 +557,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 +571,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 +582,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 +591,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 +603,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 +624,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 +635,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 +682,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 +696,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/tests/test_mail_access_rights.py b/addons/mail/tests/test_mail_access_rights.py
index 7b90e07b9b5..ec08d257efe 100644
--- a/addons/mail/tests/test_mail_access_rights.py
+++ b/addons/mail/tests/test_mail_access_rights.py
@@ -19,11 +19,11 @@
#
##############################################################################
-from openerp.addons.mail.tests import test_mail
+from openerp.addons.mail.tests import test_mail_mockup
from osv.orm import except_orm
-class test_mail_access_rights(test_mail.TestMailMockups):
+class test_mail_access_rights(test_mail_mockup.TestMailMockups):
def setUp(self):
super(test_mail_access_rights, self).setUp()
diff --git a/addons/mail/tests/test_mail_mockup.py b/addons/mail/tests/test_mail_mockup.py
new file mode 100644
index 00000000000..cba04a0c6b3
--- /dev/null
+++ b/addons/mail/tests/test_mail_mockup.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.tests import common
+
+
+class TestMailMockups(common.TransactionCase):
+
+ def _mock_smtp_gateway(self, *args, **kwargs):
+ return True
+
+ def _init_mock_build_email(self):
+ self._build_email_args_list = []
+ self._build_email_kwargs_list = []
+
+ def _mock_build_email(self, *args, **kwargs):
+ """ Mock build_email to be able to test its values. Store them into
+ some internal variable for latter processing. """
+ self._build_email_args_list.append(args)
+ self._build_email_kwargs_list.append(kwargs)
+ return self._build_email(*args, **kwargs)
+
+ def setUp(self):
+ super(TestMailMockups, self).setUp()
+ # Install mock SMTP gateway
+ self._init_mock_build_email()
+ self._build_email = self.registry('ir.mail_server').build_email
+ self.registry('ir.mail_server').build_email = self._mock_build_email
+ self._send_email = self.registry('ir.mail_server').send_email
+ self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
+
+ def tearDown(self):
+ # Remove mocks
+ self.registry('ir.mail_server').build_email = self._build_email
+ self.registry('ir.mail_server').send_email = self._send_email
+ super(TestMailMockups, self).tearDown()
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index 33712847534..839a3a6970e 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -114,7 +114,7 @@ class mail_compose_message(osv.TransientModel):
_defaults = {
'composition_mode': 'comment',
- 'content_subtype': lambda self, cr, uid, ctx={}: 'plain',
+ 'content_subtype': lambda self, cr, uid, ctx={}: 'html',
'body_text': lambda self, cr, uid, ctx={}: False,
'body': lambda self, cr, uid, ctx={}: '',
'subject': lambda self, cr, uid, ctx={}: False,
@@ -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/i18n/lt.po b/addons/marketing/i18n/lt.po
new file mode 100644
index 00000000000..70b6c1645b3
--- /dev/null
+++ b/addons/marketing/i18n/lt.po
@@ -0,0 +1,28 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-02-08 00:36+0000\n"
+"PO-Revision-Date: 2012-11-15 13:26+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Lithuanian \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-16 04:36+0000\n"
+"X-Generator: Launchpad (build 16272)\n"
+
+#. module: marketing
+#: model:res.groups,name:marketing.group_marketing_manager
+msgid "Manager"
+msgstr ""
+
+#. module: marketing
+#: model:res.groups,name:marketing.group_marketing_user
+msgid "User"
+msgstr ""
diff --git a/addons/mrp/mrp_data.xml b/addons/mrp/mrp_data.xml
index 3310bc98899..a6b65b7c475 100644
--- a/addons/mrp/mrp_data.xml
+++ b/addons/mrp/mrp_data.xml
@@ -6,11 +6,11 @@
mail.groupnotification
+ MRP application installed!
- Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers.
-This application supports complete integration and production scheduling for stockable goods, consumables, and services.
-
-From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.
+ Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers.
+This application supports complete integration and production scheduling for stockable goods, consumables, and services.
+
From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.
]]>
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.27841.8855.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_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/__openerp__.py b/addons/note/__openerp__.py
index d87ee70086d..797270637e2 100644
--- a/addons/note/__openerp__.py
+++ b/addons/note/__openerp__.py
@@ -38,6 +38,7 @@ Notes can be found in the 'Home' menu.
'author': 'OpenERP SA',
'website': 'http://openerp.com',
'summary': 'Sticky notes, Collaborative, Memos',
+ 'sequence': 9,
'depends': [
'mail',
],
diff --git a/addons/note/i18n/pt_BR.po b/addons/note/i18n/pt_BR.po
new file mode 100644
index 00000000000..eea43f2275f
--- /dev/null
+++ b/addons/note/i18n/pt_BR.po
@@ -0,0 +1,334 @@
+# Brazilian Portuguese translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-11-02 12:54+0000\n"
+"PO-Revision-Date: 2012-11-14 04:29+0000\n"
+"Last-Translator: Guilherme R. Santos \n"
+"Language-Team: Brazilian Portuguese \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-15 04:42+0000\n"
+"X-Generator: Launchpad (build 16265)\n"
+
+#. module: note
+#: sql_constraint:res.users:0
+msgid "You can not have two users with the same login !"
+msgstr "Você não pode ter dois usuários com o mesmo login!"
+
+#. module: note
+#: field:note.note,memo:0
+msgid "Note Content"
+msgstr "Conteúdo da Nota"
+
+#. module: note
+#: view:note.stage:0
+msgid "Stages of Notes"
+msgstr "Estágio das Notas"
+
+#. module: note
+#: model:ir.model,name:note.model_base_config_settings
+msgid "base.config.settings"
+msgstr "base.config.settings"
+
+#. module: note
+#: model:ir.model,name:note.model_note_tag
+msgid "Note Tag"
+msgstr "Tag da Nota"
+
+#. module: note
+#: model:res.groups,name:note.group_note_fancy
+msgid "Notes / Fancy mode"
+msgstr "Notas / Modo fantasia"
+
+#. module: note
+#: model:ir.model,name:note.model_note_note
+#: view:note.note:0
+msgid "Note"
+msgstr "Nota"
+
+#. module: note
+#: view:note.note:0
+msgid "Group By..."
+msgstr "Agrupar Por..."
+
+#. module: note
+#: field:note.note,message_summary:0
+msgid "Summary"
+msgstr "Resumo"
+
+#. module: note
+#: field:note.note,message_follower_ids:0
+msgid "Followers"
+msgstr "Seguidores"
+
+#. module: note
+#: model:ir.actions.act_window,help:note.action_note_note
+msgid ""
+"
\n"
+" Click to add a personal note.\n"
+"
\n"
+" Use notes to organize personal tasks or notes. All\n"
+" notes are private; no one else will be able to see them. "
+"However\n"
+" you can share some notes with other people by inviting "
+"followers\n"
+" on the note. (Useful for meeting minutes, especially if\n"
+" you activate the pad feature for collaborative writings).\n"
+"
\n"
+" You can customize how you process your notes/tasks by adding,\n"
+" removing or modifying columns.\n"
+"
\n"
+" "
+msgstr ""
+"
\n"
+" Clique para adicionar nota pessoal.\n"
+"
\n"
+" Use notas para organizar tarefas ou notas pessoais. Todas\n"
+" notas são privadas; ninguém mais é capaz de vê-las. Contudo\n"
+" você pode compartilhar algumas notas com outras pessoas "
+"convidando seguidores\n"
+" na nota. (Útil para atas de reunião, especialmente se\n"
+" você ativar o recurso \"PAD\" para textos colaborativos).\n"
+"
\n"
+" Você pode customizar a forma como você processa suas "
+"notas/tarefas adicionando,\n"
+" removendo ou modificando colunas.\n"
+"
\n"
+" "
+
+#. module: note
+#: view:note.note:0
+msgid "kanban note"
+msgstr "nota kanban"
+
+#. module: note
+#: model:note.stage,name:note.demo_note_stage_01
+#: model:note.stage,name:note.note_stage_01
+msgid "Today"
+msgstr "Hoje"
+
+#. module: note
+#: model:ir.model,name:note.model_res_users
+msgid "Users"
+msgstr "Usuários"
+
+#. module: note
+#: view:note.note:0
+msgid "í"
+msgstr "í"
+
+#. module: note
+#: view:note.stage:0
+msgid "Stage of Notes"
+msgstr "Estágios das Notas"
+
+#. module: note
+#: field:note.note,message_unread:0
+msgid "Unread Messages"
+msgstr "Mensagens não lidas"
+
+#. module: note
+#: field:note.note,current_partner_id:0
+msgid "unknown"
+msgstr "desconhecido"
+
+#. module: note
+#: view:note.note:0
+msgid "By sticky note Category"
+msgstr ""
+
+#. module: note
+#: help:note.note,message_unread:0
+msgid "If checked new messages require your attention."
+msgstr "Se marcado novas mensagens requerem sua atenção"
+
+#. module: note
+#: field:note.stage,name:0
+msgid "Stage Name"
+msgstr "Nome do Estágio"
+
+#. module: note
+#: field:note.note,message_is_follower:0
+msgid "Is a Follower"
+msgstr "É um seguidor"
+
+#. module: note
+#: view:note.note:0
+msgid "title"
+msgstr "título"
+
+#. module: note
+#: model:note.stage,name:note.demo_note_stage_02
+#: model:note.stage,name:note.note_stage_02
+msgid "Tomorrow"
+msgstr "Amanhã"
+
+#. module: note
+#: view:note.note:0
+#: field:note.note,open:0
+msgid "Active"
+msgstr "Ativo"
+
+#. module: note
+#: help:note.stage,user_id:0
+msgid "Owner of the note stage."
+msgstr "Proprietário do estágio da nota."
+
+#. module: note
+#: model:ir.ui.menu,name:note.menu_notes_stage
+msgid "Categories"
+msgstr "Categorias"
+
+#. module: note
+#: field:note.note,message_comment_ids:0
+#: help:note.note,message_comment_ids:0
+msgid "Comments and emails"
+msgstr "Comentários e emails"
+
+#. module: note
+#: field:note.tag,name:0
+msgid "Tag Name"
+msgstr "Nome da Tag"
+
+#. module: note
+#: field:note.note,message_ids:0
+msgid "Messages"
+msgstr "Mensagens"
+
+#. module: note
+#: view:base.config.settings:0
+#: model:ir.actions.act_window,name:note.action_note_note
+#: model:ir.ui.menu,name:note.menu_note_notes
+#: view:note.note:0
+#: model:note.stage,name:note.note_stage_04
+msgid "Notes"
+msgstr "Notas"
+
+#. module: note
+#: model:note.stage,name:note.demo_note_stage_03
+#: model:note.stage,name:note.note_stage_03
+msgid "Later"
+msgstr "Mais tarde"
+
+#. module: note
+#: model:ir.model,name:note.model_note_stage
+msgid "Note Stage"
+msgstr "Estágio da Nota"
+
+#. module: note
+#: view:note.note:0
+msgid "dropdown menu"
+msgstr "dropdown menu"
+
+#. module: note
+#: model:note.stage,name:note.demo_note_stage_04
+msgid "Morning"
+msgstr "Manhã"
+
+#. module: note
+#: help:note.stage,sequence:0
+msgid "Used to order the note stages"
+msgstr "Usado para ordenar os estágios das notas"
+
+#. module: note
+#: view:note.note:0
+msgid "W"
+msgstr "W"
+
+#. module: note
+#: field:note.note,stage_ids:0
+msgid "Stages of Users"
+msgstr "Estágios de Usuários"
+
+#. module: note
+#: field:note.note,name:0
+msgid "Note Summary"
+msgstr "Resumo da Nota"
+
+#. module: note
+#: model:ir.actions.act_window,name:note.action_note_stage
+#: view:note.note:0
+msgid "Stages"
+msgstr "Estágios"
+
+#. module: note
+#: help:note.note,message_ids:0
+msgid "Messages and communication history"
+msgstr "Histórico de mensagens e comunicação"
+
+#. module: note
+#: view:note.note:0
+msgid "Delete"
+msgstr "Excluir"
+
+#. module: note
+#: field:note.note,color:0
+msgid "Color Index"
+msgstr "Índice de Cores"
+
+#. module: note
+#: field:note.note,sequence:0
+#: field:note.stage,sequence:0
+msgid "Sequence"
+msgstr "Sequencia"
+
+#. module: note
+#: field:note.note,tag_ids:0
+msgid "Tags"
+msgstr "Tags"
+
+#. module: note
+#: view:note.note:0
+msgid "Archive"
+msgstr "Arquivo"
+
+#. module: note
+#: field:base.config.settings,module_note_pad:0
+msgid "Use collaborative pads (etherpad)"
+msgstr "Usar pads colaborativos (etherpad)"
+
+#. module: note
+#: help:note.note,message_summary:0
+msgid ""
+"Holds the Chatter summary (number of messages, ...). This summary is "
+"directly in html format in order to be inserted in kanban views."
+msgstr ""
+
+#. module: note
+#: field:base.config.settings,group_note_fancy:0
+msgid "Use fancy layouts for notes"
+msgstr "Usar leiautes fantasia para notas"
+
+#. module: note
+#: field:note.stage,user_id:0
+msgid "Owner"
+msgstr "Proprietário"
+
+#. module: note
+#: constraint:res.users:0
+msgid "The chosen company is not in the allowed companies for this user"
+msgstr ""
+"A empresa escolhida não está entre as empresas habilitadas para este usuário"
+
+#. module: note
+#: view:note.note:0
+#: field:note.note,stage_id:0
+msgid "Stage"
+msgstr "Estágio"
+
+#. module: note
+#: field:note.note,date_done:0
+msgid "Date done"
+msgstr "Data de conclusão"
+
+#. module: note
+#: field:note.stage,fold:0
+msgid "Folded by Default"
+msgstr "Dobrado por Padrão"
diff --git a/addons/note/note.py b/addons/note/note.py
index fe5eca5efd7..9e1a9187095 100644
--- a/addons/note/note.py
+++ b/addons/note/note.py
@@ -20,9 +20,7 @@
##############################################################################
from openerp.osv import osv, fields
-from tools.translate import _
-import re
-from openerp.tools.misc import html2plaintext
+from openerp.tools import html2plaintext
class note_stage(osv.osv):
""" Category of Note """
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/security/ir.rule.xml b/addons/note/security/ir.rule.xml
index 1195314cc9e..b0c79561355 100644
--- a/addons/note/security/ir.rule.xml
+++ b/addons/note/security/ir.rule.xml
@@ -6,6 +6,10 @@
[('message_follower_ids','=',user.partner_id.id)]
+
+
+
+
diff --git a/addons/pad/pad.py b/addons/pad/pad.py
index 932fc5a21a4..8f9f79a78e0 100644
--- a/addons/pad/pad.py
+++ b/addons/pad/pad.py
@@ -6,7 +6,7 @@ import string
import urllib2
import logging
from tools.translate import _
-from openerp.tools.misc import html2plaintext
+from openerp.tools import html2plaintext
from py_etherpad import EtherpadLiteClient
_logger = logging.getLogger(__name__)
diff --git a/addons/point_of_sale/point_of_sale_data.xml b/addons/point_of_sale/point_of_sale_data.xml
index 634d2606aa8..01d8dd9ff60 100644
--- a/addons/point_of_sale/point_of_sale_data.xml
+++ b/addons/point_of_sale/point_of_sale_data.xml
@@ -20,10 +20,10 @@
mail.groupnotification
+ Point of Sale application installed!
- Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface.
-
-If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals.
+ Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface.
+
If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals.
" % partner.signup_url), plaintext=False)
return body
diff --git a/addons/portal/portal_demo.xml b/addons/portal/portal_demo.xml
index e8d0fb4159b..fc20bbccae7 100644
--- a/addons/portal/portal_demo.xml
+++ b/addons/portal/portal_demo.xml
@@ -1,17 +1,22 @@
-
+
-
-
+
+ Demo Portal User
- portal
- portal
-
-
+ demo@portal.example.com
- demo@portal.wrong.address
+
+
+
+ portal
+ portal
+ --
+Mr Demo Portal
+
+
@@ -24,33 +29,41 @@
Our company's first blog-post !mail.group
- sit amet, consectetur adipiscing elit. Pellentesque et quam sapien, in sagittis tellus.
-Praesent vel massa sed massa consequat egestas in tristique orci. Praesent iaculis libero et neque vehicula iaculis. Vivamus placerat tincidunt orci ac ornare. Proin ut dolor fringilla velit ultricies consequat. Maecenas sit amet ipsum non leo interdum imperdiet. Donec sapien mi.
-
-Fusce tempus elit volutpat mi auctor adipiscing. Nam congue luctus suscipit. Sed tellus libero, venenatis ut mollis ut, luctus quis dui. Sed rhoncus pulvinar orci in consectetur.
-
-Nulla turpis leo, rhoncus ut egestas sit amet, consectetur vitae urna. Mauris in dolor in sapien tempus vehicula.]]>
+ Hello, and welcome to our company's portal !
+
It is a great pleasure to announce you the creation of our portal by writing this first news! As you may have seen, a new discussion group is now present under your 'My groups' menu: Company's News. We will post news about the company and its employees in this discussion group. Moreover, we will be able to communicate with our partners that are given the opportunity to join us in our portal.
+
A new era of communication has begun! Feel free to post your feelings about our portal by replying on this message!
]]>comment
+ mail.group
-
+ As your first portal member, I am very pleased to be able to be able to communicate directly with you. Be sure I'll read all news carefully!]]>comment
-
+
+ mail.group
-
+ That's good news! As said by Demo Portal User in the previous post, I'm looking forward to hearing from you!]]>comment
+
+
+
+
+
+ mail.group
+
+ This feature is realy great! We will be able to communicate directly to our partners!]]>
+
+ comment
+
diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py
index 83b10b39c28..be32b015743 100644
--- a/addons/portal/tests/test_portal.py
+++ b/addons/portal/tests/test_portal.py
@@ -19,12 +19,11 @@
#
##############################################################################
-from openerp.addons.mail.tests import test_mail
-from openerp.tools import append_content_to_html
+from openerp.addons.mail.tests import test_mail_mockup
from osv.orm import except_orm
-class test_portal(test_mail.TestMailMockups):
+class test_portal(test_mail_mockup.TestMailMockups):
def setUp(self):
super(test_portal, self).setUp()
diff --git a/addons/portal/wizard/portal_wizard.py b/addons/portal/wizard/portal_wizard.py
index c94d6509f63..bf8353c92c1 100644
--- a/addons/portal/wizard/portal_wizard.py
+++ b/addons/portal/wizard/portal_wizard.py
@@ -24,10 +24,9 @@ import random
from osv import osv, fields
from tools.translate import _
-from tools.misc import email_re
+from tools import email_re
from openerp import SUPERUSER_ID
-from base.res.res_partner import _lang_get
_logger = logging.getLogger(__name__)
# welcome email sent to portal users
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/security/portal_security.xml b/addons/portal_claim/security/portal_security.xml
index e177b07eab9..3742765f795 100644
--- a/addons/portal_claim/security/portal_security.xml
+++ b/addons/portal_claim/security/portal_security.xml
@@ -7,6 +7,10 @@
[('message_follower_ids','in', [user.partner_id.id])]
+
+
+
+
diff --git a/addons/portal_project/security/portal_security.xml b/addons/portal_project/security/portal_security.xml
index 1247d25365a..ba686f72db4 100644
--- a/addons/portal_project/security/portal_security.xml
+++ b/addons/portal_project/security/portal_security.xml
@@ -7,6 +7,10 @@
[('message_follower_ids','in', [user.partner_id.id])]
+
+
+
+
diff --git a/addons/portal_project_issue/security/portal_security.xml b/addons/portal_project_issue/security/portal_security.xml
index 9527f1f9628..a121eeb593e 100644
--- a/addons/portal_project_issue/security/portal_security.xml
+++ b/addons/portal_project_issue/security/portal_security.xml
@@ -7,6 +7,10 @@
[('message_follower_ids','in', [user.partner_id.id])]
+
+
+
+
diff --git a/addons/portal_sale/security/portal_security.xml b/addons/portal_sale/security/portal_security.xml
index 39dabf754fe..19d44947f03 100644
--- a/addons/portal_sale/security/portal_security.xml
+++ b/addons/portal_sale/security/portal_security.xml
@@ -8,6 +8,10 @@
[('message_follower_ids','in',[user.partner_id.id])]
+
+
+
+
diff --git a/addons/process/__openerp__.py b/addons/process/__openerp__.py
index fcae18c5490..c998288a614 100644
--- a/addons/process/__openerp__.py
+++ b/addons/process/__openerp__.py
@@ -35,7 +35,7 @@ This module shows the basic processes involved in the selected modules and in th
""",
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
- 'depends': ['base'],
+ 'depends': ['web'],
'data': [
'security/ir.model.access.csv',
'process_view.xml'
diff --git a/addons/product/product.py b/addons/product/product.py
index b6a58fcd1e8..27cd4249a60 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -657,9 +657,9 @@ class product_product(osv.osv):
# Performing a quick memory merge of ids in Python will give much better performance
ids = set()
ids.update(self.search(cr, user, args + [('default_code',operator,name)], limit=limit, context=context))
- if len(ids) < limit:
+ if not limit or len(ids) < limit:
# we may underrun the limit because of dupes in the results, that's fine
- ids.update(self.search(cr, user, args + [('name',operator,name)], limit=(limit-len(ids)), context=context))
+ ids.update(self.search(cr, user, args + [('name',operator,name)], limit=(limit and (limit-len(ids)) or False) , context=context))
ids = list(ids)
if not ids:
ptrn = re.compile('(\[(.*?)\])')
diff --git a/addons/product_expiry/product_expiry.py b/addons/product_expiry/product_expiry.py
index c16ccc2b1ee..e4ed28db4e6 100644
--- a/addons/product_expiry/product_expiry.py
+++ b/addons/product_expiry/product_expiry.py
@@ -45,12 +45,13 @@ class stock_production_lot(osv.osv):
_columns = {
'life_date': fields.datetime('End of Life Date',
- help='The date on which the lot may become dangerous and should not be consumed.'),
+ help='This is the date on which the goods with this Serial Number may become dangerous and must not be consumed.'),
'use_date': fields.datetime('Best before Date',
- help='The date on which the lot starts deteriorating without becoming dangerous.'),
+ help='This is the date on which the goods with this Serial Number start deteriorating, without being dangerous yet.'),
'removal_date': fields.datetime('Removal Date',
- help='The date on which the lot should be removed.'),
- 'alert_date': fields.datetime('Alert Date', help="The date on which an alert should be notified about the serial number."),
+ help='This is the date on which the goods with this Serial Number should be removed from the stock.'),
+ 'alert_date': fields.datetime('Alert Date',
+ help="This is the date on which an alert should be notified about the goods with this Serial Number."),
}
# Assign dates according to products data
def create(self, cr, uid, vals, context=None):
@@ -78,12 +79,13 @@ class product_product(osv.osv):
_inherit = 'product.product'
_columns = {
'life_time': fields.integer('Product Life Time',
- help='The number of days before a serial number may become dangerous and should not be consumed.'),
+ help='When a new a Serial Number is issued, this is the number of days before the goods may become dangerous and must not be consumed.'),
'use_time': fields.integer('Product Use Time',
- help='The number of days before a serial number starts deteriorating without becoming dangerous.'),
+ help='When a new a Serial Number is issued, this is the number of days before the goods starts deteriorating, without being dangerous yet.'),
'removal_time': fields.integer('Product Removal Time',
- help='The number of days before a serial number should be removed.'),
- 'alert_time': fields.integer('Product Alert Time', help="The number of days after which an alert should be notified about the serial number."),
+ help='When a new a Serial Number is issued, this is the number of days before the goods should be removed from the stock.'),
+ 'alert_time': fields.integer('Product Alert Time',
+ help='When a new a Serial Number is issued, this is the number of days before an alert should be notified.'),
}
product_product()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/product_margin/product_margin.py b/addons/product_margin/product_margin.py
index 4c033a4a6ca..c06c4971474 100644
--- a/addons/product_margin/product_margin.py
+++ b/addons/product_margin/product_margin.py
@@ -56,11 +56,12 @@ class product_product(osv.osv):
sum(l.price_unit * l.quantity)/sum(l.quantity) as avg_unit_price,
sum(l.quantity) as num_qty,
sum(l.quantity * (l.price_subtotal/l.quantity)) as total,
- sum(l.quantity * product.list_price) as sale_expected,
- sum(l.quantity * product.standard_price) as normal_cost
+ sum(l.quantity * pt.list_price) as sale_expected,
+ sum(l.quantity * pt.standard_price) as normal_cost
from account_invoice_line l
left join account_invoice i on (l.invoice_id = i.id)
- left join product_template product on (product.id=l.product_id)
+ left join product_product product on (product.id=l.product_id)
+ left join product_template pt on (pt.id=product.product_tmpl_id)
where l.product_id = %s and i.state in %s and i.type IN %s and (i.date_invoice IS NULL or (i.date_invoice>=%s and i.date_invoice<=%s))
"""
invoice_types = ('out_invoice', 'in_refund')
diff --git a/addons/product_visible_discount/i18n/lt.po b/addons/product_visible_discount/i18n/lt.po
new file mode 100644
index 00000000000..da70b62c1dd
--- /dev/null
+++ b/addons/product_visible_discount/i18n/lt.po
@@ -0,0 +1,62 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-02-08 00:37+0000\n"
+"PO-Revision-Date: 2012-11-15 13:54+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Lithuanian \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-16 04:36+0000\n"
+"X-Generator: Launchpad (build 16272)\n"
+
+#. module: product_visible_discount
+#: code:addons/product_visible_discount/product_visible_discount.py:153
+#, python-format
+msgid "No Sale Pricelist Found!"
+msgstr ""
+
+#. module: product_visible_discount
+#: field:product.pricelist,visible_discount:0
+msgid "Visible Discount"
+msgstr "Matoma Nuolaida"
+
+#. module: product_visible_discount
+#: code:addons/product_visible_discount/product_visible_discount.py:145
+#, python-format
+msgid "No Purchase Pricelist Found!"
+msgstr "Nerastas pirkimo kainoraštis !"
+
+#. module: product_visible_discount
+#: model:ir.model,name:product_visible_discount.model_account_invoice_line
+msgid "Invoice Line"
+msgstr "Sąskaitos eilutė"
+
+#. module: product_visible_discount
+#: model:ir.model,name:product_visible_discount.model_product_pricelist
+msgid "Pricelist"
+msgstr "Kainoraštis"
+
+#. module: product_visible_discount
+#: code:addons/product_visible_discount/product_visible_discount.py:145
+#, python-format
+msgid "You must first define a pricelist on the supplier form!"
+msgstr "Pirma turite aprašyti kainoraštį tiekėjo formoje !"
+
+#. module: product_visible_discount
+#: model:ir.model,name:product_visible_discount.model_sale_order_line
+msgid "Sales Order Line"
+msgstr "Pardavimo užsakymo eilutė"
+
+#. module: product_visible_discount
+#: code:addons/product_visible_discount/product_visible_discount.py:153
+#, python-format
+msgid "You must first define a pricelist on the customer form!"
+msgstr "Pirma turite aprašyti kainoraštį pirkėjo formoje !"
diff --git a/addons/project/project.py b/addons/project/project.py
index df422f4cc8f..9c28fadeab9 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -166,17 +166,17 @@ class project(osv.osv):
res[id]['progress_rate'] = 0.0
return res
- def unlink(self, cr, uid, ids, *args, **kwargs):
+ def unlink(self, cr, uid, ids, context=None):
alias_ids = []
mail_alias = self.pool.get('mail.alias')
- for proj in self.browse(cr, uid, ids):
+ for proj in self.browse(cr, uid, ids, context=context):
if proj.tasks:
raise osv.except_osv(_('Invalid Action!'),
_('You cannot delete a project containing tasks. You can either delete all the project\'s tasks and then delete the project or simply deactivate the project.'))
elif proj.alias_id:
alias_ids.append(proj.alias_id.id)
- res = super(project, self).unlink(cr, uid, ids, *args, **kwargs)
- mail_alias.unlink(cr, uid, alias_ids, *args, **kwargs)
+ res = super(project, self).unlink(cr, uid, ids, context=context)
+ mail_alias.unlink(cr, uid, alias_ids, context=context)
return res
def _get_attached_docs(self, cr, uid, ids, field_name, arg, context):
@@ -474,7 +474,7 @@ def Project():
resource = %s
""" % (
project.id,
- project.date_start, working_days,
+ project.date_start or time.strftime('%Y-%m-%d'), working_days,
'|'.join(['User_'+str(x) for x in puids])
)
vacation = calendar_id and tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context)) or False
diff --git a/addons/project/project_data.xml b/addons/project/project_data.xml
index 4f467c89a29..08981bd126a 100644
--- a/addons/project/project_data.xml
+++ b/addons/project/project_data.xml
@@ -125,11 +125,11 @@
mail.groupnotification
+ Project Management application installed!
- Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning.
-
-You can manage todo lists on tasks by installing the "Todo Lists" application, supporting the Getting Things Done (GTD) methodology.
-You can also manage issues/bugs in projects by installing the "Issue Tracker" application.
+ Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning.
+
You can manage todo lists on tasks by installing the Todo Lists application, supporting the Getting Things Done (GTD) methodology.
+
You can also manage issues/bugs in projects by installing the "Issue Tracker" application.
]]>
diff --git a/addons/project/project_demo.xml b/addons/project/project_demo.xml
index cd22bad67d4..698a1a99627 100644
--- a/addons/project/project_demo.xml
+++ b/addons/project/project_demo.xml
@@ -21,31 +21,15 @@
Usability
-
-
- Internal Projects
-
-
- project.task
-
-
-
-
- Customer Projects
-
-
- project.task
-
-
-
opennormalThe Jackson Group's Project
+ 3
- followers
+ public
@@ -58,6 +42,7 @@
Research & Development
+ publicproject.task
@@ -69,6 +54,7 @@
E-Learning Integrationproject.task
+ public
diff --git a/addons/project_gtd/__openerp__.py b/addons/project_gtd/__openerp__.py
index 441f8859dc6..c99535f63fd 100644
--- a/addons/project_gtd/__openerp__.py
+++ b/addons/project_gtd/__openerp__.py
@@ -24,7 +24,7 @@
'name': 'Todo Lists',
'version': '1.0',
'category': 'Project Management',
- 'sequence': 9,
+ 'sequence': 100,
'summary': 'Personal Tasks, Contexts, Timeboxes',
'description': """
Implement concepts of the "Getting Things Done" methodology
diff --git a/addons/project_gtd/project_gtd_data.xml b/addons/project_gtd/project_gtd_data.xml
index 61b2468329c..9d8c99f23ff 100644
--- a/addons/project_gtd/project_gtd_data.xml
+++ b/addons/project_gtd/project_gtd_data.xml
@@ -30,9 +30,10 @@
mail.groupnotification
+ Todo Lists application installed!
- Add todo items on project tasks, to help you organize your work.
-This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.
+ Add todo items on project tasks, to help you organize your work.
+This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.
]]>
diff --git a/addons/project_issue/project_issue_data.xml b/addons/project_issue/project_issue_data.xml
index 72f824715a8..c1460167097 100644
--- a/addons/project_issue/project_issue_data.xml
+++ b/addons/project_issue/project_issue_data.xml
@@ -36,10 +36,11 @@
mail.groupnotification
+ Issue Tracker application installed!
- Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns.
-You can record issues, assign them to a responsible person, and keep track of their status as they evolve over time.
-Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.
+ Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns.
+You can record issues, assign them to a responsible person, and keep track of their status as they evolve over time.
+Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.
]]>
diff --git a/addons/project_issue/project_issue_demo.xml b/addons/project_issue/project_issue_demo.xml
index 9759d15dabb..63fa37c84c3 100644
--- a/addons/project_issue/project_issue_demo.xml
+++ b/addons/project_issue/project_issue_demo.xml
@@ -1,5 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/project_long_term/project_long_term_view.xml b/addons/project_long_term/project_long_term_view.xml
index 52eb5d80a3a..18e471ddd40 100644
--- a/addons/project_long_term/project_long_term_view.xml
+++ b/addons/project_long_term/project_long_term_view.xml
@@ -121,8 +121,8 @@
- Phases()
- Phase()
+ Phases
+ Phase
diff --git a/addons/purchase/edi/purchase_order_action_data.xml b/addons/purchase/edi/purchase_order_action_data.xml
index daad4467929..fab7eeacf6c 100644
--- a/addons/purchase/edi/purchase_order_action_data.xml
+++ b/addons/purchase/edi/purchase_order_action_data.xml
@@ -40,7 +40,7 @@
Automated Purchase Order Notification Mail${object.validator.email or ''}${object.company_id.name} Order (Ref ${object.name or 'n/a' })
- ${object.partner_id.email}
+ ${object.partner_id.id}mail.groupnotification
+ Purchase Management application installed!
- From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments.
-
-You can also manage purchase requisitions, see also the Purchase Settings.
+ From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments.
+
You can also manage purchase requisitions, see also the Purchase Settings.
]]>
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}mail.groupnotification
+ Sales Management application installed!
- This application lets you create and send quotations and process your sales orders; from delivery to invoicing.
-
-If you need to manage your sales pipeline (leads, opportunities, phonecalls), the <i>CRM</i> application may be useful. Use the Settings menu to install it.
+ This application lets you create and send quotations and process your sales orders; from delivery to invoicing.
+
If you need to manage your sales pipeline (leads, opportunities, phonecalls), the CRM application may be useful. Use the Settings menu to install it.