diff --git a/addons/account/account.py b/addons/account/account.py
index d262a5e273c..3959799f1bb 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -1001,8 +1001,7 @@ class account_period(osv.osv):
def find(self, cr, uid, dt=None, context=None):
if context is None: context = {}
if not dt:
- dt = fields.date.context_today(self,cr,uid,context=context)
-#CHECKME: shouldn't we check the state of the period?
+ dt = fields.date.context_today(self, cr, uid, context=context)
args = [('date_start', '<=' ,dt), ('date_stop', '>=', dt)]
if context.get('company_id', False):
args.append(('company_id', '=', context['company_id']))
@@ -1010,7 +1009,7 @@ class account_period(osv.osv):
company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
args.append(('company_id', '=', company_id))
result = []
- if context.get('account_period_prefer_normal'):
+ if context.get('account_period_prefer_normal', True):
# look for non-special periods first, and fallback to all if no result is found
result = self.search(cr, uid, args + [('special', '=', False)], context=context)
if not result:
@@ -1214,7 +1213,7 @@ class account_move(osv.osv):
return res
def _get_period(self, cr, uid, context=None):
- ctx = dict(context or {}, account_period_prefer_normal=True)
+ ctx = dict(context or {})
period_ids = self.pool.get('account.period').find(cr, uid, context=ctx)
return period_ids[0]
@@ -1786,7 +1785,7 @@ class account_tax_code(osv.osv):
if context.get('period_id', False):
period_id = context['period_id']
else:
- period_id = self.pool.get('account.period').find(cr, uid)
+ period_id = self.pool.get('account.period').find(cr, uid, context=context)
if not period_id:
return dict.fromkeys(ids, 0.0)
period_id = period_id[0]
diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py
index 56e061a707b..023765d73f0 100644
--- a/addons/account/account_bank_statement.py
+++ b/addons/account/account_bank_statement.py
@@ -61,7 +61,7 @@ class account_bank_statement(osv.osv):
return res
def _get_period(self, cr, uid, context=None):
- periods = self.pool.get('account.period').find(cr, uid,context=context)
+ periods = self.pool.get('account.period').find(cr, uid, context=context)
if periods:
return periods[0]
return False
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index e0a64a002a8..c47cf70b673 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -286,7 +286,10 @@ class account_invoice(osv.osv):
'payment_ids': fields.function(_compute_lines, relation='account.move.line', type="many2many", string='Payments'),
'move_name': fields.char('Journal Entry', size=64, readonly=True, states={'draft':[('readonly',False)]}),
'user_id': fields.many2one('res.users', 'Salesperson', readonly=True, track_visibility='onchange', states={'draft':[('readonly',False)]}),
- 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]})
+ 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]}),
+ 'commercial_partner_id': fields.related('partner_id', 'commercial_partner_id', string='Commercial Entity', type='many2one',
+ relation='res.partner', store=True, readonly=True,
+ help="The commercial entity that will be used on Journal Entries for this invoice")
}
_defaults = {
'type': _get_type,
@@ -985,8 +988,7 @@ class account_invoice(osv.osv):
'narration':inv.comment
}
period_id = inv.period_id and inv.period_id.id or False
- ctx.update(company_id=inv.company_id.id,
- account_period_prefer_normal=True)
+ ctx.update(company_id=inv.company_id.id)
if not period_id:
period_ids = period_obj.find(cr, uid, inv.date_invoice, context=ctx)
period_id = period_ids and period_ids[0] or False
@@ -1262,9 +1264,7 @@ class account_invoice(osv.osv):
ref = invoice.reference
else:
ref = self._convert_ref(cr, uid, invoice.number)
- partner = invoice.partner_id
- if partner.parent_id and not partner.is_company:
- partner = partner.parent_id
+ partner = self.pool['res.partner']._find_accounting_partner(invoice.partner_id)
# Pay attention to the sign for both debit/credit AND amount_currency
l1 = {
'debit': direction * pay_amount>0 and direction * pay_amount,
@@ -1734,15 +1734,11 @@ class res_partner(osv.osv):
'invoice_ids': fields.one2many('account.invoice.line', 'partner_id', 'Invoices', readonly=True),
}
- def _find_accounting_partner(self, part):
+ def _find_accounting_partner(self, partner):
'''
Find the partner for which the accounting entries will be created
'''
- #if the chosen partner is not a company and has a parent company, use the parent for the journal entries
- #because you want to invoice 'Agrolait, accounting department' but the journal items are for 'Agrolait'
- if part.parent_id and not part.is_company:
- part = part.parent_id
- return part
+ return partner.commercial_partner_id
def copy(self, cr, uid, id, default=None, context=None):
default = default or {}
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index c2f21c0d8bc..7469c38decb 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -117,6 +117,7 @@
+
@@ -320,7 +321,8 @@
+ options='{"always_reload": True}'
+ domain="[('customer', '=', True)]"/>
@@ -447,19 +449,20 @@
account.invoice
-
+
-
+
-
+
+
@@ -622,8 +625,6 @@
-
-
-
+
@@ -1194,7 +1194,12 @@
sequence="1"
groups="group_account_user"
/>
-
+
+ Journal Items
+ account.move.line
+ {'search_default_partner_id': [active_id], 'default_partner_id': active_id}
+
+ account.move.line
@@ -1288,7 +1293,7 @@
-
+
@@ -1352,7 +1357,7 @@
-
+
@@ -1771,23 +1776,6 @@
-
-
-
-
-
\n"
" "
msgstr ""
+"
\n"
+" Klik om een journaal toe te voegen.\n"
+"
\n"
+" Een journaal groepeert boekingen in functie\n"
+" van de dagelijkse bezigheden.\n"
+"
\n"
+" Een firma geruikt doorgaans een journaal per betaalmethode "
+"(kas,\n"
+" bankrekeningen, cheques), een aankoopdagboek, een "
+"verkoopdagboek\n"
+" en een diversendagboek.\n"
+"
\n"
+" "
#. module: account
#: model:ir.model,name:account.model_account_fiscalyear_close_state
@@ -9276,6 +9405,9 @@ msgid ""
"computed. Because it is space consuming, we do not allow to use it while "
"doing a comparison."
msgstr ""
+"Met deze optie krijgt u meer details over de manier waarop de saldi worden "
+"berekend. Omdat dit ruimte inneemt, is deze optie niet mogelijk bij "
+"vergelijkingen."
#. module: account
#: model:ir.model,name:account.model_account_fiscalyear_close
@@ -9292,6 +9424,8 @@ msgstr "De code van de rekening moet uniek zijn per firma."
#: help:product.template,property_account_expense:0
msgid "This account will be used to value outgoing stock using cost price."
msgstr ""
+"Deze rekening dient voor de voorraadwaardering van de uitgaande voorraad op "
+"basis van de kostprijs."
#. module: account
#: view:account.invoice:0
@@ -9354,6 +9488,17 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik als u een nieuwe recurrente boeking wilt maken.\n"
+"
\n"
+" Een terugkerende boeking wordt regelmatig op een bepaald "
+"tijdstip herhaald,\n"
+" vb. bij vervallen van een contract of overeenkomst met een\n"
+" klant of een leverancier. U kunt dergelijke boekingen "
+"voorbereiden\n"
+" zodat deze automatisch worden geboekt.\n"
+"
\n"
+" "
#. module: account
#: view:account.journal:0
@@ -9396,6 +9541,8 @@ msgid ""
"This allows you to check writing and printing.\n"
" This installs the module account_check_writing."
msgstr ""
+"Hiermee kunt u cheques schrijven en afdrukken.\n"
+" Hiermee wordt de module account_check_writing geïnstalleerd."
#. module: account
#: model:res.groups,name:account.group_account_invoice
@@ -9681,6 +9828,9 @@ msgid ""
"chart\n"
" of accounts."
msgstr ""
+"Bevestigde facturen kunnen niet meer\n"
+" worden gewijzigd. Facturen krijgen een uniek nummer\n"
+" en de boekingen worden gemaakt."
#. module: account
#: model:process.node,note:account.process_node_bankstatement0
@@ -9906,11 +10056,15 @@ msgid ""
"payments.\n"
" This installs the module account_payment."
msgstr ""
+"Hiermee kunt u betaalopdrachten maken\n"
+" * die als basis dienen voor verdere automatisering,\n"
+" * om efficiënter betalingen te kunnen uitvoeren.\n"
+" Hiermee wordt de module account_payment geïnstalleerd."
#. module: account
#: xsl:account.transfer:0
msgid "Document"
-msgstr ""
+msgstr "Document"
#. module: account
#: view:account.chart.template:0
@@ -10132,7 +10286,7 @@ msgstr "Kan geen boekingen maken tussen verschillende firma's."
#. module: account
#: model:ir.ui.menu,name:account.menu_finance_periodical_processing
msgid "Periodic Processing"
-msgstr ""
+msgstr "Periodieke verwerking"
#. module: account
#: view:account.invoice.report:0
@@ -10212,7 +10366,7 @@ msgstr "Vervaldatum"
#: model:account.payment.term,name:account.account_payment_term_immediate
#: model:account.payment.term,note:account.account_payment_term_immediate
msgid "Immediate Payment"
-msgstr ""
+msgstr "Contante betaling"
#. module: account
#: code:addons/account/account.py:1464
@@ -10424,11 +10578,16 @@ msgid ""
"analytic account.\n"
" This installs the module account_budget."
msgstr ""
+"Hiermee kunnen accountants budgetten beheren.\n"
+" Als de hoofdbudgetten zijn ingesteld, kunnen de "
+"projectleiders\n"
+" het geplande bedrag instellen per analytische rekening.\n"
+" Hiermee wordt de module account_budget geïnstalleerd."
#. module: account
#: field:account.bank.statement.line,name:0
msgid "OBI"
-msgstr ""
+msgstr "Omschrijving"
#. module: account
#: help:res.partner,property_account_payable:0
@@ -10915,6 +11074,8 @@ msgid ""
"If you unreconcile transactions, you must also verify all the actions that "
"are linked to those transactions because they will not be disable"
msgstr ""
+"Als u afgepunte transacties ongedaan maakt, moet u alle gekoppelde acties "
+"nakijken, want deze worden niet ongedaan gemaakt."
#. module: account
#: code:addons/account/account_move_line.py:1059
@@ -10949,6 +11110,9 @@ msgid ""
"customer. The tool search can also be used to personalise your Invoices "
"reports and so, match this analysis to your needs."
msgstr ""
+"Dit rapport biedt een overzicht van het bedrag gefactureerd aan uw klant. De "
+"zoekfunctie kan worden aangepast om het overzicht van uw facturen te "
+"personaliseren, zodat u de gewenste analyse krijgt."
#. module: account
#: view:account.partner.reconcile.process:0
@@ -11207,6 +11371,16 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik als u een nieuw btw-vak wilt toevoegen.\n"
+"
\n"
+" Afhankelijk van uw land, dient een btw-vak om uw btw-"
+"aangifte in te vullen.\n"
+" In OpenERP kunt u een btw-structuur instellen en elke btw-"
+"berekening\n"
+" kan in een of meer btw-vakken worden opgenomen.\n"
+"
\n"
+" Selecteer de periode en het journaal.\n"
+"
\n"
+" Hiermee kan de boekhouder in een sneltempo boekingen "
+"invoeren in\n"
+" OpenERP. Als u een aankoopfactuur wilt inboeken,\n"
+" begint u met de kostenrekening. OpenERP stelt automatisch\n"
+" de betrokken btw voor die is gekoppeld aan deze rekening, "
+"net\n"
+" als de centralisatierekening.\n"
+"
\n"
+" "
#. module: account
#: help:account.invoice.line,account_id:0
@@ -11403,7 +11589,7 @@ msgstr "Rekeningmodel"
#: code:addons/account/account_cash_statement.py:292
#, python-format
msgid "Loss"
-msgstr ""
+msgstr "Verlies"
#. module: account
#: selection:account.entries.report,month:0
@@ -11475,7 +11661,7 @@ msgstr "Kostenrekening van productsjabloon"
#. module: account
#: field:res.partner,property_payment_term:0
msgid "Customer Payment Term"
-msgstr ""
+msgstr "Betaaltermijn klant"
#. module: account
#: help:accounting.report,label_filter:0
diff --git a/addons/account/i18n/pt_BR.po b/addons/account/i18n/pt_BR.po
index ba985c5e0a8..d1816589139 100644
--- a/addons/account/i18n/pt_BR.po
+++ b/addons/account/i18n/pt_BR.po
@@ -7,15 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
-"PO-Revision-Date: 2012-12-22 23:17+0000\n"
-"Last-Translator: Fábio Martinelli - http://zupy.com.br "
-"\n"
+"PO-Revision-Date: 2013-04-18 17:44+0000\n"
+"Last-Translator: Thiago Tognoli \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:19+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-19 05:24+0000\n"
+"X-Generator: Launchpad (build 16567)\n"
#. module: account
#: model:process.transition,name:account.process_transition_supplierreconcilepaid0
@@ -431,7 +430,7 @@ msgstr "Data de criação"
#. module: account
#: selection:account.journal,type:0
msgid "Purchase Refund"
-msgstr "Devolução da Venda"
+msgstr "Devolução de Compra"
#. module: account
#: selection:account.journal,type:0
@@ -12678,13 +12677,6 @@ msgstr ""
#~ msgid "This period is already closed !"
#~ msgstr "Este período já está fechado"
-#, python-format
-#~ msgid ""
-#~ "Selected Move lines does not have any account move enties in draft state"
-#~ msgstr ""
-#~ "As linhas do movimento selecionado nao tem nenhuma conta a ser movida para o "
-#~ "estado de esboço"
-
#~ msgid "Unpaid Customer Refunds"
#~ msgstr "Reembolsos a clientes não pagos"
@@ -13232,6 +13224,13 @@ msgstr ""
#~ msgid "Can not %s draft/proforma/cancel invoice."
#~ msgstr "Não pode %s provisório/proforma/cancelar fatura."
+#, python-format
+#~ msgid ""
+#~ "Selected Move lines does not have any account move enties in draft state"
+#~ msgstr ""
+#~ "As linhas de movimento selecionadas não tem nenhum movimento nesta conta no "
+#~ "modo provisório"
+
#, python-format
#~ msgid "Can not pay draft/proforma/cancel invoice."
#~ msgstr "Não se pode pagar uma fatura provisória/proforma/cancelada"
diff --git a/addons/account/i18n/zh_CN.po b/addons/account/i18n/zh_CN.po
index ff84dd866e8..0e216ddb68f 100644
--- a/addons/account/i18n/zh_CN.po
+++ b/addons/account/i18n/zh_CN.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
-"PO-Revision-Date: 2013-01-30 03:58+0000\n"
-"Last-Translator: Wei \"oldrev\" Li \n"
+"PO-Revision-Date: 2013-04-25 09:04+0000\n"
+"Last-Translator: Oliver Yuan \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:20+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-26 05:34+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
#. module: account
#: model:process.transition,name:account.process_transition_supplierreconcilepaid0
@@ -10748,7 +10748,7 @@ msgstr "手动的发票税(非主营业务纳税)"
#: code:addons/account/account_invoice.py:550
#, python-format
msgid "The payment term of supplier does not have a payment term line."
-msgstr ""
+msgstr "供应商付款条件没有包含付款条件行"
#. module: account
#: field:account.account,parent_right:0
diff --git a/addons/account/installer.py b/addons/account/installer.py
index 4e2c2b2e024..537371d0f64 100644
--- a/addons/account/installer.py
+++ b/addons/account/installer.py
@@ -23,10 +23,16 @@ import datetime
from dateutil.relativedelta import relativedelta
import logging
from operator import itemgetter
-from os.path import join as opj
import time
+import urllib2
+import urlparse
-from openerp import tools
+try:
+ import simplejson as json
+except ImportError:
+ import json # noqa
+
+from openerp.release import serie
from openerp.tools.translate import _
from openerp.osv import fields, osv
@@ -38,13 +44,28 @@ class account_installer(osv.osv_memory):
def _get_charts(self, cr, uid, context=None):
modules = self.pool.get('ir.module.module')
+
+ # try get the list on apps server
+ try:
+ apps_server = self.pool.get('ir.config_parameter').get_param(cr, uid, 'apps.server', 'https://apps.openerp.com')
+
+ up = urlparse.urlparse(apps_server)
+ url = '{0.scheme}://{0.netloc}/apps/charts?serie={1}'.format(up, serie)
+
+ j = urllib2.urlopen(url, timeout=3).read()
+ apps_charts = json.loads(j)
+
+ charts = dict(apps_charts)
+ except Exception:
+ charts = dict()
+
# Looking for the module with the 'Account Charts' category
category_name, category_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'module_category_localization_account_charts')
ids = modules.search(cr, uid, [('category_id', '=', category_id)], context=context)
- charts = list(
- sorted(((m.name, m.shortdesc)
- for m in modules.browse(cr, uid, ids, context=context)),
- key=itemgetter(1)))
+ if ids:
+ charts.update((m.name, m.shortdesc) for m in modules.browse(cr, uid, ids, context=context))
+
+ charts = sorted(charts.items(), key=itemgetter(1))
charts.insert(0, ('configurable', _('Custom')))
return charts
@@ -57,9 +78,9 @@ class account_installer(osv.osv_memory):
"country."),
'date_start': fields.date('Start Date', required=True),
'date_stop': fields.date('End Date', required=True),
- 'period': fields.selection([('month', 'Monthly'), ('3months','3 Monthly')], 'Periods', required=True),
+ 'period': fields.selection([('month', 'Monthly'), ('3months', '3 Monthly')], 'Periods', required=True),
'company_id': fields.many2one('res.company', 'Company', required=True),
- 'has_default_company' : fields.boolean('Has Default Company', readonly=True),
+ 'has_default_company': fields.boolean('Has Default Company', readonly=True),
}
def _default_company(self, cr, uid, context=None):
@@ -78,30 +99,29 @@ class account_installer(osv.osv_memory):
'has_default_company': _default_has_default_company,
'charts': 'configurable'
}
-
+
def get_unconfigured_cmp(self, cr, uid, context=None):
""" get the list of companies that have not been configured yet
but don't care about the demo chart of accounts """
- cmp_select = []
company_ids = self.pool.get('res.company').search(cr, uid, [], context=context)
cr.execute("SELECT company_id FROM account_account WHERE active = 't' AND account_account.parent_id IS NULL AND name != %s", ("Chart For Automated Tests",))
configured_cmp = [r[0] for r in cr.fetchall()]
return list(set(company_ids)-set(configured_cmp))
-
+
def check_unconfigured_cmp(self, cr, uid, context=None):
""" check if there are still unconfigured companies """
if not self.get_unconfigured_cmp(cr, uid, context=context):
raise osv.except_osv(_('No unconfigured company !'), _("There is currently no company without chart of account. The wizard will therefore not be executed."))
-
+
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
- if context is None:context = {}
- res = super(account_installer, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar,submenu=False)
+ if context is None: context = {}
+ res = super(account_installer, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=False)
cmp_select = []
# display in the widget selection only the companies that haven't been configured yet
unconfigured_cmp = self.get_unconfigured_cmp(cr, uid, context=context)
for field in res['fields']:
if field == 'company_id':
- res['fields'][field]['domain'] = [('id','in',unconfigured_cmp)]
+ res['fields'][field]['domain'] = [('id', 'in', unconfigured_cmp)]
res['fields'][field]['selection'] = [('', '')]
if unconfigured_cmp:
cmp_select = [(line.id, line.name) for line in self.pool.get('res.company').browse(cr, uid, unconfigured_cmp)]
@@ -117,7 +137,7 @@ class account_installer(osv.osv_memory):
def execute(self, cr, uid, ids, context=None):
self.execute_simple(cr, uid, ids, context)
- super(account_installer, self).execute(cr, uid, ids, context=context)
+ return super(account_installer, self).execute(cr, uid, ids, context=context)
def execute_simple(self, cr, uid, ids, context=None):
if context is None:
@@ -129,8 +149,8 @@ class account_installer(osv.osv_memory):
if not f_ids:
name = code = res['date_start'][:4]
if int(name) != int(res['date_stop'][:4]):
- name = res['date_start'][:4] +'-'+ res['date_stop'][:4]
- code = res['date_start'][2:4] +'-'+ res['date_stop'][2:4]
+ name = res['date_start'][:4] + '-' + res['date_stop'][:4]
+ code = res['date_start'][2:4] + '-' + res['date_stop'][2:4]
vals = {
'name': name,
'code': code,
@@ -150,7 +170,7 @@ class account_installer(osv.osv_memory):
chart = self.read(cr, uid, ids, ['charts'],
context=context)[0]['charts']
_logger.debug('Installing chart of accounts %s', chart)
- return modules | set([chart])
+ return (modules | set([chart])) - set(['has_default_company', 'configurable'])
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account/partner.py b/addons/account/partner.py
index 50addd88942..f582da6b765 100644
--- a/addons/account/partner.py
+++ b/addons/account/partner.py
@@ -233,5 +233,10 @@ class res_partner(osv.osv):
'last_reconciliation_date': fields.datetime('Latest Full Reconciliation Date', help='Date on which the partner accounting entries were fully reconciled last time. It differs from the last date where a reconciliation has been made for this partner, as here we depict the fact that nothing more was to be reconciled at this date. This can be achieved in 2 different ways: either the last unreconciled debit/credit entry of this partner was reconciled, either the user pressed the button "Nothing more to reconcile" during the manual reconciliation process.')
}
+ def _commercial_fields(self, cr, uid, context=None):
+ return super(res_partner, self)._commercial_fields(cr, uid, context=context) + \
+ ['debit_limit', 'property_account_payable', 'property_account_receivable', 'property_account_position',
+ 'property_payment_term', 'property_supplier_payment_term', 'last_reconciliation_date']
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml
index 1267e20165b..b6fae3140b5 100644
--- a/addons/account/partner_view.xml
+++ b/addons/account/partner_view.xml
@@ -50,6 +50,29 @@
+
+ {'search_default_partner_id': [active_id], 'default_partner_id': active_id}
+ Contracts/Analytic Accounts
+ account.analytic.account
+ tree,form
+
+
+ partner.view.buttons
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
Fiscal Positionsaccount.fiscal.position
@@ -73,7 +96,7 @@
-
+
@@ -103,20 +126,13 @@
+
+
+
Accounting-related settings are managed on
+
+
-
-
-
-
-
diff --git a/addons/account/project/project_view.xml b/addons/account/project/project_view.xml
index aa567d2fc79..79a1e76c7e7 100644
--- a/addons/account/project/project_view.xml
+++ b/addons/account/project/project_view.xml
@@ -31,7 +31,7 @@
-
+
diff --git a/addons/account/report/account_entries_report.py b/addons/account/report/account_entries_report.py
index 907da56535a..6060d97c182 100644
--- a/addons/account/report/account_entries_report.py
+++ b/addons/account/report/account_entries_report.py
@@ -81,7 +81,7 @@ class account_entries_report(osv.osv):
period_obj = self.pool.get('account.period')
for arg in args:
if arg[0] == 'period_id' and arg[2] == 'current_period':
- current_period = period_obj.find(cr, uid)[0]
+ current_period = period_obj.find(cr, uid, context=context)[0]
args.append(['period_id','in',[current_period]])
break
elif arg[0] == 'period_id' and arg[2] == 'current_year':
@@ -100,7 +100,7 @@ class account_entries_report(osv.osv):
fiscalyear_obj = self.pool.get('account.fiscalyear')
period_obj = self.pool.get('account.period')
if context.get('period', False) == 'current_period':
- current_period = period_obj.find(cr, uid)[0]
+ current_period = period_obj.find(cr, uid, context=context)[0]
domain.append(['period_id','in',[current_period]])
elif context.get('year', False) == 'current_year':
current_year = fiscalyear_obj.find(cr, uid)
diff --git a/addons/account/report/account_invoice_report.py b/addons/account/report/account_invoice_report.py
index 5395d79af03..799b9b1c9fb 100644
--- a/addons/account/report/account_invoice_report.py
+++ b/addons/account/report/account_invoice_report.py
@@ -70,6 +70,7 @@ class account_invoice_report(osv.osv):
'categ_id': fields.many2one('product.category','Category of Product', readonly=True),
'journal_id': fields.many2one('account.journal', 'Journal', readonly=True),
'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
+ 'commercial_partner_id': fields.many2one('res.partner', 'Partner Company', help="Commercial Entity"),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'user_id': fields.many2one('res.users', 'Salesperson', readonly=True),
'price_total': fields.float('Total Without Tax', readonly=True),
@@ -108,7 +109,7 @@ class account_invoice_report(osv.osv):
sub.fiscal_position, sub.user_id, sub.company_id, sub.nbr, sub.type, sub.state,
sub.categ_id, sub.date_due, sub.account_id, sub.account_line_id, sub.partner_bank_id,
sub.product_qty, sub.price_total / cr.rate as price_total, sub.price_average /cr.rate as price_average,
- cr.rate as currency_rate, sub.residual / cr.rate as residual
+ cr.rate as currency_rate, sub.residual / cr.rate as residual, sub.commercial_partner_id as commercial_partner_id
"""
return select_str
@@ -170,7 +171,8 @@ class account_invoice_report(osv.osv):
LEFT JOIN account_invoice a ON a.id = l.invoice_id
WHERE a.id = ai.id)
ELSE 1::bigint
- END::numeric AS residual
+ END::numeric AS residual,
+ ai.commercial_partner_id as commercial_partner_id
"""
return select_str
@@ -193,7 +195,7 @@ class account_invoice_report(osv.osv):
ai.partner_id, ai.payment_term, ai.period_id, u.name, ai.currency_id, ai.journal_id,
ai.fiscal_position, ai.user_id, ai.company_id, ai.type, ai.state, pt.categ_id,
ai.date_due, ai.account_id, ail.account_id, ai.partner_bank_id, ai.residual,
- ai.amount_total, u.uom_type, u.category_id
+ ai.amount_total, u.uom_type, u.category_id, ai.commercial_partner_id
"""
return group_by_str
diff --git a/addons/account/report/account_invoice_report_view.xml b/addons/account/report/account_invoice_report_view.xml
index dad70f695dc..96dc948b09a 100644
--- a/addons/account/report/account_invoice_report_view.xml
+++ b/addons/account/report/account_invoice_report_view.xml
@@ -14,6 +14,7 @@
+
@@ -65,7 +66,8 @@
-
+
+
diff --git a/addons/account/static/src/js/account_move_reconciliation.js b/addons/account/static/src/js/account_move_reconciliation.js
index dbbfe3cc069..cbc0abc4f4d 100644
--- a/addons/account/static/src/js/account_move_reconciliation.js
+++ b/addons/account/static/src/js/account_move_reconciliation.js
@@ -26,7 +26,7 @@ openerp.account = function (instance) {
if (this.partners) {
this.$el.prepend(QWeb.render("AccountReconciliation", {widget: this}));
this.$(".oe_account_recon_previous").click(function() {
- self.current_partner = (self.current_partner - 1) % self.partners.length;
+ self.current_partner = (((self.current_partner - 1) % self.partners.length) + self.partners.length) % self.partners.length;
self.search_by_partner();
});
this.$(".oe_account_recon_next").click(function() {
diff --git a/addons/account/wizard/account_reconcile.py b/addons/account/wizard/account_reconcile.py
index aaf0ae4acf7..0d5a3525af4 100644
--- a/addons/account/wizard/account_reconcile.py
+++ b/addons/account/wizard/account_reconcile.py
@@ -148,7 +148,6 @@ class account_move_line_reconcile_writeoff(osv.osv_memory):
context['analytic_id'] = data['analytic_id'][0]
if context['date_p']:
date = context['date_p']
-
ids = period_obj.find(cr, uid, dt=date, context=context)
if ids:
period_id = ids[0]
diff --git a/addons/account/wizard/account_tax_chart.py b/addons/account/wizard/account_tax_chart.py
index 49492a04604..3283d2ba6d1 100644
--- a/addons/account/wizard/account_tax_chart.py
+++ b/addons/account/wizard/account_tax_chart.py
@@ -38,7 +38,7 @@ class account_tax_chart(osv.osv_memory):
def _get_period(self, cr, uid, context=None):
"""Return default period value"""
- period_ids = self.pool.get('account.period').find(cr, uid)
+ period_ids = self.pool.get('account.period').find(cr, uid, context=context)
return period_ids and period_ids[0] or False
def account_tax_chart_open_window(self, cr, uid, ids, context=None):
diff --git a/addons/account/wizard/pos_box.py b/addons/account/wizard/pos_box.py
index 1d6d13e140b..874a8e3b7c9 100644
--- a/addons/account/wizard/pos_box.py
+++ b/addons/account/wizard/pos_box.py
@@ -67,6 +67,8 @@ class CashBoxIn(CashBox):
class CashBoxOut(CashBox):
_name = 'cash.box.out'
+ _columns = CashBox._columns.copy()
+
def _compute_values_for_statement_line(self, cr, uid, box, record, context=None):
amount = box.amount or 0.0
return {
diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
index 97a4bb8fac2..d31746e7e70 100644
--- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml
+++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml
@@ -213,7 +213,7 @@
-
+
diff --git a/addons/account_analytic_default/i18n/nl_BE.po b/addons/account_analytic_default/i18n/nl_BE.po
index 4d7b5295f16..86fed1b535a 100644
--- a/addons/account_analytic_default/i18n/nl_BE.po
+++ b/addons/account_analytic_default/i18n/nl_BE.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
-"PO-Revision-Date: 2012-11-27 13:19+0000\n"
+"PO-Revision-Date: 2013-04-15 15:56+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:28+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_partner
@@ -40,6 +40,9 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"product, it will automatically take this as an analytic account)"
msgstr ""
+"Kies een product voor de analytische rekening in analytische "
+"standaardrekening (vb. maak een nieuwe verkoopfactuur of verkooporder: als "
+"we dit product kiezen, wordt de analytische rekening voorgesteld)."
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_stock_picking
@@ -64,6 +67,9 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"partner, it will automatically take this as an analytic account)"
msgstr ""
+"Kies een relatie voor de analytische rekening in analytische "
+"standaardrekening (vb. maak een nieuwe verkoopfactuur of verkooporder: als "
+"we deze relatie kiezen, wordt de analytische rekening voorgesteld)."
#. module: account_analytic_default
#: view:account.analytic.default:0
@@ -118,6 +124,9 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"company, it will automatically take this as an analytic account)"
msgstr ""
+"Kies een firma voor de analytische rekening in analytische standaardrekening "
+"(vb. maak een nieuwe verkoopfactuur of verkooporder: als we deze firma "
+"kiezen, wordt de analytische rekening voorgesteld)."
#. module: account_analytic_default
#: view:account.analytic.default:0
diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py
index 3a1bb083762..5c019155fdc 100644
--- a/addons/account_asset/account_asset.py
+++ b/addons/account_asset/account_asset.py
@@ -82,7 +82,7 @@ class account_asset_asset(osv.osv):
return super(account_asset_asset, self).unlink(cr, uid, ids, context=context)
def _get_period(self, cr, uid, context=None):
- periods = self.pool.get('account.period').find(cr, uid)
+ periods = self.pool.get('account.period').find(cr, uid, context=context)
if periods:
return periods[0]
else:
diff --git a/addons/account_asset/account_asset_view.xml b/addons/account_asset/account_asset_view.xml
index c4cb17bded3..fe1fcf473ba 100644
--- a/addons/account_asset/account_asset_view.xml
+++ b/addons/account_asset/account_asset_view.xml
@@ -223,7 +223,7 @@
-
+
diff --git a/addons/account_asset/i18n/nl_BE.po b/addons/account_asset/i18n/nl_BE.po
index 5bee5f9bfd9..3413cf38ac8 100644
--- a/addons/account_asset/i18n/nl_BE.po
+++ b/addons/account_asset/i18n/nl_BE.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
-"PO-Revision-Date: 2012-11-27 13:35+0000\n"
+"PO-Revision-Date: 2013-04-15 15:59+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: Dutch (Belgium) \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:50+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
#. module: account_asset
#: view:account.asset.asset:0
@@ -148,7 +148,7 @@ msgstr "Dit is het bedrag dat u niet kunt afschrijven."
#. module: account_asset
#: help:account.asset.asset,method_period:0
msgid "The amount of time between two depreciations, in months"
-msgstr ""
+msgstr "De tijd tussen twee afschrijvingen, in maanden"
#. module: account_asset
#: field:account.asset.depreciation.line,depreciation_date:0
@@ -265,7 +265,7 @@ msgstr "Duur wijzigen"
#: help:account.asset.category,method_number:0
#: help:account.asset.history,method_number:0
msgid "The number of depreciations needed to depreciate your asset"
-msgstr ""
+msgstr "Het aantal keer dat er moet worden afgeschreven."
#. module: account_asset
#: view:account.asset.category:0
@@ -295,7 +295,7 @@ msgstr ""
#. module: account_asset
#: field:account.asset.depreciation.line,remaining_value:0
msgid "Next Period Depreciation"
-msgstr ""
+msgstr "Volgende afschrijvingsperiode"
#. module: account_asset
#: help:account.asset.history,method_period:0
@@ -346,7 +346,7 @@ msgstr "Investeringscategorie zoeken"
#. module: account_asset
#: view:asset.modify:0
msgid "months"
-msgstr ""
+msgstr "maanden"
#. module: account_asset
#: model:ir.model,name:account_asset.model_account_invoice_line
@@ -608,7 +608,7 @@ msgstr "Afschrijvingsmethode"
#. module: account_asset
#: field:account.asset.depreciation.line,amount:0
msgid "Current Depreciation"
-msgstr ""
+msgstr "Huidige afschrijving"
#. module: account_asset
#: field:account.asset.asset,name:0
@@ -653,6 +653,9 @@ msgid ""
" * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
" * Degressive: Calculated on basis of: Residual Value * Degressive Factor"
msgstr ""
+"Kies de methode om het aantal afschrijvingsregels te berekenen.\n"
+" * Lineair: op basis van: brutowaarde / aantal afschrijvingen\n"
+" * Degressief: op basis van: restwaarde * degressieve factor"
#. module: account_asset
#: field:account.asset.depreciation.line,move_check:0
diff --git a/addons/account_asset/report/account_asset_report_view.xml b/addons/account_asset/report/account_asset_report_view.xml
index 4865196c4a8..c772c6e4103 100644
--- a/addons/account_asset/report/account_asset_report_view.xml
+++ b/addons/account_asset/report/account_asset_report_view.xml
@@ -49,7 +49,7 @@
-
+
diff --git a/addons/account_asset/wizard/wizard_asset_compute.py b/addons/account_asset/wizard/wizard_asset_compute.py
index ee18a832e7b..f7cc6cf89c0 100755
--- a/addons/account_asset/wizard/wizard_asset_compute.py
+++ b/addons/account_asset/wizard/wizard_asset_compute.py
@@ -30,7 +30,7 @@ class asset_depreciation_confirmation_wizard(osv.osv_memory):
}
def _get_period(self, cr, uid, context=None):
- periods = self.pool.get('account.period').find(cr, uid)
+ periods = self.pool.get('account.period').find(cr, uid, context=context)
if periods:
return periods[0]
return False
diff --git a/addons/account_bank_statement_extensions/i18n/hu.po b/addons/account_bank_statement_extensions/i18n/hu.po
new file mode 100644
index 00000000000..a631c43ade0
--- /dev/null
+++ b/addons/account_bank_statement_extensions/i18n/hu.po
@@ -0,0 +1,362 @@
+# Hungarian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-05-05 23:08+0000\n"
+"Last-Translator: krnkris \n"
+"Language-Team: Hungarian \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-05-06 05:40+0000\n"
+"X-Generator: Launchpad (build 16598)\n"
+
+#. module: account_bank_statement_extensions
+#: help:account.bank.statement.line.global,name:0
+msgid "Originator to Beneficiary Information"
+msgstr "Kezdeményezőtől a kedvezményezetthez intézett információ"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+#: selection:account.bank.statement.line,state:0
+msgid "Confirmed"
+msgstr "Jóváhagyott"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement:0
+#: view:account.bank.statement.line:0
+msgid "Glob. Id"
+msgstr "Globális ID azonosító"
+
+#. module: account_bank_statement_extensions
+#: selection:account.bank.statement.line.global,type:0
+msgid "CODA"
+msgstr "CODA"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line.global,parent_id:0
+msgid "Parent Code"
+msgstr "Szülő kód"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Debit"
+msgstr "Tartozik"
+
+#. module: account_bank_statement_extensions
+#: view:cancel.statement.line:0
+#: model:ir.actions.act_window,name:account_bank_statement_extensions.action_cancel_statement_line
+#: model:ir.model,name:account_bank_statement_extensions.model_cancel_statement_line
+msgid "Cancel selected statement lines"
+msgstr "Kiválasztott számlakivonat sorok visszavonása"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line,val_date:0
+msgid "Value Date"
+msgstr "Értéknap"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Group By..."
+msgstr "Csoportosítás ezzel..."
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+#: selection:account.bank.statement.line,state:0
+msgid "Draft"
+msgstr "Tervezet"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Statement"
+msgstr "Kivonat"
+
+#. module: account_bank_statement_extensions
+#: view:confirm.statement.line:0
+#: model:ir.actions.act_window,name:account_bank_statement_extensions.action_confirm_statement_line
+#: model:ir.model,name:account_bank_statement_extensions.model_confirm_statement_line
+msgid "Confirm selected statement lines"
+msgstr "Kiválasztott bankszámla kivonat sorok jóváhagyása"
+
+#. module: account_bank_statement_extensions
+#: report:bank.statement.balance.report:0
+#: model:ir.actions.report.xml,name:account_bank_statement_extensions.bank_statement_balance_report
+msgid "Bank Statement Balances Report"
+msgstr "Bank kivonat egyenleg kimutatás"
+
+#. module: account_bank_statement_extensions
+#: view:cancel.statement.line:0
+msgid "Cancel Lines"
+msgstr "Sorok elvetése"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line.global:0
+#: model:ir.model,name:account_bank_statement_extensions.model_account_bank_statement_line_global
+msgid "Batch Payment Info"
+msgstr "Köptegelt fizetés információ"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line,state:0
+msgid "Status"
+msgstr "Állapot"
+
+#. module: account_bank_statement_extensions
+#: code:addons/account_bank_statement_extensions/account_bank_statement.py:129
+#, python-format
+msgid ""
+"Delete operation not allowed. Please go to the associated bank "
+"statement in order to delete and/or modify bank statement line."
+msgstr ""
+"A törlés végrehajtás nem engedélyezett. Kérem menjen az ide vonatkozó banki "
+"kivonathoz, hogy azt törölhesse és/vagy módosíthassa."
+
+#. module: account_bank_statement_extensions
+#: view:confirm.statement.line:0
+msgid "or"
+msgstr "vagy"
+
+#. module: account_bank_statement_extensions
+#: view:confirm.statement.line:0
+msgid "Confirm Lines"
+msgstr "Jóváhagyott sorok5"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line.global:0
+msgid "Transactions"
+msgstr "Tranzakciók"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line.global,type:0
+msgid "Type"
+msgstr "Típus"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+#: report:bank.statement.balance.report:0
+msgid "Journal"
+msgstr "Napló"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Confirmed Statement Lines."
+msgstr "Jóváhagyott kivonat sorok"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Credit Transactions."
+msgstr "Jóváírási tranzakció"
+
+#. module: account_bank_statement_extensions
+#: model:ir.actions.act_window,help:account_bank_statement_extensions.action_cancel_statement_line
+msgid "cancel selected statement lines."
+msgstr "kiválasztott kivonat sorok visszavonása"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line,counterparty_number:0
+msgid "Counterparty Number"
+msgstr "Ellanoldali szám"
+
+#. module: account_bank_statement_extensions
+#: report:bank.statement.balance.report:0
+msgid "Closing Balance"
+msgstr "Záró egyenleg"
+
+#. module: account_bank_statement_extensions
+#: report:bank.statement.balance.report:0
+msgid "Date"
+msgstr "Dátum"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+#: field:account.bank.statement.line,globalisation_amount:0
+msgid "Glob. Amount"
+msgstr "Globális összeg"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Debit Transactions."
+msgstr "Terhelés tranzakciók"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Extended Filters..."
+msgstr "Kiterjesztett szűrők…"
+
+#. module: account_bank_statement_extensions
+#: view:confirm.statement.line:0
+msgid "Confirmed lines cannot be changed anymore."
+msgstr "Jóváhagyott sorokat enm lehet többé megváltoztatni."
+
+#. module: account_bank_statement_extensions
+#: view:cancel.statement.line:0
+msgid "Are you sure you want to cancel the selected Bank Statement lines ?"
+msgstr ""
+"Biztos benne, hogy vissza akarja vonni a kijelölt banki kivonat sorokat?"
+
+#. module: account_bank_statement_extensions
+#: report:bank.statement.balance.report:0
+msgid "Name"
+msgstr "Név"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line.global,name:0
+msgid "OBI"
+msgstr "OBI"
+
+#. module: account_bank_statement_extensions
+#: selection:account.bank.statement.line.global,type:0
+msgid "ISO 20022"
+msgstr "ISO 20022"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Notes"
+msgstr "Jegyzetek"
+
+#. module: account_bank_statement_extensions
+#: selection:account.bank.statement.line.global,type:0
+msgid "Manual"
+msgstr "Kézi"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Bank Transaction"
+msgstr "Banki tranzakciók"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Credit"
+msgstr "Jóváírás"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line.global,amount:0
+msgid "Amount"
+msgstr "Összeg"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Fin.Account"
+msgstr "Főkönyvi számla"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line,counterparty_currency:0
+msgid "Counterparty Currency"
+msgstr "Ellenoldal pénzneme"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line,counterparty_bic:0
+msgid "Counterparty BIC"
+msgstr "Ellenoldali BIC"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line.global,child_ids:0
+msgid "Child Codes"
+msgstr "Alárendelt kódok"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Search Bank Transactions"
+msgstr "Banki tranzakciók keresése"
+
+#. module: account_bank_statement_extensions
+#: view:confirm.statement.line:0
+msgid "Are you sure you want to confirm the selected Bank Statement lines ?"
+msgstr "Biztos, hogy jóvá akarja hagyni a kiválasztott banki kivonat sorait?"
+
+#. module: account_bank_statement_extensions
+#: help:account.bank.statement.line,globalisation_id:0
+msgid ""
+"Code to identify transactions belonging to the same globalisation level "
+"within a batch payment"
+msgstr ""
+"Ugynahhoz, a kötegelt utaláson belüli, globalizált szinthez tartozó "
+"tranzakció azonosító kód"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Draft Statement Lines."
+msgstr "Tervezet kivonat sorok."
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Glob. Am."
+msgstr ""
+
+#. module: account_bank_statement_extensions
+#: model:ir.model,name:account_bank_statement_extensions.model_account_bank_statement_line
+msgid "Bank Statement Line"
+msgstr "Bankkivonat sor"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line.global,code:0
+msgid "Code"
+msgstr "Kód"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line,counterparty_name:0
+msgid "Counterparty Name"
+msgstr "Ellenoldal megnevezése"
+
+#. module: account_bank_statement_extensions
+#: model:ir.model,name:account_bank_statement_extensions.model_res_partner_bank
+msgid "Bank Accounts"
+msgstr "Bankszámlák"
+
+#. module: account_bank_statement_extensions
+#: model:ir.model,name:account_bank_statement_extensions.model_account_bank_statement
+msgid "Bank Statement"
+msgstr "Bankszámlakivonat"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Statement Line"
+msgstr "Kivonat sor"
+
+#. module: account_bank_statement_extensions
+#: sql_constraint:account.bank.statement.line.global:0
+msgid "The code must be unique !"
+msgstr "A kódnak egyedinek kell lennie !"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line.global,bank_statement_line_ids:0
+#: model:ir.actions.act_window,name:account_bank_statement_extensions.action_bank_statement_line
+#: model:ir.ui.menu,name:account_bank_statement_extensions.bank_statement_line
+msgid "Bank Statement Lines"
+msgstr "Bankkivonat sorai"
+
+#. module: account_bank_statement_extensions
+#: code:addons/account_bank_statement_extensions/account_bank_statement.py:129
+#, python-format
+msgid "Warning!"
+msgstr "Figyelem!"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line.global:0
+msgid "Child Batch Payments"
+msgstr "Alárendelt kötegelt utalások"
+
+#. module: account_bank_statement_extensions
+#: view:confirm.statement.line:0
+msgid "Cancel"
+msgstr "Mégse"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Statement Lines"
+msgstr "Kivonat sorai"
+
+#. module: account_bank_statement_extensions
+#: view:account.bank.statement.line:0
+msgid "Total Amount"
+msgstr "Teljes érték"
+
+#. module: account_bank_statement_extensions
+#: field:account.bank.statement.line,globalisation_id:0
+msgid "Globalisation ID"
+msgstr "Globalizált ID azonosító"
diff --git a/addons/account_followup/account_followup_customers.xml b/addons/account_followup/account_followup_customers.xml
index 6be11399b68..6893abe012e 100644
--- a/addons/account_followup/account_followup_customers.xml
+++ b/addons/account_followup/account_followup_customers.xml
@@ -10,7 +10,7 @@
-
+
@@ -29,7 +29,7 @@
res.partner
-
+
diff --git a/addons/account_followup/i18n/nl_BE.po b/addons/account_followup/i18n/nl_BE.po
index 1a92e60dfc9..64a73d776ef 100644
--- a/addons/account_followup/i18n/nl_BE.po
+++ b/addons/account_followup/i18n/nl_BE.po
@@ -1,20 +1,21 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
-# * account_followup
-#
+# * account_followup
+# Els Van Vossel , 2013.
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
-"PO-Revision-Date: 2010-12-17 09:57+0000\n"
-"Last-Translator: Niels Huylebroeck \n"
-"Language-Team: \n"
+"PO-Revision-Date: 2013-04-15 23:02+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
+"Language-Team: Els Van Vossel\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:11+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-17 05:15+0000\n"
+"X-Generator: Launchpad (build 16567)\n"
+"Language: nl\n"
#. module: account_followup
#: model:email.template,subject:account_followup.email_template_account_followup_default
@@ -22,12 +23,12 @@ msgstr ""
#: model:email.template,subject:account_followup.email_template_account_followup_level1
#: model:email.template,subject:account_followup.email_template_account_followup_level2
msgid "${user.company_id.name} Payment Reminder"
-msgstr ""
+msgstr "${user.company_id.name} Aanmaning"
#. module: account_followup
#: help:res.partner,latest_followup_level_id:0
msgid "The maximum follow-up level"
-msgstr ""
+msgstr "Het maximale aanmaningsniveau"
#. module: account_followup
#: view:account_followup.stat:0
@@ -43,33 +44,33 @@ msgstr "Aanmanen"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "%(date)s"
-msgstr ""
+msgstr "%(date)s"
#. module: account_followup
#: field:res.partner,payment_next_action_date:0
msgid "Next Action Date"
-msgstr ""
+msgstr "Volgende actiedatum"
#. module: account_followup
#: view:account_followup.followup.line:0
#: field:account_followup.followup.line,manual_action:0
msgid "Manual Action"
-msgstr ""
+msgstr "Manuele actie"
#. module: account_followup
#: field:account_followup.sending.results,needprinting:0
msgid "Needs Printing"
-msgstr ""
+msgstr "Moet worden afgedrukt"
#. module: account_followup
#: view:res.partner:0
msgid "⇾ Mark as Done"
-msgstr ""
+msgstr "⇾ Als Gedaan markeren"
#. module: account_followup
#: field:account_followup.followup.line,manual_action_note:0
msgid "Action To Do"
-msgstr ""
+msgstr "Uit te voeren actie"
#. module: account_followup
#: field:account_followup.followup,company_id:0
@@ -89,39 +90,39 @@ msgstr "Factuurdatum"
#. module: account_followup
#: field:account_followup.print,email_subject:0
msgid "Email Subject"
-msgstr "E-mail onderwerp"
+msgstr "E-mailonderwerp"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "%(user_signature)s"
-msgstr ""
+msgstr "%(user_signature)s"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "days overdue, do the following actions:"
-msgstr ""
+msgstr "dagen vervallen, voer volgende acties uit:"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "Follow-up Steps"
-msgstr ""
+msgstr "Aanmaningsstappen"
#. module: account_followup
#: field:account_followup.print,email_body:0
msgid "Email Body"
-msgstr ""
+msgstr "E-mailbericht"
#. module: account_followup
#: model:ir.actions.act_window,name:account_followup.action_account_followup_print
msgid "Send Follow-Ups"
-msgstr ""
+msgstr "Aanmaningen versturen"
#. module: account_followup
#: report:account_followup.followup.print:0
#: code:addons/account_followup/account_followup.py:263
#, python-format
msgid "Amount"
-msgstr ""
+msgstr "Bedrag"
#. module: account_followup
#: help:res.partner,payment_next_action:0
@@ -129,11 +130,14 @@ msgid ""
"This is the next action to be taken. It will automatically be set when the "
"partner gets a follow-up level that requires a manual action. "
msgstr ""
+"Dit is de volgende actie die moet worden ondernomen. Deze wordt automatisch "
+"ingesteld als de relatie een aanmaningsniveau bereikt waarvoor een manuele "
+"actie is vereist. "
#. module: account_followup
#: view:res.partner:0
msgid "No Responsible"
-msgstr ""
+msgstr "Niemand verantwoordelijk"
#. module: account_followup
#: model:account_followup.followup.line,description:account_followup.demo_followup_line2
@@ -158,6 +162,24 @@ msgid ""
"\n"
"Best Regards,\n"
msgstr ""
+"\n"
+"Beste %(partner_name)s,\n"
+"\n"
+"Het spijt ons te moeten vaststellen dat, ondanks een eerdere aanmaning, u "
+"nog steeds een openstaand saldo hebt.\n"
+"\n"
+"Wij verzoeken u dringend het openstaande saldo te betalen. Bij gebrek aan "
+"betaling, zijn wij genoodzaakt de verdere levering van goederen en diensten "
+"stop te zetten.\n"
+"Gelieve de betalingen uit te voeren binnen de 8 dagen.\n"
+"\n"
+"Als er een probleem is rond de betaling waarvan wij niet op de hoogte zijn, "
+"kunt u steeds contact opnemen met onze boekhouding, zodat dit snel kan "
+"worden opgelost.\n"
+"\n"
+"Hierna vindt u een overzicht van de vervallen documenten.\n"
+"\n"
+"Hoogachtend,\n"
#. module: account_followup
#: model:email.template,body_html:account_followup.email_template_account_followup_level0
@@ -195,6 +217,38 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"
\n"
+"\n"
+"
Beste ${object.name},
\n"
+"
\n"
+" Volgens onze informatie, heeft u nog een openstaand saldo. Wij verzoeken "
+"u het nodige te doen om deze betaling binnen de 8 dagen over te schrijven op "
+"onze rekening.\n"
+"\n"
+"Indien uw betaling deze e-mail heeft gekruist, mag u dit bericht als "
+"onbestaand beschouwen. Neem gerust contact op met onze boekhouding mocht u "
+"nog vragen hebben.\n"
+"\n"
+"
\n"
+" "
#. module: account_followup
#: view:account_followup.stat.by.partner:0
@@ -209,17 +263,17 @@ msgstr "Totaal debet"
#. module: account_followup
#: field:res.partner,payment_next_action:0
msgid "Next Action"
-msgstr ""
+msgstr "Volgende actie"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid ": Partner Name"
-msgstr ""
+msgstr "Relatienaam"
#. module: account_followup
#: field:account_followup.followup.line,manual_action_responsible_id:0
msgid "Assign a Responsible"
-msgstr ""
+msgstr "Duid iemand aan die verantwoordelijk is"
#. module: account_followup
#: view:account_followup.followup:0
@@ -231,7 +285,7 @@ msgstr "Aanmaning"
#. module: account_followup
#: report:account_followup.followup.print:0
msgid "VAT:"
-msgstr "BTW:"
+msgstr "Btw:"
#. module: account_followup
#: view:account_followup.stat:0
@@ -255,11 +309,24 @@ msgid ""
" same customer, the actions of the most \n"
" overdue invoice will be executed."
msgstr ""
+"Om klanten aan te manen tot betaling, kunt u\n"
+" verschillende acties instellen in functie van de "
+"grootte\n"
+" van het openstaand bedrag. Deze acties worden "
+"samengevoegd\n"
+" in aanmaningsniveaus die worden aangesproken als de\n"
+" vervaldatum van een factuur een ingesteld aantal "
+"dagen\n"
+" overschrijdt. Als de klant ook andere openstaande "
+"facturen heeft,\n"
+" worden de acties uitgevoerd in functie van het "
+"langst \n"
+" openstaande document."
#. module: account_followup
#: report:account_followup.followup.print:0
msgid "Date :"
-msgstr "Datum :"
+msgstr "Datum:"
#. module: account_followup
#: field:account_followup.print,partner_ids:0
@@ -269,43 +336,43 @@ msgstr "Relaties"
#. module: account_followup
#: sql_constraint:account_followup.followup:0
msgid "Only one follow-up per company is allowed"
-msgstr ""
+msgstr "Per bedrijf is maar een aanmaningsniveau toegelaten."
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:254
#, python-format
msgid "Invoices Reminder"
-msgstr "Facturen aanmaning"
+msgstr "Aanmaning facturen"
#. module: account_followup
#: help:account_followup.followup.line,send_letter:0
msgid "When processing, it will print a letter"
-msgstr ""
+msgstr "Bij verwerking wordt een brief gemaakt"
#. module: account_followup
#: field:res.partner,payment_earliest_due_date:0
msgid "Worst Due Date"
-msgstr ""
+msgstr "Slechtste vervaldatum"
#. module: account_followup
#: view:account_followup.stat:0
msgid "Not Litigation"
-msgstr ""
+msgstr "Geen betwisting"
#. module: account_followup
#: view:account_followup.print:0
msgid "Send emails and generate letters"
-msgstr ""
+msgstr "Verstuur e-mails en maak brieven"
#. module: account_followup
#: model:ir.actions.act_window,name:account_followup.action_customer_followup
msgid "Manual Follow-Ups"
-msgstr ""
+msgstr "Manuele aanmaningen"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "%(partner_name)s"
-msgstr ""
+msgstr "%(partner_name)s"
#. module: account_followup
#: model:email.template,body_html:account_followup.email_template_account_followup_level1
@@ -347,6 +414,42 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"
\n"
+" \n"
+"
Beste ${object.name},
\n"
+"
\n"
+" Het spijt ons te moeten vaststellen dat, ondanks een eerdere aanmaning, "
+"u nog steeds een openstaand saldo hebt.\n"
+"Wij verzoeken u dringend het openstaande saldo te betalen. Bij gebrek aan "
+"betaling, zijn wij genoodzaakt de verdere levering van goederen en diensten "
+"stop te zetten.\n"
+"Gelieve de betalingen uit te voeren binnen de 8 dagen.\n"
+"\n"
+"Als er een probleem is rond de betaling waarvan wij niet op de hoogte zijn, "
+"kunt u steeds contact opnemen met onze boekhouding, zodat dit snel kan "
+"worden opgelost.\n"
+"\n"
+"Hierna vindt u een overzicht van de vervallen documenten.\n"
+"
\n"
+" "
#. module: account_followup
#: field:account_followup.stat,debit:0
@@ -356,49 +459,49 @@ msgstr "Debet"
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_stat
msgid "Follow-up Statistics"
-msgstr ""
+msgstr "Aanmaningsstatistieken"
#. module: account_followup
#: view:res.partner:0
msgid "Send Overdue Email"
-msgstr ""
+msgstr "Aanmaningsmail sturen"
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_followup_line
msgid "Follow-up Criteria"
-msgstr ""
+msgstr "Aanmaningscriteria"
#. module: account_followup
#: help:account_followup.followup.line,sequence:0
msgid "Gives the sequence order when displaying a list of follow-up lines."
-msgstr "Bepaalt de volgorde bij het afbeelden van de aanmaningregels"
+msgstr "Bepaalt de volgorde bij het weergeven van de aanmaningslijnen."
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:166
#, python-format
msgid " will be sent"
-msgstr ""
+msgstr " wordt verstuurd"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid ": User's Company Name"
-msgstr ""
+msgstr "Bedrijfsnaam van gebruiker"
#. module: account_followup
#: view:account_followup.followup.line:0
#: field:account_followup.followup.line,send_letter:0
msgid "Send a Letter"
-msgstr ""
+msgstr "Brief sturen"
#. module: account_followup
#: model:ir.actions.act_window,name:account_followup.action_account_followup_definition_form
msgid "Payment Follow-ups"
-msgstr ""
+msgstr "Aanmaningen"
#. module: account_followup
#: field:account_followup.followup.line,delay:0
msgid "Due Days"
-msgstr ""
+msgstr "Dagen vervallen"
#. module: account_followup
#: field:account.move.line,followup_line_id:0
@@ -414,48 +517,48 @@ msgstr "Laatste aanmaning"
#. module: account_followup
#: model:ir.ui.menu,name:account_followup.menu_manual_reconcile_followup
msgid "Reconcile Invoices & Payments"
-msgstr ""
+msgstr "Facturen en betalingen afpunten"
#. module: account_followup
#: model:ir.ui.menu,name:account_followup.account_followup_s
msgid "Do Manual Follow-Ups"
-msgstr ""
+msgstr "Manuele aanmaningen uitvoeren"
#. module: account_followup
#: report:account_followup.followup.print:0
msgid "Li."
-msgstr ""
+msgstr "Bt."
#. module: account_followup
#: field:account_followup.print,email_conf:0
msgid "Send Email Confirmation"
-msgstr ""
+msgstr "Bevestiging per e-mail sturen"
#. module: account_followup
#: view:account_followup.stat:0
msgid "Follow-up Entries with period in current year"
-msgstr ""
+msgstr "Aanmaningen met periode in huidig jaar"
#. module: account_followup
#: field:account_followup.stat.by.partner,date_followup:0
msgid "Latest follow-up"
-msgstr ""
+msgstr "Laatste aanmaning"
#. module: account_followup
#: field:account_followup.print,partner_lang:0
msgid "Send Email in Partner Language"
-msgstr "Stuur email-bericht in taal relatie"
+msgstr "Stuur e-mail in taal relatie"
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:169
#, python-format
msgid " email(s) sent"
-msgstr ""
+msgstr " e-mail(s) verstuurd"
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_print
msgid "Print Follow-up & Send Mail to Customers"
-msgstr ""
+msgstr "Aanmaningen afdrukken & mail sturen naar klanten"
#. module: account_followup
#: field:account_followup.followup.line,description:0
@@ -466,12 +569,12 @@ msgstr "Afgedrukt bericht"
#: code:addons/account_followup/wizard/account_followup_print.py:155
#, python-format
msgid "Anybody"
-msgstr ""
+msgstr "Iedereen"
#. module: account_followup
#: help:account_followup.followup.line,send_email:0
msgid "When processing, it will send an email"
-msgstr ""
+msgstr "Bij verwerking wordt een e-mail verstuurd"
#. module: account_followup
#: view:account_followup.stat.by.partner:0
@@ -481,7 +584,7 @@ msgstr "Relatie voor aanmaning"
#. module: account_followup
#: view:res.partner:0
msgid "Print Overdue Payments"
-msgstr ""
+msgstr "Vervallen documenten afdrukken"
#. module: account_followup
#: field:account_followup.followup.line,followup_id:0
@@ -494,11 +597,13 @@ msgstr "Aanmaningen"
#, python-format
msgid "Email not sent because of email address of partner not filled in"
msgstr ""
+"E-mail is niet verstuurd, omdat er voor de relatie geen e-mailadres is "
+"ingevuld."
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_followup
msgid "Account Follow-up"
-msgstr ""
+msgstr "Aanmaningen"
#. module: account_followup
#: help:res.partner,payment_responsible_id:0
@@ -506,11 +611,13 @@ msgid ""
"Optionally you can assign a user to this field, which will make him "
"responsible for the action."
msgstr ""
+"U kunt eventueel een gebruiker toewijzen aan dit veld. Dit betekent dat hij "
+"verantwoordelijk is voor deze actie."
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_sending_results
msgid "Results from the sending of the different letters and emails"
-msgstr ""
+msgstr "Resultaten van het versturen van brieven en e-mails"
#. module: account_followup
#: constraint:account_followup.followup.line:0
@@ -518,43 +625,45 @@ msgid ""
"Your description is invalid, use the right legend or %% if you want to use "
"the percent character."
msgstr ""
+"Uw beschrijving is niet geldig. Gebruik de juiste parameter of %% als u het "
+"percentageteken wilt gebruiken."
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:172
#, python-format
msgid " manual action(s) assigned:"
-msgstr ""
+msgstr " manuele actie(s) toegewezen"
#. module: account_followup
#: view:res.partner:0
msgid "Search Partner"
-msgstr ""
+msgstr "Relatie zoeken"
#. module: account_followup
#: model:ir.ui.menu,name:account_followup.account_followup_print_menu
msgid "Send Letters and Emails"
-msgstr ""
+msgstr "Brieven en e-mails sturen"
#. module: account_followup
#: view:account_followup.followup:0
msgid "Search Follow-up"
-msgstr ""
+msgstr "Aanmaningen zoeken"
#. module: account_followup
#: view:res.partner:0
msgid "Account Move line"
-msgstr ""
+msgstr "Boeking"
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:237
#, python-format
msgid "Send Letters and Emails: Actions Summary"
-msgstr ""
+msgstr "Brieven en e-mails sturen: overzicht acties"
#. module: account_followup
#: view:account_followup.print:0
msgid "or"
-msgstr ""
+msgstr "of"
#. module: account_followup
#: view:res.partner:0
@@ -562,21 +671,23 @@ msgid ""
"If not specified by the latest follow-up level, it will send from the "
"default email template"
msgstr ""
+"Indien dit niet is ingesteld via de laatste aanmaning, dan wordt de "
+"standaard e-mailsjabloon gebruikt."
#. module: account_followup
#: sql_constraint:account_followup.followup.line:0
msgid "Days of the follow-up levels must be different"
-msgstr ""
+msgstr "De dagen moeten verschillen per aanmaningsniveau."
#. module: account_followup
#: view:res.partner:0
msgid "Click to mark the action as done."
-msgstr ""
+msgstr "Klik om de actie als Gedaan te markeren."
#. module: account_followup
#: model:ir.ui.menu,name:account_followup.menu_action_followup_stat_follow
msgid "Follow-Ups Analysis"
-msgstr ""
+msgstr "Aanmaningsanalyse"
#. module: account_followup
#: help:res.partner,payment_next_action_date:0
@@ -586,11 +697,15 @@ msgid ""
"action. Can be practical to set manually e.g. to see if he keeps his "
"promises."
msgstr ""
+"Dit is als er manuele opvolging nodig is. De datum wordt ingesteld op de "
+"huidige datum als de relatie een aanmaningsniveau bereikt waarvoor een "
+"manuele handeling nodig is. Kan handig zijn om dit als manueel in te "
+"stellen, vb. om na te gaan of beloften worden nagekomen."
#. module: account_followup
#: view:res.partner:0
msgid "Print overdue payments report independent of follow-up line"
-msgstr ""
+msgstr "Aanmaningen afdrukken onafgezien van de aanmaningslijn."
#. module: account_followup
#: help:account_followup.print,date:0
@@ -609,7 +724,7 @@ msgstr "Verzenddatum aanmaning"
#: view:res.partner:0
#: field:res.partner,payment_responsible_id:0
msgid "Follow-up Responsible"
-msgstr ""
+msgstr "Verantwoordelijk voor aanmaning"
#. module: account_followup
#: model:email.template,body_html:account_followup.email_template_account_followup_level2
@@ -646,16 +761,48 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"
\n"
+" \n"
+"
Beste ${object.name},
\n"
+"
\n"
+" Ondanks het feit dat wij u meerdere aanmaningen hebben gestuurd, is uw "
+"openstaand saldo nog steeds niet betaald.\n"
+"Indien de betaling ervan niet binnen de 8 dagen op onze rekening staat, "
+"schakelen wij een advocaat in om het verschuldigde saldo bij u te innen. U "
+"ontvangt hierover geen verdere communicatie.\n"
+"Wij gaan ervan uit dat deze stap niet nodig zal zijn. De details van de "
+"openstaande betalingen vindt u hierna.\n"
+"Aarzel niet contact op te nemen met onze boekhouding als u nog vragen "
+"heeft.\n"
+"
\n"
+" "
#. module: account_followup
#: report:account_followup.followup.print:0
msgid "Document : Customer account statement"
-msgstr ""
+msgstr "Document: Rekeninguittreksel"
#. module: account_followup
#: model:ir.ui.menu,name:account_followup.account_followup_menu
msgid "Follow-up Levels"
-msgstr ""
+msgstr "Aanmaningsniveaus"
#. module: account_followup
#: model:account_followup.followup.line,description:account_followup.demo_followup_line4
@@ -678,11 +825,27 @@ msgid ""
"Best Regards,\n"
" "
msgstr ""
+"\n"
+"Beste %(partner_name)s,\n"
+"\n"
+"Ondanks meerdere aanmaningen, merken wij dat uw saldo nog steeds openstaat.\n"
+"\n"
+"Indien het openstaande saldo niet binnen 8 dagen op onze rekening is gestort "
+", zullen wij een advocaat inschakelen. Wij sturen in dat verband geen "
+"bericht meer.\n"
+"\n"
+"Wij gaan ervan uit dat deze actie niet nodig zal zijn. Details van de "
+"openstaande documenten vindt u hierbij.\n"
+"\n"
+"Aarzel niet contact op te nemen met de boekhouding als u nog vragen heeft.\n"
+"\n"
+"Hoogachtend,\n"
+" "
#. module: account_followup
#: field:res.partner,payment_amount_due:0
msgid "Amount Due"
-msgstr ""
+msgstr "Vervallen bedrag"
#. module: account_followup
#: field:account.move.line,followup_date:0
@@ -692,19 +855,19 @@ msgstr "Laatste aanmaning"
#. module: account_followup
#: view:account_followup.sending.results:0
msgid "Download Letters"
-msgstr ""
+msgstr "Brieven downloaden"
#. module: account_followup
#: field:account_followup.print,company_id:0
#: field:res.partner,unreconciled_aml_ids:0
msgid "unknown"
-msgstr ""
+msgstr "onbekend"
#. module: account_followup
#: code:addons/account_followup/account_followup.py:314
#, python-format
msgid "Printed overdue payments report"
-msgstr ""
+msgstr "Afgedrukt aanmaningsrapport"
#. module: account_followup
#: help:account_followup.followup.line,manual_action:0
@@ -712,6 +875,7 @@ msgid ""
"When processing, it will set the manual action to be taken for that "
"customer. "
msgstr ""
+"Bij verwerking zal de manuele actie voor die klant worden ingesteld. "
#. module: account_followup
#: view:res.partner:0
@@ -721,18 +885,25 @@ msgid ""
" order to exclude it from the next follow-up "
"actions."
msgstr ""
+"Hieronder vindt u een overzicht van de transacties voor deze\n"
+" klant. U kunt \"Stuur geen aanmaning\" kiezen "
+"om\n"
+" de factuur uit te sluiten van volgende "
+"aanmaningsacties."
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:171
#, python-format
msgid " email(s) should have been sent, but "
-msgstr ""
+msgstr " e-mail(s) zouden moeten zijn verstuurd, maar "
#. module: account_followup
#: help:account_followup.print,test_print:0
msgid ""
"Check if you want to print follow-ups without changing follow-ups level."
msgstr ""
+"Schakel dit veld in als u aanmaningen wilt afdrukken zonder het niveau te "
+"veranderen."
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_move_line
@@ -742,23 +913,23 @@ msgstr "Boekingen"
#. module: account_followup
#: report:account_followup.followup.print:0
msgid "Total:"
-msgstr ""
+msgstr "Totaal:"
#. module: account_followup
#: field:account_followup.followup.line,email_template_id:0
msgid "Email Template"
-msgstr ""
+msgstr "E-mailsjabloon"
#. module: account_followup
#: field:account_followup.print,summary:0
msgid "Summary"
-msgstr ""
+msgstr "Overzicht"
#. module: account_followup
#: view:account_followup.followup.line:0
#: field:account_followup.followup.line,send_email:0
msgid "Send an Email"
-msgstr ""
+msgstr "E-mail versturen"
#. module: account_followup
#: field:account_followup.stat,credit:0
@@ -768,7 +939,7 @@ msgstr "Krediet"
#. module: account_followup
#: field:res.partner,payment_amount_overdue:0
msgid "Amount Overdue"
-msgstr ""
+msgstr "Vervallen bedrag"
#. module: account_followup
#: help:res.partner,latest_followup_level_id_without_lit:0
@@ -776,12 +947,14 @@ msgid ""
"The maximum follow-up level without taking into account the account move "
"lines with litigation"
msgstr ""
+"Het maximale aanmaningsniveau, zonder rekening te houden met boekingen die "
+"worden betwist."
#. module: account_followup
#: view:account_followup.stat:0
#: field:res.partner,latest_followup_date:0
msgid "Latest Follow-up Date"
-msgstr ""
+msgstr "Datum laatste aanmaning"
#. module: account_followup
#: model:email.template,body_html:account_followup.email_template_account_followup_default
@@ -814,6 +987,33 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"
\n"
+" \n"
+"
Beste ${object.name},
\n"
+"
\n"
+" Volgens onze administratie hebben wij het onderstaande bedrag nog niet "
+"ontvangen. Wij verzoeken\n"
+"u het verschuldigde bedrag uiterlijk binnen 8 dagen over te maken.\n"
+"Indien dit schrijven uw betaling heeft gekruist, kunt u deze herinnering als "
+"niet verzonden beschouwen.\n"
+"Voor meer info kunt u steeds contact opnemen met onze boekhouding.\n"
+"
\n"
+" "
#. module: account_followup
#: field:account.move.line,result:0
@@ -826,17 +1026,17 @@ msgstr "Saldo"
#. module: account_followup
#: help:res.partner,payment_note:0
msgid "Payment Note"
-msgstr ""
+msgstr "Betalingsbewijs"
#. module: account_followup
#: view:res.partner:0
msgid "My Follow-ups"
-msgstr ""
+msgstr "Mijn aanmaningen"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "%(company_name)s"
-msgstr ""
+msgstr "%(company_name)s"
#. module: account_followup
#: model:account_followup.followup.line,description:account_followup.demo_followup_line1
@@ -854,28 +1054,40 @@ msgid ""
"\n"
"Best Regards,\n"
msgstr ""
+"\n"
+"Beste %(partner_name)s,\n"
+"\n"
+"Volgens onze administratie hebben wij het onderstaande bedrag nog niet "
+"ontvangen. Wij verzoeken u het verschuldigde bedrag binnen 8 dagen over te "
+"maken.\n"
+"\n"
+"Indien dit schrijven uw betaling heeft gekruist, kunt u deze herinnering als "
+"niet verzonden beschouwen.\n"
+"Voor meer info kunt u steeds contact opnemen met onze boekhouding.\n"
+"\n"
+"Hoogachtend,\n"
#. module: account_followup
#: field:account_followup.stat,date_move_last:0
#: field:account_followup.stat.by.partner,date_move_last:0
msgid "Last move"
-msgstr ""
+msgstr "Laatste boeking"
#. module: account_followup
#: field:account_followup.stat,period_id:0
msgid "Period"
-msgstr ""
+msgstr "Periode"
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:228
#, python-format
msgid "%s partners have no credits and as such the action is cleared"
-msgstr ""
+msgstr "%s relaties hebben geen schulden en de actie wordt gewist"
#. module: account_followup
#: model:ir.actions.report.xml,name:account_followup.account_followup_followup_report
msgid "Follow-up Report"
-msgstr ""
+msgstr "Aanmaningsrapport"
#. module: account_followup
#: view:res.partner:0
@@ -883,48 +1095,50 @@ msgid ""
", the latest payment follow-up\n"
" was:"
msgstr ""
+", het laatste aanmaningsniveau\n"
+" was:"
#. module: account_followup
#: view:account_followup.print:0
msgid "Cancel"
-msgstr ""
+msgstr "Annuleren"
#. module: account_followup
#: view:account_followup.sending.results:0
msgid "Close"
-msgstr ""
+msgstr "Afsluiten"
#. module: account_followup
#: view:account_followup.stat:0
msgid "Litigation"
-msgstr ""
+msgstr "Betwist"
#. module: account_followup
#: field:account_followup.stat.by.partner,max_followup_id:0
msgid "Max Follow Up Level"
-msgstr ""
+msgstr "Max. aanmaningsniveau"
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:171
#, python-format
msgid " had unknown email address(es)"
-msgstr ""
+msgstr " had een onbekend e-mailadres"
#. module: account_followup
#: view:res.partner:0
msgid "Responsible"
-msgstr ""
+msgstr "Verantwoordelijke"
#. module: account_followup
#: model:ir.ui.menu,name:account_followup.menu_finance_followup
#: view:res.partner:0
msgid "Payment Follow-up"
-msgstr ""
+msgstr "Aanmaningen"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid ": Current Date"
-msgstr ""
+msgstr ": Huidige datum"
#. module: account_followup
#: view:account_followup.print:0
@@ -933,16 +1147,19 @@ msgid ""
" set the manual actions per customer, according to "
"the follow-up levels defined."
msgstr ""
+"Met deze actie stuurt u aanmaningsmails, kunt u brieven afdrukken en\n"
+" manuele acties instellen per klant, in functie van "
+"de ingestelde aanmaningsniveaus."
#. module: account_followup
#: field:account_followup.followup.line,name:0
msgid "Follow-Up Action"
-msgstr ""
+msgstr "Aanmaningsactie"
#. module: account_followup
#: view:account_followup.stat:0
msgid "Including journal entries marked as a litigation"
-msgstr ""
+msgstr "Inclusief betwiste boekingen"
#. module: account_followup
#: report:account_followup.followup.print:0
@@ -955,7 +1172,7 @@ msgstr "Omschrijving"
#. module: account_followup
#: view:account_followup.sending.results:0
msgid "Summary of actions"
-msgstr ""
+msgstr "Overzicht van acties"
#. module: account_followup
#: report:account_followup.followup.print:0
@@ -965,17 +1182,17 @@ msgstr "Ref"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "After"
-msgstr ""
+msgstr "Na"
#. module: account_followup
#: view:account_followup.stat:0
msgid "This Fiscal year"
-msgstr ""
+msgstr "Dit boekjaar"
#. module: account_followup
#: field:res.partner,latest_followup_level_id_without_lit:0
msgid "Latest Follow-up Level without litigation"
-msgstr ""
+msgstr "Laatste aanmaningsniveau met betwisting"
#. module: account_followup
#: model:ir.actions.act_window,help:account_followup.action_account_manual_reconcile_receivable
@@ -985,16 +1202,20 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Geen boekingen gevonden.\n"
+"
\n"
+" "
#. module: account_followup
#: view:account.move.line:0
msgid "Partner entries"
-msgstr ""
+msgstr "Relatieboekingen"
#. module: account_followup
#: view:account_followup.stat:0
msgid "Follow-up lines"
-msgstr ""
+msgstr "Aanmaningsregels"
#. module: account_followup
#: model:account_followup.followup.line,description:account_followup.demo_followup_line3
@@ -1015,6 +1236,21 @@ msgid ""
"\n"
"Best Regards,\n"
msgstr ""
+"\n"
+"Beste %(partner_name)s,\n"
+"\n"
+"Ondanks eerdere aanmaningen, heeft u nog steeds een openstaand saldo.\n"
+"\n"
+"Als uw betaling binnen de 8 dagen opnieuw uitblijft, zijn wij genoodzaakt de "
+"vordering definitief uit handen te geven.\n"
+"\n"
+"Wij vertrouwen erop dat u het niet zover zult laten komen. Details van hety "
+"openstaande saldo vindt u hierna.\n"
+"\n"
+"Indien u nog vragen heeft, kunt u steeds contact opnemen met onze "
+"boekhouding.\n"
+"\n"
+"Hoogachtend,\n"
#. module: account_followup
#: help:account_followup.print,partner_lang:0
@@ -1022,6 +1258,8 @@ msgid ""
"Do not change message text, if you want to send email in partner language, "
"or configure from company"
msgstr ""
+"Wijzig de tekst niet als u de e-mail in de taal van de relatie wilt sturen, "
+"of stel de tekst in op firma."
#. module: account_followup
#: view:account_followup.followup.line:0
@@ -1034,12 +1272,18 @@ msgid ""
"installed\n"
" using to top right icon."
msgstr ""
+"Schrijf hier de inleiding van uw brief,\n"
+" in functie van het aanmaningsniveau. U kunt\n"
+" de volgende parameters in de tekst gebruiken. "
+"Vergeet\n"
+" niet all geïnstalleerde talen te vertalen via "
+"het pictogram in de rechterbovenhoek."
#. module: account_followup
#: view:account_followup.stat:0
#: model:ir.actions.act_window,name:account_followup.action_followup_stat
msgid "Follow-ups Sent"
-msgstr ""
+msgstr "Verstuurde aanmaningen"
#. module: account_followup
#: field:account_followup.followup,name:0
@@ -1049,34 +1293,34 @@ msgstr "Naam:"
#. module: account_followup
#: field:res.partner,latest_followup_level_id:0
msgid "Latest Follow-up Level"
-msgstr ""
+msgstr "Laatste aanmaningsniveau"
#. module: account_followup
#: field:account_followup.stat,date_move:0
#: field:account_followup.stat.by.partner,date_move:0
msgid "First move"
-msgstr ""
+msgstr "Eerste boeking"
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_stat_by_partner
msgid "Follow-up Statistics by Partner"
-msgstr ""
+msgstr "Aanmaningsstatistieken per relatie"
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:172
#, python-format
msgid " letter(s) in report"
-msgstr ""
+msgstr " brieven in rapport"
#. module: account_followup
#: view:res.partner:0
msgid "Partners with Overdue Credits"
-msgstr ""
+msgstr "Klanten met openstaande facturen"
#. module: account_followup
#: view:res.partner:0
msgid "Customer Followup"
-msgstr ""
+msgstr "Aanmaningen"
#. module: account_followup
#: model:ir.actions.act_window,help:account_followup.action_account_followup_definition_form
@@ -1092,42 +1336,52 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik als u de aanmaningsniveaus wilt instellen met de "
+"daaraan gekoppelde acties.\n"
+"
\n"
+" Per stap kunt u de acties opgeven en ook de dagen vervallen. "
+"U kunt\n"
+" brieven en e-mailsjablonen maken om specifieke berichten "
+"naar de klant te sturen.\n"
+"
\n"
+" "
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:166
#, python-format
msgid "Follow-up letter of "
-msgstr ""
+msgstr "Aanmaningsbrief van "
#. module: account_followup
#: view:res.partner:0
msgid "The"
-msgstr ""
+msgstr "De"
#. module: account_followup
#: view:account_followup.print:0
msgid "Send follow-ups"
-msgstr ""
+msgstr "Aanmaningen versturen"
#. module: account_followup
#: view:account.move.line:0
msgid "Total credit"
-msgstr ""
+msgstr "Totaal credit"
#. module: account_followup
#: field:account_followup.followup.line,sequence:0
msgid "Sequence"
-msgstr ""
+msgstr "Volgorde"
#. module: account_followup
#: view:res.partner:0
msgid "Follow-ups To Do"
-msgstr ""
+msgstr "Te versturen aanmaningen"
#. module: account_followup
#: report:account_followup.followup.print:0
msgid "Customer Ref :"
-msgstr ""
+msgstr "Klantenref.:"
#. module: account_followup
#: report:account_followup.followup.print:0
@@ -1141,26 +1395,30 @@ msgid ""
"the reminder. Could be negative if you want to send a polite alert "
"beforehand."
msgstr ""
+"Het aantal dagen dat de vervaldatum van de factuur moet zijn overschreden "
+"voordat een aanmaning wordt verstuurd. Kan negatief zijn als u vooraf een "
+"vriendelijk bericht wilt sturen."
#. module: account_followup
#: help:res.partner,latest_followup_date:0
msgid "Latest date that the follow-up level of the partner was changed"
msgstr ""
+"Laatste datum waarop het aanmaningsniveau van de relatie is gewijzigd."
#. module: account_followup
#: field:account_followup.print,test_print:0
msgid "Test Print"
-msgstr ""
+msgstr "Testafdruk"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid ": User Name"
-msgstr ""
+msgstr ": Gberuikersnaam"
#. module: account_followup
#: view:res.partner:0
msgid "Accounting"
-msgstr ""
+msgstr "Boekhouding"
#. module: account_followup
#: field:account_followup.stat,blocked:0
@@ -1170,7 +1428,7 @@ msgstr "Geblokkeerd"
#. module: account_followup
#: field:res.partner,payment_note:0
msgid "Customer Payment Promise"
-msgstr ""
+msgstr "Betalingsbelofte klant"
#~ msgid "All payable entries"
#~ msgstr "Alle crediteuren"
diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py
index 15664696bd5..b176c3b8fd9 100644
--- a/addons/account_voucher/account_voucher.py
+++ b/addons/account_voucher/account_voucher.py
@@ -84,7 +84,7 @@ class account_voucher(osv.osv):
if context is None: context = {}
if context.get('period_id', False):
return context.get('period_id')
- periods = self.pool.get('account.period').find(cr, uid)
+ periods = self.pool.get('account.period').find(cr, uid, context=context)
return periods and periods[0] or False
def _make_journal_search(self, cr, uid, ttype, context=None):
diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml
index f429480f656..4674d62b6a0 100644
--- a/addons/account_voucher/account_voucher_view.xml
+++ b/addons/account_voucher/account_voucher_view.xml
@@ -129,7 +129,7 @@
-
+
diff --git a/addons/account_voucher/i18n/nl_BE.po b/addons/account_voucher/i18n/nl_BE.po
index 0cdc8cd8399..a58e655aec6 100644
--- a/addons/account_voucher/i18n/nl_BE.po
+++ b/addons/account_voucher/i18n/nl_BE.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
-"PO-Revision-Date: 2012-12-19 18:04+0000\n"
+"PO-Revision-Date: 2013-04-26 16:01+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: Els Van Vossel\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:33+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-27 05:44+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
"Language: nl\n"
#. module: account_voucher
@@ -138,6 +138,8 @@ msgid ""
"You can not change the journal as you already reconciled some statement "
"lines!"
msgstr ""
+"U kunt het journaal niet veranderen, omdat er al uittreksellijnen zijn "
+"afgepunt."
#. module: account_voucher
#: view:account.voucher:0
@@ -148,7 +150,7 @@ msgstr "Goedkeuren"
#: model:ir.actions.act_window,name:account_voucher.action_vendor_payment
#: model:ir.ui.menu,name:account_voucher.menu_action_vendor_payment
msgid "Supplier Payments"
-msgstr ""
+msgstr "Leveranciersbetalingen"
#. module: account_voucher
#: model:ir.actions.act_window,help:account_voucher.action_purchase_receipt
@@ -223,7 +225,7 @@ msgstr "Berichten"
#: model:ir.actions.act_window,name:account_voucher.action_purchase_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_purchase_receipt
msgid "Purchase Receipts"
-msgstr ""
+msgstr "Aankoopbewijzen"
#. module: account_voucher
#: field:account.voucher.line,move_line_id:0
@@ -431,7 +433,7 @@ msgstr "Debet"
#: code:addons/account_voucher/account_voucher.py:1547
#, python-format
msgid "Unable to change journal !"
-msgstr ""
+msgstr "Het dagboek kan niet worden gewijzigd"
#. module: account_voucher
#: view:sale.receipt.report:0
@@ -745,7 +747,7 @@ msgstr "Augustus"
#. module: account_voucher
#: view:account.voucher:0
msgid "Validate Payment"
-msgstr ""
+msgstr "Betaling bevestigen"
#. module: account_voucher
#: help:account.voucher,audit:0
@@ -786,7 +788,7 @@ msgstr "Betaald"
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_sale_receipt
msgid "Sales Receipts"
-msgstr ""
+msgstr "Verkoopbewijzen"
#. module: account_voucher
#: field:account.voucher,message_is_follower:0
@@ -834,7 +836,7 @@ msgstr "Onmiddellijk betalen"
#. module: account_voucher
#: field:account.voucher.line,type:0
msgid "Dr/Cr"
-msgstr ""
+msgstr "Db/Cr"
#. module: account_voucher
#: field:account.voucher,pre_line:0
@@ -845,7 +847,7 @@ msgstr "Vorige betalingen?"
#: code:addons/account_voucher/account_voucher.py:1112
#, python-format
msgid "The invoice you are willing to pay is not valid anymore."
-msgstr ""
+msgstr "De factuur die u wilt betalen, is niet meer geldig."
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@@ -884,7 +886,7 @@ msgstr "Gelieve een reeks in te stellen voor het journaal."
#: model:ir.actions.act_window,name:account_voucher.action_vendor_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_vendor_receipt
msgid "Customer Payments"
-msgstr ""
+msgstr "Klantenbetalingen"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt_report_all
@@ -938,7 +940,7 @@ msgstr "Nummer"
#. module: account_voucher
#: selection:account.voucher.line,type:0
msgid "Credit"
-msgstr ""
+msgstr "Credit"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_bank_statement
@@ -1279,7 +1281,7 @@ msgstr "Openstaand saldo"
#. module: account_voucher
#: model:mail.message.subtype,description:account_voucher.mt_voucher_state_change
msgid "Status changed"
-msgstr ""
+msgstr "Status vgewijzigd"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1014
diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml
index de873c9195c..109c2f9aec9 100644
--- a/addons/account_voucher/voucher_payment_receipt_view.xml
+++ b/addons/account_voucher/voucher_payment_receipt_view.xml
@@ -11,7 +11,7 @@
-
+
@@ -34,7 +34,7 @@
-
+
diff --git a/addons/account_voucher/voucher_sales_purchase_view.xml b/addons/account_voucher/voucher_sales_purchase_view.xml
index 05b783dd339..6a84a09d5e6 100644
--- a/addons/account_voucher/voucher_sales_purchase_view.xml
+++ b/addons/account_voucher/voucher_sales_purchase_view.xml
@@ -10,7 +10,7 @@
-
+
@@ -32,7 +32,7 @@
-
+
diff --git a/addons/analytic/i18n/lt.po b/addons/analytic/i18n/lt.po
new file mode 100644
index 00000000000..d9073313307
--- /dev/null
+++ b/addons/analytic/i18n/lt.po
@@ -0,0 +1,388 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-29 15:10+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: 2013-04-30 05:29+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: analytic
+#: field:account.analytic.account,child_ids:0
+msgid "Child Accounts"
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,state:0
+msgid "In Progress"
+msgstr ""
+
+#. module: analytic
+#: code:addons/analytic/analytic.py:229
+#, python-format
+msgid "Contract: "
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,state:0
+msgid "Template"
+msgstr ""
+
+#. module: analytic
+#: view:account.analytic.account:0
+msgid "End Date"
+msgstr ""
+
+#. module: analytic
+#: help:account.analytic.line,unit_amount:0
+msgid "Specifies the amount of quantity to count."
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,debit:0
+msgid "Debit"
+msgstr ""
+
+#. module: analytic
+#: help:account.analytic.account,type:0
+msgid ""
+"If you select the View Type, it means you won't allow to create journal "
+"entries using that account.\n"
+"The type 'Analytic account' stands for usual accounts that you only want to "
+"use in accounting.\n"
+"If you select Contract or Project, it offers you the possibility to manage "
+"the validity and the invoicing options for this account.\n"
+"The special type 'Template of Contract' allows you to define a template with "
+"default data that you can reuse easily."
+msgstr ""
+
+#. module: analytic
+#: view:account.analytic.account:0
+msgid ""
+"Once the end date of the contract is\n"
+" passed or the maximum number of "
+"service\n"
+" units (e.g. support contract) is\n"
+" reached, the account manager is "
+"notified \n"
+" by email to renew the contract with "
+"the\n"
+" customer."
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,type:0
+msgid "Contract or Project"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,name:0
+msgid "Account/Contract Name"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,manager_id:0
+msgid "Account Manager"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,message_follower_ids:0
+msgid "Followers"
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,state:0
+msgid "Closed"
+msgstr ""
+
+#. module: analytic
+#: model:mail.message.subtype,name:analytic.mt_account_pending
+msgid "Contract to Renew"
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,state:0
+msgid "New"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,user_id:0
+msgid "Project Manager"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,state:0
+msgid "Status"
+msgstr ""
+
+#. module: analytic
+#: code:addons/analytic/analytic.py:271
+#, python-format
+msgid "%s (copy)"
+msgstr ""
+
+#. module: analytic
+#: model:ir.model,name:analytic.model_account_analytic_line
+msgid "Analytic Line"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,description:0
+#: field:account.analytic.line,name:0
+msgid "Description"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,message_unread:0
+msgid "Unread Messages"
+msgstr ""
+
+#. module: analytic
+#: constraint:account.analytic.account:0
+msgid "Error! You cannot create recursive analytic accounts."
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,company_id:0
+#: field:account.analytic.line,company_id:0
+msgid "Company"
+msgstr ""
+
+#. module: analytic
+#: view:account.analytic.account:0
+msgid "Renewal"
+msgstr ""
+
+#. module: analytic
+#: help:account.analytic.account,message_ids:0
+msgid "Messages and communication history"
+msgstr ""
+
+#. module: analytic
+#: model:mail.message.subtype,description:analytic.mt_account_opened
+msgid "Stage opened"
+msgstr ""
+
+#. module: analytic
+#: help:account.analytic.account,quantity_max:0
+msgid ""
+"Sets the higher limit of time to work on the contract, based on the "
+"timesheet. (for instance, number of hours in a limited support contract.)"
+msgstr ""
+
+#. module: analytic
+#: code:addons/analytic/analytic.py:160
+#, python-format
+msgid ""
+"If you set a company, the currency selected has to be the same as it's "
+"currency. \n"
+"You can remove the company belonging, and thus change the currency, only on "
+"analytic account of type 'view'. This can be really usefull for "
+"consolidation purposes of several companies charts with different "
+"currencies, for example."
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,message_is_follower:0
+msgid "Is a Follower"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.line,user_id:0
+msgid "User"
+msgstr ""
+
+#. module: analytic
+#: model:mail.message.subtype,description:analytic.mt_account_pending
+msgid "Contract pending"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.line,date:0
+msgid "Date"
+msgstr ""
+
+#. module: analytic
+#: model:mail.message.subtype,name:analytic.mt_account_closed
+msgid "Contract Finished"
+msgstr ""
+
+#. module: analytic
+#: view:account.analytic.account:0
+msgid "Terms and Conditions"
+msgstr ""
+
+#. module: analytic
+#: help:account.analytic.line,amount:0
+msgid ""
+"Calculated by multiplying the quantity and the price given in the Product's "
+"cost price. Always expressed in the company main currency."
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,partner_id:0
+msgid "Customer"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,child_complete_ids:0
+msgid "Account Hierarchy"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,message_ids:0
+msgid "Messages"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,parent_id:0
+msgid "Parent Analytic Account"
+msgstr ""
+
+#. module: analytic
+#: view:account.analytic.account:0
+msgid "Contract Information"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,template_id:0
+#: selection:account.analytic.account,type:0
+msgid "Template of Contract"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,message_summary:0
+msgid "Summary"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,quantity_max:0
+msgid "Prepaid Service Units"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,credit:0
+msgid "Credit"
+msgstr ""
+
+#. module: analytic
+#: model:mail.message.subtype,name:analytic.mt_account_opened
+msgid "Contract Opened"
+msgstr ""
+
+#. module: analytic
+#: model:mail.message.subtype,description:analytic.mt_account_closed
+msgid "Contract closed"
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,state:0
+msgid "Cancelled"
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,type:0
+msgid "Analytic View"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,balance:0
+msgid "Balance"
+msgstr ""
+
+#. module: analytic
+#: help:account.analytic.account,message_unread:0
+msgid "If checked new messages require your attention."
+msgstr ""
+
+#. module: analytic
+#: selection:account.analytic.account,state:0
+msgid "To Renew"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,quantity:0
+#: field:account.analytic.line,unit_amount:0
+msgid "Quantity"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,date:0
+msgid "Date End"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,code:0
+msgid "Reference"
+msgstr ""
+
+#. module: analytic
+#: code:addons/analytic/analytic.py:160
+#, python-format
+msgid "Error!"
+msgstr ""
+
+#. module: analytic
+#: model:res.groups,name:analytic.group_analytic_accounting
+msgid "Analytic Accounting"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.line,amount:0
+msgid "Amount"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,complete_name:0
+msgid "Full Account Name"
+msgstr ""
+
+#. module: analytic
+#: view:account.analytic.account:0
+#: selection:account.analytic.account,type:0
+#: field:account.analytic.line,account_id:0
+#: model:ir.model,name:analytic.model_account_analytic_account
+msgid "Analytic Account"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,currency_id:0
+msgid "Currency"
+msgstr ""
+
+#. module: analytic
+#: help:account.analytic.account,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: analytic
+#: field:account.analytic.account,type:0
+msgid "Type of Account"
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,date_start:0
+msgid "Start Date"
+msgstr ""
+
+#. module: analytic
+#: constraint:account.analytic.line:0
+msgid "You cannot create analytic line on view account."
+msgstr ""
+
+#. module: analytic
+#: field:account.analytic.account,line_ids:0
+msgid "Analytic Entries"
+msgstr ""
diff --git a/addons/analytic_contract_hr_expense/i18n/nl_BE.po b/addons/analytic_contract_hr_expense/i18n/nl_BE.po
new file mode 100644
index 00000000000..4bc0cc559e5
--- /dev/null
+++ b/addons/analytic_contract_hr_expense/i18n/nl_BE.po
@@ -0,0 +1,72 @@
+# Dutch (Belgium) translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-15 16:33+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
+"Language-Team: Dutch (Belgium) \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
+
+#. module: analytic_contract_hr_expense
+#: view:account.analytic.account:0
+msgid "or view"
+msgstr "of bekijk"
+
+#. module: analytic_contract_hr_expense
+#: view:account.analytic.account:0
+msgid "Nothing to invoice, create"
+msgstr "Niets te factureren, aanmaken"
+
+#. module: analytic_contract_hr_expense
+#: view:account.analytic.account:0
+msgid "expenses"
+msgstr "onkosten"
+
+#. module: analytic_contract_hr_expense
+#: model:ir.model,name:analytic_contract_hr_expense.model_account_analytic_account
+msgid "Analytic Account"
+msgstr "Analytische rekening"
+
+#. module: analytic_contract_hr_expense
+#: code:addons/analytic_contract_hr_expense/analytic_contract_hr_expense.py:129
+#, python-format
+msgid "Expenses to Invoice of %s"
+msgstr "Te factureren onkosten van %s"
+
+#. module: analytic_contract_hr_expense
+#: code:addons/analytic_contract_hr_expense/analytic_contract_hr_expense.py:121
+#, python-format
+msgid "Expenses of %s"
+msgstr "Onkosten van %s"
+
+#. module: analytic_contract_hr_expense
+#: field:account.analytic.account,expense_invoiced:0
+#: field:account.analytic.account,expense_to_invoice:0
+#: field:account.analytic.account,remaining_expense:0
+msgid "unknown"
+msgstr "onbekend"
+
+#. module: analytic_contract_hr_expense
+#: field:account.analytic.account,est_expenses:0
+msgid "Estimation of Expenses to Invoice"
+msgstr "Te verwachten te factureren onkosten"
+
+#. module: analytic_contract_hr_expense
+#: field:account.analytic.account,charge_expenses:0
+msgid "Charge Expenses"
+msgstr "Onkosten doorrekenen"
+
+#. module: analytic_contract_hr_expense
+#: view:account.analytic.account:0
+msgid "⇒ Invoice"
+msgstr "⇒ Factuur"
diff --git a/addons/auth_crypt/i18n/lt.po b/addons/auth_crypt/i18n/lt.po
new file mode 100644
index 00000000000..03f0bd5249f
--- /dev/null
+++ b/addons/auth_crypt/i18n/lt.po
@@ -0,0 +1,28 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-24 18:24+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: 2013-04-25 05:20+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: auth_crypt
+#: field:res.users,password_crypt:0
+msgid "Encrypted Password"
+msgstr "Užšifruotas slaptažodis"
+
+#. module: auth_crypt
+#: model:ir.model,name:auth_crypt.model_res_users
+msgid "Users"
+msgstr "Naudotojai"
diff --git a/addons/auth_crypt/i18n/nl_BE.po b/addons/auth_crypt/i18n/nl_BE.po
index b9477ece5dc..abb65c8700f 100644
--- a/addons/auth_crypt/i18n/nl_BE.po
+++ b/addons/auth_crypt/i18n/nl_BE.po
@@ -1,42 +1,28 @@
# Dutch (Belgium) translation for openobject-addons
-# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
-# FIRST AUTHOR , 2012.
+# FIRST AUTHOR , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
-"POT-Creation-Date: 2012-12-03 16:03+0000\n"
-"PO-Revision-Date: 2012-07-26 17:52+0000\n"
-"Last-Translator: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-15 16:02+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: Dutch (Belgium) \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-12-04 05:53+0000\n"
-"X-Generator: Launchpad (build 16335)\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
-#. module: base_crypt
-#: model:ir.model,name:base_crypt.model_res_users
+#. module: auth_crypt
+#: field:res.users,password_crypt:0
+msgid "Encrypted Password"
+msgstr "Geëncrypteerd wachtwoord"
+
+#. module: auth_crypt
+#: model:ir.model,name:auth_crypt.model_res_users
msgid "Users"
-msgstr ""
-
-#~ msgid "You can not have two users with the same login !"
-#~ msgstr "U kunt geen twee gebruikers met dezelfde login maken."
-
-#, python-format
-#~ msgid "Please specify the password !"
-#~ msgstr "Gelieve een wachtwoord op te geven"
-
-#~ msgid "The chosen company is not in the allowed companies for this user"
-#~ msgstr ""
-#~ "De gekozen firma behoort niet tot de toegelaten bedrijven voor deze "
-#~ "gebruiker."
-
-#~ msgid "res.users"
-#~ msgstr "res.users"
-
-#, python-format
-#~ msgid "Error"
-#~ msgstr "Fout"
+msgstr "Gebruikers"
diff --git a/addons/auth_oauth_signup/i18n/lt.po b/addons/auth_oauth_signup/i18n/lt.po
new file mode 100644
index 00000000000..27fb83e6a4f
--- /dev/null
+++ b/addons/auth_oauth_signup/i18n/lt.po
@@ -0,0 +1,23 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-24 18:21+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: 2013-04-25 05:20+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: auth_oauth_signup
+#: model:ir.model,name:auth_oauth_signup.model_res_users
+msgid "Users"
+msgstr "Naudotojai"
diff --git a/addons/auth_oauth_signup/i18n/nl_BE.po b/addons/auth_oauth_signup/i18n/nl_BE.po
new file mode 100644
index 00000000000..04d5034d029
--- /dev/null
+++ b/addons/auth_oauth_signup/i18n/nl_BE.po
@@ -0,0 +1,23 @@
+# Dutch (Belgium) translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-15 16:01+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
+"Language-Team: Dutch (Belgium) \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
+
+#. module: auth_oauth_signup
+#: model:ir.model,name:auth_oauth_signup.model_res_users
+msgid "Users"
+msgstr "Gebruikers"
diff --git a/addons/auth_signup/i18n/lt.po b/addons/auth_signup/i18n/lt.po
new file mode 100644
index 00000000000..7ae419856e6
--- /dev/null
+++ b/addons/auth_signup/i18n/lt.po
@@ -0,0 +1,279 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-29 15:13+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: 2013-04-30 05:29+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: auth_signup
+#: field:res.partner,signup_type:0
+msgid "Signup Token Type"
+msgstr ""
+
+#. module: auth_signup
+#: field:base.config.settings,auth_signup_uninvited:0
+msgid "Allow external users to sign up"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:16
+#, python-format
+msgid "Confirm Password"
+msgstr ""
+
+#. module: auth_signup
+#: help:base.config.settings,auth_signup_uninvited:0
+msgid "If unchecked, only invited users may sign up."
+msgstr ""
+
+#. module: auth_signup
+#: model:ir.model,name:auth_signup.model_base_config_settings
+msgid "base.config.settings"
+msgstr ""
+
+#. module: auth_signup
+#: code:addons/auth_signup/res_users.py:265
+#, python-format
+msgid "Cannot send email: user has no email address."
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:24
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:28
+#, python-format
+msgid "Reset password"
+msgstr ""
+
+#. module: auth_signup
+#: field:base.config.settings,auth_signup_template_user_id:0
+msgid "Template user for new users created through signup"
+msgstr ""
+
+#. module: auth_signup
+#: model:email.template,subject:auth_signup.reset_password_email
+msgid "Password reset"
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/js/auth_signup.js:117
+#, python-format
+msgid "Please enter a password and confirm it."
+msgstr ""
+
+#. module: auth_signup
+#: view:res.users:0
+msgid "Send an email to the user to (re)set their password."
+msgstr ""
+
+#. module: auth_signup
+#. openerp-web
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:23
+#: code:addons/auth_signup/static/src/xml/auth_signup.xml:26
+#, python-format
+msgid "Sign Up"
+msgstr ""
+
+#. module: auth_signup
+#: selection:res.users,state:0
+msgid "New"
+msgstr ""
+
+#. module: auth_signup
+#: code:addons/auth_signup/res_users.py:258
+#, python-format
+msgid "Mail sent to:"
+msgstr ""
+
+#. module: auth_signup
+#: field:res.users,state:0
+msgid "Status"
+msgstr ""
+
+#. module: auth_signup
+#: model:email.template,body_html:auth_signup.reset_password_email
+msgid ""
+"\n"
+"
A password reset was requested for the OpenERP account linked to this "
+"email.
\n"
+"\n"
+"
You may change your password by following this link.
\n"
+"\n"
+"
Note: If you do not expect this, you can safely ignore this email.
\n"
+" The calendar is shared between employees and fully integrated "
+"with\n"
+" other applications such as the employee holidays or the "
+"business\n"
+" opportunities.\n"
+"
\n"
+" "
+msgstr ""
#. module: base_calendar
#: help:calendar.alarm,description:0
@@ -1262,129 +1188,103 @@ msgid ""
"calendar component, than that provided by the "
"\"SUMMARY\" property"
msgstr ""
-"Facilita una descripción más completa del componente del calendario que la "
-"facilitada por la propiedad \"RESUMEN\""
#. module: base_calendar
#: view:calendar.event:0
msgid "Responsible User"
-msgstr "Usuario responsable"
+msgstr ""
#. module: base_calendar
+#: view:crm.meeting:0
+msgid "Select Weekdays"
+msgstr ""
+
+#. module: base_calendar
+#: code:addons/base_calendar/base_calendar.py:1519
#: selection:calendar.attendee,availability:0
#: selection:calendar.event,show_as:0
#: selection:calendar.todo,show_as:0
-#: selection:res.users,availability:0
+#: selection:crm.meeting,show_as:0
+#, python-format
msgid "Busy"
-msgstr "Ocupado"
+msgstr ""
#. module: base_calendar
#: model:ir.model,name:base_calendar.model_calendar_event
msgid "Calendar Event"
-msgstr "Evento de calendario"
-
-#. module: base_calendar
-#: selection:calendar.attendee,state:0
-#: selection:calendar.event,state:0
-#: selection:calendar.todo,state:0
-msgid "Tentative"
-msgstr "Provisional"
-
-#. module: base_calendar
-#: field:calendar.event,interval:0
-#: field:calendar.todo,interval:0
-msgid "Repeat every"
-msgstr "Repetir cada"
-
-#. module: base_calendar
-#: selection:calendar.event,end_type:0
-#: selection:calendar.todo,end_type:0
-msgid "Fix amout of times"
-msgstr "Cantidad fija de veces"
+msgstr ""
#. module: base_calendar
#: field:calendar.event,recurrency:0
#: field:calendar.todo,recurrency:0
+#: field:crm.meeting,recurrency:0
msgid "Recurrent"
-msgstr "Recurrente"
+msgstr ""
#. module: base_calendar
#: field:calendar.event,rrule_type:0
#: field:calendar.todo,rrule_type:0
+#: field:crm.meeting,rrule_type:0
msgid "Recurrency"
-msgstr "Recurrencia"
+msgstr ""
#. module: base_calendar
-#: model:ir.actions.act_window,name:base_calendar.action_view_attendee_form
-#: model:ir.ui.menu,name:base_calendar.menu_attendee_invitations
-msgid "Event Invitations"
-msgstr "Invitaciones al evento"
-
-#. module: base_calendar
-#: selection:base.calendar.set.exrule,week_list:0
#: selection:calendar.event,week_list:0
#: selection:calendar.todo,week_list:0
+#: selection:crm.meeting,week_list:0
msgid "Thursday"
-msgstr "Jueves"
+msgstr ""
#. module: base_calendar
#: field:calendar.event,exrule:0
#: field:calendar.todo,exrule:0
+#: field:crm.meeting,exrule:0
msgid "Exception Rule"
-msgstr "Regla de excepción"
+msgstr ""
#. module: base_calendar
#: help:calendar.attendee,language:0
msgid ""
"To specify the language for text values in aproperty or property parameter."
msgstr ""
-"Para indicar el idioma de los valores de texto en una propiedad o parámetro "
-"de propiedad."
#. module: base_calendar
#: view:calendar.event:0
msgid "Details"
-msgstr "Detalles"
+msgstr ""
#. module: base_calendar
#: help:calendar.event,exrule:0
#: help:calendar.todo,exrule:0
+#: help:crm.meeting,exrule:0
msgid ""
"Defines a rule or repeating pattern of time to exclude from the recurring "
"rule."
msgstr ""
-"Define una regla o patrón de repetición de tiempo a excluir de la regla "
-"recurrente."
#. module: base_calendar
-#: field:base.calendar.set.exrule,month_list:0
#: field:calendar.event,month_list:0
#: field:calendar.todo,month_list:0
+#: field:crm.meeting,month_list:0
msgid "Month"
-msgstr "Mes"
-
-#. module: base_calendar
-#: view:base_calendar.invite.attendee:0
-#: view:calendar.event:0
-msgid "Invite People"
-msgstr "Invitar personas"
-
-#. module: base_calendar
-#: help:calendar.event,rrule:0
-#: help:calendar.todo,rrule:0
-msgid ""
-"Defines a rule or repeating pattern for recurring events\n"
-"e.g.: Every other month on the last Sunday of the month for 10 occurrences: "
-" FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=-1SU"
msgstr ""
-"Define una regla o patrón repetitivo para eventos recurrentes.\n"
-"Por ejemplo: Para 10 ocurrencias cada último domingo de cada dos meses : "
-"FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=-1SU"
+
+#. module: base_calendar
+#: selection:calendar.event,rrule_type:0
+#: selection:calendar.todo,rrule_type:0
+#: selection:crm.meeting,rrule_type:0
+msgid "Day(s)"
+msgstr ""
+
+#. module: base_calendar
+#: view:calendar.event:0
+msgid "Confirmed Events"
+msgstr ""
#. module: base_calendar
#: field:calendar.attendee,dir:0
msgid "URI Reference"
-msgstr "Referencia URI"
+msgstr ""
#. module: base_calendar
#: field:calendar.alarm,description:0
@@ -1393,110 +1293,115 @@ msgstr "Referencia URI"
#: field:calendar.event,name:0
#: field:calendar.todo,description:0
#: field:calendar.todo,name:0
+#: field:crm.meeting,description:0
msgid "Description"
-msgstr "Descripción"
+msgstr ""
#. module: base_calendar
-#: selection:base.calendar.set.exrule,month_list:0
#: selection:calendar.event,month_list:0
#: selection:calendar.todo,month_list:0
+#: selection:crm.meeting,month_list:0
msgid "May"
-msgstr "Mayo"
-
-#. module: base_calendar
-#: field:base_calendar.invite.attendee,type:0
-#: view:calendar.attendee:0
-msgid "Type"
-msgstr "Tipo"
-
-#. module: base_calendar
-#: view:calendar.attendee:0
-msgid "Search Invitations"
-msgstr "Buscar invitaciones"
+msgstr ""
#. module: base_calendar
#: selection:calendar.alarm,trigger_occurs:0
#: selection:res.alarm,trigger_occurs:0
msgid "After"
-msgstr "Después de"
+msgstr ""
#. module: base_calendar
#: selection:calendar.alarm,state:0
msgid "Stop"
-msgstr "Parar"
+msgstr ""
#. module: base_calendar
#: model:ir.model,name:base_calendar.model_ir_values
msgid "ir.values"
-msgstr "ir.valores"
+msgstr ""
#. module: base_calendar
-#: model:ir.model,name:base_calendar.model_ir_model
-msgid "Objects"
-msgstr "Objetos"
+#: view:crm.meeting:0
+msgid "Search Meetings"
+msgstr ""
+
+#. module: base_calendar
+#: model:ir.model,name:base_calendar.model_ir_attachment
+msgid "ir.attachment"
+msgstr ""
+
+#. module: base_calendar
+#: model:ir.model,name:base_calendar.model_crm_meeting_type
+msgid "Meeting Type"
+msgstr ""
#. module: base_calendar
-#: view:calendar.attendee:0
#: selection:calendar.attendee,state:0
msgid "Delegated"
-msgstr "Delegada"
+msgstr ""
#. module: base_calendar
-#: field:base.calendar.set.exrule,sa:0
#: field:calendar.event,sa:0
#: field:calendar.todo,sa:0
+#: field:crm.meeting,sa:0
msgid "Sat"
-msgstr "Sáb"
+msgstr ""
#. module: base_calendar
-#: view:calendar.event:0
-msgid "Choose day where repeat the meeting"
-msgstr "Eligir día en el que repetir la cita"
+#: model:ir.actions.act_window,help:base_calendar.action_res_alarm_view
+msgid ""
+"
\n"
+" Click to setup a new alarm type.\n"
+"
\n"
+" You can define a customized type of calendar alarm that may "
+"be\n"
+" assigned to calendar events or meetings.\n"
+"
\n"
+" "
+msgstr ""
#. module: base_calendar
-#: selection:base.calendar.set.exrule,freq:0
-msgid "Minutely"
-msgstr "Cada minuto"
+#: selection:crm.meeting,state:0
+msgid "Unconfirmed"
+msgstr ""
#. module: base_calendar
#: help:calendar.attendee,sent_by:0
msgid "Specify the user that is acting on behalf of the calendar user"
msgstr ""
-"Indique el usuario que está actuando en nombre del usuario del calendario."
#. module: base_calendar
#: view:calendar.event:0
-#: field:calendar.event.edit.all,date_deadline:0
+#: field:calendar.event,date_deadline:0
+#: field:calendar.todo,date_deadline:0
+#: field:crm.meeting,date_deadline:0
msgid "End Date"
-msgstr "Fecha final"
+msgstr ""
#. module: base_calendar
-#: selection:base.calendar.set.exrule,month_list:0
#: selection:calendar.event,month_list:0
#: selection:calendar.todo,month_list:0
+#: selection:crm.meeting,month_list:0
msgid "February"
-msgstr "Febrero"
-
-#. module: base_calendar
-#: selection:calendar.event,freq:0
-#: selection:calendar.todo,freq:0
-msgid "Months"
-msgstr "Meses"
+msgstr ""
#. module: base_calendar
#: selection:calendar.attendee,cutype:0
msgid "Resource"
-msgstr "Recurso"
+msgstr ""
#. module: base_calendar
+#: field:crm.meeting.type,name:0
#: field:res.alarm,name:0
msgid "Name"
-msgstr "Nombre"
+msgstr ""
#. module: base_calendar
-#: model:ir.model,name:base_calendar.model_calendar_alarm
-msgid "Event alarm information"
-msgstr "Información del aviso del evento"
+#: field:calendar.event,exdate:0
+#: field:calendar.todo,exdate:0
+#: field:crm.meeting,exdate:0
+msgid "Exception Date/Times"
+msgstr ""
#. module: base_calendar
#: help:calendar.alarm,name:0
@@ -1504,154 +1409,162 @@ msgid ""
"Contains the text to be used as the message subject for "
"email or contains the text to be used for display"
msgstr ""
-"Contiene el texto a usar como asunto del mensaje para correos electrónicos, "
-"o contiene el texto a mostrar"
#. module: base_calendar
-#: field:calendar.event,alarm_id:0
-#: field:calendar.event,base_calendar_alarm_id:0
-#: field:calendar.todo,alarm_id:0
-#: field:calendar.todo,base_calendar_alarm_id:0
-msgid "Alarm"
-msgstr "Alarma"
-
-#. module: base_calendar
-#: code:addons/base_calendar/wizard/base_calendar_set_exrule.py:90
-#, python-format
-msgid "Please Apply Recurrency before applying Exception Rule."
+#: model:ir.model,name:base_calendar.model_mail_message
+msgid "Message"
+msgstr ""
+
+#. module: base_calendar
+#: field:calendar.event,base_calendar_alarm_id:0
+#: field:calendar.todo,base_calendar_alarm_id:0
+#: field:crm.meeting,base_calendar_alarm_id:0
+msgid "Alarm"
msgstr ""
-"Por favor, aplique la repetición antes de aplicar la excepción de la regla"
#. module: base_calendar
#: field:calendar.attendee,sent_by_uid:0
msgid "Sent By User"
-msgstr "Enviado por usuario"
+msgstr ""
#. module: base_calendar
-#: selection:base.calendar.set.exrule,month_list:0
#: selection:calendar.event,month_list:0
#: selection:calendar.todo,month_list:0
+#: selection:crm.meeting,month_list:0
msgid "April"
-msgstr "Abril"
+msgstr ""
+
+#. module: base_calendar
+#: code:addons/base_calendar/crm_meeting.py:106
+#, python-format
+msgid "Email addresses not found"
+msgstr ""
#. module: base_calendar
#: view:calendar.event:0
msgid "Recurrency period"
-msgstr "Periodo de recurrencia"
+msgstr ""
#. module: base_calendar
-#: field:base.calendar.set.exrule,week_list:0
#: field:calendar.event,week_list:0
#: field:calendar.todo,week_list:0
+#: field:crm.meeting,week_list:0
msgid "Weekday"
-msgstr "Día de la semana"
+msgstr ""
+
+#. module: base_calendar
+#: code:addons/base_calendar/base_calendar.py:1013
+#, python-format
+msgid "Interval cannot be negative."
+msgstr ""
#. module: base_calendar
-#: field:base.calendar.set.exrule,byday:0
#: field:calendar.event,byday:0
#: field:calendar.todo,byday:0
+#: field:crm.meeting,byday:0
msgid "By day"
-msgstr "Por día"
+msgstr ""
+
+#. module: base_calendar
+#: code:addons/base_calendar/base_calendar.py:441
+#, python-format
+msgid "First you have to specify the date of the invitation."
+msgstr ""
#. module: base_calendar
#: field:calendar.alarm,model_id:0
msgid "Model"
-msgstr "Modelo"
+msgstr ""
#. module: base_calendar
#: selection:calendar.alarm,action:0
msgid "Audio"
-msgstr "Audio"
+msgstr ""
#. module: base_calendar
#: field:calendar.event,id:0
#: field:calendar.todo,id:0
+#: field:crm.meeting,id:0
msgid "ID"
-msgstr "ID"
+msgstr ""
#. module: base_calendar
#: selection:calendar.attendee,role:0
msgid "For information Purpose"
-msgstr "Con propósito informativo"
+msgstr ""
#. module: base_calendar
-#: view:base_calendar.invite.attendee:0
-msgid "Invite"
-msgstr "Invitar"
+#: field:calendar.event,select1:0
+#: field:calendar.todo,select1:0
+#: field:crm.meeting,select1:0
+msgid "Option"
+msgstr ""
#. module: base_calendar
#: model:ir.model,name:base_calendar.model_calendar_attendee
msgid "Attendee information"
-msgstr "Información asistentes"
+msgstr ""
#. module: base_calendar
#: field:calendar.alarm,res_id:0
msgid "Resource ID"
-msgstr "ID del registro"
+msgstr ""
#. module: base_calendar
#: selection:calendar.attendee,state:0
msgid "Needs Action"
-msgstr "Necesita acción"
+msgstr ""
#. module: base_calendar
#: field:calendar.attendee,sent_by:0
msgid "Sent By"
-msgstr "Enviado por"
+msgstr ""
#. module: base_calendar
#: field:calendar.event,sequence:0
#: field:calendar.todo,sequence:0
+#: field:crm.meeting,sequence:0
msgid "Sequence"
-msgstr "Secuencia"
+msgstr ""
#. module: base_calendar
#: help:calendar.event,alarm_id:0
#: help:calendar.todo,alarm_id:0
+#: help:crm.meeting,alarm_id:0
msgid "Set an alarm at this time, before the event occurs"
-msgstr "Configure una alarma en este momento, antes de que ocurra el evento"
+msgstr ""
#. module: base_calendar
-#: selection:base_calendar.invite.attendee,type:0
-msgid "Internal User"
-msgstr "Usuario interno"
-
-#. module: base_calendar
-#: view:calendar.attendee:0
#: view:calendar.event:0
+#: view:crm.meeting:0
msgid "Accept"
-msgstr "Aceptar"
+msgstr ""
#. module: base_calendar
-#: selection:base.calendar.set.exrule,week_list:0
#: selection:calendar.event,week_list:0
#: selection:calendar.todo,week_list:0
+#: selection:crm.meeting,week_list:0
msgid "Saturday"
-msgstr "Sábado"
+msgstr ""
#. module: base_calendar
-#: view:calendar.attendee:0
-msgid "Invitation To"
-msgstr "Invitación a"
+#: field:calendar.event,interval:0
+#: field:calendar.todo,interval:0
+#: field:crm.meeting,interval:0
+msgid "Repeat Every"
+msgstr ""
#. module: base_calendar
-#: selection:base.calendar.set.exrule,byday:0
#: selection:calendar.event,byday:0
#: selection:calendar.todo,byday:0
+#: selection:crm.meeting,byday:0
msgid "Second"
-msgstr "Segundo"
+msgstr ""
#. module: base_calendar
#: field:calendar.attendee,availability:0
-#: field:res.users,availability:0
msgid "Free/Busy"
-msgstr "Libre/Ocupado"
-
-#. module: base_calendar
-#: field:calendar.event,end_type:0
-#: field:calendar.todo,end_type:0
-msgid "Way to end reccurency"
-msgstr "Forma de terminar recurrencia"
+msgstr ""
#. module: base_calendar
#: field:calendar.alarm,duration:0
@@ -1659,20 +1572,16 @@ msgstr "Forma de terminar recurrencia"
#: field:calendar.event,duration:0
#: field:calendar.todo,date:0
#: field:calendar.todo,duration:0
+#: field:crm.meeting,duration:0
#: field:res.alarm,duration:0
#: field:res.alarm,trigger_duration:0
msgid "Duration"
-msgstr "Duración"
-
-#. module: base_calendar
-#: selection:base_calendar.invite.attendee,type:0
-msgid "External Email"
-msgstr "Email externo"
+msgstr ""
#. module: base_calendar
#: field:calendar.alarm,trigger_date:0
msgid "Trigger Date"
-msgstr "Fecha activación"
+msgstr ""
#. module: base_calendar
#: help:calendar.alarm,attach:0
@@ -1684,19 +1593,10 @@ msgid ""
" * Points to a procedure resource, which is invoked when "
" the alarm is triggered for procedure."
msgstr ""
-"* Apunta a un recurso de sonido, que se escucha cuando la alarma se activa "
-"por audio.\n"
-"* El archivo que está intentando ser enviado como adjunto en el correo "
-"electrónico.\n"
-"* Apunta a un recurso de procedimiento, que se invoca cuando la alarma se "
-"activa por procedimiento."
#. module: base_calendar
-#: selection:base.calendar.set.exrule,byday:0
#: selection:calendar.event,byday:0
#: selection:calendar.todo,byday:0
+#: selection:crm.meeting,byday:0
msgid "Fifth"
-msgstr "Quinto"
-
-#~ msgid "Set Exclude range"
-#~ msgstr "Fijar el rango de exclusión"
+msgstr ""
diff --git a/addons/base_crypt/i18n/nl_BE.po b/addons/base_crypt/i18n/nl_BE.po
index 7ad3faa1ef5..d77a3f14b47 100644
--- a/addons/base_crypt/i18n/nl_BE.po
+++ b/addons/base_crypt/i18n/nl_BE.po
@@ -8,19 +8,19 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-12-03 16:03+0000\n"
-"PO-Revision-Date: 2012-07-26 17:52+0000\n"
-"Last-Translator: FULL NAME \n"
+"PO-Revision-Date: 2013-04-15 16:02+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: Dutch (Belgium) \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:49+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
#. module: base_crypt
#: model:ir.model,name:base_crypt.model_res_users
msgid "Users"
-msgstr ""
+msgstr "Gebruikers"
#~ msgid "You can not have two users with the same login !"
#~ msgstr "U kunt geen twee gebruikers met dezelfde login maken."
diff --git a/addons/base_report_designer/base_report_designer.py b/addons/base_report_designer/base_report_designer.py
index 6a0a2722755..bc7959a17df 100644
--- a/addons/base_report_designer/base_report_designer.py
+++ b/addons/base_report_designer/base_report_designer.py
@@ -20,12 +20,13 @@
##############################################################################
import base64
+from StringIO import StringIO
+
+from openerp.modules.module import get_module_resource
import openerp.modules.registry
from openerp.osv import osv
from openerp_sxw2rml import sxw2rml
-from StringIO import StringIO
-from openerp import addons
-
+
class report_xml(osv.osv):
_inherit = 'ir.actions.report.xml'
@@ -36,9 +37,9 @@ class report_xml(osv.osv):
'''
sxwval = StringIO(base64.decodestring(file_sxw))
if file_type=='sxw':
- fp = open(addons.get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_oo2rml.xsl'),'rb')
+ fp = open(get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_oo2rml.xsl'),'rb')
if file_type=='odt':
- fp = open(addons.get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_odt2rml.xsl'),'rb')
+ fp = open(get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_odt2rml.xsl'),'rb')
return {'report_rml_content': str(sxw2rml(sxwval, xsl=fp.read()))}
def upload_report(self, cr, uid, report_id, file_sxw, file_type, context=None):
@@ -47,9 +48,9 @@ class report_xml(osv.osv):
'''
sxwval = StringIO(base64.decodestring(file_sxw))
if file_type=='sxw':
- fp = open(addons.get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_oo2rml.xsl'),'rb')
+ fp = open(get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_oo2rml.xsl'),'rb')
if file_type=='odt':
- fp = open(addons.get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_odt2rml.xsl'),'rb')
+ fp = open(get_module_resource('base_report_designer','openerp_sxw2rml', 'normalized_odt2rml.xsl'),'rb')
report = self.pool['ir.actions.report.xml'].write(cr, uid, [report_id], {
'report_sxw_content': base64.decodestring(file_sxw),
'report_rml_content': str(sxw2rml(sxwval, xsl=fp.read())),
diff --git a/addons/base_report_designer/base_report_designer_installer.xml b/addons/base_report_designer/base_report_designer_installer.xml
index 657eae8fd63..99898f5a703 100644
--- a/addons/base_report_designer/base_report_designer_installer.xml
+++ b/addons/base_report_designer/base_report_designer_installer.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/addons/base_report_designer/installer.py b/addons/base_report_designer/installer.py
index 0c0e6086df0..7fddc27f037 100644
--- a/addons/base_report_designer/installer.py
+++ b/addons/base_report_designer/installer.py
@@ -23,7 +23,6 @@ from openerp.osv import fields
from openerp.osv import osv
import base64
from openerp.tools.translate import _
-from openerp import addons
class base_report_designer_installer(osv.osv_memory):
_name = 'base_report_designer.installer'
@@ -31,13 +30,13 @@ class base_report_designer_installer(osv.osv_memory):
def default_get(self, cr, uid, fields, context=None):
data = super(base_report_designer_installer, self).default_get(cr, uid, fields, context=context)
- plugin_file = open(addons.get_module_resource('base_report_designer','plugin', 'openerp_report_designer.zip'),'rb')
- data['plugin_file'] = base64.encodestring(plugin_file.read())
+ base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
+ data['plugin_file'] = base_url + '/base_report_designer/static/base-report-designer-plugin/openerp_report_designer.zip'
return data
_columns = {
'name':fields.char('File name', size=34),
- 'plugin_file':fields.binary('OpenObject Report Designer Plug-in', readonly=True, help="OpenObject Report Designer plug-in file. Save as this file and install this plug-in in OpenOffice."),
+ 'plugin_file':fields.char('OpenObject Report Designer Plug-in', size=256, readonly=True, help="OpenObject Report Designer plug-in file. Save as this file and install this plug-in in OpenOffice."),
'description':fields.text('Description', readonly=True)
}
diff --git a/addons/base_report_designer/plugin/openerp_report_designer.zip b/addons/base_report_designer/static/base-report-designer-plugin/openerp_report_designer.zip
similarity index 100%
rename from addons/base_report_designer/plugin/openerp_report_designer.zip
rename to addons/base_report_designer/static/base-report-designer-plugin/openerp_report_designer.zip
diff --git a/addons/base_setup/i18n/nl_BE.po b/addons/base_setup/i18n/nl_BE.po
index f22fd2c8adc..518ada07a5c 100644
--- a/addons/base_setup/i18n/nl_BE.po
+++ b/addons/base_setup/i18n/nl_BE.po
@@ -7,19 +7,19 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
-"PO-Revision-Date: 2012-10-01 11:22+0000\n"
+"PO-Revision-Date: 2013-04-26 16:24+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:12+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-27 05:44+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Emails Integration"
-msgstr ""
+msgstr "E-mailintegratie"
#. module: base_setup
#: selection:base.setup.terminology,partner:0
@@ -29,18 +29,19 @@ msgstr "Gast"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Contacts"
-msgstr ""
+msgstr "Contactpersonen"
#. module: base_setup
#: model:ir.model,name:base_setup.model_base_config_settings
msgid "base.config.settings"
-msgstr ""
+msgstr "base.config.settings"
#. module: base_setup
#: field:base.config.settings,module_auth_oauth:0
msgid ""
"Use external authentication providers, sign in with google, facebook, ..."
msgstr ""
+"Gebruik externe verificatieproviders. Meld aan met Google, Facebook, ..."
#. module: base_setup
#: view:sale.config.settings:0
@@ -54,11 +55,19 @@ msgid ""
"OpenERP using specific\n"
" plugins for your preferred email application."
msgstr ""
+"OpenERP maakt het mogelijk om automatisch leads (of andere documenten)\n"
+" aan te maken op basis van inkomende e-mails. U "
+"kunt automatisch e-mails synchroniseren met OpenERP\n"
+" met behulp van reguliere POP / IMAP-accounts, "
+"via een direct e-mailintegratiescript voor uw\n"
+" e-mailserver, of door zelf uw e-mails naar "
+"OpenERP te sturen met behulp van specifieke\n"
+" plug-ins voor uw favoriete e-mailprogramma."
#. module: base_setup
#: field:sale.config.settings,module_sale:0
msgid "SALE"
-msgstr ""
+msgstr "VERKOOP"
#. module: base_setup
#: selection:base.setup.terminology,partner:0
@@ -68,24 +77,24 @@ msgstr "Lid"
#. module: base_setup
#: view:base.config.settings:0
msgid "Portal access"
-msgstr ""
+msgstr "Portaaltoegang"
#. module: base_setup
#: view:base.config.settings:0
msgid "Authentication"
-msgstr ""
+msgstr "Verificatie"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Quotations and Sales Orders"
-msgstr ""
+msgstr "Offertes en verkooporders"
#. module: base_setup
#: view:base.config.settings:0
#: model:ir.actions.act_window,name:base_setup.action_general_configuration
#: model:ir.ui.menu,name:base_setup.menu_general_configuration
msgid "General Settings"
-msgstr ""
+msgstr "Algemeen"
#. module: base_setup
#: selection:base.setup.terminology,partner:0
@@ -95,12 +104,12 @@ msgstr "Donor"
#. module: base_setup
#: view:base.config.settings:0
msgid "Email"
-msgstr ""
+msgstr "E-mail"
#. module: base_setup
#: field:sale.config.settings,module_crm:0
msgid "CRM"
-msgstr ""
+msgstr "Relatiebeheer"
#. module: base_setup
#: selection:base.setup.terminology,partner:0
@@ -110,32 +119,32 @@ msgstr "Patiënt"
#. module: base_setup
#: field:base.config.settings,module_base_import:0
msgid "Allow users to import data from CSV files"
-msgstr ""
+msgstr "Gebruikers mogen gegevens importeren uit csv-bestanden"
#. module: base_setup
#: field:base.config.settings,module_multi_company:0
msgid "Manage multiple companies"
-msgstr ""
+msgstr "Meerdere bedrijven beheren"
#. module: base_setup
#: view:sale.config.settings:0
msgid "On Mail Client"
-msgstr ""
+msgstr "Op e-mailclient"
#. module: base_setup
#: view:base.config.settings:0
msgid "--db-filter=YOUR_DATABAE"
-msgstr ""
+msgstr "--db-filter=UW_DATABASE"
#. module: base_setup
#: field:sale.config.settings,module_web_linkedin:0
msgid "Get contacts automatically from linkedIn"
-msgstr ""
+msgstr "Haal contactpersonen op uit LinkedIn"
#. module: base_setup
#: field:sale.config.settings,module_plugin_thunderbird:0
msgid "Enable Thunderbird plug-in"
-msgstr ""
+msgstr "Activeer de Thunderbirdplug-in"
#. module: base_setup
#: view:base.setup.terminology:0
@@ -145,22 +154,22 @@ msgstr "res_config_contents"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Customer Features"
-msgstr ""
+msgstr "Klantenopties"
#. module: base_setup
#: view:base.config.settings:0
msgid "Import / Export"
-msgstr ""
+msgstr "Import / Export"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Sale Features"
-msgstr ""
+msgstr "Verkoopopties"
#. module: base_setup
#: field:sale.config.settings,module_plugin_outlook:0
msgid "Enable Outlook plug-in"
-msgstr ""
+msgstr "Activeer de Outlookplug-in"
#. module: base_setup
#: view:base.setup.terminology:0
@@ -179,7 +188,7 @@ msgstr "Huurder"
#. module: base_setup
#: help:base.config.settings,module_share:0
msgid "Share or embbed any screen of openerp."
-msgstr ""
+msgstr "Gelijk welk scherm van OpenERP delen of insluiten"
#. module: base_setup
#: selection:base.setup.terminology,partner:0
@@ -192,6 +201,8 @@ msgid ""
"When you create a new contact (person or company), you will be able to load "
"all the data from LinkedIn (photos, address, etc)."
msgstr ""
+"Als u een nieuwe contactpersoon maakt (persoon of bedrijf), kunt u alle "
+"gegevens van LinkedIn laden (foto, adres, enz.)"
#. module: base_setup
#: help:base.config.settings,module_multi_company:0
@@ -200,6 +211,9 @@ msgid ""
"companies.\n"
" This installs the module multi_company."
msgstr ""
+"Werken in omgevingen met meerdere bedrijven, met de nodige "
+"toegangsbeveiliging tussen de bedrijven.\n"
+" Hiermee installeert u de module multi_company."
#. module: base_setup
#: view:base.config.settings:0
@@ -208,6 +222,9 @@ msgid ""
"You can\n"
" launch the OpenERP Server with the option"
msgstr ""
+"Het openbare portaal is alleen toegankelijk als u zich in een enkele "
+"databasemodus bevindt. U kunt\n"
+" de OpenERP-server starten met de optie"
#. module: base_setup
#: view:base.config.settings:0
@@ -215,11 +232,13 @@ msgid ""
"You will find more options in your company details: address for the header "
"and footer, overdue payments texts, etc."
msgstr ""
+"U vindt meer opties bij de bedrijfsgegevens: adres voor de kop- en "
+"voettekst, teksten voor achterstallige betalingen, enz."
#. module: base_setup
#: model:ir.model,name:base_setup.model_sale_config_settings
msgid "sale.config.settings"
-msgstr ""
+msgstr "sale.config.settings"
#. module: base_setup
#: field:base.setup.terminology,partner:0
@@ -238,6 +257,12 @@ msgid ""
"projects,\n"
" etc."
msgstr ""
+"Wanneer u een document naar een klant stuurt,\n"
+" (offerte, factuur), kan uw klant\n"
+" aanmelden en zijn documenten bekijken,\n"
+" uw bedrijfsnieuws lezen, zijn projecten "
+"controleren,\n"
+" enz."
#. module: base_setup
#: model:ir.model,name:base_setup.model_base_setup_terminology
@@ -253,6 +278,8 @@ msgstr "Cliënt"
#: help:base.config.settings,module_portal_anonymous:0
msgid "Enable the public part of openerp, openerp becomes a public website."
msgstr ""
+"Activeer het openbare deel van OpenERP; OpenERP wordt hiermee een openbare "
+"website."
#. module: base_setup
#: help:sale.config.settings,module_plugin_thunderbird:0
@@ -265,6 +292,13 @@ msgid ""
" Partner from the selected emails.\n"
" This installs the module plugin_thunderbird."
msgstr ""
+"Met de plug-in kunt u e-mails met bijlagen koppelen aan de geselecteerde\n"
+" OpenERP-objecten. U kunt een relatie of een lead kiezen en\n"
+" de gekozen e-mail koppelen als een .eml-bestand als bijlage\n"
+" aan het geselecteerde record. U kunt documenten aanmaken "
+"voor CRM-lead\n"
+" en relaties vanuit de geselecteerde e-mails. Hiermee "
+"installeert u de module plugin_thunderbird."
#. module: base_setup
#: selection:base.setup.terminology,partner:0
@@ -280,7 +314,7 @@ msgstr "Gebruik een andere benaming voor Klant"
#: model:ir.actions.act_window,name:base_setup.action_sale_config
#: view:sale.config.settings:0
msgid "Configure Sales"
-msgstr ""
+msgstr "Verkoop instellen"
#. module: base_setup
#: help:sale.config.settings,module_plugin_outlook:0
@@ -293,16 +327,23 @@ msgid ""
" email into an OpenERP mail message with attachments.\n"
" This installs the module plugin_outlook."
msgstr ""
+"Met de Outlookplug-in kunt u een object selecteren dat u wilt toevoegen\n"
+" aan uw e-mail en de bijlagen van MS Outlook. U kunt een "
+"relatie \n"
+" of een lead kiezen en de geselecteerde e-mail archiveren in "
+"een\n"
+" OpenERP-mailbericht met bijlagen.\n"
+" Hiermee installeert u de module plugin_outlook."
#. module: base_setup
#: view:base.config.settings:0
msgid "Options"
-msgstr ""
+msgstr "Opties"
#. module: base_setup
#: field:base.config.settings,module_portal:0
msgid "Activate the customer portal"
-msgstr ""
+msgstr "Klantenportaal activeren"
#. module: base_setup
#: view:base.config.settings:0
@@ -311,36 +352,37 @@ msgid ""
" Once activated, the login page will be "
"replaced by the public website."
msgstr ""
+"Na activering zal de aanmeldpagina worden vervangen door de openbare website."
#. module: base_setup
#: field:base.config.settings,module_share:0
msgid "Allow documents sharing"
-msgstr ""
+msgstr "Sta het delen van documenten toe"
#. module: base_setup
#: view:base.config.settings:0
msgid "(company news, jobs, contact form, etc.)"
-msgstr ""
+msgstr "(bedrijfsnieuws, vacatures, contactformulier, enz.)"
#. module: base_setup
#: field:base.config.settings,module_portal_anonymous:0
msgid "Activate the public portal"
-msgstr ""
+msgstr "Openbare portaal activeren"
#. module: base_setup
#: view:base.config.settings:0
msgid "Configure outgoing email servers"
-msgstr ""
+msgstr "Uitgaande e-mailservers instellen"
#. module: base_setup
#: view:sale.config.settings:0
msgid "Social Network Integration"
-msgstr ""
+msgstr "Integratie sociale netwerken"
#. module: base_setup
#: help:base.config.settings,module_portal:0
msgid "Give your customers access to their documents."
-msgstr ""
+msgstr "Geef uw klanten toegang tot hun documenten."
#. module: base_setup
#: view:base.config.settings:0
@@ -352,7 +394,7 @@ msgstr "Afbreken"
#: view:base.config.settings:0
#: view:sale.config.settings:0
msgid "Apply"
-msgstr ""
+msgstr "Toepassen"
#. module: base_setup
#: view:base.setup.terminology:0
@@ -363,12 +405,12 @@ msgstr "Kies uw terminologie"
#: view:base.config.settings:0
#: view:sale.config.settings:0
msgid "or"
-msgstr ""
+msgstr "of"
#. module: base_setup
#: view:base.config.settings:0
msgid "Configure your company data"
-msgstr ""
+msgstr "Uw bedrijfsgegevens instellen"
#~ msgid "Logo"
#~ msgstr "Logo"
diff --git a/addons/base_status/i18n/lt.po b/addons/base_status/i18n/lt.po
new file mode 100644
index 00000000000..cdaf9b0db37
--- /dev/null
+++ b/addons/base_status/i18n/lt.po
@@ -0,0 +1,76 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-29 15:17+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: 2013-04-30 05:29+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:107
+#, python-format
+msgid "Error !"
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:166
+#, python-format
+msgid "%s has been opened."
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:199
+#, python-format
+msgid "%s has been renewed."
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_stage.py:210
+#, python-format
+msgid "Error!"
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:107
+#, python-format
+msgid ""
+"You can not escalate, you are already at the top level regarding your sales-"
+"team category."
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:193
+#, python-format
+msgid "%s is now pending."
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:187
+#, python-format
+msgid "%s has been canceled."
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_stage.py:210
+#, python-format
+msgid ""
+"You are already at the top level of your sales-team category.\n"
+"Therefore you cannot escalate furthermore."
+msgstr ""
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:181
+#, python-format
+msgid "%s has been closed."
+msgstr ""
diff --git a/addons/base_status/i18n/nl_BE.po b/addons/base_status/i18n/nl_BE.po
new file mode 100644
index 00000000000..6a3c2d83fc7
--- /dev/null
+++ b/addons/base_status/i18n/nl_BE.po
@@ -0,0 +1,80 @@
+# Dutch (Belgium) translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-15 16:40+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
+"Language-Team: Dutch (Belgium) \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:107
+#, python-format
+msgid "Error !"
+msgstr "Fout"
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:166
+#, python-format
+msgid "%s has been opened."
+msgstr "%s is geopend."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:199
+#, python-format
+msgid "%s has been renewed."
+msgstr "%s is vernieuwd."
+
+#. module: base_status
+#: code:addons/base_status/base_stage.py:210
+#, python-format
+msgid "Error!"
+msgstr "Fout"
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:107
+#, python-format
+msgid ""
+"You can not escalate, you are already at the top level regarding your sales-"
+"team category."
+msgstr ""
+"U kunt niet escaleren; u heeft het hoogste niveau in de verkoopteams al "
+"bereikt."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:193
+#, python-format
+msgid "%s is now pending."
+msgstr "%s is wachtend."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:187
+#, python-format
+msgid "%s has been canceled."
+msgstr "%s is geannuleerd."
+
+#. module: base_status
+#: code:addons/base_status/base_stage.py:210
+#, python-format
+msgid ""
+"You are already at the top level of your sales-team category.\n"
+"Therefore you cannot escalate furthermore."
+msgstr ""
+"U bent al op het hoogste niveau van uw verkoopteam.\n"
+"U kunt dus niet verder escaleren."
+
+#. module: base_status
+#: code:addons/base_status/base_state.py:181
+#, python-format
+msgid "%s has been closed."
+msgstr "%s is gesloten."
diff --git a/addons/base_vat/base_vat.py b/addons/base_vat/base_vat.py
index cfb2dbd04d0..e7501334997 100644
--- a/addons/base_vat/base_vat.py
+++ b/addons/base_vat/base_vat.py
@@ -134,6 +134,9 @@ class res_partner(osv.osv):
'vat_subjected': fields.boolean('VAT Legal Statement', help="Check this box if the partner is subjected to the VAT. It will be used for the VAT legal statement.")
}
+ def _commercial_fields(self, cr, uid, context=None):
+ return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['vat_subjected']
+
def _construct_constraint_msg(self, cr, uid, ids, context=None):
def default_vat_check(cn, vn):
# by default, a VAT number is valid if:
diff --git a/addons/base_vat/i18n/nl_BE.po b/addons/base_vat/i18n/nl_BE.po
index 39966dc58ef..a2fe05c5705 100644
--- a/addons/base_vat/i18n/nl_BE.po
+++ b/addons/base_vat/i18n/nl_BE.po
@@ -7,19 +7,19 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
-"PO-Revision-Date: 2012-10-01 11:23+0000\n"
+"PO-Revision-Date: 2013-04-15 16:03+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:10+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
#. module: base_vat
#: view:res.partner:0
msgid "Check Validity"
-msgstr ""
+msgstr "Geldigheid controleren"
#. module: base_vat
#: code:addons/base_vat/base_vat.py:147
@@ -45,7 +45,7 @@ msgstr "Bedrijven"
#: code:addons/base_vat/base_vat.py:111
#, python-format
msgid "Error!"
-msgstr ""
+msgstr "Fout"
#. module: base_vat
#: help:res.partner,vat_subjected:0
diff --git a/addons/claim_from_delivery/i18n/nl_BE.po b/addons/claim_from_delivery/i18n/nl_BE.po
index a8793109b5f..38aab39e523 100644
--- a/addons/claim_from_delivery/i18n/nl_BE.po
+++ b/addons/claim_from_delivery/i18n/nl_BE.po
@@ -8,29 +8,29 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
-"PO-Revision-Date: 2012-10-01 11:24+0000\n"
+"PO-Revision-Date: 2013-04-15 16:38+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: Dutch (Belgium) \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:41+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
#. module: claim_from_delivery
#: view:stock.picking.out:0
msgid "Claims"
-msgstr ""
+msgstr "Klachten"
#. module: claim_from_delivery
#: model:res.request.link,name:claim_from_delivery.request_link_claim_from_delivery
msgid "Delivery Order"
-msgstr ""
+msgstr "Leveringsorder"
#. module: claim_from_delivery
#: model:ir.actions.act_window,name:claim_from_delivery.action_claim_from_delivery
msgid "Claim From Delivery"
-msgstr ""
+msgstr "Klachten van levering"
#~ msgid "Claim"
#~ msgstr "Klacht"
diff --git a/addons/contacts/i18n/lt.po b/addons/contacts/i18n/lt.po
new file mode 100644
index 00000000000..f785a308009
--- /dev/null
+++ b/addons/contacts/i18n/lt.po
@@ -0,0 +1,45 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-24 18:20+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: 2013-04-25 05:20+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: contacts
+#: model:ir.actions.act_window,help:contacts.action_contacts
+msgid ""
+"
\n"
+" Click to add a contact in your address book.\n"
+"
\n"
+" OpenERP helps you easily track all activities related to\n"
+" a customer; discussions, history of business opportunities,\n"
+" documents, etc.\n"
+"
\n"
+" "
+msgstr ""
+"
\n"
+"Spauskite, kad sukurtumėte kontaktą adresų knygoje.\n"
+"
\n"
+"OpenERP pagalba galima stebėti visus veiksmus susijusius su\n"
+"kontaktu; bendravimas, pardavimų galimybių istorija,\n"
+"dokumentai, ir t.t.\n"
+"
\n"
+" "
+
+#. module: contacts
+#: model:ir.actions.act_window,name:contacts.action_contacts
+#: model:ir.ui.menu,name:contacts.menu_contacts
+msgid "Contacts"
+msgstr "Kontaktai"
diff --git a/addons/contacts/i18n/nl_BE.po b/addons/contacts/i18n/nl_BE.po
new file mode 100644
index 00000000000..78fdb540ad6
--- /dev/null
+++ b/addons/contacts/i18n/nl_BE.po
@@ -0,0 +1,46 @@
+# Dutch (Belgium) translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-15 16:01+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
+"Language-Team: Dutch (Belgium) \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
+
+#. module: contacts
+#: model:ir.actions.act_window,help:contacts.action_contacts
+msgid ""
+"
\n"
+" Click to add a contact in your address book.\n"
+"
\n"
+" OpenERP helps you easily track all activities related to\n"
+" a customer; discussions, history of business opportunities,\n"
+" documents, etc.\n"
+"
\n"
+" "
+msgstr ""
+"
\n"
+" Klik hier om een contactpersoon toe te voegen aan het "
+"adresboek.\n"
+"
\n"
+" Met OpenERP kunt u eenvoudig alle activiteiten registreren met "
+"betrekking tot \n"
+" een klant, discussies, opportuniteiten, documenten, enz. \n"
+"
\n"
+" "
+
+#. module: contacts
+#: model:ir.actions.act_window,name:contacts.action_contacts
+#: model:ir.ui.menu,name:contacts.menu_contacts
+msgid "Contacts"
+msgstr "Contactpersonen"
diff --git a/addons/crm/__init__.py b/addons/crm/__init__.py
index d78fb09eae7..4e3a704d5f3 100644
--- a/addons/crm/__init__.py
+++ b/addons/crm/__init__.py
@@ -28,6 +28,7 @@ import report
import wizard
import res_partner
import res_config
+import base_partner_merge
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py
index 072624a7d98..8e17a882076 100644
--- a/addons/crm/__openerp__.py
+++ b/addons/crm/__openerp__.py
@@ -97,6 +97,7 @@ Dashboard for CRM will include:
'board_crm_view.xml',
'res_config_view.xml',
+ 'base_partner_merge_view.xml',
],
'demo': [
'crm_demo.xml',
diff --git a/addons/crm/base_partner_merge.py b/addons/crm/base_partner_merge.py
new file mode 100644
index 00000000000..b2645e7fb79
--- /dev/null
+++ b/addons/crm/base_partner_merge.py
@@ -0,0 +1,760 @@
+#!/usr/bin/env python
+from __future__ import absolute_import
+from email.utils import parseaddr
+import functools
+import htmlentitydefs
+import itertools
+import logging
+import operator
+import re
+from ast import literal_eval
+from openerp.tools import mute_logger
+
+# Validation Library https://pypi.python.org/pypi/validate_email/1.1
+from .validate_email import validate_email
+
+from openerp.osv import osv, orm
+from openerp.osv import fields
+from openerp.osv.orm import browse_record
+from openerp.tools.translate import _
+
+pattern = re.compile("&(\w+?);")
+
+_logger = logging.getLogger('base.partner.merge')
+
+
+# http://www.php2python.com/wiki/function.html-entity-decode/
+def html_entity_decode_char(m, defs=htmlentitydefs.entitydefs):
+ try:
+ return defs[m.group(1)]
+ except KeyError:
+ return m.group(0)
+
+
+def html_entity_decode(string):
+ return pattern.sub(html_entity_decode_char, string)
+
+
+def sanitize_email(email):
+ assert isinstance(email, basestring) and email
+
+ result = re.subn(r';|/|:', ',',
+ html_entity_decode(email or ''))[0].split(',')
+
+ emails = [parseaddr(email)[1]
+ for item in result
+ for email in item.split()]
+
+ return [email.lower()
+ for email in emails
+ if validate_email(email)]
+
+
+def is_integer_list(ids):
+ return all(isinstance(i, (int, long)) for i in ids)
+
+
+class ResPartner(osv.Model):
+ _inherit = 'res.partner'
+
+ _columns = {
+ 'id': fields.integer('Id', readonly=True),
+ 'create_date': fields.datetime('Create Date', readonly=True),
+ }
+
+class MergePartnerLine(osv.TransientModel):
+ _name = 'base.partner.merge.line'
+
+ _columns = {
+ 'wizard_id': fields.many2one('base.partner.merge.automatic.wizard',
+ 'Wizard'),
+ 'min_id': fields.integer('MinID'),
+ 'aggr_ids': fields.char('Ids', required=True),
+ }
+
+ _order = 'min_id asc'
+
+
+class MergePartnerAutomatic(osv.TransientModel):
+ """
+ The idea behind this wizard is to create a list of potential partners to
+ merge. We use two objects, the first one is the wizard for the end-user.
+ And the second will contain the partner list to merge.
+ """
+ _name = 'base.partner.merge.automatic.wizard'
+
+ _columns = {
+ # Group by
+ 'group_by_email': fields.boolean('Email'),
+ 'group_by_name': fields.boolean('Name'),
+ 'group_by_is_company': fields.boolean('Is Company'),
+ 'group_by_vat': fields.boolean('VAT'),
+ 'group_by_parent_id': fields.boolean('Parent Company'),
+
+ 'state': fields.selection([('option', 'Option'),
+ ('selection', 'Selection'),
+ ('finished', 'Finished')],
+ 'State',
+ readonly=True,
+ required=True),
+ 'number_group': fields.integer("Group of Contacts", readonly=True),
+ 'current_line_id': fields.many2one('base.partner.merge.line', 'Current Line'),
+ 'line_ids': fields.one2many('base.partner.merge.line', 'wizard_id', 'Lines'),
+ 'partner_ids': fields.many2many('res.partner', string='Contacts'),
+
+ 'exclude_contact': fields.boolean('A user associated to the contact'),
+ 'exclude_journal_item': fields.boolean('Journal Items associated to the contact'),
+ 'maximum_group': fields.integer("Maximum of Group of Contacts"),
+ }
+
+ _defaults = {
+ 'state': 'option',
+ }
+
+ def get_fk_on(self, cr, table):
+ q = """ SELECT cl1.relname as table,
+ att1.attname as column
+ FROM pg_constraint as con, pg_class as cl1, pg_class as cl2,
+ pg_attribute as att1, pg_attribute as att2
+ WHERE con.conrelid = cl1.oid
+ AND con.confrelid = cl2.oid
+ AND array_lower(con.conkey, 1) = 1
+ AND con.conkey[1] = att1.attnum
+ AND att1.attrelid = cl1.oid
+ AND cl2.relname = %s
+ AND att2.attname = 'id'
+ AND array_lower(con.confkey, 1) = 1
+ AND con.confkey[1] = att2.attnum
+ AND att2.attrelid = cl2.oid
+ AND con.contype = 'f'
+ """
+ return cr.execute(q, (table,))
+
+ def _update_foreign_keys(self, cr, uid, src_partners, dst_partner, context=None):
+ _logger.debug('_update_foreign_keys for dst_partner: %s for src_partners: %r', dst_partner.id, list(map(operator.attrgetter('id'), src_partners)))
+
+ # find the many2one relation to a partner
+ proxy = self.pool.get('res.partner')
+ self.get_fk_on(cr, 'res_partner')
+
+ # ignore two tables
+
+ for table, column in cr.fetchall():
+ if 'base_partner_merge_' in table:
+ continue
+ partner_ids = tuple(map(int, src_partners))
+
+ query = "SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%s'" % (table)
+ cr.execute(query, ())
+ columns = []
+ for data in cr.fetchall():
+ if data[0] != column:
+ columns.append(data[0])
+
+ query_dic = {
+ 'table': table,
+ 'column': column,
+ 'value': columns[0],
+ }
+ if len(columns) <= 1:
+ # unique key treated
+ query = """
+ UPDATE "%(table)s" as ___tu
+ SET %(column)s = %%s
+ WHERE
+ %(column)s = %%s AND
+ NOT EXISTS (
+ SELECT 1
+ FROM "%(table)s" as ___tw
+ WHERE
+ %(column)s = %%s AND
+ ___tu.%(value)s = ___tw.%(value)s
+ )""" % query_dic
+ for partner_id in partner_ids:
+ cr.execute(query, (dst_partner.id, partner_id, dst_partner.id))
+ else:
+ cr.execute("SAVEPOINT recursive_partner_savepoint")
+ try:
+ query = 'UPDATE "%(table)s" SET %(column)s = %%s WHERE %(column)s IN %%s' % query_dic
+ cr.execute(query, (dst_partner.id, partner_ids,))
+
+ if column == proxy._parent_name and table == 'res_partner':
+ query = """
+ WITH RECURSIVE cycle(id, parent_id) AS (
+ SELECT id, parent_id FROM res_partner
+ UNION
+ SELECT cycle.id, res_partner.parent_id
+ FROM res_partner, cycle
+ WHERE res_partner.id = cycle.parent_id AND
+ cycle.id != cycle.parent_id
+ )
+ SELECT id FROM cycle WHERE id = parent_id AND id = %s
+ """
+ cr.execute(query, (dst_partner.id,))
+ if cr.fetchall():
+ cr.execute("ROLLBACK TO SAVEPOINT recursive_partner_savepoint")
+ finally:
+ cr.execute("RELEASE SAVEPOINT recursive_partner_savepoint")
+
+ def _update_reference_fields(self, cr, uid, src_partners, dst_partner, context=None):
+ _logger.debug('_update_reference_fields for dst_partner: %s for src_partners: %r', dst_partner.id, list(map(operator.attrgetter('id'), src_partners)))
+
+ def update_records(model, src, field_model='model', field_id='res_id', context=None):
+ proxy = self.pool.get(model)
+ if proxy is None:
+ return
+ domain = [(field_model, '=', 'res.partner'), (field_id, '=', src.id)]
+ ids = proxy.search(cr, uid, domain, context=context)
+ return proxy.write(cr, uid, ids, {field_id: dst_partner.id}, context=context)
+
+ update_records = functools.partial(update_records, context=context)
+
+ for partner in src_partners:
+ update_records('base.calendar', src=partner, field_model='model_id.model')
+ update_records('ir.attachment', src=partner, field_model='res_model')
+ update_records('mail.followers', src=partner, field_model='res_model')
+ update_records('mail.message', src=partner)
+ update_records('marketing.campaign.workitem', src=partner, field_model='object_id.model')
+ update_records('ir.model.data', src=partner)
+
+ proxy = self.pool['ir.model.fields']
+ domain = [('ttype', '=', 'reference')]
+ record_ids = proxy.search(cr, uid, domain, context=context)
+
+ for record in proxy.browse(cr, uid, record_ids, context=context):
+ proxy_model = self.pool[record.model]
+
+ field_type = proxy_model._columns.get(record.name).__class__._type
+
+ if field_type == 'function':
+ continue
+
+ for partner in src_partners:
+ domain = [
+ (record.name, '=', 'res.partner,%d' % partner.id)
+ ]
+ model_ids = proxy_model.search(cr, uid, domain, context=context)
+ values = {
+ record.name: 'res.partner,%d' % dst_partner.id,
+ }
+ proxy_model.write(cr, uid, model_ids, values, context=context)
+
+ def _update_values(self, cr, uid, src_partners, dst_partner, context=None):
+ _logger.debug('_update_values for dst_partner: %s for src_partners: %r', dst_partner.id, list(map(operator.attrgetter('id'), src_partners)))
+
+ columns = dst_partner._columns
+ def write_serializer(column, item):
+ if isinstance(item, browse_record):
+ return item.id
+ else:
+ return item
+
+ values = dict()
+ for column, field in columns.iteritems():
+ if field._type not in ('many2many', 'one2many', 'function'):
+ for item in itertools.chain(src_partners, [dst_partner]):
+ if item[column]:
+ values[column] = write_serializer(column, item[column])
+
+ values.pop('id', None)
+ parent_id = values.pop('parent_id', None)
+ dst_partner.write(values)
+ if parent_id and parent_id != dst_partner.id:
+ try:
+ dst_partner.write({'parent_id': parent_id})
+ except (osv.except_osv, orm.except_orm):
+ _logger.info('Skip recursive partner hierarchies for parent_id %s of partner: %s', parent_id, dst_partner.id)
+
+ @mute_logger('openerp.osv.expression', 'openerp.osv.orm')
+ def _merge(self, cr, uid, partner_ids, context=None):
+ proxy = self.pool.get('res.partner')
+
+ partner_ids = proxy.exists(cr, uid, list(partner_ids), context=context)
+ if len(partner_ids) < 2:
+ return
+
+ partners = proxy.browse(cr, uid, list(partner_ids), context=context)
+ ordered_partners = sorted(sorted(partners,
+ key=operator.attrgetter('create_date'), reverse=True),
+ key=operator.attrgetter('active'), reverse=True)
+
+ dst_partner = ordered_partners[-1]
+ src_partners = ordered_partners[:-1]
+ _logger.info("dst_partner: %s", dst_partner.id)
+
+ call_it = lambda function: function(cr, uid, src_partners, dst_partner,
+ context=context)
+
+ call_it(self._update_foreign_keys)
+ call_it(self._update_reference_fields)
+ call_it(self._update_values)
+
+ _logger.info("---merged---")
+
+ for partner in src_partners:
+ partner.unlink()
+
+
+ def clean_emails(self, cr, uid, context=None):
+ """
+ Clean the email address of the partner, if there is an email field with
+ a mimum of two addresses, the system will create a new partner, with the
+ information of the previous one and will copy the new cleaned email into
+ the email field.
+ """
+ if context is None:
+ context = {}
+
+ proxy_model = self.pool['ir.model.fields']
+ field_ids = proxy_model.search(cr, uid, [('model', '=', 'res.partner'),
+ ('ttype', 'like', '%2many')],
+ context=context)
+ fields = proxy_model.read(cr, uid, field_ids, context=context)
+ reset_fields = dict((field['name'], []) for field in fields)
+
+ proxy_partner = self.pool['res.partner']
+ context['active_test'] = False
+ ids = proxy_partner.search(cr, uid, [], context=context)
+
+ fields = ['name', 'var' 'partner_id' 'is_company', 'email']
+ partners = proxy_partner.read(cr, uid, ids, fields, context=context)
+
+ partners.sort(key=operator.itemgetter('id'))
+ partners_len = len(partners)
+
+ _logger.info('partner_len: %r', partners_len)
+
+ for idx, partner in enumerate(partners):
+ if not partner['email']:
+ continue
+
+ percent = (idx / float(partners_len)) * 100.0
+ _logger.info('idx: %r', idx)
+ _logger.info('percent: %r', percent)
+ try:
+ emails = sanitize_email(partner['email'])
+ head, tail = emails[:1], emails[1:]
+ email = head[0] if head else False
+
+ proxy_partner.write(cr, uid, [partner['id']],
+ {'email': email}, context=context)
+
+ for email in tail:
+ values = dict(reset_fields, email=email)
+ proxy_partner.copy(cr, uid, partner['id'], values,
+ context=context)
+
+ except Exception:
+ _logger.exception("There is a problem with this partner: %r", partner)
+ raise
+ return True
+
+ def close_cb(self, cr, uid, ids, context=None):
+ return {'type': 'ir.actions.act_window_close'}
+
+ def _generate_query(self, fields, maximum_group=100):
+ group_fields = ', '.join(fields)
+
+ filters = []
+ for field in fields:
+ if field in ['email', 'name']:
+ filters.append((field, 'IS NOT', 'NULL'))
+
+ criteria = ' AND '.join('%s %s %s' % (field, operator, value)
+ for field, operator, value in filters)
+
+ text = [
+ "SELECT min(id), array_agg(id)",
+ "FROM res_partner",
+ ]
+
+ if criteria:
+ text.append('WHERE %s' % criteria)
+
+ text.extend([
+ "GROUP BY %s" % group_fields,
+ "HAVING COUNT(*) >= 2",
+ "ORDER BY min(id)",
+ ])
+
+ if maximum_group:
+ text.extend([
+ "LIMIT %s" % maximum_group,
+ ])
+
+ return ' '.join(text)
+
+ def _compute_selected_groupby(self, this):
+ group_by_str = 'group_by_'
+ group_by_len = len(group_by_str)
+
+ fields = [
+ key[group_by_len:]
+ for key in self._columns.keys()
+ if key.startswith(group_by_str)
+ ]
+
+ groups = [
+ field
+ for field in fields
+ if getattr(this, '%s%s' % (group_by_str, field), False)
+ ]
+
+ if not groups:
+ raise osv.except_osv(_('Error'),
+ _("You have to specify a filter for your selection"))
+
+ return groups
+
+ def next_cb(self, cr, uid, ids, context=None):
+ """
+ Don't compute any thing
+ """
+ context = dict(context or {}, active_test=False)
+ this = self.browse(cr, uid, ids[0], context=context)
+ if this.current_line_id:
+ this.current_line_id.unlink()
+ return self._next_screen(this)
+
+ def _next_screen(self, this):
+ this.refresh()
+ values = {}
+ if this.line_ids:
+ # in this case, we try to find the next record.
+ current_line = this.line_ids[0]
+ current_partner_ids = literal_eval(current_line.aggr_ids)
+ values.update({
+ 'current_line_id': current_line.id,
+ 'partner_ids': [(6, 0, current_partner_ids)],
+ 'state': 'selection',
+ })
+ else:
+ values.update({
+ 'current_line_id': False,
+ 'partner_ids': [],
+ 'state': 'finished',
+ })
+
+ this.write(values)
+
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': this._name,
+ 'res_id': this.id,
+ 'view_mode': 'form',
+ 'target': 'new',
+ }
+
+ def _model_is_installed(self, cr, uid, model, context=None):
+ proxy = self.pool.get('ir.model')
+ domain = [('model', '=', model)]
+ return proxy.search_count(cr, uid, domain, context=context) > 0
+
+ def _partner_use_in(self, cr, uid, aggr_ids, models, context=None):
+ """
+ Check if there is no occurence of this group of partner in the selected
+ model
+ """
+ for model, field in models.iteritems():
+ proxy = self.pool.get(model)
+ domain = [(field, 'in', aggr_ids)]
+ if proxy.search_count(cr, uid, domain, context=context):
+ return True
+ return False
+
+ def compute_models(self, cr, uid, ids, context=None):
+ """
+ Compute the different models needed by the system if you want to exclude
+ some partners.
+ """
+ assert is_integer_list(ids)
+
+ this = self.browse(cr, uid, ids[0], context=context)
+
+ models = {}
+ if this.exclude_contact:
+ models['res.users'] = 'partner_id'
+
+ if self._model_is_installed(cr, uid, 'account.move.line', context=context) and this.exclude_journal_item:
+ models['account.move.line'] = 'partner_id'
+
+ return models
+
+ def _process_query(self, cr, uid, ids, query, context=None):
+ """
+ Execute the select request and write the result in this wizard
+ """
+ proxy = self.pool.get('base.partner.merge.line')
+ this = self.browse(cr, uid, ids[0], context=context)
+ models = self.compute_models(cr, uid, ids, context=context)
+ cr.execute(query)
+
+ counter = 0
+ for min_id, aggr_ids in cr.fetchall():
+ if models and self._partner_use_in(cr, uid, aggr_ids, models, context=context):
+ continue
+ values = {
+ 'wizard_id': this.id,
+ 'min_id': min_id,
+ 'aggr_ids': aggr_ids,
+ }
+
+ proxy.create(cr, uid, values, context=context)
+ counter += 1
+
+ values = {
+ 'state': 'selection',
+ 'number_group': counter,
+ }
+
+ this.write(values)
+
+ _logger.info("counter: %s", counter)
+
+ def start_process_cb(self, cr, uid, ids, context=None):
+ """
+ Start the process.
+ * Compute the selected groups (with duplication)
+ * If the user has selected the 'exclude_XXX' fields, avoid the partners.
+ """
+ assert is_integer_list(ids)
+
+ context = dict(context or {}, active_test=False)
+ this = self.browse(cr, uid, ids[0], context=context)
+ groups = self._compute_selected_groupby(this)
+ query = self._generate_query(groups, this.maximum_group)
+ self._process_query(cr, uid, ids, query, context=context)
+
+ return self._next_screen(this)
+
+ def automatic_process_cb(self, cr, uid, ids, context=None):
+ assert is_integer_list(ids)
+ this = self.browse(cr, uid, ids[0], context=context)
+ this.start_process_cb()
+ this.refresh()
+
+ for line in this.line_ids:
+ partner_ids = literal_eval(line.aggr_ids)
+ self._merge(cr, uid, partner_ids, context=context)
+ line.unlink()
+ cr.commit()
+
+ this.write({'state': 'finished'})
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': this._name,
+ 'res_id': this.id,
+ 'view_mode': 'form',
+ 'target': 'new',
+ }
+
+ def parent_migration_process_cb(self, cr, uid, ids, context=None):
+ assert is_integer_list(ids)
+
+ context = dict(context or {}, active_test=False)
+ this = self.browse(cr, uid, ids[0], context=context)
+
+ query = """
+ SELECT
+ min(p1.id),
+ array_agg(DISTINCT p1.id)
+ FROM
+ res_partner as p1
+ INNER join
+ res_partner as p2
+ ON
+ p1.email = p2.email AND
+ p1.name = p2.name AND
+ (p1.parent_id = p2.id OR p1.id = p2.parent_id)
+ WHERE
+ p2.id IS NOT NULL
+ GROUP BY
+ p1.email,
+ p1.name,
+ CASE WHEN p1.parent_id = p2.id THEN p2.id
+ ELSE p1.id
+ END
+ HAVING COUNT(*) >= 2
+ ORDER BY
+ min(p1.id)
+ """
+
+ self._process_query(cr, uid, ids, query, context=context)
+
+ for line in this.line_ids:
+ partner_ids = literal_eval(line.aggr_ids)
+ self._merge(cr, uid, partner_ids, context=context)
+ line.unlink()
+ cr.commit()
+
+ this.write({'state': 'finished'})
+
+ cr.execute("""
+ UPDATE
+ res_partner
+ SET
+ is_company = NULL,
+ parent_id = NULL
+ WHERE
+ parent_id = id
+ """)
+
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': this._name,
+ 'res_id': this.id,
+ 'view_mode': 'form',
+ 'target': 'new',
+ }
+
+ def update_all_process_cb(self, cr, uid, ids, context=None):
+ assert is_integer_list(ids)
+
+ # WITH RECURSIVE cycle(id, parent_id) AS (
+ # SELECT id, parent_id FROM res_partner
+ # UNION
+ # SELECT cycle.id, res_partner.parent_id
+ # FROM res_partner, cycle
+ # WHERE res_partner.id = cycle.parent_id AND
+ # cycle.id != cycle.parent_id
+ # )
+ # UPDATE res_partner
+ # SET parent_id = NULL
+ # WHERE id in (SELECT id FROM cycle WHERE id = parent_id);
+
+ this = self.browse(cr, uid, ids[0], context=context)
+
+ self.parent_migration_process_cb(cr, uid, ids, context=None)
+
+ list_merge = [
+ {'group_by_vat': True, 'group_by_email': True, 'group_by_name': True},
+ # {'group_by_name': True, 'group_by_is_company': True, 'group_by_parent_id': True},
+ # {'group_by_email': True, 'group_by_is_company': True, 'group_by_parent_id': True},
+ # {'group_by_name': True, 'group_by_vat': True, 'group_by_is_company': True, 'exclude_journal_item': True},
+ # {'group_by_email': True, 'group_by_vat': True, 'group_by_is_company': True, 'exclude_journal_item': True},
+ # {'group_by_email': True, 'group_by_is_company': True, 'exclude_contact': True, 'exclude_journal_item': True},
+ # {'group_by_name': True, 'group_by_is_company': True, 'exclude_contact': True, 'exclude_journal_item': True}
+ ]
+
+ for merge_value in list_merge:
+ id = self.create(cr, uid, merge_value, context=context)
+ self.automatic_process_cb(cr, uid, [id], context=context)
+
+ cr.execute("""
+ UPDATE
+ res_partner
+ SET
+ is_company = NULL
+ WHERE
+ parent_id IS NOT NULL AND
+ is_company IS NOT NULL
+ """)
+
+ # cr.execute("""
+ # UPDATE
+ # res_partner as p1
+ # SET
+ # is_company = NULL,
+ # parent_id = (
+ # SELECT p2.id
+ # FROM res_partner as p2
+ # WHERE p2.email = p1.email AND
+ # p2.parent_id != p2.id
+ # LIMIT 1
+ # )
+ # WHERE
+ # p1.parent_id = p1.id
+ # """)
+
+ return self._next_screen(this)
+
+ def merge_cb(self, cr, uid, ids, context=None):
+ assert is_integer_list(ids)
+
+ context = dict(context or {}, active_test=False)
+ this = self.browse(cr, uid, ids[0], context=context)
+
+ partner_ids = set(map(int, this.partner_ids))
+ if not partner_ids:
+ this.write({'state': 'finished'})
+ return {
+ 'type': 'ir.actions.act_window',
+ 'res_model': this._name,
+ 'res_id': this.id,
+ 'view_mode': 'form',
+ 'target': 'new',
+ }
+
+ self._merge(cr, uid, partner_ids, context=context)
+
+ this.current_line_id.unlink()
+
+ return self._next_screen(this)
+
+ def merge_multi(self, cr, uid, ids, context=None):
+
+ active_model = context.get('active_model')
+ if active_model != 'res.partner':
+ raise osv.except_osv(
+ _('Error'),
+ _('This wizard can only used with the Partners')
+ )
+
+ partner_ids = context.get('active_ids', [])
+
+ MINIMAL_NUMBER = 2
+ if len(partner_ids) < MINIMAL_NUMBER:
+ raise osv.except_osv(
+ _('Error'),
+ _("You can't use this wizard with only one Partner")
+ )
+
+ self._merge(cr, uid, partner_ids, context=context)
+
+ return True
+
+ def auto_set_parent_id(self, cr, uid, ids, context=None):
+ assert is_integer_list(ids)
+
+ # select partner who have one least invoice
+ partner_treated = ['@gmail.com']
+ cr.execute(""" SELECT p.id, p.email
+ FROM res_partner as p
+ LEFT JOIN account_invoice as a
+ ON p.id = a.partner_id AND a.state in ('open','paid')
+ WHERE p.grade_id is NOT NULL
+ GROUP BY p.id
+ ORDER BY COUNT(a.id) DESC
+ """)
+ re_email = re.compile(r".*@")
+ for id, email in cr.fetchall():
+ # check email domain
+ email = re_email.sub("@", email or "")
+ if not email or email in partner_treated:
+ continue
+ partner_treated.append(email)
+
+ # don't update the partners if they are more of one who have invoice
+ cr.execute(""" SELECT *
+ FROM res_partner as p
+ WHERE p.id != %s AND p.email LIKE '%%%s' AND
+ EXISTS (SELECT * FROM account_invoice as a WHERE p.id = a.partner_id AND a.state in ('open','paid'))
+ """ % (id, email))
+
+ if len(cr.fetchall()) > 1:
+ _logger.info("%s MORE OF ONE COMPANY", email)
+ continue
+
+ # to display changed values
+ cr.execute(""" SELECT id,email
+ FROM res_partner
+ WHERE parent_id != %s AND id != %s AND email LIKE '%%%s'
+ """ % (id, id, email))
+ _logger.info("%r", cr.fetchall())
+
+ # upgrade
+ cr.execute(""" UPDATE res_partner
+ SET parent_id = %s
+ WHERE id != %s AND email LIKE '%%%s'
+ """ % (id, id, email))
+ return False
diff --git a/addons/crm/base_partner_merge_view.xml b/addons/crm/base_partner_merge_view.xml
new file mode 100644
index 00000000000..74e7a72d7a8
--- /dev/null
+++ b/addons/crm/base_partner_merge_view.xml
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+ Deduplicate Contacts
+ base.partner.merge.automatic.wizard
+ form
+ form
+ new
+ {'active_test': False}
+
+
+
+
+
+ base.partner.merge.automatic.wizard.form
+ base.partner.merge.automatic.wizard
+
+
+
+
+
+
+ pool.get('base.partner.merge.automatic.wizard').merge_multi(cr, uid, None, context)
+ True
+
+ Automatic Merge
+
+ code
+ ir.actions.server
+
+
+
+
+ res.partner
+ Automatic Merge
+
+
+
+
+
+
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index 2361f12d61b..61e8c75cea8 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -1053,6 +1053,14 @@ class crm_lead(base_stage, format_address, osv.osv):
message = _("%s a call for %s.%s") % (prefix, phonecall.date, suffix)
return self.message_post(cr, uid, ids, body=message, context=context)
+ def log_meeting(self, cr, uid, ids, meeting_subject, meeting_date, duration, context=None):
+ if not duration:
+ duration = _('unknown')
+ else:
+ duration = str(duration)
+ message = _("Meeting scheduled at '%s' Subject: %s Duration: %s hour(s)") % (meeting_date, meeting_subject, duration)
+ return self.message_post(cr, uid, ids, body=message, context=context)
+
def onchange_state(self, cr, uid, ids, state_id, context=None):
if state_id:
country_id=self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index d94683f895f..8c22a0a2e1c 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -330,7 +330,7 @@
-
+
@@ -548,7 +548,7 @@
-
+
diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py
index 14b69ed0e11..c31907bebe2 100644
--- a/addons/crm/crm_meeting.py
+++ b/addons/crm/crm_meeting.py
@@ -34,6 +34,13 @@ class crm_meeting(osv.Model):
'opportunity_id': fields.many2one ('crm.lead', 'Opportunity', domain="[('type', '=', 'opportunity')]"),
}
+ def create(self, cr, uid, vals, context=None):
+ res = super(crm_meeting, self).create(cr, uid, vals, context=context)
+ obj = self.browse(cr, uid, res, context=context)
+ if obj.opportunity_id:
+ self.pool.get('crm.lead').log_meeting(cr, uid, [obj.opportunity_id.id], obj.name, obj.date, obj.duration, context=context)
+ return res
+
class calendar_attendee(osv.osv):
""" Calendar Attendee """
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml
index 3efb54f98b8..6c1b31180be 100644
--- a/addons/crm/crm_phonecall_view.xml
+++ b/addons/crm/crm_phonecall_view.xml
@@ -186,7 +186,7 @@
-
+
diff --git a/addons/crm/i18n/nl_BE.po b/addons/crm/i18n/nl_BE.po
index 697c7c4f083..a22d1f605a6 100644
--- a/addons/crm/i18n/nl_BE.po
+++ b/addons/crm/i18n/nl_BE.po
@@ -1,20 +1,20 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * crm
-# Els Van Vossel , 2012.
+# Els Van Vossel , 2012, 2013.
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
-"PO-Revision-Date: 2012-10-02 07:29+0000\n"
+"PO-Revision-Date: 2013-04-26 23:39+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: Els Van Vossel\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:09+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-27 05:44+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
"Language: nl\n"
#. module: crm
@@ -28,6 +28,8 @@ msgid ""
"Allows you to configure your incoming mail server, and create leads from "
"incoming emails."
msgstr ""
+"Hiermee kunt u de inkomende mailserver instellen en leads laten maken van "
+"binnenkomende e-mails."
#. module: crm
#: code:addons/crm/crm_lead.py:881
@@ -76,7 +78,7 @@ msgstr "Opportuniteiten kiezen"
#: model:res.groups,name:crm.group_fund_raising
#: field:sale.config.settings,group_fund_raising:0
msgid "Manage Fund Raising"
-msgstr ""
+msgstr "Fondsenwerving"
#. module: crm
#: view:crm.lead.report:0
@@ -96,7 +98,7 @@ msgstr "Fasenaam"
#: view:crm.lead.report:0
#: view:crm.phonecall.report:0
msgid "Salesperson"
-msgstr ""
+msgstr "Verkoper"
#. module: crm
#: model:ir.model,name:crm.model_crm_lead_report
@@ -113,18 +115,18 @@ msgstr "Dag"
#. module: crm
#: view:crm.lead:0
msgid "Company Name"
-msgstr ""
+msgstr "Bedrijfsnaam"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor6
msgid "Training"
-msgstr ""
+msgstr "Training"
#. module: crm
#: model:ir.actions.act_window,name:crm.crm_lead_categ_action
#: model:ir.ui.menu,name:crm.menu_crm_lead_categ
msgid "Sales Tags"
-msgstr ""
+msgstr "Verkooplabels"
#. module: crm
#: view:crm.lead.report:0
@@ -137,6 +139,7 @@ msgstr "Verw. sluiting"
#: help:crm.phonecall,message_unread:0
msgid "If checked new messages require your attention."
msgstr ""
+"Als dit is ingeschakeld, zijn er nieuwe berichten die uw aandacht vragen."
#. module: crm
#: help:crm.lead.report,creation_day:0
@@ -182,6 +185,8 @@ msgid ""
"Holds the Chatter summary (number of messages, ...). This summary is "
"directly in html format in order to be inserted in kanban views."
msgstr ""
+"Bevat de Chatsamenvatting (aantal berichten, ...). Deze samenvatting is in "
+"html-formaat, zodat ze in de kanbanweergave kan worden gebruikt."
#. module: crm
#: code:addons/crm/crm_lead.py:624
@@ -189,7 +194,7 @@ msgstr ""
#: code:addons/crm/crm_phonecall.py:280
#, python-format
msgid "Warning!"
-msgstr ""
+msgstr "Waarschuwing"
#. module: crm
#: view:crm.lead:0
@@ -238,7 +243,7 @@ msgstr ""
#. module: crm
#: model:ir.actions.server,name:crm.action_email_reminder_lead
msgid "Reminder to User"
-msgstr ""
+msgstr "Herinnering voor gebruiker"
#. module: crm
#: field:crm.segmentation,segmentation_line:0
@@ -266,7 +271,7 @@ msgstr "Leadanalyse"
#: code:addons/crm/crm_lead.py:1010
#, python-format
msgid "%s a call for the %s."
-msgstr ""
+msgstr "%s een gesprek voor %s."
#. module: crm
#: model:ir.actions.act_window,name:crm.crm_case_resource_type_act
@@ -328,6 +333,16 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik als u een nieuwe klantensegmentering wilt instellen.\n"
+"
\n"
+" Maak specifiieke categorieën en ken deze toe aan uw\n"
+" contactpersonen voor een betere interactie. Via\n"
+" segmentering kunt u categorieën toekennen aan "
+"contactpersonen\n"
+" volgens de door u ingestelde criteria.\n"
+"
\n"
+" "
#. module: crm
#: field:crm.opportunity2phonecall,contact_name:0
@@ -341,6 +356,7 @@ msgstr "Contactpersoon"
msgid ""
"When escalating to this team override the salesman with the team leader."
msgstr ""
+"Bij escaleren naar dit team, wordt de verkoper vervangen door de teamleider."
#. module: crm
#: model:process.transition,name:crm.process_transition_opportunitymeeting0
@@ -380,12 +396,25 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik om een opportuniteit voor deze klant te maken.\n"
+"
\n"
+" Met opportuniteiten kunt u uw verkooppijplijn en uw "
+"mogelijke verkopen opvolgen,\n"
+" voor een beter zicht op te verwachten inkomsten.\n"
+"
\n"
+" U kunt vergaderingen en telefoongesprekken plannen\n"
+" voor opportuniteiten. U kunt van een opportuniteit een "
+"offerte maken, documenten\n"
+" toevoegen, discussies volgen, en nog veel meer.\n"
+"
\n"
+" "
#. module: crm
#: model:crm.case.stage,name:crm.stage_lead7
#: view:crm.lead:0
msgid "Dead"
-msgstr ""
+msgstr "Dood"
#. module: crm
#: field:crm.case.section,message_unread:0
@@ -393,7 +422,7 @@ msgstr ""
#: field:crm.lead,message_unread:0
#: field:crm.phonecall,message_unread:0
msgid "Unread Messages"
-msgstr ""
+msgstr "Ongelezen berichten"
#. module: crm
#: view:crm.segmentation:0
@@ -407,7 +436,7 @@ msgstr "Segmentering"
#: selection:crm.lead2opportunity.partner.mass,action:0
#: selection:crm.partner.binding,action:0
msgid "Link to an existing customer"
-msgstr ""
+msgstr "Koppelen aan een bestaande relatie"
#. module: crm
#: field:crm.lead,write_date:0
@@ -425,8 +454,8 @@ msgid ""
"This percentage depicts the default/average probability of the Case for this "
"stage to be a success"
msgstr ""
-"Dit percentage drukt de standaard/gemiddelde slaagkans uit voor de zaak in "
-"deze fase."
+"Dit percentage drukt de standaard/gemiddelde slagingskans uit voor de zaak "
+"in deze fase."
#. module: crm
#: view:crm.lead:0
@@ -454,6 +483,7 @@ msgstr ""
#: view:crm.lead:0
msgid "Leads that are assigned to one of the sale teams I manage, or to me"
msgstr ""
+"Leads toegewezen aan een van de verkoopteams onder mijn beheer, of aan mij"
#. module: crm
#: field:crm.lead,partner_address_email:0
@@ -472,6 +502,15 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik als u een nieuw verkoopteam wilt maken.\n"
+"
\n"
+" Met verkoopteams organiseert u meerdere verkopers of "
+"afdelingen in\n"
+" aparte teams. Elk team werkt op zijn eigen\n"
+" opportuniteitenlijst.\n"
+"
\n"
+" "
#. module: crm
#: model:process.transition,note:crm.process_transition_opportunitymeeting0
@@ -485,7 +524,7 @@ msgstr "Gewone of telefonische vergadering over opportuniteit"
#: view:crm.phonecall.report:0
#: field:crm.phonecall.report,state:0
msgid "Status"
-msgstr ""
+msgstr "Status"
#. module: crm
#: view:crm.lead2opportunity.partner:0
@@ -495,7 +534,7 @@ msgstr "Opportuniteit maken"
#. module: crm
#: view:sale.config.settings:0
msgid "Configure"
-msgstr ""
+msgstr "Instellen"
#. module: crm
#: view:crm.lead:0
@@ -555,18 +594,26 @@ msgid ""
" If the call needs to be done then the status is set "
"to 'Not Held'."
msgstr ""
+"De status wordt op 'Uit te voeren' gezet als er een zaak wordt gemaakt. "
+" \n"
+"Als de zaak lopende is, wordt de status op 'Open' gezet. "
+" \n"
+"Als het gesprek is gevoerd, wordt de status op 'Uitgevoerd' gezet. "
+" \n"
+"Als het gesprek nog moet worden uitgevoerd, gaat de status naar 'Niet "
+"uitgevoerd'."
#. module: crm
#: field:crm.case.section,message_summary:0
#: field:crm.lead,message_summary:0
#: field:crm.phonecall,message_summary:0
msgid "Summary"
-msgstr "Samenvatting"
+msgstr "Overzicht"
#. module: crm
#: view:crm.merge.opportunity:0
msgid "Merge"
-msgstr ""
+msgstr "Samenvoegen"
#. module: crm
#: model:email.template,subject:crm.email_template_opportunity_mail
@@ -589,6 +636,8 @@ msgid ""
"Reminder on Lead: [[object.id ]] [[object.partner_id and 'of ' "
"+object.partner_id.name or '']]"
msgstr ""
+"Herinnering voor Lead: [[object.id ]] [[object.partner_id and 'van ' "
+"+object.partner_id.name or '']]"
#. module: crm
#: view:crm.segmentation:0
@@ -608,7 +657,7 @@ msgstr "De code van het verkoopteam moet uniek zijn"
#. module: crm
#: help:crm.lead,email_from:0
msgid "Email address of the contact"
-msgstr ""
+msgstr "E-mailadres van de contactpersoon"
#. module: crm
#: selection:crm.case.stage,state:0
@@ -629,6 +678,13 @@ msgid ""
" \n"
" "
msgstr ""
+"
\n"
+" Klik als u een nieuwe categorie wilt maken.\n"
+"
\n"
+" Maak specifieke telefooncategorieën om beter de gesprekstypen\n"
+" op te volgen in het systeem.\n"
+"
\n"
+" "
#. module: crm
#: help:crm.case.section,reply_to:0
@@ -734,12 +790,12 @@ msgstr "Televisie"
#. module: crm
#: model:ir.actions.act_window,name:crm.action_crm_send_mass_convert
msgid "Convert to opportunities"
-msgstr ""
+msgstr "Omzetten naar opportuniteit"
#. module: crm
#: model:ir.model,name:crm.model_sale_config_settings
msgid "sale.config.settings"
-msgstr ""
+msgstr "sale.config.settings"
#. module: crm
#: view:crm.segmentation:0
@@ -749,7 +805,7 @@ msgstr "Verwerking stoppen"
#. module: crm
#: field:crm.case.section,alias_id:0
msgid "Alias"
-msgstr ""
+msgstr "Alias"
#. module: crm
#: view:crm.phonecall:0
@@ -761,6 +817,8 @@ msgstr "Telefoongesprekken zoeken"
msgid ""
"Leads/Opportunities that are assigned to one of the sale teams I manage"
msgstr ""
+"Leads/Opportuniteiten die zijn toegewezen aan een van de verkoopteams onder "
+"mijn beheer"
#. module: crm
#: field:calendar.attendee,categ_id:0
@@ -781,7 +839,7 @@ msgstr "Van %s : %s"
#. module: crm
#: view:crm.lead2opportunity.partner.mass:0
msgid "Convert to Opportunities"
-msgstr ""
+msgstr "Omzetten naar opportuniteit"
#. module: crm
#: view:crm.lead2opportunity.partner:0
@@ -790,7 +848,7 @@ msgstr ""
#: view:crm.opportunity2phonecall:0
#: view:crm.phonecall2phonecall:0
msgid "or"
-msgstr ""
+msgstr "of"
#. module: crm
#: field:crm.lead.report,create_date:0
@@ -809,6 +867,8 @@ msgid ""
"Link between stages and sales teams. When set, this limitate the current "
"stage to the selected sales teams."
msgstr ""
+"Koppeling tussen fasen en verkoopteams. Deze maken de huidige fase enkel "
+"toegankelijk voor de gekozen verkoopteams."
#. module: crm
#: view:crm.case.stage:0
@@ -847,7 +907,7 @@ msgstr "Relatiecategorie"
#. module: crm
#: field:crm.lead,probability:0
msgid "Success Rate (%)"
-msgstr ""
+msgstr "Slagingskans (%)"
#. module: crm
#: field:crm.segmentation,sales_purchase_active:0
@@ -889,7 +949,7 @@ msgstr "Maart"
#. module: crm
#: view:crm.lead:0
msgid "Send Email"
-msgstr ""
+msgstr "E-mail verzenden"
#. module: crm
#: code:addons/crm/wizard/crm_lead_to_opportunity.py:89
@@ -919,6 +979,8 @@ msgid ""
"Opportunities that are assigned to either me or one of the sale teams I "
"manage"
msgstr ""
+"Opportuniteiten die zijn toegewezen aan een van de verkoopteams onder mijn "
+"beheer of aan mij"
#. module: crm
#: help:crm.case.section,resource_calendar_id:0
@@ -984,6 +1046,9 @@ msgid ""
"Allows you to track your customers/suppliers claims and grievances.\n"
" This installs the module crm_claim."
msgstr ""
+"Hiermee kunt u klachten en problemen van klanten/ aan leveranciers "
+"opvolgen.\n"
+" Hiermee installeert u de module crm_claim."
#. module: crm
#: model:crm.case.stage,name:crm.stage_lead6
@@ -1058,7 +1123,7 @@ msgstr "Fase"
#. module: crm
#: view:crm.phonecall.report:0
msgid "Phone Calls that are assigned to me"
-msgstr ""
+msgstr "Aan mij toegewezen telefoongesprekken"
#. module: crm
#: field:crm.lead,user_login:0
@@ -1086,11 +1151,13 @@ msgid ""
"Allows you to communicate with Customer, process Customer query, and "
"provide better help and support. This installs the module crm_helpdesk."
msgstr ""
+"Hiermee kunt u met de klant communiceren, vragen beantwoorden en betere "
+"ondersteuning verlenen. Hiermee installeert u de module crm_helpdesk."
#. module: crm
#: view:crm.lead:0
msgid "Delete"
-msgstr ""
+msgstr "Verwijderen"
#. module: crm
#: model:mail.message.subtype,description:crm.mt_lead_create
@@ -1100,7 +1167,7 @@ msgstr ""
#. module: crm
#: view:crm.lead:0
msgid "í"
-msgstr ""
+msgstr "í"
#. module: crm
#: selection:crm.lead.report,creation_month:0
@@ -1141,12 +1208,12 @@ msgstr ""
#. module: crm
#: view:crm.lead:0
msgid "oe_kanban_text_red"
-msgstr ""
+msgstr "oe_kanban_text_red"
#. module: crm
#: model:ir.ui.menu,name:crm.menu_crm_payment_mode_act
msgid "Payment Modes"
-msgstr ""
+msgstr "Betalingswijzen"
#. module: crm
#: field:crm.lead.report,opening_date:0
@@ -1193,6 +1260,9 @@ msgid ""
"This field is used to distinguish stages related to Leads from stages "
"related to Opportunities, or to specify stages available for both types."
msgstr ""
+"Dit veld dient om een onderscheid te maken tussen de fasen voor leads en die "
+"voor opportuniteiten, of om fasen in te stellen die voor beide typen van "
+"toepassing zijn."
#. module: crm
#: model:mail.message.subtype,name:crm.mt_lead_create
@@ -1234,7 +1304,7 @@ msgstr "onbekend"
#: field:crm.lead,message_is_follower:0
#: field:crm.phonecall,message_is_follower:0
msgid "Is a Follower"
-msgstr ""
+msgstr "Is een volger"
#. module: crm
#: field:crm.opportunity2phonecall,date:0
@@ -1247,7 +1317,7 @@ msgstr "Datum"
#. module: crm
#: model:crm.case.section,name:crm.crm_case_section_4
msgid "Online Support"
-msgstr ""
+msgstr "Onlineondersteuning"
#. module: crm
#: view:crm.lead.report:0
@@ -1273,6 +1343,10 @@ msgid ""
"set to 'Done'. If the case needs to be reviewed then the Status is set to "
"'Pending'."
msgstr ""
+"De status wordt op 'Voorlopig' gezet als de zaak wordt gemaakt. Als de zaak "
+"lopende is, wordt de status op 'Open' gezet. Als de zaak is behandeld, wordt "
+"de status op 'Gereed' gezet. Als de zaak moet worden bekeken, wordt de "
+"status op 'Wachtend' gezet."
#. module: crm
#: model:crm.case.section,name:crm.crm_case_section_1
@@ -1306,7 +1380,7 @@ msgstr "Segmenteringsomschrijving"
#. module: crm
#: view:crm.lead:0
msgid "Lead Description"
-msgstr ""
+msgstr "Leadomschrijving"
#. module: crm
#: code:addons/crm/crm_lead.py:565
@@ -1317,7 +1391,7 @@ msgstr "Samengevoegde opportuniteiten"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor7
msgid "Consulting"
-msgstr ""
+msgstr "Consulting"
#. module: crm
#: field:crm.case.section,code:0
@@ -1327,7 +1401,7 @@ msgstr "Code"
#. module: crm
#: view:sale.config.settings:0
msgid "Features"
-msgstr ""
+msgstr "Opties"
#. module: crm
#: field:crm.case.section,child_ids:0
@@ -1342,7 +1416,7 @@ msgstr "Telefoongesprekken in status Uit te voeren en Open."
#. module: crm
#: field:crm.lead2opportunity.partner.mass,user_ids:0
msgid "Salesmen"
-msgstr ""
+msgstr "Verkopers"
#. module: crm
#: view:crm.lead:0
@@ -1362,12 +1436,12 @@ msgstr "Annuleren"
#. module: crm
#: view:crm.lead:0
msgid "Opportunities Assigned to Me or My Team(s)"
-msgstr ""
+msgstr "Opportuniteiten voor mij of mijn team(s)"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor4
msgid "Information"
-msgstr ""
+msgstr "Informatie"
#. module: crm
#: view:crm.lead.report:0
@@ -1389,7 +1463,7 @@ msgstr ""
#: field:crm.lead2opportunity.partner.mass,action:0
#: field:crm.partner.binding,action:0
msgid "Related Customer"
-msgstr ""
+msgstr "Gekoppelde klant"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor8
@@ -1406,12 +1480,12 @@ msgstr "Lead/opportuniteit"
#: model:ir.actions.act_window,name:crm.action_merge_opportunities
#: model:ir.actions.act_window,name:crm.merge_opportunity_act
msgid "Merge leads/opportunities"
-msgstr ""
+msgstr "Leads/opportuniteiten samenvoegen"
#. module: crm
#: help:crm.case.stage,sequence:0
msgid "Used to order stages. Lower is better."
-msgstr ""
+msgstr "WOrdt gebruikt om fasen te rangschikken. Lager is beter."
#. module: crm
#: model:ir.actions.act_window,name:crm.crm_phonecall_categ_action
@@ -1426,7 +1500,7 @@ msgstr "Leads/opportuniteiten in status Open."
#. module: crm
#: model:ir.model,name:crm.model_res_users
msgid "Users"
-msgstr ""
+msgstr "Gebruikers"
#. module: crm
#: model:mail.message.subtype,name:crm.mt_lead_stage
@@ -1484,7 +1558,7 @@ msgstr "Naam"
#. module: crm
#: view:crm.lead.report:0
msgid "Leads/Opportunities that are assigned to me"
-msgstr ""
+msgstr "Leads/opportuniteiten die aan mij zijn toegekend"
#. module: crm
#: field:crm.lead.report,date_closed:0
@@ -1502,12 +1576,12 @@ msgstr "Mijn zaken"
#: help:crm.lead,message_ids:0
#: help:crm.phonecall,message_ids:0
msgid "Messages and communication history"
-msgstr ""
+msgstr "Berichten en communicatiehistoriek"
#. module: crm
#: view:crm.lead:0
msgid "Show Countries"
-msgstr ""
+msgstr "Landen tonen"
#. module: crm
#: view:crm.lead:0
@@ -1531,7 +1605,7 @@ msgstr "Prospect omzetten naar relatie"
#. module: crm
#: model:ir.model,name:crm.model_crm_payment_mode
msgid "CRM Payment Mode"
-msgstr ""
+msgstr "CRM betalingswijze"
#. module: crm
#: view:crm.lead.report:0
@@ -1554,7 +1628,7 @@ msgstr "Groeperen op..."
#. module: crm
#: view:crm.merge.opportunity:0
msgid "Merge Leads/Opportunities"
-msgstr ""
+msgstr "Leads/opportuniteiten samenvoegen"
#. module: crm
#: field:crm.case.section,parent_id:0
@@ -1566,7 +1640,7 @@ msgstr "Hoofdteam"
#: selection:crm.lead2opportunity.partner.mass,action:0
#: selection:crm.partner.binding,action:0
msgid "Do not link to a customer"
-msgstr ""
+msgstr "Geen relatie koppelen"
#. module: crm
#: field:crm.lead,date_action:0
@@ -1580,11 +1654,14 @@ msgid ""
"stage. For example, if a stage is related to the status 'Close', when your "
"document reaches this stage, it is automatically closed."
msgstr ""
+"De status van uw document wordt automatisch gewijzigd in de functie van de "
+"gekozen fase. Als een fase gekoppeld is aan de status 'Gesloten', dan wordt "
+"het document automatisch gesloten als het in deze status komt."
#. module: crm
#: view:crm.lead2opportunity.partner.mass:0
msgid "Assign opportunities to"
-msgstr ""
+msgstr "Opportuniteiten toewijzen aan"
#. module: crm
#: model:crm.case.categ,name:crm.categ_phone1
@@ -1600,12 +1677,12 @@ msgstr "Maand van gesprek"
#: code:addons/crm/crm_phonecall.py:290
#, python-format
msgid "Partner has been created."
-msgstr ""
+msgstr "Relatie is gemaakt."
#. module: crm
#: field:sale.config.settings,module_crm_claim:0
msgid "Manage Customer Claims"
-msgstr ""
+msgstr "Klachten van klanten opvolgen"
#. module: crm
#: model:ir.actions.act_window,help:crm.action_report_crm_lead
@@ -1618,7 +1695,7 @@ msgstr ""
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor3
msgid "Services"
-msgstr ""
+msgstr "Diensten"
#. module: crm
#: selection:crm.lead,priority:0
@@ -1657,7 +1734,7 @@ msgstr "Antwoord aan"
#. module: crm
#: view:crm.lead:0
msgid "Display"
-msgstr ""
+msgstr "Weergeven"
#. module: crm
#: view:board.board:0
@@ -1693,12 +1770,12 @@ msgstr "Extra informatie"
#. module: crm
#: view:crm.lead:0
msgid "Fund Raising"
-msgstr ""
+msgstr "Fondsenwerving"
#. module: crm
#: view:crm.lead:0
msgid "Edit..."
-msgstr ""
+msgstr "Bewerken…"
#. module: crm
#: model:crm.case.resource.type,name:crm.type_lead5
@@ -1730,13 +1807,15 @@ msgstr "Lead naar opportuniteit / relatie"
#: help:crm.lead,partner_id:0
msgid "Linked partner (optional). Usually created when converting the lead."
msgstr ""
+"Gekoppelde relatie (optioneel). Doorgaans gemaakt bij het omzetten van de "
+"lead."
#. module: crm
#: field:crm.lead,payment_mode:0
#: view:crm.payment.mode:0
#: model:ir.actions.act_window,name:crm.action_crm_payment_mode
msgid "Payment Mode"
-msgstr ""
+msgstr "Betalingswijze"
#. module: crm
#: model:ir.model,name:crm.model_crm_lead2opportunity_partner_mass
@@ -1746,19 +1825,19 @@ msgstr "Vele leads naar opportuniteit / relatie"
#. module: crm
#: view:sale.config.settings:0
msgid "On Mail Server"
-msgstr ""
+msgstr "Op mailserver"
#. module: crm
#: model:ir.actions.act_window,name:crm.open_board_statistical_dash
#: model:ir.ui.menu,name:crm.menu_board_statistics_dash
msgid "CRM"
-msgstr ""
+msgstr "CRM"
#. module: crm
#: model:ir.actions.act_window,name:crm.crm_segmentation_tree-act
#: model:ir.ui.menu,name:crm.menu_crm_segmentation-act
msgid "Contacts Segmentation"
-msgstr ""
+msgstr "Contactpersoonsegmentering"
#. module: crm
#: model:process.node,note:crm.process_node_meeting0
@@ -1773,7 +1852,7 @@ msgstr "Televerkoop"
#. module: crm
#: view:crm.lead:0
msgid "Leads Assigned to Me or My Team(s)"
-msgstr ""
+msgstr "Leads voor mij of mijn team(s)"
#. module: crm
#: model:ir.model,name:crm.model_crm_segmentation_line
@@ -1817,7 +1896,7 @@ msgstr "Lead / klant"
#. module: crm
#: model:crm.case.section,name:crm.crm_case_section_2
msgid "Support Department"
-msgstr ""
+msgstr "Supportafdeling"
#. module: crm
#: view:crm.lead.report:0
@@ -1881,13 +1960,13 @@ msgstr ""
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor5
msgid "Design"
-msgstr ""
+msgstr "Ontwerp"
#. module: crm
#: selection:crm.lead2opportunity.partner,name:0
#: selection:crm.lead2opportunity.partner.mass,name:0
msgid "Merge with existing opportunities"
-msgstr ""
+msgstr "Samenvoegen met bestaande opportuniteiten"
#. module: crm
#: view:crm.phonecall.report:0
@@ -1912,6 +1991,8 @@ msgid ""
"The name of the future partner company that will be created while converting "
"the lead into opportunity"
msgstr ""
+"De naam van de toekomstige relatie die zal worden gemaakt als van de lead "
+"een opportuniteit wordt gemaakt."
#. module: crm
#: field:crm.opportunity2phonecall,note:0
@@ -1945,7 +2026,7 @@ msgstr "Openstaande opportuniteiten"
#. module: crm
#: model:crm.case.resource.type,name:crm.type_lead2
msgid "Email Campaign - Services"
-msgstr ""
+msgstr "E-mailcampagne - Diensten"
#. module: crm
#: selection:crm.case.stage,state:0
@@ -2018,7 +2099,7 @@ msgstr ""
#: selection:crm.lead2opportunity.partner.mass,action:0
#: selection:crm.partner.binding,action:0
msgid "Create a new customer"
-msgstr ""
+msgstr "Een nieuwe klant maken"
#. module: crm
#: field:crm.lead.report,deadline_day:0
@@ -2028,7 +2109,7 @@ msgstr "Verw. sluiting"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor2
msgid "Software"
-msgstr ""
+msgstr "Software"
#. module: crm
#: field:crm.case.section,change_responsible:0
@@ -2063,12 +2144,12 @@ msgstr "Plaats"
#. module: crm
#: selection:crm.case.stage,type:0
msgid "Both"
-msgstr ""
+msgstr "Beide"
#. module: crm
#: view:crm.phonecall:0
msgid "Call Done"
-msgstr ""
+msgstr "Gesprek uitgevoerd"
#. module: crm
#: view:crm.phonecall:0
@@ -2079,12 +2160,12 @@ msgstr "Verantwoordelijke"
#. module: crm
#: model:crm.case.section,name:crm.crm_case_section_3
msgid "Direct Marketing"
-msgstr ""
+msgstr "Direct Marketing"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor1
msgid "Product"
-msgstr ""
+msgstr "Product"
#. module: crm
#: field:crm.lead.report,creation_year:0
@@ -2094,7 +2175,7 @@ msgstr "Creatiejaar"
#. module: crm
#: view:crm.lead2opportunity.partner.mass:0
msgid "Conversion Options"
-msgstr ""
+msgstr "Conversieopties"
#. module: crm
#: view:crm.case.section:0
@@ -2106,7 +2187,7 @@ msgstr ""
#. module: crm
#: view:crm.lead:0
msgid "Address"
-msgstr ""
+msgstr "Adres"
#. module: crm
#: help:crm.case.section,alias_id:0
@@ -2114,6 +2195,8 @@ msgid ""
"The email address associated with this team. New emails received will "
"automatically create new leads assigned to the team."
msgstr ""
+"Het e-mailadres van het team. Nieuwe e-mails worden automatisch als lead "
+"gemaakt en toegekend aan dit team."
#. module: crm
#: view:crm.lead:0
@@ -2172,7 +2255,7 @@ msgstr "Verder verwerken"
#: selection:crm.lead2opportunity.partner.mass,name:0
#: model:ir.actions.act_window,name:crm.action_crm_lead2opportunity_partner
msgid "Convert to opportunity"
-msgstr ""
+msgstr "Omzetten naar opportuniteit"
#. module: crm
#: field:crm.opportunity2phonecall,user_id:0
@@ -2214,6 +2297,8 @@ msgid ""
"This stage is not visible, for example in status bar or kanban view, when "
"there are no records in that stage to display."
msgstr ""
+"Deze fase is niet zichtbaar, vb. in statusbalk of kanbanweergave, als er "
+"zich geen records in deze fase bevinden."
#. module: crm
#: field:crm.lead.report,nbr:0
@@ -2229,12 +2314,12 @@ msgstr "Verkoopteam aan wie de zaak toebehoort"
#. module: crm
#: model:crm.case.resource.type,name:crm.type_lead6
msgid "Banner Ads"
-msgstr ""
+msgstr "Kopadvertenties"
#. module: crm
#: field:crm.merge.opportunity,opportunity_ids:0
msgid "Leads/Opportunities"
-msgstr ""
+msgstr "Leads/opportuniteiten"
#. module: crm
#: field:crm.lead,fax:0
@@ -2279,17 +2364,17 @@ msgstr "Objectnaam"
#. module: crm
#: view:crm.phonecall:0
msgid "Phone Calls Assigned to Me or My Team(s)"
-msgstr ""
+msgstr "Telefoongesprekken voor mij of mijn team(s)"
#. module: crm
#: view:crm.lead:0
msgid "Reset"
-msgstr ""
+msgstr "Herstellen"
#. module: crm
#: view:sale.config.settings:0
msgid "After-Sale Services"
-msgstr ""
+msgstr "Klantenservice"
#. module: crm
#: field:crm.case.section,message_ids:0
@@ -2344,7 +2429,7 @@ msgstr ""
#. module: crm
#: field:crm.case.stage,state:0
msgid "Related Status"
-msgstr ""
+msgstr "Gekoppelde status"
#. module: crm
#: field:crm.phonecall,name:0
@@ -2365,7 +2450,7 @@ msgstr "Een gesprek plannen/noteren"
#. module: crm
#: view:crm.merge.opportunity:0
msgid "Select Leads/Opportunities"
-msgstr ""
+msgstr "Leads/opportuniteiten kiezen"
#. module: crm
#: selection:crm.phonecall,state:0
@@ -2390,7 +2475,7 @@ msgstr "Bevestigen"
#. module: crm
#: view:crm.lead:0
msgid "Unread messages"
-msgstr ""
+msgstr "Ongelezen berichten"
#. module: crm
#: field:crm.phonecall.report,section_id:0
@@ -2407,7 +2492,7 @@ msgstr "Optionele expressie"
#: field:crm.lead,message_follower_ids:0
#: field:crm.phonecall,message_follower_ids:0
msgid "Followers"
-msgstr ""
+msgstr "Volgers"
#. module: crm
#: model:ir.actions.act_window,help:crm.crm_case_category_act_leads_all
@@ -2430,7 +2515,7 @@ msgstr ""
#. module: crm
#: field:sale.config.settings,fetchmail_lead:0
msgid "Create leads from incoming mails"
-msgstr ""
+msgstr "Leads maken van binnenkomende mails"
#. module: crm
#: view:crm.lead:0
@@ -2481,7 +2566,7 @@ msgstr "Opportuniteiten maken van leads"
#. module: crm
#: model:crm.case.resource.type,name:crm.type_lead3
msgid "Email Campaign - Products"
-msgstr ""
+msgstr "E-mailcampagne - Producten"
#. module: crm
#: model:ir.actions.act_window,help:crm.crm_case_categ_phone_incoming0
@@ -2509,7 +2594,7 @@ msgstr "Allereerste contact met een nieuwe prospect"
#. module: crm
#: view:res.partner:0
msgid "Calls"
-msgstr ""
+msgstr "Gesprekken"
#. module: crm
#: field:crm.case.stage,on_change:0
@@ -2519,7 +2604,7 @@ msgstr "Kans automatisch wijzigen"
#. module: crm
#: view:crm.phonecall.report:0
msgid "My Phone Calls"
-msgstr ""
+msgstr "Mijn telefoongesprekken"
#. module: crm
#: model:crm.case.stage,name:crm.stage_lead3
@@ -2530,7 +2615,7 @@ msgstr "Kwalificatie"
#: field:crm.lead2opportunity.partner,name:0
#: field:crm.lead2opportunity.partner.mass,name:0
msgid "Conversion Action"
-msgstr ""
+msgstr "Conversieactie"
#. module: crm
#: model:ir.actions.act_window,help:crm.crm_lead_categ_action
@@ -2606,7 +2691,7 @@ msgstr "Verw. sluitingsjaar"
#. module: crm
#: model:ir.actions.client,name:crm.action_client_crm_menu
msgid "Open Sale Menu"
-msgstr ""
+msgstr "Het verkoopmenu openen"
#. module: crm
#: field:crm.lead,date_open:0
@@ -2629,12 +2714,12 @@ msgstr "Een gesprek plannen/noteren"
#. module: crm
#: field:crm.lead,planned_cost:0
msgid "Planned Costs"
-msgstr ""
+msgstr "Geplande kosten"
#. module: crm
#: help:crm.lead,date_deadline:0
msgid "Estimate of the date on which the opportunity will be won."
-msgstr ""
+msgstr "Verwachte datum waarop de opportuniteit kan worden gerealiseerd."
#. module: crm
#: help:crm.lead,email_cc:0
@@ -2698,7 +2783,7 @@ msgstr "Straat 2"
#. module: crm
#: field:sale.config.settings,module_crm_helpdesk:0
msgid "Manage Helpdesk and Support"
-msgstr ""
+msgstr "Helpdesk en ondersteuning"
#. module: crm
#: field:crm.lead.report,delay_open:0
@@ -2785,7 +2870,7 @@ msgstr "Gesprek noteren"
#. module: crm
#: help:sale.config.settings,group_fund_raising:0
msgid "Allows you to trace and manage your activities for fund raising."
-msgstr ""
+msgstr "Hiermee kunt u activiteiten voor fondsenwerving beheren"
#. module: crm
#: field:crm.meeting,phonecall_id:0
@@ -2797,6 +2882,8 @@ msgstr "Telefoongesprek"
#: view:crm.phonecall.report:0
msgid "Phone calls that are assigned to one of the sale teams I manage"
msgstr ""
+"Telefoongesprekken die zijn toegewezen aan een van de verkoopteams onder "
+"mijn beheer"
#. module: crm
#: view:crm.lead:0
@@ -2806,7 +2893,7 @@ msgstr "Creatiedatum"
#. module: crm
#: view:crm.lead:0
msgid "at"
-msgstr ""
+msgstr "bij"
#. module: crm
#: model:crm.case.stage,name:crm.stage_lead1
@@ -2875,7 +2962,7 @@ msgstr ""
#. module: crm
#: view:crm.lead:0
msgid "Internal Notes"
-msgstr ""
+msgstr "Interne notities"
#. module: crm
#: view:crm.lead:0
@@ -2895,7 +2982,7 @@ msgstr "Straat"
#. module: crm
#: field:crm.lead,referred:0
msgid "Referred By"
-msgstr ""
+msgstr "Doorverwezen via"
#. module: crm
#: view:crm.phonecall:0
@@ -2940,6 +3027,7 @@ msgstr "Verloren"
#, python-format
msgid "Closed/Cancelled leads cannot be converted into opportunities."
msgstr ""
+"Gesloten/geannuleerde leads kunnen niet in een opportuniteit worden omgezet"
#. module: crm
#: view:crm.lead:0
@@ -4199,3 +4287,6 @@ msgstr ""
#~ msgid "Recurrent"
#~ msgstr "Recurrent"
+
+#~ msgid "Conditions on Case Fields"
+#~ msgstr "Voorwaardevelden"
diff --git a/addons/crm/report/crm_lead_report_view.xml b/addons/crm/report/crm_lead_report_view.xml
index 1009e1c376d..759063b3c1d 100644
--- a/addons/crm/report/crm_lead_report_view.xml
+++ b/addons/crm/report/crm_lead_report_view.xml
@@ -82,7 +82,7 @@
groups="base.group_multi_salesteams"/>
-
+
diff --git a/addons/crm/report/crm_phonecall_report_view.xml b/addons/crm/report/crm_phonecall_report_view.xml
index c27d876ddd7..070d574e0cd 100644
--- a/addons/crm/report/crm_phonecall_report_view.xml
+++ b/addons/crm/report/crm_phonecall_report_view.xml
@@ -64,7 +64,7 @@
groups="base.group_multi_salesteams"/>
-
+
diff --git a/addons/crm/security/ir.model.access.csv b/addons/crm/security/ir.model.access.csv
index 52648c8e347..b09c201df2b 100644
--- a/addons/crm/security/ir.model.access.csv
+++ b/addons/crm/security/ir.model.access.csv
@@ -35,3 +35,5 @@ access_crm_lead_partner_manager,crm.lead.partner.manager,model_crm_lead,base.gro
access_crm_phonecall_partner_manager,crm.phonecall.partner.manager,model_crm_phonecall,base.group_partner_manager,1,1,1,1
access_crm_payment_mode_user,crm.payment.mode,model_crm_payment_mode,base.group_sale_salesman,1,0,0,0
access_crm_payment_mode,crm.payment.mode,model_crm_payment_mode,base.group_sale_manager,1,1,1,1
+access_base_partner_merge_line_manager,base_partner_merge_line.manager,model_base_partner_merge_line,base.group_system,1,1,1,1
+access_base_partner_merge_manager,base_partner_merge.manager,model_base_partner_merge_automatic_wizard,base.group_system,1,1,1,1
diff --git a/addons/crm/test/crm_lead_message.yml b/addons/crm/test/crm_lead_message.yml
index 221a4ab634f..0f7d4655398 100644
--- a/addons/crm/test/crm_lead_message.yml
+++ b/addons/crm/test/crm_lead_message.yml
@@ -4,8 +4,7 @@
Mail script will fetch his request from mail server. Then I process that mail after read EML file.
-
!python {model: mail.thread}: |
- from openerp import addons
- request_file = open(addons.get_module_resource('crm','test', 'customer_request.eml'),'rb')
+ request_file = open(openerp.modules.module.get_module_resource('crm','test', 'customer_request.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'crm.lead', request_message)
-
diff --git a/addons/crm/validate_email.py b/addons/crm/validate_email.py
new file mode 100644
index 00000000000..38de5743fca
--- /dev/null
+++ b/addons/crm/validate_email.py
@@ -0,0 +1,123 @@
+# RFC 2822 - style email validation for Python
+# (c) 2012 Syrus Akbary
+# Extended from (c) 2011 Noel Bush
+# for support of mx and user check
+# This code is made available to you under the GNU LGPL v3.
+#
+# This module provides a single method, valid_email_address(),
+# which returns True or False to indicate whether a given address
+# is valid according to the 'addr-spec' part of the specification
+# given in RFC 2822. Ideally, we would like to find this
+# in some other library, already thoroughly tested and well-
+# maintained. The standard Python library email.utils
+# contains a parse_addr() function, but it is not sufficient
+# to detect many malformed addresses.
+#
+# This implementation aims to be faithful to the RFC, with the
+# exception of a circular definition (see comments below), and
+# with the omission of the pattern components marked as "obsolete".
+
+import re
+import smtplib
+import socket
+
+try:
+ import DNS
+ ServerError = DNS.ServerError
+except:
+ DNS = None
+ class ServerError(Exception): pass
+# All we are really doing is comparing the input string to one
+# gigantic regular expression. But building that regexp, and
+# ensuring its correctness, is made much easier by assembling it
+# from the "tokens" defined by the RFC. Each of these tokens is
+# tested in the accompanying unit test file.
+#
+# The section of RFC 2822 from which each pattern component is
+# derived is given in an accompanying comment.
+#
+# (To make things simple, every string below is given as 'raw',
+# even when it's not strictly necessary. This way we don't forget
+# when it is necessary.)
+#
+WSP = r'[ \t]' # see 2.2.2. Structured Header Field Bodies
+CRLF = r'(?:\r\n)' # see 2.2.3. Long Header Fields
+NO_WS_CTL = r'\x01-\x08\x0b\x0c\x0f-\x1f\x7f' # see 3.2.1. Primitive Tokens
+QUOTED_PAIR = r'(?:\\.)' # see 3.2.2. Quoted characters
+FWS = r'(?:(?:' + WSP + r'*' + CRLF + r')?' + \
+ WSP + r'+)' # see 3.2.3. Folding white space and comments
+CTEXT = r'[' + NO_WS_CTL + \
+ r'\x21-\x27\x2a-\x5b\x5d-\x7e]' # see 3.2.3
+CCONTENT = r'(?:' + CTEXT + r'|' + \
+ QUOTED_PAIR + r')' # see 3.2.3 (NB: The RFC includes COMMENT here
+ # as well, but that would be circular.)
+COMMENT = r'\((?:' + FWS + r'?' + CCONTENT + \
+ r')*' + FWS + r'?\)' # see 3.2.3
+CFWS = r'(?:' + FWS + r'?' + COMMENT + ')*(?:' + \
+ FWS + '?' + COMMENT + '|' + FWS + ')' # see 3.2.3
+ATEXT = r'[\w!#$%&\'\*\+\-/=\?\^`\{\|\}~]' # see 3.2.4. Atom
+ATOM = CFWS + r'?' + ATEXT + r'+' + CFWS + r'?' # see 3.2.4
+DOT_ATOM_TEXT = ATEXT + r'+(?:\.' + ATEXT + r'+)*' # see 3.2.4
+DOT_ATOM = CFWS + r'?' + DOT_ATOM_TEXT + CFWS + r'?' # see 3.2.4
+QTEXT = r'[' + NO_WS_CTL + \
+ r'\x21\x23-\x5b\x5d-\x7e]' # see 3.2.5. Quoted strings
+QCONTENT = r'(?:' + QTEXT + r'|' + \
+ QUOTED_PAIR + r')' # see 3.2.5
+QUOTED_STRING = CFWS + r'?' + r'"(?:' + FWS + \
+ r'?' + QCONTENT + r')*' + FWS + \
+ r'?' + r'"' + CFWS + r'?'
+LOCAL_PART = r'(?:' + DOT_ATOM + r'|' + \
+ QUOTED_STRING + r')' # see 3.4.1. Addr-spec specification
+DTEXT = r'[' + NO_WS_CTL + r'\x21-\x5a\x5e-\x7e]' # see 3.4.1
+DCONTENT = r'(?:' + DTEXT + r'|' + \
+ QUOTED_PAIR + r')' # see 3.4.1
+DOMAIN_LITERAL = CFWS + r'?' + r'\[' + \
+ r'(?:' + FWS + r'?' + DCONTENT + \
+ r')*' + FWS + r'?\]' + CFWS + r'?' # see 3.4.1
+DOMAIN = r'(?:' + DOT_ATOM + r'|' + \
+ DOMAIN_LITERAL + r')' # see 3.4.1
+ADDR_SPEC = LOCAL_PART + r'@' + DOMAIN # see 3.4.1
+
+# A valid address will match exactly the 3.4.1 addr-spec.
+VALID_ADDRESS_REGEXP = '^' + ADDR_SPEC + '$'
+
+def validate_email(email, check_mx=False,verify=False):
+
+ """Indicate whether the given string is a valid email address
+ according to the 'addr-spec' portion of RFC 2822 (see section
+ 3.4.1). Parts of the spec that are marked obsolete are *not*
+ included in this test, and certain arcane constructions that
+ depend on circular definitions in the spec may not pass, but in
+ general this should correctly identify any email address likely
+ to be in use as of 2011."""
+ try:
+ assert re.match(VALID_ADDRESS_REGEXP, email) is not None
+ check_mx |= verify
+ if check_mx:
+ if not DNS: raise Exception('For check the mx records or check if the email exists you must have installed pyDNS python package')
+ DNS.DiscoverNameServers()
+ hostname = email[email.find('@')+1:]
+ mx_hosts = DNS.mxlookup(hostname)
+ for mx in mx_hosts:
+ try:
+ smtp = smtplib.SMTP()
+ smtp.connect(mx[1])
+ if not verify: return True
+ status, _ = smtp.helo()
+ if status != 250: continue
+ smtp.mail('')
+ status, _ = smtp.rcpt(email)
+ if status != 250: return False
+ break
+ except smtplib.SMTPServerDisconnected: #Server not permits verify user
+ break
+ except smtplib.SMTPConnectError:
+ continue
+ except (AssertionError, ServerError):
+ return False
+ return True
+
+# import sys
+
+# sys.modules[__name__],sys.modules['validate_email_module'] = validate_email,sys.modules[__name__]
+# from validate_email_module import *
diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml
index 78e467a7ba8..e295bfdd250 100644
--- a/addons/crm_claim/crm_claim_view.xml
+++ b/addons/crm_claim/crm_claim_view.xml
@@ -201,7 +201,7 @@
-
+
diff --git a/addons/crm_claim/report/crm_claim_report_view.xml b/addons/crm_claim/report/crm_claim_report_view.xml
index febf9cafd73..530eb6061a3 100644
--- a/addons/crm_claim/report/crm_claim_report_view.xml
+++ b/addons/crm_claim/report/crm_claim_report_view.xml
@@ -65,7 +65,7 @@
-
+
diff --git a/addons/crm_claim/test/process/claim.yml b/addons/crm_claim/test/process/claim.yml
index bacb073b4b9..a843372956e 100644
--- a/addons/crm_claim/test/process/claim.yml
+++ b/addons/crm_claim/test/process/claim.yml
@@ -4,8 +4,7 @@
Mail script will be fetched him request from mail server. so I process that mail after read EML file
-
!python {model: mail.thread}: |
- from openerp import addons
- request_file = open(addons.get_module_resource('crm_claim','test', 'customer_claim.eml'),'rb')
+ request_file = open(openerp.modules.module.get_module_resource('crm_claim','test', 'customer_claim.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'crm.claim', request_message)
-
diff --git a/addons/crm_helpdesk/crm_helpdesk_view.xml b/addons/crm_helpdesk/crm_helpdesk_view.xml
index 6769b42a7f8..6e3521be6f2 100644
--- a/addons/crm_helpdesk/crm_helpdesk_view.xml
+++ b/addons/crm_helpdesk/crm_helpdesk_view.xml
@@ -152,7 +152,7 @@
-
+
diff --git a/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml b/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml
index 795ae210d8d..6ce2c60093f 100644
--- a/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml
+++ b/addons/crm_helpdesk/report/crm_helpdesk_report_view.xml
@@ -62,6 +62,7 @@
+
diff --git a/addons/crm_helpdesk/test/process/help-desk.yml b/addons/crm_helpdesk/test/process/help-desk.yml
index e2be4a64ca3..95536b1c8dd 100644
--- a/addons/crm_helpdesk/test/process/help-desk.yml
+++ b/addons/crm_helpdesk/test/process/help-desk.yml
@@ -4,8 +4,7 @@
Mail script will be fetched him request from mail server. so I process that mail after read EML file
-
!python {model: mail.thread}: |
- from openerp import addons
- request_file = open(addons.get_module_resource('crm_helpdesk','test', 'customer_question.eml'),'rb')
+ request_file = open(openerp.modules.module.get_module_resource('crm_helpdesk','test', 'customer_question.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'crm.helpdesk', request_message)
-
diff --git a/addons/document_webdav/test/webdav_test1.yml b/addons/document_webdav/test/webdav_test1.yml
index 82236f63846..ae91d7cd4a8 100644
--- a/addons/document_webdav/test/webdav_test1.yml
+++ b/addons/document_webdav/test/webdav_test1.yml
@@ -47,10 +47,9 @@
-
!python {model: ir.attachment}: |
from document_webdav import test_davclient as te
- import addons
dc = te.DAVClient()
dc.get_creds(self, cr, uid)
- tdp = addons.get_module_resource('document_webdav', 'test_davclient.py')
+ tdp = openerp.modules.module.get_module_resource('document_webdav', 'test_davclient.py')
res = dc.gd_put(path=cr.dbname+'/Documents/test_davclient.py', srcpath=tdp)
-
I will try to get the file from the root
@@ -60,5 +59,5 @@
import addons
dc = te.DAVClient()
dc.get_creds(self, cr, uid)
- tdp = addons.get_module_resource('document_webdav', 'test_davclient.py')
+ tdp = openerp.modules.module.get_module_resource('document_webdav', 'test_davclient.py')
res = dc.gd_get(path=cr.dbname+'/Documents/test_davclient.py', crange=(4,508), compare=tdp)
diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py
index 1804b9bfdb2..f67de272e29 100644
--- a/addons/document_webdav/webdav_server.py
+++ b/addons/document_webdav/webdav_server.py
@@ -608,7 +608,7 @@ try:
if base_path and base_path == '/':
dir_path = config.get_misc('static-http', 'dir_path', False)
else:
- dir_path = openerp.addons.get_module_resource('document_webdav','public_html')
+ dir_path = openerp.modules.module.get_module_resource('document_webdav','public_html')
# an _ugly_ hack: we put that dir back in tools.config.misc, so that
# the StaticHttpHandler can find its dir_path.
config.misc.setdefault('static-http',{})['dir_path'] = dir_path
diff --git a/addons/edi/i18n/lt.po b/addons/edi/i18n/lt.po
new file mode 100644
index 00000000000..4c00a1dc6d6
--- /dev/null
+++ b/addons/edi/i18n/lt.po
@@ -0,0 +1,87 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-29 15:19+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: 2013-04-30 05:29+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: edi
+#. openerp-web
+#: code:addons/edi/static/src/js/edi.js:67
+#, python-format
+msgid "Reason:"
+msgstr ""
+
+#. module: edi
+#. openerp-web
+#: code:addons/edi/static/src/js/edi.js:60
+#, python-format
+msgid "The document has been successfully imported!"
+msgstr ""
+
+#. module: edi
+#. openerp-web
+#: code:addons/edi/static/src/js/edi.js:65
+#, python-format
+msgid "Sorry, the document could not be imported."
+msgstr ""
+
+#. module: edi
+#: model:ir.model,name:edi.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: edi
+#: model:ir.model,name:edi.model_res_currency
+msgid "Currency"
+msgstr ""
+
+#. module: edi
+#. openerp-web
+#: code:addons/edi/static/src/js/edi.js:71
+#, python-format
+msgid "Document Import Notification"
+msgstr ""
+
+#. module: edi
+#: code:addons/edi/models/edi.py:130
+#, python-format
+msgid "Missing application."
+msgstr ""
+
+#. module: edi
+#: code:addons/edi/models/edi.py:131
+#, python-format
+msgid ""
+"The document you are trying to import requires the OpenERP `%s` application. "
+"You can install it by connecting as the administrator and opening the "
+"configuration assistant."
+msgstr ""
+
+#. module: edi
+#: code:addons/edi/models/edi.py:47
+#, python-format
+msgid "'%s' is an invalid external ID"
+msgstr ""
+
+#. module: edi
+#: model:ir.model,name:edi.model_res_partner
+msgid "Partner"
+msgstr ""
+
+#. module: edi
+#: model:ir.model,name:edi.model_edi_edi
+msgid "EDI Subsystem"
+msgstr ""
diff --git a/addons/edi/i18n/nl_BE.po b/addons/edi/i18n/nl_BE.po
index f5fc80a6fcc..aa96f26d13b 100644
--- a/addons/edi/i18n/nl_BE.po
+++ b/addons/edi/i18n/nl_BE.po
@@ -8,35 +8,35 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
-"PO-Revision-Date: 2012-10-02 08:10+0000\n"
+"PO-Revision-Date: 2013-04-15 16:04+0000\n"
"Last-Translator: Els Van Vossel (Agaplan) \n"
"Language-Team: Dutch (Belgium) \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2013-03-16 05:50+0000\n"
-"X-Generator: Launchpad (build 16532)\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
#. module: edi
#. openerp-web
#: code:addons/edi/static/src/js/edi.js:67
#, python-format
msgid "Reason:"
-msgstr ""
+msgstr "Reden:"
#. module: edi
#. openerp-web
#: code:addons/edi/static/src/js/edi.js:60
#, python-format
msgid "The document has been successfully imported!"
-msgstr ""
+msgstr "Het document is met succes geïmporteerd"
#. module: edi
#. openerp-web
#: code:addons/edi/static/src/js/edi.js:65
#, python-format
msgid "Sorry, the document could not be imported."
-msgstr ""
+msgstr "Sorry, het document kan niet worden geïmporteerd"
#. module: edi
#: model:ir.model,name:edi.model_res_company
@@ -53,13 +53,13 @@ msgstr "Munt"
#: code:addons/edi/static/src/js/edi.js:71
#, python-format
msgid "Document Import Notification"
-msgstr ""
+msgstr "Documentimportbericht"
#. module: edi
#: code:addons/edi/models/edi.py:130
#, python-format
msgid "Missing application."
-msgstr ""
+msgstr "Ontbrekend programma"
#. module: edi
#: code:addons/edi/models/edi.py:131
@@ -87,7 +87,7 @@ msgstr "Relatie"
#. module: edi
#: model:ir.model,name:edi.model_edi_edi
msgid "EDI Subsystem"
-msgstr ""
+msgstr "EDI-subsysteem"
#~ msgid "The currency code must be unique per company!"
#~ msgstr "De munt moet uniek zijn per firma."
diff --git a/addons/email_template/i18n/lt.po b/addons/email_template/i18n/lt.po
new file mode 100644
index 00000000000..20c2c5e0e5d
--- /dev/null
+++ b/addons/email_template/i18n/lt.po
@@ -0,0 +1,488 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-29 15:19+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: 2013-04-30 05:29+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: email_template
+#: field:email.template,email_from:0
+#: field:email_template.preview,email_from:0
+msgid "From"
+msgstr ""
+
+#. module: email_template
+#: field:mail.compose.message,template_id:0
+msgid "Template"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,ref_ir_value:0
+#: help:email_template.preview,ref_ir_value:0
+msgid "Sidebar button to open the sidebar action"
+msgstr ""
+
+#. module: email_template
+#: field:res.partner,opt_out:0
+msgid "Opt-Out"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,email_to:0
+#: field:email_template.preview,email_to:0
+msgid "To (Emails)"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,mail_server_id:0
+#: field:email_template.preview,mail_server_id:0
+msgid "Outgoing Mail Server"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,ref_ir_act_window:0
+#: help:email_template.preview,ref_ir_act_window:0
+msgid ""
+"Sidebar action to make this template available on records of the related "
+"document model"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,model_object_field:0
+#: field:email_template.preview,model_object_field:0
+msgid "Field"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,email_from:0
+#: help:email_template.preview,email_from:0
+msgid "Sender address (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Remove context action"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,mail_server_id:0
+#: help:email_template.preview,mail_server_id:0
+msgid ""
+"Optional preferred server for outgoing mails. If not set, the highest "
+"priority one will be used."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,report_name:0
+#: field:email_template.preview,report_name:0
+msgid "Report Filename"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Preview"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,reply_to:0
+#: field:email_template.preview,reply_to:0
+msgid "Reply-To"
+msgstr ""
+
+#. module: email_template
+#: view:mail.compose.message:0
+msgid "Use template"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,body_html:0
+#: field:email_template.preview,body_html:0
+msgid "Body"
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:244
+#, python-format
+msgid "%s (copy)"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,user_signature:0
+#: help:email_template.preview,user_signature:0
+msgid ""
+"If checked, the user's signature will be appended to the text version of the "
+"message"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "SMTP Server"
+msgstr ""
+
+#. module: email_template
+#: view:mail.compose.message:0
+msgid "Save as new template"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,sub_object:0
+#: help:email_template.preview,sub_object:0
+msgid ""
+"When a relationship field is selected as first field, this field shows the "
+"document model the relationship goes to."
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_email_template
+msgid "Email Templates"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,report_name:0
+#: help:email_template.preview,report_name:0
+msgid ""
+"Name to use for the generated report file (may contain placeholders)\n"
+"The extension can be omitted and will then come from the report type."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,ref_ir_act_window:0
+#: field:email_template.preview,ref_ir_act_window:0
+msgid "Sidebar action"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,lang:0
+#: help:email_template.preview,lang:0
+msgid ""
+"Optional translation language (ISO code) to select when sending out an "
+"email. If not set, the english version will be used. This should usually be "
+"a placeholder expression that provides the appropriate language code, e.g. "
+"${object.partner_id.lang.code}."
+msgstr ""
+
+#. module: email_template
+#: field:email_template.preview,res_id:0
+msgid "Sample Document"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,model_object_field:0
+#: help:email_template.preview,model_object_field:0
+msgid ""
+"Select target field from the related document model.\n"
+"If it is a relationship field you will be able to select a target field at "
+"the destination of the relationship."
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Dynamic Value Builder"
+msgstr ""
+
+#. module: email_template
+#: model:ir.actions.act_window,name:email_template.wizard_email_template_preview
+msgid "Template Preview"
+msgstr ""
+
+#. module: email_template
+#: view:mail.compose.message:0
+msgid "Save as a new template"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid ""
+"Display an option on related documents to open a composition wizard with "
+"this template"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,email_cc:0
+#: help:email_template.preview,email_cc:0
+msgid "Carbon copy recipients (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,email_to:0
+#: help:email_template.preview,email_to:0
+msgid "Comma-separated recipient addresses (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Advanced"
+msgstr ""
+
+#. module: email_template
+#: view:email_template.preview:0
+msgid "Preview of"
+msgstr ""
+
+#. module: email_template
+#: view:email_template.preview:0
+msgid "Using sample document"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+#: model:ir.actions.act_window,name:email_template.action_email_template_tree_all
+#: model:ir.ui.menu,name:email_template.menu_email_templates
+msgid "Templates"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,name:0
+#: field:email_template.preview,name:0
+msgid "Name"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,lang:0
+#: field:email_template.preview,lang:0
+msgid "Language"
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_email_template_preview
+msgid "Email Template Preview"
+msgstr ""
+
+#. module: email_template
+#: view:email_template.preview:0
+msgid "Email Preview"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid ""
+"Remove the contextual action to use this template on related documents"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,copyvalue:0
+#: field:email_template.preview,copyvalue:0
+msgid "Placeholder Expression"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,sub_object:0
+#: field:email_template.preview,sub_object:0
+msgid "Sub-model"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,subject:0
+#: help:email_template.preview,subject:0
+msgid "Subject (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,reply_to:0
+#: help:email_template.preview,reply_to:0
+msgid "Preferred response address (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,ref_ir_value:0
+#: field:email_template.preview,ref_ir_value:0
+msgid "Sidebar Button"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,report_template:0
+#: field:email_template.preview,report_template:0
+msgid "Optional report to print and attach"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,null_value:0
+#: help:email_template.preview,null_value:0
+msgid "Optional value to use if the target field is empty"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Model"
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_mail_compose_message
+msgid "Email composition wizard"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Add context action"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,model_id:0
+#: help:email_template.preview,model_id:0
+msgid "The kind of document with with this template can be used"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,email_recipients:0
+#: field:email_template.preview,email_recipients:0
+msgid "To (Partners)"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,auto_delete:0
+#: field:email_template.preview,auto_delete:0
+msgid "Auto Delete"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,copyvalue:0
+#: help:email_template.preview,copyvalue:0
+msgid ""
+"Final placeholder expression, to be copy-pasted in the desired template "
+"field."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,model:0
+#: field:email_template.preview,model:0
+msgid "Related Document Model"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Addressing"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,email_recipients:0
+#: help:email_template.preview,email_recipients:0
+msgid ""
+"Comma-separated ids of recipient partners (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,attachment_ids:0
+#: field:email_template.preview,attachment_ids:0
+msgid "Attachments"
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:231
+#, python-format
+msgid "Deletion of the action record failed."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,email_cc:0
+#: field:email_template.preview,email_cc:0
+msgid "Cc"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,model_id:0
+#: field:email_template.preview,model_id:0
+msgid "Applies to"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,sub_model_object_field:0
+#: field:email_template.preview,sub_model_object_field:0
+msgid "Sub-field"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Email Details"
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:196
+#, python-format
+msgid "Send Mail (%s)"
+msgstr ""
+
+#. module: email_template
+#: help:res.partner,opt_out:0
+msgid ""
+"If checked, this partner will not receive any automated email notifications, "
+"such as the availability of invoices."
+msgstr ""
+
+#. module: email_template
+#: help:email.template,auto_delete:0
+#: help:email_template.preview,auto_delete:0
+msgid "Permanently delete this email after sending it, to save space"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Group by..."
+msgstr ""
+
+#. module: email_template
+#: help:email.template,sub_model_object_field:0
+#: help:email_template.preview,sub_model_object_field:0
+msgid ""
+"When a relationship field is selected as first field, this field lets you "
+"select the target field within the destination document model (sub-model)."
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:231
+#, python-format
+msgid "Warning"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,user_signature:0
+#: field:email_template.preview,user_signature:0
+msgid "Add Signature"
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_res_partner
+msgid "Partner"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,null_value:0
+#: field:email_template.preview,null_value:0
+msgid "Default Value"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,attachment_ids:0
+#: help:email_template.preview,attachment_ids:0
+msgid ""
+"You may attach files to this template, to be added to all emails created "
+"from this template"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,body_html:0
+#: help:email_template.preview,body_html:0
+msgid "Rich-text/HTML version of the message (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Contents"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,subject:0
+#: field:email_template.preview,subject:0
+msgid "Subject"
+msgstr ""
diff --git a/addons/email_template/i18n/nl_BE.po b/addons/email_template/i18n/nl_BE.po
new file mode 100644
index 00000000000..5e7ddeec587
--- /dev/null
+++ b/addons/email_template/i18n/nl_BE.po
@@ -0,0 +1,489 @@
+# Dutch (Belgium) translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-26 16:28+0000\n"
+"Last-Translator: Els Van Vossel (Agaplan) \n"
+"Language-Team: Dutch (Belgium) \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-04-27 05:44+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: email_template
+#: field:email.template,email_from:0
+#: field:email_template.preview,email_from:0
+msgid "From"
+msgstr "Van"
+
+#. module: email_template
+#: field:mail.compose.message,template_id:0
+msgid "Template"
+msgstr "Sjabloon"
+
+#. module: email_template
+#: help:email.template,ref_ir_value:0
+#: help:email_template.preview,ref_ir_value:0
+msgid "Sidebar button to open the sidebar action"
+msgstr ""
+
+#. module: email_template
+#: field:res.partner,opt_out:0
+msgid "Opt-Out"
+msgstr "Uitschrijven"
+
+#. module: email_template
+#: field:email.template,email_to:0
+#: field:email_template.preview,email_to:0
+msgid "To (Emails)"
+msgstr "Naar (E-mails)"
+
+#. module: email_template
+#: field:email.template,mail_server_id:0
+#: field:email_template.preview,mail_server_id:0
+msgid "Outgoing Mail Server"
+msgstr "Uitgaande mailserver"
+
+#. module: email_template
+#: help:email.template,ref_ir_act_window:0
+#: help:email_template.preview,ref_ir_act_window:0
+msgid ""
+"Sidebar action to make this template available on records of the related "
+"document model"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,model_object_field:0
+#: field:email_template.preview,model_object_field:0
+msgid "Field"
+msgstr "Veld"
+
+#. module: email_template
+#: help:email.template,email_from:0
+#: help:email_template.preview,email_from:0
+msgid "Sender address (placeholders may be used here)"
+msgstr ""
+"Adres van de afzender (variabele aanduidingen kunnen hier worden gebruikt)"
+
+#. module: email_template
+#: view:email.template:0
+msgid "Remove context action"
+msgstr "Contextactie verwijderen"
+
+#. module: email_template
+#: help:email.template,mail_server_id:0
+#: help:email_template.preview,mail_server_id:0
+msgid ""
+"Optional preferred server for outgoing mails. If not set, the highest "
+"priority one will be used."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,report_name:0
+#: field:email_template.preview,report_name:0
+msgid "Report Filename"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Preview"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,reply_to:0
+#: field:email_template.preview,reply_to:0
+msgid "Reply-To"
+msgstr ""
+
+#. module: email_template
+#: view:mail.compose.message:0
+msgid "Use template"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,body_html:0
+#: field:email_template.preview,body_html:0
+msgid "Body"
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:244
+#, python-format
+msgid "%s (copy)"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,user_signature:0
+#: help:email_template.preview,user_signature:0
+msgid ""
+"If checked, the user's signature will be appended to the text version of the "
+"message"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "SMTP Server"
+msgstr ""
+
+#. module: email_template
+#: view:mail.compose.message:0
+msgid "Save as new template"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,sub_object:0
+#: help:email_template.preview,sub_object:0
+msgid ""
+"When a relationship field is selected as first field, this field shows the "
+"document model the relationship goes to."
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_email_template
+msgid "Email Templates"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,report_name:0
+#: help:email_template.preview,report_name:0
+msgid ""
+"Name to use for the generated report file (may contain placeholders)\n"
+"The extension can be omitted and will then come from the report type."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,ref_ir_act_window:0
+#: field:email_template.preview,ref_ir_act_window:0
+msgid "Sidebar action"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,lang:0
+#: help:email_template.preview,lang:0
+msgid ""
+"Optional translation language (ISO code) to select when sending out an "
+"email. If not set, the english version will be used. This should usually be "
+"a placeholder expression that provides the appropriate language code, e.g. "
+"${object.partner_id.lang.code}."
+msgstr ""
+
+#. module: email_template
+#: field:email_template.preview,res_id:0
+msgid "Sample Document"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,model_object_field:0
+#: help:email_template.preview,model_object_field:0
+msgid ""
+"Select target field from the related document model.\n"
+"If it is a relationship field you will be able to select a target field at "
+"the destination of the relationship."
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Dynamic Value Builder"
+msgstr ""
+
+#. module: email_template
+#: model:ir.actions.act_window,name:email_template.wizard_email_template_preview
+msgid "Template Preview"
+msgstr ""
+
+#. module: email_template
+#: view:mail.compose.message:0
+msgid "Save as a new template"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid ""
+"Display an option on related documents to open a composition wizard with "
+"this template"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,email_cc:0
+#: help:email_template.preview,email_cc:0
+msgid "Carbon copy recipients (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,email_to:0
+#: help:email_template.preview,email_to:0
+msgid "Comma-separated recipient addresses (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Advanced"
+msgstr ""
+
+#. module: email_template
+#: view:email_template.preview:0
+msgid "Preview of"
+msgstr ""
+
+#. module: email_template
+#: view:email_template.preview:0
+msgid "Using sample document"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+#: model:ir.actions.act_window,name:email_template.action_email_template_tree_all
+#: model:ir.ui.menu,name:email_template.menu_email_templates
+msgid "Templates"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,name:0
+#: field:email_template.preview,name:0
+msgid "Name"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,lang:0
+#: field:email_template.preview,lang:0
+msgid "Language"
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_email_template_preview
+msgid "Email Template Preview"
+msgstr ""
+
+#. module: email_template
+#: view:email_template.preview:0
+msgid "Email Preview"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid ""
+"Remove the contextual action to use this template on related documents"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,copyvalue:0
+#: field:email_template.preview,copyvalue:0
+msgid "Placeholder Expression"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,sub_object:0
+#: field:email_template.preview,sub_object:0
+msgid "Sub-model"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,subject:0
+#: help:email_template.preview,subject:0
+msgid "Subject (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,reply_to:0
+#: help:email_template.preview,reply_to:0
+msgid "Preferred response address (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,ref_ir_value:0
+#: field:email_template.preview,ref_ir_value:0
+msgid "Sidebar Button"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,report_template:0
+#: field:email_template.preview,report_template:0
+msgid "Optional report to print and attach"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,null_value:0
+#: help:email_template.preview,null_value:0
+msgid "Optional value to use if the target field is empty"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Model"
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_mail_compose_message
+msgid "Email composition wizard"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Add context action"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,model_id:0
+#: help:email_template.preview,model_id:0
+msgid "The kind of document with with this template can be used"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,email_recipients:0
+#: field:email_template.preview,email_recipients:0
+msgid "To (Partners)"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,auto_delete:0
+#: field:email_template.preview,auto_delete:0
+msgid "Auto Delete"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,copyvalue:0
+#: help:email_template.preview,copyvalue:0
+msgid ""
+"Final placeholder expression, to be copy-pasted in the desired template "
+"field."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,model:0
+#: field:email_template.preview,model:0
+msgid "Related Document Model"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Addressing"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,email_recipients:0
+#: help:email_template.preview,email_recipients:0
+msgid ""
+"Comma-separated ids of recipient partners (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,attachment_ids:0
+#: field:email_template.preview,attachment_ids:0
+msgid "Attachments"
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:231
+#, python-format
+msgid "Deletion of the action record failed."
+msgstr ""
+
+#. module: email_template
+#: field:email.template,email_cc:0
+#: field:email_template.preview,email_cc:0
+msgid "Cc"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,model_id:0
+#: field:email_template.preview,model_id:0
+msgid "Applies to"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,sub_model_object_field:0
+#: field:email_template.preview,sub_model_object_field:0
+msgid "Sub-field"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Email Details"
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:196
+#, python-format
+msgid "Send Mail (%s)"
+msgstr ""
+
+#. module: email_template
+#: help:res.partner,opt_out:0
+msgid ""
+"If checked, this partner will not receive any automated email notifications, "
+"such as the availability of invoices."
+msgstr ""
+
+#. module: email_template
+#: help:email.template,auto_delete:0
+#: help:email_template.preview,auto_delete:0
+msgid "Permanently delete this email after sending it, to save space"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Group by..."
+msgstr ""
+
+#. module: email_template
+#: help:email.template,sub_model_object_field:0
+#: help:email_template.preview,sub_model_object_field:0
+msgid ""
+"When a relationship field is selected as first field, this field lets you "
+"select the target field within the destination document model (sub-model)."
+msgstr ""
+
+#. module: email_template
+#: code:addons/email_template/email_template.py:231
+#, python-format
+msgid "Warning"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,user_signature:0
+#: field:email_template.preview,user_signature:0
+msgid "Add Signature"
+msgstr ""
+
+#. module: email_template
+#: model:ir.model,name:email_template.model_res_partner
+msgid "Partner"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,null_value:0
+#: field:email_template.preview,null_value:0
+msgid "Default Value"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,attachment_ids:0
+#: help:email_template.preview,attachment_ids:0
+msgid ""
+"You may attach files to this template, to be added to all emails created "
+"from this template"
+msgstr ""
+
+#. module: email_template
+#: help:email.template,body_html:0
+#: help:email_template.preview,body_html:0
+msgid "Rich-text/HTML version of the message (placeholders may be used here)"
+msgstr ""
+
+#. module: email_template
+#: view:email.template:0
+msgid "Contents"
+msgstr ""
+
+#. module: email_template
+#: field:email.template,subject:0
+#: field:email_template.preview,subject:0
+msgid "Subject"
+msgstr ""
diff --git a/addons/fleet/i18n/nl_BE.po b/addons/fleet/i18n/nl_BE.po
new file mode 100644
index 00000000000..380de8a945e
--- /dev/null
+++ b/addons/fleet/i18n/nl_BE.po
@@ -0,0 +1,1912 @@
+# Dutch (Belgium) translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:06+0000\n"
+"PO-Revision-Date: 2013-04-15 16:40+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Dutch (Belgium) \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2013-04-16 04:37+0000\n"
+"X-Generator: Launchpad (build 16564)\n"
+
+#. module: fleet
+#: selection:fleet.vehicle,fuel_type:0
+msgid "Hybrid"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_compact
+msgid "Compact"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_1
+msgid "A/C Compressor Replacement"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,vin_sn:0
+msgid "Unique number written on the vehicle motor (VIN/SN number)"
+msgstr ""
+
+#. module: fleet
+#: selection:fleet.service.type,category:0
+#: view:fleet.vehicle.log.contract:0
+#: view:fleet.vehicle.log.services:0
+msgid "Service"
+msgstr ""
+
+#. module: fleet
+#: selection:fleet.vehicle.log.contract,cost_frequency:0
+msgid "Monthly"
+msgstr ""
+
+#. module: fleet
+#: code:addons/fleet/fleet.py:62
+#, python-format
+msgid "Unknown"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_20
+msgid "Engine/Drive Belt(s) Replacement"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.cost:0
+msgid "Vehicle costs"
+msgstr ""
+
+#. module: fleet
+#: selection:fleet.vehicle,fuel_type:0
+msgid "Diesel"
+msgstr ""
+
+#. module: fleet
+#: code:addons/fleet/fleet.py:421
+#, python-format
+msgid "License Plate: from '%s' to '%s'"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_38
+msgid "Resurface Rotors"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.cost:0
+#: view:fleet.vehicle.model:0
+msgid "Group By..."
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_32
+msgid "Oil Pump Replacement"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_18
+msgid "Engine Belt Inspection"
+msgstr ""
+
+#. module: fleet
+#: selection:fleet.vehicle.log.contract,cost_frequency:0
+msgid "No"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,power:0
+msgid "Power in kW of the vehicle"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_service_2
+msgid "Depreciation and Interests"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle.log.contract,insurer_id:0
+#: field:fleet.vehicle.log.fuel,vendor_id:0
+#: field:fleet.vehicle.log.services,vendor_id:0
+msgid "Supplier"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_35
+msgid "Power Steering Hose Replacement"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.contract:0
+msgid "Odometer details"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle:0
+msgid "Has Alert(s)"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle.log.fuel,liter:0
+msgid "Liter"
+msgstr ""
+
+#. module: fleet
+#: model:ir.actions.client,name:fleet.action_fleet_menu
+msgid "Open Fleet Menu"
+msgstr ""
+
+#. module: fleet
+#: view:board.board:0
+msgid "Fuel Costs"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_9
+msgid "Battery Inspection"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle,company_id:0
+msgid "Company"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.contract:0
+msgid "Invoice Date"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.fuel:0
+msgid "Refueling Details"
+msgstr ""
+
+#. module: fleet
+#: code:addons/fleet/fleet.py:669
+#, python-format
+msgid "%s contract(s) need(s) to be renewed and/or closed!"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.cost:0
+msgid "Indicative Costs"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_16
+msgid "Charging System Diagnosis"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,car_value:0
+msgid "Value of the bought vehicle"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_44
+msgid "Tie Rod End Replacement"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_24
+msgid "Head Gasket(s) Replacement"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle:0
+#: selection:fleet.vehicle.cost,cost_type:0
+msgid "Services"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,odometer:0
+#: help:fleet.vehicle.cost,odometer:0
+#: help:fleet.vehicle.cost,odometer_id:0
+msgid "Odometer measure of the vehicle at the moment of this log"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.contract:0
+#: field:fleet.vehicle.log.contract,notes:0
+msgid "Terms and Conditions"
+msgstr ""
+
+#. module: fleet
+#: model:ir.actions.act_window,name:fleet.action_fleet_vehicle_kanban
+msgid "Vehicles with alerts"
+msgstr ""
+
+#. module: fleet
+#: model:ir.actions.act_window,name:fleet.fleet_vehicle_costs_act
+#: model:ir.ui.menu,name:fleet.fleet_vehicle_costs_menu
+msgid "Vehicle Costs"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.cost:0
+msgid "Total Cost"
+msgstr ""
+
+#. module: fleet
+#: selection:fleet.service.type,category:0
+msgid "Both"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle.log.contract,cost_id:0
+#: field:fleet.vehicle.log.fuel,cost_id:0
+#: field:fleet.vehicle.log.services,cost_id:0
+msgid "Automatically created field to link to parent fleet.vehicle.cost"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.contract:0
+msgid "Terminate Contract"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.cost,parent_id:0
+msgid "Parent cost to this current cost"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.log.contract,cost_frequency:0
+msgid "Frequency of the recuring cost"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_service_1
+msgid "Calculation Benefit In Kind"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.log.contract,expiration_date:0
+msgid ""
+"Date when the coverage of the contract expirates (by default, one year after "
+"begin date)"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.fuel:0
+#: field:fleet.vehicle.log.fuel,notes:0
+#: view:fleet.vehicle.log.services:0
+#: field:fleet.vehicle.log.services,notes:0
+msgid "Notes"
+msgstr ""
+
+#. module: fleet
+#: code:addons/fleet/fleet.py:47
+#, python-format
+msgid "Operation not allowed!"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle,message_ids:0
+msgid "Messages"
+msgstr ""
+
+#. module: fleet
+#: model:res.groups,name:fleet.group_fleet_user
+msgid "User"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.cost,vehicle_id:0
+msgid "Vehicle concerned by this log"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle.log.contract,cost_amount:0
+#: field:fleet.vehicle.log.fuel,cost_amount:0
+#: field:fleet.vehicle.log.services,cost_amount:0
+msgid "Amount"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle,message_unread:0
+msgid "Unread Messages"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_6
+msgid "Air Filter Replacement"
+msgstr ""
+
+#. module: fleet
+#: model:ir.model,name:fleet.model_fleet_vehicle_tag
+msgid "fleet.vehicle.tag"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle:0
+msgid "show the services logs for this vehicle"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle,contract_renewal_name:0
+msgid "Name of contract to renew soon"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_senior
+msgid "Senior"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.log.contract,state:0
+msgid "Choose wheter the contract is still valid or not"
+msgstr ""
+
+#. module: fleet
+#: selection:fleet.vehicle,transmission:0
+msgid "Automatic"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,message_unread:0
+msgid "If checked new messages require your attention."
+msgstr ""
+
+#. module: fleet
+#: code:addons/fleet/fleet.py:414
+#, python-format
+msgid "Driver: from '%s' to '%s'"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle:0
+msgid "and"
+msgstr ""
+
+#. module: fleet
+#: field:fleet.vehicle.model.brand,image_medium:0
+msgid "Medium-sized photo"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_34
+msgid "Oxygen Sensor Replacement"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.services:0
+msgid "Service Type"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,transmission:0
+msgid "Transmission Used by the vehicle"
+msgstr ""
+
+#. module: fleet
+#: code:addons/fleet/fleet.py:740
+#: view:fleet.vehicle.log.contract:0
+#: model:ir.actions.act_window,name:fleet.act_renew_contract
+#, python-format
+msgid "Renew Contract"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle:0
+msgid "show the odometer logs for this vehicle"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,odometer_unit:0
+msgid "Unit of the odometer "
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.services:0
+msgid "Services Costs Per Month"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.cost:0
+msgid "Effective Costs"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_service_8
+msgid "Repair and maintenance"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.log.contract,purchaser_id:0
+msgid "Person to which the contract is signed for"
+msgstr ""
+
+#. module: fleet
+#: model:ir.actions.act_window,help:fleet.fleet_vehicle_log_contract_act
+msgid ""
+"
\n"
+" Click to create a new contract. \n"
+"
\n"
+" Manage all your contracts (leasing, insurances, etc.) with\n"
+" their related services, costs. OpenERP will automatically "
+"warn\n"
+" you when some contracts have to be renewed.\n"
+"
\n"
+" Each contract (e.g.: leasing) may include several services\n"
+" (reparation, insurances, periodic maintenance).\n"
+"
\n"
+" OpenERP helps you managing the costs for your different\n"
+" vehicles. Costs are created automatically from services,\n"
+" contracts (fixed or recurring) and fuel logs.\n"
+"
\n"
+" Here you can add refuelling entries for all vehicles. You "
+"can\n"
+" also filter logs of a particular vehicle using the search\n"
+" field.\n"
+"
\n"
+" You will be able to manage your fleet by keeping track of "
+"the\n"
+" contracts, services, fixed and recurring costs, odometers "
+"and\n"
+" fuel logs associated to each vehicle.\n"
+"
\n"
+" OpenERP will warn you when services or contract have to be\n"
+" renewed.\n"
+"
\n"
+" To add your first report into this dashboard, go to any\n"
+" menu, switch to list or graph view, and click 'Add "
+"to\n"
+" Dashboard' in the extended search options.\n"
+"
\n"
+" You can filter and group data before inserting into the\n"
+" dashboard using the search options.\n"
+"
\n"
+" OpenERP helps you managing the costs for your different vehicles\n"
+" Costs are generally created from services and contract and appears "
+"here.\n"
+"
\n"
+"
\n"
+" Thanks to the different filters, OpenERP can only print the "
+"effective\n"
+" costs, sort them by type and by vehicle.\n"
+"
\n"
+" Here you can add various odometer entries for all vehicles.\n"
+" You can also show odometer value for a particular vehicle "
+"using\n"
+" the search field.\n"
+"
\n"
+" Here are displayed vehicles for which one or more contracts need "
+"to be renewed. If you see this message, then there is no contracts to "
+"renew.\n"
+"
\n"
+" Click to create a new service entry. \n"
+"
\n"
+" OpenERP helps you keeping track of all the services done\n"
+" on your vehicle. Services can be of many type: occasional\n"
+" repair, fixed maintenance, etc.\n"
+"
\n"
+" Click to create a new type of service.\n"
+"
\n"
+" Each service can used in contracts, as a standalone service "
+"or both.\n"
+"
\n"
+" "
+msgstr ""
+
+#. module: fleet
+#: view:board.board:0
+msgid "Services Costs"
+msgstr ""
+
+#. module: fleet
+#: code:addons/fleet/fleet.py:47
+#, python-format
+msgid "Emptying the odometer value of a vehicle is not allowed."
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,seats:0
+msgid "Number of seats of the vehicle"
+msgstr ""
+
+#. module: fleet
+#: model:res.groups,name:fleet.group_fleet_manager
+msgid "Manager"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.services:0
+msgid "Cost"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_39
+msgid "Rotate Tires"
+msgstr ""
+
+#. module: fleet
+#: model:fleet.service.type,name:fleet.type_service_42
+msgid "Starter Replacement"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.cost:0
+#: field:fleet.vehicle.cost,year:0
+msgid "Year"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle,license_plate:0
+msgid "License plate number of the vehicle (ie: plate number for a car)"
+msgstr ""
+
+#. module: fleet
+#: model:ir.model,name:fleet.model_fleet_contract_state
+msgid "Contains the different possible status of a leasing contract"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle:0
+msgid "show the contract for this vehicle"
+msgstr ""
+
+#. module: fleet
+#: view:fleet.vehicle.log.services:0
+msgid "Total"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.service.type,category:0
+msgid ""
+"Choose wheter the service refer to contracts, vehicle services or both"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.cost,cost_type:0
+msgid "For internal purpose only"
+msgstr ""
+
+#. module: fleet
+#: help:fleet.vehicle.state,sequence:0
+msgid "Used to order the note stages"
+msgstr ""
diff --git a/addons/hr/hr.py b/addons/hr/hr.py
index b8d4bfb4267..585e5ce81a4 100644
--- a/addons/hr/hr.py
+++ b/addons/hr/hr.py
@@ -19,10 +19,12 @@
#
##############################################################################
-from openerp import addons
import logging
+
+from openerp.modules.module import get_module_resource
from openerp.osv import fields, osv
from openerp import tools
+
_logger = logging.getLogger(__name__)
class hr_employee_category(osv.osv):
@@ -219,7 +221,7 @@ class hr_employee(osv.osv):
(model, mail_group_id) = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'group_all_employees')
employee = self.browse(cr, uid, employee_id, context=context)
self.pool.get('mail.group').message_post(cr, uid, [mail_group_id],
- body='Welcome to %s! Please help them take the first steps with OpenERP!' % (employee.name),
+ body='Welcome to %s! Please help him/her take the first steps with OpenERP!' % (employee.name),
subtype='mail.mt_comment', context=context)
except:
pass # group deleted: do not push a message
@@ -259,7 +261,7 @@ class hr_employee(osv.osv):
return {'value': {'work_email' : work_email}}
def _get_default_image(self, cr, uid, context=None):
- image_path = addons.get_module_resource('hr', 'static/src/img', 'default_image.png')
+ image_path = get_module_resource('hr', 'static/src/img', 'default_image.png')
return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
_defaults = {
diff --git a/addons/hr_expense/hr_expense.py b/addons/hr_expense/hr_expense.py
index c422a2d4948..73daa64f841 100644
--- a/addons/hr_expense/hr_expense.py
+++ b/addons/hr_expense/hr_expense.py
@@ -52,6 +52,9 @@ class hr_expense_expense(osv.osv):
res[expense.id] = total
return res
+ def _get_expense_from_line(self, cr, uid, ids, context=None):
+ return [line.expense_id.id for line in self.pool.get('hr.expense.line').browse(cr, uid, ids, context=context)]
+
def _get_currency(self, cr, uid, context=None):
user = self.pool.get('res.users').browse(cr, uid, [uid], context=context)[0]
if user.company_id:
@@ -84,7 +87,10 @@ class hr_expense_expense(osv.osv):
'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')),
+ 'amount': fields.function(_amount, string='Total Amount', digits_compute=dp.get_precision('Account'),
+ store={
+ 'hr.expense.line': (_get_expense_from_line, ['unit_amount','unit_quantity'], 10)
+ }),
'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),
diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml
index eab24b06717..10abe95d892 100644
--- a/addons/hr_expense/hr_expense_view.xml
+++ b/addons/hr_expense/hr_expense_view.xml
@@ -32,7 +32,7 @@
-
+
diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py
index c4b26f0ec3a..0eb3c0cbf16 100644
--- a/addons/hr_holidays/hr_holidays.py
+++ b/addons/hr_holidays/hr_holidays.py
@@ -180,7 +180,8 @@ class hr_holidays(osv.osv):
]
_sql_constraints = [
- ('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "The employee or employee category of this request is missing."),
+ ('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))",
+ "The employee or employee category of this request is missing. Please make sure that your user login is linked to an employee."),
('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be anterior to the end date."),
('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0."),
]
diff --git a/addons/hr_payroll_account/i18n/lt.po b/addons/hr_payroll_account/i18n/lt.po
new file mode 100644
index 00000000000..c29df14b44e
--- /dev/null
+++ b/addons/hr_payroll_account/i18n/lt.po
@@ -0,0 +1,126 @@
+# Lithuanian translation for openobject-addons
+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-12-21 17:05+0000\n"
+"PO-Revision-Date: 2013-04-29 15:21+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: 2013-04-30 05:29+0000\n"
+"X-Generator: Launchpad (build 16580)\n"
+
+#. module: hr_payroll_account
+#: field:hr.salary.rule,account_credit:0
+msgid "Credit Account"
+msgstr ""
+
+#. module: hr_payroll_account
+#: code:addons/hr_payroll_account/hr_payroll_account.py:103
+#, python-format
+msgid "Payslip of %s"
+msgstr ""
+
+#. module: hr_payroll_account
+#: code:addons/hr_payroll_account/hr_payroll_account.py:156
+#, python-format
+msgid ""
+"The Expense Journal \"%s\" has not properly configured the Credit Account!"
+msgstr ""
+
+#. module: hr_payroll_account
+#: field:hr.payslip,move_id:0
+msgid "Accounting Entry"
+msgstr ""
+
+#. module: hr_payroll_account
+#: code:addons/hr_payroll_account/hr_payroll_account.py:172
+#, python-format
+msgid ""
+"The Expense Journal \"%s\" has not properly configured the Debit Account!"
+msgstr ""
+
+#. module: hr_payroll_account
+#: field:hr.salary.rule,account_tax_id:0
+msgid "Tax Code"
+msgstr ""
+
+#. module: hr_payroll_account
+#: field:hr.payslip,period_id:0
+msgid "Force Period"
+msgstr ""
+
+#. module: hr_payroll_account
+#: help:hr.payslip,period_id:0
+msgid "Keep empty to use the period of the validation(Payslip) date."
+msgstr ""
+
+#. module: hr_payroll_account
+#: model:ir.model,name:hr_payroll_account.model_hr_contract
+msgid "Contract"
+msgstr ""
+
+#. module: hr_payroll_account
+#: field:hr.contract,analytic_account_id:0
+#: field:hr.salary.rule,analytic_account_id:0
+msgid "Analytic Account"
+msgstr ""
+
+#. module: hr_payroll_account
+#: field:hr.salary.rule,account_debit:0
+msgid "Debit Account"
+msgstr ""
+
+#. module: hr_payroll_account
+#: model:ir.model,name:hr_payroll_account.model_hr_payslip_run
+msgid "Payslip Batches"
+msgstr ""
+
+#. module: hr_payroll_account
+#: model:ir.model,name:hr_payroll_account.model_hr_payslip_employees
+msgid "Generate payslips for all selected employees"
+msgstr ""
+
+#. module: hr_payroll_account
+#: code:addons/hr_payroll_account/hr_payroll_account.py:156
+#: code:addons/hr_payroll_account/hr_payroll_account.py:172
+#, python-format
+msgid "Configuration Error!"
+msgstr ""
+
+#. module: hr_payroll_account
+#: model:ir.model,name:hr_payroll_account.model_hr_salary_rule
+msgid "hr.salary.rule"
+msgstr ""
+
+#. module: hr_payroll_account
+#: view:hr.contract:0
+#: view:hr.salary.rule:0
+msgid "Accounting"
+msgstr ""
+
+#. module: hr_payroll_account
+#: model:ir.model,name:hr_payroll_account.model_hr_payslip
+msgid "Pay Slip"
+msgstr ""
+
+#. module: hr_payroll_account
+#: code:addons/hr_payroll_account/hr_payroll_account.py:158
+#: code:addons/hr_payroll_account/hr_payroll_account.py:174
+#, python-format
+msgid "Adjustment Entry"
+msgstr ""
+
+#. module: hr_payroll_account
+#: field:hr.contract,journal_id:0
+#: field:hr.payslip,journal_id:0
+#: field:hr.payslip.run,journal_id:0
+msgid "Salary Journal"
+msgstr ""
diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py
index b0b60db6bd5..e41d80fb348 100644
--- a/addons/hr_recruitment/hr_recruitment.py
+++ b/addons/hr_recruitment/hr_recruitment.py
@@ -510,8 +510,9 @@ class hr_job(osv.osv):
def _auto_init(self, cr, context=None):
"""Installation hook to create aliases for all jobs and avoid constraint errors."""
- self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(hr_job,self)._auto_init,
+ res = self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(hr_job,self)._auto_init,
self._columns['alias_id'], 'name', alias_prefix='job+', alias_defaults={'job_id': 'id'}, context=context)
+ return res
def create(self, cr, uid, vals, context=None):
mail_alias = self.pool.get('mail.alias')
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index b531677d538..716c1cba8d5 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -41,7 +41,7 @@
-
+
@@ -199,7 +199,7 @@
-
+
diff --git a/addons/hr_recruitment/test/recruitment_process.yml b/addons/hr_recruitment/test/recruitment_process.yml
index f2d4e4736fa..335edc71892 100644
--- a/addons/hr_recruitment/test/recruitment_process.yml
+++ b/addons/hr_recruitment/test/recruitment_process.yml
@@ -4,8 +4,7 @@
An applicant is interested in the job position. So he sends a resume by email.
-
!python {model: mail.thread}: |
- from openerp import addons
- request_file = open(addons.get_module_resource('hr_recruitment','test', 'resume.eml'),'rb')
+ request_file = open(openerp.modules.module.get_module_resource('hr_recruitment','test', 'resume.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'hr.applicant', request_message)
-
diff --git a/addons/im/__init__.py b/addons/im/__init__.py
new file mode 100644
index 00000000000..23c6ad13350
--- /dev/null
+++ b/addons/im/__init__.py
@@ -0,0 +1,2 @@
+
+import im
diff --git a/addons/im/__openerp__.py b/addons/im/__openerp__.py
new file mode 100644
index 00000000000..a76dd7c8cc2
--- /dev/null
+++ b/addons/im/__openerp__.py
@@ -0,0 +1,27 @@
+{
+ 'name' : 'Instant Messaging',
+ 'version': '1.0',
+ 'summary': 'Live Chat, Talks with Others',
+ 'sequence': '18',
+ 'category': 'Tools',
+ 'complexity': 'easy',
+ 'description':
+ """
+Instant Messaging
+=================
+
+Allows users to chat with each other in real time. Find other users easily and
+chat in real time. It support several chats in parallel.
+ """,
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'security/im_security.xml',
+ ],
+ 'depends' : ['base'],
+ 'js': ['static/src/js/*.js'],
+ 'css': ['static/src/css/*.css'],
+ 'qweb': ['static/src/xml/*.xml'],
+ 'installable': True,
+ 'auto_install': False,
+ 'application': True,
+}
diff --git a/addons/im/im.py b/addons/im/im.py
new file mode 100644
index 00000000000..0de9ea8c79b
--- /dev/null
+++ b/addons/im/im.py
@@ -0,0 +1,351 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import openerp
+import openerp.tools.config
+import openerp.modules.registry
+from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
+import datetime
+from openerp.osv import osv, fields
+import time
+import logging
+import json
+import select
+
+_logger = logging.getLogger(__name__)
+
+def listen_channel(cr, channel_name, handle_message, check_stop=(lambda: False), check_stop_timer=60.):
+ """
+ Begin a loop, listening on a PostgreSQL channel. This method does never terminate by default, you need to provide a check_stop
+ callback to do so. This method also assume that all notifications will include a message formated using JSON (see the
+ corresponding notify_channel() method).
+
+ :param db_name: database name
+ :param channel_name: the name of the PostgreSQL channel to listen
+ :param handle_message: function that will be called when a message is received. It takes one argument, the message
+ attached to the notification.
+ :type handle_message: function (one argument)
+ :param check_stop: function that will be called periodically (see the check_stop_timer argument). If it returns True
+ this function will stop to watch the channel.
+ :type check_stop: function (no arguments)
+ :param check_stop_timer: The maximum amount of time between calls to check_stop_timer (can be shorter if messages
+ are received).
+ """
+ try:
+ conn = cr._cnx
+ cr.execute("listen " + channel_name + ";")
+ cr.commit();
+ stopping = False
+ while not stopping:
+ if check_stop():
+ stopping = True
+ break
+ if select.select([conn], [], [], check_stop_timer) == ([],[],[]):
+ pass
+ else:
+ conn.poll()
+ while conn.notifies:
+ message = json.loads(conn.notifies.pop().payload)
+ handle_message(message)
+ finally:
+ try:
+ cr.execute("unlisten " + channel_name + ";")
+ cr.commit()
+ except:
+ pass # can't do anything if that fails
+
+def notify_channel(cr, channel_name, message):
+ """
+ Send a message through a PostgreSQL channel. The message will be formatted using JSON. This method will
+ commit the given transaction because the notify command in Postgresql seems to work correctly when executed in
+ a separate transaction (despite what is written in the documentation).
+
+ :param cr: The cursor.
+ :param channel_name: The name of the PostgreSQL channel.
+ :param message: The message, must be JSON-compatible data.
+ """
+ cr.commit()
+ cr.execute("notify " + channel_name + ", %s", [json.dumps(message)])
+ cr.commit()
+
+POLL_TIMER = 30
+DISCONNECTION_TIMER = POLL_TIMER + 5
+WATCHER_ERROR_DELAY = 10
+
+if openerp.evented:
+ import gevent
+ import gevent.event
+
+ class ImWatcher(object):
+ watchers = {}
+
+ @staticmethod
+ def get_watcher(db_name):
+ if not ImWatcher.watchers.get(db_name):
+ ImWatcher(db_name)
+ return ImWatcher.watchers[db_name]
+
+ def __init__(self, db_name):
+ self.db_name = db_name
+ ImWatcher.watchers[db_name] = self
+ self.waiting = 0
+ self.wait_id = 0
+ self.users = {}
+ self.users_watch = {}
+ gevent.spawn(self.loop)
+
+ def loop(self):
+ _logger.info("Begin watching on channel im_channel for database " + self.db_name)
+ stop = False
+ while not stop:
+ try:
+ registry = openerp.modules.registry.RegistryManager.get(self.db_name)
+ with registry.cursor() as cr:
+ listen_channel(cr, "im_channel", self.handle_message, self.check_stop)
+ stop = True
+ except:
+ # if something crash, we wait some time then try again
+ _logger.exception("Exception during watcher activity")
+ time.sleep(WATCHER_ERROR_DELAY)
+ _logger.info("End watching on channel im_channel for database " + self.db_name)
+ del ImWatcher.watchers[self.db_name]
+
+ def handle_message(self, message):
+ if message["type"] == "message":
+ for waiter in self.users.get(message["receiver"], {}).values():
+ waiter.set()
+ else: #type status
+ for waiter in self.users_watch.get(message["user"], {}).values():
+ waiter.set()
+
+ def check_stop(self):
+ return self.waiting == 0
+
+ def _get_wait_id(self):
+ self.wait_id += 1
+ return self.wait_id
+
+ def stop(self, user_id, watch_users, timeout=None):
+ wait_id = self._get_wait_id()
+ event = gevent.event.Event()
+ self.waiting += 1
+ self.users.setdefault(user_id, {})[wait_id] = event
+ for watch in watch_users:
+ self.users_watch.setdefault(watch, {})[wait_id] = event
+ try:
+ event.wait(timeout)
+ finally:
+ for watch in watch_users:
+ del self.users_watch[watch][wait_id]
+ if len(self.users_watch[watch]) == 0:
+ del self.users_watch[watch]
+ del self.users[user_id][wait_id]
+ if len(self.users[user_id]) == 0:
+ del self.users[user_id]
+ self.waiting -= 1
+
+
+class LongPollingController(openerp.addons.web.http.Controller):
+ _cp_path = '/longpolling/im'
+
+ @openerp.addons.web.http.jsonrequest
+ def poll(self, req, last=None, users_watch=None, db=None, uid=None, password=None, uuid=None):
+ assert_uuid(uuid)
+ if not openerp.evented:
+ raise Exception("Not usable in a server not running gevent")
+ if db is not None:
+ req.session._db = db
+ req.session._uid = uid
+ req.session._password = password
+ req.session.model('im.user').im_connect(uuid=uuid, context=req.context)
+ my_id = req.session.model('im.user').get_by_user_id(uuid or req.session._uid, req.context)["id"]
+ num = 0
+ while True:
+ res = req.session.model('im.message').get_messages(last, users_watch, uuid=uuid, context=req.context)
+ if num >= 1 or len(res["res"]) > 0:
+ return res
+ last = res["last"]
+ num += 1
+ ImWatcher.get_watcher(res["dbname"]).stop(my_id, users_watch or [], POLL_TIMER)
+
+ @openerp.addons.web.http.jsonrequest
+ def activated(self, req):
+ return not not openerp.evented
+
+ @openerp.addons.web.http.jsonrequest
+ def gen_uuid(self, req):
+ import uuid
+ return "%s" % uuid.uuid1()
+
+def assert_uuid(uuid):
+ if not isinstance(uuid, (str, unicode, type(None))):
+ raise Exception("%s is not a uuid" % uuid)
+
+
+class im_message(osv.osv):
+ _name = 'im.message'
+
+ _order = "date desc"
+
+ _columns = {
+ 'message': fields.char(string="Message", size=200, required=True),
+ 'from_id': fields.many2one("im.user", "From", required= True, ondelete='cascade'),
+ 'to_id': fields.many2one("im.user", "To", required=True, select=True, ondelete='cascade'),
+ 'date': fields.datetime("Date", required=True, select=True),
+ }
+
+ _defaults = {
+ 'date': lambda *args: datetime.datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
+ }
+
+ def get_messages(self, cr, uid, last=None, users_watch=None, uuid=None, context=None):
+ assert_uuid(uuid)
+ users_watch = users_watch or []
+
+ # complex stuff to determine the last message to show
+ users = self.pool.get("im.user")
+ my_id = users.get_by_user_id(cr, uid, uuid or uid, context=context)["id"]
+ c_user = users.browse(cr, openerp.SUPERUSER_ID, my_id, context=context)
+ if last:
+ if c_user.im_last_received < last:
+ users.write(cr, openerp.SUPERUSER_ID, my_id, {'im_last_received': last}, context=context)
+ else:
+ last = c_user.im_last_received or -1
+
+ # how fun it is to always need to reorder results from read
+ mess_ids = self.search(cr, openerp.SUPERUSER_ID, [['id', '>', last], ['to_id', '=', my_id]], order="id", context=context)
+ mess = self.read(cr, openerp.SUPERUSER_ID, mess_ids, ["id", "message", "from_id", "date"], context=context)
+ index = {}
+ for i in xrange(len(mess)):
+ index[mess[i]["id"]] = mess[i]
+ mess = []
+ for i in mess_ids:
+ mess.append(index[i])
+
+ if len(mess) > 0:
+ last = mess[-1]["id"]
+ users_status = users.read(cr, openerp.SUPERUSER_ID, users_watch, ["im_status"], context=context)
+ return {"res": mess, "last": last, "dbname": cr.dbname, "users_status": users_status}
+
+ def post(self, cr, uid, message, to_user_id, uuid=None, context=None):
+ assert_uuid(uuid)
+ my_id = self.pool.get('im.user').get_by_user_id(cr, uid, uuid or uid)["id"]
+ self.create(cr, openerp.SUPERUSER_ID, {"message": message, 'from_id': my_id, 'to_id': to_user_id}, context=context)
+ notify_channel(cr, "im_channel", {'type': 'message', 'receiver': to_user_id})
+ return False
+
+class im_user(osv.osv):
+ _name = "im.user"
+
+ def _im_status(self, cr, uid, ids, something, something_else, context=None):
+ res = {}
+ current = datetime.datetime.now()
+ delta = datetime.timedelta(0, DISCONNECTION_TIMER)
+ data = self.read(cr, openerp.SUPERUSER_ID, ids, ["im_last_status_update", "im_last_status"], context=context)
+ for obj in data:
+ last_update = datetime.datetime.strptime(obj["im_last_status_update"], DEFAULT_SERVER_DATETIME_FORMAT)
+ res[obj["id"]] = obj["im_last_status"] and (last_update + delta) > current
+ return res
+
+ def search_users(self, cr, uid, domain, fields, limit, context=None):
+ # do not user openerp.SUPERUSER_ID, reserved to normal users
+ found = self.pool.get('res.users').search(cr, uid, domain, limit=limit, context=context)
+ found = self.get_by_user_ids(cr, uid, found, context=context)
+ return self.read(cr, uid, found, fields, context=context)
+
+ def im_connect(self, cr, uid, uuid=None, context=None):
+ assert_uuid(uuid)
+ return self._im_change_status(cr, uid, True, uuid, context)
+
+ def im_disconnect(self, cr, uid, uuid=None, context=None):
+ assert_uuid(uuid)
+ return self._im_change_status(cr, uid, False, uuid, context)
+
+ def _im_change_status(self, cr, uid, new_one, uuid=None, context=None):
+ assert_uuid(uuid)
+ id = self.get_by_user_id(cr, uid, uuid or uid, context=context)["id"]
+ current_status = self.read(cr, openerp.SUPERUSER_ID, id, ["im_status"], context=None)["im_status"]
+ self.write(cr, openerp.SUPERUSER_ID, id, {"im_last_status": new_one,
+ "im_last_status_update": datetime.datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
+ if current_status != new_one:
+ notify_channel(cr, "im_channel", {'type': 'status', 'user': id})
+ return True
+
+ def get_by_user_id(self, cr, uid, id, context=None):
+ ids = self.get_by_user_ids(cr, uid, [id], context=context)
+ return ids[0]
+
+ def get_by_user_ids(self, cr, uid, ids, context=None):
+ user_ids = [x for x in ids if isinstance(x, int)]
+ uuids = [x for x in ids if isinstance(x, (str, unicode))]
+ users = self.search(cr, openerp.SUPERUSER_ID, ["|", ["user", "in", user_ids], ["uuid", "in", uuids]], context=None)
+ records = self.read(cr, openerp.SUPERUSER_ID, users, ["user", "uuid"], context=None)
+ inside = {}
+ for i in records:
+ if i["user"]:
+ inside[i["user"][0]] = True
+ elif ["uuid"]:
+ inside[i["uuid"]] = True
+ not_inside = {}
+ for i in ids:
+ if not (i in inside):
+ not_inside[i] = True
+ for to_create in not_inside.keys():
+ if isinstance(to_create, int):
+ created = self.create(cr, openerp.SUPERUSER_ID, {"user": to_create}, context=context)
+ records.append({"id": created, "user": [to_create, ""]})
+ else:
+ created = self.create(cr, openerp.SUPERUSER_ID, {"uuid": to_create}, context=context)
+ records.append({"id": created, "uuid": to_create})
+ return records
+
+ def assign_name(self, cr, uid, uuid, name, context=None):
+ assert_uuid(uuid)
+ id = self.get_by_user_id(cr, uid, uuid or uid, context=context)["id"]
+ self.write(cr, openerp.SUPERUSER_ID, id, {"assigned_name": name}, context=context)
+ return True
+
+ def _get_name(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for record in self.browse(cr, uid, ids, context=context):
+ res[record.id] = record.assigned_name
+ if record.user:
+ res[record.id] = record.user.name
+ continue
+ return res
+
+ _columns = {
+ 'name': fields.function(_get_name, type='char', size=200, string="Name", store=True, readonly=True),
+ 'assigned_name': fields.char(string="Assigned Name", size=200, required=False),
+ 'image': fields.related('user', 'image_small', type='binary', string="Image", readonly=True),
+ 'user': fields.many2one("res.users", string="User", select=True, ondelete='cascade'),
+ 'uuid': fields.char(string="UUID", size=50, select=True),
+ 'im_last_received': fields.integer(string="Instant Messaging Last Received Message"),
+ 'im_last_status': fields.boolean(strint="Instant Messaging Last Status"),
+ 'im_last_status_update': fields.datetime(string="Instant Messaging Last Status Update"),
+ 'im_status': fields.function(_im_status, string="Instant Messaging Status", type='boolean'),
+ }
+
+ _defaults = {
+ 'im_last_received': -1,
+ 'im_last_status': False,
+ 'im_last_status_update': lambda *args: datetime.datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
+ }
diff --git a/addons/im/security/im_security.xml b/addons/im/security/im_security.xml
new file mode 100644
index 00000000000..10297ac0669
--- /dev/null
+++ b/addons/im/security/im_security.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ Can only read messages that you sent or messages sent to you
+
+
+ ["|", ('to_id.user', '=', user.id), ('from_id.user', '=', user.id)]
+
+
+
+
+
+
+
+ Can only modify your user
+
+
+ [('user', '=', user.id)]
+
+
+
+
+
+
+
diff --git a/addons/im/security/ir.model.access.csv b/addons/im/security/ir.model.access.csv
new file mode 100644
index 00000000000..ed639353e21
--- /dev/null
+++ b/addons/im/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_im_message,im.message,model_im_message,base.group_user,1,0,1,0
+access_im_user,im.user,model_im_user,base.group_user,1,1,1,0
\ No newline at end of file
diff --git a/addons/im/static/src/audio/Ting.mp3 b/addons/im/static/src/audio/Ting.mp3
new file mode 100644
index 00000000000..6fd090a89ce
Binary files /dev/null and b/addons/im/static/src/audio/Ting.mp3 differ
diff --git a/addons/im/static/src/audio/Ting.ogg b/addons/im/static/src/audio/Ting.ogg
new file mode 100644
index 00000000000..8d17ea85bd3
Binary files /dev/null and b/addons/im/static/src/audio/Ting.ogg differ
diff --git a/addons/im/static/src/audio/purr.mp3 b/addons/im/static/src/audio/purr.mp3
new file mode 100644
index 00000000000..849d303c3b1
Binary files /dev/null and b/addons/im/static/src/audio/purr.mp3 differ
diff --git a/addons/im/static/src/audio/purr.ogg b/addons/im/static/src/audio/purr.ogg
new file mode 100644
index 00000000000..2ddc77537f1
Binary files /dev/null and b/addons/im/static/src/audio/purr.ogg differ
diff --git a/addons/im/static/src/css/im.css b/addons/im/static/src/css/im.css
new file mode 100644
index 00000000000..2f3e7dd58bb
--- /dev/null
+++ b/addons/im/static/src/css/im.css
@@ -0,0 +1,258 @@
+
+.openerp .oe_im {
+ position: fixed;
+ background-color: #E8EBEF;
+ width: 220px;
+ border-left: 1px solid #AEB9BD;
+}
+
+/* button */
+
+.openerp .oe_topbar_imbutton {
+ cursor: pointer;
+}
+
+/* search stuff */
+.openerp .oe_im_frame_header {
+ position: relative;
+ background: #dedede;
+ background: -moz-linear-gradient(#fcfcfc, #dedede);
+ background: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede));
+ border-bottom: 1px solid border-color !important;
+ padding: 5px;
+}
+.openerp .oe_im_frame_header .oe_im_searchbox {
+ width: 168px;
+ padding: 1px 21px 1px 19px;
+ font-size: 13px;
+ -moz-border-radius: 13px;
+ -webkit-border-radius: 13px;
+ border-radius: 13px;
+}
+.openerp .oe_im_frame_header .oe_im_search_icon {
+ position: absolute;
+ color: #888;
+ top: 2px;
+ left: 9px;
+ font-size: 28px;
+ font-family: "entypoRegular" !important;
+ font-weight: 300 !important;
+}
+.openerp .oe_im_frame_header .oe_im_search_clear {
+ display: none;
+ position: absolute;
+ right: 11px;
+ top: 4px;
+ font-size: 26px;
+ color: #b6b6b6;
+ cursor: pointer;
+}
+.openerp .oe_im_frame_header .oe_im_search_clear:hover {
+ color: #888;
+}
+
+/* users */
+
+.openerp .oe_im_users {
+ padding-bottom: 38px;
+}
+.openerp .oe_im_user {
+ position: relative;
+ padding: 2px 6px;
+ cursor: pointer;
+ font-size: 13px;
+ margin-bottom: 3px;
+}
+.openerp .oe_im_user:hover {
+ background: lightGrey;
+}
+.openerp .oe_im_user_clip {
+ display: inline-block;
+ width: 26px;
+ height: 26px;
+ margin-right: 4px;
+ -moz-box-shadow: 0 0 2px 1px rgba(0,0,0,0.25);
+ -webkit-box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.25);
+ box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.25);
+}
+.openerp .oe_im_user_avatar {
+ width: 26px;
+ height: auto;
+}
+.openerp .oe_im_user_name {
+ width: 162px;
+ line-height: 26px;
+ padding-right: 15px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ position: relative;
+}
+
+.openerp .oe_im_user_online {
+ display: none;
+ position: absolute;
+ top: 9.5px;
+ right: 11px;
+ width: 11px;
+ height: 11px;
+ vertical-align: middle;
+ border: 0;
+}
+
+/* conversations */
+
+.openerp .oe_im_chatview {
+ position: fixed;
+ overflow: hidden;
+ bottom: 6px;
+ margin-right: 6px;
+ background: rgba(60, 60, 60, 0.8);
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: 0 0 3px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.3);
+ -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.3);
+ width: 240px;
+}
+.openerp .oe_im_chatview .oe_im_chatview_disconnected {
+ display:none;
+ z-index: 100;
+ width: 100%;
+ background: #E8EBEF;
+ padding: 5px;
+ font-size: 11px;
+ color: #999;
+ line-height: 14px;
+ height: 28px;
+ overflow: hidden;
+}
+.openerp .oe_im_chatview.oe_im_chatview_disconnected_status .oe_im_chatview_disconnected {
+ display: block;
+}
+.openerp .oe_im_chatview .oe_im_chatview_header {
+ padding: 3px 6px 2px;
+ background: #DEDEDE;
+ background: -moz-linear-gradient(#FCFCFC, #DEDEDE);
+ background: -webkit-gradient(linear, left top, left bottom, from(#FCFCFC), to(#DEDEDE));
+ -moz-border-radius: 3px 3px 0 0;
+ -webkit-border-radius: 3px 3px 0 0;
+ border-radius: 3px 3px 0 0;
+ border-bottom: 1px solid #AEB9BD;
+ cursor: pointer;
+}
+.openerp .oe_im_chatview .oe_im_chatview_close {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+ font-size: 18px;
+ line-height: 16px;
+ float: right;
+ font-weight: bold;
+ color: black;
+ text-shadow: 0 1px 0 white;
+ opacity: 0.2;
+}
+.openerp .oe_im_chatview .oe_im_chatview_content {
+ overflow: auto;
+ height: 287px;
+}
+.openerp .oe_im_chatview.oe_im_chatview_disconnected_status .oe_im_chatview_content {
+ height: 249px;
+}
+.openerp .oe_im_chatview .oe_im_chatview_footer {
+ position: relative;
+ padding: 3px;
+ border-top: 1px solid #AEB9BD;
+ background: #DEDEDE;
+ background: -moz-linear-gradient(#FCFCFC, #DEDEDE);
+ background: -webkit-gradient(linear, left top, left bottom, from(#FCFCFC), to(#DEDEDE));
+ -moz-border-radius: 0 0 3px 3px;
+ -webkit-border-radius: 0 0 3px 3px;
+ border-radius: 0 0 3px 3px;
+}
+.openerp .oe_im_chatview .oe_im_chatview_input {
+ width: 222px;
+ font-family: Lato, Helvetica, sans-serif;
+ font-size: 13px;
+ color: #333;
+ padding: 1px 5px;
+ border: 1px solid #AEB9BD;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: inset 0 1px 4px rgba(0,0,0,0.2);
+ -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.2);
+}
+.openerp .oe_im_chatview .oe_im_chatview_bubble {
+ background: white;
+ position: relative;
+ padding: 3px;
+ margin: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+.openerp .oe_im_chatview .oe_im_chatview_clip {
+ position: relative;
+ float: left;
+ width: 26px;
+ height: 26px;
+ margin-right: 4px;
+ -moz-box-shadow: 0 0 2px 1px rgba(0,0,0,0.25);
+ -webkit-box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.25);
+ box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.25);
+}
+.openerp .oe_im_chatview .oe_im_chatview_avatar {
+ float: left;
+ width: 26px;
+ height: auto;
+ clip: rect(0, 26px, 26px, 0);
+ max-width: 100%;
+ width: auto 9;
+ height: auto;
+ vertical-align: middle;
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+.openerp .oe_im_chatview .oe_im_chatview_time {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+ margin: 3px;
+ text-align: right;
+ line-height: 13px;
+ font-size: 11px;
+ color: #999;
+ width: 60px;
+ overflow: hidden;
+}
+.openerp .oe_im_chatview .oe_im_chatview_from {
+ margin: 0 0 2px 0;
+ line-height: 14px;
+ font-weight: bold;
+ font-size: 12px;
+ width: 140px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ color: #3A87AD;
+}
+.openerp .oe_im_chatview .oe_im_chatview_bubble_list {
+}
+.openerp .oe_im_chatview .oe_im_chatview_bubble_item {
+ margin: 0 0 2px 30px;
+ line-height: 14px;
+ word-wrap: break-word;
+}
+
+.openerp .oe_im_chatview_online {
+ display: none;
+ margin-top: -4px;
+ width: 11px;
+ height: 11px;
+}
diff --git a/addons/im/static/src/img/avatar/avatar.jpeg b/addons/im/static/src/img/avatar/avatar.jpeg
new file mode 100644
index 00000000000..7168794022e
Binary files /dev/null and b/addons/im/static/src/img/avatar/avatar.jpeg differ
diff --git a/addons/im/static/src/img/button-gloss.png b/addons/im/static/src/img/button-gloss.png
new file mode 100755
index 00000000000..6f3957702fe
Binary files /dev/null and b/addons/im/static/src/img/button-gloss.png differ
diff --git a/addons/im/static/src/img/glyphicons-halflings-white.png b/addons/im/static/src/img/glyphicons-halflings-white.png
new file mode 100755
index 00000000000..3bf6484a29d
Binary files /dev/null and b/addons/im/static/src/img/glyphicons-halflings-white.png differ
diff --git a/addons/im/static/src/img/glyphicons-halflings.png b/addons/im/static/src/img/glyphicons-halflings.png
new file mode 100755
index 00000000000..a9969993201
Binary files /dev/null and b/addons/im/static/src/img/glyphicons-halflings.png differ
diff --git a/addons/im/static/src/img/green.png b/addons/im/static/src/img/green.png
new file mode 100644
index 00000000000..01fb373c251
Binary files /dev/null and b/addons/im/static/src/img/green.png differ
diff --git a/addons/im/static/src/img/icon.png b/addons/im/static/src/img/icon.png
new file mode 100644
index 00000000000..07d2503ce4e
Binary files /dev/null and b/addons/im/static/src/img/icon.png differ
diff --git a/addons/im/static/src/img/logo.png b/addons/im/static/src/img/logo.png
new file mode 100644
index 00000000000..aca5f4c60d8
Binary files /dev/null and b/addons/im/static/src/img/logo.png differ
diff --git a/addons/im/static/src/img/wood.png b/addons/im/static/src/img/wood.png
new file mode 100644
index 00000000000..22f2450d3ad
Binary files /dev/null and b/addons/im/static/src/img/wood.png differ
diff --git a/addons/im/static/src/js/im.js b/addons/im/static/src/js/im.js
new file mode 100644
index 00000000000..b21a339cb84
--- /dev/null
+++ b/addons/im/static/src/js/im.js
@@ -0,0 +1,463 @@
+
+openerp.im = function(instance) {
+
+ var USERS_LIMIT = 20;
+ var ERROR_DELAY = 5000;
+
+ var _t = instance.web._t,
+ _lt = instance.web._lt;
+ var QWeb = instance.web.qweb;
+
+ instance.web.UserMenu.include({
+ do_update: function(){
+ var self = this;
+ this.update_promise.then(function() {
+ var im = new instance.im.InstantMessaging(self);
+ im.appendTo(instance.client.$el);
+ var button = new instance.im.ImTopButton(this);
+ button.on("clicked", im, im.switch_display);
+ button.appendTo(instance.webclient.$el.find('.oe_systray'));
+ });
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ instance.im.ImTopButton = instance.web.Widget.extend({
+ template:'ImTopButton',
+ events: {
+ "click": "clicked",
+ },
+ clicked: function() {
+ this.trigger("clicked");
+ },
+ });
+
+ instance.im.InstantMessaging = instance.web.Widget.extend({
+ template: "InstantMessaging",
+ events: {
+ "keydown .oe_im_searchbox": "input_change",
+ "keyup .oe_im_searchbox": "input_change",
+ "change .oe_im_searchbox": "input_change",
+ },
+ init: function(parent) {
+ this._super(parent);
+ this.shown = false;
+ this.set("right_offset", 0);
+ this.set("current_search", "");
+ this.users = [];
+ this.c_manager = new instance.im.ConversationManager(this);
+ this.on("change:right_offset", this.c_manager, _.bind(function() {
+ this.c_manager.set("right_offset", this.get("right_offset"));
+ }, this));
+ this.user_search_dm = new instance.web.DropMisordered();
+ },
+ start: function() {
+ this.$el.css("right", -this.$el.outerWidth());
+ $(window).scroll(_.bind(this.calc_box, this));
+ $(window).resize(_.bind(this.calc_box, this));
+ this.calc_box();
+
+ this.on("change:current_search", this, this.search_changed);
+ this.search_changed();
+
+ var self = this;
+
+ return this.c_manager.start_polling();
+ },
+ calc_box: function() {
+ var $topbar = instance.client.$(".oe_topbar");
+ var top = $topbar.offset().top + $topbar.height();
+ top = Math.max(top - $(window).scrollTop(), 0);
+ this.$el.css("top", top);
+ this.$el.css("bottom", 0);
+ },
+ input_change: function() {
+ this.set("current_search", this.$(".oe_im_searchbox").val());
+ },
+ search_changed: function(e) {
+ var users = new instance.web.Model("im.user");
+ var self = this;
+ return this.user_search_dm.add(users.call("search_users",
+ [[["name", "ilike", this.get("current_search")], ["id", "<>", instance.session.uid]],
+ ["name", "user", "uuid", "im_status"], USERS_LIMIT], {context:new instance.web.CompoundContext()})).then(function(result) {
+ self.c_manager.add_to_user_cache(result);
+ self.$(".oe_im_input").val("");
+ var old_users = self.users;
+ self.users = [];
+ _.each(result, function(user) {
+ var widget = new instance.im.UserWidget(self, self.c_manager.get_user(user.id));
+ widget.appendTo(self.$(".oe_im_users"));
+ widget.on("activate_user", self, self.activate_user);
+ self.users.push(widget);
+ });
+ _.each(old_users, function(user) {
+ user.destroy();
+ });
+ });
+ },
+ switch_display: function() {
+ var fct = _.bind(function(place) {
+ this.set("right_offset", place + this.$el.outerWidth());
+ }, this);
+ var opt = {
+ step: fct,
+ };
+ if (this.shown) {
+ this.$el.animate({
+ right: -this.$el.outerWidth(),
+ }, opt);
+ } else {
+ if (! this.c_manager.get_activated()) {
+ this.do_warn("Instant Messaging is not activated on this server.", "");
+ return;
+ }
+ this.$el.animate({
+ right: 0,
+ }, opt);
+ }
+ this.shown = ! this.shown;
+ },
+ activate_user: function(user) {
+ this.c_manager.activate_user(user, true);
+ },
+ });
+
+ instance.im.UserWidget = instance.web.Widget.extend({
+ "template": "UserWidget",
+ events: {
+ "click": "activate_user",
+ },
+ init: function(parent, user) {
+ this._super(parent);
+ this.user = user;
+ this.user.add_watcher();
+ },
+ start: function() {
+ var change_status = function() {
+ this.$(".oe_im_user_online").toggle(this.user.get("im_status") === true);
+ };
+ this.user.on("change:im_status", this, change_status);
+ change_status.call(this);
+ },
+ activate_user: function() {
+ this.trigger("activate_user", this.user);
+ },
+ destroy: function() {
+ this.user.remove_watcher();
+ this._super();
+ },
+ });
+
+ instance.im.ImUser = instance.web.Class.extend(instance.web.PropertiesMixin, {
+ init: function(parent, user_rec) {
+ instance.web.PropertiesMixin.init.call(this, parent);
+ user_rec.image_url = instance.session.url("/im/static/src/img/avatar/avatar.jpeg");
+ if (user_rec.user)
+ user_rec.image_url = instance.session.url('/web/binary/image', {model:'res.users', field: 'image_small', id: user_rec.user[0]});
+ this.set(user_rec);
+ this.set("watcher_count", 0);
+ this.on("change:watcher_count", this, function() {
+ if (this.get("watcher_count") === 0)
+ this.destroy();
+ });
+ },
+ destroy: function() {
+ this.trigger("destroyed");
+ instance.web.PropertiesMixin.destroy.call(this);
+ },
+ add_watcher: function() {
+ this.set("watcher_count", this.get("watcher_count") + 1);
+ },
+ remove_watcher: function() {
+ this.set("watcher_count", this.get("watcher_count") - 1);
+ },
+ });
+
+ instance.im.ConversationManager = instance.web.Controller.extend({
+ init: function(parent) {
+ this._super(parent);
+ this.set("right_offset", 0);
+ this.conversations = [];
+ this.users = {};
+ this.on("change:right_offset", this, this.calc_positions);
+ this.set("window_focus", true);
+ this.set("waiting_messages", 0);
+ this.focus_hdl = _.bind(function() {
+ this.set("window_focus", true);
+ }, this);
+ $(window).bind("focus", this.focus_hdl);
+ this.blur_hdl = _.bind(function() {
+ this.set("window_focus", false);
+ }, this);
+ $(window).bind("blur", this.blur_hdl);
+ this.on("change:window_focus", this, this.window_focus_change);
+ this.window_focus_change();
+ this.on("change:waiting_messages", this, this.messages_change);
+ this.messages_change();
+ this.create_ting();
+ this.activated = false;
+ this.users_cache = {};
+ this.last = null;
+ this.unload_event_handler = _.bind(this.unload, this);
+ },
+ start_polling: function() {
+ var self = this;
+ return new instance.web.Model("im.user").call("get_by_user_id", [instance.session.uid]).then(function(my_id) {
+ self.my_id = my_id["id"];
+ return self.ensure_users([self.my_id]).then(function() {
+ var me = self.users_cache[self.my_id];
+ delete self.users_cache[self.my_id];
+ self.me = me;
+ self.rpc("/longpolling/im/activated", {}, {shadow: true}).then(function(activated) {
+ if (activated) {
+ self.activated = true;
+ $(window).on("unload", self.unload_event_handler);
+ self.poll();
+ }
+ }, function(a, e) {
+ e.preventDefault();
+ });
+ });
+ });
+ },
+ unload: function() {
+ return new instance.web.Model("im.user").call("im_disconnect", [], {context: new instance.web.CompoundContext()});
+ },
+ ensure_users: function(user_ids) {
+ var no_cache = {};
+ _.each(user_ids, function(el) {
+ if (! this.users_cache[el])
+ no_cache[el] = el;
+ }, this);
+ var self = this;
+ if (_.size(no_cache) === 0)
+ return $.when();
+ else
+ return new instance.web.Model("im.user").call("read", [_.values(no_cache), ["name", "user", "uuid", "im_status"]],
+ {context: new instance.web.CompoundContext()}).then(function(users) {
+ self.add_to_user_cache(users);
+ });
+ },
+ add_to_user_cache: function(user_recs) {
+ _.each(user_recs, function(user_rec) {
+ if (! this.users_cache[user_rec.id]) {
+ var user = new instance.im.ImUser(this, user_rec);
+ this.users_cache[user_rec.id] = user;
+ user.on("destroyed", this, function() {
+ delete this.users_cache[user_rec.id];
+ });
+ }
+ }, this);
+ },
+ get_user: function(user_id) {
+ return this.users_cache[user_id];
+ },
+ poll: function() {
+ var self = this;
+ var user_ids = _.map(this.users_cache, function(el) {
+ return el.get("id");
+ });
+ this.rpc("/longpolling/im/poll", {
+ last: this.last,
+ users_watch: user_ids,
+ context: instance.web.pyeval.eval('context', {}),
+ }, {shadow: true}).then(function(result) {
+ _.each(result.users_status, function(el) {
+ if (self.get_user(el.id))
+ self.get_user(el.id).set(el);
+ });
+ self.last = result.last;
+ var user_ids = _.pluck(_.pluck(result.res, "from_id"), 0);
+ self.ensure_users(user_ids).then(function() {
+ _.each(result.res, function(mes) {
+ var user = self.get_user(mes.from_id[0]);
+ self.received_message(mes, user);
+ });
+ self.poll();
+ });
+ }, function(unused, e) {
+ e.preventDefault();
+ setTimeout(_.bind(self.poll, self), ERROR_DELAY);
+ });
+ },
+ get_activated: function() {
+ return this.activated;
+ },
+ create_ting: function() {
+ var kitten = jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined;
+ this.ting = new Audio(instance.webclient.session.origin + "/im/static/src/audio/" + (kitten ? "purr" : "Ting") +
+ (new Audio().canPlayType("audio/ogg; codecs=vorbis") ? ".ogg" : ".mp3"));
+ },
+ window_focus_change: function() {
+ if (this.get("window_focus")) {
+ this.set("waiting_messages", 0);
+ }
+ },
+ messages_change: function() {
+ if (! instance.webclient.set_title_part)
+ return;
+ instance.webclient.set_title_part("aa_im_messages", this.get("waiting_messages") === 0 ? undefined :
+ _.str.sprintf(_t("%d Messages"), this.get("waiting_messages")));
+ },
+ activate_user: function(user, focus) {
+ var conv = this.users[user.get('id')];
+ if (! conv) {
+ conv = new instance.im.Conversation(this, user, this.me);
+ conv.appendTo(instance.client.$el);
+ conv.on("destroyed", this, function() {
+ this.conversations = _.without(this.conversations, conv);
+ delete this.users[conv.user.get('id')];
+ this.calc_positions();
+ });
+ this.conversations.push(conv);
+ this.users[user.get('id')] = conv;
+ this.calc_positions();
+ }
+ if (focus)
+ conv.focus();
+ return conv;
+ },
+ received_message: function(message, user) {
+ if (! this.get("window_focus")) {
+ this.set("waiting_messages", this.get("waiting_messages") + 1);
+ this.ting.play();
+ this.create_ting();
+ }
+ var conv = this.activate_user(user);
+ conv.received_message(message);
+ },
+ calc_positions: function() {
+ var current = this.get("right_offset");
+ _.each(_.range(this.conversations.length), function(i) {
+ this.conversations[i].set("right_position", current);
+ current += this.conversations[i].$el.outerWidth(true);
+ }, this);
+ },
+ destroy: function() {
+ $(window).off("unload", this.unload_event_handler);
+ $(window).unbind("blur", this.blur_hdl);
+ $(window).unbind("focus", this.focus_hdl);
+ this._super();
+ },
+ });
+
+ instance.im.Conversation = instance.web.Widget.extend({
+ "template": "Conversation",
+ events: {
+ "keydown input": "send_message",
+ "click .oe_im_chatview_close": "destroy",
+ "click .oe_im_chatview_header": "show_hide",
+ },
+ init: function(parent, user, me) {
+ this._super(parent);
+ this.me = me;
+ this.user = user;
+ this.user.add_watcher();
+ this.set("right_position", 0);
+ this.shown = true;
+ this.set("pending", 0);
+ },
+ start: function() {
+ var change_status = function() {
+ this.$el.toggleClass("oe_im_chatview_disconnected_status", this.user.get("im_status") === false);
+ this.$(".oe_im_chatview_online").toggle(this.user.get("im_status") === true);
+ this._go_bottom();
+ };
+ this.user.on("change:im_status", this, change_status);
+ change_status.call(this);
+
+ this.on("change:right_position", this, this.calc_pos);
+ this.full_height = this.$el.height();
+ this.calc_pos();
+ this.on("change:pending", this, _.bind(function() {
+ if (this.get("pending") === 0) {
+ this.$(".oe_im_chatview_nbr_messages").text("");
+ } else {
+ this.$(".oe_im_chatview_nbr_messages").text("(" + this.get("pending") + ")");
+ }
+ }, this));
+ },
+ show_hide: function() {
+ if (this.shown) {
+ this.$el.animate({
+ height: this.$(".oe_im_chatview_header").outerHeight(),
+ });
+ } else {
+ this.$el.animate({
+ height: this.full_height,
+ });
+ }
+ this.shown = ! this.shown;
+ if (this.shown) {
+ this.set("pending", 0);
+ }
+ },
+ calc_pos: function() {
+ this.$el.css("right", this.get("right_position"));
+ },
+ received_message: function(message) {
+ if (this.shown) {
+ this.set("pending", 0);
+ } else {
+ this.set("pending", this.get("pending") + 1);
+ }
+ this._add_bubble(this.user, message.message, message.date);
+ },
+ send_message: function(e) {
+ if(e && e.which !== 13) {
+ return;
+ }
+ var mes = this.$("input").val();
+ this.$("input").val("");
+ var send_it = _.bind(function() {
+ var model = new instance.web.Model("im.message");
+ return model.call("post", [mes, this.user.get('id')],
+ {context: new instance.web.CompoundContext()});
+ }, this);
+ var tries = 0;
+ send_it().then(_.bind(function() {
+ this._add_bubble(this.me, mes, instance.web.datetime_to_str(new Date()));
+ }, this), function(error, e) {
+ e.preventDefault();
+ tries += 1;
+ if (tries < 3)
+ return send_it();
+ });
+ },
+ _add_bubble: function(user, item, date) {
+ var items = [item];
+ if (user === this.last_user) {
+ this.last_bubble.remove();
+ items = this.last_items.concat(items);
+ }
+ this.last_user = user;
+ this.last_items = items;
+ date = instance.web.str_to_datetime(date);
+ var now = new Date();
+ var diff = now - date;
+ if (diff > (1000 * 60 * 60 * 24)) {
+ date = $.timeago(date);
+ } else {
+ date = date.toString(Date.CultureInfo.formatPatterns.shortTime);
+ }
+
+ this.last_bubble = $(QWeb.render("Conversation.bubble", {"items": items, "user": user, "time": date}));
+ $(this.$(".oe_im_chatview_content").children()[0]).append(this.last_bubble);
+ this._go_bottom();
+ },
+ _go_bottom: function() {
+ this.$(".oe_im_chatview_content").scrollTop($(this.$(".oe_im_chatview_content").children()[0]).height());
+ },
+ focus: function() {
+ this.$(".oe_im_chatview_input").focus();
+ if (! this.shown)
+ this.show_hide();
+ },
+ destroy: function() {
+ this.user.remove_watcher();
+ this.trigger("destroyed");
+ return this._super();
+ },
+ });
+
+}
\ No newline at end of file
diff --git a/addons/im/static/src/xml/im.xml b/addons/im/static/src/xml/im.xml
new file mode 100644
index 00000000000..795d1b3e698
--- /dev/null
+++ b/addons/im/static/src/xml/im.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+ ô
+
+ [
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/im_livechat/__init__.py b/addons/im_livechat/__init__.py
new file mode 100644
index 00000000000..2825a75179c
--- /dev/null
+++ b/addons/im_livechat/__init__.py
@@ -0,0 +1,2 @@
+
+import im_livechat
diff --git a/addons/im_livechat/__openerp__.py b/addons/im_livechat/__openerp__.py
new file mode 100644
index 00000000000..8b9ea3924d5
--- /dev/null
+++ b/addons/im_livechat/__openerp__.py
@@ -0,0 +1,29 @@
+{
+ 'name' : 'Live Support',
+ 'version': '1.0',
+ 'summary': 'Live Chat with Visitors/Customers',
+ 'category': 'Tools',
+ 'complexity': 'easy',
+ 'description':
+ """
+Live Chat Support
+=================
+
+Allow to drop instant messaging widgets on any web page that will communicate
+with the current server and dispatch visitors request amongst several live
+chat operators.
+
+ """,
+ 'data': [
+ "security/im_livechat_security.xml",
+ "security/ir.model.access.csv",
+ "im_livechat_view.xml",
+ ],
+ 'demo': [
+ "im_livechat_demo.xml",
+ ],
+ 'depends' : ["im", "mail", "portal_anonymous"],
+ 'installable': True,
+ 'auto_install': False,
+ 'application': True,
+}
diff --git a/addons/im_livechat/im_livechat.py b/addons/im_livechat/im_livechat.py
new file mode 100644
index 00000000000..1ffb422fe6a
--- /dev/null
+++ b/addons/im_livechat/im_livechat.py
@@ -0,0 +1,245 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import openerp
+import openerp.addons.im.im as im
+import json
+import random
+import jinja2
+from openerp.osv import osv, fields
+from openerp import tools
+
+env = jinja2.Environment(
+ loader=jinja2.PackageLoader('openerp.addons.im_livechat', "."),
+ autoescape=False
+)
+env.filters["json"] = json.dumps
+
+class LiveChatController(openerp.addons.web.http.Controller):
+ _cp_path = '/im_livechat'
+
+ @openerp.addons.web.http.httprequest
+ def loader(self, req, **kwargs):
+ p = json.loads(kwargs["p"])
+ db = p["db"]
+ channel = p["channel"]
+ user_name = p.get("user_name", None)
+ req.session._db = db
+ req.session._uid = None
+ req.session._login = "anonymous"
+ req.session._password = "anonymous"
+ info = req.session.model('im_livechat.channel').get_info_for_chat_src(channel)
+ info["db"] = db
+ info["channel"] = channel
+ info["userName"] = user_name
+ return req.make_response(env.get_template("loader.js").render(info),
+ headers=[('Content-Type', "text/javascript")])
+
+ @openerp.addons.web.http.httprequest
+ def web_page(self, req, **kwargs):
+ p = json.loads(kwargs["p"])
+ db = p["db"]
+ channel = p["channel"]
+ req.session._db = db
+ req.session._uid = None
+ req.session._login = "anonymous"
+ req.session._password = "anonymous"
+ script = req.session.model('im_livechat.channel').read(channel, ["script"])["script"]
+ info = req.session.model('im_livechat.channel').get_info_for_chat_src(channel)
+ info["script"] = script
+ return req.make_response(env.get_template("web_page.html").render(info),
+ headers=[('Content-Type', "text/html")])
+
+ @openerp.addons.web.http.jsonrequest
+ def available(self, req, db, channel):
+ req.session._db = db
+ req.session._uid = None
+ req.session._login = "anonymous"
+ req.session._password = "anonymous"
+ return req.session.model('im_livechat.channel').get_available_user(channel) > 0
+
+class im_livechat_channel(osv.osv):
+ _name = 'im_livechat.channel'
+
+ def _get_default_image(self, cr, uid, context=None):
+ image_path = openerp.modules.get_module_resource('im_livechat', 'static/src/img', 'default.png')
+ return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
+ def _get_image(self, cr, uid, ids, name, args, context=None):
+ result = dict.fromkeys(ids, False)
+ for obj in self.browse(cr, uid, ids, context=context):
+ result[obj.id] = tools.image_get_resized_images(obj.image)
+ return result
+ def _set_image(self, cr, uid, id, name, value, args, context=None):
+ return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
+
+
+ def _are_you_inside(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for record in self.browse(cr, uid, ids, context=context):
+ res[record.id] = False
+ for user in record.user_ids:
+ if user.id == uid:
+ res[record.id] = True
+ break
+ return res
+
+ def _script(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for record in self.browse(cr, uid, ids, context=context):
+ res[record.id] = env.get_template("include.html").render({
+ "url": self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url'),
+ "parameters": {"db":cr.dbname, "channel":record.id},
+ })
+ return res
+
+ def _web_page(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for record in self.browse(cr, uid, ids, context=context):
+ res[record.id] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url') + \
+ "/im_livechat/web_page?p=" + json.dumps({"db":cr.dbname, "channel":record.id})
+ return res
+
+ _columns = {
+ 'name': fields.char(string="Channel Name", size=200, required=True),
+ 'user_ids': fields.many2many('res.users', 'im_livechat_channel_im_user', 'channel_id', 'user_id', string="Users"),
+ 'are_you_inside': fields.function(_are_you_inside, type='boolean', string='Are you inside the matrix?', store=False),
+ 'script': fields.function(_script, type='text', string='Script', store=False),
+ 'web_page': fields.function(_web_page, type='url', string='Web Page', store=False, size="200"),
+ 'button_text': fields.char(string="Text of the Button", size=200),
+ 'input_placeholder': fields.char(string="Chat Input Placeholder", size=200),
+ 'default_message': fields.char(string="Welcome Message", size=200, help="This is an automated 'welcome' message that your visitor will see when they initiate a new chat session."),
+ # image: all image fields are base64 encoded and PIL-supported
+ 'image': fields.binary("Photo",
+ help="This field holds the image used as photo for the group, limited to 1024x1024px."),
+ 'image_medium': fields.function(_get_image, fnct_inv=_set_image,
+ string="Medium-sized photo", type="binary", multi="_get_image",
+ store={
+ 'im_livechat.channel': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+ },
+ help="Medium-sized photo of the group. It is automatically "\
+ "resized as a 128x128px image, with aspect ratio preserved. "\
+ "Use this field in form views or some kanban views."),
+ 'image_small': fields.function(_get_image, fnct_inv=_set_image,
+ string="Small-sized photo", type="binary", multi="_get_image",
+ store={
+ 'im_livechat.channel': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+ },
+ help="Small-sized photo of the group. It is automatically "\
+ "resized as a 64x64px image, with aspect ratio preserved. "\
+ "Use this field anywhere a small image is required."),
+ }
+
+ def _default_user_ids(self, cr, uid, context=None):
+ return [(6, 0, [uid])]
+
+ _defaults = {
+ 'button_text': "Have a Question? Chat with us.",
+ 'input_placeholder': "How may I help you?",
+ 'default_message': '',
+ 'user_ids': _default_user_ids,
+ 'image': _get_default_image,
+ }
+
+ def get_available_user(self, cr, uid, channel_id, context=None):
+ channel = self.browse(cr, openerp.SUPERUSER_ID, channel_id, context=context)
+ users = []
+ for user in channel.user_ids:
+ iuid = self.pool.get("im.user").get_by_user_id(cr, uid, user.id, context=context)["id"]
+ imuser = self.pool.get("im.user").browse(cr, uid, iuid, context=context)
+ if imuser.im_status:
+ users.append(imuser)
+ if len(users) == 0:
+ return False
+ return random.choice(users).id
+
+ def test_channel(self, cr, uid, channel, context=None):
+ if not channel:
+ return {}
+ return {
+ 'url': self.browse(cr, uid, channel[0], context=context or {}).web_page,
+ 'type': 'ir.actions.act_url'
+ }
+
+ def get_info_for_chat_src(self, cr, uid, channel, context=None):
+ url = self.pool.get('ir.config_parameter').get_param(cr, openerp.SUPERUSER_ID, 'web.base.url')
+ chan = self.browse(cr, uid, channel, context=context)
+ return {
+ "url": url,
+ 'buttonText': chan.button_text,
+ 'inputPlaceholder': chan.input_placeholder,
+ 'defaultMessage': chan.default_message,
+ "channelName": chan.name,
+ }
+
+ def join(self, cr, uid, ids, context=None):
+ self.write(cr, uid, ids, {'user_ids': [(4, uid)]})
+ return True
+
+ def quit(self, cr, uid, ids, context=None):
+ self.write(cr, uid, ids, {'user_ids': [(3, uid)]})
+ return True
+
+
+class im_message(osv.osv):
+ _inherit = 'im.message'
+
+ def _support_member(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for record in self.browse(cr, uid, ids, context=context):
+ res[record.id] = False
+ if record.to_id.user and record.from_id.user:
+ continue
+ elif record.to_id.user:
+ res[record.id] = record.to_id.user.id
+ elif record.from_id.user:
+ res[record.id] = record.from_id.user.id
+ return res
+
+ def _customer(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for record in self.browse(cr, uid, ids, context=context):
+ res[record.id] = False
+ if record.to_id.uuid and record.from_id.uuid:
+ continue
+ elif record.to_id.uuid:
+ res[record.id] = record.to_id.id
+ elif record.from_id.uuid:
+ res[record.id] = record.from_id.id
+ return res
+
+ def _direction(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for record in self.browse(cr, uid, ids, context=context):
+ res[record.id] = False
+ if not not record.to_id.user and not not record.from_id.user:
+ continue
+ elif not not record.to_id.user:
+ res[record.id] = "c2s"
+ elif not not record.from_id.user:
+ res[record.id] = "s2c"
+ return res
+
+ _columns = {
+ 'support_member_id': fields.function(_support_member, type='many2one', relation='res.users', string='Support Member', store=True, select=True),
+ 'customer_id': fields.function(_customer, type='many2one', relation='im.user', string='Customer', store=True, select=True),
+ 'direction': fields.function(_direction, type="selection", selection=[("s2c", "Support Member to Customer"), ("c2s", "Customer to Support Member")],
+ string='Direction', store=False),
+ }
diff --git a/addons/im_livechat/im_livechat_demo.xml b/addons/im_livechat/im_livechat_demo.xml
new file mode 100644
index 00000000000..f199179fb50
--- /dev/null
+++ b/addons/im_livechat/im_livechat_demo.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ YourWebsite.com
+ Hello, how may I help you?
+
+
+
+
+
+
+
+
diff --git a/addons/im_livechat/im_livechat_view.xml b/addons/im_livechat/im_livechat_view.xml
new file mode 100644
index 00000000000..f684fd561fc
--- /dev/null
+++ b/addons/im_livechat/im_livechat_view.xml
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+ Live Chat Channels
+ im_livechat.channel
+ kanban,form
+
+
+ Click to define a new live chat channel.
+
+ You can create channels for each website on which you want
+ to integrate the live chat widget, allowing you website
+ visitors to talk in real time with your operators.
+
+ Each channel has it's own URL that you can send by email to
+ your customers in order to start chatting with you.
+
+
+
+
+
+
+
+
+
+ support_channel.form
+ im_livechat.channel
+
+
+
+
+
+
+ History
+ im.message
+ list
+ ["|", ('to_id.user', '=', None), ('from_id.user', '=', None)]
+
+
+
+
+ im.message.tree
+ im.message
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/im_livechat/include.html b/addons/im_livechat/include.html
new file mode 100644
index 00000000000..55de6212361
--- /dev/null
+++ b/addons/im_livechat/include.html
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/addons/im_livechat/loader.js b/addons/im_livechat/loader.js
new file mode 100644
index 00000000000..669591b410f
--- /dev/null
+++ b/addons/im_livechat/loader.js
@@ -0,0 +1,24 @@
+
+require.config({
+ context: "oelivesupport",
+ baseUrl: {{url | json}} + "/im_livechat/static/ext/static/js",
+ shim: {
+ underscore: {
+ init: function() {
+ return _.noConflict();
+ },
+ },
+ "jquery.achtung": {
+ deps: ['jquery'],
+ },
+ },
+})(["livesupport", "jquery"], function(livesupport, jQuery) {
+ jQuery.noConflict();
+ livesupport.main({{url | json}}, {{db | json}}, "anonymous", "anonymous", {{channel | json}}, {
+ buttonText: {{buttonText | json}},
+ inputPlaceholder: {{inputPlaceholder | json}},
+ defaultMessage: {{(defaultMessage or None) | json}},
+ auto: window.oe_im_livechat_auto || false,
+ userName: {{userName | json}} || undefined,
+ });
+});
diff --git a/addons/im_livechat/security/im_livechat_security.xml b/addons/im_livechat/security/im_livechat_security.xml
new file mode 100644
index 00000000000..5ad020a8a78
--- /dev/null
+++ b/addons/im_livechat/security/im_livechat_security.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+ Live Support
+
+
+
+
+ User
+
+ The user will be able to join support channels.
+
+
+
+ Manager
+ The user will be able to delete support channels.
+
+
+
+
+
+
+ Live Support Managers can read messages from live support
+
+
+ ["|", ('to_id.user', '=', None), ('from_id.user', '=', None)]
+
+
+
+
+
+
+
+
diff --git a/addons/im_livechat/security/ir.model.access.csv b/addons/im_livechat/security/ir.model.access.csv
new file mode 100644
index 00000000000..6e17c1a127f
--- /dev/null
+++ b/addons/im_livechat/security/ir.model.access.csv
@@ -0,0 +1,6 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_ls_chann1,im_livechat.channel,model_im_livechat_channel,,1,0,0,0
+access_ls_chann2,im_livechat.channel,model_im_livechat_channel,group_im_livechat,1,1,1,0
+access_ls_chann3,im_livechat.channel,model_im_livechat_channel,group_im_livechat_manager,1,1,1,1
+access_ls_message,im_livechat.im.message,im.model_im_message,portal.group_anonymous,0,0,0,0
+access_im_user,im_livechat.im.user,im.model_im_user,portal.group_anonymous,1,0,0,0
\ No newline at end of file
diff --git a/addons/im_livechat/static/ext/Makefile b/addons/im_livechat/static/ext/Makefile
new file mode 100644
index 00000000000..b73ca4f2b89
--- /dev/null
+++ b/addons/im_livechat/static/ext/Makefile
@@ -0,0 +1,3 @@
+
+static/js/livesupport_templates.js: static/js/livesupport_templates.html
+ python static/js/to_jsonp.py static/js/livesupport_templates.html oe_livesupport_templates_callback > static/js/livesupport_templates.js
\ No newline at end of file
diff --git a/addons/im_livechat/static/ext/static/audio/Ting.mp3 b/addons/im_livechat/static/ext/static/audio/Ting.mp3
new file mode 100644
index 00000000000..6fd090a89ce
Binary files /dev/null and b/addons/im_livechat/static/ext/static/audio/Ting.mp3 differ
diff --git a/addons/im_livechat/static/ext/static/audio/Ting.ogg b/addons/im_livechat/static/ext/static/audio/Ting.ogg
new file mode 100644
index 00000000000..8d17ea85bd3
Binary files /dev/null and b/addons/im_livechat/static/ext/static/audio/Ting.ogg differ
diff --git a/addons/im_livechat/static/ext/static/css/livesupport.css b/addons/im_livechat/static/ext/static/css/livesupport.css
new file mode 100644
index 00000000000..bfe26b5e838
--- /dev/null
+++ b/addons/im_livechat/static/ext/static/css/livesupport.css
@@ -0,0 +1,190 @@
+
+
+
+.openerp_style { /* base style of openerp */
+ font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif;
+ color: #4c4c4c;
+ font-size: 13px;
+ background: white;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
+}
+
+/* button */
+
+.oe_chat_button {
+ position: fixed;
+ bottom: 0px;
+ right: 6px;
+ display: inline-block;
+ min-width: 100px;
+ background-color: rgba(60, 60, 60, 0.6);
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, Verdana, sans-serif;
+ font-size: 14px;
+ font-weight: bold;
+ padding: 10px;
+ color: white;
+ text-shadow: rgb(59, 76, 88) 1px 1px 0px;
+ border: 1px solid rgb(80, 80, 80);
+ border-bottom: 0px;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ cursor: pointer;
+}
+
+/* conversations */
+
+.oe_im_chatview {
+ position: fixed;
+ overflow: hidden;
+ bottom: 42px;
+ margin-right: 6px;
+ background: rgba(60, 60, 60, 0.8);
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: 0 0 3px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.3);
+ -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.3);
+ width: 240px;
+}
+.oe_im_chatview .oe_im_chatview_disconnected {
+ display:none;
+ z-index: 100;
+ width: 100%;
+ background: #E8EBEF;
+ padding: 5px;
+ font-size: 11px;
+ color: #999;
+ line-height: 14px;
+ height: 28px;
+ overflow: hidden;
+}
+.oe_im_chatview.oe_im_chatview_disconnected_status .oe_im_chatview_disconnected {
+ display: block;
+}
+.oe_im_chatview .oe_im_chatview_header {
+ padding: 3px 6px 2px;
+ background: #DEDEDE;
+ background: -moz-linear-gradient(#FCFCFC, #DEDEDE);
+ background: -webkit-gradient(linear, left top, left bottom, from(#FCFCFC), to(#DEDEDE));
+ -moz-border-radius: 3px 3px 0 0;
+ -webkit-border-radius: 3px 3px 0 0;
+ border-radius: 3px 3px 0 0;
+ border-bottom: 1px solid #AEB9BD;
+ cursor: pointer;
+}
+.oe_im_chatview .oe_im_chatview_close {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+ font-size: 18px;
+ line-height: 16px;
+ float: right;
+ font-weight: bold;
+ color: black;
+ text-shadow: 0 1px 0 white;
+ opacity: 0.2;
+}
+.oe_im_chatview .oe_im_chatview_content {
+ overflow: auto;
+ height: 287px;
+ width: 240px;
+}
+.oe_im_chatview.oe_im_chatview_disconnected_status .oe_im_chatview_content {
+ height: 249px;
+}
+.oe_im_chatview .oe_im_chatview_footer {
+ position: relative;
+ padding: 3px;
+ border-top: 1px solid #AEB9BD;
+ background: #DEDEDE;
+ background: -moz-linear-gradient(#FCFCFC, #DEDEDE);
+ background: -webkit-gradient(linear, left top, left bottom, from(#FCFCFC), to(#DEDEDE));
+ -moz-border-radius: 0 0 3px 3px;
+ -webkit-border-radius: 0 0 3px 3px;
+ border-radius: 0 0 3px 3px;
+}
+.oe_im_chatview .oe_im_chatview_input {
+ width: 222px;
+ font-family: Lato, Helvetica, sans-serif;
+ font-size: 13px;
+ color: #333;
+ padding: 1px 5px;
+ border: 1px solid #AEB9BD;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: inset 0 1px 4px rgba(0,0,0,0.2);
+ -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.2);
+}
+.oe_im_chatview .oe_im_chatview_bubble {
+ background: white;
+ position: relative;
+ padding: 3px;
+ margin: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+.oe_im_chatview .oe_im_chatview_clip {
+ position: relative;
+ float: left;
+ width: 26px;
+ height: 26px;
+ margin-right: 4px;
+ -moz-box-shadow: 0 0 2px 1px rgba(0,0,0,0.25);
+ -webkit-box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.25);
+ box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.25);
+}
+.oe_im_chatview .oe_im_chatview_avatar {
+ float: left;
+ width: 26px;
+ height: auto;
+ clip: rect(0, 26px, 26px, 0);
+ max-width: 100%;
+ width: auto 9;
+ height: auto;
+ vertical-align: middle;
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+.oe_im_chatview .oe_im_chatview_time {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+ margin: 3px;
+ text-align: right;
+ line-height: 13px;
+ font-size: 11px;
+ color: #999;
+ width: 60px;
+ overflow: hidden;
+}
+.oe_im_chatview .oe_im_chatview_from {
+ margin: 0 0 2px 0;
+ line-height: 14px;
+ font-weight: bold;
+ font-size: 12px;
+ width: 140px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ color: #3A87AD;
+}
+.oe_im_chatview .oe_im_chatview_bubble_list {
+}
+.oe_im_chatview .oe_im_chatview_bubble_item {
+ margin: 0 0 2px 30px;
+ line-height: 14px;
+ word-wrap: break-word;
+}
+
+.oe_im_chatview_online {
+ display: none;
+ margin-top: -4px;
+ width: 11px;
+ height: 11px;
+}
diff --git a/addons/im_livechat/static/ext/static/img/avatar/avatar.jpeg b/addons/im_livechat/static/ext/static/img/avatar/avatar.jpeg
new file mode 100644
index 00000000000..7168794022e
Binary files /dev/null and b/addons/im_livechat/static/ext/static/img/avatar/avatar.jpeg differ
diff --git a/addons/im_livechat/static/ext/static/img/button-gloss.png b/addons/im_livechat/static/ext/static/img/button-gloss.png
new file mode 100755
index 00000000000..6f3957702fe
Binary files /dev/null and b/addons/im_livechat/static/ext/static/img/button-gloss.png differ
diff --git a/addons/im_livechat/static/ext/static/img/glyphicons-halflings-white.png b/addons/im_livechat/static/ext/static/img/glyphicons-halflings-white.png
new file mode 100755
index 00000000000..3bf6484a29d
Binary files /dev/null and b/addons/im_livechat/static/ext/static/img/glyphicons-halflings-white.png differ
diff --git a/addons/im_livechat/static/ext/static/img/glyphicons-halflings.png b/addons/im_livechat/static/ext/static/img/glyphicons-halflings.png
new file mode 100755
index 00000000000..a9969993201
Binary files /dev/null and b/addons/im_livechat/static/ext/static/img/glyphicons-halflings.png differ
diff --git a/addons/im_livechat/static/ext/static/img/green.png b/addons/im_livechat/static/ext/static/img/green.png
new file mode 100644
index 00000000000..01fb373c251
Binary files /dev/null and b/addons/im_livechat/static/ext/static/img/green.png differ
diff --git a/addons/im_livechat/static/ext/static/img/logo.png b/addons/im_livechat/static/ext/static/img/logo.png
new file mode 100644
index 00000000000..aca5f4c60d8
Binary files /dev/null and b/addons/im_livechat/static/ext/static/img/logo.png differ
diff --git a/addons/im_livechat/static/ext/static/img/wood.png b/addons/im_livechat/static/ext/static/img/wood.png
new file mode 100644
index 00000000000..22f2450d3ad
Binary files /dev/null and b/addons/im_livechat/static/ext/static/img/wood.png differ
diff --git a/addons/im_livechat/static/ext/static/js/jquery.achtung.css b/addons/im_livechat/static/ext/static/js/jquery.achtung.css
new file mode 100644
index 00000000000..820ae3e9194
--- /dev/null
+++ b/addons/im_livechat/static/ext/static/js/jquery.achtung.css
@@ -0,0 +1,306 @@
+/**
+ * achtung 0.3.0
+ *
+ * Growl-like notifications for jQuery
+ *
+ * Copyright (c) 2009 Josh Varner
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Portions of this file are from the jQuery UI CSS framework.
+ *
+ * @license http://www.opensource.org/licenses/mit-license.php
+ * @author Josh Varner
+ */
+
+/* IE 6 doesn't support position: fixed */
+* html #achtung-overlay {
+ position:absolute;
+}
+
+/* IE6 includes padding in width */
+* html .achtung {
+ width: 280px;
+}
+
+#achtung-overlay {
+ overflow: hidden;
+ position: fixed;
+ top: 15px;
+ right: 15px;
+ width: 280px;
+ z-index:50;
+}
+
+.achtung {
+ display:none;
+ margin-bottom: 8px;
+ padding: 15px 15px;
+ background-color: #000;
+ color: white;
+ width: 250px;
+ font-weight: bold;
+ position:relative;
+ overflow: hidden;
+ -moz-box-shadow: #aaa 1px 1px 2px;
+ -webkit-box-shadow: #aaa 1px 1px 2px;
+ box-shadow: #aaa 1px 1px 2px;
+ -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px;
+ /* Note that if using show/hide animations, IE will lose
+ this setting */
+ opacity: .85;
+ filter:Alpha(Opacity=85);
+}
+
+/**
+ * This section from jQuery UI CSS framework
+ * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
+ * Can (and should) be removed if you are already loading the jQuery UI CSS
+ * to reduce payload size.
+ */
+.ui-icon { display: block; overflow: hidden; background-repeat: no-repeat; }
+.ui-icon { width: 16px; height: 16px; }
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+.achtung .achtung-message-icon {
+ margin-top: 0px;
+ margin-left: -.5em;
+ margin-right: .5em;
+ float: left;
+ zoom: 1;
+}
+
+.achtung .ui-icon.achtung-close-button {
+ float: right;
+ margin-right: -8px;
+ margin-top: -12px;
+ cursor: pointer;
+ color: white;
+ text-align: right;
+}
+
+.achtung .ui-icon.achtung-close-button:after {
+ content: "x"
+}
+
+/* Slightly darker for these colors (readability) */
+.achtungSuccess, .achtungFail, .achtungWait {
+ /* Note that if using show/hide animations, IE will lose
+ this setting */
+ opacity: .93; filter:Alpha(Opacity=93);
+}
+
+.achtungSuccess {
+ background-color: #4DB559;
+}
+
+.achtungFail {
+ background-color: #D64450;
+}
+
+.achtungWait {
+ background-color: #658093;
+}
+
+.achtungSuccess .ui-icon.achtung-close-button,
+.achtungFail .ui-icon.achtung-close-button {
+}
+
+.achtungSuccess .ui-icon.achtung-close-button-hover,
+.achtungFail .ui-icon.achtung-close-button-hover {
+}
+
+.achtung .wait-icon {
+}
+
+.achtung .achtung-message {
+ display: inline;
+}
diff --git a/addons/im_livechat/static/ext/static/js/jquery.achtung.js b/addons/im_livechat/static/ext/static/js/jquery.achtung.js
new file mode 100644
index 00000000000..1aa69469c1d
--- /dev/null
+++ b/addons/im_livechat/static/ext/static/js/jquery.achtung.js
@@ -0,0 +1,273 @@
+/**
+ * achtung 0.3.0
+ *
+ * Growl-like notifications for jQuery
+ *
+ * Copyright (c) 2009 Josh Varner
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @license http://www.opensource.org/licenses/mit-license.php
+ * @author Josh Varner
+ */
+
+/*globals jQuery,clearTimeout,document,navigator,setTimeout
+*/
+(function($) {
+
+/**
+ * This is based on the jQuery UI $.widget code. I would have just made this
+ * a $.widget but I didn't want the jQuery UI dependency.
+ */
+$.fn.achtung = function(options)
+{
+ var isMethodCall = (typeof options === 'string'),
+ args = Array.prototype.slice.call(arguments, 0),
+ name = 'achtung';
+
+ // handle initialization and non-getter methods
+ return this.each(function() {
+ var instance = $.data(this, name);
+
+ // prevent calls to internal methods
+ if (isMethodCall && options.substring(0, 1) === '_') {
+ return this;
+ }
+
+ // constructor
+ (!instance && !isMethodCall &&
+ $.data(this, name, new $.achtung(this))._init(args));
+
+ // method call
+ (instance && isMethodCall && $.isFunction(instance[options]) &&
+ instance[options].apply(instance, args.slice(1)));
+ });
+};
+
+$.achtung = function(element)
+{
+ var args = Array.prototype.slice.call(arguments, 0), $el;
+
+ if (!element || !element.nodeType) {
+ $el = $('');
+ return $el.achtung.apply($el, args);
+ }
+
+ this.$container = $(element);
+};
+
+
+/**
+ * Static members
+ **/
+$.extend($.achtung, {
+ version: '0.3.0',
+ $overlay: false,
+ defaults: {
+ timeout: 10,
+ disableClose: false,
+ icon: false,
+ className: '',
+ animateClassSwitch: false,
+ showEffects: {'opacity':'toggle','height':'toggle'},
+ hideEffects: {'opacity':'toggle','height':'toggle'},
+ showEffectDuration: 500,
+ hideEffectDuration: 700
+ }
+});
+
+/**
+ * Non-static members
+ **/
+$.extend($.achtung.prototype, {
+ $container: false,
+ closeTimer: false,
+ options: {},
+
+ _init: function(args)
+ {
+ var o, self = this;
+
+ args = $.isArray(args) ? args : [];
+
+
+ args.unshift($.achtung.defaults);
+ args.unshift({});
+
+ o = this.options = $.extend.apply($, args);
+
+ if (!$.achtung.$overlay) {
+ $.achtung.$overlay = $('').appendTo(document.body);
+ }
+
+ if (!o.disableClose) {
+ $('')
+ .click(function () { self.close(); })
+ .hover(function () { $(this).addClass('achtung-close-button-hover'); },
+ function () { $(this).removeClass('achtung-close-button-hover'); })
+ .prependTo(this.$container);
+ }
+
+ this.changeIcon(o.icon, true);
+
+ if (o.message) {
+ this.$container.append($('' + o.message + ''));
+ }
+
+ (o.className && this.$container.addClass(o.className));
+ (o.css && this.$container.css(o.css));
+
+ this.$container
+ .addClass('achtung')
+ .appendTo($.achtung.$overlay);
+
+ if (o.showEffects) {
+ this.$container.toggle();
+ } else {
+ this.$container.show();
+ }
+
+ if (o.timeout > 0) {
+ this.timeout(o.timeout);
+ }
+ },
+
+ timeout: function(timeout)
+ {
+ var self = this;
+
+ if (this.closeTimer) {
+ clearTimeout(this.closeTimer);
+ }
+
+ this.closeTimer = setTimeout(function() { self.close(); }, timeout * 1000);
+ this.options.timeout = timeout;
+ },
+
+ /**
+ * Change the CSS class associated with this message, using
+ * a transition if available (not availble in Safari/Webkit).
+ * If no transition is available, the switch is immediate.
+ *
+ * #LATER Check if this has been corrected in Webkit or jQuery UI
+ * #TODO Make transition time configurable
+ * @param newClass string Name of new class to associate
+ */
+ changeClass: function(newClass)
+ {
+ var self = this;
+
+ if (this.options.className === newClass) {
+ return;
+ }
+
+ this.$container.queue(function() {
+ if (!self.options.animateClassSwitch ||
+ /webkit/.test(navigator.userAgent.toLowerCase()) ||
+ !$.isFunction($.fn.switchClass)) {
+ self.$container.removeClass(self.options.className);
+ self.$container.addClass(newClass);
+ } else {
+ self.$container.switchClass(self.options.className, newClass, 500);
+ }
+
+ self.options.className = newClass;
+ self.$container.dequeue();
+ });
+ },
+
+ changeIcon: function(newIcon, force)
+ {
+ var self = this;
+
+ if ((force !== true || newIcon === false) && this.options.icon === newIcon) {
+ return;
+ }
+
+ if (force || this.options.icon === false) {
+ this.$container.prepend($(''));
+ this.options.icon = newIcon;
+ return;
+ } else if (newIcon === false) {
+ this.$container.find('.achtung-message-icon').remove();
+ this.options.icon = false;
+ return;
+ }
+
+ this.$container.queue(function() {
+ var $span = $('.achtung-message-icon', self.$container);
+
+ if (!self.options.animateClassSwitch ||
+ /webkit/.test(navigator.userAgent.toLowerCase()) ||
+ !$.isFunction($.fn.switchClass)) {
+ $span.removeClass(self.options.icon);
+ $span.addClass(newIcon);
+ } else {
+ $span.switchClass(self.options.icon, newIcon, 500);
+ }
+
+ self.options.icon = newIcon;
+ self.$container.dequeue();
+ });
+ },
+
+
+ changeMessage: function(newMessage)
+ {
+ this.$container.queue(function() {
+ $('.achtung-message', $(this)).html(newMessage);
+ $(this).dequeue();
+ });
+ },
+
+
+ update: function(options)
+ {
+ (options.className && this.changeClass(options.className));
+ (options.css && this.$container.css(options.css));
+ (typeof(options.icon) !== 'undefined' && this.changeIcon(options.icon));
+ (options.message && this.changeMessage(options.message));
+ (options.timeout && this.timeout(options.timeout));
+ },
+
+ close: function()
+ {
+ var o = this.options, $container = this.$container;
+
+ if (o.hideEffects) {
+ this.$container.animate(o.hideEffects, o.hideEffectDuration);
+ } else {
+ this.$container.hide();
+ }
+
+ $container.queue(function() {
+ $container.removeData('achtung');
+ $container.remove();
+
+ if ($.achtung.$overlay && $.achtung.$overlay.is(':empty')) {
+ $.achtung.$overlay.remove();
+ $.achtung.$overlay = false;
+ }
+
+ $container.dequeue();
+ });
+ }
+});
+
+})(jQuery);
\ No newline at end of file
diff --git a/addons/im_livechat/static/ext/static/js/jquery.js b/addons/im_livechat/static/ext/static/js/jquery.js
new file mode 100644
index 00000000000..ded03845983
--- /dev/null
+++ b/addons/im_livechat/static/ext/static/js/jquery.js
@@ -0,0 +1,9555 @@
+/*!
+ * jQuery JavaScript Library v1.9.0
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-1-14
+ */
+(function( window, undefined ) {
+"use strict";
+var
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+ location = window.location,
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // [[Class]] -> type pairs
+ class2type = {},
+
+ // List of deleted data cache ids, so we can reuse them
+ core_deletedIds = [],
+
+ core_version = "1.9.0",
+
+ // Save a reference to some core methods
+ core_concat = core_deletedIds.concat,
+ core_push = core_deletedIds.push,
+ core_slice = core_deletedIds.slice,
+ core_indexOf = core_deletedIds.indexOf,
+ core_toString = class2type.toString,
+ core_hasOwn = class2type.hasOwnProperty,
+ core_trim = core_version.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+ // Used for splitting on whitespace
+ core_rnotwhite = /\S+/g,
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ },
+
+ // The ready event handler and self cleanup method
+ DOMContentLoaded = function() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ } else if ( document.readyState === "complete" ) {
+ // we're here because readyState === "complete" in oldIE
+ // which is good enough for us to call the dom ready!
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: core_version,
+
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return core_slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ },
+
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: core_push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return String( obj );
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ core_toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !core_hasOwn.call(obj, "constructor") &&
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || core_hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // keepScripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+ if ( scripts ) {
+ jQuery( scripts ).remove();
+ }
+ return jQuery.merge( [], parsed.childNodes );
+ },
+
+ parseJSON: function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ if ( data === null ) {
+ return data;
+ }
+
+ if ( typeof data === "string" ) {
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+ }
+ }
+ }
+
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+ function( text ) {
+ return text == null ?
+ "" :
+ core_trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ core_push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( core_indexOf ) {
+ return core_indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var l = second.length,
+ i = first.length,
+ j = 0;
+
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return core_concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ }
+});
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || type !== "function" &&
+ ( length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Control if a given callback is in the list
+ has: function( fn ) {
+ return jQuery.inArray( fn, list ) > -1;
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( list && ( !fired || stack ) ) {
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+jQuery.support = (function() {
+
+ var support, all, a, select, opt, input, fragment, eventName, isSupported, i,
+ div = document.createElement("div");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = "
a";
+
+ // Support tests won't run in some limited or non-browser environments
+ all = div.getElementsByTagName("*");
+ a = div.getElementsByTagName("a")[ 0 ];
+ if ( !all || !a || !all.length ) {
+ return {};
+ }
+
+ // First batch of tests
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px;float:left;opacity:.5";
+ support = {
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: div.firstChild.nodeType === 3,
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: a.getAttribute("href") === "/a",
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.5/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ checkOn: !!input.value,
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Tests for enctype support on a form (#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>",
+
+ // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
+ boxModel: document.compatMode === "CSS1Compat",
+
+ // Will be defined later
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ boxSizingReliable: true,
+ pixelPosition: false
+ };
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE<9
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ // Check if we can trust getAttribute("value")
+ input = document.createElement("input");
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "checked", "t" );
+ input.setAttribute( "name", "t" );
+
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( input );
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
+ for ( i in { submit: true, change: true, focusin: true }) {
+ div.setAttribute( eventName = "on" + i, "t" );
+
+ support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
+ }
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, marginDiv, tds,
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "
t
";
+ tds = div.getElementsByTagName("td");
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Support: IE8
+ // Check if empty table cells still have offsetWidth/Height
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check box-sizing and margin behavior
+ div.innerHTML = "";
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+ support.boxSizing = ( div.offsetWidth === 4 );
+ support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = div.appendChild( document.createElement("div") );
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.innerHTML = "";
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ div.style.display = "block";
+ div.innerHTML = "";
+ div.firstChild.style.width = "5px";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ body.style.zoom = 1;
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE
+ container = div = tds = marginDiv = null;
+ });
+
+ // Null elements to avoid leaks in IE
+ all = select = fragment = opt = a = input = null;
+
+ return support;
+})();
+
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ){
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt /* For internal use only */ ){
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i, l,
+
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data, false );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, false );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ // nodes accept data unless otherwise specified; rejection can be conditional
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var attrs, name,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attrs = elem.attributes;
+ for ( ; i < attrs.length; i++ ) {
+ name = attrs[i].name;
+
+ if ( !name.indexOf( "data-" ) ) {
+ name = jQuery.camelCase( name.substring(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ // Try to fetch any internally stored data first
+ return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
+ }
+
+ this.each(function() {
+ jQuery.data( this, key, value );
+ });
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ hooks.cur = fn;
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var nodeHook, boolHook,
+ rclass = /[\t\r\n]/g,
+ rreturn = /\r/g,
+ rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i,
+ rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ getSetInput = jQuery.support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+ elem.className = jQuery.trim( cur );
+
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+ elem.className = value ? jQuery.trim( cur ) : "";
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.match( core_rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ // Toggle whole class name
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val,
+ self = jQuery(this);
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attr: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ // In IE9+, Flash objects don't have .getAttribute (#12945)
+ // Support: IE9+
+ if ( typeof elem.getAttribute !== "undefined" ) {
+ ret = elem.getAttribute( name );
+ }
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( core_rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( rboolean.test( name ) ) {
+ // Set corresponding property to false for boolean attributes
+ // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
+ if ( !getSetAttribute && ruseDefault.test( name ) ) {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ } else {
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return ( elem[ name ] = value );
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabindex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ var
+ // Use .prop to determine if this attribute is understood as boolean
+ prop = jQuery.prop( elem, name ),
+
+ // Fetch it accordingly
+ attr = typeof prop === "boolean" && elem.getAttribute( name ),
+ detail = typeof prop === "boolean" ?
+
+ getSetInput && getSetAttribute ?
+ attr != null :
+ // oldIE fabricates an empty string for missing boolean attributes
+ // and conflates checked/selected into attroperties
+ ruseDefault.test( name ) ?
+ elem[ jQuery.camelCase( "default-" + name ) ] :
+ !!attr :
+
+ // fetch an attribute node for properties not recognized as boolean
+ elem.getAttributeNode( name );
+
+ return detail && detail.value !== false ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+
+// fix oldIE value attroperty
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return jQuery.nodeName( elem, "input" ) ?
+
+ // Ignore the value *property* by using defaultValue
+ elem.defaultValue :
+
+ ret && ret.specified ? ret.value : undefined;
+ },
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
+ ret.value :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ return name === "value" || value === elem.getAttribute( name ) ?
+ value :
+ undefined;
+ }
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+}
+
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret == null ? undefined : ret;
+ }
+ });
+ });
+
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ });
+});
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var handleObjIn, eventHandle, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ elemData = elem.nodeType !== 3 && elem.nodeType !== 8 && jQuery._data( elem );
+
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var j, origCount, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special,
+ eventPath = [ elem || document ],
+ type = event.type || event,
+ namespaces = event.namespace ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ event.isTrigger = true;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, j, ret, matched, handleObj,
+ handlerQueue = [],
+ args = core_slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var i, matches, sel, handleObj,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG